How to Use DMA on STM32: Setup and Example Guide
To use
DMA on STM32, you first enable the DMA clock, configure the DMA channel with source, destination, and data size, then start the transfer. Use the STM32 HAL library functions like HAL_DMA_Init() and HAL_DMA_Start() to manage DMA operations efficiently.Syntax
Using DMA on STM32 involves these main steps:
- Enable DMA clock: Activate the clock for the DMA controller.
- Configure DMA channel: Set source address, destination address, data length, and transfer direction.
- Initialize DMA: Use
HAL_DMA_Init()to apply the configuration. - Start DMA transfer: Use
HAL_DMA_Start()to begin data movement. - Handle completion: Optionally use interrupts or polling to detect transfer completion.
c
DMA_HandleTypeDef hdma; // 1. Enable DMA clock (example for DMA1) __HAL_RCC_DMA1_CLK_ENABLE(); // 2. Configure DMA channel hdma.Instance = DMA1_Channel1; hdma.Init.Direction = DMA_MEMORY_TO_PERIPH; // or DMA_PERIPH_TO_MEMORY hdma.Init.PeriphInc = DMA_PINC_DISABLE; hdma.Init.MemInc = DMA_MINC_ENABLE; hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma.Init.Mode = DMA_NORMAL; hdma.Init.Priority = DMA_PRIORITY_LOW; // 3. Initialize DMA HAL_DMA_Init(&hdma); // 4. Start DMA transfer HAL_DMA_Start(&hdma, (uint32_t)srcAddress, (uint32_t)dstAddress, dataLength);
Example
This example shows how to transfer a buffer of data from memory to a peripheral (e.g., USART) using DMA on STM32 with HAL library.
c
#include "stm32f1xx_hal.h" DMA_HandleTypeDef hdma_usart_tx; uint8_t txBuffer[] = "Hello DMA STM32!"; void DMA_Config(void) { __HAL_RCC_DMA1_CLK_ENABLE(); hdma_usart_tx.Instance = DMA1_Channel4; // USART1_TX channel hdma_usart_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart_tx.Init.Mode = DMA_NORMAL; hdma_usart_tx.Init.Priority = DMA_PRIORITY_LOW; HAL_DMA_Init(&hdma_usart_tx); __HAL_LINKDMA(&huart1, hdmatx, hdma_usart_tx); } int main(void) { HAL_Init(); SystemClock_Config(); MX_USART1_UART_Init(); DMA_Config(); // Start DMA transfer from txBuffer to USART1->DR register HAL_DMA_Start(&hdma_usart_tx, (uint32_t)txBuffer, (uint32_t)&USART1->DR, sizeof(txBuffer)-1); // Enable USART DMA transmit USART1->CR3 |= USART_CR3_DMAT; while (1) { // Main loop } }
Output
The string "Hello DMA STM32!" is sent via USART1 using DMA without CPU intervention.
Common Pitfalls
Common mistakes when using DMA on STM32 include:
- Not enabling the DMA clock before configuration.
- Incorrect source or destination addresses causing data corruption.
- Forgetting to enable peripheral DMA requests (e.g., USART DMA transmit).
- Not configuring data alignment properly, leading to transfer errors.
- Ignoring interrupts or flags that signal transfer completion.
Always check the DMA channel and stream numbers match your peripheral and STM32 model.
c
/* Wrong: Not enabling DMA clock */ // HAL_DMA_Init() will fail or hang /* Right: Enable DMA clock before init */ __HAL_RCC_DMA1_CLK_ENABLE(); HAL_DMA_Init(&hdma);
Quick Reference
Key tips for using DMA on STM32:
- Always enable DMA controller clock first.
- Configure DMA channel parameters carefully (direction, increment, alignment).
- Use HAL library functions for easier setup and portability.
- Link DMA handle to peripheral handle if using HAL peripheral drivers.
- Enable peripheral DMA requests and interrupts if needed.
Key Takeaways
Enable the DMA clock before configuring any DMA channels.
Set correct source, destination, and data size parameters for your transfer.
Use HAL_DMA_Init() and HAL_DMA_Start() to initialize and start DMA transfers.
Remember to enable peripheral DMA requests to allow DMA operation.
Check transfer completion with interrupts or polling to avoid data loss.