diff --git a/CHANGELOG.md b/CHANGELOG.md index d94309aa52c..f63b56b15a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/esp-hal-common/src/gpio.rs b/esp-hal-common/src/gpio.rs index c2727035e0e..89d2085fd5f 100644 --- a/esp-hal-common/src/gpio.rs +++ b/esp-hal-common/src/gpio.rs @@ -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 @@ -1530,7 +1448,6 @@ impl IO { #[macro_export] macro_rules! gpio { ( - $cores:ident, $( ($gpionum:literal, $bank:literal, $type:ident $( @@ -1593,12 +1510,12 @@ macro_rules! gpio { pub struct Pins { $( - pub [< gpio $gpionum >] : GpioPin], $crate::gpio::[< $cores CoreInteruptStatusRegisterAccessBank $bank >], [< $type PinType >], [], $gpionum>, + pub [< gpio $gpionum >] : GpioPin], $crate::gpio::[< InteruptStatusRegisterAccessBank $bank >], [< $type PinType >], [], $gpionum>, )+ } $( - pub type [] = GpioPin], $crate::gpio::[< $cores CoreInteruptStatusRegisterAccessBank $bank >], [< $type PinType >], [], $gpionum>; + pub type [] = GpioPin], $crate::gpio::[< InteruptStatusRegisterAccessBank $bank >], [< $type PinType >], [], $gpionum>; )+ pub(crate) enum ErasedPin { @@ -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(); diff --git a/esp-hal-common/src/soc/esp32/gpio.rs b/esp-hal-common/src/soc/esp32/gpio.rs index f5b2aba18a4..6c25a184006 100644 --- a/esp-hal-common/src/soc/esp32/gpio.rs +++ b/esp-hal-common/src/soc/esp32/gpio.rs @@ -9,9 +9,13 @@ use crate::{ InputOnlyAnalogPinType, InputOutputAnalogPinType, InputOutputPinType, + InteruptStatusRegisterAccess, + InteruptStatusRegisterAccessBank0, + InteruptStatusRegisterAccessBank1, Unknown, }, peripherals::GPIO, + Cpu, }; pub const NUM_PINS: usize = 39; @@ -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 @@ -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)) @@ -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() + } +} diff --git a/esp-hal-common/src/soc/esp32c2/gpio.rs b/esp-hal-common/src/soc/esp32c2/gpio.rs index 02259dfbb96..402beb5ff20 100644 --- a/esp-hal-common/src/soc/esp32c2/gpio.rs +++ b/esp-hal-common/src/soc/esp32c2/gpio.rs @@ -7,6 +7,8 @@ use crate::{ GpioPin, InputOutputAnalogPinType, InputOutputPinType, + InteruptStatusRegisterAccess, + InteruptStatusRegisterAccessBank0, Unknown, }, peripherals::GPIO, @@ -139,7 +141,6 @@ pub enum OutputSignal { } crate::gpio::gpio! { - Single, (0, 0, InputOutputAnalog) (1, 0, InputOutputAnalog) (2, 0, InputOutputAnalog (2 => FSPIQ) (2 => FSPIQ)) @@ -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() + } +} diff --git a/esp-hal-common/src/soc/esp32c3/gpio.rs b/esp-hal-common/src/soc/esp32c3/gpio.rs index 7f39a650ed0..a7a2a946de4 100644 --- a/esp-hal-common/src/soc/esp32c3/gpio.rs +++ b/esp-hal-common/src/soc/esp32c3/gpio.rs @@ -7,6 +7,8 @@ use crate::{ GpioPin, InputOutputAnalogPinType, InputOutputPinType, + InteruptStatusRegisterAccess, + InteruptStatusRegisterAccessBank0, Unknown, }, peripherals::GPIO, @@ -165,7 +167,6 @@ pub enum OutputSignal { } crate::gpio::gpio! { - Single, (0, 0, InputOutputAnalog) (1, 0, InputOutputAnalog) (2, 0, InputOutputAnalog (2 => FSPIQ) (2 => FSPIQ)) @@ -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() + } +} diff --git a/esp-hal-common/src/soc/esp32c6/gpio.rs b/esp-hal-common/src/soc/esp32c6/gpio.rs index 2c25f11d122..307202341b2 100644 --- a/esp-hal-common/src/soc/esp32c6/gpio.rs +++ b/esp-hal-common/src/soc/esp32c6/gpio.rs @@ -7,6 +7,8 @@ use crate::{ GpioPin, InputOutputAnalogPinType, InputOutputPinType, + InteruptStatusRegisterAccess, + InteruptStatusRegisterAccessBank0, Unknown, }, peripherals::GPIO, @@ -236,7 +238,6 @@ pub enum OutputSignal { } crate::gpio::gpio! { - Single, (0, 0, InputOutputAnalog) (1, 0, InputOutputAnalog) (2, 0, InputOutputAnalog (2 => FSPIQ) (2 => FSPIQ)) @@ -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 crate::otg_fs::UsbSel for Gpio?? {} diff --git a/esp-hal-common/src/soc/esp32h2/gpio.rs b/esp-hal-common/src/soc/esp32h2/gpio.rs index 36822540813..9ceffc6a367 100644 --- a/esp-hal-common/src/soc/esp32h2/gpio.rs +++ b/esp-hal-common/src/soc/esp32h2/gpio.rs @@ -7,6 +7,8 @@ use crate::{ GpioPin, InputOutputAnalogPinType, InputOutputPinType, + InteruptStatusRegisterAccess, + InteruptStatusRegisterAccessBank0, Unknown, }, peripherals::GPIO, @@ -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) @@ -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 crate::otg_fs::UsbSel for Gpio?? {} diff --git a/esp-hal-common/src/soc/esp32s2/gpio.rs b/esp-hal-common/src/soc/esp32s2/gpio.rs index 8f381e99450..02dbec49279 100644 --- a/esp-hal-common/src/soc/esp32s2/gpio.rs +++ b/esp-hal-common/src/soc/esp32s2/gpio.rs @@ -8,6 +8,9 @@ use crate::{ GpioPin, InputOutputAnalogPinType, InputOutputPinType, + InteruptStatusRegisterAccess, + InteruptStatusRegisterAccessBank0, + InteruptStatusRegisterAccessBank1, Unknown, }, peripherals::GPIO, @@ -261,7 +264,6 @@ pub enum OutputSignal { } crate::gpio::gpio! { - Single, (0, 0, InputOutputAnalog) (1, 0, InputOutputAnalog) (2, 0, InputOutputAnalog) @@ -382,6 +384,26 @@ crate::gpio::analog! { (21, 21, rtc_pad21, 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() + } +} + +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() + } +} + // implement marker traits on USB pins impl crate::otg_fs::UsbSel for Gpio18 {} impl crate::otg_fs::UsbDp for Gpio19 {} diff --git a/esp-hal-common/src/soc/esp32s3/gpio.rs b/esp-hal-common/src/soc/esp32s3/gpio.rs index 42ed47c3d52..b4ff76686d1 100644 --- a/esp-hal-common/src/soc/esp32s3/gpio.rs +++ b/esp-hal-common/src/soc/esp32s3/gpio.rs @@ -8,6 +8,9 @@ use crate::{ GpioPin, InputOutputAnalogPinType, InputOutputPinType, + InteruptStatusRegisterAccess, + InteruptStatusRegisterAccessBank0, + InteruptStatusRegisterAccessBank1, Unknown, }, peripherals::GPIO, @@ -264,7 +267,6 @@ pub enum OutputSignal { } crate::gpio::gpio! { - Single, (0, 0, InputOutputAnalog) (1, 0, InputOutputAnalog) (2, 0, InputOutputAnalog) @@ -337,6 +339,28 @@ crate::gpio::analog! { (21, 21, rtc_pad21, mux_sel, fun_sel, fun_ie, rue, rde) } +// Whilst the S3 is a dual core chip, it shares the enable registers between +// cores so treat it as a single core device +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() + } +} + +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() + } +} + // implement marker traits on USB pins impl crate::otg_fs::UsbSel for Gpio18 {} impl crate::otg_fs::UsbDp for Gpio19 {}