Skip to content

Commit

Permalink
Allow pin drivers as wakeup sources (#2095)
Browse files Browse the repository at this point in the history
Co-authored-by: Scott Mabin <[email protected]>
  • Loading branch information
bugadani and MabezDev authored Sep 9, 2024
1 parent 3ea95bd commit be82a65
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 19 deletions.
1 change: 1 addition & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added sleep and wakeup support for esp32c2 (#1922)
- `Input`, `Output`, `OutputOpenDrain` and `Flex` now implement `Peripheral`. (#2094)
- Previously unavailable memory is available via `.dram2_uninit` section (#2079)
- You can now use `Input`, `Output`, `OutputOpenDrain` and `Flex` pins as EXTI and RTCIO wakeup sources (#2095)
- Added `Rtc::set_current_time` to allow setting RTC time, and `Rtc::current_time` to getting RTC time while taking into account boot time (#1883)

### Changed
Expand Down
22 changes: 22 additions & 0 deletions esp-hal/MIGRATING-0.20.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,28 @@ let pin = Input::new(io.gpio0); // pin will have the type `Input<'some>` (or `In
let pin = Input::new_typed(io.gpio0); // pin will have the type `Input<'some, GpioPin<0>>`
```

### Wakeup using pin drivers

You can now use pin drivers as wakeup sources.

```rust
use esp_hal::peripheral::Peripheral; // needed for `into_ref`

let pin2 = Input::new(io.pins.gpio2, Pull::None);
let mut pin3 = Input::new(io.pins.gpio3, Pull::None);
// ... use pin2 as an input ..

// Ext0
let ext0 = Ext0WakeupSource::new(pin2, WakeupLevel::High);

// Ext1
let mut wakeup_pins: [&mut dyn RtcPin; 2] = [
&mut *pin_0.into_ref(),
&mut io.pins.gpio4, // unconfigured pins continue to work, too!
];
let ext1 = Ext1WakeupSource::new(&mut wakeup_pins, WakeupLevel::High);
```

## `esp_hal::time::current_time` rename

To avoid confusion with the `Rtc::current_time` wall clock time APIs, we've renamed `esp_hal::time::current_time` to `esp_hal::time::now()`.
Expand Down
18 changes: 18 additions & 0 deletions esp-hal/src/gpio/lp_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,24 @@ macro_rules! lp_gpio {
}
}
)+

#[doc(hidden)]
#[macro_export]
macro_rules! handle_rtcio {
($this:expr, $inner:ident, $code:tt) => {
match $this {
$(
ErasedPinInner::[<Gpio $gpionum >]($inner) => {
$code
},
)+

_ => panic!("Unsupported")
}
}
}
pub(crate) use handle_rtcio;
pub(crate) use handle_rtcio as handle_rtcio_with_resistors;
}
}
}
Expand Down
107 changes: 105 additions & 2 deletions esp-hal/src/gpio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,45 @@ macro_rules! rtc_pins {
$(
$crate::gpio::rtc_pins!($pin_num, $rtc_pin, $pin_reg, $prefix, $hold $(, $rue, $rde)?);
)+

#[doc(hidden)]
#[macro_export]
macro_rules! handle_rtcio {
($this:expr, $inner:ident, $code:tt) => {
match $this {
$(
paste::paste! { ErasedPinInner::[<Gpio $pin_num >]($inner) } => {
$code
},
)+

_ => panic!("Unsupported")
}
}
}

#[doc(hidden)]
#[macro_export]
macro_rules! handle_rtcio_with_resistors {
(@ignore $a:ident, $b:ident) => {};
($this:expr, $inner:ident, $code:tt) => {
match $this {
$(
$(
paste::paste! { ErasedPinInner::[<Gpio $pin_num >]($inner) } => {
// FIXME: replace with $(ignore($rue)) once stable
handle_rtcio_with_resistors!(@ignore $rue, $rde);
$code
},
)?
)+

_ => panic!("Unsupported")
}
}
}
pub(crate) use handle_rtcio;
pub(crate) use handle_rtcio_with_resistors;
};
}

Expand Down Expand Up @@ -1458,10 +1497,30 @@ macro_rules! rtc_pins {
io_mux.gpio($pin_num).modify(|_, w| w.fun_wpd().bit(enable));
}
}

};

( $( $pin_num:expr )+ ) => { $( $crate::gpio::rtc_pins!($pin_num); )+ };
( $( $pin_num:expr )+ ) => {
$( $crate::gpio::rtc_pins!($pin_num); )+

#[doc(hidden)]
#[macro_export]
macro_rules! handle_rtcio {
($this:expr, $inner:ident, $code:tt) => {
match $this {
$(
paste::paste! { ErasedPinInner::[<Gpio $pin_num >]($inner) } => {
$code
},
)+

_ => panic!("Unsupported")
}
}
}

pub(crate) use handle_rtcio;
pub(crate) use handle_rtcio as handle_rtcio_with_resistors;
};
}

#[doc(hidden)]
Expand Down Expand Up @@ -2380,6 +2439,50 @@ pub(crate) mod internal {
})
}
}

#[cfg(any(xtensa, esp32c2, esp32c3, esp32c6))]
impl RtcPin for ErasedPin {
#[cfg(xtensa)]
#[allow(unused_braces)] // False positive :/
fn rtc_number(&self) -> u8 {
handle_rtcio!(&self.0, target, { RtcPin::rtc_number(target) })
}

#[cfg(any(xtensa, esp32c6))]
fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: RtcFunction) {
handle_rtcio!(&mut self.0, target, {
RtcPin::rtc_set_config(target, input_enable, mux, func)
})
}

fn rtcio_pad_hold(&mut self, enable: bool) {
handle_rtcio!(&mut self.0, target, {
RtcPin::rtcio_pad_hold(target, enable)
})
}

#[cfg(any(esp32c2, esp32c3, esp32c6))]
unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8) {
handle_rtcio!(&mut self.0, target, {
RtcPin::apply_wakeup(target, wakeup, level)
})
}
}

#[cfg(any(esp32c2, esp32c3, esp32c6, xtensa))]
impl RtcPinWithResistors for ErasedPin {
fn rtcio_pullup(&mut self, enable: bool) {
handle_rtcio_with_resistors!(&mut self.0, target, {
RtcPinWithResistors::rtcio_pullup(target, enable)
})
}

fn rtcio_pulldown(&mut self, enable: bool) {
handle_rtcio_with_resistors!(&mut self.0, target, {
RtcPinWithResistors::rtcio_pulldown(target, enable)
})
}
}
}

fn is_listening(pin_num: u8) -> bool {
Expand Down
11 changes: 8 additions & 3 deletions esp-hal/src/rtc_cntl/sleep/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ use crate::gpio::RtcPin as RtcIoWakeupPinType;
#[cfg(any(esp32c3, esp32c6, esp32c2))]
use crate::gpio::RtcPinWithResistors as RtcIoWakeupPinType;
use crate::rtc_cntl::Rtc;
#[cfg(any(esp32, esp32s3))]
use crate::{
into_ref,
peripheral::{Peripheral, PeripheralRef},
};

#[cfg_attr(esp32, path = "esp32.rs")]
#[cfg_attr(esp32s3, path = "esp32s3.rs")]
Expand Down Expand Up @@ -71,11 +76,10 @@ pub enum Error {
}

/// External wake-up source (Ext0).
#[derive(Debug)]
#[cfg(any(esp32, esp32s3))]
pub struct Ext0WakeupSource<'a, P: RtcIoWakeupPinType> {
/// The pin used as the wake-up source.
pin: RefCell<&'a mut P>,
pin: RefCell<PeripheralRef<'a, P>>,
/// The level at which the wake-up event is triggered.
level: WakeupLevel,
}
Expand All @@ -84,7 +88,8 @@ pub struct Ext0WakeupSource<'a, P: RtcIoWakeupPinType> {
impl<'a, P: RtcIoWakeupPinType> Ext0WakeupSource<'a, P> {
/// Creates a new external wake-up source (Ext0``) with the specified pin
/// and wake-up level.
pub fn new(pin: &'a mut P, level: WakeupLevel) -> Self {
pub fn new(pin: impl Peripheral<P = P> + 'a, level: WakeupLevel) -> Self {
into_ref!(pin);
Self {
pin: RefCell::new(pin),
level,
Expand Down
6 changes: 3 additions & 3 deletions examples/src/bin/sleep_timer_ext0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use esp_backtrace as _;
use esp_hal::{
delay::Delay,
entry,
gpio::Io,
gpio::{Input, Io, Pull},
rtc_cntl::{
get_reset_reason,
get_wakeup_cause,
Expand All @@ -33,7 +33,7 @@ fn main() -> ! {
let mut rtc = Rtc::new(peripherals.LPWR);

let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let mut ext0_pin = io.pins.gpio4;
let ext0_pin = Input::new(io.pins.gpio4, Pull::None);

println!("up and runnning!");
let reason = get_reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn);
Expand All @@ -44,7 +44,7 @@ fn main() -> ! {
let delay = Delay::new();

let timer = TimerWakeupSource::new(Duration::from_secs(30));
let ext0 = Ext0WakeupSource::new(&mut ext0_pin, WakeupLevel::High);
let ext0 = Ext0WakeupSource::new(ext0_pin, WakeupLevel::High);
println!("sleeping!");
delay.delay_millis(100);
rtc.sleep_deep(&[&timer, &ext0]);
Expand Down
7 changes: 4 additions & 3 deletions examples/src/bin/sleep_timer_ext1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use esp_backtrace as _;
use esp_hal::{
delay::Delay,
entry,
gpio::{Io, RtcPin},
gpio::{Input, Io, Pull, RtcPin},
peripheral::Peripheral,
rtc_cntl::{
get_reset_reason,
get_wakeup_cause,
Expand All @@ -33,7 +34,7 @@ fn main() -> ! {
let mut rtc = Rtc::new(peripherals.LPWR);

let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let mut pin_0 = io.pins.gpio4;
let pin_0 = Input::new(io.pins.gpio4, Pull::None);
let mut pin_2 = io.pins.gpio2;

println!("up and runnning!");
Expand All @@ -45,7 +46,7 @@ fn main() -> ! {
let delay = Delay::new();

let timer = TimerWakeupSource::new(Duration::from_secs(30));
let mut wakeup_pins: [&mut dyn RtcPin; 2] = [&mut pin_0, &mut pin_2];
let mut wakeup_pins: [&mut dyn RtcPin; 2] = [&mut *pin_0.into_ref(), &mut pin_2];
let ext1 = Ext1WakeupSource::new(&mut wakeup_pins, WakeupLevel::High);
println!("sleeping!");
delay.delay_millis(100);
Expand Down
7 changes: 4 additions & 3 deletions examples/src/bin/sleep_timer_lpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use esp_backtrace as _;
use esp_hal::{
delay::Delay,
entry,
gpio::{Io, RtcPinWithResistors},
gpio::{Input, Io, Pull, RtcPinWithResistors},
peripheral::Peripheral,
rtc_cntl::{
get_reset_reason,
get_wakeup_cause,
Expand All @@ -34,7 +35,7 @@ fn main() -> ! {
let mut rtc = Rtc::new(peripherals.LPWR);

let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let mut pin2 = io.pins.gpio2;
let pin2 = Input::new(io.pins.gpio2, Pull::None);
let mut pin3 = io.pins.gpio3;

println!("up and runnning!");
Expand All @@ -47,7 +48,7 @@ fn main() -> ! {
let timer = TimerWakeupSource::new(Duration::from_secs(10));

let wakeup_pins: &mut [(&mut dyn RtcPinWithResistors, WakeupLevel)] = &mut [
(&mut pin2, WakeupLevel::Low),
(&mut *pin2.into_ref(), WakeupLevel::Low),
(&mut pin3, WakeupLevel::High),
];

Expand Down
18 changes: 13 additions & 5 deletions examples/src/bin/sleep_timer_rtcio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ use esp_hal::{
delay::Delay,
entry,
gpio,
gpio::Io,
gpio::{Input, Io, Pull},
peripheral::Peripheral,
rtc_cntl::{
get_reset_reason,
get_wakeup_cause,
Expand All @@ -35,7 +36,7 @@ use esp_println::println;
fn main() -> ! {
let peripherals = esp_hal::init(esp_hal::Config::default());

let mut io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let mut rtc = Rtc::new(peripherals.LPWR);

println!("up and runnning!");
Expand All @@ -49,13 +50,20 @@ fn main() -> ! {

cfg_if::cfg_if! {
if #[cfg(any(feature = "esp32c3", feature = "esp32c2"))] {
let pin2 = Input::new(io.pins.gpio2, Pull::None);
let mut pin3 = io.pins.gpio3;

let wakeup_pins: &mut [(&mut dyn gpio::RtcPinWithResistors, WakeupLevel)] = &mut [
(&mut io.pins.gpio2, WakeupLevel::Low),
(&mut io.pins.gpio3, WakeupLevel::High),
(&mut *pin2.into_ref(), WakeupLevel::Low),
(&mut pin3, WakeupLevel::High),
];
} else if #[cfg(feature = "esp32s3")] {
let pin17 = Input::new(io.pins.gpio17, Pull::None);
let mut pin18 = io.pins.gpio18;

let wakeup_pins: &mut [(&mut dyn gpio::RtcPin, WakeupLevel)] = &mut [
(&mut io.pins.gpio18, WakeupLevel::Low)
(&mut *pin17.into_ref(), WakeupLevel::Low),
(&mut pin18, WakeupLevel::High),
];
}
}
Expand Down

0 comments on commit be82a65

Please sign in to comment.