Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 77

DMA for Memory-to-Peripheral Transfers: Alignment & Cache Coherency

Recommended resources

Hello! Welcome to the next lesson in our embedded interview bootcamp.

In our previous session, we mapped out the internal data highways of a System-on-Chip (SoC), exploring how AXI, AHB, and APB buses connect everything from high-speed CPU cores to low-speed peripherals. Today, we'll put that knowledge to practical use by mastering one of the most critical bus masters in any SoC: the Direct Memory Access (DMA) controller.

Understanding DMA isn't just about knowing it moves data. For the roles you're targeting, you need to demonstrate deep knowledge of its configuration, its interaction with the memory subsystem, and how to manage the complex system-level issues that arise, especially cache coherency.

Your learning outcome for this lesson is to: Configure a DMA controller for memory-to-peripheral transfers, ensuring correct data alignment and cache coherency management.


1. From CPU-Bound to CPU-Free: The Role of DMA

Imagine you need to send a large image buffer from memory to a display controller. Without DMA, the CPU would have to execute a loop, reading a word from memory and writing it to the display peripheral, over and over. This is called Programmed I/O (PIO). While the CPU is busy acting as a glorified data pump, it can't perform its primary job: processing and computation.

A DMA controller is a specialized hardware block designed to solve this problem. It's a secondary bus master that, once configured by the CPU, can take over the task of moving data directly between memory and peripherals, freeing the CPU to handle other work.

This first video provides an excellent summary of why PIO is inefficient and how DMA solves the problem.

Introduction to Direct Memory Access (DMA)

To start, let's watch this introduction from Vipin Kizheppatt, which clearly contrasts Programmed I/O with Direct Memory Access and explains the fundamental performance benefits.

Please watch from the beginning to 04:32. Pay close attention to the explanation of PIO's drawbacks and how DMA alleviates the CPU's burden, enabling parallel processing.

The key takeaway is that DMA provides a massive performance boost by enabling the CPU and data transfers to run in parallel. This is essential in any high-throughput system.



2. DMA Architecture and Configuration

A DMA controller is a slave to the CPU for configuration but a master on the system bus for data transfer. Here's the typical operational flow:

  1. CPU Configures DMA: The CPU writes the parameters for the transfer (source, destination, size, etc.) to the DMA controller's registers.
  2. DMA Takes Over: The CPU starts the DMA transfer and can immediately switch to another task. The DMA controller now requests control of the system bus (e.g., AXI or AHB) via an arbiter.
  3. DMA Performs Transfer: Once it becomes the bus master, the DMA controller reads data from the source and writes it to the destination.
  4. DMA Signals Completion: When the transfer is finished, the DMA controller notifies the CPU, typically by asserting an interrupt.
System-on-Chip (SoC) Architecture with Cortex-M7 and Bus Matrix
This SoC block diagram shows how DMA controllers (HPDMA1, GPDMA1) act as masters on the bus fabric (GPV), alongside the CPU core. They have direct access to memory and peripherals, embodying the principles we are discussing.

The configuration data for a single DMA transfer is stored in a structure called a Transfer Control Descriptor (TCD). Mastering the TCD is the key to configuring a DMA. While specific register names vary between manufacturers, the concepts are universal.

The following document provides a detailed, generic look at the fields inside a TCD. It's dense but contains the precise details interviewers at semiconductor companies expect you to know.

[PDF] Examples of Setting the DMA Controller on the Power Architecture ...

This NXP application note, 'Examples of Setting the DMA Controller', offers a detailed breakdown of a typical TCD structure. We will focus on the description of the TCD fields.

Please read Section 2.2, 'Transfer Control Descriptor (TCD)' (pages 8-15). Don't worry about memorizing every bit field. Instead, focus on understanding the purpose of these key parameters: Source/Destination Address (saddr, daddr) Source/Destination Size (ssize, dsize) Source/Destination Offset (soff, doff) Minor Byte Count (nbytes) Major Iteration Count (biter, citer) Control/Status bits (start, done, int_maj) Scatter/Gather control (e_sg, dlast_sga) - we will cover this next.

The Importance of Data Alignment

Notice the ssize and dsize fields. These define the size of each read/write access on the bus (e.g., 8, 16, 32 bits). For optimal performance, the source and destination addresses (saddr, daddr) should be naturally aligned to the transfer size.

For instance, if you configure a 32-bit (dsize=4 bytes) transfer, the daddr should be a multiple of 4. A misaligned access can lead to:

  • Performance Penalty: The bus interface might have to perform two separate reads to fetch one misaligned word.
  • Hardware Faults: Some architectures will throw a bus fault exception on unaligned accesses.

Interview Question: "You've configured a DMA to transfer an array of uint32_t from memory to a peripheral, but you're seeing poor performance or bus faults. What's a likely cause?"
Your Answer: "A likely cause is a misaligned source or destination address. If the DMA is configured for 32-bit transfers, but the source buffer address is not 4-byte aligned, the DMA controller may be generating extra, inefficient bus cycles or even triggering alignment faults, depending on the architecture. Ensuring the buffers are naturally aligned, often using __attribute__((aligned(X))) or a similar compiler extension, is critical."



3. Advanced Transfers: Scatter-Gather DMA

What if your data isn't in one contiguous block of memory? For example, a network packet might be stored in several smaller, linked buffers. Without scatter-gather, the CPU would have to configure and start a new DMA transfer for each buffer segment.

