STM32 HAL Tick Interrupt priority

Hi @all, I’ve come across a problem when using STM32 HAL library in combination with FreeRTOS. I think my problem is quite basic, but I didn’t find any explanation or solution on the web. I’ve read the Cortex M Interrupt explanation page (http://www.freertos.org/RTOS-Cortex-M3-M4.html), but this also doesn’t help in my case. I’m using the ARM_CM4F Port for my STM32F303 Cortex M4F device, FreeRTOS8.2.3 and ST HAL Lib V1.4 for the F3 series. I’ve used the FreeRTOSConfig.h from the STM32F407 example and the one that comes with the HAL package as a starting point (they are the same except for some details). I’ve set up the NVIC to have 4 bit priorities and no subpriorities, as recommendet in the docs. The problem I’m having is that errorhandling within HAL lib interrupt functions doesn’t work in combination with FreeRTOS. The HAL lib uses the tick interrupt for FreeRTOS as well as it’s own tick, which is then used to detect internal timeouts. This of course only works if the tick interrupt has a higher priority than the active interrupt. The default configuration of FreeRTOS is to set the tick interrupt priority to the lowest available priority (configKERNELINTERRUPTPRIORITY). It even states that multiple times in the source code port.c ( xPortStartScheduler – /* Make PendSV and SysTick the lowest priority interrupts. / ; xPortSysTickHandler – / The SysTick runs at the lowest interrupt priority, so when this interrupt executes all interrupts must be unmasked. There is therefore no need to save and then restore the interrupt mask value as its value is already known. */ When I increase the tick priority, errorhandling works as expected. But is this a save way to go? Thanks for your help!

STM32 HAL Tick Interrupt priority

This has been raised a few times before. First the FreeRTOS tick and PendSV handlers must have the lowest possible interrupt priority because that assumption is made when the tick handler enters and exits a critical section – rather than setting the basepri register back to whatever value it had when it exits a critical section it assumes basepri was clear and just sets it to zero. If the SysTick is running at the lowest priority then this assumption is safe, as the SysTick would only execute in the first place if basepri was clear (any other value would mask the interrupt out). Now you can edit the FreeRTOS source code so the SysTick saves and restores the basepri register rather than just blindly setting it and then clearing it back to zero – that will come with the overhead of more asm instructions and more memory accesses on every tick interrupt though. However, I don’t understand your explanation of why the HAL tick needs to be at the highest priority. You say it is checking for timeouts that won’t occur if the HAL tick is not the highest priority – does that imply the SysTick is checking for timeouts in other interrupt service routines. If so, that would imply other interrupt service routines were somehow busy waiting, which is not good in an ISR, and not needed if you are using an OS anyway. Regards.

STM32 HAL Tick Interrupt priority

Thank you for your answer!
HAL tick needs to be at the highest priority
not necessarily the highest priority. Only higher than interrupts calling the HAL library.
does that imply the SysTick is checking for timeouts in other interrupt service routines
no, the SysTick itself is not checking for timeouts, but it’s value is used for this purpose.
other interrupt service routines were somehow busy waiting, which is not good in an ISR
yes, that’s the case. Timeout values are hardcoded in HAL lib and are in the range of 10..100ms. I don’t think that I can get rid of those busy-waiting parts without writing my own drivers… I came across this after adding the HAL I2C DMA driver into my project. I wanted to see if communication errors are reported correctly and simulated an error by shorting the I2C wires. This caused my program to infinitely loop in one of some routines like this: ~~~~ static HALStatusTypeDef I2CWaitOnSTOPFlagUntilTimeout(I2CHandleTypeDef *hi2c, uint32t Timeout) {
uint32t tickstart = 0x00; ->tickstart = HALGetTick(); ->while(__HALI2CGETFLAG(hi2c, I2CFLAGSTOPF) == RESET) { /* Check if a NACK is detected */ if(I2CIsAcknowledgeFailed(hi2c, Timeout) != HALOK) { return HALERROR; }
/* Check for the Timeout */
—>if((Timeout == 0) || ((HALGetTick()-tickstart) > Timeout)) { hi2c->ErrorCode |= HALI2CERRORTIMEOUT; hi2c->State= HALI2CSTATE_READY;
  /* Process Unlocked */
  __HAL_UNLOCK(hi2c);

  return HAL_TIMEOUT;
}
} return HAL_OK; } ~~~~ Without calling the corresponding HAL_IncTick() function, the loop never exits. This construct exists many time within the HAL lib source code. However, I don’t know how many of those functions are called within an interrupt context. Do you think it’s a good solution to have separate timers for HAL and FreeRTOS tick function, with different interrupt priorities?

STM32 HAL Tick Interrupt priority

—>if((Timeout == 0) || ((HAL_GetTick()-tickstart) > Timeout))
If this is meant to be called in an interrupt then this is very very bad. Your system is not going to be real time if interrupts loop for 10s of ms. I doubt the function this line is in is meant to execute in an interrupt.

STM32 HAL Tick Interrupt priority

This is called deeply inside the HALDMAIRQHandler() function multiple times. So I think it’s save to say that I’m using it correctly. As this is code from ST, I can’t tell you if interrupt execution time was in their mind. It’s in the drivers many times, the only real solution would be to write my own drivers, which I would prefer not to do…

STM32 HAL Tick Interrupt priority

Thinking about this more, perhaps the SysTick can run at a higher priority if it is being called by the ST SysTick interrupt handler, rather than the FreeRTOS SysTick interrupt handler. The FreeRTOS SysTick handler is as follows: ~~~~ void xPortSysTickHandler( void ) { /* The SysTick runs at the lowest interrupt priority, so when this interrupt executes all interrupts must be unmasked. There is therefore no need to save and then restore the interrupt mask value as its value is already known. / portDISABLE_INTERRUPTS(); { / Increment the RTOS tick. / if( xTaskIncrementTick() != pdFALSE ) { / A context switch is required. Context switching is performed in the PendSV interrupt. Pend the PendSV interrupt. */ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } } portENABLE_INTERRUPTS(); } ~~~~ xPortSysTickHandler() is a port specific handler that creates a critical section, then calls the generic xTaskIncrementTick() C function (xTaskIncrementTick() is used by all FreeRTOS ports). As can be seen in the code comments, it is the port specific part that assumes it is running at the lowest priority. However, the ST code has its own SysTick handler, so that port specific part will [presumably] not be executing anyway. If the ST SysTick handler just calls xTaskIncrementTick() then it might be ok. Also, if the SysTick handler was running at the priority defined by configMAXSYSCALLINTERRUPT_PRIORITY then the critical section would not be needed. Can you please post the code for the SysTick handler you are using.

