cancel
Showing results for 
Search instead for 
Did you mean: 

Timer interrupt triggers immediately after interrupt enabled

vtran1
Associate II

Hello all,

I want to disable the timer interrupt in the IRQ Handler and then enable again in the main loop. However the interrupt is triggered nearly immediately after I re-enable the interrupt (setting the UIE bit). I attached my code below. If I disable and enable the counter instead of just the interrupt then the code runs correctly. Why is that? I have tried to set the TIM_CR1_URS but no avail.

void MX_TIM2_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
 
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 0;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 3333;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
}
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM2_Init();
  HAL_TIM_Base_Start_IT(&htim2);
  uint16_t c;
  while (1)
  {
	  if(int_count == 1)
	  {
		  int_count = 0;
		  HAL_GPIO_WritePin(GPIOA, TX_pin, 0);
		  __HAL_TIM_SET_COUNTER(&htim2, 0);
		  __HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE);
	  }
	  c = 0xFFFF;
	  while(c)
	  {
		  c--;
	  }
  }
}
 
void TIM2_IRQHandler(void)
{
	if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET)
	{
		if (__HAL_TIM_GET_IT_SOURCE(&htim2, TIM_IT_UPDATE) != RESET)
		{
		        __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE);
			if(int_count == 0)
			{
				__HAL_TIM_DISABLE_IT(&htim2, TIM_IT_UPDATE);
				HAL_GPIO_WritePin(GPIOA, TX_pin, 1);
				int_count = 1;
			}
		}
	}
	return;
}

P/S: Side question: when I debugged the code, I notice that when I clear the interrupt flag with __HAL_TIM_CLEAR_FLAG, even though the code says the flag is cleared but I still see bit UIF set when looking at the timer register. Does anyone know why?

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

The update interrupt will fire immediately after enabled in HAL_TIM_Base_Start_IT unless you clear it first. Note that if ARR=0, it'll get set immediately. So you need to set ARR, then clear the flag, then start the timer.

When debugging, the timer is still running unless you have timers disabled during debug so it gets set immediately again.

Mixing HAL calls with your own IRQ handler doesn't seem smart. You should call HAL_TIM_IRQHandler instead. Or just ditch HAL.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

3 REPLIES 3
TDK
Guru

The update interrupt will fire immediately after enabled in HAL_TIM_Base_Start_IT unless you clear it first. Note that if ARR=0, it'll get set immediately. So you need to set ARR, then clear the flag, then start the timer.

When debugging, the timer is still running unless you have timers disabled during debug so it gets set immediately again.

Mixing HAL calls with your own IRQ handler doesn't seem smart. You should call HAL_TIM_IRQHandler instead. Or just ditch HAL.

If you feel a post has answered your question, please click "Accept as Solution".
vtran1
Associate II

"Mixing HAL calls with your own IRQ handler doesn't seem smart."

Why is that? I want to use HAL but the HAL interrupt handlers are too long so I decided to write my own.

Anw, adding __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE); before __HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE); solves the problem.

It's just preference. If you know what you're doing it's fine, as long as you're aware much of the functionality is implemented in the IRQ handler.
The basic TIM stuff is pretty simple. If you just want to trigger an update interrupt at 500 Hz (or whatever) and you're concerned about speed, direct register access is easy to read. It also gives you finer control over how things are initialized and you can avoid stuff like the update interrupt firing immediately.
If you feel a post has answered your question, please click "Accept as Solution".