Freertos中的几个中断优先级宏的理解

本文详细解释了STM32F4内核中断配置,包括最低优先级、系统API调用限制、kernel中断优先级设置及优先级分组的重要性,确保实时性和避免系统混乱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里以STM32F4-Cortex-M4内核为例,来记录下面这些配置是什么意思。

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

这个是内核优先级分组的位数,对于STM32F4来说,使用了4位来表示优先级。这里把优先级
设置到最低,主要是能够为了其它中断能够打断内核的中断(滴答,pendsv),以达到实时性

/* 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 2

上面的优先级说的意思就是,不要让抢占优先级大于configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY的中断调用rtos的api(_fromISR). 注意这里,在使用中断时,一定不要忘记配置中断优先级(默认为2),设置的优先级一定要小于这个值(数字要大于) 比如下面配置为2,那么优先级number小于2的,一定不要调用rtos api。如果调用了,rtos的一些状态就乱了(比如中断嵌套层数)系统就跑死掉了。

/* 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) )
//M4的抢占优先级在高四位,即[7:4],所以下面这个要左移动4为

上面这个主要是为了获取到当前平台所支持的最小优先级。这里上面已经配置了configLIBRARY_LOWEST_INTERRUPT_PRIORITY 为0xf,因为configPRIO_BITS在cmisc中配置为4。所以这里是左移4.之所以减掉4,是为了获取剩余不用的位数。为什么要把kernel设置为最低优先级,这个我认为是为了确保系统实时性。因为已经有了pendsv中断,有些中断是能延迟响应的。

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

这个同上面一样,获取最大允许使用系统API的应用权限等级。目前configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 定义为2,则2<<(8-4) 即32.,只允许中断优先级大于2的中断调用系统API。

调度器代码记录:

BaseType_t xPortStartScheduler( void )
{
	#if( configASSERT_DEFINED == 1 )
	{
		volatile uint32_t ulOriginalPriority;
		volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
		volatile uint8_t ucMaxPriorityValue;

		/* Determine the maximum priority from which ISR safe FreeRTOS API
		functions can be called.  ISR safe functions are those that end in
		"FromISR".  FreeRTOS maintains separate thread and ISR API functions to
		ensure interrupt entry is as fast and simple as possible.

		Save the interrupt priority value that is about to be clobbered. */
		//下面pucFirstUserPriorityRegister为应用程序第一个中断优先级寄存器,从中断向量表看到这个是WWDG
		ulOriginalPriority = *pucFirstUserPriorityRegister;

		/* Determine the number of priority bits available.  First write to all
		possible bits. */
		*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; //portMAX_8_BIT_VALUE=0xFF

		/* Read the value back to see how many bits stuck. */
		ucMaxPriorityValue = *pucFirstUserPriorityRegister;
		//虽然上面设置的是0xff,当请看下面日志打印,打印出来读过来的是0xf0.这个主要是Cortex-M4,只用4为来表示优先级
        LOGD("armwind:%x,%x",ucMaxPriorityValue, portMAX_8_BIT_VALUE); 
		/* The kernel interrupt priority should be set to the lowest
		priority. */
		configASSERT( ucMaxPriorityValue == ( configKERNEL_INTERRUPT_PRIORITY & ucMaxPriorityValue ) );
        LOGD("ucMaxPriorityValue:%x,KER_INT:%x", ucMaxPriorityValue, configKERNEL_INTERRUPT_PRIORITY);
		/* Use the same mask on the maximum system call priority. */
		ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;

		/* Calculate the maximum acceptable priority group value for the number
		of bits read back. */
		//计算最大的优先级分组
		ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; //portMAX_PRIGROUP_BITS=0x07
		while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
		{   //ucMaxPriorityValue = 0xf0
			ulMaxPRIGROUPValue--;
			//下面0xf0开始左移1位,由于ucMaxPriorityValue = 0xf0,所以能左移4次,则ulMaxPRIGROUPValue -= 4 = 3;
			ucMaxPriorityValue <<= ( uint8_t ) 0x01; 
		}

		/* Shift the priority group value back to its position within the AIRCR
		register. */
		ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; //portPRIGROUP_SHIFT = 8 即3<<8 = 0x300
		ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; 
		//portPRIORITY_GROUP_MASK = (0x07UL << 8UL),则上面的与(&) 算下来为, 0x300 & 0x700 = 0x300
		//此时系统记录ulMaxPRIGROUPValue = 0x300

		/* Restore the clobbered interrupt priority register to its original
		value. */
		*pucFirstUserPriorityRegister = ulOriginalPriority; //还原原始中断优先级
	}
	#endif /* conifgASSERT_DEFINED */

	/* Make PendSV and SysTick the lowest priority interrupts. */
	//将systick和pendsv的中断优先级设置为最低,原因是为了实时性。
	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;

