cancel
Showing results for 
Search instead for 
Did you mean: 

Measure HSE using TIM17

rb1
Associate II

We are using the STM32H753ZI and to test if the LSE and HSE have the correct frequency, we want to measure it's frequency using TIM16 and TIM17.

We managed to measure the frequency of the LSE using the internal input capture of TIM16 but when we tried to measure the HSE, nu capture interrupts where generated. After a lot of searching in the reference manual and reading topics on the internet, setting the clocksource of the RTC to HSE seemed to do the trick. Now there were capture interrupts generated on TIM17.

But there are still some thing not clear to us:

  • Why does the clock source of the RTC have to be HSE in order to measure the HSE frequency using the input capture of TIM17? The reference manual doesn't clarify this.
  • What does HSE_1MHz mean of TIM17_TISEL on page 1862 of RM0433 Rev 7? Does it mean the HSE_RTC clock has to be 1 MHz? Why not just write HSE?

We tried to find the answers in the reference manual but with no success. The code below was used (we used a CubeMX project to test only the problem with the settings from our own code).

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#define REQUIRED_NUMBER_OF_INPUT_CAPTURES 20
 
static uint8_t NofInputCaptures = 0xFF;
static uint16_t InputCaptureValues[(REQUIRED_NUMBER_OF_INPUT_CAPTURES + 1)];
 
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{       
  if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
  {
    if(NofInputCaptures < (REQUIRED_NUMBER_OF_INPUT_CAPTURES + 1))
    {
      InputCaptureValues[NofInputCaptures++] = __HAL_TIM_GET_COMPARE(htim, TIM_CHANNEL_1);
    }
  }
}
 
static uint32_t GetFrequency(TIM_TypeDef* TIMx)
{
  uint32_t ClockPeriodValue = 0;
  
  for(uint8_t i = 0; i < REQUIRED_NUMBER_OF_INPUT_CAPTURES; i++)
  {
    ClockPeriodValue += (uint32_t)((0xFFFF - InputCaptureValues[i] + InputCaptureValues[(i + 1)] + 1) & 0xFFFF);
  }
  
  ClockPeriodValue /= REQUIRED_NUMBER_OF_INPUT_CAPTURES;
  return ((HAL_RCC_GetHCLKFreq() * 8U) / ClockPeriodValue);
}
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
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_TIM17_Init();
  MX_TIM16_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */
  
  NofInputCaptures = 0;
  HAL_TIM_IC_Start_IT(&htim16, TIM_CHANNEL_1);
 
  while(NofInputCaptures < (REQUIRED_NUMBER_OF_INPUT_CAPTURES + 1))
  {    
  }
     
  HAL_TIM_IC_Stop_IT(&htim16, TIM_CHANNEL_1);
  uint32_t Frequency16 = GetFrequency(TIM16);
  
  NofInputCaptures = 0;
  HAL_TIM_IC_Start_IT(&htim17, TIM_CHANNEL_1);
 
  while(NofInputCaptures < (REQUIRED_NUMBER_OF_INPUT_CAPTURES + 1))
  {    
  }
  
  HAL_TIM_IC_Stop_IT(&htim17, TIM_CHANNEL_1);
  uint32_t Frequency17 = GetFrequency(TIM17);
  
  /* USER CODE END 2 */
 
 
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  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_SCALE1);
 
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 2;
  RCC_OscInitStruct.PLL.PLLN = 200;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV8;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief RTC Initialization Function
  * @param None
  * @retval None
  */
static void MX_RTC_Init(void)
{
 
  /* USER CODE BEGIN RTC_Init 0 */
 
  /* USER CODE END RTC_Init 0 */
 
  /* USER CODE BEGIN RTC_Init 1 */
 
  /* USER CODE END RTC_Init 1 */
  /** Initialize RTC Only 
  */
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 255;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }
  /** Enable Calibrartion 
  */
//  if (HAL_RTCEx_SetCalibrationOutPut(&hrtc, RTC_CALIBOUTPUT_1HZ) != HAL_OK)
//  {
//    Error_Handler();
//  }
  /* USER CODE BEGIN RTC_Init 2 */
 
  /* USER CODE END RTC_Init 2 */
 
}
 
