From 5e613d9abbb945e7fc7d4c895d645bfad6a3d2c8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 30 Aug 2023 01:37:18 +0200 Subject: Sync all fmt.rs files. --- embassy-nrf/src/fmt.rs | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'embassy-nrf/src') diff --git a/embassy-nrf/src/fmt.rs b/embassy-nrf/src/fmt.rs index 066970813..78e583c1c 100644 --- a/embassy-nrf/src/fmt.rs +++ b/embassy-nrf/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} -- cgit From 9de08d56a087d946bb768ed164aed459b0a2ce3c Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 6 Sep 2023 23:15:33 +0300 Subject: 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. --- embassy-nrf/src/spim.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 4 deletions(-) (limited to 'embassy-nrf/src') 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 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... + 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(); r.intenclr.write(|w| w.end().clear()); @@ -223,14 +245,33 @@ impl<'d, T: Instance> Spim<'d, T> { let r = T::regs(); // Set up the DMA write. - let (ptr, len) = slice_ptr_parts(tx); + let (ptr, tx_len) = slice_ptr_parts(tx); r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); - r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) }); // Set up the DMA read. - let (ptr, len) = slice_ptr_parts_mut(rx); + let (ptr, rx_len) = slice_ptr_parts_mut(rx); r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); + + // ANOMALY 109 workaround + #[cfg(feature = "nrf52832")] + { + let s = T::state(); + + r.events_started.reset(); + + // Set rx/tx buffer lengths to 0... + r.txd.maxcnt.reset(); + r.rxd.maxcnt.reset(); + + // ...and keep track of original buffer lengths... + s.tx.store(tx_len as _, Ordering::Relaxed); + s.rx.store(rx_len as _, Ordering::Relaxed); + + // ...signalling the start of the fake transfer. + r.intenset.write(|w| w.started().bit(true)); + } // Reset and enable the event r.events_end.reset(); @@ -386,18 +427,29 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { } pub(crate) mod sealed { + #[cfg(feature = "nrf52832")] + use core::sync::atomic::AtomicU8; + use embassy_sync::waitqueue::AtomicWaker; use super::*; pub struct State { pub end_waker: AtomicWaker, + #[cfg(feature = "nrf52832")] + pub rx: AtomicU8, + #[cfg(feature = "nrf52832")] + pub tx: AtomicU8, } impl State { pub const fn new() -> Self { Self { end_waker: AtomicWaker::new(), + #[cfg(feature = "nrf52832")] + rx: AtomicU8::new(0), + #[cfg(feature = "nrf52832")] + tx: AtomicU8::new(0), } } } -- cgit From db717d9c81c76709ea84727a31fc4a201e947014 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 6 Sep 2023 16:42:04 +0300 Subject: nrf: Remove unneeded include from Temp's example Fixes doctest when `time` feature is not enabled. --- embassy-nrf/src/temp.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'embassy-nrf/src') diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index cec46d8d0..5e2998b10 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs @@ -57,7 +57,6 @@ impl<'d> Temp<'d> { /// ```no_run /// use embassy_nrf::{bind_interrupts, temp}; /// use embassy_nrf::temp::Temp; - /// use embassy_time::{Duration, Timer}; /// /// bind_interrupts!(struct Irqs { /// TEMP => temp::InterruptHandler; -- cgit From 8413a89752b672cf21a7cd4e07a9d0f3cccfac33 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 6 Sep 2023 16:44:02 +0300 Subject: nrf: spim: Use SetConfig trait internally to reduce duplication --- embassy-nrf/src/spim.rs | 40 ++++------------------------------------ 1 file changed, 4 insertions(+), 36 deletions(-) (limited to 'embassy-nrf/src') diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index a468bc302..99a195a6e 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -189,42 +189,10 @@ impl<'d, T: Instance> Spim<'d, T> { // Enable SPIM instance. r.enable.write(|w| w.enable().enabled()); - // Configure mode. - let mode = config.mode; - r.config.write(|w| { - match mode { - MODE_0 => { - w.order().msb_first(); - w.cpol().active_high(); - w.cpha().leading(); - } - MODE_1 => { - w.order().msb_first(); - w.cpol().active_high(); - w.cpha().trailing(); - } - MODE_2 => { - w.order().msb_first(); - w.cpol().active_low(); - w.cpha().leading(); - } - MODE_3 => { - w.order().msb_first(); - w.cpol().active_low(); - w.cpha().trailing(); - } - } + let mut spim = Self { _p: spim }; - w - }); - - // Configure frequency. - let frequency = config.frequency; - r.frequency.write(|w| w.frequency().variant(frequency)); - - // Set over-read character - let orc = config.orc; - r.orc.write(|w| unsafe { w.orc().bits(orc) }); + // Apply runtime peripheral configuration + Self::set_config(&mut spim, &config); // Disable all events interrupts r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); @@ -232,7 +200,7 @@ impl<'d, T: Instance> Spim<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { _p: spim } + spim } fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { -- cgit From 93d4cfe7c10cfacc8ac88dd75a88d76e71476db0 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 6 Sep 2023 16:46:17 +0300 Subject: nrf: spis: Use SetConfig trait internally to reduce duplication --- embassy-nrf/src/spis.rs | 45 ++++----------------------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) (limited to 'embassy-nrf/src') diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 212825121..e695ba6b7 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -169,47 +169,10 @@ impl<'d, T: Instance> Spis<'d, T> { // Enable SPIS instance. r.enable.write(|w| w.enable().enabled()); - // Configure mode. - let mode = config.mode; - r.config.write(|w| { - match mode { - MODE_0 => { - w.order().msb_first(); - w.cpol().active_high(); - w.cpha().leading(); - } - MODE_1 => { - w.order().msb_first(); - w.cpol().active_high(); - w.cpha().trailing(); - } - MODE_2 => { - w.order().msb_first(); - w.cpol().active_low(); - w.cpha().leading(); - } - MODE_3 => { - w.order().msb_first(); - w.cpol().active_low(); - w.cpha().trailing(); - } - } + let mut spis = Self { _p: spis }; - w - }); - - // Set over-read character. - let orc = config.orc; - r.orc.write(|w| unsafe { w.orc().bits(orc) }); - - // Set default character. - let def = config.def; - r.def.write(|w| unsafe { w.def().bits(def) }); - - // Configure auto-acquire on 'transfer end' event. - if config.auto_acquire { - r.shorts.write(|w| w.end_acquire().bit(true)); - } + // Apply runtime peripheral configuration + Self::set_config(&mut spis, &config); // Disable all events interrupts. r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); @@ -217,7 +180,7 @@ impl<'d, T: Instance> Spis<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { _p: spis } + spis } fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { -- cgit From 521970535e119f7535d6d4d4760e1d76b2231753 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 6 Sep 2023 16:48:22 +0300 Subject: nrf: twim: Use SetConfig trait to reduce code duplication --- embassy-nrf/src/twim.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'embassy-nrf/src') diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index fdea480e3..fe38fb102 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -167,9 +167,10 @@ impl<'d, T: Instance> Twim<'d, T> { // Enable TWIM instance. r.enable.write(|w| w.enable().enabled()); - // Configure frequency. - r.frequency - .write(|w| unsafe { w.frequency().bits(config.frequency as u32) }); + let mut twim = Self { _p: twim }; + + // Apply runtime peripheral configuration + Self::set_config(&mut twim, &config); // Disable all events interrupts r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); @@ -177,7 +178,7 @@ impl<'d, T: Instance> Twim<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { _p: twim } + twim } /// Set TX buffer, checking that it is in RAM and has suitable length. -- cgit From e8b961232b80c8169eecb62c508bcf46abcd3705 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 14 Sep 2023 17:24:28 +0200 Subject: Fix gpiote when waking up from systemoff --- embassy-nrf/src/gpiote.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'embassy-nrf/src') diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 7488bc085..d16b4a43b 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -86,7 +86,6 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { unsafe { irq.enable() }; let g = regs(); - g.events_port.write(|w| w); g.intenset.write(|w| w.port().set()); } -- cgit From 2b7b7a917d0fc5917cb968c52bd19d710675f540 Mon Sep 17 00:00:00 2001 From: Nils Fitinghoff Date: Fri, 22 Sep 2023 16:12:57 +0300 Subject: spim: Fix SPIM with polling executors Co-authored-by: Priit Laes --- embassy-nrf/src/spim.rs | 67 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 22 deletions(-) (limited to 'embassy-nrf/src') 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 interrupt::typelevel::Handler for InterruptHandl 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... + 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()); } } @@ -254,6 +238,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")] + while let Poll::Pending = self.nrf52832_dma_workaround_status() {} + // Wait for 'end' event. while T::regs().events_end.read().bits() == 0 {} @@ -278,9 +265,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")] + 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 +368,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")] + 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> { @@ -403,7 +426,7 @@ pub(crate) mod sealed { use super::*; pub struct State { - pub end_waker: AtomicWaker, + pub waker: AtomicWaker, #[cfg(feature = "nrf52832")] pub rx: AtomicU8, #[cfg(feature = "nrf52832")] @@ -413,7 +436,7 @@ pub(crate) mod sealed { impl State { pub const fn new() -> Self { Self { - end_waker: AtomicWaker::new(), + waker: AtomicWaker::new(), #[cfg(feature = "nrf52832")] rx: AtomicU8::new(0), #[cfg(feature = "nrf52832")] -- cgit From 6f83acc010786d89400426c3395f871ac7199d32 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 22 Sep 2023 17:30:09 +0300 Subject: Add separate work-around specific flag for DMA errata on NRF52832 --- embassy-nrf/src/spim.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'embassy-nrf/src') diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index a0d2c8eb1..4828af43e 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -68,7 +68,7 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] if r.events_started.read().bits() != 0 { s.waker.wake(); r.intenclr.write(|w| w.started().clear()); @@ -206,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(); @@ -238,7 +237,7 @@ 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")] + #[cfg(feature = "_nrf52832_anomaly_109")] while let Poll::Pending = self.nrf52832_dma_workaround_status() {} // Wait for 'end' event. @@ -265,7 +264,7 @@ 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")] + #[cfg(feature = "_nrf52832_anomaly_109")] poll_fn(|cx| { let s = T::state(); @@ -369,7 +368,7 @@ impl<'d, T: Instance> Spim<'d, T> { self.async_inner_from_ram(&mut [], data).await } - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> { let r = T::regs(); if r.events_started.read().bits() != 0 { @@ -418,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; @@ -427,9 +426,9 @@ pub(crate) mod sealed { pub struct State { pub waker: AtomicWaker, - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] pub rx: AtomicU8, - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] pub tx: AtomicU8, } @@ -437,9 +436,9 @@ pub(crate) mod sealed { pub const fn new() -> Self { Self { waker: AtomicWaker::new(), - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] rx: AtomicU8::new(0), - #[cfg(feature = "nrf52832")] + #[cfg(feature = "_nrf52832_anomaly_109")] tx: AtomicU8::new(0), } } -- cgit From bd9021ca1db721334a518c0cfab42cfa6e373c74 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 25 Sep 2023 22:34:41 +0200 Subject: Make irq token Copy+Clone --- embassy-nrf/src/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'embassy-nrf/src') diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 355a00497..9c4b6569d 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -102,6 +102,7 @@ mod chip; #[macro_export] macro_rules! bind_interrupts { ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + #[derive(Copy, Clone)] $vis struct $name; $( -- cgit