Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add initial support for I2C in ESP32-H2 (#538)
- Implement Copy and Eq for EspTwaiError (#540)
- Add LEDC hardware fade support
- Added support for multicore async GPIO (#542)

### Fixed

Expand Down
135 changes: 34 additions & 101 deletions esp-hal-common/src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,108 +201,26 @@ pub trait OutputPin: Pin {
fn internal_pull_down(&mut self, on: bool) -> &mut Self;
}

#[doc(hidden)]
pub struct SingleCoreInteruptStatusRegisterAccessBank0;
#[doc(hidden)]
pub struct DualCoreInteruptStatusRegisterAccessBank0;
#[doc(hidden)]
pub struct SingleCoreInteruptStatusRegisterAccessBank1;
#[doc(hidden)]
pub struct DualCoreInteruptStatusRegisterAccessBank1;

#[doc(hidden)]
pub trait InteruptStatusRegisterAccess {
fn pro_cpu_interrupt_status_read() -> u32;

fn pro_cpu_nmi_status_read() -> u32;

fn app_cpu_interrupt_status_read() -> u32;

fn app_cpu_nmi_status_read() -> u32;
}

impl InteruptStatusRegisterAccess for SingleCoreInteruptStatusRegisterAccessBank0 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int.read().bits()
}

fn pro_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int.read().bits()
}

fn app_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int.read().bits()
}

fn app_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int.read().bits()
}
}

#[cfg(any(esp32, esp32s2, esp32s3))]
impl InteruptStatusRegisterAccess for SingleCoreInteruptStatusRegisterAccessBank1 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int1.read().bits()
}

fn pro_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int1.read().bits()
}

fn app_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int1.read().bits()
}

fn app_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int1.read().bits()
}
}

// ESP32S3 is a dual-core chip however pro cpu and app cpu shares the same
// interrupt enable bit see
// https://github.com/espressif/esp-idf/blob/c04803e88b871a4044da152dfb3699cf47354d18/components/hal/esp32s3/include/hal/gpio_ll.h#L32
// Treating it as SingleCore in the gpio macro makes this work.
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3)))]
impl InteruptStatusRegisterAccess for DualCoreInteruptStatusRegisterAccessBank0 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int.read().bits()
}

fn pro_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int.read().bits()
}

fn app_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.acpu_int.read().bits()
Self::pro_cpu_interrupt_status_read()
}

fn app_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.acpu_nmi_int.read().bits()
Self::pro_cpu_nmi_status_read()
}
}

// ESP32S3 is a dual-core chip however pro cpu and app cpu shares the same
// interrupt enable bit see
// https://github.com/espressif/esp-idf/blob/c04803e88b871a4044da152dfb3699cf47354d18/components/hal/esp32s3/include/hal/gpio_ll.h#L32
// Treating it as SingleCore in the gpio macro makes this work.
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3)))]
impl InteruptStatusRegisterAccess for DualCoreInteruptStatusRegisterAccessBank1 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int1.read().bits()
}

fn pro_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int1.read().bits()
}

fn app_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.acpu_int1.read().bits()
}
#[doc(hidden)]
pub struct InteruptStatusRegisterAccessBank0;

fn app_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.acpu_nmi_int1.read().bits()
}
}
#[doc(hidden)]
pub struct InteruptStatusRegisterAccessBank1;