/**
  * @brief TIM16 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM16_Init(void)
{
 
  /* USER CODE BEGIN TIM16_Init 0 */
 
  /* USER CODE END TIM16_Init 0 */
 
  TIM_IC_InitTypeDef sConfigIC = {0};
 
  /* USER CODE BEGIN TIM16_Init 1 */
 
  /* USER CODE END TIM16_Init 1 */
  htim16.Instance = TIM16;
  htim16.Init.Prescaler = 0;
  htim16.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim16.Init.Period = 0xFFFF;
  htim16.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim16.Init.RepetitionCounter = 0;
  htim16.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim16) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_Init(&htim16) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV8;
  sConfigIC.ICFilter = 0xF;
  if (HAL_TIM_IC_ConfigChannel(&htim16, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIMEx_RemapConfig(&htim16, TIM_TIM16_TI1_RCC_LSE) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM16_Init 2 */
  HAL_TIMEx_TISelection(&htim16, TIM_TIM16_TI1_RCC_LSE, TIM_CHANNEL_1);
  /* USER CODE END TIM16_Init 2 */
 
}
 
/**
  * @brief TIM17 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM17_Init(void)
{
 
  /* USER CODE BEGIN TIM17_Init 0 */
 
  /* USER CODE END TIM17_Init 0 */
 
  TIM_IC_InitTypeDef sConfigIC = {0};
 
  /* USER CODE BEGIN TIM17_Init 1 */
 
  /* USER CODE END TIM17_Init 1 */
  htim17.Instance = TIM17;
  htim17.Init.Prescaler = 0;
  htim17.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim17.Init.Period = 0xFFFF;
  htim17.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim17.Init.RepetitionCounter = 0;
  htim17.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim17) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_Init(&htim17) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV8;
  sConfigIC.ICFilter = 3;
  if (HAL_TIM_IC_ConfigChannel(&htim17, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIMEx_RemapConfig(&htim17, TIM_TIM17_TI1_RCC_HSE1MHZ) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM17_Init 2 */
  HAL_TIMEx_TISelection(&htim17, TIM_TIM17_TI1_RCC_HSE1MHZ, TIM_CHANNEL_1);
  /* USER CODE END TIM17_Init 2 */
 
}

0693W000000VuMAQA0.png

8 REPLIES 8

> What does HSE_1MHz mean of TIM17_TISEL on page 1862 of RM0433 Rev 7? Does it mean the HSE_RTC clock has to be 1 MHz? Why not just write HSE?

It's HSE divided by a prescaler given by RCC_CFGR.RTCPRE. For TIM17 it does not necessarily need to be 1MHz (it's the maximum input frequency of RTC, so the prescaler has to be set so that its output i.e. the HSE_1M signal is max 1MHz, should this signal be used as RTC input).

> Why does the clock source of the RTC have to be HSE in order to measure the HSE frequency using the input capture of TIM17? The reference manual doesn't clarify this.

There's no such requirement. That you can't click some setting in CubeMX, is a limitation of CubeMX and Cube, not limitation of the chip.

Using Cube/CubeMX means, that you constrain yourself to the "usual" usage cases envisaged by Cube/CubeMX authors. If you want to use any of the gazillion possible options and their combinations, ditch Cube and go for adult programming.

Nonetheless, measuring HSE against a timer driven by clock derived from the same HSE can't give you any usable result.

> It's HSE divided by a prescaler given by RCC_CFGR.RTCPRE. For TIM17 it does not necessarily need to be 1MHz (it's the maximum input frequency of RTC, so the prescaler has to be set so that its output i.e. the HSE_1M signal is max 1MHz, should this signal be used as RTC input).

Why is this mentioned in a register setting of TIM17 as this would relate to the RTC?

> There's no such requirement. That you can't click some setting in CubeMX, is a limitation of CubeMX and Cube, not limitation of the chip.

As CubeMX was used to isolate the problem and sets all the registers with the same values as our own code, CubeMX would not be the limitation for this case. I never mentioned that the problem is a limitation of the chip, only that I can't find an explanation why TIM17 only gets capture/compare 1 interrupts when the RTC has the HSE as clock input. You state that there is no requirement for this and you are correct as the reference manual doesn't mention it but that doesn't explain the fact of the interrupts I mentioned earlier.

>> It's HSE divided by a prescaler given by RCC_CFGR.RTCPRE. For TIM17 it does not necessarily need to be 1MHz (it's the maximum input frequency of RTC, so the

>> prescaler has to be set so that its output i.e. the HSE_1M signal is max 1MHz, should this signal be used as RTC input).

>

>Why is this mentioned in a register setting of TIM17 as this would relate to the RTC?

Where is it mentioned?

If you mean "HSE_1MHz" itself, it's the name of that signal.

>> There's no such requirement. That you can't click some setting in CubeMX, is a limitation of CubeMX and Cube, not limitation of the chip.

 > As CubeMX was used to isolate the problem and sets all the registers with the same values as our own code, CubeMX would not be the limitation for this case. I never > mentioned that the problem is a limitation of the chip, only that I can't find an explanation why TIM17 only gets capture/compare 1 interrupts when the RTC has the

> HSE as clock input.

Okay, so you tried to set RCC_CFGR.RTCPRE to a value which is not reserved, set TIM17_TISEL.TI1SEL to HSE_1MHz, set TIM17_CH1 to capture, enabled, and enabled interrupt on CC1; and then *without* setting HSE as RTC clock in RCC_BDCR.RTCSEL it won't trigger TIM17 CC1?

