使用 STM32 和 FreeRTOS 时,“HAL_NVIC_SetPriority()”的有效值是什么?

Gab*_*les 8 c stm32 freertos

在学习了有关中断优先级的一些知识之后,我仍然有点困惑,试图理解允许HAL_NVIC_SetPriority()SysTick_IRQn(每 1 毫秒调用 FreeRTOS 调度程序的 ISR)上调用什么值。

太长了;

我的一部分认为HAL_NVIC_SetPriority(SysTick_IRQn, 15 ,0U)(可能的最低优先级)和HAL_NVIC_SetPriority(SysTick_IRQn, 10 ,0U)(更高一点)之间的任何内容都是允许的,而我的一部分认为HAL_NVIC_SetPriority(SysTick_IRQn, 15 ,0U)(可能的最低优先级)和HAL_NVIC_SetPriority(SysTick_IRQn, 5 ,0U)(更高一点)之间的任何内容都是允许的。这是假设configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY在 FreeRTOSConfig.h 中设置为 5。令人困惑的是,在 FreeRTOS 中,数字越大优先级越高,但在 STM32 中,数字越高优先级越低,并且文档非常难以理解。


细节:

为了证明我已经做出了勇敢的努力,也为了帮助大家帮我填补空白,以下是我目前的理解。我将以这样一种方式写下我所知道的真实情况的描述,看起来像是在教,尽管我正在寻求上述问题的答案,以及 更正确认补充您认为合适的洞察力。

尽管这可能适用于许多 STM32 微控制器或系列,但让我们特别针对 STM32F207ZG 进行讨论

注意:STM32CubeF2下载在这里

我的理解:

如果您查看标准FreeRTOSConfig.h文件(例如:STM32Cube_FW_F2_V1.7.0/Projects/STM322xG_EVAL/Applications/FreeRTOS/FreeRTOS_ThreadCreation/Inc/FreeRTOSConfig.h),您将看到以下内容:

/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
    /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
    #define configPRIO_BITS             __NVIC_PRIO_BITS
#else
    #define configPRIO_BITS             4        /* 15 priority levels */
#endif

/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY         0xf

/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5

/* Interrupt priorities used by the kernel port layer itself.  These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY         ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
Run Code Online (Sandbox Code Playgroud)

__NVIC_PRIO_BITS在STM32Cube_FW_F2_V1.7.0/Drivers/CMSIS/Device/ST/STM32F2xx/Include/stm32f217xx.h中定义,因为4U“STM32F2XX 使用 4 位作为优先级”。

首先,这很有趣,因为这意味着可用的 8 个优先级位中只有 4 个被实际使用!STM32 HAL 库调用HAL_NVIC_SetPriority()有一个如下所示的标头,似乎表明您有 8 位需要设置(PreemptPriority从 0 到 15 和SubPriority从 0 到 15),但实际上您没有 - 您只有 4 位需要设置。

/**
  * @brief  Sets the priority of an interrupt.
  * @param  IRQn: External interrupt number.
  *         This parameter can be an enumerator of IRQn_Type enumeration
  *         (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f2xxxx.h))
  * @param  PreemptPriority: The preemption priority for the IRQn channel.
  *         This parameter can be a value between 0 and 15
  *         A lower priority value indicates a higher priority 
  * @param  SubPriority: the subpriority level for the IRQ channel.
  *         This parameter can be a value between 0 and 15
  *         A lower priority value indicates a higher priority.          
  * @retval None
  */
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)
{ 
Run Code Online (Sandbox Code Playgroud)

所以,你只有 4 位需要设置,但事实证明你可以决定多少位PreemptPriority和多少位SubPriority,如下所示:

HAL_NVIC_SetPriorityGrouping()来自UM1940,9.2.4,p124/1371。 在此输入图像描述

FreeRTOS 在他们的文档中说

如果您将 STM32 与 STM32 驱动程序库一起使用,请通过调用 NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); 确保将所有优先级位分配为抢占优先级位;在 RTOS 启动之前。

因此,您应该在代码中做的第一件事(至少在通过osKernelStart()or启动 FreeRTOS 调度程序之前vTaskStartScheduler())是:

/* Set Interrupt Group Priority */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
Run Code Online (Sandbox Code Playgroud)

这会将所有 4 个优先级位配置为PreemptPriority位,并且没有位配置为SubPriority位。这意味着对该HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)函数的任何调用现在将始终使用 0 作为最右侧的参数。

然后你应该本质上调用(注意:这是通过以下方式调用的HAL_InitTick()

/*Configure the SysTick IRQ priority */
HAL_NVIC_SetPriority(SysTick_IRQn, 15 ,0U);
Run Code Online (Sandbox Code Playgroud)

其中15是 SysTick 刻度优先级。由于我们拥有所有 4 位可用,因此优先级范围为 0 到 15,其中 15 是最低中断优先级,0 是最高优先级。

那么,为什么我们要将 SysTick 设置为最低优先级呢?答案:因为这对于 SysTick 中断调用的 FreeRTOS 调度程序来说是一个很好的做法。事实上,根据他们自己的文档,给它太高的优先级会破坏 FreeRTOS。让我们试着弄清楚这一点。

我们知道现在我们的中断选项设置为 0 到 15 PreemptPriority,但它甚至比这更窄:我们只能将 SysTick 中断的 PreemptPriority 设置为10 到 15(我想——我在这里需要一些帮助)。为什么是10到15?嗯,FreeRTOS 文档(尽管这非常令人困惑)甚至明确指出:

以“FromISR”结尾的 FreeRTOS 函数是中断安全的,但即使这些函数也不能从逻辑优先级高于[即:数字上较低]由 configMAX_SYSCALL_INTERRUPT_PRIORITY 定义的优先级的中断调用(configMAX_SYSCALL_INTERRUPT_PRIORITY 在 FreeRTOSConfig.h 头文件中定义) 。因此,任何使用 RTOS API 函数的中断服务例程都必须手动将其优先级设置为在数值上等于或大于 configMAX_SYSCALL_INTERRUPT_PRIORITY 设置的值。这可确保中断的逻辑优先级等于或小于 configMAX_SYSCALL_INTERRUPT_PRIORITY 设置。

现在,请返回本页顶部的FreeRTOSConfig.h 。我们知道__NVIC_PRIO_BITS是 4 并且我们看到:

configMAX_SYSCALL_INTERRUPT_PRIORITY(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)),这意味着它是5 << (8 - 4) = decimal 80 = 0b01010000

FreeRTOS 文档提供了一些关于左移原因的有价值的见解(请参阅标题为“Cortex-M 内部优先级表示”的部分),但除此之外我无法辨别。

因此,现在进行一些有根据的猜测,并知道我们的优先级选项是 0 到 15,其中 0 最高,15 最低,并且知道 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 是 5,我们也许可以使用 15 - 5 = 10 作为最高优先级,15 作为最低优先级,或者也许 5 到 15 是可以的,但 0 到 4 是禁止的?我不知道……我很困惑……

Rea*_*Rik 4

首先,不要将 FreeRTOS 任务优先级与 NVIC 优先级混淆。他们是完全不同的。

在上面的示例中,如果中断进行 FreeRTOS API 调用,您可以使用 5 到 15 的中断优先级。如果它们不进行 FreeRTOS API 调用,那么您可以使用 0 到 15 之间任意优先级的中断。

不用担心移位,因为它全部为您处理,但原因是使用了优先级寄存器的前 4 位(请注意,某些处理器使用不同数量的优先级位)。