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.
DMA with UART for bulk transfer in 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.
// 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// 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 transmitterThis 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.
#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; }
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.
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.
Practice
Solution
Step 1: Understand DMA role in UART transfer
DMA transfers data directly between memory and UART without CPU intervention for each byte.Step 2: Identify the benefit of reduced CPU load
This frees CPU to perform other tasks while data moves in background.Final Answer:
It reduces CPU load by handling data transfer automatically. -> Option AQuick Check:
DMA offloads CPU [OK]
- Thinking DMA increases UART speed beyond hardware limits
- Confusing DMA with encryption or clock control
- Assuming UART can work without clock signal
Solution
Step 1: Identify UART register for DMA transmit enable
UART control register 3 (CR3) contains the DMAT bit to enable DMA for transmission.Step 2: Check correct bit and register usage
Setting USART_CR3_DMAT in UART->CR3 enables DMA transmit requests.Final Answer:
UART->CR3 |= USART_CR3_DMAT; -> Option AQuick Check:
DMA transmit enable bit is in CR3 [OK]
- Using CR1 instead of CR3 for DMA transmit enable
- Confusing DMA channel enable with UART DMA request enable
- Setting baud rate register instead of control bits
DMA->CCR = DMA_CCR_MINC | DMA_CCR_TCIE; DMA->CNDTR = 100; DMA->CPAR = (uint32_t)&UART->RDR; DMA->CMAR = (uint32_t)rx_buffer; DMA->CCR |= DMA_CCR_EN;
Solution
Step 1: Understand DMA CNDTR register role
CNDTR holds the number of data items to transfer; initially set to 100.Step 2: Check when CNDTR changes
CNDTR decrements only after each data transfer, so right after enabling DMA, it remains 100.Final Answer:
100 -> Option CQuick Check:
DMA transfer count starts at set value = 100 [OK]
- Assuming CNDTR decrements immediately on enable
- Confusing CNDTR with current data register
- Thinking CNDTR resets to zero on start
DMA->CCR = DMA_CCR_MINC | DMA_CCR_DIR; DMA->CNDTR = 50; DMA->CPAR = (uint32_t)&UART->TDR; DMA->CMAR = (uint32_t)tx_buffer; DMA->CCR |= DMA_CCR_EN; UART->CR3 &= ~USART_CR3_DMAT;
Solution
Step 1: Check UART DMA transmit enable bit
UART->CR3 must have DMAT bit set to enable DMA requests for transmit.Step 2: Identify disabling of DMAT bit
Code clears DMAT bit after DMA enable, disabling UART DMA transmit requests, so transfer won't start.Final Answer:
UART DMA transmit request is disabled after enabling DMA. -> Option BQuick Check:
DMAT bit must be set for DMA transmit [OK]
- Disabling UART DMA transmit request after DMA enable
- Confusing DMA direction bit meaning
- Forgetting to enable memory increment mode
Solution
Step 1: Identify direction for UART transmit DMA
For UART transmit, DMA source is memory buffer, destination is UART TDR register.Step 2: Enable UART DMA transmit request and DMA channel
Set UART DMAT bit to enable DMA requests on transmit, then enable DMA channel to start transfer.Final Answer:
Set DMA source to buffer, destination to UART TDR, length 256; enable UART DMAT bit; enable DMA channel. -> Option DQuick Check:
Memory to UART TDR + DMAT enabled [OK]
- Confusing UART TDR and RDR registers for source/destination
- Using DMAR bit for transmit instead of DMAT
- Setting DMA direction opposite to data flow
Ready to prove it?
Pass the test and this pattern moves unknown