That then would mean a problem in description of how TIM17 TISEL works, maybe even granting an erratum.

Can you please read out and post the RCC and TIM17 registers' content for this case?

JW

>> It's HSE divided by a prescaler given by RCC_CFGR.RTCPRE. For TIM17 it does not necessarily need to be 1MHz (it's the maximum input frequency of RTC, so the

>> prescaler has to be set so that its output i.e. the HSE_1M signal is max 1MHz, should this signal be used as RTC input).

>

>Why is this mentioned in a register setting of TIM17 as this would relate to the RTC?

> Where is it mentioned?

> If you mean "HSE_1MHz" itself, it's the name of that signal.

Yes, I mean the name "HSE_1MHz" itself. The HSE would be the input signal for TIM17 TI1 but I think the 1MHz is somewhat misleading. This signal is in fact the RTC clock (with a maximum frequency of 1 MHz), derived from the HSE. Would you not agree that this signal relates to the RTC but is not clear in the name of the signal?

> Okay, so you tried to set RCC_CFGR.RTCPRE to a value which is not reserved, set TIM17_TISEL.TI1SEL to HSE_1MHz, set TIM17_CH1 to capture, enabled, and enabled interrupt on CC1; and then *without* setting HSE as RTC clock in RCC_BDCR.RTCSEL it won't trigger TIM17 CC1?

That is correct.

The images below show the registers of RCC and TIM17. The first three show the registers as when HSE is selected as input for the RTC clock. The last three with LSE as input.

0693W000000W4vUQAS.png

0693W000000W4vZQAS.png

0693W000000W4wSQAS.png

0693W000000W4wXQAS.png

0693W000000W4x6QAC.png

0693W000000W4xQQAS.png

>> Okay, so you tried to set RCC_CFGR.RTCPRE to a value which is not reserved, set TIM17_TISEL.TI1SEL to HSE_1MHz, set TIM17_CH1 to capture, enabled, and enabled

>> interrupt on CC1; and then *without* setting HSE as RTC clock in RCC_BDCR.RTCSEL it won't trigger TIM17 CC1?

>>

> That is correct.

>

> The images below show the registers of RCC and TIM17. The first three show the registers as when HSE is selected as input for the RTC clock.

> The last three with LSE as input.

But in those last three, you have set RCC_CFGR.RTCPRE=0:

0693W000000W8MJQA0.png

JW

> But in those last three, you have set RCC_CFGR.RTCPRE=0:

Yes, that's because:

a) It is the HSE division factor for RTC clock and I am not aware of the link to TIM17 TI1 after the prescaler as it is not described in the reference manual.

b) The HAL library resets the RTC prescaler when the HSE is not selected as RTC clock input:

#define __HAL_RCC_RTC_CLKPRESCALER(__RTCCLKSource__) (((__RTCCLKSource__) & RCC_BDCR_RTCSEL) == RCC_BDCR_RTCSEL) ?    \
                                                 MODIFY_REG(RCC->CFGR, RCC_CFGR_RTCPRE, (((__RTCCLKSource__) & 0xFFFFCFFU) >> 4)) : CLEAR_BIT(RCC->CFGR, RCC_CFGR_RTCPRE)

I've tested the following settings:

RCC_BDCR.RTCSEL = 0x00 (no clockinput)

RCC_CFGR.RTCPRE = 0x08 (HSE/8)

And this activates the TIM17 CC1 interrupts. So you are right that the RTC itself has nothing to do with the HSE signal. Is the following then correct?:

0693W000000W9QWQA0.png

I think that the reference manual does need some extra clarification on where the HSE_1MHz signal is linked to (RTC clock input/TIM17 TI1). Also adding some information that the RCC_CFGR.RTCPRE has to be set to some value or there will be no signal from the HSE to TIM17 TI1.

Some modifications to the HAL library could make it easier to set the registers correct (see code snippet above and split the clock selection from the prescaler setting in the code snippet below).

#define RCC_RTCCLKSOURCE_HSE_DIV2        (0x00002300U)
#define RCC_RTCCLKSOURCE_HSE_DIV3        (0x00003300U)
#define RCC_RTCCLKSOURCE_HSE_DIV4        (0x00004300U)
#define RCC_RTCCLKSOURCE_HSE_DIV5        (0x00005300U)
...

> Is the following [drawing] then correct?:

 Yes.

> I think that the reference manual does need some extra clarification on where the HSE_1MHz signal is linked to (RTC clock input/TIM17 TI1).

> Also adding some information that the RCC_CFGR.RTCPRE has to be set to some value or there will be no signal from the HSE to TIM17 TI1.

Yes, it ought to go to the Interconnections chapter, here:

0693W000000WAW1QAO.png

@Imen DAHMEN​ , can you please have a look at it?

I don't care about Cube/HAL.

JW

Alright, thanks for helping and clarifying where the signal come from.