Search topics...
UARTDMA and Ring Buffersfoundational

Why is DMA preferred over interrupt-driven UART reception, and how do you set it up?

0 upvotes
Practice with AISoon
Study the fundamentals first — UART topic page

Interrupt-driven UART reception fires an ISR for every single byte received. At 115200 baud, that is up to 11520 interrupts per second — each one requiring context save/restore, flag checking, and a byte copy. At higher baud rates (921600+), the interrupt overhead can consume a significant fraction of CPU time, especially on lower-end Cortex-M0 cores. Worse, if interrupts are briefly disabled (during a flash erase, for example), bytes are lost to overrun errors.

DMA (Direct Memory Access) solves both problems. The DMA controller transfers received bytes directly from the UART data register into a RAM buffer without CPU intervention. The CPU is only interrupted when the buffer is half-full, completely full, or when the UART detects an idle line — reducing interrupt frequency from thousands per second to a handful.

A typical STM32 setup uses DMA in circular mode with a buffer of 64-256 bytes. The DMA controller writes to the buffer continuously, wrapping around to the beginning when it reaches the end. Firmware tracks a read index (tail pointer) and compares it against the DMA's current write position (obtained from the DMA NDTR register) to determine how many new bytes are available. The idle-line interrupt is critical for protocols where messages are separated by pauses — it tells firmware "the transmitter stopped sending, process what you have" even if the buffer is not full.

c
// Pseudo-code: checking for new data in DMA circular buffer
uint16_t dma_head = BUFFER_SIZE - DMA1_Channel5->CNDTR;
while (uart_tail != dma_head) {
process_byte(rx_buffer[uart_tail]);
uart_tail = (uart_tail + 1) % BUFFER_SIZE;
}

Source: UART Q&A