Skip to content

Commit 3949a86

Browse files
committed
embassy-nrf: add gpiote::InputChannel::wait_for_high/low()
Also catch GPIOTE events directly when wait() is called, even before polling the future.
1 parent eb09647 commit 3949a86

File tree

5 files changed

+77
-18
lines changed

5 files changed

+77
-18
lines changed

embassy-nrf/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222
- bugfix: Do not write to UICR from non-secure code on nrf53
2323
- bugfix: Add delay to uart init anomaly fix
2424
- changed: `BufferedUarte::read_ready` now uses the same definition for 'empty' so following read calls will not block when true is returned
25+
- added: add `gpiote::InputChannel::wait_for_high()` and `wait_for_low()` to wait for specific signal level
26+
- changed: `gpiote::InputChannel::wait()` now takes a mutable reference to `self` to avoid interference from concurrent calls
27+
- changed: `gpiote::InputChannel::wait()` now ensures events are seen as soon as the function is called, even if the future is not polled
2528

2629
## 0.8.0 - 2025-09-30
2730

embassy-nrf/src/gpiote.rs

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -349,16 +349,73 @@ impl<'d> InputChannel<'d> {
349349
}
350350

351351
/// Asynchronously wait for an event in this channel.
352-
pub async fn wait(&self) {
353-
let g = self.ch.regs();
354-
let num = self.ch.number();
355-
let waker = self.ch.waker();
352+
///
353+
/// It is possible to call this function and await the returned future later.
354+
/// If an even occurs in the mean time, the future will immediately report ready.
355+
pub fn wait(&mut self) -> impl Future<Output = ()> {
356+
// NOTE: This is `-> impl Future` and not an `async fn` on purpose.
357+
// Otherwise, events will only be detected starting at the first poll of the returned future.
358+
Self::wait_internal(&mut self.ch)
359+
}
360+
361+
/// Asynchronously wait for the pin to become high.
362+
///
363+
/// The channel must be configured with [`InputChannelPolarity::LoToHi`] or [`InputChannelPolarity::Toggle`].
364+
/// If the channel is not configured to detect rising edges, it is unspecified when the returned future completes.
365+
///
366+
/// It is possible to call this function and await the returned future later.
367+
/// If an even occurs in the mean time, the future will immediately report ready.
368+
pub fn wait_for_high(&mut self) -> impl Future<Output = ()> {
369+
// NOTE: This is `-> impl Future` and not an `async fn` on purpose.
370+
// Otherwise, events will only be detected starting at the first poll of the returned future.
371+
372+
// Subscribe to the event before checking the pin level.
373+
let wait = Self::wait_internal(&mut self.ch);
374+
let pin = &self.pin;
375+
async move {
376+
if pin.is_high() {
377+
return;
378+
}
379+
wait.await;
380+
}
381+
}
382+
383+
/// Asynchronously wait for the pin to become low.
384+
///
385+
/// The channel must be configured with [`InputChannelPolarity::HiToLo`] or [`InputChannelPolarity::Toggle`].
386+
/// If the channel is not configured to detect falling edges, it is unspecified when the returned future completes.
387+
///
388+
/// It is possible to call this function and await the returned future later.
389+
/// If an even occurs in the mean time, the future will immediately report ready.
390+
pub fn wait_for_low(&mut self) -> impl Future<Output = ()> {
391+
// NOTE: This is `-> impl Future` and not an `async fn` on purpose.
392+
// Otherwise, events will only be detected starting at the first poll of the returned future.
393+
394+
// Subscribe to the event before checking the pin level.
395+
let wait = Self::wait_internal(&mut self.ch);
396+
let pin = &self.pin;
397+
async move {
398+
if pin.is_low() {
399+
return;
400+
}
401+
wait.await;
402+
}
403+
}
404+
405+
/// Internal implementation for `wait()` and friends.
406+
fn wait_internal(channel: &mut Peri<'_, AnyChannel>) -> impl Future<Output = ()> {
407+
// NOTE: This is `-> impl Future` and not an `async fn` on purpose.
408+
// Otherwise, events will only be detected starting at the first poll of the returned future.
409+
410+
let g = channel.regs();
411+
let num = channel.number();
412+
let waker = channel.waker();
356413

357414
// Enable interrupt
358415
g.events_in(num).write_value(0);
359416
g.intenset(INTNUM).write(|w| w.0 = 1 << num);
360417

361-
poll_fn(|cx| {
418+
poll_fn(move |cx| {
362419
CHANNEL_WAKERS[waker].register(cx.waker());
363420

364421
if g.events_in(num).read() != 0 {
@@ -367,7 +424,6 @@ impl<'d> InputChannel<'d> {
367424
Poll::Pending
368425
}
369426
})
370-
.await;
371427
}
372428

373429
/// Get the associated input pin.

examples/nrf52840/src/bin/gpiote_channel.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) {
1212
let p = embassy_nrf::init(Default::default());
1313
info!("Starting!");
1414

15-
let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo);
16-
let ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::LoToHi);
17-
let ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_24, Pull::Up, InputChannelPolarity::Toggle);
18-
let ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::Toggle);
15+
let mut ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo);
16+
let mut ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::LoToHi);
17+
let mut ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_24, Pull::Up, InputChannelPolarity::Toggle);
18+
let mut ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::Toggle);
1919

