IGtti
IGtti

Reputation: 59

STM32 ADC Reading Instability

I am reading 5 ADC channels in polling mode. For each channel I get 10 samples and calculate the average. Looking for the samples array, it is visible some instability. First readings have higher values and they decrease until the last sample. This behavior is very repetitive. See the output array (ui32_RawTemp):

First read 1855

Last read 1850

Original output values

ui32_RawTemp[0]: 1855
ui32_RawTemp[1]: 1855
ui32_RawTemp[2]: 1854
ui32_RawTemp[3]: 1852
ui32_RawTemp[4]: 1852
ui32_RawTemp[5]: 1852
ui32_RawTemp[6]: 1851
ui32_RawTemp[7]: 1851
ui32_RawTemp[8]: 1850
ui32_RawTemp[9]: 1850

For debug, I replaced the sensors connected to my ADC channels by fixed resistors, in order to get fixed reading values.

ADC Self calibration is performed before the first channel read. Every 30s the Calibration and 5 reads are repeated.

Here is the original code snippet (for one channel). To make it easier to understand I removed the ADC HAL Error handling.

AVG_NUMBER 10
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5;
    sConfig.SingleDiff = ADC_SINGLE_ENDED;
    sConfig.OffsetNumber = ADC_OFFSET_NONE;
    sConfig.Offset = 0;

    // reading TEMP1_ADC on channel 5
    sConfig.Channel = ADC_CHANNEL_5;

    ADC_HAL_ErrCode = HAL_ADC_ConfigChannel(&hadc1, &sConfig);
    if(ADC_HAL_ErrCode != HAL_OK) {
    ......
    }

    ui32_Temp = 0;
    for(ui8_AVGCounter=0; ui8_AVGCounter < AVG_NUMBER; ui8_AVGCounter++) {
        HAL_ADC_Start(&hadc1);
        HAL_ADC_PollForConversion(&hadc1, 10);
        ui16_RawTemp[ui8_AVGCounter] = HAL_ADC_GetValue(&hadc1);  // Read ADC register
        ui32_Temp = ui32_Temp + (uint32_t)ui16_RawTemp[ui8_AVGCounter]; // Sum all read values

        ui16_avgADC[0] = (uint16_t)(ui32_Temp / AVG_NUMBER);    // Calculate the average

        HAL_ADC_Stop(&hadc1);
    }

After some investigation, I added a delay in my loop and the result is much better. Readings are very stable now. But, 1ms delay is a lot!

Here is the adapted code snippet, with better results:

    // reading TEMP1_ADC on channel 5
    sConfig.Channel = ADC_CHANNEL_5;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5;
    sConfig.SingleDiff = ADC_SINGLE_ENDED;
    sConfig.OffsetNumber = ADC_OFFSET_NONE;
    sConfig.Offset = 0;

    ADC_HAL_ErrCode = HAL_ADC_ConfigChannel(&hadc1, &sConfig);
    if(ADC_HAL_ErrCode != HAL_OK) {
    .....
    }

    ui32_Temp = 0;
    for(ui8_AVGCounter=0; ui8_AVGCounter < AVG_NUMBER; ui8_AVGCounter++) {
        HAL_ADC_Start(&hadc1);
        HAL_ADC_PollForConversion(&hadc1, 10);
        ui32_RawTemp[ui8_AVGCounter] = HAL_ADC_GetValue(&hadc1);    // Read ADC register
        HAL_ADC_Stop(&hadc1);

        ui32_Temp = ui32_Temp + ui32_RawTemp[ui8_AVGCounter];   // Sum all read values

        vTaskDelay(1);
    }
    ui16_avgADC[0] = (uint16_t)((ui32_Temp + (0.5 * AVG_NUMBER)) / AVG_NUMBER); //Round number and Calculate the average

See the new output array:

New output values:

ui32_RawTemp[0]: 1855
ui32_RawTemp[1]: 1855
ui32_RawTemp[2]: 1855
ui32_RawTemp[3]: 1855
ui32_RawTemp[4]: 1855
ui32_RawTemp[5]: 1855
ui32_RawTemp[6]: 1855
ui32_RawTemp[7]: 1855
ui32_RawTemp[8]: 1856
ui32_RawTemp[9]: 1855

Questions are:

Upvotes: 0

Views: 1557

Answers (1)

0___________
0___________

Reputation: 68013

It is an obvious sign thet your ADC input circuit has too large impedance and the internal ADC capacitance is not loaded fast enough.

If you want to use shorter sampling times you need to lower it by changing the input circuit - for example by adding an operating amplifier (as a voltage repeater) .

Upvotes: 2

Related Questions