{"record":{"id":"034f31d7112bfc5c","repo":"embassy-rs/embassy","slug":"dma-transfers-may-not-be-larger-than-65535-bytes-034f31","errorCode":null,"errorMessage":"DMA transfers may not be larger than 65535 bytes.","messagePattern":"DMA transfers may not be larger than 65535 bytes\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/dma/gpdma/mod.rs","lineNumber":653,"sourceCode":"        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        }\n        ch.cr().write(|w| w.set_reset(true));\n\n        ch.fcr().write(|w| {","sourceCodeStart":635,"sourceCodeEnd":671,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/dma/gpdma/mod.rs#L635-L671","documentation":"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.","triggerScenarios":"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.","commonSituations":"Large ADC sample buffers, big UART/SPI frames, or audio buffers exceeding 64 KiB in a single DMA 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"],"exampleFix":"// before\nlet buf = [0u8; 100_000];\nusart.read(&mut buf).await?;\n// after\nlet mut buf = [0u8; 100_000];\nfor chunk in buf.chunks_mut(65_535) {\n    usart.read(chunk).await?;\n}","handlingStrategy":"validation","validationCode":"fn gpdma_len_ok<T>(buf: &[T]) -> bool { buf.len() * core::mem::size_of::<T>() <= 65_535 }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["dma","embedded","stm32","size-limit","buffer"],"backgroundTag":"file-size-limit-exceeded","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"}