Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add a new RMT driver (#653, #667)
- Implemented calibrated ADC API for ESP32-S3 (#641)
- Add MCPWM DeadTime configuration (#406)
- Implement sleep with some wakeup methods for `esp32-s3` (#660)

### Changed

Expand Down
12 changes: 9 additions & 3 deletions esp-hal-common/src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,15 @@ pub enum AlternateFunction {
Function5 = 5,
}

#[derive(PartialEq)]
pub enum RtcFunction {
Rtc = 0,
Digital = 1,
}

pub trait RTCPin {
fn rtc_number(&self) -> u8;
fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: u8);
fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: RtcFunction);
}

pub trait RTCInputPin: RTCPin {}
Expand Down Expand Up @@ -1438,7 +1444,7 @@ macro_rules! rtc_pins {

/// 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) {
fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: crate::gpio::RtcFunction) {
use crate::peripherals::RTC_IO;
let rtcio = unsafe{ &*RTC_IO::ptr() };

Expand All @@ -1447,7 +1453,7 @@ macro_rules! rtc_pins {
rtcio.$pin_reg.modify(|_,w| unsafe {w
.[<$prefix fun_ie>]().bit(input_enable)
.[<$prefix mux_sel>]().bit(mux)
.[<$prefix fun_sel>]().bits(func)
.[<$prefix fun_sel>]().bits(func as u8)
});
}
}
Expand Down
44 changes: 19 additions & 25 deletions esp-hal-common/src/rtc_cntl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ 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))]
#[cfg(any(esp32, esp32s3))]
use crate::rtc_cntl::sleep::{RtcSleepConfig, WakeSource, WakeTriggers};
use crate::{
clock::Clock,
Expand All @@ -23,7 +23,7 @@ use crate::{
Cpu,
};
// only include sleep where its been implemented
#[cfg(any(esp32))]
#[cfg(any(esp32, esp32s3))]
pub mod sleep;

#[cfg(any(esp32c6, esp32h2))]
Expand Down Expand Up @@ -136,12 +136,17 @@ impl<'d> Rtc<'d> {
rtc::init();
rtc::configure_clock();

Self {
let this = Self {
_inner: rtc_cntl.into_ref(),
rwdt: Rwdt::default(),
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
swd: Swd::new(),
}
};

#[cfg(any(esp32, esp32s3))]
RtcSleepConfig::base_settings(&this);

this
}

// TODO: implement for ESP32-C6
Expand Down Expand Up @@ -198,7 +203,7 @@ impl<'d> Rtc<'d> {
}

/// enter deep sleep and wake with the provided `wake_sources`
#[cfg(esp32)]
#[cfg(any(esp32, esp32s3))]
pub fn sleep_deep<'a>(
&mut self,
wake_sources: &[&'a dyn WakeSource],
Expand All @@ -210,19 +215,19 @@ impl<'d> Rtc<'d> {
}

/// enter light sleep and wake with the provided `wake_sources`
#[cfg(esp32)]
#[cfg(any(esp32, esp32s3))]
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)
self.sleep(&config, wake_sources, delay);
}

/// enter sleep wthe the provided `config` and wake with the provided
/// enter sleep with the provided `config` and wake with the provided
/// `wake_sources`
#[cfg(esp32)]
#[cfg(any(esp32, esp32s3))]
pub fn sleep<'a>(
&mut self,
config: &RtcSleepConfig,
Expand All @@ -234,25 +239,14 @@ impl<'d> Rtc<'d> {
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());
config.apply();

// set bits for what can wake us up
rtc_cntl
.wakeup_state
.modify(|_, w| w.wakeup_ena().bits(wakeup_triggers.0.into()));
use embedded_hal::blocking::delay::DelayMs;
delay.delay_ms(100u32);

rtc_cntl
.state0
.write(|w| w.sleep_en().set_bit().slp_wakeup().set_bit());
}
config.start_sleep(wakeup_triggers);
config.finish_sleep();
}
}

