cancel
Showing results for 
Search instead for 
Did you mean: 

STM32CubeMX fixes timer interrupt priority for HAL timer if RTOS enabled?

willcfj
Senior

I'm doing my first non-trivial program using FreeRTOS, so suspect this is a newbie question. Besides the timer for FreeRTOS (using SysTick), I need a timer for the HAL (using TIM7), and another timer for some high speed audio DSP routines (using TIM6 and triggering the DAC/ADC). The audio interrupt needs to be the highest of the three. Before the RTOS that was easy, I just make sure TIM6 had a higher priority than HAL SysTick.

FreeRTOS needs to use SysTick and there are lots of warnings about not sharing the HAL and FreeRTOS timer. No problem. I just told CubeMX to use TIM7 as it's timebase instead. Once I do that, however, CubeMX fixes the interrupt priority for TIM7 to be 0 and it can't be altered. I need it higher than 0 so I can have TIM6 for the audio work be the highest priority. With TIM7 fixed at 0, I can't do that.

Since CubeMX is going out of its way to do this, I assume there is a reason. Is it trying to stop me from doing something bad I don't understand? I do need an interrupt higher priority than the HAL's timebase for sure, and before adding FreeRTOS had ho problem doing this. I even tried a dummy configuration without FreeRTOS using TIM7 for the HAL timer interrupt and still could change it's priority just fine. It is only if FreeRTOS is enabled that TIM7's priority gets fixed.

Thanks in advance. I'm on the most current version of CubeMX (5.3.0)

will

26 REPLIES 26

@willcfj Not a bug.

​ 

FreeRTOS and Cube library have different ideas about their tick timer, this is why they use two different timers.

In FreeRTOS, the tick timer has low priority and likely allows API calls (is below configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY).

In the ST "HAL" library the tick timer has high priority, it is needed to update the time and enable delays, even for other interrupt handlers (not indulging in discussion whether it is good practice or what). It is more like profiling timer.

The tick interrupt handler should be very quick : just update the counter.

If someone overloads it, this is their problem.

-- pa

Pavel A:

Thank you for the reply. Fully agree on the different intentions for the timers for RTOS and HAL. That is what I have too, SysTick for the RTOS is priority 15 (low) and TIM7 for the HAL is priority 6. The reason I started this thread is that CubeMX is forcing TIM7 to be priority 0 with no ability to change it. With the RTOS though, there is an additional requirement. That is if you have any ISR that needs to make an RTOS call, the priority of that ISR must be higher (lower number) than the LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY level specified in the RTOS. That is because the RTOS uses SYSCALLS with those higher priorities internally. If the MCU is already executing an ISR with a higher priority, then the RTOS call hangs as the SYSCALLs get blocked by NVIC. This is well documented with lots of warnings, so I knew about it. Hence, the interrupt priority for the HAL needs to be lower than SysTick, but also higher than LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY. What I need to do is clear, just CubeMX won't allow me to do it, it fixes TIM7 at priority 0 without letting me change it. The solution is the "hack" above to just override the CubeMX setting and all works fine.

Hope that makes sense, it certainly solved my problem, my big question is: Is this simply a CubeMX bug or is there a reason for forcing TIM7's interrupt priority to 0 and nothing else? A value of 0 breaks the RTOS for reasons that the docs say to explicitly avoid!

will

willcfj
Senior

Hello Nesrine and thank you for the reply:

Fully understand and OK with FreeRTROS using SysTick and the priority level for SysTick that then calls the RTOS functions. That all makes sense. What I think I'm doing different is I have the RTOS running from a different timer than the HAL. The RTOS (using SysTick) is running at 100Hz and the HAL timebase (using TIM7) needs to be at 1000Hz. That in itself should be OK. From a routine called by HAL timebase interrupt, I do need to make an RTOS call. Because of that, I need to satisfy this RTOS requirement from the link above (https://www.freertos.org/RTOS-Cortex-M3-M4.html:( (about half way down)

Relevance when using the RTOS

FreeRTOS functions that end in “FromISR�? are interrupt safe, but even these functions cannot be called from interrupts that have a logical priority above the priority defined by configMAX_SYSCALL_INTERRUPT_PRIORITY (configMAX_SYSCALL_INTERRUPT_PRIORITY is defined in the FreeRTOSConfig.h header file). Therefore, any interrupt service routine that uses an RTOS API function must have its priority manually set to a value that is numerically equal to or greater than the configMAX_SYSCALL_INTERRUPT_PRIORITY setting. This ensures the interrupt’s logical priority is equal to or less than the configMAX_SYSCALL_INTERRUPT_PRIORITY setting.

This seems straight forward and makes sense, but after setting up SysTick for RTOS and then setting up TIM7 for the HAL, CubeMX forces the interrupt priority for TIM7 to be 0. configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5. That does not meet the requirement in bold above and the RTOS hangs as predicted. The "hack" I have above fixes the issue, changing the priority for TIM7 to 6.

