Skip to main content
Associate II
March 14, 2025
Question

Stm32L562 Internal Temperature sensor reading is not right?

 

 

 

float read_internal_temperature(void)
{
 uint32_t adcValue;
 float temperature;

 // Configure ADC channel for temperature sensor
 ADC_ChannelConfTypeDef sConfig = {0};
 sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);

 // Start conversion and wait for it to complete
 HAL_ADC_Start(&hadc1);
 HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);

 // Read ADC value
 adcValue = HAL_ADC_GetValue(&hadc1);

 // Retrieve calibration values from system memory
 uint16_t ts_cal1 = TS_CAL1; // Calibration value at 30°C
 uint16_t ts_cal2 = TS_CAL2; // Calibration value at 110°C

 // Calculate the slope between TS_CAL1 and TS_CAL2
 float slope = (float)(ts_cal2 - ts_cal1) / (110.0f - 30.0f);

 // Calculate the temperature
 temperature = 30.0f + ((float)(adcValue - ts_cal1) / slope);

 // Stop ADC to save power
 HAL_ADC_Stop(&hadc1);

 return temperature;
}

 

 

The adcValue returns very low value although I am using a 12 bit resolutio

This topic has been closed for replies.

5 replies

TDK
March 14, 2025

Do you calibrate the ADC on startup?

Does your VREF+ match what was used for TS_CALx? (in datasheet)

"If you feel a post has answered your question, please click ""Accept as Solution""."
unsigned_char_array
Lead III
March 14, 2025

Isn't TS_CAL1 an address? You need to de-reference it first. Also I would invert the slope calculation so you only need to multiply instead of dividing.
If your VREF voltage is not the same you need to scale your voltage or the CAL values.

"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."
chsrinivAuthor
Associate II
March 14, 2025

Thanks all for your help!

I confirm my Vref match the CAL values in my data sheet.

Initial ADC calibration

static void MX_ADC1_Init(void)
{
 /* USER CODE BEGIN ADC1_Init 0 */

 /* USER CODE END ADC1_Init 0 */

 ADC_MultiModeTypeDef multimode = {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_DIV1;
 hadc1.Init.Resolution = ADC_RESOLUTION_12B;
 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE; // Enable scan mode for multiple channels
 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
 hadc1.Init.LowPowerAutoWait = DISABLE;
 hadc1.Init.ContinuousConvMode = DISABLE;
 hadc1.Init.NbrOfConversion = 2; // Two conversions (Temp sensor and VREFINT)
 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;
 hadc1.Init.DFSDMConfig = ADC_DFSDM_MODE_DISABLE;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure the ADC multi-mode
 */
 multimode.Mode = ADC_MODE_INDEPENDENT;
 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel for Temperature Sensor (ADC_CHANNEL_TEMPSENSOR)
 */
 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();
 }

 /** Configure Regular Channel for VREFINT (ADC_CHANNEL_VREFINT)
 */
 sConfig.Channel = ADC_CHANNEL_VREFINT;
 sConfig.Rank = ADC_REGULAR_RANK_2; // Second conversion
 sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

 /* USER CODE BEGIN ADC1_Init 2 */

 /* USER CODE END ADC1_Init 2 */
}

My temperature reading code

float read_internal_temperature(void)
{
	uint32_t adc_vref_raw;
	uint32_t adc_temp_raw;


	// Start the ADC conversion
	HAL_ADC_Start(&hadc1);

	// Wait for conversion to complete for Temperature channel
	HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
	adc_temp_raw = HAL_ADC_GetValue(&hadc1); // Temperature sensor value

	// Wait for conversion to complete for VREFINT channel
	HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); // Ensure the next channel is ready
	adc_vref_raw = HAL_ADC_GetValue(&hadc1); // VREFINT value

	// Retrieve calibration values for temperature sensor and VREFINT
	uint16_t ts_cal1 = (*TEMPSENSOR_CAL1_ADDR); // Calibration at 30°C
	uint16_t ts_cal2 = (*TEMPSENSOR_CAL2_ADDR); // Calibration at 110°C
	uint16_t vrefint_cal = (*VREFINT_CAL_ADDR); // VREFINT calibration

	// Calculate VDDA (the reference voltage)
	float vdda = (3.0 * vrefint_cal) / adc_vref_raw;

	// Calculate temperature based on calibration values
	float slope = (float)(ts_cal2 - ts_cal1) / (110.0f - 30.0f);
	float temperature = 30.0f + ((float)(adc_temp_raw - ts_cal1) / slope);

	// Stop the ADC conversion
	HAL_ADC_Stop(&hadc1);

	// You now have the calibrated temperature and VDDA (reference voltage)
	return temperature;
}

 Final Output:

adc_temp_raw = 901 -> again too low
adc_vref_raw = 1443
ts_cal1 = 1040
ts_cal2 = 1384
vrefint_cal = 1657
vdda = 3.4V

 

unsigned_char_array
Lead III
March 14, 2025

You are not calibrating your ADC in MX_ADC1_Init(). A common mistake.
Use HAL_ADCEx_Calibration_Start() or LL_ADC_StartCalibration().
Also wait after calibration before starting: https://community.st.com/t5/stm32-mcus-products/adc-register-adrdy-never-sets-when-i-enable-the-adc-so-it-keeps/m-p/106159#M17007

"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."