diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index dc2093c3..bfebf5ca 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -17,8 +17,8 @@ use crate::hal::gpio::Port as GpioPort; use crate::hal::pac; use crate::hal::prelude::*; use crate::hal::target_constants::EASY_DMA_SIZE; -use crate::interrupt; use crate::interrupt::OwnedInterrupt; +use crate::{interrupt, util}; pub use crate::hal::uarte::Pins; // Re-export SVD variants to allow user to directly set values. @@ -275,7 +275,9 @@ where .instance .tasks_stoptx .write(|w| unsafe { w.bits(1) }); - T::state().tx_done.blocking_wait(); + + // TX is stopped almost instantly, spinning is fine. + while !T::state().tx_done.signaled() {} } } } @@ -342,7 +344,8 @@ where .instance .tasks_stoprx .write(|w| unsafe { w.bits(1) }); - T::state().rx_done.blocking_wait(); + + util::low_power_wait_until(|| T::state().rx_done.signaled()) } } } @@ -361,7 +364,7 @@ where let ptr = buf.as_ptr(); let len = buf.len(); assert!(len <= EASY_DMA_SIZE); - + uarte.enable(); compiler_fence(Ordering::SeqCst); @@ -394,7 +397,7 @@ where T: Instance, { /// Stops the ongoing reception and returns the number of bytes received. - pub async fn stop(mut self) -> usize { + pub async fn stop(self) -> usize { let len = if self.uarte.rx_started() { trace!("stoprx (stop)"); diff --git a/embassy-nrf/src/util/mod.rs b/embassy-nrf/src/util/mod.rs index 2fd5453d..cf330654 100644 --- a/embassy-nrf/src/util/mod.rs +++ b/embassy-nrf/src/util/mod.rs @@ -1,2 +1,12 @@ pub mod peripheral; pub mod ring_buffer; + +/// Low power blocking wait loop using WFE/SEV. +pub fn low_power_wait_until(mut condition: impl FnMut() -> bool) { + while !condition() { + // WFE might "eat" an event that would have otherwise woken the executor. + cortex_m::asm::wfe(); + } + // Retrigger an event to be transparent to the executor. + cortex_m::asm::sev(); +} diff --git a/embassy/src/util/signal.rs b/embassy/src/util/signal.rs index cb641061..8e778d1e 100644 --- a/embassy/src/util/signal.rs +++ b/embassy/src/util/signal.rs @@ -63,12 +63,7 @@ impl Signal { futures::future::poll_fn(move |cx| self.poll_wait(cx)) } - /// Blocks until the signal has been received. - /// - /// Returns immediately when [`poll_wait()`] has not been called before. - pub fn blocking_wait(&self) { - while cortex_m::interrupt::free(|_| { - matches!(unsafe { &*self.state.get() }, State::Waiting(_)) - }) {} + pub fn signaled(&self) -> bool { + cortex_m::interrupt::free(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) } }