FreeRTOS: osDelay против HAL_delay
При создании проекта приложения FreeRTOS с помощью STM32CubeMx есть два способа ввода задержки, а именно osDelay и HAL_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 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)
{
}
}
5 ответов
HAL_Delay НЕ является функцией FreeRTOS, а _osDelay является функцией, построенной вокруг функции FreeRTOS. (acc @Clifford:) Они оба совершенно разные функции разных разработчиков для разных целей.
osDelay является частью библиотеки CMSIS и использует vTaskDelay() для введения задержки с той разницей, что входным аргументом osDelay является время задержки в миллисекундах, в то время как входным аргументом _vTaskDelay() является число тиков, которые должны быть задержаны. (в соответствии с @Bence Kaulics:) Используя эту функцию, ОС будет уведомлена о задержке, и ОС изменит статус задачи на заблокированный для этого конкретного периода времени.
HAL_Delay является частью уровня аппаратной абстракции для нашего процессора. Он в основном использует опрос, чтобы ввести задержку. (в соответствии с @Bence Kaulics:) Используя эту функцию, ОС не будет уведомлена о задержке. Также, если вы не используете ОС, то HAL_Delay является значением по умолчанию и только задержка блокировки для использования, предоставляемая библиотекой HAL. (в соответствии с @Clifford:) Это является частью библиотеки HAL и может использоваться без FreeRTOS (или когда FreeRTOS не запущен)
Чтобы ввести Delay с использованием функций FreeRTOS, вы можете использовать vTaskDelay() или vTaskDelayUntil() после запуска планировщика.
(в соответствии с @Clifford:)
Всегда поддерживайте функцию FreeRTOS API functino, если вы хотите, чтобы ваше приложение было детерминированным.
CubeMX представляет собой набор деталей из нескольких источников.
Похоже, что HAL_Delay() не предназначен для использования с ОСРВ, потому что это задержка цикла NULL. Если вы вызовите HAL_Delay() из задачи RTOS, то эта задача будет продолжаться, пока не истечет задержка. Задачи с более высоким приоритетом смогут выполняться, но задачи с более низким приоритетом будут лишены времени обработки в течение периода задержки. Это пустая трата времени, мощности и может нанести ущерб быстродействию системы.
osDelay (), с другой стороны, производит задержку, используя RTOS. Он сообщает ОСРВ, что ему нечего делать до истечения периода задержки, поэтому ОСРВ не назначает время обработки задаче в течение этого периода. Это экономит время обработки, потенциально экономит электроэнергию и позволяет задачам с более низким приоритетом получать время обработки в течение периода задержки. http://www.freertos.org/FAQWhat.html
Есть задача с наивысшим приоритетом. Если вы собираетесь использовать HAL_Delay
чтобы заблокировать задачу, вероятно, не будет переключения контекста, потому что планировщик не будет уведомлен о том, что задача в настоящее время просто опрашивает счетчик тиков в while
цикл и на самом деле не делает никаких полезных операций. Задачи с более низким приоритетом не будут выполняться.
Другая функция использует vTaskDelay
Функция операционной системы, я не заглядывал в ее исходный код, но, вероятно, это будет уведомлять ОС, что текущая задача хочет быть заблокированной на определенное время, поэтому состояние задачи изменится на заблокированное, и планировщик может переключиться на более низкий уровень приоритета. задача в то же время.
Ответ довольно прост. Если ваш проект на голом железе (то есть без ОС), вы должны (или можете) использовать HAL_Delay.
В «слабой» реализации символа используется код, подобный приведенному ниже. Вы можете объявить свою собственную функцию, если хотите.
__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)
{
}
}
Но если в вашем проекте есть ОС (скажем, FreeRTOS или Keil-RTX) или любая другая, вам следует использовать osDelay. Это связано с тем, что, как объяснил @ARK4579, если вы используете hal_delay с приведенным выше определением функции, то вышеуказанная функция является блокирующим вызовом, что означает, что это просто потребление циклов. С osDelay вызывающая задача перейдет в заблокированное состояние, и когда тики будут завершены, задача снова будет в состоянии готовности. Так что здесь вы не потребляете никаких циклов. Это неблокирующий вызов.
HAL_Delay используется в библиотеке stm32_HAL, включая, в некоторых случаях, функцию, вызываемую в ISR. Помимо того, что подразумевается, что это абстрактный уровень оборудования, таймер, который использовал HAL_Delay (HAL_GetTick), должен иметь наивысший приоритет NVIC. (потому что он может быть вызван внутри ISR и не может быть заблокирован) Хорошо это или плохо с точки зрения реализации, в сети есть некоторые обсуждения. Однако именно так поступает ST, вы выбираете, хотите ли вы использовать STM32_HAL.
osDelay находится на уровне CMSIS и реализован с помощью vTaskDelay. Которые используют функцию systick в качестве таймера. FreeRTOS также использует systick для переключения контекста задачи. Согласно документу FreeRTOS. Приоритет NVIC systick должен быть самым низким. (Чтобы он не попал в середину ISR).
Какая функция предпочтительна, зависит от того, что вы делаете: одна имеет наивысший приоритет, а другая - самый низкий (согласно рекомендациям ST и FreeRTOS). По этой причине, если вы используете STM32CubeMX, он попросит вас назначить аппаратный таймер как "галочку" в дополнение к systick, если вы решите использовать FreeRTOS.