Skip to main content
Associate III
June 8, 2024
Solved

Measuring VBAT on stm32wb55cgu with ADC

  • June 8, 2024
  • 1 reply
  • 3236 views

Hi,

i am currently trying to read out VBAT of a STM32WB55CGU6 Board (Custom).

VBAT is connected to a 3V Battery, and all other VDD pins are connected to the same battery since the board is only powered by this battery.

I have setup ADC1 and enabled the VBatChannel (at least in CubeMX).

My Question is how to read out the ADC Value of VBAT?

So far i have tried the following:

 

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 */

 /** Common config
 */
 hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_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.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.OversamplingMode = DISABLE;
 if (HAL_ADC_Init(&hadc1) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_VBAT;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN ADC1_Init 2 */

 /* USER CODE END ADC1_Init 2 */

}

 

AND:

 

 MX_GPIO_Init();
 MX_ADC1_Init();
 MX_I2C1_Init();
 MX_RTC_Init();
 MX_RF_Init();
 /* USER CODE BEGIN 2 */
 HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
 /* USER CODE END 2 */

 /* Init code for STM32_WPAN */
 MX_APPE_Init();

 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 // ADC starten und messen
 HAL_ADC_Start(&hadc1);
 if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK) {
 uint32_t adcValue = HAL_ADC_GetValue(&hadc1);
 float voltage = (adcValue / 4095.0) * 3.0;
 float percentage = (voltage / 3.0) * 100;
 printf("%.2f", percentage);
 /* USER CODE BEGIN 3 */
 }
 }

 

But it seems like this is wrong. At least i get values like 33% battery power at 3V VBat.

The raw adcValue is around 1165.

I have read that it is may needed to explicit enable VBAT with the flag VBATEN?

Where would i need to do it? Do you have an example line how this flag is set?

Thank you

 

My CubeMX ADC Config

Exeu_0-1717859518358.png

Clock configs:

Exeu_1-1717859989157.png

 

 

Best answer by AScha.3

>what hinders you to copy the code snippet above, add one or two lines and then the topic is through?

Perhaps your way of being grateful for offered help could influence my motivation.

>most likely a different platform is more sensible for that

Ask the Ai , it needs no motivation, so cannot loose motivation.

So this is your program ?

vbat = readadc(bla) * ?? * vref+?

 If "bla" is the refint channel you set with Cube , then :

HAL_ADC_Start(&hadc1);
while ((HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_READY) == 0);
// adc value = vrefint (1.212 V)
vbat = 1.212f * 4096 / (float) HAL_ADC_GetValue(&hadc1) ;

To get good/best precision, you have to adjust the "1.21" to 1.1x.. 1.3x , to match the real vbat you see on a DMM .

Note: It is recommended to perform a calibration after each power-up. (adc_ex_calibration_start(..))

1 reply

AScha.3
Super User
June 8, 2024

Hi,

 At least i get values like 33% battery power at 3V VBat.

see rm : ADC->VBAT

AScha3_0-1717866836600.png

So 1/3 vbat is perfect.. :)

 

BUT...you write:

VBAT is connected to a 3V Battery, and all other VDD pins are connected to the same battery since the board is only powered by this battery.

So also VREF+  to the ADC ? Then you always just check the 1/3 divider !

VREF+ has to be at a fix reference level, to check the supply or bat voltage, otherwise the adc-full-reference scales with the applied voltage and you can get no useful info.

So if leaving VREF+ at VBAT , measure the (fixed) internal voltage and calculate Vbat and Vref from this:

AScha3_1-1717867393339.png

read in rm...

"If you feel a post has answered your question, please click ""Accept as Solution""."
ExeuAuthor
Associate III
June 8, 2024

My MCU seems to not have a dedicated VREF+ pin. I am using the 48 pin package where this seems to be not present. Only in the bigger packages i can see a VREF+ pin.

Exeu_0-1717872528450.png

I didn't see the formula about VREF+ though, but if seeing this reading the manual does not bring me anything since i still don't know how to translate this into "code".

Where to get VREFINT_CAL and VREFINT_DATA from?

And what is VREF+_Charac ?

There is no example in the wide world of STM of how to do this. At least i couldn't find any

 

AScha.3
Super User
June 8, 2024

>Where to get VREFINT_CAL and VREFINT_DATA from?

>And what is VREF+_Charac ?

>There is no example in the wide world of STM of how to do this. At least i couldn't find any

Just - did you look at the rm at all ?  

The next lines after the Fig.91 (i showed) should tell it

AScha3_0-1717874397230.png

Again : read in rm...

next: see also register descriptions:

AScha3_1-1717874786343.png

 

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