aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src/spim.rs
diff options
context:
space:
mode:
authorPriit Laes <[email protected]>2023-09-06 23:15:33 +0300
committerPriit Laes <[email protected]>2023-09-07 18:58:22 +0300
commit9de08d56a087d946bb768ed164aed459b0a2ce3c (patch)
tree094d5344f66f9b2ad724f728c21a4811645ce4ff /embassy-nrf/src/spim.rs
parent26740bb3ef01b4965d3be92622f0f4220b6cb931 (diff)
nrf: spim: Anomaly 109 workaround for SPIM peripheral (#460)
This implements SPIM TX workaround suggested from section 3.8.1 from Anomaly 109 addendum. In workaround case we first keep track of original maxcnt values, then initiate "fake" transfer with zero-length maxcnt values. Once the "fake" transfer is triggered, we handle it, fill in the original maxcnt values and restart the transmission.
Diffstat (limited to 'embassy-nrf/src/spim.rs')
-rw-r--r--embassy-nrf/src/spim.rs60
1 files changed, 56 insertions, 4 deletions
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index d131a43dd..a468bc302 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -68,6 +68,28 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
68 let r = T::regs(); 68 let r = T::regs();
69 let s = T::state(); 69 let s = T::state();
70 70
71 #[cfg(feature = "nrf52832")]
72 // NRF32 Anomaly 109 workaround... NRF52832
73 if r.intenset.read().started().is_enabled() && r.events_started.read().bits() != 0 {
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());
88 // ... and start actual, hopefully glitch-free transmission
89 r.tasks_start.write(|w| unsafe { w.bits(1) });
90 return;
91 }
92
71 if r.events_end.read().bits() != 0 { 93 if r.events_end.read().bits() != 0 {
72 s.end_waker.wake(); 94 s.end_waker.wake();
73 r.intenclr.write(|w| w.end().clear()); 95 r.intenclr.write(|w| w.end().clear());
@@ -223,14 +245,33 @@ impl<'d, T: Instance> Spim<'d, T> {
223 let r = T::regs(); 245 let r = T::regs();
224 246
225 // Set up the DMA write. 247 // Set up the DMA write.
226 let (ptr, len) = slice_ptr_parts(tx); 248 let (ptr, tx_len) = slice_ptr_parts(tx);
227 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 249 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
228 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 250 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) });
229 251
230 // Set up the DMA read. 252 // Set up the DMA read.
231 let (ptr, len) = slice_ptr_parts_mut(rx); 253 let (ptr, rx_len) = slice_ptr_parts_mut(rx);
232 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); 254 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
233 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 255 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) });
256
257 // ANOMALY 109 workaround
258 #[cfg(feature = "nrf52832")]
259 {
260 let s = T::state();
261
262 r.events_started.reset();
263
264 // Set rx/tx buffer lengths to 0...
265 r.txd.maxcnt.reset();
266 r.rxd.maxcnt.reset();
267
268 // ...and keep track of original buffer lengths...
269 s.tx.store(tx_len as _, Ordering::Relaxed);
270 s.rx.store(rx_len as _, Ordering::Relaxed);
271
272 // ...signalling the start of the fake transfer.
273 r.intenset.write(|w| w.started().bit(true));
274 }
234 275
235 // Reset and enable the event 276 // Reset and enable the event
236 r.events_end.reset(); 277 r.events_end.reset();
@@ -386,18 +427,29 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
386} 427}
387 428
388pub(crate) mod sealed { 429pub(crate) mod sealed {
430 #[cfg(feature = "nrf52832")]
431 use core::sync::atomic::AtomicU8;
432
389 use embassy_sync::waitqueue::AtomicWaker; 433 use embassy_sync::waitqueue::AtomicWaker;
390 434
391 use super::*; 435 use super::*;
392 436
393 pub struct State { 437 pub struct State {
394 pub end_waker: AtomicWaker, 438 pub end_waker: AtomicWaker,
439 #[cfg(feature = "nrf52832")]
440 pub rx: AtomicU8,
441 #[cfg(feature = "nrf52832")]
442 pub tx: AtomicU8,
395 } 443 }
396 444
397 impl State { 445 impl State {
398 pub const fn new() -> Self { 446 pub const fn new() -> Self {
399 Self { 447 Self {
400 end_waker: AtomicWaker::new(), 448 end_waker: AtomicWaker::new(),
449 #[cfg(feature = "nrf52832")]
450 rx: AtomicU8::new(0),
451 #[cfg(feature = "nrf52832")]
452 tx: AtomicU8::new(0),
401 } 453 }
402 } 454 }
403 } 455 }