{"record":{"id":"ce8dc8ae3fdfac76","repo":"embassy-rs/embassy","slug":"memory-to-memory-transfers-are-not-valid-for-linke","errorCode":null,"errorMessage":"memory-to-memory transfers are not valid for linked-list items","messagePattern":"memory-to-memory transfers are not valid for linked-list items","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/dma/gpdma/linked_list.rs","lineNumber":143,"sourceCode":"            panic!(\"DMA transfers may not be larger than 65535 bytes.\");\n        };\n\n        let mut br1 = regs::ChBr1(0);\n        br1.set_bndt(bndt);\n\n        let mut tr1 = regs::ChTr1(0);\n        tr1.set_sdw(data_size.into());\n        tr1.set_ddw(dst_size.into());\n        tr1.set_sinc(dir == Dir::MemoryToPeripheral && incr_mem);\n        tr1.set_dinc(dir == Dir::PeripheralToMemory && incr_mem);\n\n        #[cfg(gpdma)]\n        {\n            use stm32_metapac::gpdma::vals::Ap;\n            tr1.set_sap(match dir {\n                Dir::MemoryToPeripheral => Ap::Port0,\n                Dir::PeripheralToMemory => Ap::Port1,\n                Dir::MemoryToMemory => panic!(\"memory-to-memory transfers are not valid for linked-list items\"),\n            });\n            tr1.set_dap(match dir {\n                Dir::MemoryToPeripheral => Ap::Port1,\n                Dir::PeripheralToMemory => Ap::Port0,\n                Dir::MemoryToMemory => panic!(\"memory-to-memory transfers are not valid for linked-list items\"),\n            });\n        }\n\n        let mut tr2 = regs::ChTr2(0);\n        tr2.set_dreq(match dir {\n            Dir::MemoryToPeripheral => Dreq::DestinationPeripheral,\n            Dir::PeripheralToMemory => Dreq::SourcePeripheral,\n            Dir::MemoryToMemory => panic!(\"memory-to-memory transfers are not valid for linked-list items\"),\n        });\n        tr2.set_reqsel(request);\n\n        let (sar, dar) = match dir {\n            Dir::MemoryToPeripheral => (mem_addr as _, peri_addr as _),","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/dma/gpdma/linked_list.rs#L125-L161","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet item = LinearItem::new_read(request, src as *const u32, dst, Dir::MemoryToMemory);\n// after\nuse core::ptr::copy_nonoverlapping;\nunsafe { copy_nonoverlapping(src as *const u32, dst, len); } // CPU copy, no GPDMA item needed","handlingStrategy":"validation","validationCode":"use embassy_stm32::dma::Dir;\nfn assert_gpdma_item_dir(dir: Dir) {\n    assert!(matches!(dir, Dir::MemoryToPeripheral | Dir::PeripheralToMemory),\n        \"GPDMA linked-list items cannot be memory-to-memory\");\n}","typeGuard":"fn is_peripheral_dir(dir: Dir) -> bool {\n    matches!(dir, Dir::MemoryToPeripheral | Dir::PeripheralToMemory)\n}","tryCatchPattern":"// panics are not catchable; gate the call:\nif dir == Dir::MemoryToMemory {\n    return Err(NotSupported::Mem2MemGpdmaLinkedList);\n}\nlet item = LinearItem::new_read(request, peri, buf);","preventionTips":["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"],"tags":["dma","gpdma","panic","linked-list","memory-to-memory","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}