🌡️ Get temperature from STM32 internal temperature sensor (simple library)

Image

STM32 microcontroller has internal temperature sensor. This sensor is pretty roughly (±1.5 °C) and internally connected to on of ADC-channel, that makes possible easy get device temperature, that can be used without any additional components.

Image

How it works?

1) Configure ADC to get values from both Temperature Sensor andVrefInt channel.

Image

2) Get real VDDA (in my case it's equal to VREF+) voltage with VrefInt channel value (it will be around 3.3V for BlackPill). and then sensor's voltage (it will be around 0.76V at 25 °C).

3) Calculate temperature value with equation given in the Reference Manual:

Image

Constant value given in the Datasheet:

Image

Formula and constants

So, now we have:

Temperature = ((Vsense V25)/Avg_Slope) + 25.0 

Where:
Temperature – calculated sensor temperature [°C];
Vsense – measured sensor's voltage [V];
V25 – sensor's voltage at 25 °C [0.76V];
Avg_Slope – temperature coefficient (voltage per degree) [2.5mV/°C = 0.0025V/°C];

All we need, that measure sensor's voltage and find temperature by equation above!

STM32CubeIDE Project

1) Create new project:  New -> STM32 Project

Image

2) Choose microcontroller unit (note, that F0xx series may not have internal sensor): STM32F401CCU6

Image

3) Type any project name:

Image

 Cube Configuration

1) Enable debugger:  SYS -> Debug: Serial Wire

Image

2) Enable external crystal: RCC -> HSE: Crystal/Ceramic Resonator

Image

3) Set input frequency (typically on Black Board mounted 25MHZ crystal), type HCLK 84 MHz and press Enter, wait some time for resolving.

Image

4) Select Temperature Sensor Channel and Vrefint Channel (the second one is optional, it makes possible to know real chip supply voltage):

Image

5) Add new DMA request from ADC, direction must be from peripheral (ADC) to memory (RAM region), circular mode and Half Word (uint16_t) data width.

Image

6) Enable interrupt from ADC, that help us to know, then conversion is completed:

Image

7) Enable Scan Conversion ModeContinuous Conversion Mode and DMA Continuous Mode. Set two (Tmp CH and Ref CH) channels, the first should be Vrefint and the second is Sensor (can be in the order of your convenience) set maximum sampling time and Timer 3 Trigger Out event (this timer will start conversion):

Image

8) Select Internal Clock for TIM3 and set timer frequency, in my case it will be:

APB/((PSC+1)(ARR+1)) = 84000000/((840-1+1)(10000-1+1)) = 10 Hz

*APB1/APB2 frequency, depending on using timer (in my case both peripheral bus have the same frequency)

Thus, conversion will be turned 10 times per second.

Image

Programming

I make a simple library, just add include and source files in the previously created project (uart_printf not necessarily)

Image

1) Include libraries

  1.  
  2. /* USER CODE BEGIN Includes */
  3. #include "tmpsensor.h"
  4. #include "uart_printf.h"
  5. /* USER CODE END Includes */
  6.  

2) Create uint16_t (Half Word) array for raw data from ADC, double variable for temperature and another one variable for conversion completion flag. I do this with struct and typedef:

  1.  
  2. /* USER CODE BEGIN PV */
  3. typedef struct AdcValues{
  4. uint16_t Raw[2]; /* Raw values from ADC */
  5. double IntSensTmp; /* Temperature */
  6. }adcval_t;
  7. adcval_t Adc;
  8. typedef struct Flags
  9. {
  10. uint8_t ADCCMPLT;
  11. }flag_t;
  12. flag_t Flg = {0, };
  13. /* USER CODE END PV */
  14.  

4) Create macros, that help enable/disable all serial outputs:

  1.  
  2. /* USER CODE BEGIN PD */
  3. #define DBG_UART 1
  4. /* USER CODE END PD */
  5.  

