13

While creating FreeRTOS application project with STM32CubeMx, there are two ways you can use to introduce delay, namely osDelay and HAL_Delay.

What's the difference among them and which one should be preferred?

osDelay Code:

/*********************** Generic Wait Functions *******************************/
/**
* @brief   Wait for Timeout (Time Delay)
* @param   millisec      time delay value
* @retval  status code that indicates the execution status of the function.
*/
osStatus osDelay (uint32_t millisec)
{
#if INCLUDE_vTaskDelay
  TickType_t ticks = millisec / portTICK_PERIOD_MS;

  vTaskDelay(ticks ? ticks : 1);          /* Minimum delay = 1 tick */

  return osOK;
#else
  (void) millisec;

  return osErrorResource;
#endif
}

HAL_Delay Code:

/**
* @brief This function provides accurate delay (in milliseconds) based 
*        on variable incremented.
* @note In the default implementation , SysTick timer is the source of time base.
*       It is used to generate interrupts at regular time intervals where uwTick
*       is incremented.
* @note ThiS function is declared as __weak to be overwritten in case of other
*       implementations in user file.
* @param Delay: specifies the delay time length, in milliseconds.
* @retval None
*/
__weak void HAL_Delay(__IO uint32_t Delay)
{
  uint32_t tickstart = 0;
  tickstart = HAL_GetTick();
  while((HAL_GetTick() - tickstart) < Delay)
  {
  }
}
Bence Kaulics
  • 7,066
  • 7
  • 33
  • 63
ARK4579
  • 663
  • 2
  • 6
  • 16
  • 1
    Obviously from the given code (without even knowing anything about RTOS), the first one relies on `vTaskDelay` and the second one relies on polling. So you should basically look into the implementation of `vTaskDelay`. – barak manos Feb 16 '17 at 14:39

5 Answers5

13

HAL_Delay is NOT a FreeRTOS function and _osDelay is a function built around FreeRTOS function. (acc @Clifford: ) They both are entirely different functions by different developers for different purposes.

osDelay is part of the CMSIS Library and uses vTaskDelay() internally to introduce delay with the difference that input argument of osDelay is delay time in milliseconds while the input argument of _vTaskDelay() is number of Ticks to be delayed. (acc. @Bence Kaulics:) Using this function, OS will be notified about the delay and OS will change the status of task to blocked for that particular time period.

HAL_Delay is part of the hardware abstraction layer for our processor. It basically uses polling to introduce delay. (acc. @Bence Kaulics:) Using this function, OS won't be notified about the delay. Also if you do not use OS, then HAL_Delay is the default and only blocking delay to use provided by the HAL library. (acc. @Clifford: ) This is part of HAL Library and can be used without FreeRTOS (or when FreeRTOS is not running)

To introduce Delay using FreeRTOS functions, you can use vTaskDelay() or vTaskDelayUntil() after the scheduler has started.

(acc. @Clifford: )
Always Favour FreeRTOS API function if you want your application to be deterministic.
CubeMX is a collection of parts from multiple sources.

marius
  • 163
  • 1
  • 2
  • 16
ARK4579
  • 663
  • 2
  • 6
  • 16
  • 1
    It should be noted that as of version 2, CMSIS's `osDelay` has an argument `ticks` opposed to `millisec`, and hence passes that value verbatim to `vTaskDelay`. While a configuration of "1 tick = 1 ms" is a common default, it's not necessarily the case, so `osDelay` and `HAL_Delay` calls cannot be interchanged without verifying that the tick rate is 1000 Hz. – LWChris Oct 18 '22 at 09:43
4

It does not look like HAL_Delay() is intended for use with an RTOS because it is a NULL loop delay. If you call HAL_Delay() from an RTOS task then the task will continue to run until the delay has expired. Higher priority tasks will be able to run, but lower priority tasks will be starved of any processing time during the delay period. That is a waste of processing time, power, and can be detrimental to system responsiveness.

osDelay() on the other hand effects a delay using the RTOS. It tells the RTOS that it has nothing to do until the delay period has expired, so the RTOS does not assign any processing time to the task during that period. That saves processing time, potentially saves power, and allows lower priority tasks to get processing time during the delay period. http://www.freertos.org/FAQWhat.html#WhyUseRTOS

Richard
  • 3,081
  • 11
  • 9
3

There is a task with the highest priority. If you are going to use the HAL_Delay to block the task then probably there won't be a context switch because the scheduler won't be notified that the task currently just polls a tick counter in a while loop and actually does not do any useful operation. Tasks with lower priority won't run.

The other function uses the vTaskDelay function of the OS, I did not peek into its source code, but probably this will notify the OS the current task wants to be blocked for a certain time, so the task's state will change to blocked and the scheduler can switch to a lower prio task in the meanwhile.

Bence Kaulics
  • 7,066
  • 7
  • 33
  • 63
  • hmmm that makes sense. that's why there are two of them so you can use any one of them based on your task requirements – ARK4579 Feb 16 '17 at 14:53
  • 1
    @ARK4579 Also if you do not use OS, then `HAL_Delay` is the default and only blocking delay to use provided by the HAL library. – Bence Kaulics Feb 16 '17 at 14:56
  • 2
    @ARK4579 : No there are two methods because they are independently developed from different providers for entirely different purposes. The HAL can be used without an RTOS (or before teh RTOS is running), and is a lower level service - always favour the RTOS API if you want your application to schedule deterministically. CubeMX is a collection of parts from multiple sources. – Clifford Feb 16 '17 at 15:20
0

HAL_Delay is used across the stm32_HAL library, including in some case, the function being called in ISR. Beside the naming implication that it is hardware abstract layer, the timer that used the HAL_Delay (HAL_GetTick) needs to have highest NVIC priority. (because it may be called inside ISR and can't be blocked) Whether this is good or bad from the implementation point of view, there are some discussions in web. However, this is the way ST do, you choose if you want to use STM32_HAL.

osDelay is in CMSIS layer is implemented with vTaskDelay. Which use the systick function as timer. The FreeRTOS also use systick to do task context switch. According to FreeRTOS document. The NVIC priority of systick need to be lowest. (So it won't get into the middle of ISR).

Which function is preferred depend on what you are doing, one has highest priority and the one has lowest (according to ST and FreeRTOS recommendation). That's the reason that if you use STM32CubeMX, it will ask you to assign a hardware timer as the 'tick' in addition to systick if you choose to use FreeRTOS.

Sink
  • 57
  • 3
0

The answer is quite simple, If your project is bare-metal (means without os), you should(or can) use HAL_Delay.

The "weak" symbol implementation uses a code like the below. You can declare your own function if you want.

__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;

  /* Add a period to guaranty minimum wait */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }

  while((HAL_GetTick() - tickstart) < wait)
  {
  }
}

But if your project has an os (lets say FreeRTOS or Keil-RTX) or any other, then you should use a osDelay. This is because as @ARK4579 explained if you use hal_delay with the above function definition then the above function is a blocking call, which means this is just consuming cycles. With osDelay, the caller task will go into blocked state and when the ticks are completed, the task will be in Ready state once again. So here you don't consume any cycles. It is a non-blocking call.

V B
  • 75
  • 5