[STM32L431] Cannot monitor VBAT using ADC
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