Skip to main content
Explorer
May 3, 2024
Solved

Measuring temperature - voltage is off by factor of 2ish

  • May 3, 2024
  • 2 replies
  • 1277 views

I'm running a STM32G474RET6 on a Nucleo G474RE board, and trying to read the internal temperature.

I set up ADC1 with 2 ranks (the temperature and the vrefint) like so (not including the error checking and comments for better readability):

 

hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.GainCompensation = 0;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 2;
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;

multimode.Mode = ADC_MODE_INDEPENDENT;
HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);

sConfig.Channel = ADC_CHANNEL_TEMPSENSOR_ADC1;
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;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

sConfig.Channel = ADC_CHANNEL_VREFINT;
sConfig.Rank = ADC_REGULAR_RANK_2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);

TemperatureData.StoredVolt = *((uint16_t *) 0x1FFF75AA);

HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);

 

 

I then read the 2 ADC values:

 

FirstADC = true;
HAL_ADC_Start_IT(hadc1);

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
 BaseType_t xHigherPriorityTaskWoke = pdFALSE;
 if (FirstADC)
 {
 TemperatureData.TempSensorRaw = HAL_ADC_GetValue(hadc);
 FirstADC = false;
 }
 else
 {
 TemperatureData.VoltRefRaw = HAL_ADC_GetValue(hadc);
 HAL_ADC_Stop_IT(hadc);
 TemperatureData.VoltRef = __HAL_ADC_CALC_VREFANALOG_VOLTAGE(TemperatureData.VoltRefRaw, hadc->Init.Resolution);
 TemperatureData.Temperature = __HAL_ADC_CALC_TEMPERATURE(TemperatureData.VoltRef, 
 TemperatureData.TempSensorRaw, hadc->Init.Resolution);
 TemperatureData.State = hadc->State;
 TemperatureData.ErrorCode = hadc->ErrorCode;
 TemperatureData.Success = true;
 }
 portYIELD_FROM_ISR( xHigherPriorityTaskWoke );
}

 

 

What I get back doesn't look bad, TemperatureData.StoredVolt is 1654 which is a little higher than it

should be but it's in the ballpark. What's strange is that TemperatureData.VoltRef is 3275 which is

about double what it should be.

 

What am I doing wrong?

 

    This topic has been closed for replies.
    Best answer by c_shearer_cooper

    Kholdoun -

    Thank you for your response, it took me a while to filter through it but the simple answer is:

    "__HAL_ADC_CALC_VREFANALOG_VOLTAGE does not return VREFINT, it returns VREF+"

    Chris

     

    2 replies

    Explorer
    May 8, 2024

    Any ideas?

    ST Employee
    May 9, 2024

    Hello @c_shearer_cooper

    The value calculated by the internal temperature sensor of the micro-controller is not supposed to be equivalent to the analog reference voltage VREF+. The analog reference voltage (VREF+) is used as the reference for ADC measurements, It's used to figure out what the highest numerical value that ADC can measure, while the internal temperature sensor value is a separate measurement that represents the internal temperature of the micro-controller using a specific formula that takes into account the reference voltage.

    Otherwise, The code will be structured as follows:

    #include "stm32g4xx_hal.h"
    
    // Assuming 'hadc' is the ADC handle and the ADC has been properly initialized
    
    // Start the ADC calibration
    HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED);
    
    // Configure the ADC to read the internal temperature sensor and VREFINT
    // ...
    
    // Start the ADC
    HAL_ADC_Start(&hadc);
    
    // Wait for the temperature sensor conversion to be finished
    HAL_ADC_PollForConversion(&hadc, HAL_MAX_DELAY);
    
    // Get the raw value from the temperature sensor
    uint32_t temp_sensor_raw = HAL_ADC_GetValue(&hadc);
    
    // Start the ADC again for VREFINT conversion
    HAL_ADC_Start(&hadc);
    
    // Wait for the VREFINT conversion to be finished
    HAL_ADC_PollForConversion(&hadc, HAL_MAX_DELAY);
    
    // Get the raw value from the VREFINT channel
    uint32_t vrefint_raw = HAL_ADC_GetValue(&hadc);
    
    // Stop the ADC
    HAL_ADC_Stop(&hadc);
    
    // Calculate the VREF+ voltage using the calibration value and the raw VREFINT value
    uint32_t vref_plus = __HAL_ADC_CALC_VREFANALOG_VOLTAGE(vrefint_raw, ADC_RESOLUTION_12B);
    
    // Calculate the temperature using the VREF+ voltage, the raw temperature sensor value, and the ADC resolution
    float temperature = __HAL_ADC_CALC_TEMPERATURE(vref_plus, temp_sensor_raw, ADC_RESOLUTION_12B);
    
    // Now 'vref_plus' contains the VREF+ voltage in millivolts, and 'temperature' contains the temperature in degrees Celsius

     
    With Regards,
    Kholdoun

    c_shearer_cooperAuthorAnswer
    Explorer
    May 10, 2024

    Kholdoun -

    Thank you for your response, it took me a while to filter through it but the simple answer is:

    "__HAL_ADC_CALC_VREFANALOG_VOLTAGE does not return VREFINT, it returns VREF+"

    Chris