Skip to content

Commit

Permalink
Implement LP_IO wakeup source
Browse files Browse the repository at this point in the history
  • Loading branch information
bugadani committed Nov 13, 2023
1 parent ee2ec17 commit 0fa2d96
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 4 deletions.
40 changes: 39 additions & 1 deletion esp-hal-common/src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -2528,6 +2528,44 @@ pub mod lp_gpio {
}
}
}

impl<MODE> crate::gpio::RTCPin for GpioPin<MODE, $gpionum> {
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<MODE> crate::gpio::RTCPinWithResistors for GpioPin<MODE, $gpionum> {
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));
}
}
)+
}
}
Expand Down
4 changes: 2 additions & 2 deletions esp-hal-common/src/rtc_cntl/sleep/esp32c3.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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));
}
}
}
Expand Down
82 changes: 81 additions & 1 deletion esp-hal-common/src/rtc_cntl/sleep/esp32c6.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 0fa2d96

Please sign in to comment.