cancel
Showing results for 
Search instead for 
Did you mean: 

Wrong readout of STM32U575 Temperature Sensor

RLanz.2
Associate III

Hello,

Trying to read STMU575 Internal Temperature Sensor, we get wrong readout.
We need you advise on what is required to get correct temperature readouts from the STM32U575 temperature sensor.

A. We use ADC4 configured as follows:

RLanz2_0-1736414650287.png

B. The below detailed code, which runs periodically every ~1[sec], is responsible for the following:
1. Read the temperature sensor via the ADC.
2. Read the two calibration factors for 30 and 130 Celsius, and make two corrections due to:
    2.1 Reference voltage is 3.3V and not 3.0V.
    2.2 ADC4 is 12bits and not as ACD1 which is 14bits.
3. Convert the ADC readout using the corrected calibration factors and the formula, as in STM32U575 datasheet.

But on room temperature we get a readout of more than 50 Celsius!
Using a IR camera pointed to the STMU575 MCU we read less than 30 Celsius.
Note that the temperature readout did respond to heating by a blower (temperature increased by more than 20 degrees), but it took it more than 20[sec] to 'respond' and increase from more than 50 Celsius to more than 70 Celsius.

According to some related info I've found on Practical experience | Correctly measure temperature based on STM32U5 on-chip temperature sensor (see https://mcu.eetrend.com/content/2024/100578516.html),
the calibration factors values read from MCU EEPROM seem reasonable, and the conversion formula seems ok, and the problem is probably related to the temperature value readout from the sensor via the ADC.

The code is attached here:

 

#define hadc_mcu_temp_sens hadc4

 

uint16_t Read_Temperature(void)
{
uint16_t raw_adc_value;

HAL_ADC_Start(&hadc_mcu_temp_sens); // Start ADC conversion
if (HAL_ADC_PollForConversion(&hadc_mcu_temp_sens, ADC_MAX_DELAY_MS) == HAL_OK)
{
raw_adc_value = HAL_ADC_GetValue(&hadc_mcu_temp_sens); // Read ADC value
}
HAL_ADC_Stop(&hadc_mcu_temp_sens); // Stop ADC conversion
return raw_adc_value;
}

float Calculate_Temperature(uint16_t raw_adc_value)
{
uint16_t *TS_CAL1 = (uint16_t*) 0x0BFA0710; // Calibration @ 30°C
uint16_t *TS_CAL2 = (uint16_t*) 0x0BFA0742; // Calibration @ 130°C
float TS_CAL1_corrected = (((float)(*TS_CAL1))/4.0)*3.0/3.3;
float TS_CAL2_corrected = (((float)(*TS_CAL2))/4.0)*3.0/3.3;
float TS_CAL1_TEMP = 30.0; // Calibration temperature 1
float TS_CAL2_TEMP = 130.0; // Calibration temperature 2

float temp_calculated = ((TS_CAL2_TEMP - TS_CAL1_TEMP)/(TS_CAL2_corrected - TS_CAL1_corrected))*(raw_adc_value - TS_CAL1_corrected) + TS_CAL1_TEMP;
return temp_calculated;
}

float Get_Temperature(void)
{
uint16_t adc_value = Read_Temperature();
return Calculate_Temperature(adc_value);
}


Thank you!

4 REPLIES 4
KDJEM.1
ST Employee

Hello @RLanz.2 ,

The ADC4 can measure the temperature sensor output voltage. But calibration is only done by ADC1.

So, as ADC1 is 14 bit, you can use TS_CAL value to scale to 12 bit.

This is an example:

TS_CAL1 = 0x0EB5 => 3765 = 3.0 * (3765/16384) = 0.689392 V

TS_CAL2 = 0x137E => 4990 = 3.0 * (4990/16384) = 0.913696 V

So you can use this voltage as calibration value for the 12 bit.

Or you can just change the 14bit ADC conversion result to the 12bit ADC equivalent result just moving 2 bits

0x0EB5 = 0b0000 1110 1011 0101 => two bits right shift: 0b0000 0011 1010 1101           LSB 01 is removed. => 0x03AD

0x137E = 0x0001  0011 0111 1110 => two bits right shift: 0b0000 0100 1101 1111 but rounded at 2nd LSB will result 0b0000 0100 1110 0000 => 0x4E0 (if truncated 0x4DF).

I hope this example can clarify this use case.

Thank you.

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Please use the source code formatting button:

unsigned_char_array_0-1737724560289.png


