-
Notifications
You must be signed in to change notification settings - Fork 4
DMA
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.
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)