embassy-rs/embassy · critical

DMA: error on BDMA@ channel

Error message

DMA: error on BDMA@{:08x} channel {}

What it means

Analogous to the DMA transfer-error panic, but for the BDMA controller (used on e.g. STM32L4/G0/L5 for limited peripherals like LPUART/DAC). When the channel's transfer-error flag (teif) is observed in the BDMA interrupt, the driver panics, reporting the BDMA base address and channel number.

Solutions

  1. Place the buffer in a BDMA-accessible RAM region (check the reference manual's BDMA memory map limits; use a linker section if needed).
  2. Verify channel configuration: memory/peripheral size, increment mode, and direction match the peripheral.
  3. Check the transfer length is within BDMA's 16-bit CNDTR limit.
  4. Keep the buffer valid for the entire transfer and check peripheral-level error flags too.

Example fix

// before
#[link_section = ".axisram"]
static BUF: [u8; 64] = [0u8; 64]; // region not reachable by BDMA

// after
#[link_section = ".sram1"]
static BUF: [u8; 64] = [0u8; 64]; // BDMA-accessible region
Defensive patterns

Strategy: validation

Validate before calling

// BDMA can only access specific SRAM regions; check before use:
let addr = buf.as_ptr() as u32;
assert!((0x2000_0000..0x2000_c000).contains(&addr), "buffer not in BDMA-accessible SRAM");
assert!(len <= 0xFFFF, "BDMA CNDTR is 16-bit, transfer too large");

Type guard

fn bdma_accessible<T>(buf: &[T]) -> bool {
    let addr = buf.as_ptr() as u32;
    // Adjust range to the specific chip's BDMA-capable memory map
    (0x2000_0000..0x2000_c000).contains(&addr)
}

Try / catch

// Panic in IRQ: not catchable. Prevent by validating placement before transfer:
assert!(bdma_accessible(&buf), "BDMA cannot reach this memory region");

Prevention

When it happens

Trigger: on_irq servicing a BDMA channel sees isr.teif(info.num) set — invalid memory address for the BDMA (which can only access certain RAM regions), bad memory increment/size settings, or a peripheral error on a BDMA-driven channel.

Common situations: Buffer placed in memory region BDMA cannot reach (BDMA often only accesses SRAM1/SRAM2 at fixed addresses); wrong channel configuration for LPUART/DAC; transfer size larger than the 65535 max for BDMA; buffer freed before completion.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at embassy-stm32/src/dma/dma_bdma.rs:52

            }
            if isr.tcif(info.num % 4) && cr.read().tcie() {
                // Acknowledge transfer complete interrupt
                r.ifcr(info.num / 4).write(|w| w.set_tcif(info.num % 4, true));
                state.complete_count.fetch_add(1, Ordering::Release);
                activity = true;
            }
            if !activity {
                return;
            }
            state.waker.wake();
        }
        #[cfg(bdma)]
        DmaInfo::Bdma(r) => {
            let isr = r.isr().read();
            let cr = r.ch(info.num).cr();

            if isr.teif(info.num) {
                panic!("DMA: error on BDMA@{:08x} channel {}", r.as_ptr() as u32, info.num);
            }

            let mut activity = false;
            if isr.htif(info.num) && cr.read().htie() {
                // Acknowledge half transfer complete interrupt
                r.ifcr().write(|w| w.set_htif(info.num, true));
                activity = true;
            }
            if isr.tcif(info.num) && cr.read().tcie() {
                // Acknowledge transfer complete interrupt
                r.ifcr().write(|w| w.set_tcif(info.num, true));
                #[cfg(not(armv6m))]
                state.complete_count.fetch_add(1, Ordering::Release);
                #[cfg(armv6m)]
                critical_section::with(|_| {
                    let x = state.complete_count.load(Ordering::Relaxed);
                    state.complete_count.store(x + 1, Ordering::Release);
                });

View on GitHub (pinned to 463a07b963)