Skip to content
Scott James Remnant edited this page Dec 27, 2016 · 1 revision

The DMA Engine is perhaps one of the most daunting pieces of hardware in the Raspberry Pi, perhaps due to how powerful it is, while at the same time seeming to operate on difficult to explain black magic. This is a shame, because by learning to use it, we can offload a lot of work to the hardware, improving performance and even reliability of our control of peripherals.

DMA Channels

Control Blocks

The DMA Engine has one job: it processes instructions to read a certain length of memory from one address, and to write it to another.

I like to think of it like the forklift operator in a warehouse, with a clipboard of instructions to follow. Each instruction says where to collect a box, how many to collect, and where to place them afterwards.

For DMA, these instructions are called Control Blocks. The datasheet gives the layout of the control block data structure on p40, and we can see that the three most important fields are Source Address, Destination Address, and Transfer Length.

We can define a Swift struct to represent a Control Block:

struct DMAControlBlock {
    var transferInformation: Int
    var sourceAddress: Int
    var destinationAddress: Int
    var transferLength: Int
    var stride: Int
    var nextControlBlockAddress: Int
    var reserved0: Int = 0
    var reserved1: Int = 0
}

This makes it easy to create a single instruction to copy one word of memory (4 bytes, 32-bits) between two addresses, we simply set the unused fields, including the Next Control Block Address to zero.

let cb = DMAControlBlock(
    transferInformation: 0,
    sourceAddress: dataBusAddress,
    destinationAddress: emptyBusAddress,
    transferLength: MemoryLayout<Int>.size,
    stride: 0,
    nextControlBlockAddress: 0)

Types of Memory

Clone this wiki locally