FreeRTOS:osDelay 与 HAL_delay

Posted

技术标签:

【中文标题】FreeRTOS:osDelay 与 HAL_delay【英文标题】:FreeRTOS: osDelay vs HAL_delay 【发布时间】:2017-07-05 16:53:24 【问题描述】:

在使用 STM32CubeMx 创建 FreeRTOS 应用项目时,您可以使用两种方法来引入延迟,即 osDelayHAL_Delay

它们之间有什么区别,应该首选哪一个?

osDelay代码:

/*********************** 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 代码:

/**
* @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)
  
  

【问题讨论】:

显然从给定的代码(甚至不知道任何关于 RTOS 的情况下),第一个依赖于vTaskDelay,第二个依赖于轮询。所以你基本上应该看看vTaskDelay的实现。 【参考方案1】:

HAL_Delay 不是 FreeRTOS 函数,_osDelay 是内置函数FreeRTOS 功能。 (acc @Clifford:)它们都是完全不同的功能,由不同的开发人员用于不同的目的。

osDelayCMSIS 库 的一部分,并在内部使用 vTaskDelay() 来引入延迟,区别在于 的输入参数osDelay 是以毫秒为单位的延迟时间,而 _vTaskDelay() 的输入参数是要延迟的 Ticks 数。 (acc. @Bence Kaulics:) 使用此功能,操作系统将收到延迟通知,并且操作系统将在特定时间段内将任务状态更改为阻塞

HAL_Delay 是我们处理器的硬件抽象层的一部分。它基本上使用轮询来引入延迟。 (acc. @Bence Kaulics:) 使用此功能,操作系统不会收到延迟通知。此外,如果您不使用操作系统,则 HAL_Delay 是 HAL 库提供的默认且唯一的阻塞延迟。 (acc。@Clifford:)这是 HAL 库 的一部分,可以在没有 FreeRTOS 的情况下使用(或在 FreeRTOS 未运行时)

要使用 FreeRTOS 函数引入延迟,您可以在调度程序启动后使用vTaskDelay() 或vTaskDelayUntil()。

(acc。@Clifford:) 如果您希望您的应用程序具有确定性,请始终支持 FreeRTOS API 函数。CubeMX 是来自多个来源的部分的集合。

【讨论】:

【参考方案2】:

有一个具有最高优先级的任务。如果您打算使用HAL_Delay 来阻止任务,那么可能不会有上下文切换,因为调度程序不会被通知该任务当前只是在while 循环中轮询一个滴答计数器并且实际上确实如此不做任何有用的操作。优先级较低的任务不会运行。

另外一个函数使用了操作系统的vTaskDelay函数,我没有看它的源代码,但是可能这会通知操作系统当前任务要阻塞一段时间,所以任务的状态会改变到阻塞,同时调度器可以切换到较低优先级的任务。

【讨论】:

嗯,这是有道理的。这就是为什么有两个,所以你可以根据你的任务要求使用它们中的任何一个 @ARK4579 另外,如果您不使用操作系统,那么 HAL_Delay 是默认的,并且是 HAL 库提供的唯一阻塞延迟。 @ARK4579 :不,有两种方法,因为它们是从不同的提供者独立开发的,用于完全不同的目的。 HAL 可以在没有 RTOS 的情况下使用(或在 RTOS 运行之前),并且是一个较低级别的服务 - 如果您希望您的应用程序确定性地调度,请始终支持 RTOS API。 CubeMX 是来自多个来源的部件的集合。【参考方案3】:

它看起来不像 HAL_Delay() 旨在与 RTOS 一起使用,因为它是一个 NULL 循环延迟。如果您从 RTOS 任务调用 HAL_Delay(),则该任务将继续运行,直到延迟到期。较高优先级的任务将能够运行,但较低优先级的任务将在延迟期间没有任何处理时间。这是对处理时间和功率的浪费,并且可能不利于系统响应能力。

osDelay() 另一方面,使用 RTOS 会产生延迟。它告诉 RTOS 在延迟期到期之前它无事可做,因此 RTOS 在此期间不会为任务分配任何处理时间。这节省了处理时间,潜在地节省了电力,并允许较低优先级的任务在延迟期间获得处理时间。 http://www.freertos.org/FAQWhat.html#WhyUseRTOS

【讨论】:

【参考方案4】:

HAL_Delay 在 stm32_HAL 库中使用,在某些情况下,包括在 ISR 中调用的函数。除了命名暗示它是硬件抽象层之外,使用 HAL_Delay (HAL_GetTick) 的定时器需要具有最高的 NVIC 优先级。 (因为它可能在 ISR 内部被调用,并且不能被阻止)从实现的角度来看这是好是坏,在 web.xml 中有一些讨论。不过ST是这样的,要不要用STM32_HAL你自己选。

osDelay 在 CMSIS 层是用 vTaskDelay 实现的。它使用 systick 功能作为计时器。 FreeRTOS 还使用 systick 进行任务上下文切换。根据 FreeRTOS 文档。 systick 的 NVIC 优先级需要最低。 (所以它不会进入 ISR 的中间)。

首选哪个功能取决于您在做什么,一个具有最高优先级,一个具有最低优先级(根据 ST 和 FreeRTOS 的建议)。这就是如果您使用 STM32CubeMX,如果您选择使用 FreeRTOS,它会要求您在 systick 之外分配一个硬件计时器作为“tick”。

【讨论】:

以上是关于FreeRTOS:osDelay 与 HAL_delay的主要内容,如果未能解决你的问题,请参考以下文章

osDelay() 等待时间不够

cube切换了时钟haldelay还不行

Arduino与FreeRTOS-FreeRTOS配置与简单任务创建

freeRTOS系列教程之第一章FreeRTOS概述与体验:1.1 FreeRTOS目录结构

freeRTOS系列教程之第一章FreeRTOS概述与体验:1.1 FreeRTOS的目录结构

FreeRTOS 任务与调度器