0
0
Power-electronicsHow-ToIntermediate · 4 min read

How to Use DMA with UART in Embedded C: Simple Guide

To use DMA with UART in Embedded C, configure the UART peripheral and DMA controller to handle data transfers automatically. Set up DMA channels linked to UART TX and RX, enable DMA requests in UART, and start the DMA transfer to send or receive data without CPU intervention.
📐

Syntax

The basic steps to use DMA with UART in Embedded C include:

  • Initialize UART peripheral.
  • Configure DMA channel for UART TX or RX.
  • Enable DMA requests in UART control registers.
  • Start DMA transfer by setting source and destination addresses and data length.

This setup allows UART to trigger DMA transfers automatically.

c
/* Pseudocode syntax for UART DMA setup */
UART_Init();
DMA_Channel_Config(source_address, destination_address, data_length);
UART_Enable_DMA_Request();
DMA_Start();
💻

Example

This example shows how to send a string over UART using DMA on an STM32 microcontroller. It initializes UART and DMA, then starts a DMA transfer to send data without CPU load.

c
#include "stm32f4xx.h"

char message[] = "Hello DMA UART!\r\n";

void UART_DMA_Init(void) {
    // Enable clocks for UART2 and DMA1
    RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
    RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;

    // Configure UART2: 115200 baud, 8N1
    USART2->BRR = 0x8B; // Assuming 16MHz clock
    USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;

    // Configure DMA1 Stream6 for USART2_TX
    DMA1_Stream6->CR = 0;
    DMA1_Stream6->PAR = (uint32_t)&(USART2->DR); // Peripheral address
    DMA1_Stream6->M0AR = (uint32_t)message;     // Memory address
    DMA1_Stream6->NDTR = sizeof(message) - 1;   // Number of data
    DMA1_Stream6->CR = DMA_SxCR_DIR_0 |        // Memory to peripheral
                         DMA_SxCR_MINC |         // Memory increment
                         DMA_SxCR_TCIE |         // Transfer complete interrupt enable
                         DMA_SxCR_PL_1;          // Priority high

    // Enable DMA request on USART2 TX
    USART2->CR3 |= USART_CR3_DMAT;

    // Enable DMA stream
    DMA1_Stream6->CR |= DMA_SxCR_EN;
}

int main(void) {
    UART_DMA_Init();
    while (!(DMA1->HISR & DMA_HISR_TCIF6)) {
        // Wait for transfer complete
    }
    // Transfer complete, disable DMA stream
    DMA1_Stream6->CR &= ~DMA_SxCR_EN;
    while (1) {}
}
Output
Hello DMA UART!
⚠️

Common Pitfalls

Common mistakes when using DMA with UART include:

  • Not enabling DMA requests in UART control registers.
  • Incorrectly setting DMA source or destination addresses.
  • Forgetting to enable the DMA stream/channel.
  • Not handling transfer complete interrupts or flags.
  • Using wrong data length causing incomplete transfers.

Always verify peripheral clocks and interrupt priorities.

c
/* Wrong: DMA not enabled in UART */
USART2->CR3 = 0; // DMA request disabled

/* Right: Enable DMA request for TX */
USART2->CR3 |= USART_CR3_DMAT;
📊

Quick Reference

Tips for using DMA with UART:

  • Enable peripheral clocks before configuration.
  • Set DMA direction correctly (memory-to-peripheral for TX, peripheral-to-memory for RX).
  • Enable UART DMA requests in CR3 register.
  • Use memory increment mode for buffers.
  • Check and clear DMA transfer complete flags.

Key Takeaways

Configure UART and DMA peripherals properly before starting transfers.
Enable DMA requests in UART control registers to link UART and DMA.
Set correct source, destination, and data length in DMA for reliable transfers.
Always check DMA transfer complete flags to know when transfer ends.
Common errors include missing DMA enable in UART and wrong addresses.