The STM32F0 series of 32-bit ARM Cortex M0 microcontrollers contain a huge number of internal peripherals despite their low price starting at 0,32€ @1pc. Amongst them is an internal, factory-calibrated temperature sensor and a supply voltage sensor (that specifically senses VDDA, the analog supply voltage rail) connect to channels 16 and 17 of the internal ADC.
While I usually like the STM32 documentation, it was quite hard to implement code that produced realistic values. While the STM32F0 reference manual contains both formulas and a short section of example code, I believe that some aspects of the calculation are understated in the computation:
Section 13.9 in RM0091 provides a formula for computing the temperature from the raw temperature sensor output and the factory calibration values. However it is not stated anywhere (at least in Rev7, the current RM0091 revision) that this formula is only correct for a VDDA of exactly 3.30V.
The example code in section A.7.16 uses a normalization factor VDD_APPLI / VDD_CALIB that is applied directly to the temperature sensor raw output. However, VDD_APPLI is not documented anywhere and define to 300 while VDDA_CALIB is defined to 330.
After some experimentation I found out that you need to actually continously measure the supply voltage in order to properly normalize the temperature output. By doing this, you can normalize the raw temperature sensor output. When running at VDDA=3.0V, the computed temperature sensor output without applying said normalization is about -14°C for my test circuit while actually being at about 18°C.
Computing the internal supply voltage is essentially free when also computing the temperature because the VDD_APPLI / VDDA_CALIB ratio is required for accurate temperature monitoring anyway. Therefore, my code also contains functionality to get both the temperature sensor output and the voltage sensor output at the same time.
In contrast to the RM0091 example, my code computes the temperature in m°C, yielding a resolution three orders of magnitude higher than the ST code example. However, I suspect there are still inaccuracies introduced by inappropriate ordering of integral arithmetic operations.
In order to provide a well-documented reference, I implemented an easy-to-use codebase that continously senses both temperature and voltage at the same time. In order to provide high interoperability, I implemented the hardware-specific part using the ChibiOSHAL.
The code was tested on a custom board utilizing the STM32F030F4 (that is, at the time of writing this, the cheapest STM32 microcontroller I could find) and checked for accuracy using the Fluke 289 multimeter.
For other microcontrollers in the STM32F0 series, the addresses for the three calibration values might need to be adjusted (although I suspect they are the same at least for a series of microcontrollers). Larger controllers like the STM32F4 use a slightly different ADC configuration. Maybe I’ll create some hybrid code that also works for other families in the future.
The header file contains extensive documentation on the implementation details of the code. Note that without modifying the code, it is not possible to continously monitor the temperature/VDDA and use other ADC channels in the same program.
Disclaimer: I am not affiliated with ST microelectronics and/or any distributors in any way beyond sometimes buying their products.