diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index b45c0b06a48..8adb6ce1894 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add DmaTransactionTxOwned, DmaTransactionRxOwned, DmaTransactionTxRxOwned, functions to do owning transfers added to SPI half-duplex (#1672) - uart: Implement `embedded_io::ReadReady` for `Uart` and `UartRx` (#1702) - ESP32-C6: Support lp-core as wake-up source (#1723) +- Add support for GPIO wake-up source (#1724) ### Fixed diff --git a/esp-hal/src/gpio/any_pin.rs b/esp-hal/src/gpio/any_pin.rs index 766a7ec2c4e..5f9e02b4087 100644 --- a/esp-hal/src/gpio/any_pin.rs +++ b/esp-hal/src/gpio/any_pin.rs @@ -93,6 +93,7 @@ impl<'d> Pin for AnyPin<'d> { fn unlisten(&mut self, _internal: private::Internal); fn is_interrupt_set(&self, _internal: private::Internal) -> bool; fn clear_interrupt(&mut self, _internal: private::Internal); + fn wakeup_enable(&mut self, enable: bool, event: WakeEvent, _internal: private::Internal); } } } @@ -260,6 +261,7 @@ impl<'d> Pin for AnyInputOnlyPin<'d> { fn unlisten(&mut self, _internal: private::Internal); fn is_interrupt_set(&self, _internal: private::Internal) -> bool; fn clear_interrupt(&mut self, _internal: private::Internal); + fn wakeup_enable(&mut self, enable: bool, event: WakeEvent, _internal: private::Internal); } } } diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index 5e9d99ec9a3..352bd7179f8 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -77,6 +77,25 @@ pub enum Event { HighLevel = 5, } +impl From for Event { + fn from(value: WakeEvent) -> Self { + match value { + WakeEvent::LowLevel => Event::LowLevel, + WakeEvent::HighLevel => Event::HighLevel, + } + } +} + +/// Event used to wake up from light sleep. +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum WakeEvent { + /// Wake on low level + LowLevel = 4, + /// Wake on high level + HighLevel = 5, +} + /// Digital input or output level. #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -227,6 +246,9 @@ pub trait Pin: private::Sealed { /// Clear the interrupt status bit for this Pin fn clear_interrupt(&mut self, _: private::Internal); + + /// Enable this pin as a wake up source + fn wakeup_enable(&mut self, enable: bool, event: WakeEvent, _: private::Internal); } /// Trait implemented by pins which can be used as inputs @@ -862,6 +884,10 @@ where fn clear_interrupt(&mut self, _: private::Internal) { ::Bank::write_interrupt_status_clear(1 << (GPIONUM % 32)); } + + fn wakeup_enable(&mut self, enable: bool, event: WakeEvent, _: private::Internal) { + self.listen_with_options(event.into(), false, false, enable, private::Internal); + } } impl GpioPin @@ -1672,6 +1698,14 @@ where pub fn clear_interrupt(&mut self) { self.pin.clear_interrupt(private::Internal); } + + /// Enable as a wake-up source. + /// + /// This will unlisten for interrupts + #[inline] + pub fn wakeup_enable(&mut self, enable: bool, event: WakeEvent) { + self.pin.wakeup_enable(enable, event, private::Internal); + } } /// GPIO open-drain output driver. @@ -2302,6 +2336,12 @@ pub(crate) mod internal { Pin::clear_interrupt(target, private::Internal) }) } + + fn wakeup_enable(&mut self, enable: bool, event: WakeEvent, _: private::Internal) { + handle_gpio_input!(self, target, { + Pin::wakeup_enable(target, enable, event, private::Internal) + }) + } } impl InputPin for ErasedPin { diff --git a/esp-hal/src/rtc_cntl/sleep/mod.rs b/esp-hal/src/rtc_cntl/sleep/mod.rs index 4570267f21a..d167aad2789 100644 --- a/esp-hal/src/rtc_cntl/sleep/mod.rs +++ b/esp-hal/src/rtc_cntl/sleep/mod.rs @@ -153,6 +153,34 @@ impl Default for WakeFromLpCoreWakeupSource { } } +/// GPIO wakeup source +/// +/// Wake up from GPIO high or low level. Any pin can be used with this wake up +/// source. Configure the pin for wake up via +/// [crate::gpio::Input::wakeup_enable]. +/// +/// This wakeup source can be used to wake up from light sleep only. +pub struct GpioWakeupSource {} + +impl GpioWakeupSource { + /// Create a new instance of [GpioWakeupSource] + pub fn new() -> Self { + Self {} + } +} + +impl Default for GpioWakeupSource { + fn default() -> Self { + Self::new() + } +} + +impl WakeSource for GpioWakeupSource { + fn apply(&self, _rtc: &Rtc, triggers: &mut WakeTriggers, _sleep_config: &mut RtcSleepConfig) { + triggers.set_gpio(true); + } +} + #[cfg(not(pmu))] bitfield::bitfield! { #[derive(Default, Clone, Copy)]