From 4f17dd5aaad31206e368c789a72ec02f21758199 Mon Sep 17 00:00:00 2001 From: Oyvind Netland Date: Sun, 12 Nov 2023 13:25:12 +0100 Subject: [PATCH] sleep: adds gpio deep sleep for esp32c* targets --- examples/deep_sleep.rs | 31 ++++++++++--- src/sleep.rs | 98 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 117 insertions(+), 12 deletions(-) diff --git a/examples/deep_sleep.rs b/examples/deep_sleep.rs index 40d3f40ba8d..dff452f5ac6 100644 --- a/examples/deep_sleep.rs +++ b/examples/deep_sleep.rs @@ -9,9 +9,9 @@ //! the previous run. use core::time::Duration; -#[cfg(any(esp32, esp32s2, esp32s3))] +#[cfg(any(esp32c2, esp32c3))] +use esp_idf_hal::gpio::Level; use esp_idf_hal::gpio::PinDriver; -#[cfg(any(esp32, esp32s2, esp32s3))] use esp_idf_hal::peripherals::Peripherals; use esp_idf_hal::reset::{ResetReason, WakeupReason}; use esp_idf_hal::sleep::*; @@ -30,7 +30,6 @@ fn main() -> anyhow::Result<()> { print_wakeup_result(); - #[cfg(any(esp32, esp32s2, esp32s3))] let peripherals = Peripherals::take().unwrap(); // RTC wakeup definitions @@ -62,8 +61,30 @@ fn main() -> anyhow::Result<()> { None, ); - #[cfg(not(any(esp32, esp32s2, esp32s3)))] - let dsleep = make_deep_sleep_no_pins(Some(TimerWakeup::new(Duration::from_secs(5)))); + // GPIO wakeup definitions + #[cfg(any(esp32c2, esp32c3))] + let gpio0 = PinDriver::input(peripherals.pins.gpio0)?; + #[cfg(any(esp32c2, esp32c3))] + let gpio1 = PinDriver::input(peripherals.pins.gpio1)?; + + #[cfg(any(esp32c2, esp32c3))] + let gpio_pin0 = GpioWakeupPin { + pindriver: &gpio0, + wake_level: Level::High, + }; + #[cfg(any(esp32c2, esp32c3))] + let gpio_pin1 = GpioWakeupPin { + pindriver: &gpio1, + wake_level: Level::Low, + }; + #[cfg(any(esp32c2, esp32c3))] + let gpio_wakeup = Some(GpioDeepWakeup { + pins: EmptyGpioWakeupPins::chain(gpio_pin0).chain(gpio_pin1), + }); + + #[cfg(any(esp32c2, esp32c3))] + let dsleep = + make_deep_sleep_gpio_pins(Some(TimerWakeup::new(Duration::from_secs(5))), gpio_wakeup); println!("Deep sleep with: {:?}", dsleep); dsleep.prepare()?; diff --git a/src/sleep.rs b/src/sleep.rs index aed19434825..bd3a4830d1a 100644 --- a/src/sleep.rs +++ b/src/sleep.rs @@ -27,7 +27,6 @@ use crate::gpio::{GPIOMode, InputPin, Level, PinDriver}; #[cfg(any(esp32, esp32s2, esp32s3))] use crate::gpio::{RTCMode, RTCPin}; use crate::uart::UartDriver; -#[cfg(not(any(esp32, esp32s2, esp32s3)))] use core::marker::PhantomData; /// Will wake the CPU up after a given duration @@ -274,6 +273,63 @@ where } } +#[cfg(any(esp32c2, esp32c3))] +pub struct GpioDeepWakeup

+where + P: GpioWakeupPins, +{ + pub pins: P, +} + +#[cfg(any(esp32c2, esp32c3))] +impl

GpioDeepWakeup

+where + P: GpioWakeupPins, +{ + fn mask(&self, level: Level) -> u64 { + let mut m: u64 = 0; + for pin in self.pins.iter() { + if pin.1 == level { + m |= 1 << pin.0; + } + } + m + } + + fn apply(&self) -> Result<(), EspError> { + esp!(unsafe { + esp_deep_sleep_enable_gpio_wakeup( + self.mask(Level::Low), + esp_deepsleep_gpio_wake_up_mode_t_ESP_GPIO_WAKEUP_GPIO_LOW, + ) + })?; + + esp!(unsafe { + esp_deep_sleep_enable_gpio_wakeup( + self.mask(Level::High), + esp_deepsleep_gpio_wake_up_mode_t_ESP_GPIO_WAKEUP_GPIO_HIGH, + ) + })?; + + Ok(()) + } +} + +#[cfg(any(esp32c2, esp32c3))] +impl

