HomeSTM32 TutorialsSTM32 ADC SeriesSTM32 ADC Tutorial (Part 10): Using ADC Reference Voltage

Understanding ADC Reference Voltage in STM32

The reference voltage plays a critical role in the accuracy and stability of ADC conversions on STM32 microcontrollers. Whether you are relying on the internal VREFINT or providing an external reference through VREF+, understanding how it works is essential for designing reliable embedded systems. In this tutorial, we’ll explore different reference voltage options, learn how they affect ADC measurements, and see practical examples of measuring VDD and VREF on popular STM32 boards. By the end, you’ll know how to configure and use reference voltages effectively in your own projects.

Recommended Resources:

This is the 10th tutorial in the STM32 ADC series. In the previous tutorials we covered how to configure the ADC in STM32 F1, F4 and F7 series and how to use it in the single channel polling, interrupt and DMA modes to read the potentiometer data. We have also covered the Multiple channels in DMA Normal Mode, Circular Mode and Multiple Channels with DMA.

STM32 ADC Reference Voltage Video

While the written guide below provides all the details and code for reference, sometimes a visual demonstration can make all the difference. I’ve created a complete video walkthrough that runs through the entire process in real-time. Follow the written steps here while watching the implementation in the video to solidify your understanding and catch any subtle details

Watch the Video

What is ADC Reference Voltage in STM32?

The ADC (Analog-to-Digital Converter) in STM32 microcontrollers converts an analog signal into a digital value. This conversion process depends on a reference voltage, which defines the maximum input level the ADC can measure. In simple terms, the reference voltage (VREF) sets the upper limit of the ADC input range. Any input voltage equal to VREF is converted to the maximum digital output (e.g., 4095 for a 12-bit ADC), while 0V corresponds to a digital output of zero.

Importance of Reference Voltage in ADC Conversions

The accuracy and resolution of an ADC reading are directly tied to the chosen reference voltage. If the reference voltage is unstable or noisy, the resulting ADC values will also fluctuate. For example, with a 12-bit ADC and a 3.3V reference, the smallest step size (LSB) is:

This means every ADC count represents about 0.8 mV of input change. If VREF drifts, this resolution is no longer reliable. Therefore, a clean and stable reference voltage is crucial for precise sensor measurements, battery monitoring, or any analog signal processing.


Internal vs External Reference Voltage

STM32 devices provide two ways to define the ADC reference voltage:

  • Internal Reference Voltage (VREFINT):
    STM32 includes a built-in, factory-calibrated reference (typically 1.2V). It is highly stable and useful for calibration tasks, such as measuring VDD or verifying ADC accuracy. However, since it is fixed, it may not cover the full input range for certain applications.
  • External Reference Voltage (VREF+ Pin):
    Many STM32 MCUs allow an external reference voltage to be supplied through the VREF+ pin. This gives designers flexibility to use a high-precision voltage source, especially in applications that demand very accurate ADC measurements. For instance, using a 2.5V precision reference IC can significantly improve measurement consistency.

In practice, the choice between internal and external reference voltage depends on the application requirements. For general-purpose tasks, the internal reference is often sufficient. But for high-precision measurements, an external reference is usually the preferred option.

Understanding ADC Reference Voltage Pins in STM32

The availability of Vref pin is needed to provide the external reference voltage. While some MCUs have a separate Vref pin, others has it connected with the VDDA. We will see both types in this tutorial.

Let’s first see the types of voltages related to analog circuitry in STM32.

STM32 ADC reference voltage diagram illustrating VREF+, VREFINT, VDDA, and VSSA connections for accurate analog-to-digital conversions.

VDD and VSS are the main supply voltages. Most of the STM32 MCUs can run between 1.8V ~ 3.3V VDD. When powered normally, they run at 3.3V.

VDDA and VSSA is the separate analog supply and it is used to power the analog circuits in the MCU. Some of the STM32 MCUs has separate pins for VDDA/VSSA, but almost in all the development boards it is connected to the VDD. Although there is an option to make some hardware modification to separate these pins from the VDD.

Vref+ and Vref- are used to provide external reference voltage. These pins are also not available in all the MCUs, but wherever they are available, they are tied to VDDA by default. We again have an option to separate them from VDDA by making some hardware changes.

VREFINT is the fixed internal reference voltage. This voltage does not vary with the VDD and remains fixed even if the VDD drops to 1.8V. Hence it can be used to measure the voltage supply on the Vref+ pin or even the VDD, if the Vref+ is connected to VDD.