2020
let button1 = async {
2121
loop {

examples/nrf5340/src/bin/gpiote_channel.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) {
1212
let p = embassy_nrf::init(Default::default());
1313
info!("Starting!");
1414

15-
let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_23, Pull::Up, InputChannelPolarity::HiToLo);
16-
let ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_24, Pull::Up, InputChannelPolarity::LoToHi);
17-
let ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_08, Pull::Up, InputChannelPolarity::Toggle);
18-
let ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_09, Pull::Up, InputChannelPolarity::Toggle);
15+
let mut ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_23, Pull::Up, InputChannelPolarity::HiToLo);
16+
let mut ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_24, Pull::Up, InputChannelPolarity::LoToHi);
17+
let mut ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_08, Pull::Up, InputChannelPolarity::Toggle);
18+
let mut ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_09, Pull::Up, InputChannelPolarity::Toggle);
1919

2020
let button1 = async {
2121
loop {

examples/nrf54l15/src/bin/gpiote_channel.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) {
1212
let p = embassy_nrf::init(Default::default());
1313
info!("Starting!");
1414

15-
let ch1 = InputChannel::new(p.GPIOTE20_CH0, p.P1_13, Pull::Up, InputChannelPolarity::HiToLo);
16-
let ch2 = InputChannel::new(p.GPIOTE20_CH1, p.P1_09, Pull::Up, InputChannelPolarity::LoToHi);
17-
let ch3 = InputChannel::new(p.GPIOTE20_CH2, p.P1_08, Pull::Up, InputChannelPolarity::Toggle);
18-
let ch4 = InputChannel::new(p.GPIOTE30_CH0, p.P0_04, Pull::Up, InputChannelPolarity::Toggle);
15+
let mut ch1 = InputChannel::new(p.GPIOTE20_CH0, p.P1_13, Pull::Up, InputChannelPolarity::HiToLo);
16+
let mut ch2 = InputChannel::new(p.GPIOTE20_CH1, p.P1_09, Pull::Up, InputChannelPolarity::LoToHi);
17+
let mut ch3 = InputChannel::new(p.GPIOTE20_CH2, p.P1_08, Pull::Up, InputChannelPolarity::Toggle);
18+
let mut ch4 = InputChannel::new(p.GPIOTE30_CH0, p.P0_04, Pull::Up, InputChannelPolarity::Toggle);
1919

2020
let button1 = async {
2121
loop {

0 commit comments

Comments
 (0)