下面是我加的日志打印出来的,可以看到明明写入的是0xff,可是读过来的是0xf0,这也就是所使用4bit作为优先级

RTOS_CORE [D] xPortStartScheduler:369 armwind:f0,ff
RTOS_CORE [D] xPortStartScheduler:373 ucMaxPriorityValue:f0,KER_INT:f0

上面可以看到最大的优先级分组为0x300,而且FREERTOS官网也建议将Cortex-M4优先级分组设置为Group4,即0x300。默认情况下如果不设置Group4,内核是跑不稳定的,一般是卡死了。这里我特意将stm32f4的中断优先级分组设置为Group3,档案是肯定的,内核卡死。来看一段日志

#if( configASSERT_DEFINED == 1 )

	void vPortValidateInterruptPriority( void )
	{
	uint32_t ulCurrentInterrupt;
	uint8_t ucCurrentPriority;

		/* Obtain the number of the currently executing interrupt. */
		ulCurrentInterrupt = vPortGetIPSR();
        LOGI("ulCurrentInterrupt:0x%d",ulCurrentInterrupt);
		/* Is the interrupt number a user defined interrupt? */
		if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
		{
		
			/* Look up the interrupt's priority. */
			ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];

			/* The following assertion will fail if a service routine (ISR) for
			an interrupt that has been assigned a priority above
			configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
			function.  ISR safe FreeRTOS API functions must *only* be called
			from interrupts that have been assigned a priority at or below
			configMAX_SYSCALL_INTERRUPT_PRIORITY.

			Numerically low interrupt priority numbers represent logically high
			interrupt priorities, therefore the priority of the interrupt must
			be set to a value equal to or numerically *higher* than
			configMAX_SYSCALL_INTERRUPT_PRIORITY.

			Interrupts that	use the FreeRTOS API must not be left at their
			default priority of	zero as that is the highest possible priority,
			which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
			and	therefore also guaranteed to be invalid.

			FreeRTOS maintains separate thread and ISR API functions to ensure
			interrupt entry is as fast and simple as possible.

			The following links provide detailed information:
			http://www.freertos.org/RTOS-Cortex-M3-M4.html
			http://www.freertos.org/FAQHelp.html */
            LOGI("ucCurrentPriority:0x%x,ucMaxSysCallPriority:0x%x",ucCurrentPriority, ucMaxSysCallPriority);
            LOGI("result:%d",ucCurrentPriority >= ucMaxSysCallPriority);
			configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
		}

		/* Priority grouping:  The interrupt controller (NVIC) allows the bits
		that define each interrupt's priority to be split between bits that
		define the interrupt's pre-emption priority bits and bits that define
		the interrupt's sub-priority.  For simplicity all bits must be defined
		to be pre-emption priority bits.  The following assertion will fail if
		this is not the case (if some bits represent a sub-priority).

		If the application only uses CMSIS libraries for interrupt
		configuration then the correct setting can be achieved on all Cortex-M
		devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
		scheduler.  Note however that some vendor specific peripheral libraries
		assume a non-zero priority group setting, in which cases using a value
		of zero will result in unpredicable behaviour. */
		configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); -------line798
	}

