cancel
Showing results for 
Search instead for 
Did you mean: 

How to implement multiple interrupt timers using HAL libraries

antfarmer
Associate III

I'm trying to get multiple timers with interrupts working on an STM32L462 using the provided HAL libraries in CubeIDE 1.14, but every time the chip comes out of reset, it crashes after starting the second timer. Here is the relevant code:

 

 

int main(void) {
  MX_TIM15_Init();
  MX_TIM2_Init();
  ...
  HAL_TIM_Base_Start_IT(&htim2);
  HAL_TIM_Base_Start_IT(&htim15);
  ...
}

// TIMER Interrupts
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if (htim->Instance == TIM2) {
		events.HEARTBEAT = 1;
	}
	if (htim->Instance == TIM15) {
		events.DEBOUNCE = 1;
	}
}

 

 

I can't this to work. Only when I disable the second interrupt or start the timer without interrupt will the chip start. I tried stepping through and it just gets stuck stepping indefinitely. This other topic seems to indicate it is possible, but I don't know how. Thinking about how the handler is set up, how could htim->Instance be two different values. That's impossible. So after more reading, I did try enabling 'Register Callbacks' configuration for timers, and then calling HAL_TIM_RegisterCallback before calling HAL_TIM_Base_Start_IT for each timer. It still didn't work, and stops when starting the second timer still. I don't understand what could be going on. Anyone ever get this setup? Thanks for any advice.

 

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

There are no issues with the code you presented. The problem lies elsewhere.

> I tried stepping through and it just gets stuck stepping indefinitely.

> Anyway, it still doesn't explain why it locks up as it doesn't even make it past the init phase before the main while loop.

Perhaps your timers are running too fast and swamping the chip with interrupts. "Stuck stepping" through where exactly? Interrupts?

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

View solution in original post

8 REPLIES 8

htim will depend on the value you pass in to the HAL via the IRQHandler 

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..

Yes, understood. That seems to contradict this statement though. So you should have no trouble with if/else or even a switch statement. Anyway, it still doesn't explain why it locks up as it doesn't even make it past the init phase before the main while loop. I don't know if there's some other setting needed I overlooked.

TDK
Guru

There are no issues with the code you presented. The problem lies elsewhere.

> I tried stepping through and it just gets stuck stepping indefinitely.

> Anyway, it still doesn't explain why it locks up as it doesn't even make it past the init phase before the main while loop.

Perhaps your timers are running too fast and swamping the chip with interrupts. "Stuck stepping" through where exactly? Interrupts?

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

Yes, that was it. I misconfigured it for us instead of ms. Very cool. Seems that the stepping issue indicates an overloaded cpu. I'll have to remember that in further debugging. I thought it was an issue with the board layout to the programming header.

I did not realize there's quite a bit of overhead in the IRQ handler using the HAL library. Are there any good examples of using interrupts without the HAL overhead? I think interrupts should call directly to my own handler without all those callback type checks to keep interrupt processing very quick. Of course, I'd still want to use HAL for higher-level complex operations such as SDIO, SPI, etc. Thanks in advance.

The checks are necessary to call the right callbacks. There's really not a ton of overhead in the handlers, there's just a lot of potential cases. Look at the callback for update:

  /* TIM Update event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
      htim->PeriodElapsedCallback(htim);
#else
      HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
    }
  }

This is exactly how it should be written. If UIE and UF, clear the flag and call the callback. That's it. There is some small overhead for getting the timer instance from htim, but that's the price you pay to make it more general. If you knew beforehand that UIE would be set, maybe you don't have to check for that, but HAL can't make that assumption.

If you want to make your own, take only the relevant parts from the HAL code.

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

Ya you're right, it's not a huge difference, but looking at HAL_TIM_IRQHandler there are an extra 5 unnecessary if statements before calling the update callback since I'm only using the update callback. Do you know of a simple way to override HAL_TIM_IRQHandler or even TIM1_UP_TIM16_IRQHandler so I could call my handler directly (without having to replace code every time I run CubeMX etc)? Looking to do this still within the HAL environment.

Coming from working Microchip MCU's this is very different, where you have direct control over the interrupt handler functions. The HAL libraries are a huge benefit, but at least for interrupt logic, I'd personally rather sacrifice flexibility for performance, especially at lower clocks.

You have direct control over TIM1_UP_TIM16_IRQHandler. It's part of user code. If you don't want HAL_TIM_IRQHandler, hijack it there, check your flags, do whatever, and skip out on calling HAL_TIM_IRQHandler.

 

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

Ya, nice, got it. I had to surround the generated code with my own macro conditional like this:

void TIM1_UP_TIM16_IRQHandler(void)
{
  /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 0 */
	// ADDED CODE
#if DIRECT_TIMER_CALLBACKS
    __HAL_TIM_CLEAR_IT(&htim16, TIM_IT_UPDATE);
	TMR_Debounce_Callback(&htim16);
#else
  /* USER CODE END TIM1_UP_TIM16_IRQn 0 */
  HAL_TIM_IRQHandler(&htim16);
  /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 1 */
#endif
  /* USER CODE END TIM1_UP_TIM16_IRQn 1 */
}

👍