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

7

在了解了一些关于中断优先级的知识后,我仍然有点困惑,不知道可以在SysTick_IRQn(每1毫秒调用FreeRTOS调度程序的ISR)上调用哪些值来使用HAL_NVIC_SetPriority()

简而言之;

我认为在configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY在FreeRTOSConfig.h中设置为5的情况下,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)(相当高)之间的任何值都是允许的。混淆的原因在于,在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) )

__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)
{ 

因此,您只有4个位可供设置,但实际上您可以决定其中多少是PreemptPriority位,多少是SubPriority位,如下所示:

HAL_NVIC_SetPriorityGrouping() 来自UM1940,9.2.4,p124/1371。 enter image description here

FreeRTOS在其文档中表示

如果您正在使用带有STM32驱动程序库的STM32,则在启动RTOS之前调用NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);以确保所有优先级位都被分配为抢占优先级位。

因此,在您的代码中应该首先执行以下操作(至少在通过osKernelStart()vTaskStartScheduler()启动FreeRTOS调度程序之前):

/* Set Interrupt Group Priority */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

这将配置您所有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);

其中15是SysTick的时钟中断优先级。由于我们有所有的4个位,因此这给了我们一个0到15的优先级范围,其中15是最低的中断优先级,0是最高的优先级。

为什么我们要将SysTick设置为最低优先级?答案是:这是FreeRTOS调度程序的良好实践,而SysTick中断则会调用它。事实上,根据他们自己的文档,如果给它太高的优先级,会破坏FreeRTOS。让我们尝试理解一下这个问题。

我们现在知道,PreemptPriority设置的中断选项是0到15,但甚至比这还要窄:我们只能将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) = 十进制80 = 0b01010000。
FreeRTOS文档提供了一些有价值的见解,解释了左移的原因(请参阅标题为“Cortex-M Internal Priority Representation”的部分),但我无法理解更多内容。

现在做出一些合理的猜测,我们知道我们的优先级选项是0到15,其中0是最高的,15是最低的,而且我们知道configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY是5,那么我们或许可以使用15-5=10作为最高优先级,15作为最低优先级,或者5到15也可以,但0到4是禁止的?我不知道...我很困惑...


我会说 - 如果你不理解优先级系统的工作原理,在RTOS这样复杂的环境中最好不要碰它。首先在裸机环境下学习它的工作原理,考虑为什么要改变它,当你成为NVIC大师时再调整RTOS。我建议使用CMSIS函数。 - 0___________
1
Gabriel,谢谢你的问题!这真的帮助我更好地理解了这个话题:)。到目前为止,这是一条相当具有挑战性的道路..! - bas
1个回答

3

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

在上面的示例中,如果您的中断使用了FreeRTOS API调用,则可以使用5到15的中断优先级。如果它们没有使用FreeRTOS API调用,则可以使用0到15的任何优先级中断。

不必担心移位,因为这一切都已经为您处理好了,但原因是优先级寄存器的前4位被使用(请注意,某些处理器使用不同数量的优先级位)。


感谢您的回答。好的,configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 描述的是一个 NVIC 优先级,对吗?即使它在 FreeRTOSConfig.h 中?而 FreeRTOS(任务)优先级将是您在调用 xTaskCreate(taskFunction, "Task Name", configMINIMAL_STACK_SIZE * 5, NULL, tskIDLE_PRIORITY + 1, NULL) 时传递的参数,例如,在此示例中,FreeRTOS 任务优先级比空闲任务高 1。 - Gabriel Staples
所以,确认一下:configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY是NVIC优先级的限制(这些优先级将传递给HAL_NVIC_SetPriority()),而FreeRTOS优先级在xTaskCreate()uxTaskPriorityGet()vTaskPrioritySet()等中使用,是吗?这就是你所说的不要混淆两者之间区别的地方? - Gabriel Staples
1
是的。MAX SYSCALL PRIORITY 是可以调用系统(API)的中断的最大 NVIC 优先级。这是因为 RTOS 使用更高优先级的中断,不应被调用进入 RTOS,否则会破坏 RTOS 数据。正如您所说,任务优先级由 xTaskCreate 使用,其中 0 是最低优先级任务。 - Realtime Rik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接