diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 5468f6c0..9b0451c1 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -22,7 +22,7 @@ use crate::pac; use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; use crate::timer::Instance as TimerInstance; use crate::timer::{Frequency, Timer}; -use crate::uarte::{Config, Instance as UarteInstance}; +use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; // Re-export SVD variants to allow user to directly set values pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; @@ -132,6 +132,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { irq.pend(); // Enable UARTE instance + apply_workaround_for_enable_anomaly(&r); r.enable.write(|w| w.enable().enabled()); // BAUDRATE register values are `baudrate * 2^32 / 16000000` diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 60e69e03..72dcd41b 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -116,7 +116,7 @@ impl<'d, T: Instance> Uarte<'d, T> { irq.enable(); // Enable - Self::apply_workaround_for_enable_anomaly(); + apply_workaround_for_enable_anomaly(&r); r.enable.write(|w| w.enable().enabled()); Self { @@ -124,61 +124,6 @@ impl<'d, T: Instance> Uarte<'d, T> { } } - #[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] - fn apply_workaround_for_enable_anomaly() { - // Do nothing - } - - #[cfg(any(feature = "_nrf9160", feature = "nrf5340"))] - fn apply_workaround_for_enable_anomaly() { - use core::ops::Deref; - - let r = T::regs(); - - // Apply workaround for anomalies: - // - nRF9160 - anomaly 23 - // - nRF5340 - anomaly 44 - let rxenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x564) as *const u32; - let txenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x568) as *const u32; - - // NB Safety: This is taken from Nordic's driver - - // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 - if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 { - r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); - } - - // NB Safety: This is taken from Nordic's driver - - // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 - if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 { - r.enable.write(|w| w.enable().enabled()); - r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); - - let mut workaround_succeded = false; - // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered. - // On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured - // (resulting in 12 bits per data byte sent), this may take up to 40 ms. - for _ in 0..40000 { - // NB Safety: This is taken from Nordic's driver - - // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 - if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 { - workaround_succeded = true; - break; - } else { - // Need to sleep for 1us here - } - } - - if !workaround_succeded { - panic!("Failed to apply workaround for UART"); - } - - let errors = r.errorsrc.read().bits(); - // NB Safety: safe to write back the bits we just read to clear them - r.errorsrc.write(|w| unsafe { w.bits(errors) }); - r.enable.write(|w| w.enable().disabled()); - } - } - fn on_interrupt(_: *mut ()) { let r = T::regs(); let s = T::state(); @@ -330,6 +275,59 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { } } +#[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] +pub(in crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { + // Do nothing +} + +#[cfg(any(feature = "_nrf9160", feature = "nrf5340"))] +pub(in crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) { + use core::ops::Deref; + + // Apply workaround for anomalies: + // - nRF9160 - anomaly 23 + // - nRF5340 - anomaly 44 + let rxenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x564) as *const u32; + let txenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x568) as *const u32; + + // NB Safety: This is taken from Nordic's driver - + // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 + if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 { + r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); + } + + // NB Safety: This is taken from Nordic's driver - + // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 + if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 { + r.enable.write(|w| w.enable().enabled()); + r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + + let mut workaround_succeded = false; + // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered. + // On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured + // (resulting in 12 bits per data byte sent), this may take up to 40 ms. + for _ in 0..40000 { + // NB Safety: This is taken from Nordic's driver - + // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 + if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 { + workaround_succeded = true; + break; + } else { + // Need to sleep for 1us here + } + } + + if !workaround_succeded { + panic!("Failed to apply workaround for UART"); + } + + let errors = r.errorsrc.read().bits(); + // NB Safety: safe to write back the bits we just read to clear them + r.errorsrc.write(|w| unsafe { w.bits(errors) }); + r.enable.write(|w| w.enable().disabled()); + } +} + /// Interface to an UARTE peripheral that uses an additional timer and two PPI channels, /// allowing it to implement the ReadUntilIdle trait. pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> {