embassy-rs/embassy · error
DMA transfers may not be larger than 65535 bytes.
Error message
DMA transfers may not be larger than 65535 bytes.
What it means
The computed transfer size (length in elements times word size in bytes) does not fit into the 16-bit BNDT register, so it exceeds 65535 bytes. GPDMA transfers are capped at 64 KiB minus one byte per channel programming operation. The driver panics rather than truncating the transfer.
Solutions
- Split the transfer into chunks of at most 65535 bytes and loop
- Reduce the buffer size to fit under 64 KiB
- Use DMA linked-list mode with multiple items each ≤ 65535 bytes
- Use a non-GPDMA DMA instance with a larger (e.g. 17/32-bit) count register if available
Example fix
// before
let buf = [0u8; 100_000];
usart.read(&mut buf).await?;
// after
let mut buf = [0u8; 100_000];
for chunk in buf.chunks_mut(65_535) {
usart.read(chunk).await?;
} Defensive patterns
Strategy: validation
Validate before calling
fn gpdma_len_ok<T>(buf: &[T]) -> bool { buf.len() * core::mem::size_of::<T>() <= 65_535 } Prevention
- Check buf.len() * size_of::<T>() <= 65535 before every GPDMA transfer
- Chunk large buffers and loop, or use linked-list mode
- Add a debug_assert in transfer wrappers to catch oversized buffers in tests
When it happens
Trigger: Calling read/write with a buffer whose byte length is > 65535 (e.g. a 128 KiB buffer, or 40000 u16 elements = 80000 bytes) on a GPDMA channel.
Common situations: Large ADC sample buffers, big UART/SPI frames, or audio buffers exceeding 64 KiB in a single DMA transfer.
Understand the failure class
Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.
Related errors
- DMA: data transfer error on DMA@
- DMA: user settings error on DMA@
- DMA: link transfer error on DMA@
- memory-to-memory transfers not implemented for GPDMA
- not implemented
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/034f31d7112bfc5c.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/dma/gpdma/mod.rs:653
request: Request,
dir: Dir,
peri_addr: *const u32,
mem_addr: *mut u32,
mem_len: usize,
incr_mem: bool,
data_size: WordSize,
dst_size: WordSize,
options: TransferOptions,
) {
// BNDT is the number of source bytes. For a packing/unpacking transfer
// the memory side dictates how much data the caller wants moved.
let mem_size = match dir {
Dir::MemoryToPeripheral => data_size,
Dir::PeripheralToMemory => dst_size,
Dir::MemoryToMemory => panic!("memory-to-memory transfers not implemented for GPDMA"),
};
let Ok(bndt) = (mem_len * mem_size.bytes()).try_into() else {
panic!("DMA transfers may not be larger than 65535 bytes.");
};
let info = self.info();
let ch = info.dma.ch(info.num);
// "Preceding reads and writes cannot be moved past subsequent writes."
fence(Ordering::SeqCst);
// The reset is effective when the channel is in steady state, meaning one of the following:
// - active channel in suspended state (GPDMA_CxSR.SUSPF = 1 and GPDMA_CxSR.IDLEF = GPDMA_CxCR.EN = 1)
// - channel in disabled state (GPDMA_CxSR.IDLEF = 1 and GPDMA_CxCR.EN = 0).
if ch.cr().read().en() {
ch.cr().modify(|w| w.set_susp(true));
while !ch.sr().read().suspf() {}
}
ch.cr().write(|w| w.set_reset(true));
ch.fcr().write(|w| {View on GitHub (pinned to 463a07b963)