# š”ļø Get temperature from STM32 internal temperature sensor (simple library)

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.

## How it works?

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

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:

Constant value given in the Datasheet:

### 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

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

3) Type any project name:

## Ā Cube Configuration

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

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

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

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

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.

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

7) Enable Scan Conversion Mode,Ā Continuous 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):

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.

## Programming

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

1) Include libraries

` /* USER CODE BEGIN Includes */#include "tmpsensor.h"#include "uart_printf.h"/* USER CODE END Includes */ `

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:

` /* USER CODE BEGIN PV */typedef struct AdcValues{uint16_t Raw[2]; /* Raw values from ADC */double IntSensTmp; /* Temperature */}adcval_t;adcval_t Adc;typedef struct Flags{uint8_t ADCCMPLT;}flag_t;flag_t Flg = {0, };/* USER CODE END PV */ `

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

` /* USER CODE BEGIN PD */#define DBG_UART 1/* USER CODE END PD */ `

5) Start ADC with DMA and then timer:

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

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):

` void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){    if(hadc->Instance == ADC1) /* Check if the interrupt comes from ACD1 */    {    /* Set flag to true */    Flg.ADCCMPLT = 255;    }} `

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

` /* USER CODE BEGIN WHILE */  while (1)  {if (Flg.ADCCMPLT) /* Conversion completed, do calculations */{/* Temperature Sensor ADC-value, Reference Voltage ADC-value (if use) */Adc.IntSensTmp = TMPSENSOR_getTemperature(Adc.Raw[1], Adc.Raw[0]);#if(DBG_UART) /* Send data with UART2 */UART_Printf_Dbg("Reference: Adc.Raw[0] = %u\r\n", Adc.Raw[0]);UART_Printf_Dbg("Sensor: Adc.Raw[1] = %u\r\n", Adc.Raw[1]);UART_Printf_Dbg("Temperature: Adc.IntSensTmp = %.2fā\r\n", Adc.IntSensTmp);#endif#if(DBG_UART) /* Delay */HAL_Delay(250);#endifFlg.ADCCMPLT = 0; /* Nullify flag */}/* USER CODE END WHILE */ `

## Debug

1) Right-click on project ->Ā  Build Project

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

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

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

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

## 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...).

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

## Stress test

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

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:

## 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:

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