diff options
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 122 | ||||
| -rw-r--r-- | embassy-nrf/src/util/mod.rs | 10 | ||||
| -rw-r--r-- | embassy/src/util/signal.rs | 9 |
3 files changed, 95 insertions, 46 deletions
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 8aee11c47..9daed2f4a 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -17,8 +17,8 @@ use crate::hal::gpio::Port as GpioPort; | |||
| 17 | use crate::hal::pac; | 17 | use crate::hal::pac; |
| 18 | use crate::hal::prelude::*; | 18 | use crate::hal::prelude::*; |
| 19 | use crate::hal::target_constants::EASY_DMA_SIZE; | 19 | use crate::hal::target_constants::EASY_DMA_SIZE; |
| 20 | use crate::interrupt; | ||
| 21 | use crate::interrupt::OwnedInterrupt; | 20 | use crate::interrupt::OwnedInterrupt; |
| 21 | use crate::{interrupt, util}; | ||
| 22 | 22 | ||
| 23 | pub use crate::hal::uarte::Pins; | 23 | pub use crate::hal::uarte::Pins; |
| 24 | // Re-export SVD variants to allow user to directly set values. | 24 | // Re-export SVD variants to allow user to directly set values. |
| @@ -131,6 +131,8 @@ where | |||
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | pub fn free(self) -> (T, T::Interrupt, Pins) { | 133 | pub fn free(self) -> (T, T::Interrupt, Pins) { |
| 134 | // Wait for the peripheral to be disabled from the ISR. | ||
| 135 | while self.instance.enable.read().enable().is_enabled() {} | ||
| 134 | (self.instance, self.irq, self.pins) | 136 | (self.instance, self.irq, self.pins) |
| 135 | } | 137 | } |
| 136 | 138 | ||
| @@ -156,6 +158,13 @@ where | |||
| 156 | uarte.events_endtx.reset(); | 158 | uarte.events_endtx.reset(); |
| 157 | trace!("endtx"); | 159 | trace!("endtx"); |
| 158 | compiler_fence(Ordering::SeqCst); | 160 | compiler_fence(Ordering::SeqCst); |
| 161 | |||
| 162 | if uarte.events_txstarted.read().bits() != 0 { | ||
| 163 | // The ENDTX was signal triggered because DMA has finished. | ||
| 164 | uarte.events_txstarted.reset(); | ||
| 165 | try_disable = true; | ||
| 166 | } | ||
| 167 | |||
| 159 | T::state().tx_done.signal(()); | 168 | T::state().tx_done.signal(()); |
| 160 | } | 169 | } |
| 161 | 170 | ||
| @@ -170,6 +179,13 @@ where | |||
| 170 | trace!("endrx"); | 179 | trace!("endrx"); |
| 171 | let len = uarte.rxd.amount.read().bits(); | 180 | let len = uarte.rxd.amount.read().bits(); |
| 172 | compiler_fence(Ordering::SeqCst); | 181 | compiler_fence(Ordering::SeqCst); |
| 182 | |||
| 183 | if uarte.events_rxstarted.read().bits() != 0 { | ||
| 184 | // The ENDRX was signal triggered because DMA buffer is full. | ||
| 185 | uarte.events_rxstarted.reset(); | ||
| 186 | try_disable = true; | ||
| 187 | } | ||
| 188 | |||
| 173 | T::state().rx_done.signal(len); | 189 | T::state().rx_done.signal(len); |
| 174 | } | 190 | } |
| 175 | 191 | ||
| @@ -204,7 +220,7 @@ impl<T: Instance> embassy::uart::Uart for Uarte<T> { | |||
| 204 | // `mem::forget()` on a previous future after polling it once. | 220 | // `mem::forget()` on a previous future after polling it once. |
| 205 | assert!(!self.tx_started()); | 221 | assert!(!self.tx_started()); |
| 206 | 222 | ||
| 207 | self.enable(); | 223 | T::state().tx_done.reset(); |
| 208 | 224 | ||
| 209 | SendFuture { | 225 | SendFuture { |
| 210 | uarte: self, | 226 | uarte: self, |
| @@ -227,7 +243,7 @@ impl<T: Instance> embassy::uart::Uart for Uarte<T> { | |||
| 227 | // `mem::forget()` on a previous future after polling it once. | 243 | // `mem::forget()` on a previous future after polling it once. |
| 228 | assert!(!self.rx_started()); | 244 | assert!(!self.rx_started()); |
| 229 | 245 | ||
| 230 | self.enable(); | 246 | T::state().rx_done.reset(); |
| 231 | 247 | ||
| 232 | ReceiveFuture { | 248 | ReceiveFuture { |
| 233 | uarte: self, | 249 | uarte: self, |
| @@ -241,7 +257,7 @@ pub struct SendFuture<'a, T> | |||
| 241 | where | 257 | where |
| 242 | T: Instance, | 258 | T: Instance, |
| 243 | { | 259 | { |
| 244 | uarte: &'a Uarte<T>, | 260 | uarte: &'a mut Uarte<T>, |
| 245 | buf: &'a [u8], | 261 | buf: &'a [u8], |
| 246 | } | 262 | } |
| 247 | 263 | ||
| @@ -259,7 +275,9 @@ where | |||
| 259 | .instance | 275 | .instance |
| 260 | .tasks_stoptx | 276 | .tasks_stoptx |
| 261 | .write(|w| unsafe { w.bits(1) }); | 277 | .write(|w| unsafe { w.bits(1) }); |
| 262 | T::state().tx_done.blocking_wait(); | 278 | |
| 279 | // TX is stopped almost instantly, spinning is fine. | ||
| 280 | while !T::state().tx_done.signaled() {} | ||
| 263 | } | 281 | } |
| 264 | } | 282 | } |
| 265 | } | 283 | } |
| @@ -273,28 +291,34 @@ where | |||
| 273 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | 291 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 274 | let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; | 292 | let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; |
| 275 | 293 | ||
| 276 | if !uarte.tx_started() { | 294 | if T::state().tx_done.poll_wait(cx).is_pending() { |
| 277 | let uarte = &uarte.instance; | ||
| 278 | |||
| 279 | T::state().tx_done.reset(); | ||
| 280 | |||
| 281 | let ptr = buf.as_ptr(); | 295 | let ptr = buf.as_ptr(); |
| 282 | let len = buf.len(); | 296 | let len = buf.len(); |
| 283 | assert!(len <= EASY_DMA_SIZE); | 297 | assert!(len <= EASY_DMA_SIZE); |
| 284 | // TODO: panic if buffer is not in SRAM | 298 | // TODO: panic if buffer is not in SRAM |
| 285 | 299 | ||
| 300 | uarte.enable(); | ||
| 301 | |||
| 286 | compiler_fence(Ordering::SeqCst); | 302 | compiler_fence(Ordering::SeqCst); |
| 287 | uarte.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||
| 288 | uarte | 303 | uarte |
| 304 | .instance | ||
| 305 | .txd | ||
| 306 | .ptr | ||
| 307 | .write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||
| 308 | uarte | ||
| 309 | .instance | ||
| 289 | .txd | 310 | .txd |
| 290 | .maxcnt | 311 | .maxcnt |
| 291 | .write(|w| unsafe { w.maxcnt().bits(len as _) }); | 312 | .write(|w| unsafe { w.maxcnt().bits(len as _) }); |
| 292 | 313 | ||
| 293 | trace!("starttx"); | 314 | trace!("starttx"); |
| 294 | uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 315 | uarte.instance.tasks_starttx.write(|w| unsafe { w.bits(1) }); |
| 295 | } | 316 | while !uarte.tx_started() {} // Make sure transmission has started |
| 296 | 317 | ||
| 297 | T::state().tx_done.poll_wait(cx).map(|()| Ok(())) | 318 | Poll::Pending |
| 319 | } else { | ||
| 320 | Poll::Ready(Ok(())) | ||
| 321 | } | ||
| 298 | } | 322 | } |
| 299 | } | 323 | } |
| 300 | 324 | ||
| @@ -303,7 +327,7 @@ pub struct ReceiveFuture<'a, T> | |||
| 303 | where | 327 | where |
| 304 | T: Instance, | 328 | T: Instance, |
| 305 | { | 329 | { |
| 306 | uarte: &'a Uarte<T>, | 330 | uarte: &'a mut Uarte<T>, |
| 307 | buf: &'a mut [u8], | 331 | buf: &'a mut [u8], |
| 308 | } | 332 | } |
| 309 | 333 | ||
| @@ -313,14 +337,15 @@ where | |||
| 313 | { | 337 | { |
| 314 | fn drop(self: &mut Self) { | 338 | fn drop(self: &mut Self) { |
| 315 | if self.uarte.rx_started() { | 339 | if self.uarte.rx_started() { |
| 316 | trace!("stoprx"); | 340 | trace!("stoprx (drop)"); |
| 317 | 341 | ||
| 318 | self.uarte.instance.events_rxstarted.reset(); | 342 | self.uarte.instance.events_rxstarted.reset(); |
| 319 | self.uarte | 343 | self.uarte |
| 320 | .instance | 344 | .instance |
| 321 | .tasks_stoprx | 345 | .tasks_stoprx |
| 322 | .write(|w| unsafe { w.bits(1) }); | 346 | .write(|w| unsafe { w.bits(1) }); |
| 323 | T::state().rx_done.blocking_wait(); | 347 | |
| 348 | util::low_power_wait_until(|| T::state().rx_done.signaled()) | ||
| 324 | } | 349 | } |
| 325 | } | 350 | } |
| 326 | } | 351 | } |
| @@ -334,27 +359,35 @@ where | |||
| 334 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | 359 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 335 | let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; | 360 | let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; |
| 336 | 361 | ||
| 337 | if !uarte.rx_started() { | 362 | match T::state().rx_done.poll_wait(cx) { |
| 338 | let uarte = &uarte.instance; | 363 | Poll::Pending if !uarte.rx_started() => { |
| 339 | 364 | let ptr = buf.as_ptr(); | |
| 340 | T::state().rx_done.reset(); | 365 | let len = buf.len(); |
| 341 | 366 | assert!(len <= EASY_DMA_SIZE); | |
| 342 | let ptr = buf.as_ptr(); | 367 | |
| 343 | let len = buf.len(); | 368 | uarte.enable(); |
| 344 | assert!(len <= EASY_DMA_SIZE); | 369 | |
| 345 | 370 | compiler_fence(Ordering::SeqCst); | |
| 346 | compiler_fence(Ordering::SeqCst); | 371 | uarte |
| 347 | uarte.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | 372 | .instance |
| 348 | uarte | 373 | .rxd |
| 349 | .rxd | 374 | .ptr |
| 350 | .maxcnt | 375 | .write(|w| unsafe { w.ptr().bits(ptr as u32) }); |
| 351 | .write(|w| unsafe { w.maxcnt().bits(len as _) }); | 376 | uarte |
| 352 | 377 | .instance | |
| 353 | trace!("startrx"); | 378 | .rxd |
| 354 | uarte.tasks_startrx.write(|w| unsafe { w.bits(1) }); | 379 | .maxcnt |
| 380 | .write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||
| 381 | |||
| 382 | trace!("startrx"); | ||
| 383 | uarte.instance.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 384 | while !uarte.rx_started() {} // Make sure reception has started | ||
| 385 | |||
| 386 | Poll::Pending | ||
| 387 | } | ||
| 388 | Poll::Pending => Poll::Pending, | ||
| 389 | Poll::Ready(_) => Poll::Ready(Ok(())), | ||
| 355 | } | 390 | } |
| 356 | |||
| 357 | T::state().rx_done.poll_wait(cx).map(|_| Ok(())) | ||
| 358 | } | 391 | } |
| 359 | } | 392 | } |
| 360 | 393 | ||
| @@ -365,8 +398,19 @@ where | |||
| 365 | { | 398 | { |
| 366 | /// Stops the ongoing reception and returns the number of bytes received. | 399 | /// Stops the ongoing reception and returns the number of bytes received. |
| 367 | pub async fn stop(self) -> usize { | 400 | pub async fn stop(self) -> usize { |
| 368 | drop(self); | 401 | let len = if self.uarte.rx_started() { |
| 369 | let len = T::state().rx_done.wait().await; | 402 | trace!("stoprx (stop)"); |
| 403 | |||
| 404 | self.uarte.instance.events_rxstarted.reset(); | ||
| 405 | self.uarte | ||
| 406 | .instance | ||
| 407 | .tasks_stoprx | ||
| 408 | .write(|w| unsafe { w.bits(1) }); | ||
| 409 | T::state().rx_done.wait().await | ||
| 410 | } else { | ||
| 411 | // Transfer was stopped before it even started. No bytes were sent. | ||
| 412 | 0 | ||
| 413 | }; | ||
| 370 | len as _ | 414 | len as _ |
| 371 | } | 415 | } |
| 372 | } | 416 | } |
diff --git a/embassy-nrf/src/util/mod.rs b/embassy-nrf/src/util/mod.rs index 2fd5453d3..cf3306545 100644 --- a/embassy-nrf/src/util/mod.rs +++ b/embassy-nrf/src/util/mod.rs | |||
| @@ -1,2 +1,12 @@ | |||
| 1 | pub mod peripheral; | 1 | pub mod peripheral; |
| 2 | pub mod ring_buffer; | 2 | pub mod ring_buffer; |
| 3 | |||
| 4 | /// Low power blocking wait loop using WFE/SEV. | ||
| 5 | pub fn low_power_wait_until(mut condition: impl FnMut() -> bool) { | ||
| 6 | while !condition() { | ||
| 7 | // WFE might "eat" an event that would have otherwise woken the executor. | ||
| 8 | cortex_m::asm::wfe(); | ||
| 9 | } | ||
| 10 | // Retrigger an event to be transparent to the executor. | ||
| 11 | cortex_m::asm::sev(); | ||
| 12 | } | ||
diff --git a/embassy/src/util/signal.rs b/embassy/src/util/signal.rs index cb6410611..8e778d1e3 100644 --- a/embassy/src/util/signal.rs +++ b/embassy/src/util/signal.rs | |||
| @@ -63,12 +63,7 @@ impl<T: Send> Signal<T> { | |||
| 63 | futures::future::poll_fn(move |cx| self.poll_wait(cx)) | 63 | futures::future::poll_fn(move |cx| self.poll_wait(cx)) |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | /// Blocks until the signal has been received. | 66 | pub fn signaled(&self) -> bool { |
| 67 | /// | 67 | cortex_m::interrupt::free(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) |
| 68 | /// Returns immediately when [`poll_wait()`] has not been called before. | ||
| 69 | pub fn blocking_wait(&self) { | ||
| 70 | while cortex_m::interrupt::free(|_| { | ||
| 71 | matches!(unsafe { &*self.state.get() }, State::Waiting(_)) | ||
| 72 | }) {} | ||
| 73 | } | 68 | } |
| 74 | } | 69 | } |
