cancel
Showing results for 
Search instead for 
Did you mean: 

TIM6 undefined interrupt reason on STM32H753I eval board

Pavel A.
Evangelist III

Dear experts,

I'm struggling with a strange TIM6 interrupt issue on STM32H753I.

Playing with one of Cube example projects with FreeRTOS, where TIM6 is used as HAL timer.

The original IRQ handler is very simple (and the demo works fine) :

void TIM6_DAC_IRQHandler(void)
{
  HAL_TIM_IRQHandler(&TimHandle);
}

https://github.com/STMicroelectronics/STM32CubeH7/blob/e261d820b398846a94f22f4aeb32d86c29546efb/Projects/STM32H743I-EVAL/Applications/LwIP/LwIP_HTTP_Server_Netconn_RTOS/Src/stm32h7xx_hal_timebase_tim.c#L149

But after looking at HAL_TIM_IRQHandler I wanted to "optimize" it.

https://github.com/STMicroelectronics/STM32CubeH7/blob/e261d820b398846a94f22f4aeb32d86c29546efb/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim.c#L3178

Well, all good people don't use the HAL libraries at all, I know.... Anyway.

The HAL_TIM_IRQHandler checks all possible interrupt reasons before the only one possible for TIM6, the update event. So I changed the interrupt handler to this:

void TIM6_DAC_IRQHandler(void)
{
  static unsigned long unkn_cnt = 0;
 
  if (__HAL_TIM_GET_FLAG(&TimHandle, TIM_FLAG_UPDATE) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(&TimHandle, TIM_IT_UPDATE) != RESET)
    {
      __HAL_TIM_CLEAR_IT(&TimHandle, TIM_IT_UPDATE);
      HAL_IncTick();
      return;
    }
  }
  unkn_cnt++; //? __BKPT(6); // Unexpected interrupt reason on this vector ??
}

The demo still seems to run fine, but now a lot of unknown interrupts arrive to this handler! the unkn_cnt is almost as large as tick count!

When the code falls to line 14 unkn_cnt++, the SR of TIM6 is 0.

What is really disturbing that the original code with HAL_TIM_IRQHandler() does NOT get any unknown interupts. I tested it this way:

void TIM6_DAC_IRQHandler(void)
{
  uint32_t before = HAL_GetTick();
 
  HAL_TIM_IRQHandler(&TimHandle);
 
  if (before == HAL_GetTick()) {
      __BKPT(6); // Unexpected interrupt reason on this vector ??
  }
}

So a breakpoint should occur whenever calling HAL_TIM_IRQHandler does not result in incrementing tick count. It does not occur.

What is missing - besides of proverbial "not broken - don't touch"?

Why the ISR is entered with TIM6 SR == 0?

Regards,

-- pa

1 ACCEPTED SOLUTION

Accepted Solutions

Don't look at the TIM registers in the debugger.

Check what the code in HAL_IncTick() actually does.

Tail-chaining can occur before the TIM interrupt and NVIC state propagate. Clear the state early, and have fencing operations so the write-buffers vacate.

perhaps try unkn_sr |= TIM6->SR; to see what bits are sticky

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

View solution in original post

3 REPLIES 3

Don't look at the TIM registers in the debugger.

Check what the code in HAL_IncTick() actually does.

Tail-chaining can occur before the TIM interrupt and NVIC state propagate. Clear the state early, and have fencing operations so the write-buffers vacate.

perhaps try unkn_sr |= TIM6->SR; to see what bits are sticky

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

Hi Clive,

Not in debugger. I added reading SR in code (not shown). It is 0 every time when it is not 0x1.

HAL_IncTick() only increments the tick count.

After more digging it seems that "optimized" handler returns too fast and request still is pending in NVIC after clearing TIM6 interrupt.

The following variant no longer detects unknown things:

void TIM6_DAC_IRQHandler(void)
{
  if (__HAL_TIM_GET_FLAG(&TimHandle, TIM_FLAG_UPDATE) != RESET)
  {
      __HAL_TIM_CLEAR_IT(&TimHandle, TIM_IT_UPDATE);
      HAL_IncTick();
       NVIC_ClearPendingIRQ(TIM6_DAC_IRQn);
     return;
  }
   __BKPT(6); // no longer hit
}

On 'F4 I never had to call NVIC_ClearPendingIRQ.

Is anything wrong with the HAL library, like it needs "fencing instructions" after writing to TIM registers? What are these by the way - DSB? ISB?

Or something with I/D caching settings?

Or this is normal behavior of Cortex M7 vs. M4?

Regards,

Pavel

*** EDIT ***

Clive, you are right to the point as always. The DSB is enough to prevent the issue. The final working variant...

void TIM6_DAC_IRQHandler(void)
{
  if (__HAL_TIM_GET_FLAG(&TimHandle, TIM_FLAG_UPDATE) != RESET)
  {
      __HAL_TIM_CLEAR_IT(&TimHandle, TIM_IT_UPDATE);
      HAL_IncTick();
       __DSB();
     return;
  }
   __BKPT(6); // no longer hit
}

The re-entry due to tail-chaining is a known problem in CM3 and CM4 designs also. Might be worse on the CM7, hard to say.

The two problems here are pipe-lining, where multiple instructions are at different stages of execution, the CM7 can add some additional parallelism/super-scalar issues, and the write buffer(s) which are a lagging, lazy-write type construct which get retired at bus speeds after instruction execution has been completed. Slower buses might compound this. These are why Hard Faults on writes are "Imprecise" because they fire when the memory sub-system says there's no memory behind the address you just wrote some X or Y cycles earlier. It doesn't track which instruction buffered the write.

Anyway the tail-chaining logic in the NVIC is making its decision a lot earlier than the bubble through on the TIM->SR write side.

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