{"record":{"id":"bde9e98477bd604b","repo":"embassy-rs/embassy","slug":"dma-error-on-dma-08x-channel","errorCode":null,"errorMessage":"DMA: error on DMA@{:08x} channel {}","messagePattern":"DMA: error on DMA@(.+?) channel (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"embassy-stm32/src/dma/dma_bdma.rs","lineNumber":26,"sourceCode":"use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer};\nuse super::word::{Word, WordSize};\nuse super::{Channel, Dir, Increment, Request, STATE, info};\nuse crate::_generated::DmaChannel;\nuse crate::interrupt::typelevel::Interrupt;\nuse crate::rcc::WakeGuard;\nuse crate::{interrupt, pac};\n\npub(crate) unsafe fn on_irq(channel: DmaChannel) {\n    let info = info(channel);\n    let state = &STATE[channel as usize];\n    match info.dma {\n        #[cfg(dma)]\n        DmaInfo::Dma(r) => {\n            let cr = r.st(info.num).cr();\n            let isr = r.isr(info.num / 4).read();\n\n            if isr.teif(info.num % 4) {\n                panic!(\"DMA: error on DMA@{:08x} channel {}\", r.as_ptr() as u32, info.num);\n            }\n\n            let mut activity = false;\n            if isr.htif(info.num % 4) && cr.read().htie() {\n                // Acknowledge half transfer complete interrupt\n                r.ifcr(info.num / 4).write(|w| w.set_htif(info.num % 4, true));\n                activity = true;\n            }\n            if isr.tcif(info.num % 4) && cr.read().tcie() {\n                // Acknowledge transfer complete interrupt\n                r.ifcr(info.num / 4).write(|w| w.set_tcif(info.num % 4, true));\n                state.complete_count.fetch_add(1, Ordering::Release);\n                activity = true;\n            }\n            if !activity {\n                return;\n            }\n            state.waker.wake();","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/dma/dma_bdma.rs#L8-L44","documentation":"The DMA (direct memory access) interrupt handler for classic STM32 DMA controllers panics when the transfer-error flag (TEIF) is set for the channel being serviced. A transfer error means the hardware could not complete the memory/peripheral access (bad address, bus fault, unsupported alignment/size), so the driver stops with a panic naming the DMA instance base address and channel number.","triggerScenarios":"A DMA transfer completes with isr.teif(info.num % 4) set when on_irq runs — e.g. invalid source/destination address, misaligned buffer, or peripheral FIFO error during an active DMA channel transfer.","commonSituations":"Passing a slice in flash/CCM RAM not accessible by DMA; buffer not aligned to the transfer size; writing to a peripheral register with wrong word size; stack-allocated buffer moved/freed while transfer in flight; wrong DMA channel/mux routing configuration.","solutions":["Check the buffer address/alignment: DMA targets must be in DMA-accessible RAM (not flash for writes, not CCMRAM on many chips) and aligned to the access size.","Ensure the source/destination pointer and data width configuration match (e.g. u16 slice with 16-bit transfer).","Verify the peripheral is enabled/clocked and the request multiplexer (DMAMUX) routes the correct request to the channel.","Keep the buffer alive for the whole transfer (e.g. await the future or use a 'static/owned buffer)."],"exampleFix":"// before\nlet buf = [0u8; 16]; // stack, may be invalid after return\nuart.write_dma(&buf).await;\n\n// after\nstatic BUF: [u8; 16] = [0u8; 16]; // DMA-accessible, alive during transfer\nuart.write_dma(&BUF).await;","handlingStrategy":"validation","validationCode":"// Before starting a DMA transfer:\nlet addr = buf.as_ptr() as u32;\nassert!(addr % core::mem::size_of::<T>() == 0, \"DMA buffer misaligned\");\n// and ensure buf lives in DMA-accessible RAM (not flash/CCM for writes).","typeGuard":"fn dma_accessible<T>(buf: &[T]) -> bool {\n    let addr = buf.as_ptr() as u32;\n    // SRAM range example; adjust per chip\n    (0x2000_0000..0x2005_0000).contains(&addr)\n}","tryCatchPattern":"// This is a hard panic in an IRQ handler; it cannot be caught.\n// Guard instead: validate address and lifetime before write_dma/read_dma.\nassert!(dma_accessible(&buf), \"buffer not DMA accessible\");","preventionTips":["Use static or long-lived buffers (linked into DMA-capable RAM) for DMA transfers.","Keep buffers aligned to the transfer word size.","Never move, free, or reuse a buffer while a transfer is in flight; await the transfer future.","Check the chip reference manual for which RAM regions each DMA controller can address."],"tags":["embedded","dma","panic","interrupt","hardware-error"],"backgroundTag":"invalid-config-value","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"}