In this lesson, you will learn how to synchronize memory buffers when your processor’s cache and your DMA controller are both accessing the same data, preventing the use of stale information.
The Conflict of Two Masters
In modern embedded systems, the CPU often uses a Cache—a small, high-speed memory block—to store copies of data from the main system RAM. This makes the processor run much faster. However, a DMA controller is a separate hardware peripheral that interacts directly with RAM, completely bypassing the CPU’s cache.
The problem occurs when the CPU modifies data in its cache, but that change hasn’t been written back to RAM yet. If the DMA controller initiates a transfer, it will grab the old, "stale" data from RAM. Conversely, if a DMA controller writes new incoming data directly into RAM, the CPU might be unaware of the update and continue using the old values still sitting in its cache.
Solving Incoherency
To fix this, we use two fundamental cache maintenance operations:
- Cache Clean (or Flush): Before starting a DMA transfer out of memory to a peripheral, the CPU must "clean" the cache. This forces any modified data in the cache to be written out to the physical RAM so the DMA controller sees the most recent version.
- Cache Invalidate: Before the CPU reads data that a DMA controller has just written into RAM, the CPU must "invalidate" its cache lines for that memory range. This tells the CPU, "Forget what you think you know about this memory location; go fetch the fresh version from RAM."
Example Workflow
If you are receiving data via DMA into a buffer, the pattern looks like this:
// 1. Prepare buffer to receive DMA data
// 2. Start DMA transfer
// 3. Wait for DMA Interrupt (Completion Signaling)
// 4. Invalidate cache range for the buffer
cache_invalidate(buffer_address, buffer_size);
// 5. Now it is safe for the CPU to read the buffer
process_data(buffer_address);
By ensuring the cache and RAM are aligned before and after these transfers, you prevent the system from operating on inconsistent data states.
Key Takeaway: Always clean the cache before a DMA output transfer and invalidate the cache after a DMA input transfer to ensure the CPU and DMA controller are always operating on the same physical data.