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

  1. 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.
  2. Ensure CLOCK_SPEED is set correctly for the actual clock so the delay loop waits long enough.
  3. Update embassy-nrf to the latest version, where the workaround timing may have been corrected.
  4. 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

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


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)