2024-05-03 09:06 AM - edited 2024-05-03 09:09 AM
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?
Solved! Go to Solution.
2024-05-10 10:46 AM
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
2024-05-08 11:09 AM
Any ideas?
2024-05-09 08:50 AM
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
2024-05-10 10:46 AM
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