STM32 Vref
STM32 Vref
The main issue with VREF generally is, that there are many "references" involved in related
texts, and there's not a single unified nomenclature for them. ST often uses confusing
nomenclature and their formulae are sometimes written from an impractical point of view,
increasing the confusion. So let's just derive ours.
Let's introduce a convention, where dimensionless units (i.e. ADC readings, although
sometimes their units are called "bins") are written in capital letters, and voltages (in, ehm,
volts... :-) 1) in lowercase.
The ADC physically works using voltage between VREF+ and VREF- pins. On most packages,
VREF- is internally tied hard to common ground (namely VSSA), and even if it is brought out to
pin on the largest packages, it is required to be tied to VSSA externally. VREF+ is brought out
on larger packages as separate pin, but on most packages it is connected to VDDA2.
Let's denote this VREF+/VDDA reference voltage vrefext.
If any arbitrary voltage vmeas is connected to ADC pin and ADC measurement is taken, with
the readout result of MEAS, the formula to calculate the voltage from the readout is
vmeas = vrefext * MEAS / MAX (1)
where MAX is ADC reading for input voltage equal to reference voltage, i.e. number
of ADC bins = 2^resolution - 13. For most STM32 ADCs are 12-bits so MAX = 4095, but note,
that in some STM32 models the ADC resolution is adjustable, so it should not be taken as a
constant.
Now the problem is, that for this formula to work we need to know the vrefext voltage (i.e.
voltage at VREF+/VDDA pins), and it's not always the case, e.g. when the power supply is
derived from a battery and we don't want to use an external voltage reference chip.
So we have an internal reference in the STM32 (another "reference" to increase the confusion).
That's a supposedly stable (i.e. invariant in whole operation temperature range, supply voltage
range, time) "bandgap" reference; but its voltage is subject to semiconductor manufacturing
process variations, that's why there is a factory calibration for it (see below). In many STM32 it
cannot be used directly as the reference for the ADC (which, as said above, is tied to VREF+ or
VREF+/VDDA pins)4, so if we don't have a precise enough external reference on VREF+ (or
VREF+/VDDA) with known-to-us voltage, we can utilize this "bandgap" reference to indirectly
establish VREF+/VDDA voltage by measuring the "bandgap" reference output and then use the
internal calibration to calculate the VREF+/VDDA voltage.
So, let's denote the actual voltage of the internal "bandgap" reference vrefint, let's connect it
to the ADC (by setting the appropriate register controlling ADC MUX), and let's take an ADC
readout, REFINT. Then, applying and reversing eq.(1), we can calculate ADC's external
reference vrefext as
vrefext = vrefint * MAX / REFINT (2)
This assumes vrefint is a known value, and while there is a typical value for it in the datasheet
and we can use it as it is, for increased precision, we want to know its voltage as precisely as
possible, as it's actual value is process dependent. ST did a measurement for us when
manufacturing the chip, using a precise external reference voltage on the VREF+ pin, and
stored the resulting ADC reading into the system memory, let's denote it CAL (it's denoted in
different ways in different STM32 datasheets, e.g. VREFINT for 'L476, VREFINT_CAL for 'F042,
or VREFIN_CAL for 'F4xx). The voltage used as external reference at calibration, let's denote it
vcal, depends on the particular STM32 model, usually one of 3.0V or 3.3V, see the same spot
in datasheet where the address of calibration value is given. Again, applying eq.(1) for the
moment when the calibration was taken at the factory
vrefint = vcal * CAL / MAX (3)
2
and for the actual temperature measurement, according to (4)
vtemp = vcal * TEMP / MAX * CAL / REFINT (9)
Substituting (7) to (9) into (6), and considering that the factory calibrations were taken at the
same VREF+/VDDA reference voltage (see datasheets) i.e. vcal = vtempcal, we can eliminate
vcal/MAX, obtaining the resulting formula
temperature =
t1 + (t2 - t1) * (TEMP*CAL/REFINT - TEMP1) / (TEMP2 - TEMP1) (10)
where t1 and t2 are the temperatures at which calibration values were taken (i.e. usually
t1 = 30°C and t2 = 110°C, TEMP is the ADC reading taken for our actual temperature; CAL
is the internal reference calibration value read out of system memory (from VREFINT_CAL or
similarly sounding address, see text above); REFINT is the ADC reading taken for the internal
voltage reference; TEMP1/TEMP2 are the temperature calibration values read out from
system memory (from TS_CAL1/TS_CAL2 addresses).
We can again perform the calculation in floating point, or keeping things integer, we would
reorganize the formula as
temperature = t1 + (t2 - t1) * (TEMP * CAL - TEMP1 * REFINT) / (REFINT * (TEMP2 - TEMP1))
Given TEMP * CAL is roughly 23 bits and (t2 - t1) is 7 bits, this formula should not overflow in
32-bit arithmetics. Caution should be exercised though, observing rules for integer promotions
in C, as signed variables have to be used, given the result may be negative.
In case, when vrefext (i.e. voltage on VDDA/VREF+) is known (e.g. derived from a precise
external voltage reference chip) and it's not desired to derive it from the internal reference,
from (1)
vtemp = vrefext * TEMP / MAX (10)
We substite this together with (7) and (8) into (6), and, again eliminating vtempcal/MAX, we
obtain
temperature =
t1 + (t2 - t1) * (vrefext/vtempcal*TEMP - TEMP1) / (TEMP2 - TEMP1) (11)
Note, that both the temperature sensor's output, and the ADC itself, are relatively noisy, as
they work in close vicinity of heavy digital circuitry, often sharing ground, so there are several
paths how digital noise impacts the analog measurements. Without any special consideration,
it's not uncommon to see ADC noise in the range of several tens of bins, i.e. 1/100 of the
range, i.e. a few tens of mV. As the temperature sensor's slope is typically 2.5 mV/°C, it's not
uncommon to see the raw calculated temperature to vary within cca 10°C, which is quite a lot.
So, for reasonable temperature readings, it is vital not only to maintain all usual precautions
for good ADC readings (i.e. careful ground layout, heavy VDDA/VREF+filtering, reducing digital
activity (e.g. going to sleep during ADC conversions) etc.); but also some of the usual filtering
techniques (e.g. averaging) should be considered.
1 This may sound funny in English, but in many languages, the expression for "voltage" (which is often
akin to "potential" or "tension") does not have the name of the unit, i.e. "volt", in it. In fact, English is
the exception rather than rule in this.
2 In the older STM32 families (such as 'F1, 'L1, 'F2, upper-end 'F4, 'F7) generally, the separate VREF+
pin starts to appear at package sizes having 100 pins and above (there may be a few exceptions,
mainly in BGA-style packages at around 60 pins). The 'F0 family has no model with separate VREF+
pin. Generally, the smallest packages with separate VREF+ pin start at 48 pins - from the "non-G"
families, only 'F401Cx comes in QFN48 with separate VREF+, and the same 'F401Cx and some 'L0xx
models in BGA-style (Wafer-Level, WLxxx). However, in the 'G0 and 'G4 families, there are plenty of
models starting at 48 pins with separate VREF+, even in QFP packages.
3
3 Many texts use in this place 2^resolution instead of 2^resolution - 1,i.e. for 12-bit ADC they divide
the readout by 4096 rather than by 4095. Which one is more accurate?
Strictly speaking, none of these; but as we'll show, it does not really matter.
4096 would appear more appropriate as there are indeed 4096 "bins"; however, that would never
result in output voltage equal to Vref, so that speaks in favour of 4095.
Let's for brevity denote resolution as N. In fact, the ADC splits the whole V ref range into 2^N bins, so
the K-th bin corresponds to voltages between K*V ref/2^N and (K+1)*Vref/2^N, so it is appropriate to
take middle of that interval and write that ADC readout K corresponds to (2K+1)/2*Vref/2^N with
error of ±Vref/(2*2^N).
The simplified formula which still does output Vref at the high end is K*Vref/(2^N-1) The difference
between this and the "exact" formula above is Vref*(2^N-1-2K)/(2*2^N*(2^N-1)). This is a linear
function of K, crossing zero at K=(2^N-1)/2 thus for the practical range of K having absolute maxima
at both K=0 and K=2^N-1, both being Vref/(2*2^N) in value. Note, that that's exactly what's the
uncertainty of the "exact" formula above is, that's why the difference does not really matter, and we
can use the simplified formula safely.
One more, and maybe more valid, reason, why the simplified formula can be used, is, that all
practical ADCs have inaccuracies (nonlinearities) higher than one bin, i.e. higher than Vref/2^N.
4 In some STM32 models (e.g. 'L4, 'H7, 'G0, 'G4), there's a VREFBUF module which allows to output
the internal voltage reference to the VREF+ pin (in packages where it's not tied to VDDA internally).
If the precision of the VREFBUF output given in datasheet is considered appropriate, eq.(1) could be
simply used; however, the described calibration process against the internal reference still can be
utilized if it yields higher measurement precision.
5 It may come as a surprise, that vrefext i.e. the actual VREF+/VDDA voltage, is not present in this
formula. The reason for that is, that both the actual input volrage measurement and the internal
reference measurement are ratiometric i.e. relative to vrefext, and putting them into ratio we indeed
eliminate vrefext. However, as the two measurements are not taken in the same moment of time,
for this all to work properly, it must be ensured, that vrefext, while unknown in value, remains
stable.