{"record":{"id":"5dfc4f7f8e873e7e","repo":"embassy-rs/embassy","slug":"memory-to-memory-transfers-not-implemented-for-gpd","errorCode":null,"errorMessage":"memory-to-memory transfers not implemented for GPDMA","messagePattern":"memory-to-memory transfers not implemented for GPDMA","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/dma/gpdma/mod.rs","lineNumber":650,"sourceCode":"    /// This function also causes the channel to reset, which unsuspends (resumes) it.\n    unsafe fn configure(\n        &self,\n        request: Request,\n        dir: Dir,\n        peri_addr: *const u32,\n        mem_addr: *mut u32,\n        mem_len: usize,\n        incr_mem: bool,\n        data_size: WordSize,\n        dst_size: WordSize,\n        options: TransferOptions,\n    ) {\n        // BNDT is the number of source bytes. For a packing/unpacking transfer\n        // the memory side dictates how much data the caller wants moved.\n        let mem_size = match dir {\n            Dir::MemoryToPeripheral => data_size,\n            Dir::PeripheralToMemory => dst_size,\n            Dir::MemoryToMemory => panic!(\"memory-to-memory transfers not implemented for GPDMA\"),\n        };\n        let Ok(bndt) = (mem_len * mem_size.bytes()).try_into() else {\n            panic!(\"DMA transfers may not be larger than 65535 bytes.\");\n        };\n\n        let info = self.info();\n        let ch = info.dma.ch(info.num);\n\n        // \"Preceding reads and writes cannot be moved past subsequent writes.\"\n        fence(Ordering::SeqCst);\n\n        // The reset is effective when the channel is in steady state, meaning one of the following:\n        // - active channel in suspended state (GPDMA_CxSR.SUSPF = 1 and GPDMA_CxSR.IDLEF = GPDMA_CxCR.EN = 1)\n        // - channel in disabled state (GPDMA_CxSR.IDLEF = 1 and GPDMA_CxCR.EN = 0).\n        if ch.cr().read().en() {\n            ch.cr().modify(|w| w.set_susp(true));\n            while !ch.sr().read().suspf() {}\n        }","sourceCodeStart":632,"sourceCodeEnd":668,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/dma/gpdma/mod.rs#L632-L668","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\ndma_copy(&src, &dst); // GPDMA mem-to-mem\n// after\ndst.copy_from_slice(&src); // CPU copy","handlingStrategy":"fallback","validationCode":"let mem_to_mem = matches!(dir, Dir::MemoryToMemory);\nassert!(!mem_to_mem, \"use CPU copy for GPDMA\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["dma","embedded","stm32","unsupported-operation","memory-to-memory"],"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"}