DMA with ADC lets your microcontroller collect data continuously without using the CPU all the time. This saves power and makes your program faster.
DMA with ADC for continuous sampling in 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.
/* Configure ADC in continuous mode */ ADC_InitTypeDef ADC_InitStruct = {0}; ADC_InitStruct.ContinuousConvMode = ENABLE; ADC_Init(&ADC_InitStruct);
/* 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);
/* Start ADC and DMA */
DMA_Cmd(ENABLE);
ADC_Cmd(ENABLE);
ADC_SoftwareStartConv();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.
#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 } } }
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.
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.
Practice
Solution
Step 1: Understand DMA role with ADC
DMA (Direct Memory Access) moves data from ADC to memory automatically, reducing CPU load.Step 2: Identify continuous sampling benefit
Continuous mode means ADC keeps sampling without CPU restarting it each time.Final Answer:
It transfers ADC data to memory automatically without CPU intervention. -> Option BQuick Check:
DMA automates data transfer = It transfers ADC data to memory automatically without CPU intervention. [OK]
- Thinking DMA increases ADC resolution
- Confusing manual and automatic data transfer
- Assuming DMA disables ADC interrupts
Solution
Step 1: Recall DMA modes for continuous ADC sampling
DMA_Mode_Circular allows buffer to be reused endlessly for continuous data.Step 2: Match correct DMA mode setting
DMA_Mode_Normal stops after one transfer; DMA_Mode_Circular repeats automatically.Final Answer:
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; -> Option AQuick Check:
Circular mode enables continuous buffer reuse = DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; [OK]
- Using DMA_Mode_Normal for continuous sampling
- Confusing DMA_Mode_Manual which doesn't exist
- Selecting interrupt mode instead of circular
uint16_t adc_buffer[4] = {0};
// DMA and ADC configured in circular mode
// ADC conversions produce values: 100, 200, 300
// DMA transfers these values into adc_buffer sequentially
// After 3 conversions, what is adc_buffer content?Solution
Step 1: Understand DMA circular buffer filling
DMA fills buffer sequentially from index 0 upwards with ADC values.Step 2: Map ADC values to buffer after 3 transfers
First 3 elements get 100, 200, 300; last element remains 0 as no 4th conversion yet.Final Answer:
[100, 200, 300, 0] -> Option CQuick Check:
Buffer fills sequentially = [100, 200, 300, 0] [OK]
- Assuming buffer shifts values on each new sample
- Thinking DMA fills buffer backwards
- Confusing buffer initialization with data content
ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; // ADC and DMA configuration omitted for brevity DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_Init(DMA1_Channel1, &DMA_InitStructure); ADC_Cmd(ADC1, ENABLE); ADC_SoftwareStartConvCmd(ADC1, ENABLE);
Solution
Step 1: Check DMA mode for continuous ADC sampling
DMA_Mode_Normal stops after one transfer; continuous sampling needs DMA_Mode_Circular.Step 2: Verify other calls order and parameters
Calling ADC_SoftwareStartConvCmd after DMA_Init is correct; DMA1_Channel1 is valid for many MCUs; ADC_Cmd before conversion start is correct.Final Answer:
DMA_Mode_Normal should be DMA_Mode_Circular for continuous sampling. -> Option AQuick Check:
Continuous DMA needs circular mode = DMA_Mode_Normal should be DMA_Mode_Circular for continuous sampling. [OK]
- Using normal mode for continuous DMA
- Misordering ADC and DMA initialization calls
- Assuming DMA channel is invalid without checking MCU
Solution
Step 1: Understand circular DMA buffer usage
Circular DMA fills buffer continuously; half-transfer and transfer-complete interrupts signal when half/full buffer is ready.Step 2: Choose method to avoid data loss
Processing halves alternately on interrupts prevents overwriting unprocessed data and ensures continuous handling.Final Answer:
Use half-transfer and transfer-complete DMA interrupts to process buffer halves alternately. -> Option DQuick Check:
Half/full DMA interrupts enable safe continuous processing = Use half-transfer and transfer-complete DMA interrupts to process buffer halves alternately. [OK]
- Waiting for full buffer before processing causes data loss
- Disabling circular mode loses continuous sampling benefit
- Polling ADC flags wastes CPU and misses DMA data
Ready to prove it?
Pass the test and this pattern moves unknown
