cancel
Showing results for 
Search instead for 
Did you mean: 

Stm32L562 Internal Temperature sensor reading is not right?

chsriniv
Associate II
 

 

 

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

5 REPLIES 5
TDK
Guru

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

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.
chsriniv
Associate II

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

 

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.

> vdda = 3.4V

TS_CAL values are taken at 3.0 V per the datasheet.

TDK_0-1741966110921.png

So not the same.

Scale adc_temp_raw by 3.4 / 3.0 which gives 1021.

Put that in the calculation and you'll get a temp just under 30 C which is reasonable.

If you feel a post has answered your question, please click "Accept as Solution".