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

Implementing DMA Memory-to-Memory Data Transfers

Develop a bare-metal routine to copy large data blocks between memory regions without triggering CPU interrupt overhead.

In this lesson, you will learn how to offload bulk data movement from the CPU to the DMA controller, effectively freeing your processor for other computation tasks.

Why Move Data Without the CPU?

Previously, we discussed CPU bottlenecks. When the CPU copies large arrays using a loop, it must fetch each instruction, read the source memory, and write to the destination. This consumes clock cycles and keeps the processor "busy" for tasks that require no logic—just movement. Direct Memory Access (DMA) acts as an independent hardware engine that moves data across the system bus matrix without the CPU's direct involvement.

Setting Up a Memory-to-Memory Transfer

To perform a memory-to-memory transfer, you configure the DMA controller rather than the CPU. The process follows these core steps:

  1. Configure Source and Destination: Point the DMA register to your starting source address and ending destination address.
  2. Define Block Size: Set the number of data units (e.g., bytes, half-words, or words) to be transferred.
  3. Increment Mode: Enable address incrementing for both source and destination pointers so the controller traverses your memory buffers sequentially.
  4. Trigger the Transfer: Set the "enable" bit in the DMA control register.

Unlike peripheral-to-memory transfers, memory-to-memory transfers usually rely on a software trigger. Once enabled, the DMA controller requests access to the bus. It effectively "steals" cycles from the CPU to move data, but it does so far more efficiently than the CPU could.

// Conceptual bare-metal trigger for a DMA transfer
DMA1_Stream0->PAR = (uint32_t)&src_buffer;  // Peripheral/Source Address
DMA1_Stream0->M0AR = (uint32_t)&dst_buffer; // Memory/Destination Address
DMA1_Stream0->NDTR = BUFFER_SIZE;           // Number of data items
DMA1_Stream0->CR |= DMA_SxCR_EN;            // Enable the transfer

Because we are not using interrupts here, the CPU is free to perform other logic. You can monitor the status flag in the DMA status register (e.g., TCIF - Transfer Complete) to know when the operation is finished, or simply use the DMA controller's ability to operate silently in the background while your main loop continues executing.

Key Takeaway: Memory-to-memory DMA transfers eliminate CPU cycle wastage by delegating bulk data movement to the DMA hardware, allowing the processor to focus on high-level logic rather than tedious memory copying.