cancel
Showing results for 
Search instead for 
Did you mean: 

Timer cascading not working as expected

RobK1
Senior II

I'm working on a design with an STM32L072CZT6TR, where I want to calibrate my main timebase.

 

That main timebase is TIM6, which counts 16,000. The HSE is 16MHz, so there's an interrupt evey 1ms.

 

Calibration is done by counting the number of HSE cycles between two consecutive PPS pulses from a GPS receiver. The PPS triggers an EXTI interrupt, which starts TIM21 and TIM22 at 0 on the first pulse, and reads the timer values on the second.
TIM21 is set to count 16,000 pulses and TIM22 is slaved to TIM21. This way, I can conveniently determine whether the HSE is slow (TIM22 == 999) or fast (TIM22 == 1000), and calculate a correction based on TIM21.

This logic is copied straight from an older design with an STM8, where it works like a charm.

 

However, the cascading does not work. No matter what, TIM22 is always 0 on the second PPS. I have used CubeMX to set the timers up, and, going over the code with the reference manual as my guide, I can see no errors. Being a hardware engineer by nature, I'm sometimes a bit stoopid when it comes to code, so if anyone sees any problem or has some valid comment to make, I would be much obliged.

Here's the timer init:

/* TIM21 init function */
void MX_TIM21_Init(void)
{

  /* USER CODE BEGIN TIM21_Init 0 */

  /* USER CODE END TIM21_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM21_Init 1 */

  /* USER CODE END TIM21_Init 1 */
  htim21.Instance = TIM21;
  htim21.Init.Prescaler = 0;
  htim21.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim21.Init.Period = 16000-1;
  htim21.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim21.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim21) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim21, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim21, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM21_Init 2 */
  __HAL_TIM_ENABLE(&htim21);
  /* USER CODE END TIM21_Init 2 */

}
/* TIM22 init function */
void MX_TIM22_Init(void)
{

  /* USER CODE BEGIN TIM22_Init 0 */

  /* USER CODE END TIM22_Init 0 */

  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM22_Init 1 */

  /* USER CODE END TIM22_Init 1 */
  htim22.Instance = TIM22;
  htim22.Init.Prescaler = 0;
  htim22.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim22.Init.Period = 0;
  htim22.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim22.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim22) != HAL_OK)
  {
    Error_Handler();
  }
  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
  sSlaveConfig.InputTrigger = TIM_TS_ITR0;
  if (HAL_TIM_SlaveConfigSynchro(&htim22, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim22, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM22_Init 2 */
  __HAL_TIM_ENABLE(&htim22);
  HAL_TIM_Base_Start(&htim22);
  /* USER CODE END TIM22_Init 2 */

}

 And this is the relevant portion of the PPS interrupt:

    if (EVENTCALCLK) {
     TIM21_Val = TIM21->CNT;		// Get the timer values
     TIM22_Val = TIM22->CNT;
     if (tst == false) {			// If this is the first PPS
        tst = true;
        GPIO_Set(LED_ind_port, LED_ind);
        HAL_TIM_Base_Start(&htim21);		// Start both timers at 0
        TIM21->CNT = 0;
        HAL_TIM_Base_Start(&htim22);
        LL_TIM_SetCounter(TIM22,0);
      }
      else {						// On the second PPS
        tst = false;
        EVENTCALCLK = false;
        GPIO_Set(LED_ind_port, LED_ind);
       if (TIM22_Val == 999) {				// Does the clock run slow?
          timer_correction = -((SystemCoreClock/1000) - 1 - TIM21_Val - 130); // we need fewer ticks
          HAL_TIM_Base_Stop(&htim21);
       }
       else if ((TIM22_Val == 1000) || (TIM22_Val == 0)) { 	// Otherwise, the clock is fast
          timer_correction = TIM21_Val + 130;				// and we need some more ticks
          if (timer_correction >= (SystemCoreClock/1000))
            timer_correction -= (SystemCoreClock/1000) - 1;
          HAL_TIM_Base_Stop(&htim21);
       }
1 ACCEPTED SOLUTION

Accepted Solutions
waclawek.jan
Super User

Read out and check/post content of the TIM registers.

I don't use Cube/HAL, but this

       htim22.Init.Period = 0;

may be wrong.

JW

View solution in original post

2 REPLIES 2
waclawek.jan
Super User

Read out and check/post content of the TIM registers.

I don't use Cube/HAL, but this

       htim22.Init.Period = 0;

may be wrong.

JW

You were not wrong Jan. Thanks!

That's another beer I owe you, I think.