Showing results for 
Search instead for 
Did you mean: 

STM32G051 ADC Calibration issue

Associate II

Hi I am using the STM23G051C8T6 for the internal RTC and an external battery on Vbat. I noticed if I perform the Calibration using the following line


my initial ADC reading will be lower then actual reading. For example will read 2.7 instead of 2.9. 


If I don't perform the Calibration I read the 2.9 correctly from the 1st measurement however subsequence measurements read higher. My ADC Config below.




static void MX_ADC1_Init(void)

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.LowPowerAutoPowerOff = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_12CYCLES_5;
  hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_12CYCLES_5;
  hadc1.Init.OversamplingMode = DISABLE;
  hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)

  /** Configure Regular Channel
  sConfig.Channel = ADC_CHANNEL_VBAT;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */




And my ADC Measurment code:



  ADC->CCR |= ADC_CCR_VBATEN; // Set Divide by 3 Bridge to Measure Voltage on Vbat

         HAL_ADC_Start(&hadc1); // Start ADC conversion
        // HAL_Delay(100);

         if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK) // Wait for conversion to complete
             adcValue = HAL_ADC_GetValue(&hadc1); // Read ADC value

             // Calculate voltage from ADC value
             battery_voltage_mv = ((float)adcValue / 4096.0f) * 3.04f * 3000;

        // HAL_Delay(100);
         ADC->CCR &= ~ADC_CCR_VBATEN; // Clear Divide by 3 Bridge to Vbat to reduce battery drain




Per the datasheet, VBAT has a minimum 12us sampling time. 12.5 cycles is almost assuredly not enough if you're using typical ADC clock speeds. Bump up the sampling time to max.



If you feel a post has answered your question, please click "Accept as Solution".

Hi Thank you for the reply. When I increase the sampling time I notice we hit the Actual Voltage right away but then in subsequent measurements we start measuring a Voltage Higher then the actual voltage. This is with Calibration. 

For example we will hit 2.9 quick then in future measurements we start measuring > 3.0


If I sample even Slower then initial Voltage is incorrect but future measurements bring it up to the correct voltage.


Any tips?





What it does when not calibrated, and what it does with <12 us sampling time is immaterial. Focus on what it does with proper calibration and with proper sampling duration.

Note the measurement is only as good as your VREF+. Sounds like this may be slow to come up. Check proper VDDA and VREF+ layout and voltage stability at the time of the measurements.

If you feel a post has answered your question, please click "Accept as Solution".