Also make sure the ADC is calibrated and initialized and the proper channel is selected:
https://community.st.com/t5/stm32-mcus-products/stm32l431rct6-internal-temperature-value-too-high-when-using-dma/td-p/93414

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

Hello KDJEM.1

Thank you for a detailed reply, but as far as I can tell, these points are already addressed in the code snippet attached to my query.

Here is a revised more documented version of the code:

 

 

float calculate_mcu_temperature(uint16_t raw_adc_value)
{
    // Calibration factors - addresses:
    // Section 33.3 Table 298 in https://www.st.com/resource/en/reference_manual/rm0456-stm32u5-series-armbased-32bit-mcus-stmicroelectronics.pdf
    uint16_t *TS_CAL1 = (uint16_t*) 0x0BFA0710; // Calibration @ 30°C
    uint16_t *TS_CAL2 = (uint16_t*) 0x0BFA0742; // Calibration @ 130°C

    // Calibration factors - two corrections are required: see also https://mcu.eetrend.com/content/2024/100578516.html
    //
    // Correction due to ADC resolution:
    // Calibration data was set to a highest available resolution of ADC1 (14 bits). We use ADC4 (12 bits).
    // Thus need to scale 14bits to 12bits, to lower the resolution of the calibration data as well.
    // https://community.st.com/t5/stm32-mcus-products/stm32u575-temperature-sensor-adc4-calculation/td-p/758839
    //
    // Correction due to ADC reference voltage:
    // Calibration data was set for 3V, while the ADC reference voltage in STMU575 is 3.3V.
    // Thus the need to correct the factors to 3.3V.
    // Section 33.3 Table 298 in https://www.st.com/resource/en/reference_manual/rm0456-stm32u5-series-armbased-32bit-mcus-stmicroelectronics.pdf
    float TS_CAL1_corrected = (((float)(*TS_CAL1))/4.0)*3.0/3.3; // https://mcu.eetrend.com/content/2024/100578516.html
    float TS_CAL2_corrected = (((float)(*TS_CAL2))/4.0)*3.0/3.3; // https://mcu.eetrend.com/content/2024/100578516.html

    // Calibration temperatures
    float TS_CAL1_TEMP = 30.0;                 // Calibration temperature 1
    float TS_CAL2_TEMP = 130.0;                // Calibration temperature 2

    // Formula: Section 33.4.44 in https://www.st.com/resource/en/reference_manual/rm0456-stm32u5-series-armbased-32bit-mcus-stmicroelectronics.pdf
    float mcu_temp_calculated = ((TS_CAL2_TEMP - TS_CAL1_TEMP)/(TS_CAL2_corrected - TS_CAL1_corrected))*(raw_adc_value - TS_CAL1_corrected) + TS_CAL1_TEMP;
    return mcu_temp_calculated;
}

 

 

 

Thank you

 

Have you read my previous comment?

 

I recommend calculating a multiplier and offset once in an init function and then use those values in calculating the temperature.

 

I use this:

 

 

#define VREFINT_CAL_VREF_VOLT 		((float)VREFINT_CAL_VREF / 1000.0f)
#define FULL_SCALE 					(4095.0f) 		// according to reference manual page 448 (of another MCU) full scale is 2^n-1, not 2^n.


float VddaMultiplier;
float TemperatureMultiplierCPerV;
float TemperatureOffsetC;
	VddaMultiplier = (float) (*VREFINT_CAL_ADDR) * VREFINT_CAL_VREF_VOLT;
	TemperatureMultiplierCPerV = (TEMPSENSOR_CAL2_TEMP - TEMPSENSOR_CAL1_TEMP) / ((TEMPSENSOR_CAL_VREF_VOLT / FULL_SCALE) * (*TEMPSENSOR_CAL2_ADDR - *TEMPSENSOR_CAL1_ADDR));
	TemperatureOffsetC = TEMPSENSOR_CAL1_TEMP - ((TEMPSENSOR_CAL_VREF_VOLT / FULL_SCALE) * (*TEMPSENSOR_CAL1_ADDR) * TemperatureMultiplierCPerV);

 

 

 

In my case I use calculate the voltage using the factory calibration values of the internal reference voltage.
The advantage of this is that instead of converting the temperature calibration values to work with a different voltage I scale them to temperature per voltage and it will work with any reference voltage.

 

 

voltage * TemperatureMultiplierCPerV + TemperatureOffsetC;

 

 

 

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.