embassy-rs/embassy · critical
Failed to apply workaround for UART
Error message
Failed to apply workaround for UART
What it means
This is a workaround routine for the nRF52840 UARTE 'enable during ongoing DMA' anomaly (errata). The function repeatedly delays and toggles the ENABLE register expecting a specific readback; if the expected state is never observed after the retry loop, `workaround_succeded` remains false and it panics. Reaching this panic means the errata workaround could not be applied and the UART may misbehave.
Solutions
- Verify the target chip/silicon revision is one the workaround supports (nRF52840 errata 173-class issues) and that the correct feature/chip selection is compiled in.
- Ensure CLOCK_SPEED is set correctly for the actual clock so the delay loop waits long enough.
- Update embassy-nrf to the latest version, where the workaround timing may have been corrected.
- File an issue with the embassy-nrf maintainers if the panic reproduces on supported silicon — it indicates an internal invariant violation.
Defensive patterns
Strategy: try-catch
Try / catch
// Rust panics are not catchable in embedded firmware; treat as fatal.
// Guard by verifying chip/feature support at build time:
#[cfg(all(target_chip = "nrf52840", feature = "_nrf52840_anomaly"))]
compile_error!("verify UARTE enable-anomaly workaround applies to your silicon revision"); Prevention
- Compile for a chip/silicon revision explicitly supported by embassy-nrf's errata workarounds.
- Keep embassy-nrf updated so workaround timing fixes are picked up.
- Test RX start/stop paths on real hardware during bring-up, not only in simulation.
When it happens
Trigger: Calling the UARTE driver code path that invokes `apply_workaround_for_enable_anomaly` (e.g. stopping/starting RX on an affected nRF52840 chip) when the ENABLE register never reaches the state the workaround loop waits for within its delay/retry budget.
Common situations: Running on silicon revisions not targeted by the workaround's assumptions; clock speed mismatch making the fixed `delay(CLOCK_SPEED / 1_000_000)` budget insufficient; using the driver on hardware where the errata workaround sequence is invalid.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- RTS and CTS pins must be either both set or none set.
- Boot prepare error
- BufferedUarte UART overrun
- unwrap of ` ` failed
- unwrap of ` ` failed
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/fbd954c11a742be8.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-nrf/src/uarte.rs:1229
// 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
// Get the worst case clock speed
#[cfg(feature = "_nrf9160")]
const CLOCK_SPEED: u32 = 64_000_000;
#[cfg(feature = "_nrf5340")]
const CLOCK_SPEED: u32 = 128_000_000;
cortex_m::asm::delay(CLOCK_SPEED / 1_000_000);
}
}
if !workaround_succeded {
panic!("Failed to apply workaround for UART");
}
// write back the bits we just read to clear them
let errors = r.errorsrc().read();
r.errorsrc().write_value(errors);
r.enable().write(|w| w.set_enable(vals::Enable::Disabled));
}
}
pub(crate) fn drop_tx_rx(r: pac::uarte::Uarte, s: &State) {
if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 {
// Finally we can disable, and we do so for the peripheral
// i.e. not just rx concerns.
r.enable().write(|w| w.set_enable(vals::Enable::Disabled));
gpio::deconfigure_pin(r.psel().rxd().read());
gpio::deconfigure_pin(r.psel().txd().read());
gpio::deconfigure_pin(r.psel().rts().read());View on GitHub (pinned to 463a07b963)