In this lesson, you will learn how to configure the DMA controller to automatically traverse memory and peripheral buffers by controlling address incrementation logic.
The Problem of Static Addressing
When you initiate a DMA transfer, the controller needs to know not just where to start, but how to navigate the data. If you are moving data from a peripheral (like an ADC data register) to a memory array, the behavior required for each side is fundamentally different.
If the DMA reads from a peripheral, the source address is static. You want to read the same register address over and over to capture every new sample. However, if you are writing that data into a memory array, the destination address must increment after every transfer so that the next piece of data lands in the next slot of your array.
Configuring the Increment Logic
Most DMA controllers provide specific configuration bits—often called PINC (Peripheral Increment) and MINC (Memory Increment)—to control this behavior.
Consider an ADC sampling process:
- Source (Peripheral): Set increment to disabled. The DMA stays locked onto the ADC data register address.
- Destination (Memory): Set increment to enabled. The DMA adds the size of the data type (e.g., 2 bytes for a 16-bit integer) to the address pointer automatically after every single write operation.
// Conceptual DMA Configuration
dma_stream->CR |= DMA_SxCR_MINC; // Enable memory increment
dma_stream->CR &= ~DMA_SxCR_PINC; // Disable peripheral increment
dma_stream->PAR = (uint32_t)&ADC1->DR; // Source: Static ADC register
dma_stream->M0AR = (uint32_t)&buffer[0]; // Destination: Start of array
Why it Matters
If you forget to enable MINC, the DMA will overwrite the same memory address repeatedly, resulting in an array that only contains the final value of the transfer. Conversely, if you accidentally enable PINC on a peripheral, the DMA will increment its source pointer into undefined memory space, likely triggering a memory fault or reading garbage data. By mastering these toggles, you ensure your data streams perfectly into contiguous memory blocks without consuming a single cycle of CPU time.
Key Takeaway: Enable incrementation only for contiguous memory buffers and keep it disabled for static peripheral registers to ensure data is correctly channeled into your arrays.