From 0fa2d9615348fd1edd8acaaf04a45dcef3d73f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 13 Nov 2023 11:06:42 +0100 Subject: [PATCH] Implement LP_IO wakeup source --- esp-hal-common/src/gpio.rs | 40 +++++++++- esp-hal-common/src/rtc_cntl/sleep/esp32c3.rs | 4 +- esp-hal-common/src/rtc_cntl/sleep/esp32c6.rs | 82 +++++++++++++++++++- 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/esp-hal-common/src/gpio.rs b/esp-hal-common/src/gpio.rs index 243a97e1a34..e1a7721d353 100644 --- a/esp-hal-common/src/gpio.rs +++ b/esp-hal-common/src/gpio.rs @@ -165,7 +165,7 @@ pub trait RTCPin: Pin { // Unsafe because `level` needs to be a valid setting for the // rtc_cntl.gpio_wakeup.gpio_pinX_int_type - #[cfg(esp32c3)] + #[cfg(any(esp32c3, esp32c6))] unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8); } @@ -2528,6 +2528,44 @@ pub mod lp_gpio { } } } + + impl crate::gpio::RTCPin for GpioPin { + unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8) { + let lp_io = &*crate::peripherals::LP_IO::ptr(); + lp_io.[< pin $gpionum >].modify(|_, w| { + w + .[< lp_gpio $gpionum _wakeup_enable >]().bit(wakeup) + .[< lp_gpio $gpionum _int_type >]().bits(level) + }); + } + + fn rtcio_pad_hold(&mut self, enable: bool) { + let mask = 1 << $gpionum; + unsafe { + let lp_aon = &*crate::peripherals::LP_AON::ptr(); + + lp_aon.gpio_hold0.modify(|r, w| { + if enable { + w.gpio_hold0().bits(r.gpio_hold0().bits() | mask) + } else { + w.gpio_hold0().bits(r.gpio_hold0().bits() & !mask) + } + }); + } + } + } + + impl crate::gpio::RTCPinWithResistors for GpioPin { + fn rtcio_pullup(&mut self, enable: bool) { + let lp_io = unsafe { &*crate::peripherals::LP_IO::ptr() }; + lp_io.[< gpio $gpionum >].modify(|_, w| w.[< lp_gpio $gpionum _fun_wpu >]().bit(enable)); + } + + fn rtcio_pulldown(&mut self, enable: bool) { + let lp_io = unsafe { &*crate::peripherals::LP_IO::ptr() }; + lp_io.[< gpio $gpionum >].modify(|_, w| w.[< lp_gpio $gpionum _fun_wpd >]().bit(enable)); + } + } )+ } } diff --git a/esp-hal-common/src/rtc_cntl/sleep/esp32c3.rs b/esp-hal-common/src/rtc_cntl/sleep/esp32c3.rs index 24f16d643d6..9d771690517 100644 --- a/esp-hal-common/src/rtc_cntl/sleep/esp32c3.rs +++ b/esp-hal-common/src/rtc_cntl/sleep/esp32c3.rs @@ -1,6 +1,6 @@ use super::{TimerWakeupSource, WakeSource, WakeTriggers, WakeupLevel}; use crate::{ - gpio::RTCPinWithResistors, + gpio::{RTCPinWithResistors, RtcFunction}, regi2c_write_mask, rtc_cntl::{sleep::RtcioWakeupSource, Clock, RtcClock}, Rtc, @@ -170,7 +170,7 @@ fn isolate_digital_gpio() { io_mux.gpio[pin_num].modify(|_, w| w.fun_wpd().clear_bit()); // make pad work as gpio (otherwise, deep_sleep bottom current will rise) - io_mux.gpio[pin_num].modify(|_, w| w.mcu_sel().variant(PIN_FUNC_GPIO)); + io_mux.gpio[pin_num].modify(|_, w| w.mcu_sel().variant(RtcFunction::Digital as u8)); } } } diff --git a/esp-hal-common/src/rtc_cntl/sleep/esp32c6.rs b/esp-hal-common/src/rtc_cntl/sleep/esp32c6.rs index ff45dd30db9..b11d1176fb9 100644 --- a/esp-hal-common/src/rtc_cntl/sleep/esp32c6.rs +++ b/esp-hal-common/src/rtc_cntl/sleep/esp32c6.rs @@ -1,4 +1,76 @@ -use crate::{rtc_cntl::sleep::WakeTriggers, system::RadioPeripherals, Rtc}; +use crate::{ + clock::Clock, + gpio::RTCPinWithResistors, + rtc_cntl::{ + sleep::{RtcioWakeupSource, TimerWakeupSource, WakeSource, WakeTriggers, WakeupLevel}, + RtcClock, + }, + system::RadioPeripherals, + Rtc, +}; + +impl<'a, 'b> RtcioWakeupSource<'a, 'b> { + fn apply_pin(&self, pin: &mut dyn RTCPinWithResistors, level: WakeupLevel) { + pub const GPIO_INTR_LOW_LEVEL: u8 = 4; + pub const GPIO_INTR_HIGH_LEVEL: u8 = 5; + + // The pullup/pulldown part is like in gpio_deep_sleep_wakeup_prepare + let level = match level { + WakeupLevel::High => { + pin.rtcio_pullup(false); + pin.rtcio_pulldown(true); + GPIO_INTR_HIGH_LEVEL + } + WakeupLevel::Low => { + pin.rtcio_pullup(true); + pin.rtcio_pulldown(false); + GPIO_INTR_LOW_LEVEL + } + }; + pin.rtcio_pad_hold(true); + + // apply_wakeup does the same as idf's esp_deep_sleep_enable_gpio_wakeup + unsafe { + pin.apply_wakeup(true, level); + } + } +} + +impl WakeSource for RtcioWakeupSource<'_, '_> { + fn apply(&self, _rtc: &Rtc, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig) { + let mut pins = self.pins.borrow_mut(); + + if pins.is_empty() { + return; + } + + triggers.set_gpio(true); + + if sleep_config.deep_slp() { + for (pin, level) in pins.iter_mut() { + self.apply_pin(*pin, *level); + } + } + + // like rtcio_ll_clear_interrupt_status, as called from + // gpio_deep_sleep_wakeup_prepare + unsafe { + lp_io().status_w1tc.write(|w| w.bits(0xff)); + } + } +} + +impl Drop for RtcioWakeupSource<'_, '_> { + 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, _level) in pins.iter_mut() { + // pin.rtc_set_config(true, false, RtcFunction::Rtc); + // } + } +} bitfield::bitfield! { #[derive(Clone, Copy)] @@ -676,6 +748,10 @@ unsafe fn lp_aon<'a>() -> &'a esp32c6::lp_aon::RegisterBlock { &*esp32c6::LP_AON::ptr() } +unsafe fn lp_io<'a>() -> &'a esp32c6::lp_io::RegisterBlock { + &*esp32c6::LP_IO::ptr() +} + fn pmu_power_domain_force_default() { unsafe { // for bypass reserved power domain @@ -957,6 +1033,10 @@ fn modem_clock_select_lp_clock_source( } impl RtcSleepConfig { + pub fn deep_slp(&self) -> bool { + self.deep + } + pub fn deep() -> Self { // Set up for ultra-low power sleep. Wakeup sources may modify these settings. let mut cfg = Self::default();