Allow pin drivers as wakeup sources (#2095)
Co-authored-by: Scott Mabin <scott@mabez.dev>
This commit is contained in:
parent
3ea95bd0d8
commit
be82a6521a
@ -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
|
||||
|
||||
@ -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()`.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@ -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)]
|
||||
@ -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 {
|
||||
|
||||
@ -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")]
|
||||
@ -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,
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
@ -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);
|
||||
@ -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]);
|
||||
|
||||
@ -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,
|
||||
@ -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!");
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
@ -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!");
|
||||
@ -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),
|
||||
];
|
||||
|
||||
|
||||
@ -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,
|
||||
@ -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!");
|
||||
@ -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),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user