Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 223 of 9363. Microcontroller Fundamentals and Bare-Metal CFree lesson

Mitigating Cache Coherency Issues in DMA Operations

Apply memory barrier instructions and cache maintenance operations to ensure the CPU reads valid data after DMA completion.

In this lesson, you will learn how to prevent the CPU from reading stale data by managing cache synchronization after a DMA transfer completes.

The Visibility Problem

When your microcontroller uses a data cache, the CPU interacts with the cache rather than the physical RAM directly. This is great for speed, but it creates a "coherency" problem when using DMA. When a DMA controller writes data from a peripheral into RAM, it bypasses the CPU cache entirely. If the CPU tries to read that memory address, it may find an older version of the data still sitting in its local cache, ignoring the fresh data the DMA just delivered to the RAM.

Ensuring Data Freshness

To fix this, you must perform a cache maintenance operation. Specifically, you need to invalidate the cache range corresponding to the DMA destination buffer. Invalidating tells the CPU, "Whatever you have in your cache for these addresses is invalid; go fetch it again from actual RAM."

You should perform this operation after the DMA transfer completes but before your application code accesses the buffer. Furthermore, because the CPU might reorder instructions during execution, you must use a Memory Barrier instruction (like DMB on ARM Cortex-M processors) before and after your maintenance operations to ensure that all memory accesses are completed in the correct order.

Implementation Pattern

Here is how you structure this flow in your code:

// 1. Wait for DMA transfer completion interrupt
// 2. Insert a memory barrier to ensure pending memory operations finish
__asm volatile ("dmb sy" ::: "memory");

// 3. Invalidate the cache for the DMA destination buffer
// This forces the CPU to fetch the new data from physical RAM
Cache_Invalidate(buffer_addr, buffer_size);

// 4. Insert another barrier to ensure invalidation completes
__asm volatile ("dmb sy" ::: "memory");

// 5. Now it is safe to process the data
Process_Data(buffer_addr);

By explicitly telling the CPU that its cache is out of date, you bridge the gap between the DMA’s direct memory access and the CPU’s high-speed local storage.

Key Takeaway: Because DMA operates independently of the CPU cache, you must invalidate the relevant cache lines and use memory barriers after a DMA transfer to ensure the CPU reads the updated data from RAM rather than stale data from its cache.