on
2024-01-30
04:00 AM
- edited on
2024-06-18
12:51 AM
by
Laurids_PETERSE
In some applications, specifically battery-powered ones, it is common for the supply voltage to drop as the battery discharges. Sometimes, both VDDA and VREF+ is powered directly by the battery. The problem with this is if the VDDA is based off of this battery voltage, then you may have difficulties to get precise voltage conversions from the ADC. This is due to the math that converts the raw ADC value to a voltage relies on knowing VDDA/VREF+.
One solution to this is to separate VDDA and VREF+, using an external LDO to drop the VREF+ voltage below the battery voltage. This is done to ensure that the LDO maintains a stable voltage for VREF+ even as the battery is close to discharged. On some packages, VDDA, and VREF+ are internally bonded, which removes this as a solution.
For those who do not want the following:
VREF internal can be used to calculate the voltage of VDDA in software.
As an example, I am using the STM32CubeMX/STM32CubeIDE with the NUCLEO-C031. However, this example generally applies to any STM32 with an internal VREF.
In CubeMX, we set up two channels: A channel of a voltage we want to read, and another channel, which is the VREF internal channel. We need to understand how long to sample the VREF internal channel. The datasheet for C031 shows that the internal reference voltage needs to be sampled for at least 4us. From DS13867, Table 27:
4u / (1 / 24M) = 96
Out of the available sampling time options, 160.5 cycles is the only option that is greater than or equal to 96. Therefore, we use that sampling time.
I am using the same sampling time for Channel 0, but you can feel free to use whatever sampling time you prefer for that channel. That is all for the CubeMX configuration and now we can generate code.
During factory programming, a calibration value of the raw ADC data of VREF internal at a known temperature and VDDA was collected and stored in ROM. From DS13867, Table 6:
Using this calibration value presented below, along with the measured VREF internal in the application, the VDDA can be calculated. The formula below was obtained from the C0x1 reference manual, RM0490 page 274:
The HAL libraries make the usage of VREF internal quite simple. In this example, I am using a simple polling method to get the ADC readings, but this could be implemented using interrupts or DMA as well.
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
// 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, 0xFFFF);
uint32_t vrefint_raw = HAL_ADC_GetValue(&hadc1);
/*
* Rank 2: measurement channel
*/
HAL_ADC_PollForConversion(&hadc1, 0xFFFF);
uint32_t measurement_raw = 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_raw, ADC_RESOLUTION_12B);
/*
* A helper function for doing a raw ADC value to voltage conversion, essentially
*
* vdda_voltage * measurement_raw / 2^12
*
*/
uint32_t measurement_voltage = __HAL_ADC_CALC_DATA_TO_VOLTAGE(vdda_voltage, measurement_raw, ADC_RESOLUTION_12B);
/* USER CODE END 2 */
In a situation where your application is battery powered, your VDDA voltage will drop over time as the battery discharges. If absolute voltage measurements are required regardless of VDDA's voltage, the internal reference voltage can be used to measure the voltage of VDDA. By using the measured voltage of VDDA in our ADC data conversions, precise voltage measurements can be made without a consistent VDDA.
Datasheet DS13867: STM32C031x4/x6 Arm Cortex®-M0+ 32-bit MCU
Reference Manual RM0490: STM32C0x1 advanced Arm®-based 32-bit MCUs