Skip to main content
Explorer
May 8, 2024
Solved

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

  • May 8, 2024
  • 6 replies
  • 3406 views

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.

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

    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!

    6 replies

    Graduate II
    May 8, 2024

    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?

    Graduate II
    May 8, 2024

    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.

     

    Fran9Author
    Explorer
    May 8, 2024

    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

    Graduate II
    May 8, 2024

    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();
    }
    

     

    Fran9Author
    Explorer
    May 8, 2024

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

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

    Graduate II
    May 8, 2024

    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

    Fran9AuthorAnswer
    Explorer
    May 10, 2024

    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!

    Super User
    May 10, 2024

    @Fran9 wrote:

    What must be taken into account is that the temperature measured is the internal temperature of the chip and not the superificial one


    Given that the sensor is internal to the chip, how could it measure anything other than the internal temperature of the chip?

    :thinking_face:

    Fran9Author
    Explorer
    May 10, 2024

    I measured the surface temperature.

    I have been modifying the chip temperature by external means so I could see how it varied. In this way I was able to make a small characterization of the temperature and understand the results I was seeing.