mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 22:32:29 +00:00
rp: add dormant-wake functionality for Input
this temporarily takes ownership of pins because we need to clear edge interrupts before waiting for them (otherwise we may wait indefinitely), we want to clean up the dormant-wake bits after a wakeup, and doing anything *else* with the input while we're waiting for a wakeup isn't possible at all. doing it like this lets us not impose any cost on those who don't use dormant wakes without entangling dormant waits too badly with regular interrupt waits.
This commit is contained in:
parent
4d60c715e6
commit
9dfda46e0c
@ -75,6 +75,15 @@ pub enum Bank {
|
||||
Qspi = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct DormantWakeConfig {
|
||||
pub edge_high: bool,
|
||||
pub edge_low: bool,
|
||||
pub level_high: bool,
|
||||
pub level_low: bool,
|
||||
}
|
||||
|
||||
pub struct Input<'d, T: Pin> {
|
||||
pin: Flex<'d, T>,
|
||||
}
|
||||
@ -128,6 +137,11 @@ impl<'d, T: Pin> Input<'d, T> {
|
||||
pub async fn wait_for_any_edge(&mut self) {
|
||||
self.pin.wait_for_any_edge().await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> {
|
||||
self.pin.dormant_wake(cfg)
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt trigger levels.
|
||||
@ -639,15 +653,62 @@ impl<'d, T: Pin> Flex<'d, T> {
|
||||
pub async fn wait_for_any_edge(&mut self) {
|
||||
InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> {
|
||||
let idx = self.pin._pin() as usize;
|
||||
self.pin.io().intr(idx / 8).write(|w| {
|
||||
w.set_edge_high(idx % 8, cfg.edge_high);
|
||||
w.set_edge_low(idx % 8, cfg.edge_low);
|
||||
});
|
||||
self.pin.io().int_dormant_wake().inte(idx / 8).write_set(|w| {
|
||||
w.set_edge_high(idx % 8, cfg.edge_high);
|
||||
w.set_edge_low(idx % 8, cfg.edge_low);
|
||||
w.set_level_high(idx % 8, cfg.level_high);
|
||||
w.set_level_low(idx % 8, cfg.level_low);
|
||||
});
|
||||
DormantWake {
|
||||
pin: self.pin.reborrow(),
|
||||
cfg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> Drop for Flex<'d, T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
let idx = self.pin._pin() as usize;
|
||||
self.pin.pad_ctrl().write(|_| {});
|
||||
self.pin.gpio().ctrl().write(|w| {
|
||||
w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _);
|
||||
});
|
||||
self.pin.io().int_dormant_wake().inte(idx / 8).write_clear(|w| {
|
||||
w.set_edge_high(idx % 8, true);
|
||||
w.set_edge_low(idx % 8, true);
|
||||
w.set_level_high(idx % 8, true);
|
||||
w.set_level_low(idx % 8, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DormantWake<'w, T: Pin> {
|
||||
pin: PeripheralRef<'w, T>,
|
||||
cfg: DormantWakeConfig,
|
||||
}
|
||||
|
||||
impl<'w, T: Pin> Drop for DormantWake<'w, T> {
|
||||
fn drop(&mut self) {
|
||||
let idx = self.pin._pin() as usize;
|
||||
self.pin.io().intr(idx / 8).write(|w| {
|
||||
w.set_edge_high(idx % 8, self.cfg.edge_high);
|
||||
w.set_edge_low(idx % 8, self.cfg.edge_low);
|
||||
});
|
||||
self.pin.io().int_dormant_wake().inte(idx / 8).write_clear(|w| {
|
||||
w.set_edge_high(idx % 8, true);
|
||||
w.set_edge_low(idx % 8, true);
|
||||
w.set_level_high(idx % 8, true);
|
||||
w.set_level_low(idx % 8, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user