DMA
micro/dma provides direct memory access for high-throughput data transfers without CPU involvement.
DMA lets you transfer data between peripherals and memory (or between memory regions) while the CPU does other work.
Basic Usage
use micro/dma
if let Some(mut ch) = dma.channel(0) {
let src: [u8; 256] = [0xAA; 256]
let mut dst: [u8; 256] = [0; 256]
ch.mem_to_mem(src, dst)?
ch.wait()? // block until transfer completes
}
Getting a Channel
DMA channels are optional; the hardware may have a fixed number, and some may already be in use:
if let Some(mut ch) = dma.channel(0) {
// use channel
} else {
// no channel 0 available; fall back to CPU transfer
}
On RP2040, there are 12 DMA channels (0-11).
Transfer Types
// Memory to memory
ch.mem_to_mem(src, dst)?
// Peripheral to memory (e.g., SPI RX FIFO to buffer)
ch.periph_to_mem(periph_dreq, dst)?
// Memory to peripheral (e.g., buffer to SPI TX FIFO)
ch.mem_to_periph(src, periph_dreq)?
Waiting for Completion
ch.start_transfer()? // start and return immediately
// ... CPU does other work ...
ch.wait()? // block until complete
Or chain transfers for continuous operation.
Capability Check
use board/pico
let caps = pico.capabilities()
if caps.dma_channels > 0 {
// DMA is available
}
Do and Don’t
// Do: check channel availability with if let Some
if let Some(mut ch) = dma.channel(0) {
ch.mem_to_mem(src, dst)?
}
// Do: use ch.wait() before accessing the destination buffer
ch.start_transfer()?
do_other_work()
ch.wait()? // ensure completion before reading dst
// Avoid: accessing the destination buffer while DMA is still running
// This is a race condition that produces corrupted data
// Avoid: using DMA for very small transfers (< ~32 bytes)
// CPU overhead of setup often exceeds the transfer time