在实时操作系统中,中断是一种重要的机制,用于处理紧急事件,确保系统能够及时响应外部或内部的突发状况。FreeRTOS 作为一款广泛应用的实时操作系统,其中断管理机制设计精巧,既保证了中断处理的高效性,又与任务调度系统深度融合,确保整个系统的实时性和稳定性。
FreeRTOS 的中断管理主要涉及中断优先级的设置、中断服务例程(ISR)的编写规范,以及中断与任务之间的交互方式。通过合理配置和使用这些特性,开发者能够充分发挥硬件性能,实现复杂的实时应用。
FreeRTOS 支持中断优先级分组,通过配置configPRIO_BITS宏定义来确定优先级的位数。例如,在 32 位处理器上,若configPRIO_BITS设置为 4,那么就有 16 个优先级可供使用。优先级分组将优先级分为抢占式优先级和亚优先级(也称为子优先级),不同的分组方式决定了抢占式优先级和亚优先级的分配比例。
通过调用NVIC_PriorityGroupConfig()函数(以 Cortex-M 内核为例)可以设置优先级分组。例如,将优先级分组设置为抢占式优先级 3 位,亚优先级 1 位的代码如下:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
在 FreeRTOS 中,任务也有优先级。为了避免中断优先级与任务优先级产生冲突,中断优先级必须高于任务优先级。通过NVIC_SetPriority()函数(以 Cortex-M 内核为例)可以设置具体中断的优先级。例如,设置 USART1 中断的优先级为 2(假设抢占式优先级 3 位,亚优先级 1 位):
NVIC_SetPriority(USART1_IRQn, 2);
同时,FreeRTOS 提供了configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY宏来定义系统调用可安全执行的最高中断优先级。高于此优先级的中断在执行时不会被 FreeRTOS 的调度器打断,以保证中断处理的实时性(注意:低于此优先级的中断被屏蔽,并由FreeRTOS软件管理,既可用FromISR的API设置)。
FreeRTOS 在 Cortex-M 架构中,通过以下步骤管理中断:
BASEPRI
寄存器屏蔽优先级低于某个阈值的中断在FreeRTOSConfig.h
中:
// 配置系统调用可安全执行的最高中断优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
// 内核使用的中断优先级(通常等于上面的值)
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
configPRIO_BITS
:硬件实际使用的优先级位数(如 Cortex-M3/M4 为 4 位)FreeRTOS 将中断优先级划分为两部分:
BASEPRI
寄存器动态屏蔽FreeRTOS 在进入临界区时,会设置BASEPRI
寄存器:
// 屏蔽优先级<=configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY的中断
__set_BASEPRI(configKERNEL_INTERRUPT_PRIORITY);
FreeRTOS 要求 5~15 优先级的 ISR 必须使用特殊的 API与内核交互:
void vAnExampleInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// 处理中断...
// 如果需要唤醒任务,使用带"FromISR"后缀的API
xSemaphoreGiveFromISR( xBinarySemaphore, &xHigherPriorityTaskWoken );
// 如果有更高优先级任务就绪,强制上下文切换
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
FreeRTOS 提供 API 动态控制中断屏蔽:
// 禁用所有可屏蔽中断(5~15)
taskDISABLE_INTERRUPTS();
// 启用所有可屏蔽中断
taskENABLE_INTERRUPTS();
// 选择性屏蔽(仅屏蔽优先级<=5的中断)
vPortSetBASEPRI( configKERNEL_INTERRUPT_PRIORITY );
假设configPRIO_BITS=4
(4 位优先级),配置步骤如下:
NVIC_SetPriorityGrouping( 0xf ); // 4位抢占式优先级,0位亚优先级
#define configPRIO_BITS 4
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define configKERNEL_INTERRUPT_PRIORITY ( 5 << (8 - 4) ) // 即0x50
// 将USART1中断优先级设为5(由FreeRTOS管理)
NVIC_SetPriority(USART1_IRQn, 5);
// 将SysTick中断优先级设为0(最高优先级,不受FreeRTOS管理)
NVIC_SetPriority(SysTick_IRQn, 0);
寄存器 | 功能描述 | 屏蔽范围 | 是否影响 NMI | 是否影响 HardFault | 典型应用场景 |
---|---|---|---|---|---|
FAULTMASK | 屏蔽除 NMI 外的所有异常和中断,仅在异常处理期间可用,退出时自动清零。 | - 所有可屏蔽中断 - 所有异常(如 SVC、PendSV、SysTick) - HardFault |
否 | 是 | 极端临界区(不允许任何非 NMI 打断) |
PRIMASK | 屏蔽所有可屏蔽中断(不影响异常和 NMI、HardFault)。 | - 所有可屏蔽中断(如 GPIO、USART 等外设中断) - 不影响异常和不可屏蔽中断 |
否 | 否 | RTOS 任务切换临界区、中断安全操作 |
BASEPRI | 屏蔽优先级低于或等于设定阈值的可屏蔽中断(阈值范围:0~255,0 为最高优先级)。 | - 优先级 ≤ 阈值的可屏蔽中断 - 不影响高优先级中断、异常和不可屏蔽中断 |
否 | 否 | 按优先级分级屏蔽中断(精细控制) |
异常类型 | 全称 | 优先级 | 是否可屏蔽 | 触发条件 | 处理特点 |
---|---|---|---|---|---|
NMI | 不可屏蔽中断 | -2(最高) | 否 | - 外部紧急事件(如电源故障、看门狗超时) - 特定处理器定义的紧急信号 |
- 可打断任何代码(包括 FAULTMASK 生效时) - 处理函数不可被其他异常打断 |
HardFault | 硬件错误异常 | -1 | FAULTMASK 可屏蔽 |
场景 | 使用的寄存器 | 代码示例 | 作用 |
---|---|---|---|
任务切换临界区 | PRIMASK | taskENTER_CRITICAL() |
屏蔽可屏蔽中断,确保上下文切换安全 |
高优先级中断保护 | BASEPRI | __set_BASEPRI(0x80) |
屏蔽优先级 ≤ 0x80 的中断 |
绝对不可打断的操作 | FAULTMASK | __set_FAULTMASK(1) |
仅允许 NMI 打断,其他均屏蔽 |