‎2022-03-30 09:30 PM
I've been testing the internal temperature sensor on STM32 Nucleo-L452RE.
Therefore, I am using the internal Macors as well as a self-build function to calculate the temperature. Both yield the same value, thus the same constant negative offset of roughly -6°C.
The offset appears over the whole temperature range of -40°C to 85°C. I have verified the temperature set in the climate chamber with several other sensors. I have checked everything I can think of. Maybe some of you can find the mistake I keep making in my code, which explains the strange behaviour.
Thank you in advance!
Best regards,
Jan
#include "main.h"
#include <stdio.h>
#include <stdlib.h>
ADC_HandleTypeDef hadc1;
UART_HandleTypeDef huart2;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_ADC1_Init(void);
#define TEMP_CAL2 110
#define TEMP_CAL1 30
#define TS_CAL1 ((uint16_t*) (0x1FFF75A8UL))
#define TS_CAL2 ((uint16_t*) (0x1FFF75CAUL))
#define VREFINTCAL ((uint16_t*)(0x1FFF75AAUL))
int ADCstep_temp=0;
int ADCstep_VBAT=0;
int ADCstep_VREF=0;
float tempf=0;
int tempi=0;
float VAPLI=3.475;
float VCALIB=3.00;
float VBAT=0;
float VREF=0;
int inc=0;
static void select_ADC_VBAT(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_VBAT;
sConfig.Rank = ADC_REGULAR_RANK_1;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
static void select_ADC_VREFINT(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_VREFINT;
sConfig.Rank = ADC_REGULAR_RANK_1;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
static void select_ADC_TEMP(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = ADC_REGULAR_RANK_1;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
void temp_meas(int inc)
{
HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_5);
HAL_Delay (100); /* Insert delay 100 ms */
select_ADC_TEMP();
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, ADC_TEMPSENSOR_DELAY_US); // Poll ADC1 Perihperal & TimeOut = 1mSec
ADCstep_temp=HAL_ADC_GetValue(&hadc1); // Read The ADC Conversion Result & Map It To PWM DutyCycle
HAL_ADC_Stop(&hadc1);
select_ADC_VBAT();
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, ADC_TEMPSENSOR_DELAY_US); // Poll ADC1 Perihperal & TimeOut = 1mSec
ADCstep_VBAT=HAL_ADC_GetValue(&hadc1); // Read The ADC Conversion Result & Map It To PWM DutyCycle
HAL_ADC_Stop(&hadc1);
select_ADC_VREFINT();
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, ADC_TEMPSENSOR_DELAY_US); // Poll ADC1 Perihperal & TimeOut = 1mSec
ADCstep_VREF=HAL_ADC_GetValue(&hadc1); // Read The ADC Conversion Result & Map It To PWM DutyCycle
HAL_ADC_Stop(&hadc1);
// VREF
VREF =3*(float)((int32_t) *(VREFINTCAL))/ADCstep_VREF;
// VBAT
VBAT =3*VREF*ADCstep_VBAT/4096;//Divider by 3
float TC1=(float)((int32_t) *(TS_CAL1));
float TC2=(float)((int32_t) *(TS_CAL2));
tempf = ((float)TEMP_CAL2-(float)TEMP_CAL1) / (TC2 - TC1) * (ADCstep_temp*VREF/VCALIB - TC1) + 30.0F;
tempi= __LL_ADC_CALC_TEMPERATURE(VREF,ADCstep_temp,ADC_RESOLUTION12b);
HAL_Delay(1000);
}
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_ADC1_Init();
while (1)
{
temp_meas(inc);
inc+=1;
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = 0;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
/** Enable MSI Auto calibration
*/
HAL_RCCEx_EnableMSIPLLMode();
}
/**
* @brief ADC1 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief USART2 Initialization Function
* @param None
* @retval None
*/
static void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : B1_Pin */
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : LD4_Pin */
GPIO_InitStruct.Pin = LD4_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD4_GPIO_Port, &GPIO_InitStruct);
}
...
Solved! Go to Solution.
‎2022-03-30 10:31 PM
(edited)
Try calibrating at the beginning of main:
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
see ch. 16.4.8 of ref. man. RM0394 Rev 4
hth
KnarfB
‎2022-03-30 10:08 PM
Maybe it's just the heat generated by the MCU itself, since I don't see any power-saving code this is probably it:
http://www.efton.sk/STM32/gotcha/g56.html
I mean, you can't expect to measure ambient temperature from within a power-consuming IC?
Thanks to Mr. Waclawek for this helpful website!
Edit: and I might expect that some calibration / adjustment might be necessary anyway.
It's a good start that there's a constant difference over all temperatures! 😉
‎2022-03-30 10:13 PM
Thanks for your quick answer! 🙂
However sorry... I have made a mistake in my description of the problem. Unfortunately, the offset is not positive, as falsely indicated by me (I have corrected the above post).
Your answer would have made absolute sense; that was also something that came to my mind at first. But I have never really heard of a chip, that cools itself 😉
‎2022-03-30 10:31 PM
(edited)
Try calibrating at the beginning of main:
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
see ch. 16.4.8 of ref. man. RM0394 Rev 4
hth
KnarfB
‎2022-03-30 10:44 PM
😅 Okay, 6 deg cooler, that makes quite a difference!
Try the calibration as KnarfB suggested, and / or try playing with the ADC parameters or do some filtering / averaging on your own.
‎2022-03-30 10:50 PM
Huge thanks to both of you, KnarfB and LCE!
The ADC Calibration seems to be the solution.
At roughly 23°C RT I am now getting 25°C, which looks totally fine to me, now. 🙂
I was under the wrong impression, that while using the formula, which took into account all calibration data considering the temperature sensor, I would not have to perform other calibration measures.