Skip to main content
Associate
September 6, 2023
Solved

HAL_TIM_PeriodElapsedCallback firing very prematurely

  • September 6, 2023
  • 2 replies
  • 12357 views

Hello, all.
I am using STM32CubeIDE with an STM32G030 micro. I attempted to implement a simple interrupt - based timeout timer on Timer17 using the HAL driver. See attached file “Screenshot1”for the TIM7configuration info. Here’s the Init Code generated from the setup in the .ioc file:

/* USER CODE END TIM17_Init 1 */
htim17.Instance = TIM17;
htim17.Init.Prescaler = 64 - 1;
htim17.Init.CounterMode = TIM_COUNTERMODE_UP;
htim17.Init.Period = 10000 - 1;
htim17.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim17.Init.RepetitionCounter = 0;
htim17.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim17) != HAL_OK)
{
Error_Handler();
}

My micro is running a 64 MHz clock, so the prescaler setting has it running at 1 MHz (counting microseconds). I ran the htim17.Init.Period in the .ioc out to 65536 - 1 to handle a 50 millisecond interval and tested to see if it was running correctly with this simple, no - interrupt code from Sean Hymel’s Digi-Key instructional video here: https://www.digikey.com/en/maker/projects/getting-started-with-stm32-timers-and-timer-interrupts/d08e6493cefa486fb1e79c43c0b08cc

while (1)
{
/*TEMP TIMER TEST*/
timer_val = __HAL_TIM_GET_COUNTER(&htim17);

HAL_Delay(50);

timer_val = __HAL_TIM_GET_COUNTER(&htim17) - timer_val;
sprintf(data_buffer,”%u us\r\n”, timer_val);
Send_UART_NonBlocking();

HAL_Delay(1000);
/*END TEMP TEST */

}
That achieves the same terminal output as Sean’s result in the video - 51000 microseconds each time (he was unable to explain why the timer always measures 1 msec more than we expected. So I know the timer is being clocked correctly at an internal 1 microsecond - per - count rate.

The malfunction comes when I tried to set up the HAL_TIM_PeriodElapsedCallback interrupt. I start it with this instruction:
HAL_TIM_Base_Start_IT(&htim17);

In the Callback function, I am checking to make sure the source of the interrupt is Timer17. Here is my ISR:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htim17) //make the interrupt triggered off of our intended timer
{
HAL_TIM_Base_Stop_IT(&htim17); //reset and de-allocate the timer
HAL_GPIO_WritePin(DIAG_PA12_GPIO_Port, DIAG_PA12_Pin, GPIO_PIN_RESET);
TimeOutFlag_17 = true; //flag indicates to other functions that we triggered this timeout
}
}

I have a diagnostic port going high upon calling HAL_TIM_Base_Start_IT, and I am driving it low in the ISR - the HAL_GPIO_WritePin(DIAG_PA12_GPIO_Port, DIAG_PA12_Pin, GPIO_PIN_RESET); statement above. I am measuring 5.83 microseconds from the Start function call to the logic low write instruction in the Callback ISR. If I break on the HAL_TIM_Base_Start_IT function call, and single - step through the code, the interrupt fires within one statement after returning from that function. Looking at the timer’s CNT register in the IDE’s SFRs tab, CNT is jumping erratically from one executed C instruction to the next while single - stepping. Yet when NOT using the interrupt code, the timer runs accurately. I am stumped. What am I doing wrong with this simple interrupt implementation?

This topic has been closed for replies.
Best answer by dspusr
 
As a test
Before HAL_TIM_Base_Start_IT
Reset the UIF flag by 
TIM17->SR &= ~TIM_SR_UIF

 

2 replies

dspusrBest answer
Visitor II
September 9, 2023
 
As a test
Before HAL_TIM_Base_Start_IT
Reset the UIF flag by 
TIM17->SR &= ~TIM_SR_UIF

 

Associate
September 11, 2023

Thanks! I just needed to reset the UIF flag as per your instruction before HAL_TIM_Base_Start_IT. That sure wasn't obvious!

waclawek.jan
Super User
September 9, 2023

As @dspusr said above, Cube/HAL functions generate an Update during setup, so the UIF flag is already set.

Looking at the timer’s CNT register in the IDE’s SFRs tab, CNT is jumping erratically from one executed C instruction to the next while single - stepping.

Timer is not stopped during debugging/single-stepping, unless you set the respective bit in DBGMCU_APBx_FZ  register. Some IDEs have a tickbox which when ticked, will set this bit for you, but you can set it in code too.

JW

Associate
September 11, 2023

Thanks! Executing TIM17->SR &= ~TIM_SR_UIF before the HAL_TIM_Base_Start_IT() call did the trick!

Visitor II
September 16, 2023

Maybe it's more of a bug than a trick For a long time, the UIF was set automatically when using NVIC_INIT().


Also, there is no other way to clear the UIF than by directly manipulating bits.If you follow HAL's method, Another way is to call __HAL_TIM_CLEAR_FLAG(&htim7, TIM_FLAG_UPDATE);.