cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 on-chip temperature sensor read different values when modifying system clock

Fran9
Associate II

Hi everyone,

As commented in the title, in our system we have two ways of working. At low speed (120MHz) and at high speed (480MHz). When reading the ADC3 (temperature sensor) depending on the mode (low or high speed) I get different values. 

When I work at low speed I can read values around 25º~30º (OK values) but when I read at high speed my values go around 40º~45º.

My config:

I'm using the ADC3 as a temperature sensor with a clock preescaler of SYNC_DIV4 which I understand that I'm taking the sample frequency from AHB.

I have seen that if I use the same SYNC but with another DIV(1 or 2) I obtain wrong values when usign low speed very similar like when working at high speed. But when using ASYNC option values always remain equal, for low speed OK but high speed Wrong.

In clock configuration I have configured the PLL2P to work with the ADC at 5,12Mhz. 

I attach here my configs:

My ADC configuration:

 

void MX_ADC3_Init(void)
{
  /* USER CODE BEGIN ADC3_Init 0 */
  /* USER CODE END ADC3_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC3_Init 1 */
  /* USER CODE END ADC3_Init 1 */

  /** Common config
  */
  hadc3.Instance = ADC3;
  hadc3.Init.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc3.Init.Resolution = ADC_RESOLUTION_16B;
  hadc3.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc3.Init.LowPowerAutoWait = DISABLE;
  hadc3.Init.ContinuousConvMode = DISABLE;
  hadc3.Init.NbrOfConversion = 1;
  hadc3.Init.DiscontinuousConvMode = DISABLE;
  hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc3.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
  hadc3.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc3.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  hadc3.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc3) != HAL_OK)
  {
    //Error_Handler(); //TODO
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  sConfig.OffsetSignedSaturation = DISABLE;
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
  {
    //Error_Handler(); //TODO
  }
  /* USER CODE BEGIN ADC3_Init 2 */
  /* USER CODE END ADC3_Init 2 */
}

 

Reading from ADC:

 

uint32_t readADC(ADC_TypeDef* ADC_instance) //TODO take channels into consideration
{
  uint32_t adc_value = 0;

  if (ADC_instance == ADC3) {
    if(HAL_ADCEx_Calibration_Start(&hadc3, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK){
      LOG_MESSAGE(ERROR_FILE, "ADC3 calibration failed");
    }
  
    if (HAL_ADC_Start(&hadc3) != HAL_OK){
      LOG_MESSAGE(ERROR_FILE, "ADC3 Start failed");
    }

    // Wait for the conversion to complete
    HAL_ADC_PollForConversion(&hadc3, HAL_ADC3_DELAY);

    // Read the converted value
    adc_value = HAL_ADC_GetValue(&hadc3);

    // Stop the ADC
    HAL_ADC_Stop(&hadc3);
  }
  return adc_value;
}

 

Conversion value.

int32_t readTemperature() {
    int32_t JTemp = 0x0;
    uint32_t raw_value = readADC(ADC_TEMPERATURE_SENSOR);

    JTemp = __HAL_ADC_CALC_TEMPERATURE(3300, raw_value, ADC_RESOLUTION_16B);
    PRINT_DBG_V(PRINTS_VERBOSITY_LOW, "Internal temperature: %ld degrees\r\n", JTemp);
    
    return JTemp;
}

Clock init configuration.

 

void systemClockInitConfig(void)
{
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};

  /* Supply configuration update enable */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  /* Configure the main internal regulator output voltage */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

#if defined(SYSTEM_LOW_POWER_120MHZ)
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
#endif

  /** Configure LSE Drive Capability */
  //HAL_PWR_EnableBkUpAccess();
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);

  /** Macro to configure the PLL clock source */
  __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSI);
  /* Initializes the RCC Oscillators according to the specified parameters in the RCC_OscInitTypeDef structure. */

  /* System clock is initialized using PLL as source */
  systemClockConfigure(SYSTEM_RCC_PLL_DIVN_LP, SYSTEM_RCC_FLASH_LATENCY_LP);

  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_SPI2
                              |RCC_PERIPHCLK_SAI1|RCC_PERIPHCLK_SDMMC|RCC_PERIPHCLK_SPI45
                              |RCC_PERIPHCLK_USB|RCC_PERIPHCLK_FMC|RCC_PERIPHCLK_ADC;
  PeriphClkInitStruct.PLL2.PLL2M = 32;
  PeriphClkInitStruct.PLL2.PLL2N = 256;
  PeriphClkInitStruct.PLL2.PLL2P = 100;
  PeriphClkInitStruct.PLL2.PLL2Q = 11;
  PeriphClkInitStruct.PLL2.PLL2R = 8;
  PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_1;
  PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
  PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
  PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2;
  PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_HCLK;
  PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL2;
  PeriphClkInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL2;
  PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL2;
  PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PLL2;
  PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
  PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C4|RCC_PERIPHCLK_I2C2
                                        |RCC_PERIPHCLK_USART6|RCC_PERIPHCLK_SPI6;
  PeriphClkInitStruct.PLL3.PLL3M = 16;
  PeriphClkInitStruct.PLL3.PLL3N = 64;
  PeriphClkInitStruct.PLL3.PLL3P = 50;
  PeriphClkInitStruct.PLL3.PLL3Q = 6;
  PeriphClkInitStruct.PLL3.PLL3R = 8;
  PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_2;
  PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
  PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
  PeriphClkInitStruct.I2c123ClockSelection = RCC_I2C1235CLKSOURCE_D2PCLK1;
  PeriphClkInitStruct.I2c4ClockSelection = RCC_I2C4CLKSOURCE_PLL3;
  PeriphClkInitStruct.Usart16ClockSelection = RCC_USART16CLKSOURCE_PLL3;
  PeriphClkInitStruct.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PLL3;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

  /** Enable USB Voltage detector */
  HAL_PWREx_EnableUSBVoltageDetector();
}

 

 Clock high speed configuration:

 

