0
0
Embedded Cprogramming~10 mins

DMA with ADC for continuous sampling in Embedded C

Choose your learning style9 modes available
Introduction

DMA with ADC lets your microcontroller collect data continuously without using the CPU all the time. This saves power and makes your program faster.

You want to measure sensor data like temperature or light continuously.
You need to record analog signals without missing any samples.
You want to free the CPU to do other tasks while data is collected.
You want smooth and fast data collection for real-time processing.
You want to avoid delays caused by manual reading of ADC values.
Syntax
Embedded C
1. Configure ADC for continuous conversion mode.
2. Set up DMA to transfer ADC data to memory buffer.
3. Enable DMA and ADC.
4. Start ADC conversion.
5. Use interrupts or polling to process data when buffer is full.

DMA automatically moves ADC data to memory without CPU help.

Continuous mode means ADC keeps sampling without stopping.

Examples
This sets the ADC to keep sampling automatically.
Embedded C
/* Configure ADC in continuous mode */
ADC_InitTypeDef ADC_InitStruct = {0};
ADC_InitStruct.ContinuousConvMode = ENABLE;
ADC_Init(&ADC_InitStruct);
DMA is set to circular mode to keep filling the buffer repeatedly.
Embedded C
/* Configure DMA to transfer ADC data to buffer */
DMA_InitTypeDef DMA_InitStruct = {0};
DMA_InitStruct.Direction = DMA_PERIPH_TO_MEMORY;
DMA_InitStruct.PeriphInc = DMA_PINC_DISABLE;
DMA_InitStruct.MemInc = DMA_MINC_ENABLE;
DMA_InitStruct.Mode = DMA_CIRCULAR;
DMA_InitStruct.BufferSize = BUFFER_SIZE;
DMA_Init(&DMA_InitStruct);
This starts the ADC conversions and DMA transfers.
Embedded C
/* Start ADC and DMA */
DMA_Cmd(ENABLE);
ADC_Cmd(ENABLE);
ADC_SoftwareStartConv();
Sample Program

This program sets up ADC1 to sample channel 0 continuously. DMA2 Stream0 moves ADC data to adc_buffer in circular mode. The CPU can use adc_buffer anytime without stopping ADC.

Embedded C
#include "stm32f4xx.h"

#define BUFFER_SIZE 10
uint16_t adc_buffer[BUFFER_SIZE];

void ADC_DMA_Config(void) {
    // Enable clocks
    RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;

    // Configure DMA2 Stream0 for ADC1
    DMA2_Stream0->CR = 0;
    DMA2_Stream0->PAR = (uint32_t)&ADC1->DR; // ADC data register
    DMA2_Stream0->M0AR = (uint32_t)adc_buffer; // Memory buffer
    DMA2_Stream0->NDTR = BUFFER_SIZE;
    DMA2_Stream0->CR |= DMA_SxCR_CHSEL_0; // Channel 0 for ADC1
    DMA2_Stream0->CR |= DMA_SxCR_MINC; // Memory increment
    DMA2_Stream0->CR |= DMA_SxCR_CIRC; // Circular mode
    DMA2_Stream0->CR |= DMA_SxCR_PL_1; // Priority high
    DMA2_Stream0->CR |= DMA_SxCR_DIR_0; // Peripheral to memory
    DMA2_Stream0->CR |= DMA_SxCR_EN; // Enable DMA stream

    // Configure ADC1
    ADC1->CR2 = 0;
    ADC1->CR2 |= ADC_CR2_DMA;
    ADC1->CR2 |= ADC_CR2_DDS; // DMA requests continuous
    ADC1->CR2 |= ADC_CR2_CONT; // Continuous conversion
    ADC1->SQR3 = 0; // Channel 0
    ADC1->SMPR2 = ADC_SMPR2_SMP0_0 | ADC_SMPR2_SMP0_1; // Sample time

    ADC1->CR2 |= ADC_CR2_ADON; // Enable ADC
    for (volatile int i=0; i<1000; i++); // Delay
    ADC1->CR2 |= ADC_CR2_SWSTART; // Start conversion
}

int main(void) {
    ADC_DMA_Config();

    while(1) {
        // Main loop can process adc_buffer data
        // For example, check adc_buffer[0] value
        if (adc_buffer[0] > 2000) {
            // Do something
        }
    }
}
OutputSuccess
Important Notes

Make sure DMA and ADC clocks are enabled before configuration.

Use circular DMA mode to keep filling the buffer without stopping.

Remember to set ADC sample time to get stable readings.

Summary

DMA with ADC lets you collect analog data continuously without CPU load.

Configure ADC in continuous mode and DMA in circular mode for smooth data flow.

Use the buffer filled by DMA to process data anytime in your program.