The parameters like availability of physical Vref+ pin, its connection with VDDA or VDD changes according to the design of the development board. For the same MCU, one dev board can have the Vref+ tied to the VDDA to VDD, while the other could have a separate Vref+ and a separate VDDA. Therefore while focussing on the MCUs, we will also see the schematic of the dev board.

Measuring VDD in F446RE

Let’s start with the Nucleo F446RE. Below is the image from the datasheet of F446RE showing the pin availabilities in different MCUs.

Vref pin availability in different STM32 F446 series MCUs

As you can see above:

  • On the 144-pin STM32 package, VREF+, VDDA, and VSSA are all available as separate pins.
  • In contrast, the 100-pin package exposes only VREF+ and VDDA as individual pins.
  • For the Nucleo F446RE, which uses the LQFP64 package, VREF+ is internally connected to VDDA, so they are not separate.

Below is the image from the schematic of the nucleo F446RE.

Nucleo F446RE schematic showing Vref pin is connected to VDD

Although VDDA/VREF+ is a separate pin on the Nucleo F446, it is connected to VDD in the schematic above. You could separate it by removing the SB57 jumper, allowing an independent external reference voltage.

In this tutorial, we won’t modify the board. Instead, we will vary VDD, which automatically varies VDDA and VREF+ because they are tied together. The internal reference voltage (VREFINT) can then be used to measure VREF+, which effectively allows us to measure VDD directly.

Why Measuring VDD is Important

  • Scenario: The MCU is powered by a 3.3V battery.
  • ADC Reference: ADC uses VDD (3.3V) as the reference voltage.
  • Problem: As the battery discharges, VDD drops (e.g., to 2V).
    • If the ADC input is 2V, the ADC output will give the maximum digital value.
    • Using the old 3.3V reference in calculations would incorrectly interpret the input voltage as 3.3V.

Solution

  1. Periodically measure VDD using the internal reference (VREFINT).
  2. Update the ADC formula with the current VDD:

Here, VREF​ = measured VDD. This ensures accurate voltage readings even as battery voltage changes.


STM32 ADC CubeMX Configuration

STM32F4 ADC VrefINT Configuration

I have enabled the Vrefint channel in ADC1. There is another channel (channel 0) configured as well to measure the input voltage. I have enabled DMA, so multiple conversions can be done.

While configuring the Vrefint channel, the care must be taken to choose the sampling time. As per the datasheet of the MCU, the sampling time for this channel should be at least 10us.

STM32 ADC Vrefint Sampling Time

As shown in the image above, the Vrefint is around 1.21V. There is also calibration data for the internal reference voltage stored in the memory. The calibration was done at VDDA = 3.3V.


Measuring VREFINT with STM32 ADC: Example Code

uint16_t ADC_VAL[2];
int voltage;
int vref = 0;
#define Vref_CAL *VREFINT_CAL_ADDR

The array ADC_VAL[2] will be used to store the Raw ADC values. The variable vref will store the reference voltage or VDD (in this case) whereas the variable voltage will store the ADC input voltage on channel 0.

The Vref_CAL will fetch the internal reference calibration data from the memory.


int main ()
{
  ....
  HAL_ADC_Start_DMA(&hadc1, ADC_VAL, 2);
  while (1){}
}

Inside the main function we will simply start the ADC in DMA mode. The Raw data will be stored in the array ADC_VAL and here we are converting 2 channels.


Once both the conversions are finished, an interrupt will trigger and the HAL_ADC_ConvCpltCallback will be called.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
	vref = 3300*Vref_CAL/ADC_VAL[0];
	voltage = ADC_VAL[1]*vref/4095;
}

Inside this callback we will first calculate the Vref/VDD using the calibrated value. The calibration was done at 3.3V, hence the value 3300 is used here.

Then using this Vref we will calculate the input voltage to the ADC.


ADC VREFINT Measurement Result

In order to provide the variable supply voltage to the nucleo F446, we need to first remove its main supply from the ST link.

Necleo F446

The Highlighted Jumper on the nucleo board allows it to receive the power from the ST link. So we need to remove this jumper and then provide supply on the 5V pin of the board. You can provide it on any 5V pin of the board.

Below are the images showing the result of the project. Here I am providing the supply voltage of 2V to the nucleo board. You can see the Vref is also showing the same value around 200mV.

STM32 ADC Vref Measured
  • The first image shows when the ADC input voltage is 0.5V, the live expression shows the same voltage 499mV. Also note that the ADC Raw value is 1047 for this 0.5V input.
  • The second image shows when the ADC input voltage is 2V, the live expression shows the same voltage 1997mV. The ADC Raw value is 4095 for this 2V input.