5) Start ADC with DMA and then timer:

  1.  
  2. /* USER CODE BEGIN 2 */
  3. HAL_ADC_Start_DMA(&hadc1, (uint32_t*)Adc.Raw, 2);
  4. HAL_TIM_Base_Start(&htim3); /* This timer starts ADC conversion */
  5. /* USER CODE END 2 */
  6.  

6) When conversion is completed set variable-flag to positive value (you can do this in callback function of in the interrupt, file  stm32f4xx_it.c):

  1.  
  2. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
  3. {
  4. if(hadc->Instance == ADC1) /* Check if the interrupt comes from ACD1 */
  5. {
  6. /* Set flag to true */
  7. Flg.ADCCMPLT = 255;
  8. }
  9. }
  10.  

7)  In the main loop check conversion completion flag, and if it true put raw data to function, that return calculated temperature:

  1.  
  2. /* USER CODE BEGIN WHILE */
  3. while (1)
  4. {
  5. if (Flg.ADCCMPLT) /* Conversion completed, do calculations */
  6. {
  7. /* Temperature Sensor ADC-value, Reference Voltage ADC-value (if use) */
  8. Adc.IntSensTmp = TMPSENSOR_getTemperature(Adc.Raw[1], Adc.Raw[0]);
  9. #if(DBG_UART) /* Send data with UART2 */
  10. UART_Printf_Dbg("Reference: Adc.Raw[0] = %u\r\n", Adc.Raw[0]);
  11. UART_Printf_Dbg("Sensor: Adc.Raw[1] = %u\r\n", Adc.Raw[1]);
  12. UART_Printf_Dbg("Temperature: Adc.IntSensTmp = %.2f\r\n", Adc.IntSensTmp);
  13. #endif
  14. #if(DBG_UART) /* Delay */
  15. HAL_Delay(250);
  16. #endif
  17. Flg.ADCCMPLT = 0; /* Nullify flag */
  18. }/* USER CODE END WHILE */
  19.  

Debug

1) Right-click on project ->  Build Project

Image

Right-click on project ->  Debug As -> STM32 Cortex-M C/C++ Application:

Image

2) Open Live Variables (Ctrl + 3 for search) and add global variables (in out case it's struct Adc. Run program:

Image

Open structure and you will see data from ADC and calculated temperature value in Celsius degrees:

Image

3) If you use full code (with UART_Printf...) also you can open serial terminal into STM32CubeIDE and get debug data:

Image

Full Project

Full tested project for STM32CubeIDE you can get on GitHub:
➡️ https://github.com/Egoruch/Internal-Temperature-Sensor-STM32-HAL

Cube Monitor

CubeIDE so slow and can't do graphs without SWO, so I recommend try STM32CubeMonitor for real-time graphs (instruction will be here...).

Image

I added temperature variable and now it's displaying as a curve of time:

Image

Stress test

The hot-air gun help us to test STM32 under high temperatur:

Image

When chip temperature reaches 240°C-300°C data acquisition stops (apparently MCU resets?), and in a few seconds after heater removing work is being restored:

Image

Video

Conclusion

Of course, this internal sensor can't be used for measurement air temperature, because it's related to thermal link between microchip and board. So, you can use it for data-logging device environment state or just show measurements on the screen:

Image

15.76K
0
Tom 6 months ago #
Great tutorial, however i am having some issues with the timer:> SYSCLK/APB1/APB2 = 25MHz> PSC = 5000-1> AutoReloadReg 25000-1> No internal clock division> Auto-Reload Preload = FALSEThis is for 5000ms ADC conversion period.It seems to wait for 5s before executing the first ADC conversion, however then ADC conversion executes continuously.Do i have to explicitly reset the timer somewhere?Why is auto-reload preload set to false? (i tried enabling this however it has the same result)
0
Tom 6 months ago #
Replying to my previous comment — it was the ADC Continuous Conversion mode. I believe this should be disabled as we want the timer to initiate each conversion.Thats what worked for me.Cheers
0
simone gasparella 4 months ago #
hi… thanks a lot… reading some comment from ST they suggest to calibrate the internal sensor of thje mcu. Did you do that? Thanks
Cookies?