diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index eee92721..3c706b47 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -51,7 +51,7 @@ nrf52805 = ["nrf52805-pac", "_nrf52"] nrf52810 = ["nrf52810-pac", "_nrf52"] nrf52811 = ["nrf52811-pac", "_nrf52"] nrf52820 = ["nrf52820-pac", "_nrf52"] -nrf52832 = ["nrf52832-pac", "_nrf52"] +nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"] nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] nrf5340-app-s = ["_nrf5340-app", "_s"] @@ -90,6 +90,9 @@ _ppi = [] _dppi = [] _gpio-p1 = [] +# Errata workarounds +_nrf52832_anomaly_109 = [] + [dependencies] embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-sync = { version = "0.3.0", path = "../embassy-sync" } diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 99a195a6..4828af43 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -68,30 +68,14 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); - #[cfg(feature = "nrf52832")] - // NRF32 Anomaly 109 workaround... NRF52832 - if r.intenset.read().started().is_enabled() && r.events_started.read().bits() != 0 { - // Handle the first "fake" transmission - r.events_started.reset(); - r.events_end.reset(); - - // Update DMA registers with correct rx/tx buffer sizes - r.rxd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) }); - r.txd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) }); - - // Disable interrupt for STARTED event... + #[cfg(feature = "_nrf52832_anomaly_109")] + if r.events_started.read().bits() != 0 { + s.waker.wake(); r.intenclr.write(|w| w.started().clear()); - // ... and start actual, hopefully glitch-free transmission - r.tasks_start.write(|w| unsafe { w.bits(1) }); - return; } if r.events_end.read().bits() != 0 { - s.end_waker.wake(); + s.waker.wake(); r.intenclr.write(|w| w.end().clear()); } } @@ -222,8 +206,7 @@ impl<'d, T: Instance> Spim<'d, T> { r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); - // ANOMALY 109 workaround - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] { let s = T::state(); @@ -254,6 +237,9 @@ impl<'d, T: Instance> Spim<'d, T> { fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { self.prepare(rx, tx)?; + #[cfg(feature = "_nrf52832_anomaly_109")] + while let Poll::Pending = self.nrf52832_dma_workaround_status() {} + // Wait for 'end' event. while T::regs().events_end.read().bits() == 0 {} @@ -278,9 +264,19 @@ impl<'d, T: Instance> Spim<'d, T> { async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { self.prepare(rx, tx)?; + #[cfg(feature = "_nrf52832_anomaly_109")] + poll_fn(|cx| { + let s = T::state(); + + s.waker.register(cx.waker()); + + self.nrf52832_dma_workaround_status() + }) + .await; + // Wait for 'end' event. poll_fn(|cx| { - T::state().end_waker.register(cx.waker()); + T::state().waker.register(cx.waker()); if T::regs().events_end.read().bits() != 0 { return Poll::Ready(()); } @@ -371,6 +367,32 @@ impl<'d, T: Instance> Spim<'d, T> { pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> { self.async_inner_from_ram(&mut [], data).await } + + #[cfg(feature = "_nrf52832_anomaly_109")] + fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> { + let r = T::regs(); + if r.events_started.read().bits() != 0 { + let s = T::state(); + + // Handle the first "fake" transmission + r.events_started.reset(); + r.events_end.reset(); + + // Update DMA registers with correct rx/tx buffer sizes + r.rxd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) }); + r.txd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) }); + + r.intenset.write(|w| w.end().set()); + // ... and start actual, hopefully glitch-free transmission + r.tasks_start.write(|w| unsafe { w.bits(1) }); + return Poll::Ready(()); + } + Poll::Pending + } } impl<'d, T: Instance> Drop for Spim<'d, T> { @@ -395,7 +417,7 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { } pub(crate) mod sealed { - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] use core::sync::atomic::AtomicU8; use embassy_sync::waitqueue::AtomicWaker; @@ -403,20 +425,20 @@ pub(crate) mod sealed { use super::*; pub struct State { - pub end_waker: AtomicWaker, - #[cfg(feature = "nrf52832")] + pub waker: AtomicWaker, + #[cfg(feature = "_nrf52832_anomaly_109")] pub rx: AtomicU8, - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] pub tx: AtomicU8, } impl State { pub const fn new() -> Self { Self { - end_waker: AtomicWaker::new(), - #[cfg(feature = "nrf52832")] + waker: AtomicWaker::new(), + #[cfg(feature = "_nrf52832_anomaly_109")] rx: AtomicU8::new(0), - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] tx: AtomicU8::new(0), } }