diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 320426060..15ebcdd57 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -114,6 +114,7 @@ impl<'d, T: Instance> Uarte<'d, T> { irq.enable(); // Enable + Self::apply_workaround_for_enable_anomaly(); r.enable.write(|w| w.enable().enabled()); Self { @@ -121,6 +122,61 @@ 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();