#[doc(hidden)]
pub trait InterruptStatusRegisters<RegisterAccess>
Expand Down Expand Up @@ -1530,7 +1448,6 @@ impl IO {
#[macro_export]
macro_rules! gpio {
(
$cores:ident,
$(
($gpionum:literal, $bank:literal, $type:ident
$(
Expand Down Expand Up @@ -1593,12 +1510,12 @@ macro_rules! gpio {

pub struct Pins {
$(
pub [< gpio $gpionum >] : GpioPin<Unknown, [< Bank $bank GpioRegisterAccess >], $crate::gpio::[< $cores CoreInteruptStatusRegisterAccessBank $bank >], [< $type PinType >], [<Gpio $gpionum Signals>], $gpionum>,
pub [< gpio $gpionum >] : GpioPin<Unknown, [< Bank $bank GpioRegisterAccess >], $crate::gpio::[< InteruptStatusRegisterAccessBank $bank >], [< $type PinType >], [<Gpio $gpionum Signals>], $gpionum>,
)+
}

$(
pub type [<Gpio $gpionum >]<MODE> = GpioPin<MODE, [< Bank $bank GpioRegisterAccess >], $crate::gpio::[< $cores CoreInteruptStatusRegisterAccessBank $bank >], [< $type PinType >], [<Gpio $gpionum Signals>], $gpionum>;
pub type [<Gpio $gpionum >]<MODE> = GpioPin<MODE, [< Bank $bank GpioRegisterAccess >], $crate::gpio::[< InteruptStatusRegisterAccessBank $bank >], [< $type PinType >], [<Gpio $gpionum Signals>], $gpionum>;
)+

pub(crate) enum ErasedPin<MODE> {
Expand Down Expand Up @@ -1909,18 +1826,34 @@ mod asynch {

#[interrupt]
unsafe fn GPIO() {
// TODO how to handle dual core reg access
// we need to check which core the interrupt is currently firing on
// and only fire interrupts registered for that core
type Bank0 = SingleCoreInteruptStatusRegisterAccessBank0;
#[cfg(any(esp32, esp32s2, esp32s3))]
type Bank1 = SingleCoreInteruptStatusRegisterAccessBank1;
let mut intrs = Bank0::pro_cpu_interrupt_status_read() as u64;
let mut intrs = match crate::get_core() {
crate::Cpu::ProCpu => {
InteruptStatusRegisterAccessBank0::pro_cpu_interrupt_status_read() as u64
}
#[cfg(multi_core)]
crate::Cpu::AppCpu => {
InteruptStatusRegisterAccessBank0::app_cpu_interrupt_status_read() as u64
}
};

#[cfg(any(esp32, esp32s2, esp32s3))]
{
intrs |= (Bank1::pro_cpu_interrupt_status_read() as u64) << 32;
}
match crate::get_core() {
crate::Cpu::ProCpu => {
intrs |= (InteruptStatusRegisterAccessBank1::pro_cpu_interrupt_status_read() as u64)
<< 32
}
#[cfg(multi_core)]
crate::Cpu::AppCpu => {
intrs |= (InteruptStatusRegisterAccessBank1::app_cpu_interrupt_status_read() as u64)
<< 32
}
};

log::trace!(
"Handling interrupt on {:?} - {:064b}",
crate::get_core(),
intrs
);

while intrs != 0 {
let pin_nr = intrs.trailing_zeros();
Expand Down
51 changes: 46 additions & 5 deletions esp-hal-common/src/soc/esp32/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ use crate::{
InputOnlyAnalogPinType,
InputOutputAnalogPinType,
InputOutputPinType,
InteruptStatusRegisterAccess,
InteruptStatusRegisterAccessBank0,
InteruptStatusRegisterAccessBank1,
Unknown,
},
peripherals::GPIO,
Cpu,
};

pub const NUM_PINS: usize = 39;
Expand Down Expand Up @@ -72,10 +76,12 @@ pub(crate) fn get_io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mu
}

pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 {
int_enable as u8
| ((nmi_enable as u8) << 1)
| (int_enable as u8) << 2
| ((nmi_enable as u8) << 3)
match crate::get_core() {
Cpu::AppCpu => int_enable as u8 | ((nmi_enable as u8) << 1),
// this should be bits 3 & 4 respectively, according to the TRM, but it doesn't seem to
// work. This does though.
Cpu::ProCpu => (int_enable as u8) << 2 | ((nmi_enable as u8) << 3),
}
}

/// Peripheral input signals for the GPIO mux
Expand Down Expand Up @@ -657,7 +663,6 @@ pub(crate) fn errata36(pin_num: u8, pull_up: bool, pull_down: bool) {
}

crate::gpio::gpio! {
Dual,
(0, 0, InputOutputAnalog (5 => EMAC_TX_CLK) (1 => CLK_OUT1))
(1, 0, InputOutput (5 => EMAC_RXD2) (0 => U0TXD 1 => CLK_OUT3))
(2, 0, InputOutputAnalog (1 => HSPIWP 3 => HS2_DATA0 4 => SD_DATA0) (3 => HS2_DATA0 4 => SD_DATA0))
Expand Down Expand Up @@ -716,3 +721,39 @@ crate::gpio::analog! {
(14, 16, touch_pad6, mux_sel, fun_sel, fun_ie, rue, rde )
(27, 17, touch_pad7, mux_sel, fun_sel, fun_ie, rue, rde )
}

impl InteruptStatusRegisterAccess for InteruptStatusRegisterAccessBank0 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int.read().bits()
}

fn pro_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int.read().bits()
}

fn app_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.acpu_int.read().bits()
}

fn app_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.acpu_nmi_int.read().bits()
}
}

impl InteruptStatusRegisterAccess for InteruptStatusRegisterAccessBank1 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int1.read().bits()
}

fn pro_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int1.read().bits()
}

fn app_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.acpu_int1.read().bits()
}

fn app_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.acpu_nmi_int1.read().bits()
}
}
13 changes: 12 additions & 1 deletion esp-hal-common/src/soc/esp32c2/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::{
GpioPin,
InputOutputAnalogPinType,
InputOutputPinType,
InteruptStatusRegisterAccess,
InteruptStatusRegisterAccessBank0,
Unknown,
},
peripherals::GPIO,
Expand Down Expand Up @@ -139,7 +141,6 @@ pub enum OutputSignal {
}

