aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaarten de Vries <[email protected]>2025-10-30 11:52:53 +0100
committerMaarten de Vries <[email protected]>2025-10-30 14:55:30 +0100
commit3949a8601f293856df326ccc21252cb5f1518c5c (patch)
tree2a320fe5f351a6b3d02717f764913cef29386652
parenteb096476cc34ff9775801b9b4d2d6f3b1861583e (diff)
embassy-nrf: add gpiote::InputChannel::wait_for_high/low()
Also catch GPIOTE events directly when wait() is called, even before polling the future.
-rw-r--r--embassy-nrf/CHANGELOG.md3
-rw-r--r--embassy-nrf/src/gpiote.rs68
-rw-r--r--examples/nrf52840/src/bin/gpiote_channel.rs8
-rw-r--r--examples/nrf5340/src/bin/gpiote_channel.rs8
-rw-r--r--examples/nrf54l15/src/bin/gpiote_channel.rs8
5 files changed, 77 insertions, 18 deletions
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md
index a0668c495..98f40f9a9 100644
--- a/embassy-nrf/CHANGELOG.md
+++ b/embassy-nrf/CHANGELOG.md
@@ -22,6 +22,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
22- bugfix: Do not write to UICR from non-secure code on nrf53 22- bugfix: Do not write to UICR from non-secure code on nrf53
23- bugfix: Add delay to uart init anomaly fix 23- bugfix: Add delay to uart init anomaly fix
24- changed: `BufferedUarte::read_ready` now uses the same definition for 'empty' so following read calls will not block when true is returned 24- 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
25 28
26## 0.8.0 - 2025-09-30 29## 0.8.0 - 2025-09-30
27 30
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 91944d8cd..d4f6668f3 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -349,16 +349,73 @@ impl<'d> InputChannel<'d> {
349 } 349 }
350 350
351 /// Asynchronously wait for an event in this channel. 351 /// Asynchronously wait for an event in this channel.
352 pub async fn wait(&self) { 352 ///
353 let g = self.ch.regs(); 353 /// It is possible to call this function and await the returned future later.
354 let num = self.ch.number(); 354 /// If an even occurs in the mean time, the future will immediately report ready.
355 let waker = self.ch.waker(); 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();
356 413
357 // Enable interrupt 414 // Enable interrupt
358 g.events_in(num).write_value(0); 415 g.events_in(num).write_value(0);
359 g.intenset(INTNUM).write(|w| w.0 = 1 << num); 416 g.intenset(INTNUM).write(|w| w.0 = 1 << num);
360 417
361 poll_fn(|cx| { 418 poll_fn(move |cx| {
362 CHANNEL_WAKERS[waker].register(cx.waker()); 419 CHANNEL_WAKERS[waker].register(cx.waker());
363 420
364 if g.events_in(num).read() != 0 { 421 if g.events_in(num).read() != 0 {
@@ -367,7 +424,6 @@ impl<'d> InputChannel<'d> {
367 Poll::Pending 424 Poll::Pending
368 } 425 }
369 }) 426 })
370 .await;
371 } 427 }
372 428
373 /// Get the associated input pin. 429 /// Get the associated input pin.
diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs
index c7ddc1d8d..e358779b2 100644
--- a/examples/nrf52840/src/bin/gpiote_channel.rs
+++ b/examples/nrf52840/src/bin/gpiote_channel.rs
@@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default()); 12 let p = embassy_nrf::init(Default::default());
13 info!("Starting!"); 13 info!("Starting!");
14 14
15 let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo); 15 let mut 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); 16 let mut 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); 17 let mut 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); 18 let mut ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::Toggle);
19 19
20 let button1 = async { 20 let button1 = async {
21 loop { 21 loop {
diff --git a/examples/nrf5340/src/bin/gpiote_channel.rs b/examples/nrf5340/src/bin/gpiote_channel.rs
index a085310ce..41ee732c3 100644
--- a/examples/nrf5340/src/bin/gpiote_channel.rs
+++ b/examples/nrf5340/src/bin/gpiote_channel.rs
@@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default()); 12 let p = embassy_nrf::init(Default::default());
13 info!("Starting!"); 13 info!("Starting!");
14 14
15 let ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_23, Pull::Up, InputChannelPolarity::HiToLo); 15 let mut 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); 16 let mut 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); 17 let mut 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); 18 let mut ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_09, Pull::Up, InputChannelPolarity::Toggle);
19 19
20 let button1 = async { 20 let button1 = async {
21 loop { 21 loop {
diff --git a/examples/nrf54l15/src/bin/gpiote_channel.rs b/examples/nrf54l15/src/bin/gpiote_channel.rs
index 6333250ba..cac8823f8 100644
--- a/examples/nrf54l15/src/bin/gpiote_channel.rs
+++ b/examples/nrf54l15/src/bin/gpiote_channel.rs
@@ -12,10 +12,10 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default()); 12 let p = embassy_nrf::init(Default::default());
13 info!("Starting!"); 13 info!("Starting!");
14 14
15 let ch1 = InputChannel::new(p.GPIOTE20_CH0, p.P1_13, Pull::Up, InputChannelPolarity::HiToLo); 15 let mut 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); 16 let mut 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); 17 let mut 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); 18 let mut ch4 = InputChannel::new(p.GPIOTE30_CH0, p.P0_04, Pull::Up, InputChannelPolarity::Toggle);
19 19
20 let button1 = async { 20 let button1 = async {
21 loop { 21 loop {