什么是中断?
让CPU打断正常运行的程序, 转而去处理紧急的事件 (程序 ) , 就叫中断
中断执行机制, 可简单概括为三步:
1, 中断请求: 外设产生中断请求 (GPIO外部中断、定时器中断等 )
2, 响应中断: CPU停止执行当前程序, 转而去执行中断处理程序 (ISR )
3, 退出中断: 执行完毕, 返回被打断的程序处, 继续往下执行
中断优先级分组设置
ARM Cortex-M 使用了 8 位宽的寄存器来配置中断的优先等级, 这个寄存器就是中断优先级配置寄存器
但STM32, 只用了中断优先级配置寄存器的高4位 [7 : 4], 所以STM32提供了最大16级的中断优先等级
STM32 的中断优先级可以分为抢占优先级
和子优先级
抢占优先级: 抢占优先级高的中断可以打断正在执行但抢占优先级低的中断
子优先级: 当同时发生具有相同抢占优先级的两个中断时, 子优先级数值小的优先执行
注意: 中断优先级数值越小越优先
中断优先级分组设置
一共有 5 种分配方式, 对应着中断优先级分组的 5 个组
优先级分组 | 抢占优先级 | 子优先级 | 优先级配置寄存器高 4 位 |
---|---|---|---|
NVIC_PriorityGroup_0 | 0 级抢占优先级 | 0-15 级子优先级 | 0bit 用于抢占优先级 4bit 用于子优先级 |
NVIC_PriorityGroup_1 | 0-1 级抢占优先级 | 0-7 级子优先级 | 1bit 用于抢占优先级 3bit 用于子优先级 |
NVIC_PriorityGroup_2 | 0-3 级抢占优先级 | 0-3 级子优先级 | 2bit 用于抢占优先级 2bit 用于子优先级 |
NVIC_PriorityGroup_3 | 0-7 级抢占优先级 | 0-1 级子优先级 | 3bit 用于抢占优先级 1bit 用于子优先级 |
NVIC_PriorityGroup_4 | 0-15 级抢占优先级 | 0 级子优先级 | 4bit 用于抢占优先级 0bit 用于子优先级 |
在HAL_Init中通过调用函数HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4)
即可完成设置
中断优先级分组设置
特点:
- 低于
configMAX_SYSCALL_INTERRUPT_PRIORITY
优先级的中断里才允许调用 FreeRTOS 的API函数 - 建议将所有优先级位指定为抢占优先级位, 方便FreeRTOS管理
- 中断优先级数值越小越优先, 任务优先级数值越大越优先
中断相关寄存器
三个系统中断优先级配置寄存器, 分别为 SHPR1. SHPR2. SHPR3
SHPR1寄存器地址: 0xE000ED18
SHPR2寄存器地址: 0xE000ED1C
SHPR3寄存器地址: 0xE000ED20
PendSV 和 SysTick 设置最低优先级的作用: 保证系统任务切换不会阻塞系统其他中断的响应
三个, 分别为 PRIMASK、 FAULTMASK 和BASEPRI
FreeRTOS所使用的中断管理就是利用的BASEPRI这个寄存器
BASEPRI: 屏蔽优先级低于某一个阈值的中断
比如: BASEPRI设置为0x50, 代表中断优先级在5~15内的均被屏蔽, 0~4的中断优先级正常执行
BASEPRI寄存器
屏蔽优先级低于某一个阈值的中断, 当设置为0时, 则不关闭任何中断
关中断程序示例:
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
msr basepri, ulNewBASEPRI
dsb
isb
}
}
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 /* FreeRTOS可管理的最高中断优先级 */
中断优先级在5 ~ 15的全部被关闭
当BASEPRI设置为0x50时:
在中断服务函数中调度 FreeRTOS 的API函数需注意:
- 中断服务函数的优先级需在 FreeRTOS 所管理的范围内
- 在中断服务函数里边需调用 FreeRTOS 的API函数, 必须使用带
FromISR
后缀的函数
开中断程序示例:
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
__asm
{
msr basepri, ulBASEPRI
}
}
FreeRTOS中断管理就是利用BASEPRI寄存器实现的