The ADC in STM32 is typically a 12-bit converter, which means it produces digital values ranging from 0 to 4095. These values correspond to the input voltage relative to the reference voltage (VREF).
For example, if the reference voltage is 2V, the ADC output will span the full range (0–4095) for input voltages between 0V and 2V. This means that even a small change in input voltage—for instance, a 2V variation—can result in the ADC value jumping from 0 to 4095.

Now, imagine we assume a fixed reference voltage of 3.3V in our calculations, without actually measuring VREF. If the real input is 2V, the ADC will still output the maximum digital value (4095) because it’s scaled to the actual VREF (2V). However, if we calculate the input voltage using 3.3V as the reference, the formula will incorrectly interpret the 2V input as 3.3V.

In other words, not accounting for the actual reference voltage leads to significant measurement errors, especially when VREF varies due to factors like battery voltage drops or an unmodified development board. This is why measuring VREF (or VDD when VDDA/VREF+ is tied to it) is critical for accurate ADC readings.

We can also use this method to monitor the VDD and set a kind of alarm system to indicate the low voltage of the battery.


How ADC Value Depends on VREF

The ADC output is calculated using: STM32 ADC calculation using VREF

  • VIN = input voltage
  • VREF = reference voltage (VREF+)
  • n = ADC resolution (12-bit → 4096 steps)

Example:

  • Suppose VREF=2VVREF = 2VVREF=2V, 12-bit ADC: STM32 ADC calculation using VREF
  • Input voltage VIN = 2V = 2V → ADC output = 4095 (maximum).
  • If we assume VREF = 3.3V in calculations: STM32 ADC calculated value
  • The 2V input is incorrectly interpreted as 3.3V.
How ADC Value depends on VREF.

Measuring VREF in STM32H750

We saw that on nucleo F446 the Vref pin is connected to the VDDA, which is then connected to the VDD. Hence we were able to measure the VDD using the Vrefint channel. Now we will take a look at the H750 Based Custom Development Board. It has separate pins for Vref and VDDA, therefore we will use the Vrefint to calculate the actual variable Vref this time, while keeping the VDD constant.

Below is the image showing the schematic of this board.

ADC Vref pin on STM32 H750

The Red Line shows the connection of the Vref+ to 3.3V. Whereas the Green line shows the connection of VDDA to 3.3V. There is a 0 Ohm Resistor (R11), which can be removed to make the Vref+ an independent pin. I did the same on this board and now the Vref+ can be used to provide an external reference voltage for the ADC.

ADC Vref pin on STM32 H750

STM32 ADC CubeMX Configuration

Below is the configuration for Vrefint channel.

STM32 ADC Vrefint Configuration

The Vrefint channel is available in ADC3. I have disabled the continuous conversion mode and we will read this channel in the blocking mode.

While configuring the Vrefint channel, the care must be taken to choose the sampling time. As per the datasheet of the MCU, the sampling time for this channel should be at least 4.3us.

STM32 ADC Vrefint H750

As shown in the image above, the Vrefint is around 1.216V. There is also calibration data for the internal reference voltage stored in the memory. The calibration was done at VDDA = 3.3V.

Below is the image showing the configuration for ADC input channel.

ADC Configuration H750

I have enabled ADC1 channel 3 in single ended mode. We will provide the variable input voltage on this pin. The ADC is configured in Circular DMA mode, so the data reading will continue on its own.


Measuring VREFINT with STM32 ADC: Example Code

uint16_t ADC_VAL[2];
int voltage;
int vref = 0;
#define Vref_CAL *VREFINT_CAL_ADDR

The array ADC_VAL[2] will be used to store the Raw ADC values. The variable vref will store the reference voltage or VDD (in this case) whereas the variable voltage will store the ADC input voltage on channel 0.

The Vref_CAL will fetch the internal reference calibration data from the memory.


volatile int isDone =0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
	isDone = 1;
}

When the ADC finished the conversion and the data is transferred via the DMA, the ConvCpltCallback will be called. Inside this callback we will simply set the variable isDone. The data will be processed in the while loop.


int main(void)
{
  ....
  ....
  HAL_ADC_Start_DMA(&hadc1, &ADC_VAL[0], 1);
  while (1)
  {
	  HAL_ADC_Start(&hadc3);
	  HAL_ADC_PollForConversion(&hadc3, 10);
	  ADC_VAL[1] = HAL_ADC_GetValue(&hadc3);
	  HAL_ADC_Stop(&hadc3);
	  vref = 3300*vref_cal/ADC_VAL[1];
	  if (isDone)
	  {
		  voltage = ADC_VAL[0]*vref/65535;
		  isDone = 0;
	  }
	  HAL_Delay(250);
  }
}

