cancel
Showing results for 
Search instead for 
Did you mean: 

How to measure VBAT using ADC correctly in STM32U073RCT6 MCU

RB4020
Associate II

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?



 

1 REPLY 1
ELABI.1
ST Employee

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

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.