How to accurately measure VDDA? I'm of by 5%. All ADC measurements are too low.
I supply my STM32G4 with 3.3V.
The 3.3V is more like 3.246 Volt.
The VREF+ is connected externally to VDDA, which is connected to the 3.246V.
My VREFINT_CAL_ADDR is 1662. On the Vref channel of the ADC I measure 1465, so I calculated 3.4034V for VDDA. This is 4.8% too high.
I would expect a more accurate value. I use an Agilent bench multimeter.
My regular multimeter is off by less than 1% from the bench, so it is definitely the ADC that is not accurate.
On another channel I measure a voltage from an opamp.
The measurement is 15% lower than what I measure with my multimeter.
I've initally had the ADC clock set to 32MHZ, but I lowered it to the lowest value possible and it didn't make a difference.
static const float VddaNumerator = float(*VREFINT_CAL_ADDR)*VREFINT_CAL_VREF/1000;
[[maybe_unused]] static bool testAdc()
{
ADC_ChannelConfTypeDef sConfig = {0};
uint16_t value;
float voltage;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
printf("VREFINT_CAL_ADDR: %d\n", *VREFINT_CAL_ADDR);
sConfig.Channel = LL_ADC_CHANNEL_VREFINT; // internal reference voltage, measured with VDDA/VREF+
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
HAL_ADC_Stop(&hadc1);
value = HAL_ADC_GetValue(&hadc1);
printf("ADC channel VREFINT: %d\n", value);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
HAL_ADC_Stop(&hadc1);
value = HAL_ADC_GetValue(&hadc1);
printf("ADC channel VREFINT: %d\n", value);
if(value != 0)
{
float vdda = VddaNumerator/value;
printf("VDDA: %0.4f\n", vdda);
sConfig.Channel = ADC_CHANNEL_1; // 0-10V channel
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
HAL_ADC_Stop(&hadc1);
value = HAL_ADC_GetValue(&hadc1);
printf("ADC channel 1: %d\n", value);
voltage = float(value) * ((112.0f/12.0)*(3.3f/(4095))) ;
printf("ADC channel 1 voltage: %0.3f V\n", voltage);
voltage = float(value) * vdda * ((112.0f/12.0)/(4095));
printf("ADC channel 1 voltage calibrated: %0.3f V\n", voltage);
}
return true;
}