diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-09-23 11:14:16 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-09-23 11:14:16 +0000 |
| commit | 1e80fd81f7ccc8cd48d4f9e373395222c3394c6e (patch) | |
| tree | 96ece93b25608b63163b0bfadd6f1a51b528e13b | |
| parent | 52e269edbb5bddfc9d9101d07903a0266367007f (diff) | |
| parent | 6f83acc010786d89400426c3395f871ac7199d32 (diff) | |
Merge pull request #1939 from nilfit/spim-anomaly-109
spim: Fix nRF52832 SPIM with polling executors
| -rw-r--r-- | embassy-nrf/Cargo.toml | 5 | ||||
| -rw-r--r-- | embassy-nrf/src/spim.rs | 82 |
2 files changed, 56 insertions, 31 deletions
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index eee927211..3c706b473 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -51,7 +51,7 @@ nrf52805 = ["nrf52805-pac", "_nrf52"] | |||
| 51 | nrf52810 = ["nrf52810-pac", "_nrf52"] | 51 | nrf52810 = ["nrf52810-pac", "_nrf52"] |
| 52 | nrf52811 = ["nrf52811-pac", "_nrf52"] | 52 | nrf52811 = ["nrf52811-pac", "_nrf52"] |
| 53 | nrf52820 = ["nrf52820-pac", "_nrf52"] | 53 | nrf52820 = ["nrf52820-pac", "_nrf52"] |
| 54 | nrf52832 = ["nrf52832-pac", "_nrf52"] | 54 | nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"] |
| 55 | nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] | 55 | nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] |
| 56 | nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] | 56 | nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] |
| 57 | nrf5340-app-s = ["_nrf5340-app", "_s"] | 57 | nrf5340-app-s = ["_nrf5340-app", "_s"] |
| @@ -90,6 +90,9 @@ _ppi = [] | |||
| 90 | _dppi = [] | 90 | _dppi = [] |
| 91 | _gpio-p1 = [] | 91 | _gpio-p1 = [] |
| 92 | 92 | ||
| 93 | # Errata workarounds | ||
| 94 | _nrf52832_anomaly_109 = [] | ||
| 95 | |||
| 93 | [dependencies] | 96 | [dependencies] |
| 94 | embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } | 97 | embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } |
| 95 | embassy-sync = { version = "0.3.0", path = "../embassy-sync" } | 98 | embassy-sync = { version = "0.3.0", path = "../embassy-sync" } |
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 99a195a6e..4828af43e 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs | |||
| @@ -68,30 +68,14 @@ 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")] | 71 | #[cfg(feature = "_nrf52832_anomaly_109")] |
| 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 | } |
| @@ -222,8 +206,7 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 222 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); | 206 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); |
| 223 | r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); | 207 | r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); |
| 224 | 208 | ||
| 225 | // ANOMALY 109 workaround | 209 | #[cfg(feature = "_nrf52832_anomaly_109")] |
| 226 | #[cfg(feature = "nrf52832")] | ||
| 227 | { | 210 | { |
| 228 | let s = T::state(); | 211 | let s = T::state(); |
| 229 | 212 | ||
| @@ -254,6 +237,9 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 254 | fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { | 237 | fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { |
| 255 | self.prepare(rx, tx)?; | 238 | self.prepare(rx, tx)?; |
| 256 | 239 | ||
| 240 | #[cfg(feature = "_nrf52832_anomaly_109")] | ||
| 241 | while let Poll::Pending = self.nrf52832_dma_workaround_status() {} | ||
| 242 | |||
| 257 | // Wait for 'end' event. | 243 | // Wait for 'end' event. |
| 258 | while T::regs().events_end.read().bits() == 0 {} | 244 | while T::regs().events_end.read().bits() == 0 {} |
| 259 | 245 | ||
| @@ -278,9 +264,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> { | 264 | async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { |
| 279 | self.prepare(rx, tx)?; | 265 | self.prepare(rx, tx)?; |
| 280 | 266 | ||
| 267 | #[cfg(feature = "_nrf52832_anomaly_109")] | ||
| 268 | poll_fn(|cx| { | ||
| 269 | let s = T::state(); | ||
| 270 | |||
| 271 | s.waker.register(cx.waker()); | ||
| 272 | |||
| 273 | self.nrf52832_dma_workaround_status() | ||
| 274 | }) | ||
| 275 | .await; | ||
| 276 | |||
| 281 | // Wait for 'end' event. | 277 | // Wait for 'end' event. |
| 282 | poll_fn(|cx| { | 278 | poll_fn(|cx| { |
| 283 | T::state().end_waker.register(cx.waker()); | 279 | T::state().waker.register(cx.waker()); |
| 284 | if T::regs().events_end.read().bits() != 0 { | 280 | if T::regs().events_end.read().bits() != 0 { |
| 285 | return Poll::Ready(()); | 281 | return Poll::Ready(()); |
| 286 | } | 282 | } |
| @@ -371,6 +367,32 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 371 | pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> { | 367 | pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> { |
| 372 | self.async_inner_from_ram(&mut [], data).await | 368 | self.async_inner_from_ram(&mut [], data).await |
| 373 | } | 369 | } |
| 370 | |||
| 371 | #[cfg(feature = "_nrf52832_anomaly_109")] | ||
| 372 | fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> { | ||
| 373 | let r = T::regs(); | ||
| 374 | if r.events_started.read().bits() != 0 { | ||
| 375 | let s = T::state(); | ||
| 376 | |||
| 377 | // Handle the first "fake" transmission | ||
| 378 | r.events_started.reset(); | ||
| 379 | r.events_end.reset(); | ||
| 380 | |||
| 381 | // Update DMA registers with correct rx/tx buffer sizes | ||
| 382 | r.rxd | ||
| 383 | .maxcnt | ||
| 384 | .write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) }); | ||
| 385 | r.txd | ||
| 386 | .maxcnt | ||
| 387 | .write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) }); | ||
| 388 | |||
| 389 | r.intenset.write(|w| w.end().set()); | ||
| 390 | // ... and start actual, hopefully glitch-free transmission | ||
| 391 | r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||
| 392 | return Poll::Ready(()); | ||
| 393 | } | ||
| 394 | Poll::Pending | ||
| 395 | } | ||
| 374 | } | 396 | } |
| 375 | 397 | ||
| 376 | impl<'d, T: Instance> Drop for Spim<'d, T> { | 398 | impl<'d, T: Instance> Drop for Spim<'d, T> { |
| @@ -395,7 +417,7 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { | |||
| 395 | } | 417 | } |
| 396 | 418 | ||
| 397 | pub(crate) mod sealed { | 419 | pub(crate) mod sealed { |
| 398 | #[cfg(feature = "nrf52832")] | 420 | #[cfg(feature = "_nrf52832_anomaly_109")] |
| 399 | use core::sync::atomic::AtomicU8; | 421 | use core::sync::atomic::AtomicU8; |
| 400 | 422 | ||
| 401 | use embassy_sync::waitqueue::AtomicWaker; | 423 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -403,20 +425,20 @@ pub(crate) mod sealed { | |||
| 403 | use super::*; | 425 | use super::*; |
| 404 | 426 | ||
| 405 | pub struct State { | 427 | pub struct State { |
| 406 | pub end_waker: AtomicWaker, | 428 | pub waker: AtomicWaker, |
| 407 | #[cfg(feature = "nrf52832")] | 429 | #[cfg(feature = "_nrf52832_anomaly_109")] |
| 408 | pub rx: AtomicU8, | 430 | pub rx: AtomicU8, |
| 409 | #[cfg(feature = "nrf52832")] | 431 | #[cfg(feature = "_nrf52832_anomaly_109")] |
| 410 | pub tx: AtomicU8, | 432 | pub tx: AtomicU8, |
| 411 | } | 433 | } |
| 412 | 434 | ||
| 413 | impl State { | 435 | impl State { |
| 414 | pub const fn new() -> Self { | 436 | pub const fn new() -> Self { |
| 415 | Self { | 437 | Self { |
| 416 | end_waker: AtomicWaker::new(), | 438 | waker: AtomicWaker::new(), |
| 417 | #[cfg(feature = "nrf52832")] | 439 | #[cfg(feature = "_nrf52832_anomaly_109")] |
| 418 | rx: AtomicU8::new(0), | 440 | rx: AtomicU8::new(0), |
| 419 | #[cfg(feature = "nrf52832")] | 441 | #[cfg(feature = "_nrf52832_anomaly_109")] |
| 420 | tx: AtomicU8::new(0), | 442 | tx: AtomicU8::new(0), |
| 421 | } | 443 | } |
| 422 | } | 444 | } |
