freeRTOS小结——中断管理
概述
本章所述中断管理主要是针对中断处理程序的管理。
RTOS中,中断处理程序由用户自定义,是类似于TASK一样的存在,中断处理程序有自己的栈,可以支持低优先级中断处理程序被高优先级中断处理程序打断。实际上,个人认为TASK就是以中断处理程序为原型演进而来。
考虑到OS的很多功能,如时间片机制、TASK切换(后边将会讲到)都是基于中断处理程序来完成的。
如之前所述,中断处理程序具有比常规用户指令集合更高的处理优先级,当中断发生时,CPU会立即执行中断处理程序。TASK就处于常规用户指令集合之中,因此中断发生时,TASK必然被中断处理程序打断,如下图所示,
其中,
· t1时刻,TASK 1开始在CPU上执行
· t2时刻,CPU检测到中断,开始执行中断处理程序
· t3时刻,中断处理程序执行完成,CPU在切换回TASK 1继续执行
中断嵌套
某些嵌入式系统中,支持低优先级中断处理程序被高优先级中断处理程序打断,即为中断嵌套,如下图所示,
其中
· t1时刻,TASK 1开始在CPU上执行
· t2时刻,CPU检测到中断1,开始执行其对应的 中断处理程序
· t3时刻,CPU检测到中断2,由于其优先级较高,开始执行其对应的 中断处理程序
· t4时刻,CPU完成中断2的中断处理程序,恢复执行中断1的中断处理程序
· t5时刻,CPU完成中断1的中断处理程序,恢复执行TASK1
基于中断的任务切换
大部分的RTOS中,都使用基于中断的TASK切换方式:
· 当TASK需要触发TASK切换时,其触发产生一次中断(记为SWI),SWI的中断处理程序即为包含压栈、出栈的任务切换处理过程。
· 当中断处理程序需要触发TASK切换时,可在中断处理程序执行过程中,将出栈处理恢复的寄存器直接替换为新切换TASK的寄存器
这样做的好处在于保证TASK切换不会中断处理程序打断导致异常。
此时TASK切换过程如下图所示,
当然,这并非唯一方式,任何能够保证TASK切换正常执行的方式也是可行的 :如TASK触发的TASK切换,可以采用后边提到的临界区机制;又如对于不支持中断嵌套的系统,以上两种情况都可采用直接触发switch interrupt的方式。
基于中断的时间片机制
时间片机制,即外部的硬件定时器周期性地向CPU发送一个中断(记为TickINT),该中断的ISR即OS的时间片处理过程:尝试进行TASK切换并统计OS的状态信息。
如下图所示
其中,
· t1~t2时间段,TASK 1在CPU上执行
· t2时刻,时间片超时,OS发现存在更高优先级的TASK2,因此触发TASK切换,切换到TASK 2
· t2~t3时间段,TASK 2在CPU上执行
· t3时刻,时间片超时,OS发现没有更高优先级的TASK,不触发TASK切换
其中的TASK切换过程细节可参考之前提到的ISR触发的TASK切换过程。
中断处理程序
由于ISR的特殊性(ISR优先于TASK执行,且部分OS功能如时间片和TASK切换基于ISR实现),freeRTOS为ISR设计了一套特殊的API函数,即后缀为“FromISR”的API函数,以保证ISR在使用API时不会出现异常,如下表所示(其中只给出了常用的部分),
功能 | TASK使用API | ISR使用API |
触发TASK切换 | portYIELD | portYIELD_FROM_ISR |
发送消息 | xMessageBufferSend | xMessageBufferSendFromISR |
接收消息 | xMessageBufferRecv | xMessageBufferRecvFromISR |
xSemaphoreTake | xSemaphoreTakeFromISR | |
释放互斥信号量 | xSemaphoreGive | xSemaphoreGiveFromISR |
获取信号量 | xSemaphoreTake | xSemaphoreTakeFromISR |
释放信号量 | xSemaphoreGive | xSemaphoreGiveFromISR |
它们的区别再去,TASK使用API会立即尝试触发TASK切换,而ISR使用API只会返回一个BOOL值,指示是否需要触发TASK切换——ISR触发的TASK切换需要在其执行完成后在进行。