#endif /* configASSERT_DEFINED */

上面如果我们将优先级分组设置为Group3,则前面计算出来的ulMaxPRIGROUPValue=0x300;

RTOS_CORE  [D] xMBPortEventPost:137 obj:20019dcc,role:0,ev:EV_READY
RTOS_CORE  [I] vPortValidateInterruptPriority:750 ulCurrentInterrupt:0x44
RTOS_CORE  [I] vPortValidateInterruptPriority:781 ucCurrentPriority:0x50,ucMaxSysCallPriority:32
RTOS_CORE  [E] vPortValidateInterruptPriority:798 ASSERT ERROR:0

.由于Group3对应的是0x400,所以上面的断言就为假了,就卡死在哪里。

#define NVIC_PriorityGroup_0         ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
                                                            4 bits for subpriority */
#define NVIC_PriorityGroup_1         ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
                                                            3 bits for subpriority */
#define NVIC_PriorityGroup_2         ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
                                                            2 bits for subpriority */
#define NVIC_PriorityGroup_3         ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
                                                            1 bits for subpriority */
#define NVIC_PriorityGroup_4         ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
                                                            0 bits for subpriority */

优先级分组:
在这里插入图片描述

<think>好的,用户问的是“这个stm32配置了freertos以后的中断优先级是怎么样的”。之前他遇到了设置定时器中断优先级的问题,现在想全面了解配置FreeRTOS后的中断优先级机制。我需要先回忆FreeRTOSSTM32中断优先级相关知识。 首先,STM32中断优先级分为抢占优先级和子优先级,数值越小优先级越高。而FreeRTOS为了管理中断安全,引入了configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY这个参数,用来限制可以安全调用FreeRTOS API的中断优先级。默认情况下,这个值设为5,所以抢占优先级高于5(即数值≤4)的中断不能调用API,否则会导致问题。用户之前无法设置0-4就是这个原因。 现在用户可能想知道整个中断优先级的结构,以及如何正确配置。需要分几个部分说明:FreeRTOS中断安全机制、中断分类、配置优先级时的注意事项,以及实际应用中的建议。可能还需要对比有无FreeRTOS时的区别,帮助用户理解变化。 要注意用户可能不太熟悉FreeRTOS内部机制,需要用简单明了的语言解释。同时,用户可能关心如何配置不同中断优先级,特别是那些需要调用API的中断和不需要的。需要给出具体例子,比如HAL库中的SysTick、PendSV,以及外设定时器、串口等的中断设置。 还要考虑用户可能在实际项目中遇到的常见问题,比如中断优先级冲突、任务调度延迟等,给出调试建议。最后,总结配置步骤,帮助用户快速应用。 需要确保回答结构清晰,分点列出,可能用表格对比不同中断类型,以及配置示例。避免使用过多术语,但必要的术语需要解释清楚,比如抢占优先级、子优先级、临界区等。 最后检查是否覆盖了用户可能的问题点:为什么需要这样配置,如何设置不同中断,常见错误和解决方法,确保回答全面且实用。</think>--- ### **STM32配置FreeRTOS后的中断优先级详解** 在STM32中结合FreeRTOS时,中断优先级的设计直接影响系统稳定性和实时性。以下是关键规则和配置指南: --- ### **一、中断优先级机制** #### 1. **STM32的NVIC优先级结构** - **优先级数值范围**:STM32使用4位优先级(0-15),数值越小优先级越高。 - **优先级分组**:通过`HAL_NVIC_SetPriorityGrouping()`设置分组方式(通常为分组4,即抢占优先级占4位,子优先级占0位)。 ```c // 默认分组(推荐): HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); // 抢占优先级0-15,子优先级固定为0 ``` #### 2. **FreeRTOS中断安全约束** - **关键参数**:`configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY` - **作用**:定义可以安全调用FreeRTOS API的中断的最高抢占优先级。 - **默认值**:通常为5(对应优先级数值5,实际优先级高于数值更小的中断)。 - **规则**: - 若中断需要调用FreeRTOS API(如`xQueueSendFromISR()`),其抢占优先级 **必须 ≥** `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`(数值≥5)。 - 抢占优先级更高(数值<5)的中断 **禁止调用FreeRTOS API**,否则可能导致数据竞争或系统崩溃。 --- ### **二、中断分类与优先级配置** #### 1. **FreeRTOS内核相关中断** | 中断类型 | 默认抢占优先级 | 作用 | 是否可修改 | |-----------------|----------------|---------------------------|---------------------| | **SysTick** | 15(最低) | FreeRTOS时间片调度 | 不可修改(自动设置)| | **PendSV** | 15(最低) | 上下文切换(任务切换) | 不可修改 | #### 2. **用户中断** | 中断类型 | 推荐抢占优先级范围 | 是否调用FreeRTOS API | 配置要求 | |-------------------------|--------------------|----------------------------|-----------------------------| | **需调用API的中断** | 5-15 | 是(如发送队列、信号量) | 优先级数值≥`configLIBRARY_MAX_SYSCALL...` | | **不调用API的中断** | 0-15 | 否(仅硬件操作) | 无限制 | --- ### **三、配置步骤(以STM32CubeMX为例)** #### 1. **配置FreeRTOS参数** - 在`FreeRTOSConfig.h`中确认以下参数: ```c #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 // 默认值,允许调用API的中断优先级下限 #define configKERNEL_INTERRUPT_PRIORITY 15 // SysTick和PendSV的优先级(最低) ``` #### 2. **配置外设中断优先级** - **案例1:定时器中断需调用FreeRTOS API** - 在CubeMX的NVIC设置中,将定时器的抢占优先级设为5-15(例如5)。 - 确保中断服务程序(ISR)中调用的FreeRTOS函数均为`FromISR`版本: ```c void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR(hSemaphore, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } ``` - **案例2:外部中断不调用API** - 抢占优先级可设为0-4(高优先级快速响应): ```c HAL_NVIC_SetPriority(EXTI0_IRQn, 3, 0); // 抢占优先级=3 HAL_NVIC_EnableIRQ(EXTI0_IRQn); ``` --- ### **四、调试与常见问题** #### 1. **中断优先级冲突** - **症状**:高优先级中断长时间占用CPU,导致任务无法调度。 - **解决**: - 确保高优先级中断(0-4)执行时间极短(如仅置标志位)。 - 使用`vApplicationTickHook()`在SysTick钩子函数中处理非实时任务。 #### 2. **FreeRTOS API调用崩溃** - **症状**:在抢占优先级<5的中断中调用API后触发HardFault。 - **解决**: - 检查`configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`是否≥中断优先级数值。 - 使用`configASSERT()`捕捉非法API调用。 --- ### **五、配置总结** | 中断类型 | 抢占优先级范围 | 调用FreeRTOS API | 安全建议 | |-----------------------|-----------------|------------------|-----------------------------------------------| | SysTick、PendSV | 15(最低) | 不可调用 | 禁止修改 | | 需调API的用户中断 | 5-15 | 必须使用FromISR | 优先级数值≥`configLIBRARY_MAX_SYSCALL...` | | 不调API的用户中断 | 0-15 | 禁止调用 | 高优先级中断执行时间需极短(<10μs) | --- ### **六、关键原则** 1. **优先级数值 vs 实际优先级**:数值越小,实际优先级越高。 2. **中断服务程序(ISR)最小化**:ISR中仅做关键操作,复杂逻辑交给任务处理。 3. **临界区保护**:在任务中操作共享资源时,使用`taskENTER_CRITICAL()`和`taskEXIT_CRITICAL()`。 通过合理配置中断优先级,可确保FreeRTOS任务调度与硬件中断的高效协同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值