一、什么是中断
中断时微控制器一个很常见的特性,中断是由硬件产生,当中断产生以后CPU就会中断当前的流程而去处理中断服务,Cortex-M内核的MCU提供了一个用于中断管理的嵌套向量中断控制器(NVIC)。
二、中断优先级分组定义
当多个中断来临的时候处理器应该响应哪一个中断是由中断的优先级来决定的,高优先级的中断(优先级编号小)肯定是首先得到响应的,而且高优先的中断可以抢占低优先级的中断,这个就是中断嵌套。
Cortex-M处理器的有些中断是具有固定的优先级的,比如复位、NMI、HardFault,这些中断的优先级都是负数,优先级也是最高的。
STM32,只用了中断优先级配置寄存器的高4位 [7 : 4],所以STM32提供了最大16级的中断优先等级,MSB 对齐。
STM32优先级分组:
ST 官方默认的是组 4,4 位优先级就都全是抢占优先级了,没有亚优先级,那么就有 0~15 共 16 个优先级。
三、用于中断屏蔽的特殊寄存器
PRIMASK 寄存器
PRIMASK 用于禁止除 NMI 和 HardFalut 外的所有异常和中断。
只有 1 个位的寄存器,当它置 1 时,就关掉所有可屏蔽的异常,只剩NMI和HardFalut 可以响应。当它置 0 时,表示没有关中断。
FAULTMASK 寄存器
PRIMASK 用于禁止除 NMI 外的所有异常和中断。它可以连 HardFault 都屏蔽掉。
只有 1 个位的寄存器,当它置 1 时,就关掉所有可屏蔽的异常,只剩NMI可以响应。当它置 0 时,表示没有关中断。
BASEPRI 寄存器
这个寄存器最多有 9 位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设置为 0,则不关闭任何中断。默认值是 0.
四、中断配置宏
1、configPRIO_BITS
此宏用来设置 MCU 使用几位优先级,STM32 使用的是 4 位,因此此宏为 4
2、configKERNEL_INTERRUPT_PRIORITY
此宏是用来设置最低优先级。STM32 优先级使用了 4 位,而且 STM32 配置的使用组 4,也就是 4 位都是抢占优先级。优先级数就是 16 个,最低优先级那就是 15。所以此宏就是 15
3、configKERNEL_INTERRUPT_PRIORITY
此宏用来设置内核中断优先级。
4、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
此宏用来设置 FreeRTOS 系统可管理的最大优先级。这里设置为了 5。也就是高于 5 的优先级(优先级数小于 5)不归 FreeRTOS 管理!
5、configMAX_SYSCALL_INTERRUPT_PRIORITY
此宏是 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 左移 4 位而来的,原因和宏 configKERNEL_INTERRUPT_PRIORITY 一样。此宏设置好以后,低于此优先级的中断可以安全的调用 FreeRTOS 的 API 函数,高于此优先级的中断 FreeRTOS 是不能禁止的,中断服务函数也不能调用 FreeRTOS 的 API 函数!
五、开关中断
FreeRTOS 开关中断函数为 portENABLE_INTERRUPTS ()和 portDISABLE_INTERRUPTS()
可以看出开关中断实际上是通过函数 vPortSetBASEPRI(0)和 vPortRaiseBASEPRI()来实现的。
六、临界段代码
临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段,比如有的外设的初始化需要严格的时序,初始化过程中不能被打断。FreeRTOS 在进入临界段代码的时候需要关闭中断,当处理完临界段代码以后再打开中断。FreeRTOS 系统本身就有很多的临界段代码,这些代码都加了临界段代码保护,我们在写自己的用户程序的时候有些地方也需要添加临界段代码保护。
FreeRTOS 与临界段代码保护有关的函数有 4 个:
- taskENTER_CRITICAL()
- taskEXIT_CRITICAL()
- taskENTER_CRITICAL_FROM_ISR()
- taskEXIT_CRITICAL_FROM_ISR()
这四个函数其实是宏定义,在 task.h 文件中有定义。这四个函数的区别是前两个是任务级的临界段代码保护,后两个是中断级的临界段代码保护。
taskENTER_CRITICAL()和 taskEXIT_CRITICAL()是任务级的临界代码保护,一个是进入临界段,一个是退出临界段,这两个函数是成对使用的。
任务级别使用方法如下:
函数 taskENTER_CRITICAL_FROM_ISR()和 taskEXIT_CRITICAL_FROM_ISR()中断级别临界段代码保护,是用在中断服务程序中的,而且这个中断的优先级一定要低于 configMAX_SYSCALL_INTERRUPT_PRIORITY!这两个函数是成对使用的。
中断级临界代码保护使用方法如下: