Skip to main content
Visitor II
January 18, 2025
Question

How to measure VBAT using ADC correctly in STM32U073RCT6 MCU

  • January 18, 2025
  • 1 reply
  • 997 views

Hi everyone!
I'm having trouble in measuring the VBAT through ADC. I'm using a battery of 2.5V and when I measure VBAT through ADC, I'm getting values around 4000mV. 

Here's my code:

/**
  * @brief ADC1 Initialization Function
  * @PAram None
  * @retval None
  */
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_DIV1;
  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_160CYCLES_5;
  hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_1CYCLE_5;
  hadc1.Init.OversamplingMode = DISABLE;
  hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

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

  /* USER CODE END ADC1_Init 2 */

}

Note: I'm keeping the MCU in Stop2 Mode. So, I'm de-initializing the ADC every time I go to Stop2 mode.

void measure_voltage(){
    // Initialize ADC1
    HAL_ADC_Init(&hadc1);  

    // Always calibrate ADC first
    // HAL_ADCEx_Calibration_Start(&hadc1);

    // Start the conversion sequence
    HAL_ADC_Start(&hadc1);

    /*
     * Rank 1: vref internal
     */
    HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
    uint32_t vrefint_data = HAL_ADC_GetValue(&hadc1);

    /*
     * This macro calculates the vdda voltage (as a uint32_t representing the voltage in milliVolts)
     * using the vref internal raw adc value, and the internal calibration value in ROM
     */
    uint32_t vdda_voltage = __HAL_ADC_CALC_VREFANALOG_VOLTAGE(vrefint_data, ADC_RESOLUTION_12B);

    bat_vol = vdda_voltage;

    // Stop the conversion sequence
    HAL_ADC_Stop(&hadc1);

    // De-initialize ADC1
    HAL_ADC_DeInit(&hadc1);

    return;
}

Can anyone please tell me where I'm doing it wrong?



 

    This topic has been closed for replies.

    1 reply

    Technical Moderator
    February 27, 2025

    Hi @RB4020,

     

    First of all, please see this article "How to write your question to maximize your chances of finding a solution" to learn how to ask a question in the community and how to insert your code.

    I also only saw ADC_CHANNEL_VREFINT in your code, not ADC_CHANNEL_VBAT.

    VBAT would also be divided by 3, so the measured value must be multiplied by 3. Given that VREFINT has a value of 1.212V, this would give 3.636V, which is at least close to the value of 4.

    However, if you want to measure VBAT, VBATEN must be set (see the Reference Manual RM0503, specifically section 14.11 Battery voltage monitoring), which is not visible in your code.

    Thank you.

    ELABI.1