diff --git a/CHANGELOG.md b/CHANGELOG.md index fc6aabbf3..70c856142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - A way to push into I2S DMA buffer via a closure (#1189) - Added basic `LP-I2C` driver for C6 (#1185) - Ensuring that the random number generator is TRNG. (#1200) +- ESP32-C6: Add timer wakeup source for deepsleep (#1201) ### Fixed diff --git a/esp-hal/src/reset.rs b/esp-hal/src/reset.rs index 0e304bea8..3402f2ed3 100644 --- a/esp-hal/src/reset.rs +++ b/esp-hal/src/reset.rs @@ -73,8 +73,12 @@ bitflags::bitflags! { const ExtEvent1Trig = 1 << 1; /// GPIO wakeup (light sleep only) const GpioTrigEn = 1 << 2; + #[cfg(not(any(esp32c6, esp32h2)))] /// Timer wakeup const TimerTrigEn = 1 << 3; + #[cfg(any(esp32c6, esp32h2))] + /// Timer wakeup + const TimerTrigEn = 1 << 4; #[cfg(pm_support_wifi_wakeup)] /// MAC wakeup (light sleep only) const WifiTrigEn = 1 << 5; diff --git a/esp-hal/src/rtc_cntl/sleep/esp32c6.rs b/esp-hal/src/rtc_cntl/sleep/esp32c6.rs index f686be410..8f05b2018 100644 --- a/esp-hal/src/rtc_cntl/sleep/esp32c6.rs +++ b/esp-hal/src/rtc_cntl/sleep/esp32c6.rs @@ -1,6 +1,7 @@ use core::ops::Not; use crate::{ + clock::Clock, efuse::Efuse, gpio::{Pins, RtcFunction}, peripherals::Peripherals, @@ -15,12 +16,44 @@ use crate::{ RtcCalSel, SavedClockConfig, }, - sleep::{Ext1WakeupSource, WakeSource, WakeTriggers, WakeupLevel}, + sleep::{Ext1WakeupSource, TimerWakeupSource, WakeSource, WakeTriggers, WakeupLevel}, RtcClock, }, Rtc, }; +impl WakeSource for TimerWakeupSource { + fn apply(&self, rtc: &Rtc, triggers: &mut WakeTriggers, _sleep_config: &mut RtcSleepConfig) { + triggers.set_timer(true); + + let lp_timer = unsafe { &*esp32c6::LP_TIMER::ptr() }; + let clock_freq = RtcClock::get_slow_freq(); + // TODO: maybe add sleep time adjustlemnt like idf + // TODO: maybe add check to prevent overflow? + let clock_hz = clock_freq.frequency().to_Hz() as u64; + let ticks = self.duration.as_micros() as u64 * clock_hz / 1_000_000u64; + // "alarm" time in slow rtc ticks + let now = rtc.get_time_raw(); + let time_in_ticks = now + ticks; + unsafe { + lp_timer.tar0_high().write(|w| { + w.main_timer_tar_high0() + .bits(((time_in_ticks >> 32) & 0xffff) as u16) + }); + lp_timer.tar0_low().write(|w| { + w.main_timer_tar_low0() + .bits((time_in_ticks & 0xffffffff) as u32) + }); + lp_timer + .int_clr() + .write(|w| w.soc_wakeup_int_clr().set_bit()); + lp_timer + .tar0_high() + .modify(|_, w| w.main_timer_tar_en0().set_bit()); + } + } +} + impl Ext1WakeupSource<'_, '_> { /// Returns the currently configured wakeup pins. fn wakeup_pins() -> u8 { diff --git a/esp-hal/src/rtc_cntl/sleep/mod.rs b/esp-hal/src/rtc_cntl/sleep/mod.rs index f5b50d7d1..7315ef525 100644 --- a/esp-hal/src/rtc_cntl/sleep/mod.rs +++ b/esp-hal/src/rtc_cntl/sleep/mod.rs @@ -21,7 +21,7 @@ //! * `BT (Bluetooth) wake` - light sleep only use core::cell::RefCell; -#[cfg(any(esp32, esp32c3, esp32s3))] +#[cfg(any(esp32, esp32c3, esp32s3, esp32c6))] use core::time::Duration; #[cfg(any(esp32, esp32s3))] @@ -46,12 +46,12 @@ pub enum WakeupLevel { } #[derive(Debug, Default, Clone, Copy)] -#[cfg(any(esp32, esp32c3, esp32s3))] +#[cfg(any(esp32, esp32c3, esp32s3, esp32c6))] pub struct TimerWakeupSource { duration: Duration, } -#[cfg(any(esp32, esp32c3, esp32s3))] +#[cfg(any(esp32, esp32c3, esp32s3, esp32c6))] impl TimerWakeupSource { pub fn new(duration: Duration) -> Self { Self { duration } diff --git a/examples/src/bin/sleep_timer.rs b/examples/src/bin/sleep_timer.rs index 8c0c474b1..9d91cbaa8 100644 --- a/examples/src/bin/sleep_timer.rs +++ b/examples/src/bin/sleep_timer.rs @@ -1,6 +1,6 @@ //! Demonstrates deep sleep with timer wakeup -//% CHIPS: esp32 esp32c3 esp32s3 +//% CHIPS: esp32 esp32c3 esp32c6 esp32s3 #![no_std] #![no_main] diff --git a/examples/src/bin/sleep_lpio.rs b/examples/src/bin/sleep_timer_lpio.rs similarity index 81% rename from examples/src/bin/sleep_lpio.rs rename to examples/src/bin/sleep_timer_lpio.rs index c30b921b2..1f60bd88d 100644 --- a/examples/src/bin/sleep_lpio.rs +++ b/examples/src/bin/sleep_timer_lpio.rs @@ -1,10 +1,12 @@ -//! Demonstrates deep sleep with gpio2 (low) and gpio3 (high) as wakeup sources. +//! Demonstrates deep sleep with timer, using gpio2 (low) and gpio3 (high) as wakeup sources. //% CHIPS: esp32c6 #![no_std] #![no_main] +use core::time::Duration; + use esp_backtrace as _; use esp_hal::{ clock::ClockControl, @@ -15,7 +17,7 @@ use esp_hal::{ rtc_cntl::{ get_reset_reason, get_wakeup_cause, - sleep::{Ext1WakeupSource, WakeupLevel}, + sleep::{Ext1WakeupSource, TimerWakeupSource, WakeupLevel}, SocResetReason, }, Cpu, @@ -44,6 +46,8 @@ fn main() -> ! { println!("wake reason: {:?}", wake_reason); let mut delay = Delay::new(&clocks); + let timer = TimerWakeupSource::new(Duration::from_secs(10)); + let wakeup_pins: &mut [(&mut dyn RTCPinWithResistors, WakeupLevel)] = &mut [ (&mut pin2, WakeupLevel::Low), (&mut pin3, WakeupLevel::High), @@ -52,5 +56,5 @@ fn main() -> ! { let rtcio = Ext1WakeupSource::new(wakeup_pins); println!("sleeping!"); delay.delay_ms(100u32); - rtc.sleep_deep(&[&rtcio], &mut delay); + rtc.sleep_deep(&[&timer, &rtcio], &mut delay); }