Direct Memory Access (DMA) is a process of transferring data from one memory location to another without the direct involvement of the processor (CPU). The main benefit of using DMA is more efficient data movement in the embedded system.

Principle of Operation

There are many different types of DMA implementations, some of them for very specific use cases. In this article, we will focus on the general principles of operation. Let’s start with the simple system shown below in Fig.1.

A single bus connecting RAM, CPU and DMA controller.
Fig,1 Simplified DMA block diagram

The functional unit that performs the operations for directly accessing the memory is called a DMA controller. On the simplified block diagram (Fig.1) we have a CPU, a RAM, a peripheral unit, and a DMA controller. All except the peripheral unit are connected on the same bus. As the CPU and the DMA controller must be able to initiate transfers they have master interfaces. Although the goal is to have DMA that operates independently, the CPU is the one that has to configure the DMA controller to perform transfers. The DMA controller can be dedicated to a specific DMA-capable peripheral unit (as shown in Fig. 1) or can be a more general DMA able to access various types of memory-mapped peripherals.

Example: Saving ADC results in RAM using a DMA

Let’s have an ADC peripheral unit that produces a new conversion result every 4 microseconds. The CPU has configured a DMA controller to read this new data and store it in RAM memory. The source address for the transfers is always the ADC data register. The destination address is an address in the RAM memory. This destination address is increased by the DMA controller with each consecutive transfer. The ADC indicates to the DMA that new data is available using a dedicated interface. When the DMA detects that new data is available it proceeds by reading the data register of the ADC. The read data is then stored in the DMA FIFO buffer. The DMA controller checks that the memory bus is not busy and then transfers the data from the FIFO buffer to the destination address in the RAM. This concludes a single DMA transfer.

DMA Interaction With The CPU

As the CPU and the DMA controller use the same bus, there must be some form of handshaking between them. They can’t access the bus simultaneously. The handshaking can be implemented as a dedicated interface between the CPU and the DMA controller or can be part of the bus protocol. The DMA controller contains registers that the CPU must configure. The configuration may include: the source address of the transfer, the destination address of the transfer, the number of bytes to be transferred, interrupt request to the CPU on completion of a transfer, etc.

An important thing to remember is that DMA is not cost-free and it may affect the CPU operation in certain situations. If the CPU is using the memory bus the DMA has to wait. If the DMA starts a transfer, then the CPU has to wait for it to finish if it wants to access the bus. For avoiding these situations some systems are designed with multiple areas of memory (see Fig.2). Each memory area has its own dedicated bus and DMA controller. In that scenario, the CPU may be accessing one area of the memory, while a DMA controller is accessing at the same time another area. Bus bridges and interconnects are used for connecting all subsystems and forming a single memory space.

An embedded system containing three DMA controllers. Two of them with separate memory buses.
Fig.2 Simplified block diagram of an embedded system with two DMA subsystems

Type of Transfers

The most common configuration in modern microcontrollers is the use of a single memory address space, where all types of memories (Code Flash, RAM, Data flash, etc.) and peripheral units are mapped into the same address space. For the DMA controller, all transfers are memory-to-memory. For us as developers however, by knowing what functionality is behind each memory address we can use the DMA for the following type of transfers:

  • memory to peripheral unit and vice versa
  • memory to memory
  • peripheral unit to peripheral unit

Each DMA controller has FIFO buffers. They are used in case a busy resource is preventing the transfer from completing. Using FIFO allows the DMA controller to perform two-step transfers:

  1. Read access – data is transferred from the source address to the DMA FIFO
  2. Write access – data is transferred from the DMA FIFO to the destination address
Fig.3 Two-step DMA transfer

Why Use DMA?

DMA is used for moving data from one address of the memory to another. When used properly it can improve the efficiency of an embedded system. The CPU can be more focused on performing calculations, without having to waste too many instruction cycles for transferring data. This can result in improving the speed of our program.

Another benefit can be the reduction of power consumption. The two common ways of transferring data without the use of DMA are:

  • based on interrupts – interrupt is generated when a new data is available and CPU has to transfer it
  • polling – the CPU waits for a new data to become available and then transfers it

Both methods require the CPU to be awake. In contrast, some DMA controllers can perform data transfers while the CPU is in sleep mode (low-power mode).

Was this article helpful?