Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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