Reputation: 59
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:
Any explanation for this behavior?
Is something wrong in my code?
I noticed the first read is the most instable. Should I do something before the first ADC conversion?
Upvotes: 0
Views: 1557
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