embassy-rs/embassy · error
memory-to-memory transfers are not valid for linked-list…
Error message
memory-to-memory transfers are not valid for linked-list items
What it means
GPDMA linked-list items in embassy-stm32 require at least one port to be a peripheral because the item is configured with a request (reqsel) and peripheral port assignment. MemoryToMemory direction has no peripheral request, so Item::new panics when mapping Dir::MemoryToMemory to a source port (AP).
Solutions
- Use a memory-to-memory-capable DMA type (classic MDMA or DMA/BDMA channel) instead of a GPDMA linked-list item.
- Perform the copy with the CPU (core::ptr::copy_nonoverlapping or slice copy_from_slice) if no DMA is strictly required.
- Use MDMA, which explicitly supports MemoryToMemory (with increment configured), for the memory copy.
- Restructure the transfer so the data flows through a peripheral (e.g. SPI in loopback) if GPDMA linked lists are mandatory.
Example fix
// before
let item = LinearItem::new_read(request, src as *const u32, dst, Dir::MemoryToMemory);
// after
use core::ptr::copy_nonoverlapping;
unsafe { copy_nonoverlapping(src as *const u32, dst, len); } // CPU copy, no GPDMA item needed Defensive patterns
Strategy: validation
Validate before calling
use embassy_stm32::dma::Dir;
fn assert_gpdma_item_dir(dir: Dir) {
assert!(matches!(dir, Dir::MemoryToPeripheral | Dir::PeripheralToMemory),
"GPDMA linked-list items cannot be memory-to-memory");
} Type guard
fn is_peripheral_dir(dir: Dir) -> bool {
matches!(dir, Dir::MemoryToPeripheral | Dir::PeripheralToMemory)
} Try / catch
// panics are not catchable; gate the call:
if dir == Dir::MemoryToMemory {
return Err(NotSupported::Mem2MemGpdmaLinkedList);
}
let item = LinearItem::new_read(request, peri, buf); Prevention
- Never pass Dir::MemoryToMemory to GPDMA linked-list constructors
- Route memory-to-memory copies through MDMA or CPU copies
- Validate direction at API boundaries before constructing linked-list items
- Check chip family capabilities when porting classic-DMA code to GPDMA parts
When it happens
Trigger: Constructing a LinearItem/TwoDItem (or calling Item::new) with dir = Dir::MemoryToMemory on a GPDMA channel — e.g. requesting a memory-to-memory copy as a linked-list item via new_read/new_write-style item constructors with MemoryToMemory direction.
Common situations: Porting memory-to-memory DMA code that worked on classic DMA/BDMA (where Mem2Mem is supported) to a GPDMA part (STM32 H5/U5/H7RS); building a linked list to perform an internal buffer copy; passing a generic dir parameter that is MemoryToMemory at runtime.
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
- DMA transfers may not be larger than 65535 bytes.
- DMA: link transfer error on DMA@
- memory-to-memory transfers not implemented for GPDMA
- DMA data error
- DMA: error on DMA_0 channel
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/ce8dc8ae3fdfac76.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/dma/gpdma/linked_list.rs:143
panic!("DMA transfers may not be larger than 65535 bytes.");
};
let mut br1 = regs::ChBr1(0);
br1.set_bndt(bndt);
let mut tr1 = regs::ChTr1(0);
tr1.set_sdw(data_size.into());
tr1.set_ddw(dst_size.into());
tr1.set_sinc(dir == Dir::MemoryToPeripheral && incr_mem);
tr1.set_dinc(dir == Dir::PeripheralToMemory && incr_mem);
#[cfg(gpdma)]
{
use stm32_metapac::gpdma::vals::Ap;
tr1.set_sap(match dir {
Dir::MemoryToPeripheral => Ap::Port0,
Dir::PeripheralToMemory => Ap::Port1,
Dir::MemoryToMemory => panic!("memory-to-memory transfers are not valid for linked-list items"),
});
tr1.set_dap(match dir {
Dir::MemoryToPeripheral => Ap::Port1,
Dir::PeripheralToMemory => Ap::Port0,
Dir::MemoryToMemory => panic!("memory-to-memory transfers are not valid for linked-list items"),
});
}
let mut tr2 = regs::ChTr2(0);
tr2.set_dreq(match dir {
Dir::MemoryToPeripheral => Dreq::DestinationPeripheral,
Dir::PeripheralToMemory => Dreq::SourcePeripheral,
Dir::MemoryToMemory => panic!("memory-to-memory transfers are not valid for linked-list items"),
});
tr2.set_reqsel(request);
let (sar, dar) = match dir {
Dir::MemoryToPeripheral => (mem_addr as _, peri_addr as _),View on GitHub (pinned to 463a07b963)