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
- Place the buffer in a BDMA-accessible RAM region (check the reference manual's BDMA memory map limits; use a linker section if needed).
- Verify channel configuration: memory/peripheral size, increment mode, and direction match the peripheral.
- Check the transfer length is within BDMA's 16-bit CNDTR limit.
- 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
- Place BDMA buffers in the exact RAM region documented for BDMA access (often a fixed SRAM bank).
- Keep transfer counts at or below 65535 (16-bit CNDTR).
- Double-check channel configuration (size, increment, direction) against the peripheral's requirements.
- Hold the buffer alive for the whole transfer with proper lifetimes or statics.
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
- DMA data error
- DMA: error on DMA_0 channel
- DMA: error on DMA@ channel
- DMA: error on MDMA@ channel
- DMA: error on DMA_0 channel
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)