aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNils Fitinghoff <[email protected]>2023-09-22 16:12:57 +0300
committerNils Fitinghoff <[email protected]>2023-09-22 17:02:21 +0200
commit2b7b7a917d0fc5917cb968c52bd19d710675f540 (patch)
tree999bab6f3f7f82aa55966f52ebdab2cd27db3048
parentf1488864ebee3daebdc2cc6ed3ccdf7014fa67b2 (diff)
spim: Fix SPIM with polling executors
Co-authored-by: Priit Laes <[email protected]>
-rw-r--r--embassy-nrf/src/spim.rs67
1 files changed, 45 insertions, 22 deletions
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 99a195a6e..a0d2c8eb1 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -69,29 +69,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
69 let s = T::state(); 69 let s = T::state();
70 70
71 #[cfg(feature = "nrf52832")] 71 #[cfg(feature = "nrf52832")]
72 // NRF32 Anomaly 109 workaround... NRF52832 72 if r.events_started.read().bits() != 0 {
73 if r.intenset.read().started().is_enabled() && r.events_started.read().bits() != 0 { 73 s.waker.wake();
74 // Handle the first "fake" transmission
75 r.events_started.reset();
76 r.events_end.reset();
77
78 // Update DMA registers with correct rx/tx buffer sizes
79 r.rxd
80 .maxcnt
81 .write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) });
82 r.txd
83 .maxcnt
84 .write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) });
85
86 // Disable interrupt for STARTED event...
87 r.intenclr.write(|w| w.started().clear()); 74 r.intenclr.write(|w| w.started().clear());
88 // ... and start actual, hopefully glitch-free transmission
89 r.tasks_start.write(|w| unsafe { w.bits(1) });
90 return;
91 } 75 }
92 76
93 if r.events_end.read().bits() != 0 { 77 if r.events_end.read().bits() != 0 {
94 s.end_waker.wake(); 78 s.waker.wake();
95 r.intenclr.write(|w| w.end().clear()); 79 r.intenclr.write(|w| w.end().clear());
96 } 80 }
97 } 81 }
@@ -254,6 +238,9 @@ impl<'d, T: Instance> Spim<'d, T> {
254 fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 238 fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
255 self.prepare(rx, tx)?; 239 self.prepare(rx, tx)?;
256 240
241 #[cfg(feature = "nrf52832")]
242 while let Poll::Pending = self.nrf52832_dma_workaround_status() {}
243
257 // Wait for 'end' event. 244 // Wait for 'end' event.
258 while T::regs().events_end.read().bits() == 0 {} 245 while T::regs().events_end.read().bits() == 0 {}
259 246
@@ -278,9 +265,19 @@ impl<'d, T: Instance> Spim<'d, T> {
278 async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 265 async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
279 self.prepare(rx, tx)?; 266 self.prepare(rx, tx)?;
280 267
268 #[cfg(feature = "nrf52832")]
269 poll_fn(|cx| {
270 let s = T::state();
271
272 s.waker.register(cx.waker());
273
274 self.nrf52832_dma_workaround_status()
275 })
276 .await;
277
281 // Wait for 'end' event. 278 // Wait for 'end' event.
282 poll_fn(|cx| { 279 poll_fn(|cx| {
283 T::state().end_waker.register(cx.waker()); 280 T::state().waker.register(cx.waker());
284 if T::regs().events_end.read().bits() != 0 { 281 if T::regs().events_end.read().bits() != 0 {
285 return Poll::Ready(()); 282 return Poll::Ready(());
286 } 283 }
@@ -371,6 +368,32 @@ impl<'d, T: Instance> Spim<'d, T> {
371 pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> { 368 pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> {
372 self.async_inner_from_ram(&mut [], data).await 369 self.async_inner_from_ram(&mut [], data).await
373 } 370 }
371
372 #[cfg(feature = "nrf52832")]
373 fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> {
374 let r = T::regs();
375 if r.events_started.read().bits() != 0 {
376 let s = T::state();
377
378 // Handle the first "fake" transmission
379 r.events_started.reset();
380 r.events_end.reset();
381
382 // Update DMA registers with correct rx/tx buffer sizes
383 r.rxd
384 .maxcnt
385 .write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) });
386 r.txd
387 .maxcnt
388 .write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) });
389
390 r.intenset.write(|w| w.end().set());
391 // ... and start actual, hopefully glitch-free transmission
392 r.tasks_start.write(|w| unsafe { w.bits(1) });
393 return Poll::Ready(());
394 }
395 Poll::Pending
396 }
374} 397}
375 398
376impl<'d, T: Instance> Drop for Spim<'d, T> { 399impl<'d, T: Instance> Drop for Spim<'d, T> {
@@ -403,7 +426,7 @@ pub(crate) mod sealed {
403 use super::*; 426 use super::*;
404 427
405 pub struct State { 428 pub struct State {
406 pub end_waker: AtomicWaker, 429 pub waker: AtomicWaker,
407 #[cfg(feature = "nrf52832")] 430 #[cfg(feature = "nrf52832")]
408 pub rx: AtomicU8, 431 pub rx: AtomicU8,
409 #[cfg(feature = "nrf52832")] 432 #[cfg(feature = "nrf52832")]
@@ -413,7 +436,7 @@ pub(crate) mod sealed {
413 impl State { 436 impl State {
414 pub const fn new() -> Self { 437 pub const fn new() -> Self {
415 Self { 438 Self {
416 end_waker: AtomicWaker::new(), 439 waker: AtomicWaker::new(),
417 #[cfg(feature = "nrf52832")] 440 #[cfg(feature = "nrf52832")]
418 rx: AtomicU8::new(0), 441 rx: AtomicU8::new(0),
419 #[cfg(feature = "nrf52832")] 442 #[cfg(feature = "nrf52832")]