embassy-rs/embassy · critical

DMA: error on DMA_0 channel

Error message

DMA: error on DMA_0 channel {}

What it means

In the LPC55 DMA interrupt handler, each channel with an error bit set in `errint0` causes an immediate panic naming the failing channel. DMA transfer errors (bus errors, invalid descriptors) on LPC55 are treated as unrecoverable by this driver rather than returned to the application. The panic aborts the firmware at the point of the interrupt.

Solutions

  1. Identify the failing channel from the panic message and audit what transfer that channel was running (addresses, lengths, peripheral).
  2. Validate the source/destination addresses and buffer sizes passed to the DMA transfer API before starting it.
  3. Ensure the source peripheral is powered/clocked and its DMA requests are correctly wired in your init code.
  4. Update embassy-nxp in case the driver has gained proper error handling (Result-returning transfers) since your version.

Example fix

// before
let dma_channel = p.DMA0_CH0.into();
dma_channel.read(&mut weird_ptr as *mut u8, &mut buf).await; // invalid address -> bus error
// after
assert!(core::ptr::addr_of!(buf).is_aligned());
dma_channel.read(&mut peripheral_rx_addr, &mut buf).await; // valid mapped peripheral address
Defensive patterns

Strategy: validation

Validate before calling

// Before issuing a DMA transfer, validate addresses and lengths:
fn dma_transfer_ok(src: *const u8, dst: *mut u8, len: usize) -> bool {
    !src.is_null() && !dst.is_null() && len > 0
        && (src as usize) >= 0x0000_0000 && (dst as usize) < 0x2000_0000
        // plus peripheral-region checks per your memory map
}

Try / catch

// The driver panics in the IRQ; errors cannot be caught at runtime.
// Mitigate by pre-validating every transfer configuration before .await:

Prevention

When it happens

Trigger: A DMA transfer on DMA_0 encounters a hardware error (source/destination bus fault, misaligned or invalid transfer configuration, descriptor issue); the DMA0 IRQ fires, the handler scans `errint0` and finds the error bit for the channel.

Common situations: DMA-ing from/to a peripheral or memory region that is not accessible (wrong address, powered-down peripheral); buffer in uncacheable/invalid memory; race where the transfer is configured with a zero length or bad burst settings; hardware fault on the bus.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/c1d500d32738be9a. Report an issue: GitHub.

Appendix: source

Thrown at embassy-nxp/src/dma/lpc55.rs:25

use core::task::{Context, Poll};

use critical_section::Mutex;
use embassy_hal_internal::interrupt::InterruptExt;
use embassy_hal_internal::{PeripheralType, impl_peripheral};
use embassy_sync::waitqueue::AtomicWaker;

use crate::Peri;
#[cfg(feature = "rt")]
use crate::pac::interrupt;
use crate::pac::{SYSCON, *};

#[cfg(feature = "rt")]
#[interrupt]
fn DMA0() {
    let inta = DMA0.inta0().read().ia();
    for channel in 0..CHANNEL_COUNT {
        if (DMA0.errint0().read().err() & (1 << channel)) != 0 {
            panic!("DMA: error on DMA_0 channel {}", channel);
        }

        if (inta & (1 << channel)) != 0 {
            CHANNEL_WAKERS[channel].wake();
            DMA0.inta0().modify(|w| w.set_ia(1 << channel));
        }
    }
}

pub(crate) fn init() {
    assert_eq!(core::mem::size_of::<DmaDescriptor>(), 16, "Descriptor must be 16 bytes");
    assert_eq!(
        core::mem::align_of::<DmaDescriptor>(),
        16,
        "Descriptor must be 16-byte aligned"
    );
    assert_eq!(
        core::mem::align_of::<DmaDescriptorTable>(),

View on GitHub (pinned to 463a07b963)