diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-03-26 23:22:06 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-03-29 00:58:58 +0200 |
| commit | 7a41541ab279e200b7bda93704e8ba66df52f5b4 (patch) | |
| tree | 412154b40724427638ae2976697d5a2daed0a4b2 | |
| parent | 0e8bb5dc0b59a490f679f82c3efc6c2994c2d1d9 (diff) | |
nrf/uarte: use Peripheral, wait for stop on drop.
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 239 |
1 files changed, 101 insertions, 138 deletions
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 9a6e49907..06493da69 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -3,10 +3,11 @@ | |||
| 3 | use core::future::Future; | 3 | use core::future::Future; |
| 4 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 5 | use core::pin::Pin; | 5 | use core::pin::Pin; |
| 6 | use core::sync::atomic::{compiler_fence, Ordering}; | 6 | use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; |
| 7 | use core::task::Poll; | 7 | use core::task::Poll; |
| 8 | use embassy::traits::uart::{Error, Read, Write}; | 8 | use embassy::traits::uart::{Error, Read, Write}; |
| 9 | use embassy::util::{wake_on_interrupt, OnDrop, PeripheralBorrow}; | 9 | use embassy::util::{AtomicWaker, OnDrop, PeripheralBorrow}; |
| 10 | use embassy_extras::peripheral_shared::{Peripheral, PeripheralState}; | ||
| 10 | use embassy_extras::unborrow; | 11 | use embassy_extras::unborrow; |
| 11 | use futures::future::poll_fn; | 12 | use futures::future::poll_fn; |
| 12 | 13 | ||
| @@ -37,10 +38,18 @@ impl Default for Config { | |||
| 37 | } | 38 | } |
| 38 | } | 39 | } |
| 39 | 40 | ||
| 41 | struct State<T: Instance> { | ||
| 42 | peri: T, | ||
| 43 | did_stoprx: AtomicBool, | ||
| 44 | did_stoptx: AtomicBool, | ||
| 45 | |||
| 46 | endrx_waker: AtomicWaker, | ||
| 47 | endtx_waker: AtomicWaker, | ||
| 48 | } | ||
| 49 | |||
| 40 | /// Interface to the UARTE peripheral | 50 | /// Interface to the UARTE peripheral |
| 41 | pub struct Uarte<'d, T: Instance> { | 51 | pub struct Uarte<'d, T: Instance> { |
| 42 | peri: T, | 52 | inner: Peripheral<State<T>>, |
| 43 | irq: T::Interrupt, | ||
| 44 | phantom: PhantomData<&'d mut T>, | 53 | phantom: PhantomData<&'d mut T>, |
| 45 | } | 54 | } |
| 46 | 55 | ||
| @@ -90,23 +99,85 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 90 | r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); | 99 | r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); |
| 91 | r.config.write(|w| w.parity().variant(config.parity)); | 100 | r.config.write(|w| w.parity().variant(config.parity)); |
| 92 | 101 | ||
| 102 | // Disable all interrupts | ||
| 103 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||
| 104 | |||
| 93 | // Enable | 105 | // Enable |
| 94 | r.enable.write(|w| w.enable().enabled()); | 106 | r.enable.write(|w| w.enable().enabled()); |
| 95 | 107 | ||
| 96 | Self { | 108 | Self { |
| 97 | peri: uarte, | 109 | inner: Peripheral::new( |
| 98 | irq, | 110 | irq, |
| 111 | State { | ||
| 112 | did_stoprx: AtomicBool::new(false), | ||
| 113 | did_stoptx: AtomicBool::new(false), | ||
| 114 | peri: uarte, | ||
| 115 | endrx_waker: AtomicWaker::new(), | ||
| 116 | endtx_waker: AtomicWaker::new(), | ||
| 117 | }, | ||
| 118 | ), | ||
| 99 | phantom: PhantomData, | 119 | phantom: PhantomData, |
| 100 | } | 120 | } |
| 101 | } | 121 | } |
| 122 | |||
| 123 | fn inner(self: Pin<&mut Self>) -> Pin<&mut Peripheral<State<T>>> { | ||
| 124 | unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } | ||
| 125 | } | ||
| 102 | } | 126 | } |
| 103 | 127 | ||
| 104 | impl<'d, T: Instance> Drop for Uarte<'d, T> { | 128 | impl<T: Instance> PeripheralState for State<T> { |
| 105 | fn drop(&mut self) { | 129 | type Interrupt = T::Interrupt; |
| 130 | |||
| 131 | fn on_interrupt(&self) { | ||
| 132 | info!("irq"); | ||
| 133 | |||
| 106 | let r = self.peri.regs(); | 134 | let r = self.peri.regs(); |
| 135 | if r.events_endrx.read().bits() != 0 { | ||
| 136 | self.endrx_waker.wake(); | ||
| 137 | r.intenclr.write(|w| w.endrx().clear()); | ||
| 138 | } | ||
| 139 | if r.events_endtx.read().bits() != 0 { | ||
| 140 | self.endtx_waker.wake(); | ||
| 141 | r.intenclr.write(|w| w.endtx().clear()); | ||
| 142 | } | ||
| 143 | |||
| 144 | if r.events_rxto.read().bits() != 0 { | ||
| 145 | r.intenclr.write(|w| w.rxto().clear()); | ||
| 146 | } | ||
| 147 | if r.events_txstopped.read().bits() != 0 { | ||
| 148 | r.intenclr.write(|w| w.txstopped().clear()); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | impl<'a, T: Instance> Drop for Uarte<'a, T> { | ||
| 154 | fn drop(&mut self) { | ||
| 155 | info!("uarte drop"); | ||
| 156 | |||
| 157 | let s = unsafe { Pin::new_unchecked(&mut self.inner) }.state(); | ||
| 158 | let r = s.peri.regs(); | ||
| 159 | |||
| 160 | let did_stoprx = s.did_stoprx.load(Ordering::Relaxed); | ||
| 161 | let did_stoptx = s.did_stoptx.load(Ordering::Relaxed); | ||
| 162 | info!("did_stoprx {} did_stoptx {}", did_stoprx, did_stoptx); | ||
| 163 | |||
| 164 | // Wait for rxto or txstopped, if needed. | ||
| 165 | r.intenset.write(|w| w.rxto().set().txstopped().set()); | ||
| 166 | while (did_stoprx && r.events_rxto.read().bits() == 0) | ||
| 167 | || (did_stoptx && r.events_txstopped.read().bits() == 0) | ||
| 168 | { | ||
| 169 | info!("uarte drop: wfe"); | ||
| 170 | cortex_m::asm::wfe(); | ||
| 171 | } | ||
| 172 | |||
| 173 | cortex_m::asm::sev(); | ||
| 174 | |||
| 175 | // Finally we can disable! | ||
| 107 | r.enable.write(|w| w.enable().disabled()); | 176 | r.enable.write(|w| w.enable().disabled()); |
| 108 | 177 | ||
| 109 | // todo disable pins | 178 | info!("uarte drop: done"); |
| 179 | |||
| 180 | // TODO: disable pins | ||
| 110 | } | 181 | } |
| 111 | } | 182 | } |
| 112 | 183 | ||
| @@ -114,25 +185,29 @@ impl<'d, T: Instance> Read for Uarte<'d, T> { | |||
| 114 | #[rustfmt::skip] | 185 | #[rustfmt::skip] |
| 115 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a; | 186 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a; |
| 116 | 187 | ||
| 117 | fn read<'a>(self: Pin<&'a mut Self>, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | 188 | fn read<'a>(mut self: Pin<&'a mut Self>, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { |
| 118 | async move { | 189 | self.as_mut().inner().register_interrupt(); |
| 119 | let this = unsafe { self.get_unchecked_mut() }; | ||
| 120 | 190 | ||
| 191 | async move { | ||
| 121 | let ptr = rx_buffer.as_ptr(); | 192 | let ptr = rx_buffer.as_ptr(); |
| 122 | let len = rx_buffer.len(); | 193 | let len = rx_buffer.len(); |
| 123 | assert!(len <= EASY_DMA_SIZE); | 194 | assert!(len <= EASY_DMA_SIZE); |
| 124 | 195 | ||
| 125 | let r = this.peri.regs(); | 196 | let s = self.inner().state(); |
| 197 | let r = s.peri.regs(); | ||
| 126 | 198 | ||
| 199 | let did_stoprx = &s.did_stoprx; | ||
| 127 | let drop = OnDrop::new(move || { | 200 | let drop = OnDrop::new(move || { |
| 128 | info!("read drop: stopping"); | 201 | info!("read drop: stopping"); |
| 129 | 202 | ||
| 130 | r.intenclr.write(|w| w.endrx().clear()); | 203 | r.intenclr.write(|w| w.endrx().clear()); |
| 204 | r.events_rxto.reset(); | ||
| 131 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | 205 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); |
| 132 | 206 | ||
| 133 | // TX is stopped almost instantly, spinning is fine. | ||
| 134 | while r.events_endrx.read().bits() == 0 {} | 207 | while r.events_endrx.read().bits() == 0 {} |
| 208 | |||
| 135 | info!("read drop: stopped"); | 209 | info!("read drop: stopped"); |
| 210 | did_stoprx.store(true, Ordering::Relaxed); | ||
| 136 | }); | 211 | }); |
| 137 | 212 | ||
| 138 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | 213 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); |
| @@ -146,21 +221,17 @@ impl<'d, T: Instance> Read for Uarte<'d, T> { | |||
| 146 | trace!("startrx"); | 221 | trace!("startrx"); |
| 147 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | 222 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); |
| 148 | 223 | ||
| 149 | let irq = &mut this.irq; | ||
| 150 | poll_fn(|cx| { | 224 | poll_fn(|cx| { |
| 225 | s.endrx_waker.register(cx.waker()); | ||
| 151 | if r.events_endrx.read().bits() != 0 { | 226 | if r.events_endrx.read().bits() != 0 { |
| 152 | r.events_endrx.reset(); | ||
| 153 | return Poll::Ready(()); | 227 | return Poll::Ready(()); |
| 154 | } | 228 | } |
| 155 | |||
| 156 | wake_on_interrupt(irq, cx.waker()); | ||
| 157 | |||
| 158 | Poll::Pending | 229 | Poll::Pending |
| 159 | }) | 230 | }) |
| 160 | .await; | 231 | .await; |
| 161 | 232 | ||
| 162 | compiler_fence(Ordering::SeqCst); | 233 | compiler_fence(Ordering::SeqCst); |
| 163 | r.intenclr.write(|w| w.endrx().clear()); | 234 | s.did_stoprx.store(false, Ordering::Relaxed); |
| 164 | drop.defuse(); | 235 | drop.defuse(); |
| 165 | 236 | ||
| 166 | Ok(()) | 237 | Ok(()) |
| @@ -172,26 +243,30 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { | |||
| 172 | #[rustfmt::skip] | 243 | #[rustfmt::skip] |
| 173 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a; | 244 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a; |
| 174 | 245 | ||
| 175 | fn write<'a>(self: Pin<&'a mut Self>, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { | 246 | fn write<'a>(mut self: Pin<&'a mut Self>, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { |
| 176 | async move { | 247 | self.as_mut().inner().register_interrupt(); |
| 177 | let this = unsafe { self.get_unchecked_mut() }; | ||
| 178 | 248 | ||
| 249 | async move { | ||
| 179 | let ptr = tx_buffer.as_ptr(); | 250 | let ptr = tx_buffer.as_ptr(); |
| 180 | let len = tx_buffer.len(); | 251 | let len = tx_buffer.len(); |
| 181 | assert!(len <= EASY_DMA_SIZE); | 252 | assert!(len <= EASY_DMA_SIZE); |
| 182 | // TODO: panic if buffer is not in SRAM | 253 | // TODO: panic if buffer is not in SRAM |
| 183 | 254 | ||
| 184 | let r = this.peri.regs(); | 255 | let s = self.inner().state(); |
| 256 | let r = s.peri.regs(); | ||
| 185 | 257 | ||
| 258 | let did_stoptx = &s.did_stoptx; | ||
| 186 | let drop = OnDrop::new(move || { | 259 | let drop = OnDrop::new(move || { |
| 187 | info!("write drop: stopping"); | 260 | info!("write drop: stopping"); |
| 188 | 261 | ||
| 189 | r.intenclr.write(|w| w.endtx().clear()); | 262 | r.intenclr.write(|w| w.endtx().clear()); |
| 263 | r.events_txstopped.reset(); | ||
| 190 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | 264 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); |
| 191 | 265 | ||
| 192 | // TX is stopped almost instantly, spinning is fine. | 266 | // TX is stopped almost instantly, spinning is fine. |
| 193 | while r.events_endtx.read().bits() == 0 {} | 267 | while r.events_endtx.read().bits() == 0 {} |
| 194 | info!("write drop: stopped"); | 268 | info!("write drop: stopped"); |
| 269 | did_stoptx.store(true, Ordering::Relaxed); | ||
| 195 | }); | 270 | }); |
| 196 | 271 | ||
| 197 | r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | 272 | r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); |
| @@ -205,21 +280,17 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { | |||
| 205 | trace!("starttx"); | 280 | trace!("starttx"); |
| 206 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 281 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); |
| 207 | 282 | ||
| 208 | let irq = &mut this.irq; | ||
| 209 | poll_fn(|cx| { | 283 | poll_fn(|cx| { |
| 284 | s.endtx_waker.register(cx.waker()); | ||
| 210 | if r.events_endtx.read().bits() != 0 { | 285 | if r.events_endtx.read().bits() != 0 { |
| 211 | r.events_endtx.reset(); | ||
| 212 | return Poll::Ready(()); | 286 | return Poll::Ready(()); |
| 213 | } | 287 | } |
| 214 | |||
| 215 | wake_on_interrupt(irq, cx.waker()); | ||
| 216 | |||
| 217 | Poll::Pending | 288 | Poll::Pending |
| 218 | }) | 289 | }) |
| 219 | .await; | 290 | .await; |
| 220 | 291 | ||
| 221 | compiler_fence(Ordering::SeqCst); | 292 | compiler_fence(Ordering::SeqCst); |
| 222 | r.intenclr.write(|w| w.endtx().clear()); | 293 | s.did_stoptx.store(false, Ordering::Relaxed); |
| 223 | drop.defuse(); | 294 | drop.defuse(); |
| 224 | 295 | ||
| 225 | Ok(()) | 296 | Ok(()) |
| @@ -227,114 +298,6 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { | |||
| 227 | } | 298 | } |
| 228 | } | 299 | } |
| 229 | 300 | ||
| 230 | /* | ||
| 231 | /// Future for the [`Uarte::send()`] method. | ||
| 232 | pub struct SendFuture<'a, T> | ||
| 233 | where | ||
| 234 | T: Instance, | ||
| 235 | { | ||
| 236 | uarte: &'a mut Uarte<T>, | ||
| 237 | buf: &'a [u8], | ||
| 238 | } | ||
| 239 | |||
| 240 | impl<'a, T> Drop for SendFuture<'a, T> | ||
| 241 | where | ||
| 242 | T: Instance, | ||
| 243 | { | ||
| 244 | fn drop(self: &mut Self) { | ||
| 245 | if self.uarte.tx_started() { | ||
| 246 | trace!("stoptx"); | ||
| 247 | |||
| 248 | // Stop the transmitter to minimize the current consumption. | ||
| 249 | self.uarte.peri.events_txstarted.reset(); | ||
| 250 | self.uarte.peri.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||
| 251 | |||
| 252 | // TX is stopped almost instantly, spinning is fine. | ||
| 253 | while !T::state().tx_done.signaled() {} | ||
| 254 | } | ||
| 255 | } | ||
| 256 | } | ||
| 257 | |||
| 258 | /// Future for the [`Uarte::receive()`] method. | ||
| 259 | pub struct ReceiveFuture<'a, T> | ||
| 260 | where | ||
| 261 | T: Instance, | ||
| 262 | { | ||
| 263 | uarte: &'a mut Uarte<T>, | ||
| 264 | buf: &'a mut [u8], | ||
| 265 | } | ||
| 266 | |||
| 267 | impl<'a, T> Drop for ReceiveFuture<'a, T> | ||
| 268 | where | ||
| 269 | T: Instance, | ||
| 270 | { | ||
| 271 | fn drop(self: &mut Self) { | ||
| 272 | if self.uarte.rx_started() { | ||
| 273 | trace!("stoprx (drop)"); | ||
| 274 | |||
| 275 | self.uarte.peri.events_rxstarted.reset(); | ||
| 276 | self.uarte.peri.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 277 | |||
| 278 | embassy_extras::low_power_wait_until(|| T::state().rx_done.signaled()) | ||
| 279 | } | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | impl<'a, T> Future for ReceiveFuture<'a, T> | ||
| 284 | where | ||
| 285 | T: Instance, | ||
| 286 | { | ||
| 287 | type Output = Result<(), embassy::traits::uart::Error>; | ||
| 288 | |||
| 289 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 290 | let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; | ||
| 291 | |||
| 292 | match T::state().rx_done.poll_wait(cx) { | ||
| 293 | Poll::Pending if !uarte.rx_started() => { | ||
| 294 | let ptr = buf.as_ptr(); | ||
| 295 | let len = buf.len(); | ||
| 296 | assert!(len <= EASY_DMA_SIZE); | ||
| 297 | |||
| 298 | uarte.enable(); | ||
| 299 | |||
| 300 | compiler_fence(Ordering::SeqCst); | ||
| 301 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||
| 302 | r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||
| 303 | |||
| 304 | trace!("startrx"); | ||
| 305 | uarte.peri.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 306 | while !uarte.rx_started() {} // Make sure reception has started | ||
| 307 | |||
| 308 | Poll::Pending | ||
| 309 | } | ||
| 310 | Poll::Pending => Poll::Pending, | ||
| 311 | Poll::Ready(_) => Poll::Ready(Ok(())), | ||
| 312 | } | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | /// Future for the [`receive()`] method. | ||
| 317 | impl<'a, T> ReceiveFuture<'a, T> | ||
| 318 | where | ||
| 319 | T: Instance, | ||
| 320 | { | ||
| 321 | /// Stops the ongoing reception and returns the number of bytes received. | ||
| 322 | pub async fn stop(self) -> usize { | ||
| 323 | let len = if self.uarte.rx_started() { | ||
| 324 | trace!("stoprx (stop)"); | ||
| 325 | |||
| 326 | self.uarte.peri.events_rxstarted.reset(); | ||
| 327 | self.uarte.peri.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 328 | T::state().rx_done.wait().await | ||
| 329 | } else { | ||
| 330 | // Transfer was stopped before it even started. No bytes were sent. | ||
| 331 | 0 | ||
| 332 | }; | ||
| 333 | len as _ | ||
| 334 | } | ||
| 335 | } | ||
| 336 | */ | ||
| 337 | |||
| 338 | mod sealed { | 301 | mod sealed { |
| 339 | use super::*; | 302 | use super::*; |
| 340 | 303 | ||
