embassy-rs/embassy · error
memory-to-memory transfers not implemented for GPDMA
Error message
memory-to-memory transfers not implemented for GPDMA
What it means
The GPDMA configure routine was asked for a MemoryToMemory transfer, which this GPDMA driver does not implement (unlike the older DMA/BDMA drivers). The driver panics immediately in configure rather than silently misconfiguring the channel.
Solutions
- Perform the copy with the CPU (slice copy_from_slice) instead of DMA
- Use another transport (e.g. a timer-triggered peripheral loopback) if a hardware copy is required
- Check embassy-stm32 for updates; mem-to-mem GPDMA support may be added later
- Use a channel/driver on a non-GPDMA DMA instance if your chip has both
Example fix
// before dma_copy(&src, &dst); // GPDMA mem-to-mem // after dst.copy_from_slice(&src); // CPU copy
Defensive patterns
Strategy: fallback
Validate before calling
let mem_to_mem = matches!(dir, Dir::MemoryToMemory); assert!(!mem_to_mem, "use CPU copy for GPDMA");
Prevention
- Never construct MemoryToMemory transfers on GPDMA-based STM32s
- Check the driver docs per DMA type before porting code across chip families
- Use software copies unless bandwidth demands hardware assist
When it happens
Trigger: Calling a DMA-based API that passes Dir::MemoryToMemory to configure — e.g. manually constructing a Transfer or using an API that internally does memory-to-memory copy — on a chip using GPDMA (H503/H5/U5).
Common situations: Code ported from older STM32 DMA drivers that supported mem-to-mem (e.g. SPI DMA loops or buffer copies) onto H5/U5 boards; attempting a memory copy via DMA as an optimization.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- memory-to-memory transfers are not valid for linked-list…
- DMA: data transfer error on DMA@
- DMA: user settings error on DMA@
- DMA: link transfer error on DMA@
- DMA transfers may not be larger than 65535 bytes.
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/5dfc4f7f8e873e7e.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/dma/gpdma/mod.rs:650
/// This function also causes the channel to reset, which unsuspends (resumes) it.
unsafe fn configure(
&self,
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() {}
}View on GitHub (pinned to 463a07b963)