Skip to content

Commit

Permalink
S3: GPIO wakeup source with RTC_IO pins (#690)
Browse files Browse the repository at this point in the history
* Remove unnecessary Pin bounds

* S3: Add RTC_IO wakeup source

* Add s3 example

* Add changelog entry

---------

Co-authored-by: Jesse Braham <[email protected]>
  • Loading branch information
bugadani and jessebraham authored Aug 23, 2023
1 parent 95a1255 commit 6c2659f
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add GPIO (output) and delay functionality to `esp32c6-lp-hal` (#715)
- Implement RTCIO pullup, pulldown and hold control for Xtensa MCUs (#684)
- Add GPIO input support and implement additional `embedded-hal` output traits for the C6's LP core [#720]
- S3: Implement RTCIO wakeup source (#690)
- Add PARL_IO TX driver for ESP32-C6 / ESP32-H2 (#733)
- Implement `ufmt_write::uWrite` trait for USB Serial JTAG (#751)

Expand Down
6 changes: 3 additions & 3 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, RtcFunction},
gpio::{RTCPin, RtcFunction},
rtc_cntl::{sleep::WakeupLevel, Clock, RtcClock},
Rtc,
};
Expand Down Expand Up @@ -65,7 +65,7 @@ impl WakeSource for TimerWakeupSource {
}
}

impl<P: Pin + RTCPin> WakeSource for Ext0WakeupSource<'_, P> {
impl<P: RTCPin> WakeSource for Ext0WakeupSource<'_, 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);
Expand All @@ -91,7 +91,7 @@ impl<P: Pin + RTCPin> WakeSource for Ext0WakeupSource<'_, P> {
}
}

impl<P: Pin + RTCPin> Drop for Ext0WakeupSource<'_, P> {
impl<P: RTCPin> Drop for Ext0WakeupSource<'_, 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
Expand Down
60 changes: 56 additions & 4 deletions esp-hal-common/src/rtc_cntl/rtc/esp32s3_sleep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use super::{
WakeupLevel,
};
use crate::{
gpio::{Pin, RTCPin, RtcFunction},
gpio::{RTCPin, RtcFunction},
regi2c_write_mask,
rtc_cntl::{Clock, RtcClock},
rtc_cntl::{sleep::RtcioWakeupSource, Clock, RtcClock},
Rtc,
};

Expand Down Expand Up @@ -110,7 +110,7 @@ impl WakeSource for TimerWakeupSource {
}
}

impl<P: Pin + RTCPin> WakeSource for Ext0WakeupSource<'_, P> {
impl<P: RTCPin> WakeSource for Ext0WakeupSource<'_, 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);
Expand All @@ -136,7 +136,7 @@ impl<P: Pin + RTCPin> WakeSource for Ext0WakeupSource<'_, P> {
}
}

impl<P: Pin + RTCPin> Drop for Ext0WakeupSource<'_, P> {
impl<P: RTCPin> Drop for Ext0WakeupSource<'_, 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
Expand Down Expand Up @@ -191,6 +191,58 @@ impl Drop for Ext1WakeupSource<'_, '_> {
}
}

impl<'a, 'b> RtcioWakeupSource<'a, 'b> {
fn apply_pin(&self, pin: &mut dyn RTCPin, level: WakeupLevel) {
let rtcio = unsafe { &*crate::peripherals::RTC_IO::PTR };

pin.rtc_set_config(true, true, RtcFunction::Rtc);

rtcio.pin[pin.number() as usize].modify(|_, w| {
w.wakeup_enable().set_bit().int_type().variant(match level {
WakeupLevel::Low => 4,
WakeupLevel::High => 5,
})
});
}
}

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;
}

// don't power down RTC peripherals
sleep_config.set_rtc_peri_pd_en(false);
triggers.set_gpio(true);

// Since we only use RTCIO pins, we can keep deep sleep enabled.
let sens = unsafe { &*crate::peripherals::SENS::PTR };

// TODO: disable clock when not in use
sens.sar_peri_clk_gate_conf
.modify(|_, w| w.iomux_clk_en().set_bit());

for (pin, level) in pins.iter_mut() {
self.apply_pin(*pin, *level);
}
}
}

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)]
pub struct RtcSleepConfig(u64);
Expand Down
27 changes: 21 additions & 6 deletions esp-hal-common/src/rtc_cntl/sleep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@
use core::{cell::RefCell, time::Duration};

use crate::{
gpio::{Pin, RTCPin},
Rtc,
};
use crate::{gpio::RTCPin, Rtc};

#[cfg_attr(esp32, path = "rtc/esp32_sleep.rs")]
#[cfg_attr(esp32s3, path = "rtc/esp32s3_sleep.rs")]
Expand Down Expand Up @@ -58,12 +55,12 @@ pub enum Error {

#[allow(unused)]
#[derive(Debug)]
pub struct Ext0WakeupSource<'a, P: RTCPin + Pin> {
pub struct Ext0WakeupSource<'a, P: RTCPin> {
pin: RefCell<&'a mut P>,
level: WakeupLevel,
}

impl<'a, P: RTCPin + Pin> Ext0WakeupSource<'a, P> {
impl<'a, P: RTCPin> Ext0WakeupSource<'a, P> {
pub fn new(pin: &'a mut P, level: WakeupLevel) -> Self {
Self {
pin: RefCell::new(pin),
Expand All @@ -86,6 +83,24 @@ impl<'a, 'b> Ext1WakeupSource<'a, 'b> {
}
}

/// RTC_IO wakeup source
///
/// RTC_IO wakeup allows configuring any combination of RTC_IO pins with
/// arbitrary wakeup levels to wake up the chip from sleep. This wakeup source
/// can be used to wake up from both light and deep sleep.
#[allow(unused)]
pub struct RtcioWakeupSource<'a, 'b> {
pins: RefCell<&'a mut [(&'b mut dyn RTCPin, WakeupLevel)]>,
}

impl<'a, 'b> RtcioWakeupSource<'a, 'b> {
pub fn new(pins: &'a mut [(&'b mut dyn RTCPin, WakeupLevel)]) -> Self {
Self {
pins: RefCell::new(pins),
}
}
}

bitfield::bitfield! {
#[derive(Default, Clone, Copy)]
pub struct WakeTriggers(u16);
Expand Down
79 changes: 79 additions & 0 deletions esp32s3-hal/examples/sleep_timer_rtcio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! Demonstrates deep sleep with timer and ext0 (using gpio18) wakeup
#![no_std]
#![no_main]

use core::time::Duration;

use esp32s3_hal as hal;
use esp_backtrace as _;
use esp_hal_common::{
gpio::{RTCPin, RTCPinWithResistors},
rtc_cntl::sleep::RtcioWakeupSource,
};
use esp_println::println;
use hal::{
clock::ClockControl,
entry,
peripherals::Peripherals,
prelude::*,
rtc_cntl::{
get_reset_reason,
get_wakeup_cause,
sleep::{TimerWakeupSource, WakeupLevel},
SocResetReason,
},
timer::TimerGroup,
Delay,
Rtc,
IO,
};

#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.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 rtcio_pin18 = io.pins.gpio18;

rtcio_pin18.rtcio_pad_hold(true);
rtcio_pin18.rtcio_pullup(true);

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 RTCPin, WakeupLevel); 1] =
[(&mut rtcio_pin18, WakeupLevel::Low)];
let rtcio = RtcioWakeupSource::new(&mut wakeup_pins);
println!("sleeping!");
delay.delay_ms(100u32);
rtc.sleep_deep(&[&timer, &rtcio], &mut delay);
}

0 comments on commit 6c2659f

Please sign in to comment.