cancel
Showing results for 
Search instead for 
Did you mean: 

[STM32L431] Cannot monitor VBAT using ADC

TClar.18
Associate II

I am trying to read VBAT value through channel ADC1_IN18.

VBAT should be between 2.3 and 3.3V.

VREF+ pin is connected to VDDA=1.8V.

Values measured using ADC are linearly related to the real VBAT value, but I have not been able to get the exact value.

For example:

Real 2.8V : ADC=3583 (=4724mV)

Real 2.9V : ADC=3711 (=4893mV)

Real 3.0V : ADC=3839 (=5062mV)

Moreover, the 12-bit values are supposed to be [0-4095]. But the resolution I get when VBAT is slightly varying is not 1, ie the value read for the range [2.96 3.0]V is constant 3839, and the value read for the range [3.0 3.04] is constant 3903. I cannot explain this.

Here is the code :

#define VDD_APPLI                      ((float) 1800.0)    /* Value of analog voltage (unit: mV) */
#define RANGE_12BITS                   ((float) 4095.0)    /* Max value with a full range of 12 bits */
#define COMPUTATION_DIGITAL_12BITS_TO_VOLTAGE(ADC_DATA)                        \
				( ((ADC_DATA) * VDD_APPLI) / RANGE_12BITS)
#define COMPENSATE_VBAT_DIVIDER    		((float)3.0)         /* the converted digital value is on third of the VBAT voltage */
 
    uint16_t VoltReadValue = 0;
    ADC_ChannelConfTypeDef sConfig;
    
    // ADC init
    hadc1.Instance = ADC1;
    
    if (HAL_ADC_DeInit(&hadc1) != HAL_OK)
    {
        /* ADC de-initialization Error */
        Error_Handler();
    }
    hadc1.Init.ClockPrescaler        = ADC_CLOCK_ASYNC_DIV1;          /* Asynchronous clock mode, input ADC clock not divided */
    hadc1.Init.Resolution            = ADC_RESOLUTION_12B;            /* 12-bit resolution for converted data */
    hadc1.Init.DataAlign             = ADC_DATAALIGN_RIGHT;           /* Right-alignment for converted data */
    hadc1.Init.ScanConvMode          = DISABLE;                       /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
    hadc1.Init.EOCSelection          = ADC_EOC_SINGLE_CONV;           /* EOC flag picked-up to indicate conversion end */
    hadc1.Init.LowPowerAutoWait      = DISABLE;                       /* Auto-delayed conversion feature disabled */
    hadc1.Init.ContinuousConvMode    = DISABLE;                       /* Continuous mode disabled to have only 1 conversion at each conversion trig */
    hadc1.Init.NbrOfConversion       = 1;                             /* Parameter discarded because sequencer is disabled */
    hadc1.Init.DiscontinuousConvMode = DISABLE;                       /* Parameter discarded because sequencer is disabled */
    hadc1.Init.NbrOfDiscConversion   = 1;                             /* Parameter discarded because sequencer is disabled */
    hadc1.Init.ExternalTrigConv      = ADC_SOFTWARE_START;            /* Software start to trig the 1st conversion manually, without external event */
    hadc1.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */
    hadc1.Init.DMAContinuousRequests = DISABLE;                       /* DMA one-shot mode selected (not applied to this example) */
    hadc1.Init.Overrun               = ADC_OVR_DATA_OVERWRITTEN;      /* DR register is overwritten with the last conversion result in case of overrun */
    hadc1.Init.OversamplingMode      = DISABLE;                       /* No oversampling */
    if (HAL_ADC_Init(&hadc1) != HAL_OK) {
        Error_Handler();
    }
    
    // Channel init
    sConfig.Channel      = ADC_CHANNEL_VBAT;            /* Sampled channel number */
    sConfig.Rank         = ADC_REGULAR_RANK_1;          /* Rank of sampled channel number ADCx_CHANNEL */
    sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;    /* Sampling time (number of clock cycles unit) */
    sConfig.SingleDiff   = ADC_SINGLE_ENDED;            /* Single-ended input channel */
    sConfig.OffsetNumber = ADC_OFFSET_NONE;             /* No offset subtraction */ 
    sConfig.Offset = 0;                                 /* Parameter discarded because offset correction is disabled */
 
    /*##-2- Configure ADC regular channel ######################################*/
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    {
        /* Channel Configuration Error */
        Error_Handler();
    }
 
	/* Run the ADC calibration in single-ended mode */
    if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) != HAL_OK)
    {
        /* Calibration Error */
        Error_Handler();
    }
  
    /*##-3- Start the conversion process #######################################*/
    if (HAL_ADC_Start(&hadc1) != HAL_OK)
    {
        /* Start Conversation Error */
        Error_Handler();
    }
 
    /*##-4- Wait for the end of conversion #####################################*/
    /*  For simplicity reasons, this example is just waiting till the end of the
        conversion, but application may perform other tasks while conversion
        operation is ongoing. */
    if (HAL_ADC_PollForConversion(&hadc1, 10) != HAL_OK)
    {
        /* End Of Conversion flag not set on time */
        Error_Handler();
    }
    else
    {
        /* ADC conversion completed */
        /*##-5- Get the converted value of regular channel  ########################*/
        VoltReadValue = HAL_ADC_GetValue(&hadc1);
    }
 
	/* Convert Voltage value */
	uint32_t vbat_mV = (int)(COMPENSATE_VBAT_DIVIDER
			* COMPUTATION_DIGITAL_12BITS_TO_VOLTAGE((float )VoltReadValue));
	printf("ADC VBAT 12bits = %d\n", VoltReadValue);
 
    
    if(HAL_ADC_DeInit(&hadc1) != HAL_OK) {
        Error_Handler();
    }