Inside the main function, we will start the ADC1 in the DMA mode. The ADC Raw value will be stored in the 0th position of the ADC_VAL array.

Inside the while loop, we will read the ADC channel 3 in the blocking mode. The ADC Raw data for this Vrefint channel will be stored in the 1st position of the ADC_VAL array.
Then calculate the Vref using the calibrated value. The calibration was done at 3.3V, hence the value 3300 is used here.

Then we will check if the ADC1 has finished converting channel 3. If it did, we will calculate the input voltage using the vref value we just calculated.

Basically we are first calculating the Vref using internal reference voltage, and then using this Vref as the reference voltage for the ADC input. Therefore if the Vref varies on Vref+ pin, our ADC input will be measured as according to the updated voltage.


ADC VREFINT Measurement Result

The following images demonstrate the results of measuring the internal reference voltage (VREFINT) and the ADC input on the STM32 H750. These results validate both the ADC configuration and the accuracy of the measured voltages.

STM32 H750 Vrefint measurement with 2V external reference

In the image above, the external supply on the VREF+ pin is approximately 2V. The live measurement confirms this, showing the voltage variable correctly reflecting the applied voltage. When the ADC input is 0.6V, the voltage variable reads 625 mV, demonstrating accurate conversion and calibration.

STM32 H750 Vrefint measurement with 2V input

When the input voltage is increased to 2V, the live voltage variable matches the input, confirming that the ADC accurately reflects the applied voltage. The corresponding raw ADC value reaches near the maximum of 65535, showing full utilization of the 16-bit ADC range.

Using a custom reference voltage is particularly important when working with sensors that output voltages lower than the standard 3.3V. For example, if a sensor outputs between 0 and 2V, setting VREF+ to 2V ensures the ADC uses its full resolution for this input range. This maximizes measurement precision and avoids wasting ADC steps.

While it is possible to use a standard 3.3V reference for a 0–2V sensor, doing so would limit the effective resolution to less than two-thirds of the ADC’s full range, reducing accuracy. Custom reference voltages allow you to scale the ADC input range optimally for your specific sensor or application.

Internal Reference Voltage (VREFINT)

Some of the STM32 MCUs has a peripheral to generate the custom Reference voltage on the Vref+ pin. This can be achieved by using the peripheral Analog Voltage Reference Buffer, VREFBUF.

The VREFBUF is supplied via the VDDA pin. When enabled, it can provide a reference voltage in the range of: 1.65V, 1,8V, 2.048V or 2.5V. The VREFBUF can be used to provide an analog voltage reference for:

  • ADC internal peripheral
  • External components through the dedicated VREF+ pin.

The VREFBUF can be left unused. In this case, an external voltage regulator can provide reference voltage to VREF+ pin.

Even though the VREF+ pin can be used to provide the voltage to external component, note that the current supply in very limited on this pin, approximately around 4mA.


Below is the image showing the configuration for the VREFBUF.

VREFBUF cubeMX Configuration

I have configured the VREFBUF Mode as Internal Voltage Reference. In this mode the VREFBUF generates a custom reference voltage on VREF+ pin.

There are multiple voltage output options available on this MCU. I am selecting the 1.5V Output Voltage.

Note that the VREF+ pin is automatically configured as VREFBUF_OUT. We can even use this pin to power our sensor, but remember that the current output is very low (around 4mA).


Result

Although we do not need to measure the VREF now, since we are using VREFBUF to generate it. But I am keeping the code same, so that we can get an idea if the voltage generated is same.

Also I have removed the external power supply from this Vref+ pin.

Below is the image showing the result of this project.

VREFBUF Measurement

You can see the Vref is measured as 1500mV, which is the same as generated by the VREFBUF. Also note that we are able to measure the input voltage using this internally generated reference voltage.

Conclusion

In this tutorial, we explored how the STM32 ADC measures the internal reference voltage (VREFINT) and how the reference voltage affects ADC accuracy. We saw that using the internal reference or a custom external VREF can significantly improve measurement precision, especially when the supply voltage varies or when working with sensors that output voltages lower than 3.3V.

Accurately measuring VDD or VREF+ ensures that your ADC calculations reflect the true input voltage, preventing errors that could occur if a fixed reference voltage is assumed. This approach is particularly important for battery-powered designs or applications where sensor outputs do not match the standard reference voltage.

Check out our other STM32 ADC tutorials below to continue learning about ADC configurations, input channels, calibration, and advanced techniques.

Browse More STM32 ADC Tutorials

STM32 ADC VREF Project Download

Info

You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.

STM32 ADC Vref FAQs

Subscribe
Notify of

0 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments