cancel
Showing results for 
Search instead for 
Did you mean: 

STM32C011 invalid temerature read by ADC

MWebj
Associate III

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) ?

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Super User

> ADC_SAMPLETIME_1CYCLE_5

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

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

View solution in original post

1 REPLY 1
TDK
Super User

> ADC_SAMPLETIME_1CYCLE_5

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

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