Ben K

HAL timeout handling improvement

Discussion created by Ben K on Sep 1, 2017

Hello all,

 

I have had a number of problems with the solutions applied in the HAL drivers. One of them is how the timeout handling is implemented:

  1. It relies on the SysTick (or another timer) interrupt which increments a global variable. This solution prohibits the use of any delay or timeout using function in an ISR context (except when multiple preemption priorities are available), and the SysTick interrupt has to be explicitly disabled when entering a low power mode, and re-enabled upon returning from it.
  2. The timeout checking is always done inline in each function using the HAL_GetTick() function, therefore preventing the efficient override of the waiting procedure (e.g. reducing the task's priority during the wait of the peripheral event).

 

My suggestion is to implement the timeout by polling the SysTick's COUNTFLAG bit in Control and Status Register this way:

__weak void HAL_Delay(uint32_t milliseconds) {
   /* Initially clear flag */
   (void) SysTick->CTRL;
   while (milliseconds != 0) {
      /* COUNTFLAG returns 1 if timer counted to 0 since the last flag read */
      milliseconds -= (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) >> SysTick_CTRL_COUNTFLAG_Pos;
   }
}

This polling mode only requires the SysTick to be configured for 1ms tick, but it doesn't need the interrupt to be enabled or implemented, therefore the HAL drivers could be used without any active interrupts. The solution does have the drawback that if multiple threads / ISRs are using this resource at the same time, only the highest priority one is able to achieve accurate delay, while the rest will suffer longer delay than originally intended.

 

In case the SysTick has a different period than 1ms (e.g. because it is used by the OS), the input parameter would simply need to be scaled properly.

 

As for the timeout checking, I would recommend implementing a WaitForDiff() and a WaitForMatch() function, which perform the continuous checking of register bits against a predefined value. These could be defined as __weak, so in an OS environment an extended implementation can be used, which decreases the task's priority for the duration of the wait.

 

I'm already using the above mentioned solutions in my own peripheral library. This wiki page describes the used approach.

Outcomes