STM32 HAL Tick Interrupt priority

No problem SysTick ISR ~~~~ void SysTickHandler(void) { HALIncTick(); if (xTaskGetSchedulerState() != taskSCHEDULERNOTSTARTED) { xPortSysTickHandler(); } } ~~~~ HAL_IncTick() ~~~~ __weak void HAL_IncTick(void) { uwTick++; } ~~~~ xPortSysTickHandler() (gcc CM4F Port) ~~~~ void xPortSysTickHandler( void ) { /* The SysTick runs at the lowest interrupt priority, so when this interrupt executes all interrupts must be unmasked. There is therefore no need to save and then restore the interrupt mask value as its value is already known. / ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); { / Increment the RTOS tick. / if( xTaskIncrementTick() != pdFALSE ) { / A context switch is required. Context switching is performed in the PendSV interrupt. Pend the PendSV interrupt. */ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } } portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); } ~~~~

STM32 HAL Tick Interrupt priority

So the SysTickHandler() is calling the full FreeRTOS xPortSysTickHandler(), rather than just xTaskIncrementTick(). However, [thoughts evolving] I think this is still ok as the Cortex-M NVIC is an intelligent thing and even though portCLEARINTERRUPTMASKFROM_ISR( 0 ) is used (blindly setting to 0 rather than the previous value) the NVIC won’t internally set the basepri below that of a pending interrupt……..so I think we have come a long way around in answering your original question: yes, in fact it is probably fine after all at the higher priority (although busy waiting in an ISR is still not a good plan, it should not cause a crash).

STM32 HAL Tick Interrupt priority

Thank you for your answer! Do you have a reference for this behaviour? I can’t find anyting useful in the Cortex processor manual…

STM32 HAL Tick Interrupt priority

In the end, we decided to drop ST drivers. They use blocking wait inside interrupts (which with I could live, as they are just wait until hardware module confirmes some action) They no not do proper error handling (at least in the version I tried in april ’16). Try sending two bytes to the UART module while the driver isn’t in rx mode -> Hardware RX OV, but driver doesn’t detect that. And that’s just -one- example.