cancel
Showing results for 
Search instead for 
Did you mean: 

Measuring temperature - voltage is off by factor of 2ish

c_shearer_cooper
Associate III

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?

 

1 ACCEPTED SOLUTION

Accepted Solutions

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

 

View solution in original post

3 REPLIES 3
c_shearer_cooper
Associate III

Any ideas?

nouirakh
ST Employee

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

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