What Is DMA and How DMA Works in Microcontroller Systems
Direct Memory Access (DMA) is a hardware mechanism that allows peripherals to move data directly between memory and registers without CPU involvement during the transfer.
How DMA Works in a Microcontroller
The CPU configures the DMA controller with:
- Source address
- Destination address
- Transfer size
- Transfer type (M2M, P2M, M2P)
A peripheral (ADC, UART, SPI, etc.) generates a DMA request.
The DMA controller autonomously performs the transfer.
An interrupt notifies the CPU after completion or error.
This approach is widely used in ARM Cortex-M3 DMA applications to achieve high throughput and predictable timing.

Why DMA Matters in LPC1768 (ARM Cortex-M3)
The LPC1768 microcontroller includes a powerful General-Purpose DMA (GPDMA) controller designed for high-speed embedded systems.
Key Benefits of Using DMA in LPC1768
- Reduced CPU load – CPU remains free for control logic
- Higher throughput – Ideal for ADC sampling and UART streaming
- Power efficiency – CPU can sleep while DMA runs
- Real-time performance – Deterministic data movement
LPC1768 DMA Architecture Overview
- 8 independent DMA channels
- Memory-to-memory transfers
- Peripheral-to-memory transfers
- Memory-to-peripheral transfers
- Hardware DMA request lines from ADC, UART, SPI, I2S
- Linked-list (scatter-gather) DMA
This flexibility makes LPC1768 DMA suitable for both simple and advanced embedded applications.
Setting Up LPC1768 DMA – Step by Step
1. Enable DMA Clock and Power
// Power up GPDMA
LPC_SC->PCONP |= (1 << 29); // Enable DMA request select (if required) LPC_SC->DMAREQSEL |= 1;
2. Configure DMA Channel for ADC (LPC1768 ADC DMA)
void configure_dma_adc(void) {
LPC_GPDMA->CH[0].CSRCADDR = (uint32_t)&LPC_ADC->ADDR0;
LPC_GPDMA->CH[0].CDESTADDR = (uint32_t)adc_buffer;
LPC_GPDMA->CH[0].CCONTROL =
(1000 << 0) | // Transfer size
(2 << 18) | // Source width: 16-bit
(2 << 21) | // Destination width: 16-bit
(1 << 27) | // Destination increment
(1 << 31); // Terminal count interrupt
}
3. Link DMA to ADC Peripheral
void link_dma_to_adc(void) {
LPC_ADC->ADCR |= (1 << 21); // Enable ADC DMA LPC_GPDMA->DMACSync |= (1 << 0); LPC_GPDMA->CH[0].CCONFIG =
(1 << 0) | // Enable channel
(1 << 1) | // Source peripheral: ADC
(1 << 11); // Peripheral-to-memory
}
This completes a working LPC1768 ADC DMA example.

Practical Applications of DMA in LPC1768
A. LPC1768 UART DMA Example (High-Speed Serial Communication)
void uart_dma_send(const uint8_t *data, uint32_t length) {
LPC_GPDMA->CH[1].CCONFIG &= ~(1 << 0); LPC_GPDMA->CH[1].CSRCADDR = (uint32_t)data;
LPC_GPDMA->CH[1].CDESTADDR = (uint32_t)&LPC_UART1->THR;
LPC_GPDMA->CH[1].CCONTROL = length | (1 << 31); LPC_UART1->DMACR = 0x2;
LPC_GPDMA->CH[1].CCONFIG =
(1 << 0) | (6 << 6);
}
This LPC1768 UART DMA example enables continuous, non-blocking UART transmission.
B. Memory-to-Memory DMA Transfer
void dma_memcpy(void *dest, void *src, uint32_t size) {
LPC_GPDMA->CH[2].CSRCADDR = (uint32_t)src;
LPC_GPDMA->CH[2].CDESTADDR = (uint32_t)dest;
LPC_GPDMA->CH[2].CCONTROL = size | (1 << 31); LPC_GPDMA->CH[2].CCONFIG = (1 << 0);
}
Advanced Feature: DMA Linked Lists (Scatter-Gather)
typedef struct {
uint32_t src;
uint32_t dest;
uint32_t control;
uint32_t next;
} DMA_LLI;
Linked lists allow chained DMA transfers without CPU intervention.
Common Pitfalls and Debugging Tips
- Ensure data width alignment
- Use DMA-accessible SRAM
- Enable peripheral clocks first
- Do not reconfigure active DMA channels
DMA Status Debug Code
void check_dma_status(uint8_t channel) {
if (LPC_GPDMA->INTSTAT & (1 << channel)) { if (LPC_GPDMA->INTTCSTAT & (1 << channel)) { // Transfer complete } if (LPC_GPDMA->INTERRSTAT & (1 << channel)) { uint8_t error = (LPC_GPDMA->CH[channel].CSTAT >> 1) & 0x3;
}
LPC_GPDMA->INTTCCLEAR = (1 << channel); LPC_GPDMA->INTERRCLEAR = (1 << channel);
}
}
Performance Comparison: CPU vs DMA
| Transfer Method | CPU Usage | Time (1 KB) |
|---|
| CPU Copy | 100% | 42 µs |
| DMA Transfer | 0–5% | 8 µs |
| Improvement | 20× less CPU | 5× faster |

Conclusion
Direct Memory Access in microcontroller platforms like the LPC1768 is a game-changer for embedded systems requiring high-speed data movement with minimal CPU overhead. By implementing LPC1768 DMA, ADC DMA, and UART DMA, you can build efficient, real-time, and power-optimized applications.
Start with simple DMA transfers, then explore linked-list DMA to unlock the full potential of ARM Cortex-M3 GPDMA.