fmt::Debug for GpioDeepWakeup

+where + P: GpioWakeupPins, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "GpioDeepWakeup {{ pins: [")?; + + for pin in self.pins.iter() { + write!(f, "({} {:?}), ", pin.0, pin.1)?; + } + write!(f, "") + } +} + pub trait GpioWakeupPinTrait { fn pin(&self) -> i32; fn wake_level(&self) -> Level; @@ -584,35 +640,41 @@ where } /// Struct for deep sleep. Add wakeup sources to this struct, and then call sleep(). -pub struct DeepSleep +pub struct DeepSleep where R: RtcWakeupPins, + P: GpioWakeupPins, { pub timer: Option, #[cfg(any(esp32, esp32s2, esp32s3))] pub rtc: Option>, + #[cfg(any(esp32c2, esp32c3))] + pub gpio: Option>, #[cfg(any(esp32, esp32s2, esp32s3))] pub touch: Option, #[cfg(any(esp32, esp32s2, esp32s3))] pub ulp: Option, #[cfg(not(any(esp32, esp32s2, esp32s3)))] pub _p: PhantomData, + #[cfg(not(any(esp32c2, esp32c3)))] + pub _p: PhantomData

, } pub fn make_deep_sleep_no_pins( timer: Option, #[cfg(any(esp32, esp32s2, esp32s3))] touch: Option, #[cfg(any(esp32, esp32s2, esp32s3))] ulp: Option, -) -> DeepSleep { +) -> DeepSleep { DeepSleep { timer, #[cfg(any(esp32, esp32s2, esp32s3))] rtc: None, + #[cfg(any(esp32c2, esp32c3))] + gpio: None, #[cfg(any(esp32, esp32s2, esp32s3))] touch, #[cfg(any(esp32, esp32s2, esp32s3))] ulp, - #[cfg(not(any(esp32, esp32s2, esp32s3)))] _p: PhantomData, } } @@ -623,18 +685,32 @@ pub fn make_deep_sleep_rtc_pins( rtc: Option>, touch: Option, ulp: Option, -) -> DeepSleep { +) -> DeepSleep { DeepSleep { timer, rtc, touch, ulp, + _p: PhantomData, } } -impl DeepSleep +#[cfg(any(esp32c2, esp32c3))] +pub fn make_deep_sleep_gpio_pins( + timer: Option, + gpio: Option>, +) -> DeepSleep { + DeepSleep { + timer, + gpio, + _p: PhantomData, + } +} + +impl DeepSleep where R: RtcWakeupPins, + P: GpioWakeupPins, { pub fn prepare(&self) -> Result<(), EspError> { esp!(unsafe { esp_sleep_disable_wakeup_source(esp_sleep_source_t_ESP_SLEEP_WAKEUP_ALL) })?; @@ -648,6 +724,11 @@ where rtc.apply()?; } + #[cfg(any(esp32c2, esp32c3))] + if let Some(gpio) = &self.gpio { + gpio.apply()?; + } + #[cfg(any(esp32, esp32s2, esp32s3))] if let Some(touch) = &self.touch { touch.apply()?; @@ -679,14 +760,17 @@ where } } -impl fmt::Debug for DeepSleep +impl fmt::Debug for DeepSleep where R: RtcWakeupPins, + P: GpioWakeupPins, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DeepSleep: {{timer: {:?}, ", self.timer)?; #[cfg(any(esp32, esp32s2, esp32s3))] write!(f, "rtc: {:?}, ", self.rtc)?; + #[cfg(any(esp32c2, esp32c3))] + write!(f, "gpio: {:?}, ", self.gpio)?; #[cfg(any(esp32, esp32s2, esp32s3))] write!(f, "touch: {:?}, ", self.touch)?; #[cfg(any(esp32, esp32s2, esp32s3))]