diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 640ec6ad..a6e80a9a 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -14,13 +14,16 @@ use embassy::io::{AsyncBufRead, AsyncWrite, Result}; use embassy::util::WakerRegistration; use embedded_hal::digital::v2::OutputPin; -use crate::fmt::{panic, todo, *}; use crate::hal::gpio::Port as GpioPort; use crate::hal::ppi::ConfigurablePpi; use crate::interrupt::{self, OwnedInterrupt}; use crate::pac; use crate::util::peripheral::{PeripheralMutex, PeripheralState}; use crate::util::ring_buffer::RingBuffer; +use crate::{ + fmt::{panic, todo, *}, + util::low_power_wait_until, +}; // Re-export SVD variants to allow user to directly set values pub use crate::hal::uarte::Pins; @@ -203,14 +206,28 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex>> { unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } } + + pub fn free(self: Pin<&mut Self>) -> (U, T, P1, P2, U::Interrupt) { + let (mut state, irq) = self.inner().free(); + state.stop(); + ( + state.uarte, + state.timer, + state.ppi_channel_1, + state.ppi_channel_2, + irq, + ) + } } impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> Drop for BufferedUarte<'a, U, T, P1, P2> { fn drop(&mut self) { - // stop DMA before dropping, because DMA is using the buffer in `self`. - todo!() + let inner = unsafe { Pin::new_unchecked(&mut self.inner) }; + if let Some((mut state, _irq)) = inner.try_free() { + state.stop(); + } } } @@ -281,6 +298,26 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi } } +impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> + State<'a, U, T, P1, P2> +{ + fn stop(&mut self) { + self.timer.tasks_stop.write(|w| unsafe { w.bits(1) }); + if let RxState::Receiving = self.rx_state { + self.uarte.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + } + if let TxState::Transmitting(_) = self.tx_state { + self.uarte.tasks_stoptx.write(|w| unsafe { w.bits(1) }); + } + if let RxState::Receiving = self.rx_state { + low_power_wait_until(|| self.uarte.events_endrx.read().bits() == 0); + } + if let TxState::Transmitting(_) = self.tx_state { + low_power_wait_until(|| self.uarte.events_endtx.read().bits() == 0); + } + } +} + impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> PeripheralState for State<'a, U, T, P1, P2> { diff --git a/embassy-nrf/src/util/peripheral.rs b/embassy-nrf/src/util/peripheral.rs index e0edbf2b..1cc04f4a 100644 --- a/embassy-nrf/src/util/peripheral.rs +++ b/embassy-nrf/src/util/peripheral.rs @@ -52,12 +52,17 @@ impl PeripheralMutex { r } - pub fn free(self: Pin<&mut Self>) -> (S, S::Interrupt) { + pub fn try_free(self: Pin<&mut Self>) -> Option<(S, S::Interrupt)> { let this = unsafe { self.get_unchecked_mut() }; - let (state, irq) = unwrap!(this.inner.take()); - irq.disable(); - irq.remove_handler(); - (state.into_inner(), irq) + this.inner.take().map(|(state, irq)| { + irq.disable(); + irq.remove_handler(); + (state.into_inner(), irq) + }) + } + + pub fn free(self: Pin<&mut Self>) -> (S, S::Interrupt) { + unwrap!(self.try_free()) } }