Skip to main content
Explorer
July 23, 2025
Solved

STM32C011 invalid temerature read by ADC

  • July 23, 2025
  • 1 reply
  • 287 views

I've used CubeIDE 1.18.1 to create a small project based on a STM32C011F6. The ADC is configired thru Cube to read Vref+, temp sensor and another external voltage.
Cube has therefore created an init function MX_ADC1_Init which is called at during start

static void MX_ADC1_Init(void)
{

 /* USER CODE BEGIN ADC1_Init 0 */

 /* USER CODE END ADC1_Init 0 */

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC1_Init 1 */

 /* USER CODE END ADC1_Init 1 */

 /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
 */
 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.ScanConvMode = ADC_SCAN_SEQ_FIXED;
 hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
 hadc1.Init.LowPowerAutoWait = DISABLE;
 hadc1.Init.LowPowerAutoPowerOff = DISABLE;
 hadc1.Init.ContinuousConvMode = DISABLE;
 hadc1.Init.NbrOfConversion = 1;
 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.SamplingTimeCommon1 = ADC_SAMPLETIME_1CYCLE_5;
 hadc1.Init.OversamplingMode = DISABLE;
 hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
 if (HAL_ADC_Init(&hadc1) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_7;
 sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_VREFINT;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN ADC1_Init 2 */

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

 /* USER CODE END ADC1_Init 2 */

}

  
Later in the main-loop I read the ADC using DMA with this function

static void adc_read()
{
	uint32_t data[3];
	data[0] = 0xDEADBEEF; // TRQ_CNT/STL_TH
	data[1] = 0xDEADBEEF; // Vsense temperature
	data[2] = 0xDEADBEEF; // Vref reference voltage

	HAL_ADC_Start_DMA(&hadc1, data, LENOF(data));
	HAL_ADC_Start(&hadc1);
	if(HAL_ADC_PollForConversion(&hadc1, 500) != HAL_OK)
	{
	 Error_Handler();
	}

	/* Ref-1 16.10 : VREF = VREF_Nominal × VREFINT_CAL / VREFINT_DATA
	 */
	adc_vref = __LL_ADC_CALC_VREFANALOG_VOLTAGE(data[2], LL_ADC_RESOLUTION_12B);

	if ((adc_vref < 3200) || (3400 < adc_vref))
	{
	 Error_Handler();
	}

	/* Ref-2 5.3.16 Temperature sensor characteristics
	 * Average slope from VSENSE voltage [Avg_Slope] = 2.53mV/C -> 2530uV/C
	 * Voltage at 30°C (±5 °C) [V30] = 0.76V = 760mV Typ
	 *
	 * Sense_Data ADC voltage : sdv = (Vref × Sense_DATA) / 4095
	 * Temp sensor reference voltage @ RefTemp : trv = (TempVref × Cal1_DATA) / 4095
	 * Temperature in °C : t = (sdv - trv) / slope + RefTemp
	 */
	int32_t slope = 2530;
	//int32_t calx_v = 760;
	int32_t calx_v = (TEMPSENSOR_CAL_VREFANALOG * *TEMPSENSOR_CAL1_ADDR) / __LL_ADC_DIGITAL_SCALE(LL_ADC_RESOLUTION_12B);
	int32_t calx_t = TEMPSENSOR_CAL1_TEMP;
	adc_temp = __LL_ADC_CALC_TEMPERATURE_TYP_PARAMS(slope, calx_v,
			calx_t, adc_vref, data[1], LL_ADC_RESOLUTION_12B);

	/* Get TRQ_CNT/STL_TH in mV
	 * VCHANNELx = Vref × ADC-DATAx / ADC-Max-Value
	 */
	trq_cnt = __LL_ADC_CALC_DATA_TO_VOLTAGE(adc_vref, data[0], LL_ADC_RESOLUTION_12B);
}

Vref is tied to nominal +3.3V supply. So when I run this code I get the following ADC values

  • External voltage : 24
  • Vsense temperature : 119
  • Vref : 1513

By using Cube library macros I then get

  • adc_vref = 3293 which is very close to expected value
  • adc_temp = -234 which is not even close and approx 30C off expected value
  • trq_cnt (external source) = 19 which is very close to expetced value

ADC temp reading seems very off as temp sensor calibration ADC value at 30C (*TEMPSENSOR_CAL1_ADDR) and Vref = 3.0V is 1045.
 ADC_CCR::TSEN = 1 after init.

What could cause temperature sensor to return such an incorrect value?

One note about __LL_ADC_CALC_TEMPERATURE_TYP_PARAMS macro: 
Parameter __TEMPSENSOR_CALX_TEMP__ is described as

 * @PAram __TEMPSENSOR_CALX_TEMP__ Device datasheet data: Temperature at which temperature sensor voltage
 (see parameter above) is corresponding (unit: mV)

 (unit: mV) must be incorrect. Shouldn't it be (unit: C) ?

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

    > ADC_SAMPLETIME_1CYCLE_5

    This is not long enough. Increasing sampling time to max. See the datasheet for required minimum sampling duration.

    1 reply

    TDKAnswer
    Super User
    July 23, 2025

    > ADC_SAMPLETIME_1CYCLE_5

    This is not long enough. Increasing sampling time to max. See the datasheet for required minimum sampling duration.