diff options
| -rw-r--r-- | embassy-nrf/CHANGELOG.md | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/gpiote.rs | 68 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/gpiote_channel.rs | 8 | ||||
| -rw-r--r-- | examples/nrf5340/src/bin/gpiote_channel.rs | 8 | ||||
| -rw-r--r-- | examples/nrf54l15/src/bin/gpiote_channel.rs | 8 |
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 { |