void systemClockHighSpeed(void) {
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /* Configure the main internal regulator output voltage */
#if defined(SYSTEM_LOW_POWER_120MHZ)
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
#endif

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0); // VOS0 is needed for 480MHz
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /* Change system clock to alternative source */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, SYSTEM_RCC_FLASH_LATENCY_HSI);

  /* Reconfigure PLL1 to achieve desire frequency and select it as system clock source */
  systemClockConfigure(SYSTEM_RCC_PLL_DIVN_HP, SYSTEM_RCC_FLASH_LATENCY_HP);

  /* Reconfigure peripherals and timers as needed */
  configTimPrescaler(TIM2, SYSTEM_RCC_TIM_PRESCALER_HP);
  configTimPrescaler(TIM8, SYSTEM_RCC_TIM_PRESCALER_HP);

  systemUpdateSysTick(); 

  /* WARNING! */
  /* Keep in mind that changing Sysclk can affect other peripherals, with a high risk in communication ones */
  /* At the moment, these could be affected: USART1 (Expansion), USART2 (BLE), USART6 (Scanner), I2C2 (Expansion) */

  return;
}

 

Do you have any idea where the problem may be coming from?

If you need more information I can add it without any problem.

Thank you in advance,

 

PS: I have read this post: https://community.st.com/t5/stm32-mcus-products/stm32h7-on-chip-temperature-sensor-reading-stable-on-y-revision/td-p/300107 but no answer for my problem.

1 ACCEPTED SOLUTION

Accepted Solutions
Fran9
Associate II

Hi,

Yes indeed I'm working at 480 MHz all the time.

In the end, with some tests I have been able to verify that the measured temperature is correct.
What must be taken into account is that the temperature measured is the internal temperature of the chip and not the superificial one.
That is why there is a difference of degrees between what the ADC measures and what I can measure externally. That's why when it marked 50º my finger didn't burn when I touched it at the beginning.

 

Thanks for your help!

View solution in original post

11 REPLIES 11
Uwe Bonnes
Principal II

Did you consider self heating bu the higher clock rate? Can you perhaps measure the IC temperature by some other mean to compare? Otherwise, do you still have sufficient sampling time for the temerature sensor at the higher frequency?

LCE
Principal

Probably too high sampling rate at high speed.

I would raise this one and also the clock divider:

sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;

For temperature measurement a much lower sampling rate / more cycles would be good enough, I'd say.

 

Fran9
Associate II

Yes I though the same as you two. But actually the freq of the ADC is the one defined here: isn't it?

 hadc3.Init.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4; 

So, I'm defining as a fADC = fAHB/4 = 60MHz (when in high speed). And if I'm in low speed 15MHz. (fAHB = Fclk/2)

I also tested to define a PLL clock of 30MHz and divide it by two an obtain the same 15MHz but with no luck.

I guess that temperature will up with high frequencies but reach to 50º I see too much and I'm not doing any code execution

LCE
Principal

I'm not doing any code execution

But do you set the CPU to sleep when there is "nothing to do" ?

Edit: just have it open, for H735:

/**
  * @brief Enters Sleep mode.
  *
  * @note In Sleep mode:
  *			- all I/O pins keep the same state as in Run mode.
  *			- the systick is stopped to avoid exit from this mode with
  *       		systick interrupt when used as time base for Timeout
  */
void CpuSleepMode(void)
{
#if( 0 )
	/* Set SLEEPONEXIT
	 *	wake up only on each second Systick,
	 *	set in SysTick_Handler()
	 */
	SCB->SCR |= (uint32_t)SCB_SCR_SLEEPONEXIT_Msk;
#endif

	/* for sleep statistics */
	/* NOTE:
	 *	__disable_irq() only prevents execution of ISR,
	 *	NOT the interrupt itself
	 */
	__disable_irq();
	u32CycAwakeSumLst = DWT->CYCCNT - u32CycAwakeStart;
	u64CycAwakeSumAll += (uint64_t)u32CycAwakeSumLst;

	/* ensure that all instructions done before entering SLEEP mode */
	__DSB();
	__ISB();

	/* request Wait For Interrupt -> SLEEP */
	__WFI();

	/* end sleep statistics */
	u32CycAwakeStart = DWT->CYCCNT;
	__enable_irq();
}

 

Fran9
Associate II

No! I'm hardcoding to work at 480MHz, no sleep.

I'm pending to measure the temperature with an external device.

Well, a rough measurement is a touch with the finger. 30 degree is warm, 40 hot and at 50 degrees you should and will retract your finger  immediate

I use a BMI160 for temperature measurement at it's 0.00195 C (1/512 th) resolution.

Many MEMs designs have temp sensors for calibration/characterizing purposes.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

@Fran9 wrote:

No! I'm hardcoding to work at 480MHz, no sleep.


Then your processor is constantly running at that speed!

 


@Fran9 wrote:

I'm not doing any code execution


Unless the processor is asleep, it is always executing at the full clock speed.

Fran9
Associate II

Hi,

Yes indeed I'm working at 480 MHz all the time.

In the end, with some tests I have been able to verify that the measured temperature is correct.
What must be taken into account is that the temperature measured is the internal temperature of the chip and not the superificial one.
That is why there is a difference of degrees between what the ADC measures and what I can measure externally. That's why when it marked 50º my finger didn't burn when I touched it at the beginning.

 

Thanks for your help!