cancel
Showing results for 
Search instead for 
Did you mean: 

I am having trouble getting a realistic Internal temperature sensor reading in STM32L476. I am following the formula in the datasheet but don't seem to get a temperature that makes since.

Aaron McNeil
Associate III

/* Private define ------------------------------------------------------------*/

/* USER CODE BEGIN PD */

uint16_t adcValue = 0;

#define TS30  ((uint16_t*)((uint32_t)0x1FFF75A8))

#define TS110  ((uint16_t*)((uint32_t)0x1FFF75CA));

float adcCalValue30;

float adcCalValue110;

float degC;

float degF;

/* USER CODE END PD */

/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){

 if (hadc->Instance == ADC1){

  adcValue = HAL_ADC_GetValue(&hadc1);

  HAL_ADC_Stop_IT(&hadc1);

  degC = 110.0 - 30.0;

  degC = degC / (adcCalValue110 - adcCalValue30);

  degC = degC * (adcValue - adcCalValue30);

  degC = degC + 30.0F;

  degF = degC * 1.8 + 32.0F;

 }

  

}

int main(void)

{

 /* USER CODE BEGIN 1 */

 /* USER CODE END 1 */

 /* MCU Configuration--------------------------------------------------------*/

 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

 HAL_Init();

 /* USER CODE BEGIN Init */

 /* USER CODE END Init */

 /* Configure the system clock */

 SystemClock_Config();

 /* USER CODE BEGIN SysInit */

 /* USER CODE END SysInit */

 /* Initialize all configured peripherals */

 MX_GPIO_Init();

 MX_ADC1_Init();

 /* Create the thread(s) */

 /* definition and creation of defaultTask */

 osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 512);

 defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

 adcCalValue30 = *TS30 * 1.1;

 adcCalValue110 = *TS110;

 adcCalValue110 = adcCalValue110 * 1.1;

 HAL_ADC_Start_IT(&hadc1);

/* Start scheduler */

 osKernelStart();

  

 /* We should never get here as control is now taken by the scheduler */

 /* Infinite loop */

 /* USER CODE BEGIN WHILE */

 while (1)

 {

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

 }

 /* USER CODE END 3 */

}

static void MX_ADC1_Init(void)

{

 /* USER CODE BEGIN ADC1_Init 0 */

 /* USER CODE END ADC1_Init 0 */

 /* USER CODE BEGIN ADC1_Init 1 */

 /* USER CODE END ADC1_Init 1 */

 /**Common config 

 */

 ADC_ChannelConfTypeDef sConfig;

 hadc1.Instance = ADC1;

 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;

 hadc1.Init.Resolution = ADC_RESOLUTION_12B;

 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

 hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;

 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

 hadc1.Init.LowPowerAutoWait = 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.OversamplingMode = DISABLE;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)

 {

  Error_Handler();

 }

 /**Configure Regular Channel 

 */

 sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;

 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;

 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

 {

  Error_Handler();

 }

 /* USER CODE BEGIN ADC1_Init 2 */

 /* USER CODE END ADC1_Init 2 */

}

/* USER CODE END Header_StartDefaultTask */

void StartDefaultTask(void const * argument)

{

 /* USER CODE BEGIN 5 */

 /* Infinite loop */

 for(;;)

 {

  osDelay(500);

  HAL_ADC_Start_IT(&hadc1);

 }

 /* USER CODE END 5 */ 

}

4 REPLIES 4
Jack Peacock_2
Senior III

Is your Vref voltage at exactly 3V, same as calibration data? I don;t see where you make any adjustment for the reference voltage on your board. Use the bandgap voltage reference to determine the exact Vref, then adjust the calibration data for whatever your voltage range is.

The ADC is ratiometric. Conversions are a percentage of the reference, not actual voltage. That's why there's a bandgap reference. Since it's a known voltage you can work backwards to determine Vref from the bandgap sample.

Jack Peacock

Aaron McNeil
Associate III
My Vref is actually 3.3V. I am taking this in account at this line:
adcCalValue30 = *TS30 * 1.1;
adcCalValue110 = *TS110;
adcCalValue110 = adcCalValue110 * 1.1;
Multiplying the calibration values by 1.1 (3.3/3).
I am wondering if the problem may actually be in the raw adc counts I am getting back. I get back around 840 counts at room temp. This is giving me a -50 degrees C calculation. So even if my Vref is slightly off I don't think it would account for that much of a difference.
Are my ADC setup parameters look okay for reading the internal temp sensor?
S.Ma
Principal

You can measure Vref and deduct the instant "3.3V" variations.

Did you calibrate the ADC?

And remember you are measuing the chip temperature, so its value should be higher when running full speed ahead....

Note: There are so frequent questions about Temp measurement that if no yet available, this should be part of ADC code example in Nucleo board libraries.

Aaron McNeil
Associate III
Yes I would expect my value to read higher than the room temp but instead I’m getting a raw analog count value of around 850 which translates to roughly -50 degrees C.