Expand Down
64 changes: 54 additions & 10 deletions esp-hal-common/src/rtc_cntl/rtc/esp32_sleep.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{Ext0WakeupSource, Ext1WakeupSource, TimerWakeupSource, WakeSource, WakeTriggers};
use crate::{
gpio::{Pin, RTCPin},
gpio::{Pin, RTCPin, RtcFunction},
rtc_cntl::{sleep::WakeupLevel, Clock, RtcClock},
Rtc,
};
Expand All @@ -24,6 +24,7 @@ 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_CNTL_DBG_ATTEN_DEFAULT: u8 = 3;

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;
Expand Down Expand Up @@ -71,7 +72,9 @@ impl<'a, P: Pin + RTCPin> WakeSource for Ext0WakeupSource<'a, P> {
triggers.set_ext0(true);

// set pin to RTC function
self.pin.borrow_mut().rtc_set_config(true, true, 0);
self.pin
.borrow_mut()
.rtc_set_config(true, true, RtcFunction::Rtc);

unsafe {
let rtc_io = &*esp32::RTC_IO::ptr();
Expand All @@ -93,7 +96,9 @@ impl<'a, P: Pin + RTCPin> Drop for Ext0WakeupSource<'a, P> {
// 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);
self.pin
.borrow_mut()
.rtc_set_config(true, false, RtcFunction::Rtc);
}
}

Expand All @@ -107,15 +112,17 @@ impl<'a> WakeSource for Ext1WakeupSource<'a> {
let mut pins = self.pins.borrow_mut();
let mut bits = 0u32;
for pin in pins.iter_mut() {
pin.rtc_set_config(true, true, 0);
pin.rtc_set_config(true, true, RtcFunction::Rtc);
bits |= 1 << pin.rtc_number();
}

unsafe {
// set pin register field
// set level register field
let rtc_cntl = &*esp32::RTC_CNTL::ptr();
// clear previous wakeup status
rtc_cntl.ext_wakeup1.modify(|_, w| w.status_clr().set_bit());
// set pin register field
rtc_cntl.ext_wakeup1.modify(|_, w| w.sel().bits(bits));
// set level register field
rtc_cntl
.ext_wakeup_conf
.modify(|_r, w| w.ext_wakeup1_lv().bit(self.level == WakeupLevel::High));
Expand All @@ -130,7 +137,7 @@ impl<'a> Drop for Ext1WakeupSource<'a> {
// to IO_MUX)
let mut pins = self.pins.borrow_mut();
for pin in pins.iter_mut() {
pin.rtc_set_config(true, false, 0);
pin.rtc_set_config(true, false, RtcFunction::Rtc);
}
}
}
Expand Down Expand Up @@ -212,7 +219,7 @@ impl RtcSleepConfig {
cfg
}

fn base_settings(&self, _rtc: &Rtc) {
pub(crate) fn base_settings(_rtc: &Rtc) {
// settings derived from esp-idf after basic boot
unsafe {
let rtc_cntl = &*esp32::RTC_CNTL::ptr();
Expand Down Expand Up @@ -274,8 +281,7 @@ impl RtcSleepConfig {
}
}

pub(crate) fn apply(&self, rtc: &Rtc) {
self.base_settings(rtc);
pub(crate) fn apply(&self) {
// like esp-idf rtc_sleep_init()
unsafe {
let rtc_cntl = &*esp32::RTC_CNTL::ptr();
Expand Down Expand Up @@ -448,4 +454,42 @@ impl RtcSleepConfig {
);
}
}

pub(crate) fn start_sleep(&self, wakeup_triggers: WakeTriggers) {
unsafe {
let rtc_cntl = &*esp32::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());
}
}

pub(crate) fn finish_sleep(&self) {
// In deep sleep mode, we never get here
unsafe {
let rtc_cntl = &*esp32::RTC_CNTL::ptr();

#[rustfmt::skip]
rtc_cntl.int_clr.write(|w| w
.slp_reject_int_clr().set_bit()
.slp_wakeup_int_clr().set_bit()
);

// restore DBG_ATTEN to the default value
#[rustfmt::skip]
rtc_cntl.bias_conf.modify(|_,w| w
.dbg_atten().bits(RTC_CNTL_DBG_ATTEN_DEFAULT)
);
}
}
}
Loading