In this lesson, you will learn how to match DMA transfer widths with peripheral register sizes to ensure data integrity and maximize bus performance.
The Rule of "Natural Alignment"
In embedded systems, the CPU and DMA controller communicate with peripherals over a system bus. If you attempt to move 32 bits of data into a register that only expects 8-bit writes, or if you provide a 32-bit address that isn't divisible by 4, the hardware will likely trigger an UsageFault or a bus error.
To prevent these alignment faults, you must treat the Peripheral Data Register as the "source of truth" for your DMA settings. If a UART's data register is defined as 8 bits wide, your DMA transfer width must be set to BYTE (8-bit) size. Trying to perform a WORD (32-bit) transfer on an 8-bit peripheral is like trying to pour a gallon of water into a shot glass—the data will spill, resulting in corrupt reads or bus errors.
Matching Bus Widths for Efficiency
Bus bandwidth utilization relies on "packing." If you have a 32-bit wide system bus and you are transferring data, the bus operates most efficiently when the transfer width matches the bus width.
Consider this scenario: You are moving a buffer from RAM to a 32-bit wide DAC (Digital-to-Analog Converter).
- Optimal: DMA Transfer Width = 32-bit (Word). The bus carries 4 bytes in a single clock cycle.
- Suboptimal: DMA Transfer Width = 8-bit (Byte). The bus carries 1 byte, wasting 24 bits of bandwidth per cycle.
Practical Implementation
When configuring your DMA transfer control register, you must align your source/destination pointers according to the width:
// Example: Setting up DMA for a 32-bit wide peripheral
DMA_InitStruct.PeripheralDataAlignment = DMA_PDATAALIGN_WORD; // Match the 32-bit register
DMA_InitStruct.MemoryDataAlignment = DMA_MDATAALIGN_WORD; // Source must be word-aligned
DMA_InitStruct.PeriphInc = DMA_PINC_DISABLE; // Fixed register address
DMA_InitStruct.MemInc = DMA_MINC_ENABLE; // Increment RAM buffer
Always ensure your RAM buffer pointer is cast to a type that matches your alignment (e.g., uint32_t *buffer) so the compiler ensures the base address is a multiple of 4.
Key Takeaway: Always match your DMA transfer width to the peripheral's register size to avoid hardware faults and align your memory buffers to that same width to ensure optimal bus efficiency.