I'm relatively new to using an RTOS, so reluctant to just dismiss it as a CubeMX bug and asking if I'm doing something wrong. It seems what CubeMX is doing is violating the RTOS's clearly documented requirements, and if so, is a bug. I believe being able to make an RTOS call from a routing running from the Hal timers is something that should be expected and allowed. Yes, if I were dumb and tried to make an RTOS call every timer tick that would be bad, but I'm not doing that! 🙂

Thank you for the attention. With the above fix, the code has been working fine with no observed bad side effects.

will

Read that bolded+underlined sentence and the next sentence carefully! I'll fix your previous conclusion:

> That is if you have any ISR that needs to make an RTOS call, the priority of that ISR must not be higher (lower number) than the LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY level specified in the RTOS.

willcfj
Senior

Piranha:

OK, I know you are a lot more expert than me, so now worried there is something I don't know. The bold sentence above says the priority must be numerically equal to or greater than LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY, so >=5, right? My problem is CubeMX fixes the Timer ISR to interrupt priority 0. If I'm confused it is very fundamental! There are other places that say the same thing too. Another good example is UM1718 section 4.4.14, where they even show an example related to RTOS support. it says: "In this case, all the interrupt service routines (ISRs) that are calling the interrupt safe FreeRTOS APIs must have a priority lower than the priority defined in the LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY parameter (the highest the value, the lowest the priority). The check in the corresponding checkbox guarantees that the restriction is applied." If you check the box that says this ISR makes RTOS calls, the only available priorities are >=LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY.

Thanks in advance for your answers. RTOS programming is new to me, so trying to understand. This seems pretty fundamental and besides the conflict between CubeMX and lots of documentation, with the TIM7 priority set to 0, the RTOS hangs, but not when i override CubeMx in my source and set a priority of 6 all works fine. So even the code seems to agree with the docs.

will

One thing was that you missed "not" in that sentence, but I suppose that it's a simple error not wrong understanding. The other thing, I now see that you're missing, is that the HAL tick ISR (TIM7 in your case) is not supposed to call any RTOS functions. If it doesn't call those, then that priority rule doesn't apply to it and from FreeRTOS perspective it can have any priority.

willcfj
Senior

Piranha:

OK, that may be the official answer, I should not be making RTOS calls from code being called by the HAL Tick ISR. I have some code from a pre-RTOS project that does some status polling based on the HAL timer tick. It is polling the status of some audio DSP code that needs to be higher priority than the timer tick as I can't afford any timer tick code to preempt the audio code.

I do see that if somewhere in code that isn't mine there is an assumption that HAL code can interrupt RTOS code, something might break. Time to think about re-factoring the code...

will

You can be sure that HAL doesn't call any RTOS APIs because it's not RTOS aware in any way at all. Actually that is one of the two reasons why they implemented a separate tick counter independent RTOS. The other reason is that they use timeouts in interrupt handlers and therefore require HAL tick ISR to be with a higher priority than other ISRs. That is ridiculously stupid design, but that's what you get from a brainless code monkeys and blind management...

I've got the exact same problem using TIM2 as the HAL timebase source on an f207. I've got one interrupt that must be higher priority than HAL's tick but once I enable the RTOS in the GUI, and use a h/w timer for HAL's timebase, the GUI sets the h/w timer priority to 0 and greys it out to prevent change. Like you, I'm a little concerned there's a reason for that that I'm unaware of. But given how simple the HAL's tick interrupt is, it's hard to imagine it mustn't be interrupted by a higher priority ISR.

So like you, I've hacked it until we hear otherwise. My approach was slightly different to yours. If you follow the calling sequence the first call to HAL_InitTIck() from HAL_Init() stores away the GUI's priority value (0) in a global variable. Any later changes to the RCC clocking etc will re-use that stored value, so my approach was to overwrite the stored value after the call to HAL_Init() but before the call to SystemClock_Config().

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  //
  // We want the HAL timebase to be priority 1 (not 0) so as not to introduce jitter on 
  // load measurements.  The GUI permits that when not using the RTOS, but not when one of 
  // the h/w TIMs are the source and RTOS is in use, so we override the GUI here.
  // HAL_Init() above has already stored the GUI selection (0) in uwTickPrio via HAL_InitTick().
  // But the system clock is about to be reconfigured below, and this time it will use the 
  // priority stored away in uwTickPrio, so we clober it into what we want here.
  //
  uwTickPrio = MY_TICK_INT_PRIORITY;
  
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();

willcfj
Senior

David:

Slightly good to find out I'm not the only one! 🙂 "Don't do that" wasn't a great answer for me either and all the work-arounds I could think of wern't better solutions, just more complex to avoid just changing the timer tick priority, so I still have my hack in there. Good sluething on a better solution though, I guess I've never had a need to re-call any RCC routines afterwards or would have run into the issue you show above. Thanks for posting the better more general purpose solution!

will