Introduction to direct memory access
Implementing direct memory access is straightforward, once you know how it works and how to configure your DMA controller. Here's a primer on this most efficient means of moving data around in a system.
Direct memory access (DMA) is a means of having a peripheral device control a processor's memory bus directly. DMA permits the peripheral, such as a UART, to transfer data directly to or from memory without having each byte (or word) handled by the processor. Thus DMA enables more efficient use of interrupts, increases data throughput, and potentially reduces hardware costs by eliminating the need for peripheral-specific FIFO buffers.
In a typical DMA transfer, some event (such as an incoming data-available signal from a UART) notifies a separate device called the DMA controller that data needs to be transferred to memory. The DMA controller then asserts a DMA request signal to the CPU, asking its permission to use the bus. The CPU completes its current bus activity, stops driving the bus, and returns a DMA acknowledge signal to the DMA controller. The DMA controller then reads and writes one or more memory bytes, driving the address, data, and control signals as if it were itself the CPU. (The CPU's address, data, and control outputs are tristated while the DMA controller has control of the bus.) When the transfer is complete, the DMA controller stops driving the bus and deasserts the DMA request signal. The CPU can then remove its DMA acknowledge signal and resume control of the bus.
Each DMA cycle will typically result in at least two bus cycles: either a peripheral read followed by a memory write or a memory read followed by a peripheral write, depending on the transfer base addresses. The DMA controller itself does no processing on this data. It just transfers the bytes as instructed in its configuration registers.
It's possible to do a flyby transfer that performs the read and write in a single bus cycle. However, though supported on the ISA bus and its embedded cousin PC/104, flyby transfers are not typical.
Processors that support DMA provide one or more input signals that the bus requester can assert to gain control of the bus and one or more output signals that the processor asserts to indicate it has relinquished the bus. A typical output signal might be named HLDA (short for HoLD Acknowledge).
When designing with DMA, address buffers must be disabled during DMA so the bus requester can drive them without bus contention. To avoid bus contention, the bus buffer used by the DMA device must not drive the address bus until after HLDA goes active to indicate that the CPU has stopped driving the bus signals, and it must stop driving the bus before the CPU drives HLDA inactive. The system design may also need pullup resistors or terminators on control signals (such as read and write strobes) so the control signals don't float to the active state during the brief period when neither the processor nor the DMA controller is driving them.
DMA controllers require initialization by software. Typical setup parameters include the base address of the source area, the base address of the destination area, the length of the block, and whether the DMA controller should generate a processor interrupt once the block transfer is complete.
It's typically possible to have the DMA controller automatically increment one or both addresses after each byte (word) transfer, so that the next transfer will be from the next memory location. Transfers between peripherals and memory often require that the peripheral address not be incremented after each transfer. When the address is not incremented, each data byte will be transferred to or from the same memory location.
DMA or burst
DMA operations can be performed in either burst or single-cycle mode. Some DMA controllers support both. In burst mode, the DMA controller keeps control of the bus until all the data buffered by the requesting device has been transferred to memory (or when the output device buffer is full, if writing to a peripheral).
In single-cycle mode, the DMA controller gives up the bus after each transfer. This minimizes the amount of time that the DMA controller keeps the processor off of the memory bus, but it requires that the bus request/acknowledge sequence be performed for every transfer. This overhead can result in a drop in overall system throughput if a lot of data needs to be transferred.
In most designs, you would use single cycle mode if your system cannot tolerate more than a few cycles of added interrupt latency. Likewise, if the peripheral devices can buffer very large amounts of data, causing the DMA controller to tie up the bus for an excessive amount of time, single-cycle mode is preferable.
Note that some DMA controllers have larger address registers than length registers. For instance, a DMA controller with a 32-bit address register and a 16-bit length register can access a 4GB memory space, but can only transfer 64KB per block. If your application requires DMA transfers of larger amounts of data, software intervention is required after each block.
Get on the bus
The simplest way to use DMA is to select a processor with an internal DMA controller. This eliminates the need for external bus buffers and ensures that the timing is handled correctly. Also, an internal DMA controller can transfer data to on-chip memory and peripherals, which is something that an external DMA controller cannot do. Because the handshake is handled on-chip, the overhead of entering and exiting DMA mode is often much faster than when an external controller is used.
If an external DMA controller or processor is used, be sure that the hardware handles the transition between transfers correctly. To avoid the problem of bus contention, ensure that bus requests are inhibited if the bus is not free. This prevents the DMA controller from requesting the bus before the processor has reacquired it after a transfer.
So you see, DMA is not as mysterious as it sometimes seems. DMA transfers can provide real advantages when the system is properly designed.
Figure 1: A DMA controller shares the processor's memory bus
Stuart Ball is an electrical engineer with over 20 years of experience in embedded systems. He is the author of three books and numerous articles about embedded systems and is currently employed by Seagate Technologies. His e-mail address is firstname.lastname@example.org.