Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 326 of 9364. Peripheral Interfacing and ControlFree lesson

Implementing Double Buffering for Continuous Data Streams

Develop a dual-buffer system that allows the CPU to process one data block while the DMA controller fills the other.

In this lesson, you will learn how to use a ping-pong buffer strategy to ensure continuous data acquisition without losing samples or stalling the CPU.

The Problem: The Bottleneck of Single Buffering

When you use a single buffer for data acquisition (like streaming audio from an ADC via DMA), you face a timing dilemma. Once the DMA fills the buffer, you must pause the collection to process the data. If the CPU takes too long to process that block, the next incoming data sample will be lost because the hardware has nowhere to put it.

The Solution: Double Buffering (Ping-Pong)

Double buffering eliminates this downtime by allocating two distinct memory regions: BufferA and BufferB. You configure your DMA controller to fill BufferA while the CPU is busy analyzing BufferB. Once BufferA is full, the DMA automatically switches to BufferB.

This process creates a cycle:

  1. DMA fills Buffer A.
  2. Interrupt triggers: DMA finishes A.
  3. Switch: DMA starts filling Buffer B while the CPU begins processing Buffer A.
  4. Interrupt triggers: DMA finishes B.
  5. Switch: DMA starts filling Buffer A again while the CPU processes Buffer B.

Conceptual Implementation

To implement this, you typically use a DMA "circular mode" or a transfer-complete interrupt to toggle your pointer.

// Two distinct memory regions
uint16_t bufferA[BUFFER_SIZE];
uint16_t bufferB[BUFFER_SIZE];

void DMA_TransferComplete_ISR() {
    if (currentBuffer == bufferA) {
        process_data(bufferA);    // CPU works here
        configure_dma(bufferB);   // DMA fills B
        currentBuffer = bufferB;
    } else {
        process_data(bufferB);    // CPU works here
        configure_dma(bufferA);   // DMA fills A
        currentBuffer = bufferA;
    }
}

By decoupling the ingestion of data from the computation of data, you ensure the DMA controller always has an "empty" bucket to pour data into, while the CPU always has a "full" bucket to analyze. This maintains a seamless, continuous stream of data without missing a single sample, regardless of small variations in your CPU's processing time.

Key Takeaway: Double buffering uses two memory regions in a ping-pong fashion to allow the CPU to process one block of data while the DMA hardware concurrently collects the next, preventing data loss in high-speed streaming applications.