Scatter-Gather DMA automates this. Instead of holding data, the DMA reads a linked-list of TCDs from memory. Each TCD describes a segment of the transfer.

  • Scatter (Memory-to-Peripheral): The DMA "scatters" data from multiple non-contiguous memory locations to a single peripheral.
  • Gather (Peripheral-to-Memory): The DMA "gathers" data from a peripheral into multiple non-contiguous memory buffers.

This mechanism dramatically reduces CPU overhead for complex data structures. The dlast_sga field you saw in the TCD PDF is the "next TCD" pointer that makes this linked-list mechanism possible.

The following video explains this powerful concept clearly, contrasting a CPU-intensive approach with the automated scatter-gather method.

AXI Multi-Channel DMA (with Scatter-Gather) and Linux kernel level driver development for it

This video by Mohammad S. Sadri explains the concept of scatter-gather DMA in the context of handling multiple data streams.

Watch the two segments: The 'CPU Intensive' Method (00:55 - 06:46): Understand how the CPU must intervene for every single transfer in a simple DMA setup. The Scatter-Gather Solution (08:25 - 12:05): Focus on how the DMA uses descriptors (our TCDs) to find the source and destination for each transfer automatically, removing the CPU from the loop. Notice the significant reduction in CPU interrupts and involvement.



4. The Critical Challenge: Cache Coherency

We've established that the CPU and DMA are two separate masters accessing the same memory. This creates a classic and critical problem in system design: cache coherency.

Consider this memory-to-peripheral scenario:

  1. The CPU prepares a data buffer to be sent to a peripheral (e.g., an Ethernet packet).
  2. As the CPU writes to the buffer, that memory region is loaded into the CPU's high-speed data cache. In a write-back cache, the updated data exists only in the cache; the main memory (DDR) is now stale.
  3. The CPU configures the DMA to transmit the buffer from its main memory address.
  4. The DMA, a separate hardware master, reads directly from main memory. It reads the stale data, not the latest version sitting in the CPU's cache. The wrong data is sent to the peripheral.

This is a cache coherency problem. The system's view of memory is inconsistent.

DMA Cache Coherency Sequence Diagram
This sequence diagram clearly illustrates the coherency problem. During the 'DMA Produce' phase (here, writing to memory), the memory controller must first check the CPU cache. If the data is dirty in the cache, it must be written back to main memory before the DMA's own operation can proceed correctly.

How do we solve this? There are two main approaches.

A. Software-Enforced Coherency

The CPU software can manually manage the cache.

  • Before a DMA Read from Memory (Mem-to-Periph): The CPU must execute a cache clean (or flush) operation on the memory range of the buffer. This forces any "dirty" lines in the data cache to be written back to main memory, ensuring the DMA reads the correct data.
  • After a DMA Write to Memory (Periph-to-Mem): The CPU must execute a cache invalidate operation. This tells the cache that its copies of the data are stale and must be re-fetched from main memory on the next access.

This approach is explicit and gives the programmer full control, but it is cumbersome, error-prone, and adds software overhead.

B. Hardware-Enforced Coherency (Snooping)

Modern SoCs solve this in hardware. The cache controller "snoops" the system bus for accesses from other masters like the DMA.

When the cache controller sees the DMA attempting to read a memory address:

  1. It checks if it has a dirty copy of that data in its cache.
  2. If it does, it stalls the DMA's bus request.
  3. It writes the dirty cache line back to main memory.
  4. It releases the stall, allowing the DMA to proceed with its read, now getting the fresh data.

This process is automatic and transparent to the software (once enabled).

This NXP document is an excellent resource on the topic. It's one of the best explanations available and is prime interview material.

[PDF] PowerQUICC™ Data Cache Coherency

This application note, 'PowerQUICC™ Data Cache Coherency', is a definitive guide to the problem. It covers the theory and the specific hardware configuration bits needed to solve it.

This is a critical read. Please focus on these sections: Section 2 (page 4): 'An example of a potential cache coherency issue' clearly lays out the problem of stale data. Section 3.2 (page 5): 'Software Enforced Coherency' explains the flush/invalidate method. Section 3.3 (page 6): 'Hardware Enforced Coherency' explains the concept of snooping and the MESI protocol. Section 3.3.1 (page 7): 'Hardware Enforced Coherency for...'. This is the key part. It lists example register bits (like DMSEN, RDSEN, TDSEN, GBL) that you set to enable snooping for different DMA-capable peripherals. Knowing that these control bits exist is crucial for a system-level interview.



Conclusion

You have now dissected the operation of a DMA controller, from basic configuration to the advanced, system-level challenges it presents. For your target interviews, simply stating "DMA moves data" is insufficient. You are now equipped to discuss the specific registers in a TCD, the importance of data alignment, the power of scatter-gather, and most critically, to articulate the causes of and solutions for cache coherency problems.

Key Takeaways:

  • DMA offloads the CPU by acting as an independent bus master for data transfers between memory and peripherals.
  • Configuration is done via Transfer Control Descriptors (TCDs), which define source/destination addresses, transfer sizes, and loop counts.
  • Data alignment is crucial for DMA performance and correctness; misaligned accesses can cause stalls or faults.
  • Scatter-Gather DMA uses a linked-list of TCDs to transfer non-contiguous data blocks without CPU intervention.
  • Cache Coherency is a major issue when a caching CPU and a DMA controller share memory. It is solved either through manual software cache management (flush/invalidate) or, preferably, through hardware-enforced coherency (bus snooping).

Preview of the Next Lesson:

We've covered a complex internal peripheral. In the next lesson, we'll turn our attention to a ubiquitous external interface: the GPIO. We'll go beyond basic on/off control to tackle a classic embedded problem: implementing a software debouncing algorithm and comparing it to hardware solutions.