{"record":{"id":"6932a34a99c985db","repo":"embassy-rs/embassy","slug":"dma-link-transfer-error-on-dma-08x-channel","errorCode":null,"errorMessage":"DMA: link transfer error on DMA@{:08x} channel {}","messagePattern":"DMA: link transfer error on DMA@(.+?) channel (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"embassy-stm32/src/dma/gpdma/mod.rs","lineNumber":576,"sourceCode":"    let ch = info.dma.ch(info.num);\n    let sr = ch.sr().read();\n\n    if sr.dtef() {\n        panic!(\n            \"DMA: data transfer error on DMA@{:08x} channel {}\",\n            info.dma.cast().as_ptr() as u32,\n            info.num\n        );\n    }\n    if sr.usef() {\n        panic!(\n            \"DMA: user settings error on DMA@{:08x} channel {}\",\n            info.dma.cast().as_ptr() as u32,\n            info.num\n        );\n    }\n    if sr.ulef() {\n        panic!(\n            \"DMA: link transfer error on DMA@{:08x} channel {}\",\n            info.dma.cast().as_ptr() as u32,\n            info.num\n        );\n    }\n\n    if sr.htf() {\n        ch.fcr().write(|w| w.set_htf(true));\n    }\n\n    if sr.tcf() {\n        ch.fcr().write(|w| w.set_tcf(true));\n\n        let lli_count = state.lli_state.count.load(Ordering::Acquire);\n        let complete = if lli_count > 0 {\n            let next_lli_index = state.lli_state.index.load(Ordering::Acquire) + 1;\n            let complete = next_lli_index >= lli_count;\n","sourceCodeStart":558,"sourceCodeEnd":594,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/dma/gpdma/mod.rs#L558-L594","documentation":"The GPDMA channel IRQ handler found the link transfer error flag (ULEF) set: an error occurred while fetching or executing a linked-list item (LLI). The linked-list descriptor address was invalid or the LLI itself was corrupted/unreachable. The driver panics because linked-list state can no longer be trusted.","triggerScenarios":"Using linked-list mode (DMA linked-list/ring APIs) where an LLI points to invalid memory, an unaligned descriptor, or a descriptor in DMA-inaccessible memory; LLI struct modified while the channel runs.","commonSituations":"Building custom linked-list item chains with embassy's gpdma linked-list API and placing items in flash or DTCM; forgetting to keep LLiState items alive (dropped stack descriptors).","solutions":["Place linked-list items in DMA-accessible, writable RAM (not flash/DTCM)","Ensure LLI descriptors have required alignment and outlive the transfer","Verify each LLI's next-address field (la/pa) points to a valid item or terminates correctly","Update embassy-stm32 if using the linked-list API, as this area is under active development"],"exampleFix":"// before\nfn build(x: &[u8]) -> Transfer { let lli = LLi::new(...); Transfer::new(lli) } // lli dropped\n// after\nstatic mut LLI: LLiState = LLiState::new(); // keep descriptor alive in RAM\nfn build(x: &[u8]) -> Transfer { Transfer::new(unsafe { &mut LLI }) }","handlingStrategy":"validation","validationCode":"fn lli_valid(lli_addr: u32, item_size: usize) -> bool {\n    lli_addr != 0 && lli_addr % core::mem::align_of::<LLiState>() as u32 == 0\n        // must be in DMA-reachable RAM, e.g. SRAM region\n        && (0x2000_0000..0x2004_0000).contains(&lli_addr)\n        && core::mem::size_of::<LLiState>() == item_size\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep linked-list items in static, DMA-reachable RAM for the transfer's lifetime","Never drop or move LLi descriptors while the channel is running","Ensure LLI next-pointer fields point to valid, aligned items or terminate properly","Use the latest embassy-stm32; the linked-list API is still evolving"],"tags":["dma","embedded","stm32","linked-list","panic"],"backgroundTag":"dma-bus-error","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"}