The documentation lacks in explaining how to properly monitor VBAT voltage. I have also read about using VREFINT in this forum, but here also, I do not understand how it could help.

Does anyone have any clue about the issue?

Thanks,

Tristan

1 ACCEPTED SOLUTION

Accepted Solutions
TClar.18
Associate II

[RESOLVED] Thank you all for your answers!

I found out that VRef+ was not connected to proper Vdd... so hardware issue.

Then I could monitor vbat by implementing oversampling.

Works fine!

Tristan

View solution in original post

9 REPLIES 9
S.Ma
Principal

I think the VBAT supply pin is 3.3V and internally there is a switchable resistor divider before feeding the ADC.

I would guess that a very long sample time is required to get an ok value.

Maybe calibration of the ADC is also required to get offset right.

Check the datasheet electrical table for ADC and VBat measurement for possible clues.

> Real 3.0V : ADC=3839 (=5062mV)

How did you arrive to that number? My calculator says that (3839 / 4065) * 1.8V = 1.69V.

JW

TClar.18
Associate II

Thank you both.

waclaek.jan there is a divider /3 applied to VBAT signal before being read by the ADC (3.0V/3 = 1.0V) , so that the voltage is below VREF=1.8V. And so 1.69V*3 = 5.1V.

. I have not heard of any switchable resistor divider, can you please provide a reference?

Current sampling time is (1/8MHz) * 640.5 = 80us, while sampling time required to read VBAT is 12us (DS Table 78, p163).

The code I have provided here performs ADC calibration. Is there another calibration I need to do?

Ah I see, so you have already applied the correction for the "switchable divider" KIC ("the dot") is talking about.

It's a humm.

Read out and check/post the ADC registers content.

JW

TClar.18
Associate II

Please see below the ADC registers content after call to HAL_ADC_GetValue(), real VBAT is 3.0V.

Note that the data value is now DR=0x9ff=2559 (compared to the value 3839 above, for a real value of 3.0V).

Indeed, each time a hard reset occurs, values are changed but I still get linearly linked values (real/measured).

Otherwise, I have checked the registers content and it seems to behave as planned in the code (checked using RM0394).

0690X00000Arfb9QAB.png

I don't understand.

So, the ADC->DR register contains roughly the expected value, it's just that your program returns a different value?

JW

turboscrew
Senior III

Maybe you have errors? The code still calculates the value and prints it out.

turboscrew
Senior III

The numbers in the first posting seemed to match , if the divisor was not 3, but 1.7778.

 I think you could also try fixed point instead of float.

TClar.18
Associate II

[RESOLVED] Thank you all for your answers!

I found out that VRef+ was not connected to proper Vdd... so hardware issue.

Then I could monitor vbat by implementing oversampling.

Works fine!

Tristan