crate::gpio::gpio! {
Single,
(0, 0, InputOutputAnalog)
(1, 0, InputOutputAnalog)
(2, 0, InputOutputAnalog (2 => FSPIQ) (2 => FSPIQ))
Expand All @@ -163,3 +164,13 @@ crate::gpio::analog! {
3
4
}

impl InteruptStatusRegisterAccess for InteruptStatusRegisterAccessBank0 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int.read().bits()
}

fn pro_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int.read().bits()
}
}
13 changes: 12 additions & 1 deletion esp-hal-common/src/soc/esp32c3/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::{
GpioPin,
InputOutputAnalogPinType,
InputOutputPinType,
InteruptStatusRegisterAccess,
InteruptStatusRegisterAccessBank0,
Unknown,
},
peripherals::GPIO,
Expand Down Expand Up @@ -165,7 +167,6 @@ pub enum OutputSignal {
}

crate::gpio::gpio! {
Single,
(0, 0, InputOutputAnalog)
(1, 0, InputOutputAnalog)
(2, 0, InputOutputAnalog (2 => FSPIQ) (2 => FSPIQ))
Expand Down Expand Up @@ -198,3 +199,13 @@ crate::gpio::analog! {
4
5
}

impl InteruptStatusRegisterAccess for InteruptStatusRegisterAccessBank0 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int.read().bits()
}

fn pro_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int.read().bits()
}
}
13 changes: 12 additions & 1 deletion esp-hal-common/src/soc/esp32c6/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::{
GpioPin,
InputOutputAnalogPinType,
InputOutputPinType,
InteruptStatusRegisterAccess,
InteruptStatusRegisterAccessBank0,
Unknown,
},
peripherals::GPIO,
Expand Down Expand Up @@ -236,7 +238,6 @@ pub enum OutputSignal {
}

crate::gpio::gpio! {
Single,
(0, 0, InputOutputAnalog)
(1, 0, InputOutputAnalog)
(2, 0, InputOutputAnalog (2 => FSPIQ) (2 => FSPIQ))
Expand Down Expand Up @@ -281,6 +282,16 @@ crate::gpio::analog! {
7
}

impl InteruptStatusRegisterAccess for InteruptStatusRegisterAccessBank0 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int.read().bits()
}

fn pro_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int.read().bits()
}
}

// TODO USB pins
// implement marker traits on USB pins
// impl<T> crate::otg_fs::UsbSel for Gpio??<T> {}
Expand Down
13 changes: 12 additions & 1 deletion esp-hal-common/src/soc/esp32h2/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::{
GpioPin,
InputOutputAnalogPinType,
InputOutputPinType,
InteruptStatusRegisterAccess,
InteruptStatusRegisterAccessBank0,
Unknown,
},
peripherals::GPIO,
Expand Down Expand Up @@ -217,7 +219,6 @@ pub enum OutputSignal {

// FIXME: add alternate function numbers/signals where necessary
crate::gpio::gpio! {
Single,
(0, 0, InputOutput)
(1, 0, InputOutputAnalog)
(2, 0, InputOutputAnalog)
Expand Down Expand Up @@ -256,6 +257,16 @@ crate::gpio::analog! {
5
}

impl InteruptStatusRegisterAccess for InteruptStatusRegisterAccessBank0 {
fn pro_cpu_interrupt_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_int.read().bits()
}

fn pro_cpu_nmi_status_read() -> u32 {
unsafe { &*GPIO::PTR }.pcpu_nmi_int.read().bits()
}
}

// TODO USB pins
// implement marker traits on USB pins
// impl<T> crate::otg_fs::UsbSel for Gpio??<T> {}
Expand Down
Loading