Search code examples
stm32dmaadc

STM32 ADC Multi channel using DMA


I want to use ADC1 scan mode to read three channels of the ADC1 using DMA. I defined a buffer for ADC as shown below:

uint16_t adc_buffer[3];

Then I started DMA using the following function:

HAL_ADC_Start_DMA(&hadc1,(uint32_t*)adc_buffer, 3);

And I use the following callback to read ADC result:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
     //ADC Code
}

But now while(1) loop never executes and the program remains in the ADC callback function. How can I solve this problem?

Note: DMA mode is circular and

hadc1.Init.DMAContinuousRequests = ENABLE;

Solution

  • Problem

    Since you are only capturing three samples (per iteration), it seems likely that the ADC will be able to fill your buffer quicker than your callback function can process it. This basically means you will spend all your time in the callback function - as soon as you have processed the three samples, there are already three more to be processed.

    But it's worse than that. When the callback gets called, you are processing samples while the ADC is storing samples into the same buffer. So this is kind of a race condition.

    Possible solutions

    Use a bigger buffer

    At the very least, double the size of your buffer. Then you can use the "half-complete" callback too. When you get the half-complete callback, you can process the first half of the buffer, whilst the ADC fills the second half of the buffer. When you get the "complete" callback, you can process the second half of the buffer, whilst the ADC fills the first half.

    Use a much bigger buffer

    Same as above, but make it much bigger, e.g. 64 times as big. You'd still use the half-complete and complete callbacks, but now you're processing much more data at once, so minimising the overhead of each interrupt.

    Don't use a circular buffer

    Disable circular buffer mode. When you get the complete callback, process the data, and then start a new DMA conversion when you are finished.

    Reduce the sample rate

    You can increase the sampling time, so each sample takes longer to be taken. This should increase accuracy too. You still need to overcome the basic race condition though (by using a bigger buffer).