From acac9c49468db3a48dcade133afc58ce98bacafb Mon Sep 17 00:00:00 2001 From: liebman Date: Sat, 3 Jun 2023 11:34:08 -0700 Subject: [PATCH 01/20] deep sleep api for esp32 --- esp-hal-common/Cargo.toml | 1 + esp-hal-common/src/reset.rs | 1 + esp-hal-common/src/rtc_cntl/mod.rs | 4 + .../src/rtc_cntl/rtc/esp32_sleep.rs | 379 ++++++++++++++++++ esp-hal-common/src/rtc_cntl/sleep.rs | 102 +++++ 5 files changed, 487 insertions(+) create mode 100644 esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs create mode 100644 esp-hal-common/src/rtc_cntl/sleep.rs diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index d79f5ff3edc..185b4c864b8 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -13,6 +13,7 @@ license = "MIT OR Apache-2.0" [dependencies] bitflags = "2.3.3" +bitfield = "0.14.0" cfg-if = "1.0.0" critical-section = "1.1.1" embedded-can = { version = "0.4.1", optional = true } diff --git a/esp-hal-common/src/reset.rs b/esp-hal-common/src/reset.rs index 8c07ce4c32c..6aa760a78f1 100644 --- a/esp-hal-common/src/reset.rs +++ b/esp-hal-common/src/reset.rs @@ -2,6 +2,7 @@ use crate::rtc_cntl::SocResetReason; +#[derive(Debug, Copy, Clone)] pub enum SleepSource { /// In case of deep sleep, reset was not caused by exit from deep sleep Undefined = 0, diff --git a/esp-hal-common/src/rtc_cntl/mod.rs b/esp-hal-common/src/rtc_cntl/mod.rs index 480ed4ec9fd..211e04f288d 100644 --- a/esp-hal-common/src/rtc_cntl/mod.rs +++ b/esp-hal-common/src/rtc_cntl/mod.rs @@ -21,6 +21,10 @@ use crate::{ Cpu, }; +// only include sleep where its been implemented +#[cfg(any(esp32))] +pub mod sleep; + #[cfg(any(esp32c6, esp32h2))] type RtcCntl = crate::peripherals::LP_CLKRST; #[cfg(not(any(esp32c6, esp32h2)))] diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs new file mode 100644 index 00000000000..8b066fd0d28 --- /dev/null +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs @@ -0,0 +1,379 @@ +use super::{TimerWakeSource, WakeSource}; +use crate::{ + rtc_cntl::{Clock, RtcClock}, + Rtc, +}; + +// Approximate mapping of voltages to RTC_CNTL_DBIAS_WAK, RTC_CNTL_DBIAS_SLP, +// RTC_CNTL_DIG_DBIAS_WAK, RTC_CNTL_DIG_DBIAS_SLP values. +// Valid if RTC_CNTL_DBG_ATTEN is 0. +pub const RTC_CNTL_DBIAS_0V90: u8 = 0; +pub const RTC_CNTL_DBIAS_0V95: u8 = 1; +pub const RTC_CNTL_DBIAS_1V00: u8 = 2; +pub const RTC_CNTL_DBIAS_1V05: u8 = 3; +pub const RTC_CNTL_DBIAS_1V10: u8 = 4; +pub const RTC_CNTL_DBIAS_1V15: u8 = 5; +pub const RTC_CNTL_DBIAS_1V20: u8 = 6; +pub const RTC_CNTL_DBIAS_1V25: u8 = 7; +// Various delays to be programmed into power control state machines +pub const RTC_CNTL_XTL_BUF_WAIT_SLP_US: u32 = 1000; +pub const RTC_CNTL_PLL_BUF_WAIT_SLP_CYCLES: u8 = 1; +pub const RTC_CNTL_CK8M_WAIT_SLP_CYCLES: u8 = 4; +pub const RTC_CNTL_WAKEUP_DELAY_CYCLES: u8 = 7; +pub const RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES: u8 = 1; +pub const RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES: u16 = 1; +pub const RTC_CNTL_MIN_SLP_VAL_MIN: u8 = 128; + +pub const RTC_MEM_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES; +pub const RTC_MEM_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES; +pub const ROM_RAM_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES; +pub const ROM_RAM_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES; +pub const WIFI_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES; +pub const WIFI_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES; +pub const RTC_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES; +pub const RTC_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES; +pub const DG_WRAP_POWERUP_CYCLES: u8 = RTC_CNTL_OTHER_BLOCKS_POWERUP_CYCLES; +pub const DG_WRAP_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES; + +pub const RTC_CNTL_CK8M_WAIT_DEFAULT: u8 = 20; +pub const RTC_CK8M_ENABLE_WAIT_DEFAULT: u8 = 5; + +impl WakeSource for TimerWakeSource { + fn prepare(&self, rtc: &Rtc) { + let rtc_cntl = unsafe { &*esp32::RTC_CNTL::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 { + rtc_cntl + .slp_timer0 + .write(|w| w.slp_val_lo().bits((time_in_ticks & 0xffffffff) as u32)); + #[rustfmt::skip] + rtc_cntl.slp_timer1.write(|w| { w + .slp_val_hi().bits(((time_in_ticks >> 32) & 0xffff) as u16) + .main_timer_alarm_en().set_bit() + }); + } + } +} + +bitfield::bitfield! { + #[derive(Clone, Copy)] + pub struct RtcSleepConfig(u32); + impl Debug; + /// force normal voltage in sleep mode (digital domain memory) + pub lslp_mem_inf_fpu, set_lslp_mem_inf_fpu: 0; + /// force normal voltage in sleep mode (RTC memory) + pub rtc_mem_inf_fpu, set_rtc_mem_inf_fpu: 1; + /// keep low voltage in sleep mode (even if ULP/touch is used) + pub rtc_mem_inf_follow_cpu, set_rtc_mem_inf_follow_cpu: 2; + /// power down RTC fast memory + pub rtc_fastmem_pd_en, set_rtc_fastmem_pd_en: 3; + /// power down RTC slow memory + pub rtc_slowmem_pd_en, set_rtc_slowmem_pd_en: 4; + /// power down RTC peripherals + pub rtc_peri_pd_en, set_rtc_peri_pd_en: 5; + /// power down WiFi + pub wifi_pd_en, set_wifi_pd_en: 6; + /// Power down Internal 8M oscillator + pub int_8m_pd_en, set_int_8m_pd_en: 7; + /// power down main RAM and ROM + pub rom_mem_pd_en, set_rom_mem_pd_en: 8; + /// power down digital domain + pub deep_slp, set_deep_slp: 9; + /// enable WDT flashboot mode + pub wdt_flashboot_mod_en, set_wdt_flashboot_mod_en: 10; + /// bias for digital domain, in active mode + pub u8, dig_dbias_wak, set_dig_dbias_wak: 13, 11; + /// bias for digital domain, in sleep mode + pub u8, dig_dbias_slp, set_dig_dbias_slp: 16, 14; + /// bias for RTC domain, in active mode + pub u8, rtc_dbias_wak, set_rtc_dbias_wak: 19, 17; + /// bias for RTC domain, in sleep mode + pub u8, rtc_dbias_slp, set_rtc_dbias_slp: 22, 20; + /// remove all peripheral force power up flags + pub lslp_meminf_pd, set_lslp_meminf_pd: 23; + /// power down VDDSDIO regulator + pub vddsdio_pd_en, set_vddsdio_pd_en: 24; + /// keep main XTAL powered up in sleep + pub xtal_fpu, set_xtal_fpu: 25; + /// enable deep sleep reject + pub deep_slp_reject, set_deep_slp_reject: 26; + /// enable light sleep reject + pub light_slp_reject, set_light_slp_reject: 27; +} + +impl Default for RtcSleepConfig { + fn default() -> Self { + let mut cfg = Self(Default::default()); + cfg.set_lslp_meminf_pd(true); + cfg.set_deep_slp_reject(true); + cfg.set_light_slp_reject(true); + cfg.set_dig_dbias_wak(RTC_CNTL_DBIAS_1V10); + cfg.set_dig_dbias_slp(RTC_CNTL_DBIAS_1V10); + cfg.set_rtc_dbias_wak(RTC_CNTL_DBIAS_1V10); + cfg.set_rtc_dbias_slp(RTC_CNTL_DBIAS_1V10); + cfg + } +} + +impl RtcSleepConfig { + pub fn deep() -> Self { + let mut cfg = Self::default(); + cfg.set_deep_slp(true); + cfg.set_dig_dbias_slp(RTC_CNTL_DBIAS_0V90); + //cfg.set_rtc_dbias_slp(RTC_CNTL_DBIAS_0V90); + cfg.set_vddsdio_pd_en(true); + cfg.set_int_8m_pd_en(true); + cfg.set_xtal_fpu(false); + cfg.set_wifi_pd_en(true); + cfg.set_rom_mem_pd_en(true); + cfg.set_rtc_peri_pd_en(true); + cfg.set_rtc_fastmem_pd_en(true); + cfg.set_rtc_slowmem_pd_en(true); + cfg + } + + fn base_settings(&self, _rtc: &Rtc) { + // settings derived from esp-idf after basic boot + unsafe { + let rtc_cntl = &*esp32::RTC_CNTL::ptr(); + #[rustfmt::skip] + rtc_cntl.options0.modify(|_, w| w + .bias_core_force_pu().clear_bit() + .bias_core_folw_8m().set_bit() + .bias_i2c_force_pu().clear_bit() + .bias_i2c_folw_8m().set_bit() + .bias_force_nosleep().clear_bit() + .bias_sleep_folw_8m().set_bit() + .xtl_force_pu().clear_bit() + ); + #[rustfmt::skip] + rtc_cntl.reg.modify(|_, w| w + .force_pu().clear_bit() + .dboost_force_pu().clear_bit() + .dboost_force_pd().set_bit() + ); + #[rustfmt::skip] + rtc_cntl.pwc.modify(|_, w| w + .slowmem_force_pu().clear_bit() + .fastmem_force_pu().clear_bit() + .force_noiso().clear_bit() + .slowmem_force_noiso().clear_bit() + .fastmem_force_noiso().clear_bit() + ); + #[rustfmt::skip] + rtc_cntl.dig_pwc.modify(|_, w| w + .dg_wrap_force_pu().clear_bit() + .wifi_force_pu().clear_bit() + .wifi_force_pd().set_bit() + .inter_ram4_force_pu().clear_bit() + .inter_ram3_force_pu().clear_bit() + .inter_ram2_force_pu().clear_bit() + .inter_ram1_force_pu().clear_bit() + .inter_ram0_force_pu().clear_bit() + .rom0_force_pu().clear_bit() + .lslp_mem_force_pu().clear_bit() + ); + #[rustfmt::skip] + rtc_cntl.dig_iso.modify(|_, w| w + .dg_wrap_force_noiso().clear_bit() + .wifi_force_noiso().clear_bit() + .wifi_force_iso().set_bit() + .inter_ram4_force_noiso().clear_bit() + .inter_ram3_force_noiso().clear_bit() + .inter_ram2_force_noiso().clear_bit() + .inter_ram1_force_noiso().clear_bit() + .inter_ram0_force_noiso().clear_bit() + .rom0_force_noiso().clear_bit() + .dg_pad_force_unhold().clear_bit() + .dg_pad_force_noiso().clear_bit() + ); + #[rustfmt::skip] + rtc_cntl.int_ena.modify(|_, w| w + .brown_out_int_ena().set_bit() + ); + } + + } + + pub(super) fn apply(&self, rtc: &Rtc) { + self.base_settings(rtc); + // like esp-idf rtc_sleep_init() + unsafe { + let rtc_cntl = &*esp32::RTC_CNTL::ptr(); + + #[rustfmt::skip] + rtc_cntl.timer5.modify(|_, w| w + .min_slp_val().bits(RTC_CNTL_MIN_SLP_VAL_MIN) + // set rtc memory timer + .rtcmem_powerup_timer().bits(RTC_MEM_POWERUP_CYCLES) + .rtcmem_wait_timer().bits(RTC_MEM_WAIT_CYCLES) + ); + + #[rustfmt::skip] + rtc_cntl.timer3.modify(|_, w| w + // set rom&ram timer + .rom_ram_powerup_timer().bits(ROM_RAM_POWERUP_CYCLES) + .rom_ram_wait_timer().bits(ROM_RAM_WAIT_CYCLES) + // set wifi timer + .wifi_powerup_timer().bits(WIFI_POWERUP_CYCLES) + .wifi_wait_timer().bits(WIFI_WAIT_CYCLES) + ); + + #[rustfmt::skip] + rtc_cntl.timer4.modify(|_, w| w + // set rtc peri timer + .powerup_timer().bits(RTC_POWERUP_CYCLES) + .wait_timer().bits(RTC_WAIT_CYCLES) + // set digital wrap timer + .dg_wrap_powerup_timer().bits(DG_WRAP_POWERUP_CYCLES) + .dg_wrap_wait_timer().bits(DG_WRAP_WAIT_CYCLES) + ); + + #[rustfmt::skip] + rtc_cntl.dig_pwc.modify(|_, w| w + .lslp_mem_force_pu().bit(self.lslp_mem_inf_fpu()) + ); + + // remove all peripheral force power up flags + if self.lslp_meminf_pd() { + #[rustfmt::skip] + rtc_cntl.dig_pwc.modify(|_, w| w + .lslp_mem_force_pu().clear_bit() + ); + + #[rustfmt::skip] + rtc_cntl.pwc.modify(|_, w| w + .slowmem_force_pu().clear_bit() + .fastmem_force_pu().clear_bit() + ); + + // esp-idf also clears these: + #[rustfmt::skip] + (&*esp32::DPORT::ptr()).mem_pd_mask.modify(|_, w| w + .lslp_mem_pd_mask().clear_bit() + ); + #[rustfmt::skip] + (&*esp32::I2S0::ptr()).pd_conf.modify(|_, w| w + .plc_mem_force_pu().clear_bit() + .fifo_force_pu().clear_bit() + ); + #[rustfmt::skip] + (&*esp32::BB::ptr()).bbpd_ctrl.modify(|_, w| w + .fft_force_pu().clear_bit() + .dc_est_force_pu().clear_bit() + ); + #[rustfmt::skip] + (&*esp32::NRX::ptr()).nrxpd_ctrl.modify(|_, w| w + .rx_rot_force_pu().clear_bit() + .vit_force_pu().clear_bit() + .demap_force_pu().clear_bit() + ); + // #[rustfmt::skip] + // (&*esp32::FE::ptr()).gen_ctrl.modify(|_, w| w + // .iq_est_force_pu().clear_bit() + // ); + // #[rustfmt::skip] + // (&*esp32::FE2::ptr()).tx_interp_ctrl.modify(|_, w| w + // .inf_force_pu().clear_bit() + // ); + } + + #[rustfmt::skip] + rtc_cntl.pwc.modify(|_, w| w + .slowmem_folw_cpu().bit(self.rtc_mem_inf_follow_cpu()) + .fastmem_folw_cpu().bit(self.rtc_mem_inf_follow_cpu()) + // TODO: does this need to be optional based on if there is something stored in fastmem? + //.fastmem_pd_en().bit(self.rtc_fastmem_pd_en()) + .fastmem_force_pu().bit(!self.rtc_fastmem_pd_en()) + .fastmem_force_lpu().bit(!self.rtc_fastmem_pd_en()) + .fastmem_force_noiso().bit(!self.rtc_fastmem_pd_en()) + .slowmem_pd_en().bit(self.rtc_slowmem_pd_en()) + .slowmem_force_pu().bit(!self.rtc_slowmem_pd_en()) + .slowmem_force_noiso().bit(!self.rtc_slowmem_pd_en()) + .slowmem_force_lpu().bit(!self.rtc_slowmem_pd_en()) + .pd_en().bit(self.rtc_peri_pd_en()) + ); + + // #[rustfmt::skip] + // rtc_cntl.dig_pwc.modify(|_, w| w + // .wifi_pd_en().bit(self.wifi_pd_en()) + // .rom0_pd_en().bit(self.rom_mem_pd_en()) + // ); + + if self.deep_slp() { + #[rustfmt::skip] + rtc_cntl.dig_iso.modify(|_, w| w + .dg_wrap_force_noiso().clear_bit() + .wifi_force_noiso().clear_bit() + .dg_pad_force_iso().clear_bit() + .dg_pad_force_noiso().clear_bit() + ); + #[rustfmt::skip] + rtc_cntl.dig_pwc.modify(|_, w| w + .dg_wrap_pd_en().set_bit() + .dg_wrap_force_pu().clear_bit() + .dg_wrap_force_pd().clear_bit() + ); + #[rustfmt::skip] + rtc_cntl.options0.modify(|_, w| w + .bias_force_nosleep().clear_bit() + .bb_i2c_force_pu().clear_bit() + ); + #[rustfmt::skip] + rtc_cntl.ana_conf.modify(|_, w| w + .ckgen_i2c_pu().clear_bit() + .pll_i2c_pu().clear_bit() + .rfrx_pbus_pu().clear_bit() + .txrf_i2c_pu().clear_bit() + ); + } else { + #[rustfmt::skip] + rtc_cntl.dig_pwc.modify(|_, w| w + .dg_wrap_pd_en().clear_bit() + ); + #[rustfmt::skip] + rtc_cntl.bias_conf.modify(|_, w| w + .dbg_atten().bits(0) + ); + } + + #[rustfmt::skip] + rtc_cntl.options0.modify(|_, w| w + .xtl_force_pu().bit(self.xtal_fpu()) + ); + + #[rustfmt::skip] + rtc_cntl.clk_conf.modify(|_, w| w + .ck8m_force_pu().bit(!self.int_8m_pd_en()) + ); + + // enable VDDSDIO control by state machine + #[rustfmt::skip] + rtc_cntl.sdio_conf.modify(|_, w| w + .sdio_force().clear_bit() + .sdio_pd_en().bit(self.vddsdio_pd_en()) + ); + + #[rustfmt::skip] + rtc_cntl.reg.modify(|_, w| w + .dbias_slp().bits(self.rtc_dbias_slp()) + .dbias_wak().bits(self.rtc_dbias_wak()) + .dig_dbias_slp().bits(self.dig_dbias_slp()) + .dig_dbias_wak().bits(self.dig_dbias_wak()) + ); + + #[rustfmt::skip] + rtc_cntl.slp_reject_conf.modify(|_, w| w + .deep_slp_reject_en().bit(self.deep_slp_reject()) + .light_slp_reject_en().bit(self.light_slp_reject()) + ); + } + } +} diff --git a/esp-hal-common/src/rtc_cntl/sleep.rs b/esp-hal-common/src/rtc_cntl/sleep.rs new file mode 100644 index 00000000000..ba8b9e4723d --- /dev/null +++ b/esp-hal-common/src/rtc_cntl/sleep.rs @@ -0,0 +1,102 @@ +use core::time::Duration; + +use crate::Rtc; + +#[cfg_attr(esp32, path = "rtc/esp32_sleep.rs")] +mod rtc_sleep; +pub use rtc_sleep::*; + +#[cfg(esp32)] +use esp32 as pac; + +#[derive(Debug, Default, Clone, Copy)] +struct TimerWakeSource { + duration: Duration, +} + +bitfield::bitfield! { + #[derive(Default, Clone, Copy)] + pub struct WakeTriggers(u16); + impl Debug; + /// EXT0 GPIO wakeup + pub ext0, set_ext0: 0; + /// EXT1 GPIO wakeup + pub ext1, set_ext1: 1; + /// GPIO wakeup (light sleep only) + pub gpio, set_gpio: 2; + /// Timer wakeup + pub timer, set_timer: 3; + /// SDIO wakeup (light sleep only) + pub sdio, set_sdio: 4; + /// MAC wakeup (light sleep only) + pub mac, set_mac: 5; + /// UART0 wakeup (light sleep only) + pub uart0, set_uart0: 6; + /// UART1 wakeup (light sleep only) + pub uart1, set_uart1: 7; + /// Touch wakeup + pub touch, set_touch: 8; + /// ULP wakeup + pub ulp, set_ulp: 9; + /// BT wakeup (light sleep only) + pub bt, set_bt: 10; +} + +trait WakeSource { + fn prepare(&self, rtc: &Rtc); +} + +#[derive(Debug, Default)] +pub struct Sleep { + sleep_config: RtcSleepConfig, + wakeup_triggers: WakeTriggers, + timer_wake: Option, +} + +impl Sleep { + pub fn new() -> Sleep { + Self { + ..Default::default() + } + } + + pub fn deep() -> Sleep { + Self { + sleep_config: RtcSleepConfig::deep(), + ..Default::default() + } + } + + pub fn timer(&mut self, duration: Duration) { + self.timer_wake = Some(TimerWakeSource { duration }); + self.wakeup_triggers.set_timer(true); + } + + pub fn sleep(&self, rtc: &mut Rtc, delay: &mut crate::Delay) { + self.sleep_config.apply(rtc); + if let Some(timer) = &self.timer_wake { + timer.prepare(rtc); + } + use embedded_hal::blocking::delay::DelayMs; + delay.delay_ms(100u32); + unsafe { + let rtc_cntl = &*pac::RTC_CNTL::ptr(); + + rtc_cntl + .reset_state + .modify(|_, w| w.procpu_stat_vector_sel().set_bit()); + + // set bits for what can wake us up + rtc_cntl + .wakeup_state + .modify(|_, w| w.wakeup_ena().bits(self.wakeup_triggers.0.into())); + + // TODO: remove this! + // esp_reg_dump::rtc_cntl::dump_all(); + + rtc_cntl + .state0 + .write(|w| w.sleep_en().set_bit().slp_wakeup().set_bit()); + } + } +} From 22493afee19b26325c5c1ccfa7953386f9528276 Mon Sep 17 00:00:00 2001 From: liebman Date: Sun, 4 Jun 2023 10:23:08 -0700 Subject: [PATCH 02/20] move to list of wakeup sources --- .../src/rtc_cntl/rtc/esp32_sleep.rs | 21 ++++-- esp-hal-common/src/rtc_cntl/sleep.rs | 73 ++++++++++++++----- 2 files changed, 70 insertions(+), 24 deletions(-) diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs index 8b066fd0d28..adf3a329940 100644 --- a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs @@ -1,5 +1,6 @@ -use super::{TimerWakeSource, WakeSource}; +use super::{Ext0WakeupSource, TimerWakeupSource, WakeSource, WakeTriggers}; use crate::{ + gpio::{Pin, RTCPin}, rtc_cntl::{Clock, RtcClock}, Rtc, }; @@ -38,8 +39,9 @@ pub const DG_WRAP_WAIT_CYCLES: u16 = RTC_CNTL_OTHER_BLOCKS_WAIT_CYCLES; pub const RTC_CNTL_CK8M_WAIT_DEFAULT: u8 = 20; pub const RTC_CK8M_ENABLE_WAIT_DEFAULT: u8 = 5; -impl WakeSource for TimerWakeSource { - fn prepare(&self, rtc: &Rtc) { +impl WakeSource for TimerWakeupSource { + fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers) { + triggers.set_timer(true); let rtc_cntl = unsafe { &*esp32::RTC_CNTL::ptr() }; let clock_freq = RtcClock::get_slow_freq(); // TODO: maybe add sleep time adjustlemnt like idf @@ -62,6 +64,16 @@ impl WakeSource for TimerWakeSource { } } +impl<'a, EXT0: Pin + RTCPin> WakeSource for Ext0WakeupSource<'a, EXT0> { + fn prepare(&self, _rtc: &Rtc, triggers: &mut WakeTriggers) { + triggers.set_ext0(true); + // map pin# to rtc pin# + // set pin register field + // set level register field + todo!(); + } +} + bitfield::bitfield! { #[derive(Clone, Copy)] pub struct RtcSleepConfig(u32); @@ -127,7 +139,7 @@ impl RtcSleepConfig { let mut cfg = Self::default(); cfg.set_deep_slp(true); cfg.set_dig_dbias_slp(RTC_CNTL_DBIAS_0V90); - //cfg.set_rtc_dbias_slp(RTC_CNTL_DBIAS_0V90); + // cfg.set_rtc_dbias_slp(RTC_CNTL_DBIAS_0V90); cfg.set_vddsdio_pd_en(true); cfg.set_int_8m_pd_en(true); cfg.set_xtal_fpu(false); @@ -199,7 +211,6 @@ impl RtcSleepConfig { .brown_out_int_ena().set_bit() ); } - } pub(super) fn apply(&self, rtc: &Rtc) { diff --git a/esp-hal-common/src/rtc_cntl/sleep.rs b/esp-hal-common/src/rtc_cntl/sleep.rs index ba8b9e4723d..8de11a9bec5 100644 --- a/esp-hal-common/src/rtc_cntl/sleep.rs +++ b/esp-hal-common/src/rtc_cntl/sleep.rs @@ -1,18 +1,44 @@ use core::time::Duration; -use crate::Rtc; +use crate::{ + gpio::{Pin, RTCPin}, + Rtc, +}; #[cfg_attr(esp32, path = "rtc/esp32_sleep.rs")] mod rtc_sleep; -pub use rtc_sleep::*; - #[cfg(esp32)] use esp32 as pac; +pub use rtc_sleep::*; + +#[derive(Debug, Default, Clone, Copy)] +pub enum WakeupLevel { + Low, + #[default] + High, +} #[derive(Debug, Default, Clone, Copy)] -struct TimerWakeSource { +pub struct TimerWakeupSource { duration: Duration, } +impl TimerWakeupSource { + pub fn new(duration: Duration) -> Self { + Self { duration } + } +} + +#[allow(unused)] +#[derive(Debug)] +pub struct Ext0WakeupSource<'a, P: Pin + RTCPin> { + pin: &'a mut P, + level: WakeupLevel, +} +impl<'a, P: Pin + RTCPin> Ext0WakeupSource<'a, P> { + pub fn new(pin: &'a mut P, level: WakeupLevel) -> Self { + Self { pin, level } + } +} bitfield::bitfield! { #[derive(Default, Clone, Copy)] @@ -42,40 +68,49 @@ bitfield::bitfield! { pub bt, set_bt: 10; } -trait WakeSource { - fn prepare(&self, rtc: &Rtc); +pub trait WakeSource { + fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers); } -#[derive(Debug, Default)] -pub struct Sleep { +// non-alloc version? +extern crate alloc; +#[derive(Debug)] +pub struct Sleep<'a, W: WakeSource> { sleep_config: RtcSleepConfig, - wakeup_triggers: WakeTriggers, - timer_wake: Option, + wake_sources: alloc::vec::Vec<&'a W>, } -impl Sleep { - pub fn new() -> Sleep { +impl<'a, W: WakeSource> Default for Sleep<'a, W> { + fn default() -> Self { + Self { + sleep_config: Default::default(), + wake_sources: Default::default(), + } + } +} +impl<'a, W: WakeSource> Sleep<'a, W> { + pub fn new() -> Sleep<'a, W> { Self { ..Default::default() } } - pub fn deep() -> Sleep { + pub fn deep() -> Sleep<'a, W> { Self { sleep_config: RtcSleepConfig::deep(), ..Default::default() } } - pub fn timer(&mut self, duration: Duration) { - self.timer_wake = Some(TimerWakeSource { duration }); - self.wakeup_triggers.set_timer(true); + pub fn add_wakeup_source(&mut self, wake_source: &'a W) { + self.wake_sources.push(wake_source) } pub fn sleep(&self, rtc: &mut Rtc, delay: &mut crate::Delay) { self.sleep_config.apply(rtc); - if let Some(timer) = &self.timer_wake { - timer.prepare(rtc); + let mut wakeup_triggers = WakeTriggers::default(); + for wake_source in &self.wake_sources { + wake_source.prepare(rtc, &mut wakeup_triggers) } use embedded_hal::blocking::delay::DelayMs; delay.delay_ms(100u32); @@ -89,7 +124,7 @@ impl Sleep { // set bits for what can wake us up rtc_cntl .wakeup_state - .modify(|_, w| w.wakeup_ena().bits(self.wakeup_triggers.0.into())); + .modify(|_, w| w.wakeup_ena().bits(wakeup_triggers.0.into())); // TODO: remove this! // esp_reg_dump::rtc_cntl::dump_all(); From 905abecc3e6ca37cffaed657800b74ec78396371 Mon Sep 17 00:00:00 2001 From: liebman Date: Sun, 4 Jun 2023 12:54:10 -0700 Subject: [PATCH 03/20] improve Ext0WakeupSource - still WIP --- .../src/rtc_cntl/rtc/esp32_sleep.rs | 23 ++++-- esp-hal-common/src/rtc_cntl/sleep.rs | 77 +++++++++++++++---- 2 files changed, 77 insertions(+), 23 deletions(-) diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs index adf3a329940..e0879cae04c 100644 --- a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs @@ -1,7 +1,7 @@ use super::{Ext0WakeupSource, TimerWakeupSource, WakeSource, WakeTriggers}; use crate::{ - gpio::{Pin, RTCPin}, - rtc_cntl::{Clock, RtcClock}, + gpio::Pin, + rtc_cntl::{sleep::WakeupLevel, Clock, RtcClock}, Rtc, }; @@ -64,13 +64,22 @@ impl WakeSource for TimerWakeupSource { } } -impl<'a, EXT0: Pin + RTCPin> WakeSource for Ext0WakeupSource<'a, EXT0> { +impl<'a, P: Pin> WakeSource for Ext0WakeupSource<'a, P> { fn prepare(&self, _rtc: &Rtc, triggers: &mut WakeTriggers) { triggers.set_ext0(true); - // map pin# to rtc pin# - // set pin register field - // set level register field - todo!(); + let pin = self.to_rtc_pin().unwrap(); + unsafe { + // TODO: set pin to RTC function + + let rtc_io = &*esp32::RTC_IO::ptr(); + // set pin register field + rtc_io.ext_wakeup0.modify(|_, w| w.sel().bits(pin)); + // set level register field + let rtc_cntl = &*esp32::RTC_CNTL::ptr(); + rtc_cntl + .ext_wakeup_conf + .modify(|_r, w| w.ext_wakeup0_lv().bit(self.level == WakeupLevel::High)); + } } } diff --git a/esp-hal-common/src/rtc_cntl/sleep.rs b/esp-hal-common/src/rtc_cntl/sleep.rs index 8de11a9bec5..3cdc86c24da 100644 --- a/esp-hal-common/src/rtc_cntl/sleep.rs +++ b/esp-hal-common/src/rtc_cntl/sleep.rs @@ -1,9 +1,6 @@ use core::time::Duration; -use crate::{ - gpio::{Pin, RTCPin}, - Rtc, -}; +use crate::{gpio::Pin, Rtc}; #[cfg_attr(esp32, path = "rtc/esp32_sleep.rs")] mod rtc_sleep; @@ -11,7 +8,7 @@ mod rtc_sleep; use esp32 as pac; pub use rtc_sleep::*; -#[derive(Debug, Default, Clone, Copy)] +#[derive(Debug, Default, Clone, Copy, PartialEq)] pub enum WakeupLevel { Low, #[default] @@ -22,24 +19,73 @@ pub enum WakeupLevel { pub struct TimerWakeupSource { duration: Duration, } + impl TimerWakeupSource { pub fn new(duration: Duration) -> Self { Self { duration } } } +#[derive(Debug, Clone, Copy)] +pub enum Error { + NotRtcPin, +} + #[allow(unused)] #[derive(Debug)] -pub struct Ext0WakeupSource<'a, P: Pin + RTCPin> { +// TODO: restrict to RTCPin as well (when its implemented on RTC pins) +pub struct Ext0WakeupSource<'a, P: Pin> { pin: &'a mut P, level: WakeupLevel, } -impl<'a, P: Pin + RTCPin> Ext0WakeupSource<'a, P> { + +impl<'a, P: Pin> Ext0WakeupSource<'a, P> { pub fn new(pin: &'a mut P, level: WakeupLevel) -> Self { Self { pin, level } } + // TODO: esp32 only! - needs to be re-factored + fn to_rtc_pin(&self) -> Result { + match self.pin.number() { + 0 => Ok(11), + 2 => Ok(12), + 4 => Ok(10), + 12 => Ok(15), + 13 => Ok(14), + 14 => Ok(16), + 15 => Ok(13), + 25 => Ok(6), + 26 => Ok(7), + 27 => Ok(17), + 32 => Ok(9), + 33 => Ok(8), + 34 => Ok(4), + 35 => Ok(5), + 36 => Ok(0), + 37 => Ok(1), + 38 => Ok(2), + 39 => Ok(3), + _ => Err(Error::NotRtcPin), + } + } } - +// RTCIO_GPIO0_CHANNEL, //GPIO0 +// RTCIO_GPIO2_CHANNEL, //GPIO2 +// RTCIO_GPIO4_CHANNEL, //GPIO4 +// RTCIO_GPIO12_CHANNEL, //GPIO12 +// RTCIO_GPIO13_CHANNEL, //GPIO13 +// RTCIO_GPIO14_CHANNEL, //GPIO14 +// RTCIO_GPIO15_CHANNEL, //GPIO15 +// RTCIO_GPIO25_CHANNEL, //GPIO25 +// RTCIO_GPIO26_CHANNEL, //GPIO26 +// RTCIO_GPIO27_CHANNEL, //GPIO27 +// RTCIO_GPIO32_CHANNEL, //GPIO32 +// RTCIO_GPIO33_CHANNEL, //GPIO33 +// RTCIO_GPIO34_CHANNEL, //GPIO34 +// RTCIO_GPIO35_CHANNEL, //GPIO35 +// RTCIO_GPIO36_CHANNEL, //GPIO36 +// RTCIO_GPIO37_CHANNEL, //GPIO37 +// RTCIO_GPIO38_CHANNEL, //GPIO38 +// RTCIO_GPIO39_CHANNEL, //GPIO39 bitfield::bitfield! { #[derive(Default, Clone, Copy)] pub struct WakeTriggers(u16); @@ -74,13 +120,12 @@ pub trait WakeSource { // non-alloc version? extern crate alloc; -#[derive(Debug)] -pub struct Sleep<'a, W: WakeSource> { +pub struct Sleep<'a> { sleep_config: RtcSleepConfig, - wake_sources: alloc::vec::Vec<&'a W>, + wake_sources: alloc::vec::Vec<&'a dyn WakeSource>, } -impl<'a, W: WakeSource> Default for Sleep<'a, W> { +impl<'a> Default for Sleep<'a> { fn default() -> Self { Self { sleep_config: Default::default(), @@ -88,21 +133,21 @@ impl<'a, W: WakeSource> Default for Sleep<'a, W> { } } } -impl<'a, W: WakeSource> Sleep<'a, W> { - pub fn new() -> Sleep<'a, W> { +impl<'a> Sleep<'a> { + pub fn new() -> Self { Self { ..Default::default() } } - pub fn deep() -> Sleep<'a, W> { + pub fn deep() -> Self { Self { sleep_config: RtcSleepConfig::deep(), ..Default::default() } } - pub fn add_wakeup_source(&mut self, wake_source: &'a W) { + pub fn add_wakeup_source(&mut self, wake_source: &'a impl WakeSource) { self.wake_sources.push(wake_source) } From cf7dc6dae2e5f154915f2ddb6d32d0fd81093594 Mon Sep 17 00:00:00 2001 From: liebman Date: Thu, 8 Jun 2023 07:41:27 -0700 Subject: [PATCH 04/20] add deep sleep with timer wakeup example add Ext0 wakeup source (WIP/Non-working) --- CHANGELOG.md | 1 + esp-hal-common/Cargo.toml | 13 +-- .../src/rtc_cntl/rtc/esp32_sleep.rs | 97 ++++++++++++++++++- esp-hal-common/src/rtc_cntl/sleep.rs | 18 ++-- esp32-hal/examples/sleep_timer.rs | 95 ++++++++++++++++++ 5 files changed, 207 insertions(+), 17 deletions(-) create mode 100644 esp32-hal/examples/sleep_timer.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e48f0b2ca5..403df615787 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add initial LP-IO support for ESP32-C6 (#639) +- Implement sleep with some wakeup methods for `esp32` (#574) ### Changed diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 185b4c864b8..824cc96c45e 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -23,6 +23,7 @@ embedded-hal-1 = { version = "=1.0.0-alpha.11", optional = true, package = embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true } esp-synopsys-usb-otg = { version = "0.3.2", optional = true, features = ["fs", "esp32sx"] } fugit = "0.3.7" +heapless = "0.7.16" log = "=0.4.18" lock_api = { version = "0.4.10", optional = true } nb = "1.1.0" @@ -65,12 +66,12 @@ basic-toml = "0.1.2" serde = { version = "1.0.164", features = ["derive"] } [features] -esp32 = ["esp32/rt" , "xtensa", "xtensa-lx/esp32", "xtensa-lx-rt/esp32", "lock_api", "procmacros/esp32"] -esp32c2 = ["esp32c2/rt", "riscv", "procmacros/esp32c2"] -esp32c3 = ["esp32c3/rt", "riscv", "procmacros/esp32c3"] -esp32c6 = ["esp32c6/rt", "riscv", "procmacros/esp32c6"] -esp32h2 = ["esp32h2/rt", "riscv", "procmacros/esp32h2"] -esp32s2 = ["esp32s2/rt", "xtensa", "xtensa-lx/esp32s2", "xtensa-lx-rt/esp32s2", "esp-synopsys-usb-otg", "usb-device", "procmacros/esp32s2"] +esp32 = ["esp32/rt", "xtensa", "xtensa-lx/esp32", "xtensa-lx-rt/esp32", "lock_api", "procmacros/esp32"] +esp32c2 = ["esp32c2/rt", "riscv", "procmacros/esp32c2"] +esp32c3 = ["esp32c3/rt", "riscv", "procmacros/esp32c3"] +esp32c6 = ["esp32c6/rt", "riscv", "procmacros/esp32c6"] +esp32h2 = ["esp32h2/rt", "riscv", "procmacros/esp32h2"] +esp32s2 = ["esp32s2/rt", "xtensa", "xtensa-lx/esp32s2", "xtensa-lx-rt/esp32s2", "esp-synopsys-usb-otg", "usb-device", "procmacros/esp32s2"] esp32s3 = ["esp32s3/rt", "xtensa", "xtensa-lx/esp32s3", "xtensa-lx-rt/esp32s3", "lock_api", "esp-synopsys-usb-otg", "usb-device", "procmacros/esp32s3"] esp32_40mhz = [] diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs index e0879cae04c..a04e5adc990 100644 --- a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs @@ -40,7 +40,7 @@ pub const RTC_CNTL_CK8M_WAIT_DEFAULT: u8 = 20; pub const RTC_CK8M_ENABLE_WAIT_DEFAULT: u8 = 5; impl WakeSource for TimerWakeupSource { - fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers) { + fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers, _sleep_config: &mut RtcSleepConfig) { triggers.set_timer(true); let rtc_cntl = unsafe { &*esp32::RTC_CNTL::ptr() }; let clock_freq = RtcClock::get_slow_freq(); @@ -65,13 +65,102 @@ impl WakeSource for TimerWakeupSource { } impl<'a, P: Pin> WakeSource for Ext0WakeupSource<'a, P> { - fn prepare(&self, _rtc: &Rtc, triggers: &mut WakeTriggers) { + fn prepare(&self, _rtc: &Rtc, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig) { triggers.set_ext0(true); + sleep_config.set_rtc_peri_pd_en(false); let pin = self.to_rtc_pin().unwrap(); unsafe { - // TODO: set pin to RTC function - + // TODO: set pin to RTC function (should be handled by RTCPin impl) let rtc_io = &*esp32::RTC_IO::ptr(); + // TODO: this should be implemented by RTCPin! + match self.to_rtc_pin().unwrap() { + 0 => { + rtc_io + .sensor_pads + .modify(|_, w| w.sense1_mux_sel().bit(true)); + rtc_io.sensor_pads.modify(|_, w| w.sense1_fun_sel().bits(0)); + } + 1 => { + rtc_io + .sensor_pads + .modify(|_, w| w.sense2_mux_sel().bit(true)); + rtc_io.sensor_pads.modify(|_, w| w.sense2_fun_sel().bits(0)); + } + 2 => { + rtc_io + .sensor_pads + .modify(|_, w| w.sense3_mux_sel().bit(true)); + rtc_io.sensor_pads.modify(|_, w| w.sense3_fun_sel().bits(0)); + } + 3 => { + rtc_io + .sensor_pads + .modify(|_, w| w.sense4_mux_sel().bit(true)); + rtc_io.sensor_pads.modify(|_, w| w.sense4_fun_sel().bits(0)); + } + 4 => { + rtc_io.adc_pad.modify(|_, w| w.adc1_mux_sel().bit(true)); + rtc_io.adc_pad.modify(|_, w| w.adc1_fun_sel().bits(0)); + } + 5 => { + rtc_io.adc_pad.modify(|_, w| w.adc2_mux_sel().bit(true)); + rtc_io.adc_pad.modify(|_, w| w.adc2_fun_sel().bits(0)); + } + 6 => { + rtc_io.pad_dac1.modify(|_, w| w.pdac1_mux_sel().bit(true)); + rtc_io.pad_dac1.modify(|_, w| w.pdac1_fun_sel().bits(0)); + } + 7 => { + rtc_io.pad_dac2.modify(|_, w| w.pdac2_mux_sel().bit(true)); + rtc_io.pad_dac2.modify(|_, w| w.pdac2_fun_sel().bits(0)); + } + 8 => { + rtc_io + .xtal_32k_pad + .modify(|_, w| w.x32n_mux_sel().bit(true)); + rtc_io.xtal_32k_pad.modify(|_, w| w.x32n_fun_sel().bits(0)); + } + 9 => { + rtc_io + .xtal_32k_pad + .modify(|_, w| w.x32p_mux_sel().bit(true)); + rtc_io.xtal_32k_pad.modify(|_, w| w.x32p_fun_sel().bits(0)); + } + 10 => { + rtc_io.touch_pad0.modify(|_, w| w.mux_sel().bit(true)); + rtc_io.touch_pad0.modify(|_, w| w.fun_sel().bits(0)); + } + 11 => { + rtc_io.touch_pad1.modify(|_, w| w.mux_sel().bit(true)); + rtc_io.touch_pad1.modify(|_, w| w.fun_sel().bits(0)); + } + 12 => { + rtc_io.touch_pad2.modify(|_, w| w.mux_sel().bit(true)); + rtc_io.touch_pad2.modify(|_, w| w.fun_sel().bits(0)); + } + 13 => { + rtc_io.touch_pad3.modify(|_, w| w.mux_sel().bit(true)); + rtc_io.touch_pad3.modify(|_, w| w.fun_sel().bits(0)); + } + 14 => { + rtc_io.touch_pad4.modify(|_, w| w.mux_sel().bit(true)); + rtc_io.touch_pad4.modify(|_, w| w.fun_sel().bits(0)); + } + 15 => { + rtc_io.touch_pad5.modify(|_, w| w.mux_sel().bit(true)); + rtc_io.touch_pad5.modify(|_, w| w.fun_sel().bits(0)); + } + 16 => { + rtc_io.touch_pad6.modify(|_, w| w.mux_sel().bit(true)); + rtc_io.touch_pad6.modify(|_, w| w.fun_sel().bits(0)); + } + 17 => { + rtc_io.touch_pad7.modify(|_, w| w.mux_sel().bit(true)); + rtc_io.touch_pad7.modify(|_, w| w.fun_sel().bits(0)); + } + _ => panic!("invalid RTC pin"), + }; + // set pin register field rtc_io.ext_wakeup0.modify(|_, w| w.sel().bits(pin)); // set level register field diff --git a/esp-hal-common/src/rtc_cntl/sleep.rs b/esp-hal-common/src/rtc_cntl/sleep.rs index 3cdc86c24da..a59e68632fa 100644 --- a/esp-hal-common/src/rtc_cntl/sleep.rs +++ b/esp-hal-common/src/rtc_cntl/sleep.rs @@ -29,6 +29,7 @@ impl TimerWakeupSource { #[derive(Debug, Clone, Copy)] pub enum Error { NotRtcPin, + TooManyWakeupSources, } #[allow(unused)] @@ -43,7 +44,7 @@ impl<'a, P: Pin> Ext0WakeupSource<'a, P> { pub fn new(pin: &'a mut P, level: WakeupLevel) -> Self { Self { pin, level } } - // TODO: esp32 only! - needs to be re-factored + // TODO: esp32 only! - needs to be re-factored (should be in RTCPin impl) fn to_rtc_pin(&self) -> Result { match self.pin.number() { 0 => Ok(11), @@ -115,14 +116,14 @@ bitfield::bitfield! { } pub trait WakeSource { - fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers); + fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig); } // non-alloc version? extern crate alloc; pub struct Sleep<'a> { sleep_config: RtcSleepConfig, - wake_sources: alloc::vec::Vec<&'a dyn WakeSource>, + wake_sources: heapless::Vec<&'a dyn WakeSource, 16>, } impl<'a> Default for Sleep<'a> { @@ -147,15 +148,18 @@ impl<'a> Sleep<'a> { } } - pub fn add_wakeup_source(&mut self, wake_source: &'a impl WakeSource) { - self.wake_sources.push(wake_source) + pub fn add_wakeup_source(&mut self, wake_source: &'a impl WakeSource) -> Result<(), Error> { + self.wake_sources + .push(wake_source) + .map_err(|_| Error::TooManyWakeupSources)?; + Ok(()) } - pub fn sleep(&self, rtc: &mut Rtc, delay: &mut crate::Delay) { + pub fn sleep(&mut self, rtc: &mut Rtc, delay: &mut crate::Delay) { self.sleep_config.apply(rtc); let mut wakeup_triggers = WakeTriggers::default(); for wake_source in &self.wake_sources { - wake_source.prepare(rtc, &mut wakeup_triggers) + wake_source.prepare(rtc, &mut wakeup_triggers, &mut self.sleep_config) } use embedded_hal::blocking::delay::DelayMs; delay.delay_ms(100u32); diff --git a/esp32-hal/examples/sleep_timer.rs b/esp32-hal/examples/sleep_timer.rs new file mode 100644 index 00000000000..3d9fb74d25e --- /dev/null +++ b/esp32-hal/examples/sleep_timer.rs @@ -0,0 +1,95 @@ +//! Demonstrates deep sleep with timer wakeup + +#![no_std] +#![no_main] + +extern crate alloc; + +use core::time::Duration; + +use esp32_hal as hal; +use esp_backtrace as _; +use esp_println::println; +use hal::{ + clock::ClockControl, + entry, + peripherals::Peripherals, + prelude::*, + rtc_cntl::{ + get_reset_reason, + get_wakeup_cause, + sleep::{Sleep, TimerWakeupSource}, + SocResetReason, + }, + timer::TimerGroup, + Delay, + Rtc, +}; + +#[global_allocator] +static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); + +fn init_heap() { + const HEAP_SIZE: usize = 32 * 1024; + + extern "C" { + static mut _heap_start: u32; + #[cfg(target_arch = "xtensa")] + static mut _heap_end: u32; + } + + unsafe { + let heap_start = &_heap_start as *const _ as usize; + #[cfg(target_arch = "xtensa")] + let heap_end = &_heap_end as *const _ as usize; + #[cfg(target_arch = "xtensa")] + assert!( + heap_end - heap_start > HEAP_SIZE, + "Not enough available heap memory." + ); + ALLOCATOR.init(heap_start as *mut u8, HEAP_SIZE); + } +} + +#[entry] +fn main() -> ! { + init_heap(); + let peripherals = Peripherals::take(); + let mut system = peripherals.DPORT.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + // Disable the RTC and TIMG watchdog timers + let mut rtc = Rtc::new(peripherals.RTC_CNTL); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + println!("up and runnning!"); + let reason = get_reset_reason(hal::Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); + println!("reset reason: {:?}", reason); + let wake_reason = get_wakeup_cause(); + println!("wake reason: {:?}", wake_reason); + + let mut delay = Delay::new(&clocks); + + let mut sleep = Sleep::deep(); + let timer = TimerWakeupSource::new(Duration::from_secs(30)); + sleep.add_wakeup_source(&timer).unwrap(); + println!("sleeping!"); + delay.delay_ms(100u32); + sleep.sleep(&mut rtc, &mut delay); + unreachable!(); +} From 44c101460a3a9cd1cbfa14549988b7e48fea96f0 Mon Sep 17 00:00:00 2001 From: liebman Date: Thu, 8 Jun 2023 09:03:25 -0700 Subject: [PATCH 05/20] removed alloc (using heapless now) --- esp-hal-common/src/rtc_cntl/sleep.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/esp-hal-common/src/rtc_cntl/sleep.rs b/esp-hal-common/src/rtc_cntl/sleep.rs index a59e68632fa..48451ec5a73 100644 --- a/esp-hal-common/src/rtc_cntl/sleep.rs +++ b/esp-hal-common/src/rtc_cntl/sleep.rs @@ -119,8 +119,6 @@ pub trait WakeSource { fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig); } -// non-alloc version? -extern crate alloc; pub struct Sleep<'a> { sleep_config: RtcSleepConfig, wake_sources: heapless::Vec<&'a dyn WakeSource, 16>, From dc382aa04d56280c6de84c526aa5507a7d6eea1e Mon Sep 17 00:00:00 2001 From: liebman Date: Thu, 8 Jun 2023 12:56:44 -0700 Subject: [PATCH 06/20] Sleep: ext0 wakeup working --- .../src/rtc_cntl/rtc/esp32_sleep.rs | 166 ++++++++++++------ esp-hal-common/src/rtc_cntl/sleep.rs | 21 ++- 2 files changed, 130 insertions(+), 57 deletions(-) diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs index a04e5adc990..46d6172b89a 100644 --- a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs @@ -40,7 +40,8 @@ pub const RTC_CNTL_CK8M_WAIT_DEFAULT: u8 = 20; pub const RTC_CK8M_ENABLE_WAIT_DEFAULT: u8 = 5; impl WakeSource for TimerWakeupSource { - fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers, _sleep_config: &mut RtcSleepConfig) { + fn add(&self, _sleep_config: &mut RtcSleepConfig) {} + fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers) { triggers.set_timer(true); let rtc_cntl = unsafe { &*esp32::RTC_CNTL::ptr() }; let clock_freq = RtcClock::get_slow_freq(); @@ -65,9 +66,11 @@ impl WakeSource for TimerWakeupSource { } impl<'a, P: Pin> WakeSource for Ext0WakeupSource<'a, P> { - fn prepare(&self, _rtc: &Rtc, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig) { - triggers.set_ext0(true); + fn add(&self, sleep_config: &mut RtcSleepConfig) { sleep_config.set_rtc_peri_pd_en(false); + } + fn prepare(&self, _rtc: &Rtc, triggers: &mut WakeTriggers) { + triggers.set_ext0(true); let pin = self.to_rtc_pin().unwrap(); unsafe { // TODO: set pin to RTC function (should be handled by RTCPin impl) @@ -75,88 +78,148 @@ impl<'a, P: Pin> WakeSource for Ext0WakeupSource<'a, P> { // TODO: this should be implemented by RTCPin! match self.to_rtc_pin().unwrap() { 0 => { - rtc_io - .sensor_pads - .modify(|_, w| w.sense1_mux_sel().bit(true)); - rtc_io.sensor_pads.modify(|_, w| w.sense1_fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.sensor_pads.modify(|_, w| { w + .sense1_fun_ie().bit(true) + .sense1_mux_sel().bit(true) + .sense1_fun_sel().bits(0) + }); } 1 => { - rtc_io - .sensor_pads - .modify(|_, w| w.sense2_mux_sel().bit(true)); - rtc_io.sensor_pads.modify(|_, w| w.sense2_fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.sensor_pads.modify(|_, w| { w + .sense2_fun_ie().bit(true) + .sense2_mux_sel().bit(true) + .sense2_fun_sel().bits(0) + }); } 2 => { - rtc_io - .sensor_pads - .modify(|_, w| w.sense3_mux_sel().bit(true)); - rtc_io.sensor_pads.modify(|_, w| w.sense3_fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.sensor_pads.modify(|_, w| { w + .sense3_fun_ie().bit(true) + .sense3_mux_sel().bit(true) + .sense3_fun_sel().bits(0) + }); } 3 => { - rtc_io - .sensor_pads - .modify(|_, w| w.sense4_mux_sel().bit(true)); - rtc_io.sensor_pads.modify(|_, w| w.sense4_fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.sensor_pads.modify(|_, w| { w + .sense4_fun_ie().bit(true) + .sense4_mux_sel().bit(true) + .sense4_fun_sel().bits(0) + }); } 4 => { - rtc_io.adc_pad.modify(|_, w| w.adc1_mux_sel().bit(true)); - rtc_io.adc_pad.modify(|_, w| w.adc1_fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.adc_pad.modify(|_, w| { w + .adc1_fun_ie().bit(true) + .adc1_mux_sel().bit(true) + .adc1_fun_sel().bits(0) + }); } 5 => { - rtc_io.adc_pad.modify(|_, w| w.adc2_mux_sel().bit(true)); - rtc_io.adc_pad.modify(|_, w| w.adc2_fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.adc_pad.modify(|_, w| { w + .adc2_fun_ie().bit(true) + .adc2_mux_sel().bit(true) + .adc2_fun_sel().bits(0) + }); } 6 => { - rtc_io.pad_dac1.modify(|_, w| w.pdac1_mux_sel().bit(true)); - rtc_io.pad_dac1.modify(|_, w| w.pdac1_fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.pad_dac1.modify(|_, w| { w + .pdac1_fun_ie().bit(true) + .pdac1_mux_sel().bit(true) + .pdac1_fun_sel().bits(0) + }); } 7 => { - rtc_io.pad_dac2.modify(|_, w| w.pdac2_mux_sel().bit(true)); - rtc_io.pad_dac2.modify(|_, w| w.pdac2_fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.pad_dac2.modify(|_, w| { w + .pdac2_fun_ie().bit(true) + .pdac2_mux_sel().bit(true) + .pdac2_fun_sel().bits(0) + }); } 8 => { - rtc_io - .xtal_32k_pad - .modify(|_, w| w.x32n_mux_sel().bit(true)); - rtc_io.xtal_32k_pad.modify(|_, w| w.x32n_fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.xtal_32k_pad.modify(|_, w| { w + .x32n_fun_ie().bit(true) + .x32n_mux_sel().bit(true) + .x32n_fun_sel().bits(0) + }); } 9 => { - rtc_io - .xtal_32k_pad - .modify(|_, w| w.x32p_mux_sel().bit(true)); - rtc_io.xtal_32k_pad.modify(|_, w| w.x32p_fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.xtal_32k_pad.modify(|_, w| { w + .x32p_fun_ie().bit(true) + .x32p_mux_sel().bit(true) + .x32p_fun_sel().bits(0) + }); } 10 => { - rtc_io.touch_pad0.modify(|_, w| w.mux_sel().bit(true)); - rtc_io.touch_pad0.modify(|_, w| w.fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.touch_pad0.modify(|_, w| { w + .fun_ie().bit(true) + .mux_sel().bit(true) + .fun_sel().bits(0) + }); } 11 => { - rtc_io.touch_pad1.modify(|_, w| w.mux_sel().bit(true)); - rtc_io.touch_pad1.modify(|_, w| w.fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.touch_pad1.modify(|_, w| { w + .fun_ie().bit(true) + .mux_sel().bit(true) + .fun_sel().bits(0) + }); } 12 => { - rtc_io.touch_pad2.modify(|_, w| w.mux_sel().bit(true)); - rtc_io.touch_pad2.modify(|_, w| w.fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.touch_pad2.modify(|_, w| { w + .fun_ie().bit(true) + .mux_sel().bit(true) + .fun_sel().bits(0) + }); } 13 => { - rtc_io.touch_pad3.modify(|_, w| w.mux_sel().bit(true)); - rtc_io.touch_pad3.modify(|_, w| w.fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.touch_pad3.modify(|_, w| { w + .fun_ie().bit(true) + .mux_sel().bit(true) + .fun_sel().bits(0) + }); } 14 => { - rtc_io.touch_pad4.modify(|_, w| w.mux_sel().bit(true)); - rtc_io.touch_pad4.modify(|_, w| w.fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.touch_pad4.modify(|_, w| { w + .fun_ie().bit(true) + .mux_sel().bit(true) + .fun_sel().bits(0) + }); } 15 => { - rtc_io.touch_pad5.modify(|_, w| w.mux_sel().bit(true)); - rtc_io.touch_pad5.modify(|_, w| w.fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.touch_pad5.modify(|_, w| { w + .fun_ie().bit(true) + .mux_sel().bit(true) + .fun_sel().bits(0) + }); } 16 => { - rtc_io.touch_pad6.modify(|_, w| w.mux_sel().bit(true)); - rtc_io.touch_pad6.modify(|_, w| w.fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.touch_pad6.modify(|_, w| { w + .fun_ie().bit(true) + .mux_sel().bit(true) + .fun_sel().bits(0) + }); } 17 => { - rtc_io.touch_pad7.modify(|_, w| w.mux_sel().bit(true)); - rtc_io.touch_pad7.modify(|_, w| w.fun_sel().bits(0)); + #[rustfmt::skip] + rtc_io.touch_pad7.modify(|_, w| { w + .fun_ie().bit(true) + .mux_sel().bit(true) + .fun_sel().bits(0) + }); } _ => panic!("invalid RTC pin"), }; @@ -173,7 +236,6 @@ impl<'a, P: Pin> WakeSource for Ext0WakeupSource<'a, P> { } bitfield::bitfield! { - #[derive(Clone, Copy)] pub struct RtcSleepConfig(u32); impl Debug; /// force normal voltage in sleep mode (digital domain memory) diff --git a/esp-hal-common/src/rtc_cntl/sleep.rs b/esp-hal-common/src/rtc_cntl/sleep.rs index 48451ec5a73..cc5c0730afb 100644 --- a/esp-hal-common/src/rtc_cntl/sleep.rs +++ b/esp-hal-common/src/rtc_cntl/sleep.rs @@ -116,7 +116,8 @@ bitfield::bitfield! { } pub trait WakeSource { - fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig); + fn add(&self, sleep_config: &mut RtcSleepConfig); + fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers); } pub struct Sleep<'a> { @@ -124,6 +125,18 @@ pub struct Sleep<'a> { wake_sources: heapless::Vec<&'a dyn WakeSource, 16>, } +impl core::fmt::Debug for Sleep<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Sleep") + .field("sleep_config", &self.sleep_config) + .field( + "wake_sources", + &format_args!("#{}", self.wake_sources.len()), + ) + .finish() + } +} + impl<'a> Default for Sleep<'a> { fn default() -> Self { Self { @@ -147,6 +160,7 @@ impl<'a> Sleep<'a> { } pub fn add_wakeup_source(&mut self, wake_source: &'a impl WakeSource) -> Result<(), Error> { + wake_source.add(&mut self.sleep_config); self.wake_sources .push(wake_source) .map_err(|_| Error::TooManyWakeupSources)?; @@ -157,7 +171,7 @@ impl<'a> Sleep<'a> { self.sleep_config.apply(rtc); let mut wakeup_triggers = WakeTriggers::default(); for wake_source in &self.wake_sources { - wake_source.prepare(rtc, &mut wakeup_triggers, &mut self.sleep_config) + wake_source.prepare(rtc, &mut wakeup_triggers) } use embedded_hal::blocking::delay::DelayMs; delay.delay_ms(100u32); @@ -173,9 +187,6 @@ impl<'a> Sleep<'a> { .wakeup_state .modify(|_, w| w.wakeup_ena().bits(wakeup_triggers.0.into())); - // TODO: remove this! - // esp_reg_dump::rtc_cntl::dump_all(); - rtc_cntl .state0 .write(|w| w.sleep_en().set_bit().slp_wakeup().set_bit()); From 6ecbea27f7dcec8d34fa5224d330eb75df4f2f00 Mon Sep 17 00:00:00 2001 From: liebman Date: Thu, 8 Jun 2023 13:26:24 -0700 Subject: [PATCH 07/20] add sleep_timer_ext0 example --- esp32-hal/examples/sleep_timer.rs | 28 ---------- esp32-hal/examples/sleep_timer_ext0.rs | 73 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 esp32-hal/examples/sleep_timer_ext0.rs diff --git a/esp32-hal/examples/sleep_timer.rs b/esp32-hal/examples/sleep_timer.rs index 3d9fb74d25e..d12535a938f 100644 --- a/esp32-hal/examples/sleep_timer.rs +++ b/esp32-hal/examples/sleep_timer.rs @@ -3,8 +3,6 @@ #![no_std] #![no_main] -extern crate alloc; - use core::time::Duration; use esp32_hal as hal; @@ -26,34 +24,8 @@ use hal::{ Rtc, }; -#[global_allocator] -static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); - -fn init_heap() { - const HEAP_SIZE: usize = 32 * 1024; - - extern "C" { - static mut _heap_start: u32; - #[cfg(target_arch = "xtensa")] - static mut _heap_end: u32; - } - - unsafe { - let heap_start = &_heap_start as *const _ as usize; - #[cfg(target_arch = "xtensa")] - let heap_end = &_heap_end as *const _ as usize; - #[cfg(target_arch = "xtensa")] - assert!( - heap_end - heap_start > HEAP_SIZE, - "Not enough available heap memory." - ); - ALLOCATOR.init(heap_start as *mut u8, HEAP_SIZE); - } -} - #[entry] fn main() -> ! { - init_heap(); let peripherals = Peripherals::take(); let mut system = peripherals.DPORT.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); diff --git a/esp32-hal/examples/sleep_timer_ext0.rs b/esp32-hal/examples/sleep_timer_ext0.rs new file mode 100644 index 00000000000..84099a962a0 --- /dev/null +++ b/esp32-hal/examples/sleep_timer_ext0.rs @@ -0,0 +1,73 @@ +//! Demonstrates deep sleep with timer and ext0 (using gpio27) wakeup + +#![no_std] +#![no_main] + +use core::time::Duration; + +use esp32_hal as hal; +use esp_backtrace as _; +use esp_println::println; +use hal::{ + clock::ClockControl, + entry, + peripherals::Peripherals, + prelude::*, + rtc_cntl::{ + get_reset_reason, + get_wakeup_cause, + sleep::{Ext0WakeupSource, Sleep, TimerWakeupSource, WakeupLevel}, + SocResetReason, + }, + timer::TimerGroup, + Delay, + Rtc, + IO, +}; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.DPORT.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + // Disable the RTC and TIMG watchdog timers + let mut rtc = Rtc::new(peripherals.RTC_CNTL); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let mut ext0_pin = io.pins.gpio27; + + println!("up and runnning!"); + let reason = get_reset_reason(hal::Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); + println!("reset reason: {:?}", reason); + let wake_reason = get_wakeup_cause(); + println!("wake reason: {:?}", wake_reason); + + let mut delay = Delay::new(&clocks); + + let mut sleep = Sleep::deep(); + let timer = TimerWakeupSource::new(Duration::from_secs(30)); + sleep.add_wakeup_source(&timer).unwrap(); + let ext0 = Ext0WakeupSource::new(&mut ext0_pin, WakeupLevel::High); + sleep.add_wakeup_source(&ext0).unwrap(); + println!("sleeping!"); + delay.delay_ms(100u32); + sleep.sleep(&mut rtc, &mut delay); + unreachable!(); +} From c81f9d09ae257d31093a52c3460c017c69624cc0 Mon Sep 17 00:00:00 2001 From: liebman Date: Sat, 10 Jun 2023 06:13:09 -0700 Subject: [PATCH 08/20] API change: move sleep into RTC as sleep, sleep_deep, sleep_light --- esp-hal-common/src/rtc_cntl/mod.rs | 52 ++++++++++ .../src/rtc_cntl/rtc/esp32_sleep.rs | 11 +-- esp-hal-common/src/rtc_cntl/sleep.rs | 98 +------------------ 3 files changed, 59 insertions(+), 102 deletions(-) diff --git a/esp-hal-common/src/rtc_cntl/mod.rs b/esp-hal-common/src/rtc_cntl/mod.rs index 211e04f288d..1241074eb00 100644 --- a/esp-hal-common/src/rtc_cntl/mod.rs +++ b/esp-hal-common/src/rtc_cntl/mod.rs @@ -6,6 +6,7 @@ use fugit::HertzU32; use fugit::MicrosDurationU64; pub use self::rtc::SocResetReason; +use self::sleep::{RtcSleepConfig, WakeSource}; #[cfg(not(any(esp32c6, esp32h2)))] use crate::clock::XtalClock; #[cfg(not(esp32))] @@ -18,6 +19,7 @@ use crate::{ clock::Clock, peripheral::{Peripheral, PeripheralRef}, reset::{SleepSource, WakeupReason}, + rtc_cntl::sleep::WakeTriggers, Cpu, }; @@ -195,6 +197,56 @@ impl<'d> Rtc<'d> { pub fn get_time_ms(&self) -> u64 { self.get_time_raw() * 1_000 / RtcClock::get_slow_freq().frequency().to_Hz() as u64 } + + /// enter deep sleep and wake with the provided `wake_sources` + pub fn sleep_deep<'a>( + &mut self, + wake_sources: &[&'a dyn WakeSource], + delay: &mut crate::Delay, + ) -> ! { + let config = RtcSleepConfig::deep(); + self.sleep(&config, wake_sources, delay); + unreachable!(); + } + pub fn sleep_light<'a>( + &mut self, + wake_sources: &[&'a dyn WakeSource], + delay: &mut crate::Delay, + ) { + let config = RtcSleepConfig::default(); + self.sleep(&config, wake_sources, delay) + } + pub fn sleep<'a>( + &mut self, + config: &RtcSleepConfig, + wake_sources: &[&'a dyn WakeSource], + delay: &mut crate::Delay, + ) { + let mut config = config.clone(); + let mut wakeup_triggers = WakeTriggers::default(); + for wake_source in wake_sources { + wake_source.apply(self, &mut wakeup_triggers, &mut config) + } + config.apply(self); + use embedded_hal::blocking::delay::DelayMs; + delay.delay_ms(100u32); + unsafe { + let rtc_cntl = &*RTC_CNTL::ptr(); + + rtc_cntl + .reset_state + .modify(|_, w| w.procpu_stat_vector_sel().set_bit()); + + // set bits for what can wake us up + rtc_cntl + .wakeup_state + .modify(|_, w| w.wakeup_ena().bits(wakeup_triggers.0.into())); + + rtc_cntl + .state0 + .write(|w| w.sleep_en().set_bit().slp_wakeup().set_bit()); + } + } } #[cfg(not(any(esp32c6, esp32h2)))] diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs index 46d6172b89a..621d6eecf57 100644 --- a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs @@ -40,8 +40,7 @@ pub const RTC_CNTL_CK8M_WAIT_DEFAULT: u8 = 20; pub const RTC_CK8M_ENABLE_WAIT_DEFAULT: u8 = 5; impl WakeSource for TimerWakeupSource { - fn add(&self, _sleep_config: &mut RtcSleepConfig) {} - fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers) { + fn apply(&self, rtc: &Rtc, triggers: &mut WakeTriggers, _sleep_config: &mut RtcSleepConfig) { triggers.set_timer(true); let rtc_cntl = unsafe { &*esp32::RTC_CNTL::ptr() }; let clock_freq = RtcClock::get_slow_freq(); @@ -66,10 +65,9 @@ impl WakeSource for TimerWakeupSource { } impl<'a, P: Pin> WakeSource for Ext0WakeupSource<'a, P> { - fn add(&self, sleep_config: &mut RtcSleepConfig) { + fn apply(&self, _rtc: &Rtc, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig) { + // don't power down RTC peripherals sleep_config.set_rtc_peri_pd_en(false); - } - fn prepare(&self, _rtc: &Rtc, triggers: &mut WakeTriggers) { triggers.set_ext0(true); let pin = self.to_rtc_pin().unwrap(); unsafe { @@ -236,6 +234,7 @@ impl<'a, P: Pin> WakeSource for Ext0WakeupSource<'a, P> { } bitfield::bitfield! { + #[derive(Clone, Copy)] pub struct RtcSleepConfig(u32); impl Debug; /// force normal voltage in sleep mode (digital domain memory) @@ -373,7 +372,7 @@ impl RtcSleepConfig { } } - pub(super) fn apply(&self, rtc: &Rtc) { + pub(crate) fn apply(&self, rtc: &Rtc) { self.base_settings(rtc); // like esp-idf rtc_sleep_init() unsafe { diff --git a/esp-hal-common/src/rtc_cntl/sleep.rs b/esp-hal-common/src/rtc_cntl/sleep.rs index cc5c0730afb..3d1fd5a9cbf 100644 --- a/esp-hal-common/src/rtc_cntl/sleep.rs +++ b/esp-hal-common/src/rtc_cntl/sleep.rs @@ -4,8 +4,6 @@ use crate::{gpio::Pin, Rtc}; #[cfg_attr(esp32, path = "rtc/esp32_sleep.rs")] mod rtc_sleep; -#[cfg(esp32)] -use esp32 as pac; pub use rtc_sleep::*; #[derive(Debug, Default, Clone, Copy, PartialEq)] @@ -69,24 +67,7 @@ impl<'a, P: Pin> Ext0WakeupSource<'a, P> { } } } -// RTCIO_GPIO0_CHANNEL, //GPIO0 -// RTCIO_GPIO2_CHANNEL, //GPIO2 -// RTCIO_GPIO4_CHANNEL, //GPIO4 -// RTCIO_GPIO12_CHANNEL, //GPIO12 -// RTCIO_GPIO13_CHANNEL, //GPIO13 -// RTCIO_GPIO14_CHANNEL, //GPIO14 -// RTCIO_GPIO15_CHANNEL, //GPIO15 -// RTCIO_GPIO25_CHANNEL, //GPIO25 -// RTCIO_GPIO26_CHANNEL, //GPIO26 -// RTCIO_GPIO27_CHANNEL, //GPIO27 -// RTCIO_GPIO32_CHANNEL, //GPIO32 -// RTCIO_GPIO33_CHANNEL, //GPIO33 -// RTCIO_GPIO34_CHANNEL, //GPIO34 -// RTCIO_GPIO35_CHANNEL, //GPIO35 -// RTCIO_GPIO36_CHANNEL, //GPIO36 -// RTCIO_GPIO37_CHANNEL, //GPIO37 -// RTCIO_GPIO38_CHANNEL, //GPIO38 -// RTCIO_GPIO39_CHANNEL, //GPIO39 + bitfield::bitfield! { #[derive(Default, Clone, Copy)] pub struct WakeTriggers(u16); @@ -116,80 +97,5 @@ bitfield::bitfield! { } pub trait WakeSource { - fn add(&self, sleep_config: &mut RtcSleepConfig); - fn prepare(&self, rtc: &Rtc, triggers: &mut WakeTriggers); -} - -pub struct Sleep<'a> { - sleep_config: RtcSleepConfig, - wake_sources: heapless::Vec<&'a dyn WakeSource, 16>, -} - -impl core::fmt::Debug for Sleep<'_> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("Sleep") - .field("sleep_config", &self.sleep_config) - .field( - "wake_sources", - &format_args!("#{}", self.wake_sources.len()), - ) - .finish() - } -} - -impl<'a> Default for Sleep<'a> { - fn default() -> Self { - Self { - sleep_config: Default::default(), - wake_sources: Default::default(), - } - } -} -impl<'a> Sleep<'a> { - pub fn new() -> Self { - Self { - ..Default::default() - } - } - - pub fn deep() -> Self { - Self { - sleep_config: RtcSleepConfig::deep(), - ..Default::default() - } - } - - pub fn add_wakeup_source(&mut self, wake_source: &'a impl WakeSource) -> Result<(), Error> { - wake_source.add(&mut self.sleep_config); - self.wake_sources - .push(wake_source) - .map_err(|_| Error::TooManyWakeupSources)?; - Ok(()) - } - - pub fn sleep(&mut self, rtc: &mut Rtc, delay: &mut crate::Delay) { - self.sleep_config.apply(rtc); - let mut wakeup_triggers = WakeTriggers::default(); - for wake_source in &self.wake_sources { - wake_source.prepare(rtc, &mut wakeup_triggers) - } - use embedded_hal::blocking::delay::DelayMs; - delay.delay_ms(100u32); - unsafe { - let rtc_cntl = &*pac::RTC_CNTL::ptr(); - - rtc_cntl - .reset_state - .modify(|_, w| w.procpu_stat_vector_sel().set_bit()); - - // set bits for what can wake us up - rtc_cntl - .wakeup_state - .modify(|_, w| w.wakeup_ena().bits(wakeup_triggers.0.into())); - - rtc_cntl - .state0 - .write(|w| w.sleep_en().set_bit().slp_wakeup().set_bit()); - } - } + fn apply(&self, rtc: &Rtc, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig); } From a5900b26b4afe151ccc800d2dbabf9bba049beae Mon Sep 17 00:00:00 2001 From: liebman Date: Sat, 10 Jun 2023 06:31:27 -0700 Subject: [PATCH 09/20] fix sleep examples for new API --- esp32-hal/examples/sleep_timer.rs | 12 ++---------- esp32-hal/examples/sleep_timer_ext0.rs | 8 ++------ 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/esp32-hal/examples/sleep_timer.rs b/esp32-hal/examples/sleep_timer.rs index d12535a938f..44a5be340b6 100644 --- a/esp32-hal/examples/sleep_timer.rs +++ b/esp32-hal/examples/sleep_timer.rs @@ -13,12 +13,7 @@ use hal::{ entry, peripherals::Peripherals, prelude::*, - rtc_cntl::{ - get_reset_reason, - get_wakeup_cause, - sleep::{Sleep, TimerWakeupSource}, - SocResetReason, - }, + rtc_cntl::{get_reset_reason, get_wakeup_cause, sleep::TimerWakeupSource, SocResetReason}, timer::TimerGroup, Delay, Rtc, @@ -57,11 +52,8 @@ fn main() -> ! { let mut delay = Delay::new(&clocks); - let mut sleep = Sleep::deep(); let timer = TimerWakeupSource::new(Duration::from_secs(30)); - sleep.add_wakeup_source(&timer).unwrap(); println!("sleeping!"); delay.delay_ms(100u32); - sleep.sleep(&mut rtc, &mut delay); - unreachable!(); + rtc.sleep_deep(&[&timer], &mut delay); } diff --git a/esp32-hal/examples/sleep_timer_ext0.rs b/esp32-hal/examples/sleep_timer_ext0.rs index 84099a962a0..0260de33c78 100644 --- a/esp32-hal/examples/sleep_timer_ext0.rs +++ b/esp32-hal/examples/sleep_timer_ext0.rs @@ -16,7 +16,7 @@ use hal::{ rtc_cntl::{ get_reset_reason, get_wakeup_cause, - sleep::{Ext0WakeupSource, Sleep, TimerWakeupSource, WakeupLevel}, + sleep::{Ext0WakeupSource, TimerWakeupSource, WakeupLevel}, SocResetReason, }, timer::TimerGroup, @@ -61,13 +61,9 @@ fn main() -> ! { let mut delay = Delay::new(&clocks); - let mut sleep = Sleep::deep(); let timer = TimerWakeupSource::new(Duration::from_secs(30)); - sleep.add_wakeup_source(&timer).unwrap(); let ext0 = Ext0WakeupSource::new(&mut ext0_pin, WakeupLevel::High); - sleep.add_wakeup_source(&ext0).unwrap(); println!("sleeping!"); delay.delay_ms(100u32); - sleep.sleep(&mut rtc, &mut delay); - unreachable!(); + rtc.sleep_deep(&[&timer, &ext0], &mut delay); } From b569858b776261d34ada28e4f5e18cf34a71fa67 Mon Sep 17 00:00:00 2001 From: liebman Date: Sat, 10 Jun 2023 06:55:39 -0700 Subject: [PATCH 10/20] sleep only implemented for esp32 at this time --- esp-hal-common/src/rtc_cntl/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/esp-hal-common/src/rtc_cntl/mod.rs b/esp-hal-common/src/rtc_cntl/mod.rs index 1241074eb00..d1333ef281e 100644 --- a/esp-hal-common/src/rtc_cntl/mod.rs +++ b/esp-hal-common/src/rtc_cntl/mod.rs @@ -199,6 +199,7 @@ impl<'d> Rtc<'d> { } /// enter deep sleep and wake with the provided `wake_sources` + #[cfg(esp32)] pub fn sleep_deep<'a>( &mut self, wake_sources: &[&'a dyn WakeSource], @@ -208,6 +209,9 @@ impl<'d> Rtc<'d> { self.sleep(&config, wake_sources, delay); unreachable!(); } + + /// enter light sleep and wake with the provided `wake_sources` + #[cfg(esp32)] pub fn sleep_light<'a>( &mut self, wake_sources: &[&'a dyn WakeSource], @@ -216,6 +220,10 @@ impl<'d> Rtc<'d> { let config = RtcSleepConfig::default(); self.sleep(&config, wake_sources, delay) } + + /// enter sleep wthe the provided `config` and wake with the provided + /// `wake_sources` + #[cfg(esp32)] pub fn sleep<'a>( &mut self, config: &RtcSleepConfig, From 54bac9ccf7949dad6a6e317cc24bf0ec58ea8f61 Mon Sep 17 00:00:00 2001 From: liebman Date: Sat, 10 Jun 2023 08:03:15 -0700 Subject: [PATCH 11/20] sleep only implemented for esp32 at this time --- esp-hal-common/src/rtc_cntl/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/esp-hal-common/src/rtc_cntl/mod.rs b/esp-hal-common/src/rtc_cntl/mod.rs index d1333ef281e..9da38137f2d 100644 --- a/esp-hal-common/src/rtc_cntl/mod.rs +++ b/esp-hal-common/src/rtc_cntl/mod.rs @@ -6,7 +6,6 @@ use fugit::HertzU32; use fugit::MicrosDurationU64; pub use self::rtc::SocResetReason; -use self::sleep::{RtcSleepConfig, WakeSource}; #[cfg(not(any(esp32c6, esp32h2)))] use crate::clock::XtalClock; #[cfg(not(esp32))] @@ -15,14 +14,14 @@ use crate::efuse::Efuse; use crate::peripherals::{LP_TIMER, LP_WDT}; #[cfg(not(any(esp32c6, esp32h2)))] use crate::peripherals::{RTC_CNTL, TIMG0}; +#[cfg(any(esp32))] +use crate::rtc_cntl::sleep::{RtcSleepConfig, WakeSource, WakeTriggers}; use crate::{ clock::Clock, peripheral::{Peripheral, PeripheralRef}, reset::{SleepSource, WakeupReason}, - rtc_cntl::sleep::WakeTriggers, Cpu, }; - // only include sleep where its been implemented #[cfg(any(esp32))] pub mod sleep; From 065a76720a1f1233ceb20d757816d23d1a0cf42f Mon Sep 17 00:00:00 2001 From: liebman Date: Sun, 11 Jun 2023 07:19:30 -0700 Subject: [PATCH 12/20] Implement a simple RTCPin trait to support sleep --- esp-hal-common/src/gpio.rs | 54 +++++- .../src/rtc_cntl/rtc/esp32_sleep.rs | 163 +----------------- esp-hal-common/src/rtc_cntl/sleep.rs | 41 ++--- esp-hal-common/src/soc/esp32/gpio.rs | 21 +++ 4 files changed, 93 insertions(+), 186 deletions(-) diff --git a/esp-hal-common/src/gpio.rs b/esp-hal-common/src/gpio.rs index c29f0475db6..bb4803141ee 100644 --- a/esp-hal-common/src/gpio.rs +++ b/esp-hal-common/src/gpio.rs @@ -12,7 +12,7 @@ use core::{convert::Infallible, marker::PhantomData}; use crate::peripherals::{GPIO, IO_MUX}; pub use crate::soc::gpio::*; -pub(crate) use crate::{analog, gpio}; +pub(crate) use crate::{analog, gpio, rtc_pins}; /// Convenience type-alias for a no-pin / don't care - pin pub type NoPinType = Gpio0; @@ -89,7 +89,13 @@ pub enum AlternateFunction { Function5 = 5, } -pub trait RTCPin {} +pub trait RTCPin { + fn rtc_number(&self) -> u8; + fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: u8); +} + +pub trait RTCInputPin: RTCPin {} +pub trait RTCOutputPin: RTCPin {} pub trait AnalogPin {} @@ -1397,6 +1403,50 @@ macro_rules! gpio { }; } +#[doc(hidden)] +#[macro_export] +macro_rules! rtc_pins { + ( + $( ( $pin_num:expr, $rtc_pin:expr, $pin_reg:ident, $prefix:pat ) )+ + ) => { + impl crate::gpio::RTCPin for GpioPin + where + Self: crate::gpio::GpioProperties, + ::PinType: crate::gpio::IsAnalogPin, + { + fn rtc_number(&self) -> u8 { + match GPIONUM { + $( + $pin_num => $rtc_pin, + )+ + _ => unreachable!(), + } + } + /// Set the RTC properties of the pin. If `mux` is true then then pin is + /// routed to RTC, when false it is routed to IO_MUX. + fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: u8) { + use crate::peripherals::RTC_IO; + let rtcio = unsafe{ &*RTC_IO::ptr() }; + match GPIONUM { + $( + $pin_num => { + // disable input + paste!{ + rtcio.$pin_reg.modify(|_,w| unsafe {w + .[<$prefix fun_ie>]().bit(input_enable) + .[<$prefix mux_sel>]().bit(mux) + .[<$prefix fun_sel>]().bits(func) + }); + } + } + )+ + _ => unreachable!(), + } + } + } + }; +} + // Following code enables `into_analog` #[doc(hidden)] diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs index 621d6eecf57..9383b9093e3 100644 --- a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs @@ -1,6 +1,6 @@ use super::{Ext0WakeupSource, TimerWakeupSource, WakeSource, WakeTriggers}; use crate::{ - gpio::Pin, + gpio::{Pin, RTCPin}, rtc_cntl::{sleep::WakeupLevel, Clock, RtcClock}, Rtc, }; @@ -64,166 +64,21 @@ impl WakeSource for TimerWakeupSource { } } -impl<'a, P: Pin> WakeSource for Ext0WakeupSource<'a, P> { +impl<'a, P: Pin + RTCPin> WakeSource for Ext0WakeupSource<'a, P> { fn apply(&self, _rtc: &Rtc, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig) { // don't power down RTC peripherals sleep_config.set_rtc_peri_pd_en(false); triggers.set_ext0(true); - let pin = self.to_rtc_pin().unwrap(); + + // set pin to RTC function + self.pin.borrow_mut().rtc_set_config(true, true, 0); + unsafe { - // TODO: set pin to RTC function (should be handled by RTCPin impl) let rtc_io = &*esp32::RTC_IO::ptr(); - // TODO: this should be implemented by RTCPin! - match self.to_rtc_pin().unwrap() { - 0 => { - #[rustfmt::skip] - rtc_io.sensor_pads.modify(|_, w| { w - .sense1_fun_ie().bit(true) - .sense1_mux_sel().bit(true) - .sense1_fun_sel().bits(0) - }); - } - 1 => { - #[rustfmt::skip] - rtc_io.sensor_pads.modify(|_, w| { w - .sense2_fun_ie().bit(true) - .sense2_mux_sel().bit(true) - .sense2_fun_sel().bits(0) - }); - } - 2 => { - #[rustfmt::skip] - rtc_io.sensor_pads.modify(|_, w| { w - .sense3_fun_ie().bit(true) - .sense3_mux_sel().bit(true) - .sense3_fun_sel().bits(0) - }); - } - 3 => { - #[rustfmt::skip] - rtc_io.sensor_pads.modify(|_, w| { w - .sense4_fun_ie().bit(true) - .sense4_mux_sel().bit(true) - .sense4_fun_sel().bits(0) - }); - } - 4 => { - #[rustfmt::skip] - rtc_io.adc_pad.modify(|_, w| { w - .adc1_fun_ie().bit(true) - .adc1_mux_sel().bit(true) - .adc1_fun_sel().bits(0) - }); - } - 5 => { - #[rustfmt::skip] - rtc_io.adc_pad.modify(|_, w| { w - .adc2_fun_ie().bit(true) - .adc2_mux_sel().bit(true) - .adc2_fun_sel().bits(0) - }); - } - 6 => { - #[rustfmt::skip] - rtc_io.pad_dac1.modify(|_, w| { w - .pdac1_fun_ie().bit(true) - .pdac1_mux_sel().bit(true) - .pdac1_fun_sel().bits(0) - }); - } - 7 => { - #[rustfmt::skip] - rtc_io.pad_dac2.modify(|_, w| { w - .pdac2_fun_ie().bit(true) - .pdac2_mux_sel().bit(true) - .pdac2_fun_sel().bits(0) - }); - } - 8 => { - #[rustfmt::skip] - rtc_io.xtal_32k_pad.modify(|_, w| { w - .x32n_fun_ie().bit(true) - .x32n_mux_sel().bit(true) - .x32n_fun_sel().bits(0) - }); - } - 9 => { - #[rustfmt::skip] - rtc_io.xtal_32k_pad.modify(|_, w| { w - .x32p_fun_ie().bit(true) - .x32p_mux_sel().bit(true) - .x32p_fun_sel().bits(0) - }); - } - 10 => { - #[rustfmt::skip] - rtc_io.touch_pad0.modify(|_, w| { w - .fun_ie().bit(true) - .mux_sel().bit(true) - .fun_sel().bits(0) - }); - } - 11 => { - #[rustfmt::skip] - rtc_io.touch_pad1.modify(|_, w| { w - .fun_ie().bit(true) - .mux_sel().bit(true) - .fun_sel().bits(0) - }); - } - 12 => { - #[rustfmt::skip] - rtc_io.touch_pad2.modify(|_, w| { w - .fun_ie().bit(true) - .mux_sel().bit(true) - .fun_sel().bits(0) - }); - } - 13 => { - #[rustfmt::skip] - rtc_io.touch_pad3.modify(|_, w| { w - .fun_ie().bit(true) - .mux_sel().bit(true) - .fun_sel().bits(0) - }); - } - 14 => { - #[rustfmt::skip] - rtc_io.touch_pad4.modify(|_, w| { w - .fun_ie().bit(true) - .mux_sel().bit(true) - .fun_sel().bits(0) - }); - } - 15 => { - #[rustfmt::skip] - rtc_io.touch_pad5.modify(|_, w| { w - .fun_ie().bit(true) - .mux_sel().bit(true) - .fun_sel().bits(0) - }); - } - 16 => { - #[rustfmt::skip] - rtc_io.touch_pad6.modify(|_, w| { w - .fun_ie().bit(true) - .mux_sel().bit(true) - .fun_sel().bits(0) - }); - } - 17 => { - #[rustfmt::skip] - rtc_io.touch_pad7.modify(|_, w| { w - .fun_ie().bit(true) - .mux_sel().bit(true) - .fun_sel().bits(0) - }); - } - _ => panic!("invalid RTC pin"), - }; - // set pin register field - rtc_io.ext_wakeup0.modify(|_, w| w.sel().bits(pin)); + rtc_io + .ext_wakeup0 + .modify(|_, w| w.sel().bits(self.pin.borrow().rtc_number())); // set level register field let rtc_cntl = &*esp32::RTC_CNTL::ptr(); rtc_cntl diff --git a/esp-hal-common/src/rtc_cntl/sleep.rs b/esp-hal-common/src/rtc_cntl/sleep.rs index 3d1fd5a9cbf..de67012109f 100644 --- a/esp-hal-common/src/rtc_cntl/sleep.rs +++ b/esp-hal-common/src/rtc_cntl/sleep.rs @@ -1,6 +1,9 @@ -use core::time::Duration; +use core::{cell::RefCell, time::Duration}; -use crate::{gpio::Pin, Rtc}; +use crate::{ + gpio::{Pin, RTCPin}, + Rtc, +}; #[cfg_attr(esp32, path = "rtc/esp32_sleep.rs")] mod rtc_sleep; @@ -32,38 +35,16 @@ pub enum Error { #[allow(unused)] #[derive(Debug)] -// TODO: restrict to RTCPin as well (when its implemented on RTC pins) -pub struct Ext0WakeupSource<'a, P: Pin> { - pin: &'a mut P, +pub struct Ext0WakeupSource<'a, P: RTCPin + Pin> { + pin: RefCell<&'a mut P>, level: WakeupLevel, } -impl<'a, P: Pin> Ext0WakeupSource<'a, P> { +impl<'a, P: RTCPin + Pin> Ext0WakeupSource<'a, P> { pub fn new(pin: &'a mut P, level: WakeupLevel) -> Self { - Self { pin, level } - } - // TODO: esp32 only! - needs to be re-factored (should be in RTCPin impl) - fn to_rtc_pin(&self) -> Result { - match self.pin.number() { - 0 => Ok(11), - 2 => Ok(12), - 4 => Ok(10), - 12 => Ok(15), - 13 => Ok(14), - 14 => Ok(16), - 15 => Ok(13), - 25 => Ok(6), - 26 => Ok(7), - 27 => Ok(17), - 32 => Ok(9), - 33 => Ok(8), - 34 => Ok(4), - 35 => Ok(5), - 36 => Ok(0), - 37 => Ok(1), - 38 => Ok(2), - 39 => Ok(3), - _ => Err(Error::NotRtcPin), + Self { + pin: RefCell::new(pin), + level, } } } diff --git a/esp-hal-common/src/soc/esp32/gpio.rs b/esp-hal-common/src/soc/esp32/gpio.rs index c0474256674..caf02168cc0 100644 --- a/esp-hal-common/src/soc/esp32/gpio.rs +++ b/esp-hal-common/src/soc/esp32/gpio.rs @@ -715,6 +715,27 @@ crate::gpio::analog! { (27, 17, touch_pad7, mux_sel, fun_sel, fun_ie, rue, rde ) } +crate::gpio::rtc_pins! { + (36, 0, sensor_pads, sense1_ ) + (37, 1, sensor_pads, sense2_ ) + (38, 2, sensor_pads, sense3_ ) + (39, 3, sensor_pads, sense4_ ) + (34, 4, adc_pad, adc1_ ) + (35, 5, adc_pad, adc2_ ) + (25, 6, pad_dac1, pdac1_ ) + (26, 7, pad_dac2, pdac2_ ) + (33, 8, xtal_32k_pad, x32n_ ) + (32, 9, xtal_32k_pad, x32p_ ) + (4, 10, touch_pad0, "") + (0, 11, touch_pad1, "") + (2, 12, touch_pad2, "") + (15, 13, touch_pad3, "") + (13, 14, touch_pad4, "") + (12, 15, touch_pad5, "") + (14, 16, touch_pad6, "") + (27, 17, touch_pad7, "") +} + impl InterruptStatusRegisterAccess for InterruptStatusRegisterAccessBank0 { fn pro_cpu_interrupt_status_read() -> u32 { unsafe { &*GPIO::PTR }.pcpu_int.read().bits() From 2ac0e3e08544d083f17128cb0316de0fd261f7a8 Mon Sep 17 00:00:00 2001 From: liebman Date: Sun, 11 Jun 2023 09:13:56 -0700 Subject: [PATCH 13/20] implement RTCPin for all xtensa SOC --- esp-hal-common/src/gpio.rs | 7 +++++-- esp-hal-common/src/soc/esp32s2/gpio.rs | 25 +++++++++++++++++++++++++ esp-hal-common/src/soc/esp32s3/gpio.rs | 25 +++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/esp-hal-common/src/gpio.rs b/esp-hal-common/src/gpio.rs index bb4803141ee..e880a8f43cc 100644 --- a/esp-hal-common/src/gpio.rs +++ b/esp-hal-common/src/gpio.rs @@ -12,7 +12,9 @@ use core::{convert::Infallible, marker::PhantomData}; use crate::peripherals::{GPIO, IO_MUX}; pub use crate::soc::gpio::*; -pub(crate) use crate::{analog, gpio, rtc_pins}; +pub(crate) use crate::{analog, gpio}; +#[cfg(xtensa)] +pub(crate) use crate::rtc_pins; /// Convenience type-alias for a no-pin / don't care - pin pub type NoPinType = Gpio0; @@ -1403,11 +1405,12 @@ macro_rules! gpio { }; } +#[cfg(xtensa)] #[doc(hidden)] #[macro_export] macro_rules! rtc_pins { ( - $( ( $pin_num:expr, $rtc_pin:expr, $pin_reg:ident, $prefix:pat ) )+ + $( ( $pin_num:expr, $rtc_pin:expr, $pin_reg:expr, $prefix:pat ) )+ ) => { impl crate::gpio::RTCPin for GpioPin where diff --git a/esp-hal-common/src/soc/esp32s2/gpio.rs b/esp-hal-common/src/soc/esp32s2/gpio.rs index 6bc5c9a0466..d6d62ea78ca 100644 --- a/esp-hal-common/src/soc/esp32s2/gpio.rs +++ b/esp-hal-common/src/soc/esp32s2/gpio.rs @@ -378,6 +378,31 @@ crate::gpio::analog! { (21, 21, rtc_pad21, mux_sel, fun_sel, fun_ie, rue, rde) } +crate::gpio::rtc_pins! { + ( 0, 0, touch_pad[0], touch_pad0_) + ( 1, 1, touch_pad[1], touch_pad0_) + ( 2, 2, touch_pad[2], touch_pad0_) + ( 3, 3, touch_pad[3], touch_pad0_) + ( 4, 4, touch_pad[4], touch_pad0_) + ( 5, 5, touch_pad[5], touch_pad0_) + ( 6, 6, touch_pad[6], touch_pad0_) + ( 7, 7, touch_pad[7], touch_pad0_) + ( 8, 8, touch_pad[8], touch_pad0_) + ( 9, 9, touch_pad[9], touch_pad0_) + (10, 10, touch_pad[10], touch_pad0_) + (11, 11, touch_pad[11], touch_pad0_) + (12, 12, touch_pad[12], touch_pad0_) + (13, 13, touch_pad[13], touch_pad0_) + (14, 14, touch_pad[14], touch_pad0_) + (15, 15, xtal_32p_pad, x32p_) + (16, 16, xtal_32n_pad, x32n_) + (17, 17, pad_dac1, pdac1_) + (18, 18, pad_dac2, pdac2_) + (19, 19, rtc_pad19, "") + (20, 20, rtc_pad20, "") + (21, 21, rtc_pad21, "") +} + impl InterruptStatusRegisterAccess for InterruptStatusRegisterAccessBank0 { fn pro_cpu_interrupt_status_read() -> u32 { unsafe { &*GPIO::PTR }.pcpu_int.read().bits() diff --git a/esp-hal-common/src/soc/esp32s3/gpio.rs b/esp-hal-common/src/soc/esp32s3/gpio.rs index fd2eea84e1f..a6b7153c6ed 100644 --- a/esp-hal-common/src/soc/esp32s3/gpio.rs +++ b/esp-hal-common/src/soc/esp32s3/gpio.rs @@ -333,6 +333,31 @@ crate::gpio::analog! { (21, 21, rtc_pad21, mux_sel, fun_sel, fun_ie, rue, rde) } +crate::gpio::rtc_pins!{ + ( 0, 0, touch_pad0, "") + ( 1, 1, touch_pad1, "") + ( 2, 2, touch_pad2, "") + ( 3, 3, touch_pad3, "") + ( 4, 4, touch_pad4, "") + ( 5, 5, touch_pad5, "") + ( 6, 6, touch_pad6, "") + ( 7, 7, touch_pad7, "") + ( 8, 8, touch_pad8, "") + ( 9, 9, touch_pad9, "") + (10, 10, touch_pad10, "") + (11, 11, touch_pad11, "") + (12, 12, touch_pad12, "") + (13, 13, touch_pad13, "") + (14, 14, touch_pad14, "") + (15, 15, xtal_32p_pad, x32p_) + (16, 16, xtal_32n_pad, x32n_) + (17, 17, pad_dac1, pdac1_) + (18, 18, pad_dac2, pdac2_) + (19, 19, rtc_pad19, "") + (20, 20, rtc_pad20, "") + (21, 21, rtc_pad21, "") +} + // Whilst the S3 is a dual core chip, it shares the enable registers between // cores so treat it as a single core device impl InterruptStatusRegisterAccess for InterruptStatusRegisterAccessBank0 { From 2b69b0e3ed9afd90b26accf3ae10703893908b03 Mon Sep 17 00:00:00 2001 From: liebman Date: Sun, 11 Jun 2023 09:27:05 -0700 Subject: [PATCH 14/20] cargo fmt & update changelog --- esp-hal-common/Cargo.toml | 10 +++++----- esp-hal-common/src/gpio.rs | 4 ++-- esp-hal-common/src/soc/esp32s3/gpio.rs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 824cc96c45e..0e45a2c5090 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -66,11 +66,11 @@ basic-toml = "0.1.2" serde = { version = "1.0.164", features = ["derive"] } [features] -esp32 = ["esp32/rt", "xtensa", "xtensa-lx/esp32", "xtensa-lx-rt/esp32", "lock_api", "procmacros/esp32"] -esp32c2 = ["esp32c2/rt", "riscv", "procmacros/esp32c2"] -esp32c3 = ["esp32c3/rt", "riscv", "procmacros/esp32c3"] -esp32c6 = ["esp32c6/rt", "riscv", "procmacros/esp32c6"] -esp32h2 = ["esp32h2/rt", "riscv", "procmacros/esp32h2"] +esp32 = ["esp32/rt", "xtensa", "xtensa-lx/esp32", "xtensa-lx-rt/esp32", "lock_api", "procmacros/esp32"] +esp32c2 = ["esp32c2/rt", "riscv", "procmacros/esp32c2"] +esp32c3 = ["esp32c3/rt", "riscv", "procmacros/esp32c3"] +esp32c6 = ["esp32c6/rt", "riscv", "procmacros/esp32c6"] +esp32h2 = ["esp32h2/rt", "riscv", "procmacros/esp32h2"] esp32s2 = ["esp32s2/rt", "xtensa", "xtensa-lx/esp32s2", "xtensa-lx-rt/esp32s2", "esp-synopsys-usb-otg", "usb-device", "procmacros/esp32s2"] esp32s3 = ["esp32s3/rt", "xtensa", "xtensa-lx/esp32s3", "xtensa-lx-rt/esp32s3", "lock_api", "esp-synopsys-usb-otg", "usb-device", "procmacros/esp32s3"] diff --git a/esp-hal-common/src/gpio.rs b/esp-hal-common/src/gpio.rs index e880a8f43cc..831ecdac0c2 100644 --- a/esp-hal-common/src/gpio.rs +++ b/esp-hal-common/src/gpio.rs @@ -11,10 +11,10 @@ use core::{convert::Infallible, marker::PhantomData}; use crate::peripherals::{GPIO, IO_MUX}; -pub use crate::soc::gpio::*; -pub(crate) use crate::{analog, gpio}; #[cfg(xtensa)] pub(crate) use crate::rtc_pins; +pub use crate::soc::gpio::*; +pub(crate) use crate::{analog, gpio}; /// Convenience type-alias for a no-pin / don't care - pin pub type NoPinType = Gpio0; diff --git a/esp-hal-common/src/soc/esp32s3/gpio.rs b/esp-hal-common/src/soc/esp32s3/gpio.rs index a6b7153c6ed..7bcf204fba0 100644 --- a/esp-hal-common/src/soc/esp32s3/gpio.rs +++ b/esp-hal-common/src/soc/esp32s3/gpio.rs @@ -333,7 +333,7 @@ crate::gpio::analog! { (21, 21, rtc_pad21, mux_sel, fun_sel, fun_ie, rue, rde) } -crate::gpio::rtc_pins!{ +crate::gpio::rtc_pins! { ( 0, 0, touch_pad0, "") ( 1, 1, touch_pad1, "") ( 2, 2, touch_pad2, "") From e84b147495b6912e24670f10e62708e39ec727f2 Mon Sep 17 00:00:00 2001 From: liebman Date: Sun, 11 Jun 2023 10:19:53 -0700 Subject: [PATCH 15/20] fix change log order (accidentally swaped during rebase) From a7faaed482d4a133b695b4438d399c5d7b6987b2 Mon Sep 17 00:00:00 2001 From: liebman Date: Sun, 11 Jun 2023 13:45:28 -0700 Subject: [PATCH 16/20] implement Drop for Ext0WakeupSource --- esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs index 9383b9093e3..785d922d069 100644 --- a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs @@ -88,6 +88,15 @@ impl<'a, P: Pin + RTCPin> WakeSource for Ext0WakeupSource<'a, P> { } } +impl<'a, P: Pin + RTCPin> Drop for Ext0WakeupSource<'a, P> { + fn drop(&mut self) { + // should we have saved the pin configuration first? + // set pin back to IO_MUX (input_enable and func have no effect when pin is sent + // to IO_MUX) + self.pin.borrow_mut().rtc_set_config(true, false, 0); + } +} + bitfield::bitfield! { #[derive(Clone, Copy)] pub struct RtcSleepConfig(u32); From beefb5b9467c72870c2412c10a787a668dc94376 Mon Sep 17 00:00:00 2001 From: liebman Date: Tue, 20 Jun 2023 14:05:17 -0700 Subject: [PATCH 17/20] added Ext1 wakeup source --- .../src/rtc_cntl/rtc/esp32_sleep.rs | 40 ++++++++++- esp-hal-common/src/rtc_cntl/sleep.rs | 14 ++++ esp32-hal/examples/sleep_timer_ext1.rs | 71 +++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 esp32-hal/examples/sleep_timer_ext1.rs diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs index 785d922d069..53ed710c51c 100644 --- a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs @@ -1,4 +1,4 @@ -use super::{Ext0WakeupSource, TimerWakeupSource, WakeSource, WakeTriggers}; +use super::{Ext0WakeupSource, TimerWakeupSource, WakeSource, WakeTriggers, Ext1WakeupSource}; use crate::{ gpio::{Pin, RTCPin}, rtc_cntl::{sleep::WakeupLevel, Clock, RtcClock}, @@ -97,6 +97,44 @@ impl<'a, P: Pin + RTCPin> Drop for Ext0WakeupSource<'a, P> { } } +impl<'a> WakeSource for Ext1WakeupSource<'a> { + fn apply(&self, _rtc: &Rtc, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig) { + // don't power down RTC peripherals + sleep_config.set_rtc_peri_pd_en(false); + triggers.set_ext1(true); + + // set pins to RTC function + let mut pins = self.pins.borrow_mut(); + let mut bits = 0u32; + for pin in pins.iter_mut() { + pin.rtc_set_config(true, true, 0); + bits |= 1< Drop for Ext1WakeupSource<'a> { + fn drop(&mut self) { + // should we have saved the pin configuration first? + // set pin back to IO_MUX (input_enable and func have no effect when pin is sent + // to IO_MUX) + let mut pins = self.pins.borrow_mut(); + for pin in pins.iter_mut() { + pin.rtc_set_config(true, false, 0); + } + } +} + bitfield::bitfield! { #[derive(Clone, Copy)] pub struct RtcSleepConfig(u32); diff --git a/esp-hal-common/src/rtc_cntl/sleep.rs b/esp-hal-common/src/rtc_cntl/sleep.rs index de67012109f..0c373318b3a 100644 --- a/esp-hal-common/src/rtc_cntl/sleep.rs +++ b/esp-hal-common/src/rtc_cntl/sleep.rs @@ -49,6 +49,20 @@ impl<'a, P: RTCPin + Pin> Ext0WakeupSource<'a, P> { } } +pub struct Ext1WakeupSource<'a> { + pins: RefCell<&'a mut [&'a mut dyn RTCPin]>, + level: WakeupLevel, +} + +impl<'a> Ext1WakeupSource<'a> { + pub fn new(pins: &'a mut [&'a mut dyn RTCPin], level: WakeupLevel) -> Self { + Self { + pins: RefCell::new(pins), + level, + } + } +} + bitfield::bitfield! { #[derive(Default, Clone, Copy)] pub struct WakeTriggers(u16); diff --git a/esp32-hal/examples/sleep_timer_ext1.rs b/esp32-hal/examples/sleep_timer_ext1.rs new file mode 100644 index 00000000000..5716d9a55e6 --- /dev/null +++ b/esp32-hal/examples/sleep_timer_ext1.rs @@ -0,0 +1,71 @@ +//! Demonstrates deep sleep with timer and ext1 (using gpio27 & gpio23) wakeup + +#![no_std] +#![no_main] + +use core::time::Duration; + +use esp32_hal as hal; +use esp_backtrace as _; +use esp_println::println; +use hal::{ + clock::ClockControl, + entry, + peripherals::Peripherals, + prelude::*, + rtc_cntl::{ + get_reset_reason, + get_wakeup_cause, + sleep::{Ext1WakeupSource, TimerWakeupSource, WakeupLevel}, + SocResetReason, + }, + timer::TimerGroup, + Delay, + Rtc, + IO, +}; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.DPORT.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + // Disable the RTC and TIMG watchdog timers + let mut rtc = Rtc::new(peripherals.RTC_CNTL); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let mut pin27 = io.pins.gpio27; + let mut pin32 = io.pins.gpio32; + + println!("up and runnning!"); + let reason = get_reset_reason(hal::Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); + println!("reset reason: {:?}", reason); + let wake_reason = get_wakeup_cause(); + println!("wake reason: {:?}", wake_reason); + + let mut delay = Delay::new(&clocks); + + let timer = TimerWakeupSource::new(Duration::from_secs(30)); + let mut wakeup_pins: [&mut dyn hal::gpio::RTCPin; 2] = [&mut pin27, &mut pin32]; + let ext1 = Ext1WakeupSource::new(&mut wakeup_pins, WakeupLevel::High); + println!("sleeping!"); + delay.delay_ms(100u32); + rtc.sleep_deep(&[&timer, &ext1], &mut delay); +} From 1ef535bc684f37fabe4cfc1eac6833d0e8a5ee58 Mon Sep 17 00:00:00 2001 From: liebman Date: Tue, 20 Jun 2023 14:51:05 -0700 Subject: [PATCH 18/20] cargo fmt --- esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs index 53ed710c51c..9e3553e28ad 100644 --- a/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs +++ b/esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs @@ -1,4 +1,4 @@ -use super::{Ext0WakeupSource, TimerWakeupSource, WakeSource, WakeTriggers, Ext1WakeupSource}; +use super::{Ext0WakeupSource, Ext1WakeupSource, TimerWakeupSource, WakeSource, WakeTriggers}; use crate::{ gpio::{Pin, RTCPin}, rtc_cntl::{sleep::WakeupLevel, Clock, RtcClock}, @@ -108,7 +108,7 @@ impl<'a> WakeSource for Ext1WakeupSource<'a> { let mut bits = 0u32; for pin in pins.iter_mut() { pin.rtc_set_config(true, true, 0); - bits |= 1< Date: Tue, 20 Jun 2023 15:08:54 -0700 Subject: [PATCH 19/20] healpess was unused, removed --- esp-hal-common/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 0e45a2c5090..091fee40979 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -23,7 +23,6 @@ embedded-hal-1 = { version = "=1.0.0-alpha.11", optional = true, package = embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true } esp-synopsys-usb-otg = { version = "0.3.2", optional = true, features = ["fs", "esp32sx"] } fugit = "0.3.7" -heapless = "0.7.16" log = "=0.4.18" lock_api = { version = "0.4.10", optional = true } nb = "1.1.0" From a2b0941001a95366759009c3206b980423769e9e Mon Sep 17 00:00:00 2001 From: liebman Date: Fri, 14 Jul 2023 07:07:26 -0700 Subject: [PATCH 20/20] fix pase macro usage --- esp-hal-common/src/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp-hal-common/src/gpio.rs b/esp-hal-common/src/gpio.rs index 831ecdac0c2..44b43473071 100644 --- a/esp-hal-common/src/gpio.rs +++ b/esp-hal-common/src/gpio.rs @@ -1434,7 +1434,7 @@ macro_rules! rtc_pins { $( $pin_num => { // disable input - paste!{ + paste::paste!{ rtcio.$pin_reg.modify(|_,w| unsafe {w .[<$prefix fun_ie>]().bit(input_enable) .[<$prefix mux_sel>]().bit(mux)