Why am I getting wrong internal temperature values?
Using a Nucleo STM32F091RC board, I have configured the ADC to measure all channels in a sequence, i.e. all 10 ADC pins that particular chip has, and the 3 internal ones: temperature, vrefint, vbat.
I calibrated the ADC, waited the time before enabling as said in the errata, measured Vrefint a bunch of times (with only that channel in the sequence at that time, just in case MUXing might create slight crosstalk), calculate VDDA from the reference and the stored values from system memory.
When I meausre voltages on the 10 external pins, they seem all correct and reasonably accurate.
Vbat also looks ok. Vrefint also looks like that is said in the datasheet.
But the internal temperature is totally off.
It measures around 95 °C, but the MCU clearly feels less than human body temperature.
I have tried 3 things to calculate it:
- read the reference manual and implemented it myself. When that seemed wrong, as a sanity check, I
- looked whether the LL library had something, and indeed, it has the macro __LL_ADC_CALC_TEMPERATURE
- I looked in the appendix of the reference manual and found example code (see below)
All 3 variants get a totally unreasonable result around 95 degrees Celsius.
I checked with freezing spray on the MCU case, and indeed, after sprays a couple seconds, the measured / calculated temperature drops to almost half that, to then raise again to ~ 95°C after a few seconds.
So the temperature channel is definitely enabled, and it is the correct index in the conversion sequence.
Also note that I used the maximum available sampling time of 239.5 ADC ticks.
The ADC value I get there is roughly 1400. it's compensated for vdda already, without compensation iw would be roughly 1500.
Are those usual values for this temperature sensor output @ 3V3?
What the heck could still be wrong?
For reference, the code from the reference manual I used (almost verbatim, just omitting the reference voltage compensation as the result would be ~ 1 anyway - and yes, I also checked what my measured VDDA is - it is very close to the nominal 3300.).
static unsigned calc_tempr(int ADC_DR)
{
/* Temperature sensor calibration value address */
#define TEMP110_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7C2))
#define TEMP30_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7B8))
int32_t temperature; /* will contain the temperature in degrees Celsius */
temperature = ADC_DR - (int32_t) *TEMP30_CAL_ADDR;
temperature = temperature * (int32_t)(110 - 30);
temperature = temperature / (int32_t)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR);
temperature = temperature + 30;
return temperature;
}