cancel
Showing results for 
Search instead for 
Did you mean: 

Not the best ADC accuracy of STM32F0 even after calibration

Christian Wächter
Associate III
Posted on June 19, 2018 at 14:13

Hello everyone,

I'm currently trying to get as accurate ADC values as possible from a STM32F072. I'm using the NUCLEO-F072RB and wanted to use the internal stored reference voltage value for calibration. But I'm already off when I use this to calculate my actual VDDA for further ADC measurement. I double checked all my voltages with a calibrated multimeter and oscilloscope directly on the pins and with smalles possible ground loops. There are no spikes/drops in the voltage due to the ADC measurement and the ripple and noise is at around 5 mVpp. I also added 2x 10 nF and 1x 10 uF to C30 (100 nF) on AVDD on the nucleo. I tried all sampling times for the ADC without any change in the results and of course use 12-Bit. I do not want to read the value of the internal Vref-Voltage as it is not accurate (min 1.2V, typ 1.23V, max 1.25V).

So even after taking care of any possible error sources I'm getting a wrong value for my calculated AVDD voltage. I measured this with two multimeters to be 3.310V at 25�C. The calculated value from the STM32 is ~3.296 V, which is 14 mV off. This might be too much for measurements of voltages after a voltage divider, even when considering the 1% tolerance of the resistors. I read about a accuracy of ~1 mV (without voltage divider), so I'm curious how to achieve this when the reference value is not accurate.

This are parts of the code from the used test program:

// ADC self calibration, has to be done before any ADC Start/Enable

while(HAL_ADCEx_Calibration_Start(&hadc) != HAL_OK);

// values for calculation of actually VDDA-supply and reference voltage

volatile uint32_t VREFINT_CAL, VREF_3V3 = 330000;

const uint16_t *p = (uint16_t *)0x1FFFF7BA; // 2 Byte at this address is VRefInt @3.3V/30�C

VREFINT_CAL = *p; // read the value at pointer address

// Start ADC with DMA support

volatile uint16_t adc_value[4] = {0, 0, 0, 0};

HAL_ADC_Start_DMA(&hadc, (uint32_t*)adc_value, 4);

 

while (1)

{

   //toggle LED

   HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);

   HAL_Delay(50);

   // calculate 3.3 V supply voltage with the factory stored VREFINT_CAL value

   // adc_value[2] contains the raw ADC_IN17 value of the internal voltage reference (~1530)

   VREF_3V3 = (330000 * VREFINT_CAL) / adc_value[2];

   // VREFINT_CAL = 1529

   // adc_value[2] = 1530

   // VREF_3V3 = ~329568 (~3.29568 V calculated)

}

#accuracy #nucleo-f072rb #adc #calibration #stm32f0 #internal-voltage-reference
21 REPLIES 21

​First you have to de-initialize the ADC, setup a structure to pass to the ADC when initializing it, initialize it and then calibrate it.  I don't know why but the de-initialization is important...just make sure you reinitialize it prior to attempting to calibrate it.

I have a precision external reference.

4/4096 * 3.3 = 3.2 mV not 14 mV, so my performance is no good.

The stm32f072 doesn't have a Vrefin I believe?

Yeah, I may need to get a better external ADC.