cancel
Showing results for 
Search instead for 
Did you mean: 

STM32, ADC and continuous conversion mode

Posted on January 19, 2018 at 23:16

Hi. I need to have the value of 2 channels and the internal temperature.

My adc is setup as this:

  hadc.Instance = ADC1;

  hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;

  hadc.Init.Resolution = ADC_RESOLUTION_12B;

  hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;

  hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;

  hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

  hadc.Init.LowPowerAutoWait = DISABLE;

  hadc.Init.LowPowerAutoPowerOff = DISABLE;

  hadc.Init.ContinuousConvMode = DISABLE;

  hadc.Init.DiscontinuousConvMode = DISABLE;

  hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;

  hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

  hadc.Init.DMAContinuousRequests = DISABLE;

  hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;

and this is my callback:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {

    if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)) {

        ADCValues[ADCIndex]= HAL_ADC_GetValue(hadc);

        ADCIndex++;

    }

    if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS)) {

        ADCIndex= 0;

        Vdd= 3300 * (*VREFINT_CAL_ADDR) / ADCValues[3];

        Temperature= (((int32_t)ADCValues[2] * Vdd / 3300)- (int32_t)*TEMP30_CAL_ADDR);

        Temperature= Temperature * (int32_t)(110- 30);

        Temperature= Temperature / (int32_t)(*TEMP110_CAL_ADDR- *TEMP30_CAL_ADDR);

        Temperature= Temperature+ 30;

        Reader125_0= ADCValues[1];

        Reader125_1= ADCValues[0];

    }

}

everything is working perfectly but only with 'hadc.Init.ContinuousConvMode = DISABLE;'

If I enable 'hadc.Init.ContinuousConvMode' I have wrong values.

What can I do to resolve the problem?

5 REPLIES 5
raptorhal2
Lead
Posted on January 20, 2018 at 01:48

If the EOS processing takes longer than one ADC conversion, the next EOC process will be for the second or later conversion, out of sync with the ADCIndex.

If for some reason you can't disable continuous mode, try converting VREF or Temperature first where, I presume, you have the longer sampling times needed for accuracy. But you then run the risk that might not work for a different combination of ADC clock and system clock.

Cheers, Hal

T J
Lead
Posted on January 20, 2018 at 07:28

yes, the values go crazy down here;

ADC_CLOCK_ASYNC_DIV1

and   ADC_SAMPLETIME_1CYCLE_5

what sample time are you using ?

you really have to calibrate the ADC too, if you want some accuracy in the readings

Posted on January 20, 2018 at 09:35

Finally this is my CubeMX setup

0690X00000609RPQAY.png0690X00000609RUQAY.png

This is my callback

unsigned int ADCValues[5];

unsigned int ADCIndex= 0;

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {

    if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)) {

        ADCValues[ADCIndex]= HAL_ADC_GetValue(hadc);

        ADCIndex++;

    }

    if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS)) ADCIndex= 0;

}

And outside che callback I check the ADCValues[2] and ADCValues[3] where I should have the Temperature and Vdd values.

Is this the right approach? The Temperature value now seems to be ok.
Posted on January 20, 2018 at 12:06

I have a similar approach,

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
 if(!ADC_ChannelsCounter--) {
 ADC_ChannelsCounter = ADC_ChannelCount;
 ADC_CompleteCycle = true; // signal foreground to process 
 // copy 15 channels results away now
 for(int i = 0 ; i < ADC_ChannelCount ; i++) { 
 ADC_Channel_Buffer[i] = ADC_DMABuffer[i]; 
 }
 }
}�?�?�?�?�?�?�?�?�?�?�?�?

Posted on January 21, 2018 at 16:31

Reading the values outside the sampling loop I believe is a better approach.

The internal channels are high impedance sources, so T. J.'s example using 1.5 cycles will produce inaccurate results with any sampling method.

The root difficulty that ADC programmers have to overcome is ST's design of using one data register per ADC. The best software approach is to use DMA to save a sampling sequence to memory, then process the results when the DMA counter gets to zero. ST's ADC Sequencer example is a highly convoluted, inefficient way to do a simple task, and I suspect it leads beginner's astray.

Cheers, Hal