0
0
Embedded Cprogramming~7 mins

DMA with UART for bulk transfer in Embedded C

Choose your learning style9 modes available
Introduction

DMA helps move large amounts of data through UART without using the CPU for every byte. This makes data transfer faster and frees the CPU for other tasks.

When you need to send or receive large blocks of data over UART efficiently.
When you want to reduce CPU load during continuous data transfer.
When your application requires real-time data streaming without delays.
When you want to avoid CPU overhead caused by interrupt-driven UART transfers.
When working with sensors or devices that send bulk data over UART.
Syntax
Embedded C
1. Configure UART peripheral for desired baud rate and settings.
2. Configure DMA channel:
   - Set source address (UART data register).
   - Set destination address (memory buffer).
   - Set transfer size (number of bytes).
   - Set direction (peripheral to memory or memory to peripheral).
3. Enable DMA channel.
4. Enable UART DMA requests.
5. Start transfer and wait for completion or handle via interrupts.

The exact register names and steps depend on your microcontroller.

DMA handles data movement automatically once started, reducing CPU involvement.

Examples
This example sets DMA to receive data from UART into a buffer automatically.
Embedded C
// Example: Setup DMA for UART RX bulk transfer
DMA_Channel->CPAR = (uint32_t)&UARTx->DR; // UART data register
DMA_Channel->CMAR = (uint32_t)rx_buffer; // memory buffer
DMA_Channel->CNDTR = BUFFER_SIZE; // number of bytes
DMA_Channel->CCR = DMA_CCR_MINC | DMA_CCR_EN | DMA_CCR_TCIE; // memory increment, enable, transfer complete interrupt
UARTx->CR3 |= USART_CR3_DMAR; // enable UART DMA receiver
This example sets DMA to send data from a buffer to UART automatically.
Embedded C
// Example: Setup DMA for UART TX bulk transfer
DMA_Channel->CPAR = (uint32_t)&UARTx->DR; // UART data register
DMA_Channel->CMAR = (uint32_t)tx_buffer; // memory buffer
DMA_Channel->CNDTR = BUFFER_SIZE; // number of bytes
DMA_Channel->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_EN | DMA_CCR_TCIE; // memory increment, direction memory to peripheral, enable, transfer complete interrupt
UARTx->CR3 |= USART_CR3_DMAT; // enable UART DMA transmitter
Sample Program

This program sets up a DMA transfer to send a string over UART. It simulates the DMA moving data from memory to UART data register. The output shows the string sent.

Embedded C
#include <stdint.h>
#include <stdbool.h>

#define BUFFER_SIZE 10

// Mock registers and bits for demonstration
volatile uint8_t UART_DR = 0;
volatile uint32_t DMA_CCR_EN = 1 << 0;
volatile uint32_t DMA_CCR_MINC = 1 << 1;
volatile uint32_t DMA_CCR_DIR = 1 << 4;
volatile uint32_t DMA_CCR_TCIE = 1 << 5;
volatile uint32_t USART_CR3_DMAR = 1 << 6;
volatile uint32_t USART_CR3_DMAT = 1 << 7;

// Simulated UART and DMA structures
typedef struct {
    volatile uint32_t CR3;
    volatile uint8_t DR;
} UART_TypeDef;

typedef struct {
    volatile uint32_t CPAR;
    volatile uint32_t CMAR;
    volatile uint32_t CNDTR;
    volatile uint32_t CCR;
} DMA_Channel_TypeDef;

UART_TypeDef UART1 = {0};
DMA_Channel_TypeDef DMA1_Channel4 = {0};

uint8_t tx_buffer[BUFFER_SIZE] = { 'H','e','l','l','o',' ','D','M','A','\0' };
uint8_t rx_buffer[BUFFER_SIZE] = {0};

void dma_uart_tx_start(UART_TypeDef *uart, DMA_Channel_TypeDef *dma, uint8_t *buffer, uint32_t size) {
    dma->CPAR = (uint32_t)&uart->DR; // UART data register
    dma->CMAR = (uint32_t)buffer;   // memory buffer
    dma->CNDTR = size;              // number of bytes
    dma->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_EN | DMA_CCR_TCIE; // enable DMA for memory to peripheral
    uart->CR3 |= USART_CR3_DMAT;    // enable UART DMA transmitter
}

int main() {
    // Start DMA transfer of tx_buffer over UART1
    dma_uart_tx_start(&UART1, &DMA1_Channel4, tx_buffer, BUFFER_SIZE);

    // Simulate DMA transfer by copying data manually (for demo only)
    for (int i = 0; i < BUFFER_SIZE; i++) {
        UART1.DR = tx_buffer[i];
        // Normally hardware moves data, here we just print
        // Simulate sending each byte
        // In real embedded code, UART DR register sends data
    }

    // Print what was sent
    for (int i = 0; i < BUFFER_SIZE; i++) {
        putchar(tx_buffer[i]);
    }
    putchar('\n');

    return 0;
}
OutputSuccess
Important Notes

DMA reduces CPU load by handling data transfer automatically.

Make sure to configure UART and DMA clocks and interrupts properly in real hardware.

Always check DMA transfer complete flags or interrupts to know when transfer ends.

Summary

DMA with UART lets you send or receive large data blocks efficiently.

It frees the CPU from moving each byte manually.

Setup involves configuring UART, DMA addresses, size, and enabling DMA requests.