1.PendSV异常
- PendSV 的中断由中断控制状态寄存器(ICSR) 中 PENDSVSET 为置1触发。
- PendSV 的中断是非实时的。
- PendSV 的中断服务函数就会在其他所有中断处理完成后才执行。(优先级最低)
- OS 内核的执行可以有两种触发方式:SVC 指令触发及SysTick 周期性的中断。
- 任务切换导致中断请求延迟处理(中断请求IRQ在SysTick中断产生之前产生)
- FreeRTOS的任务切换就是在PendSV中完成的。
2.PendSV中断服务函数
- PendSV 的中断服务函数定义成函数 xPortPendSVHandler()。
- 在进行任务切换的时候, 还需考虑是否保护和恢复浮点寄存器的值。
- 在 PendSV 中断服务函数中, 主要要做的事情就是, 保存硬件不会自动入栈的 CPU 信息, 已经确定写一个要运行的任务, 并将 pxCurrentTCB 指向该任务的任务控制块, 然后更新PSP 指针为该任务的任务堆栈指针。
3.FreeRTOS确定下一个要运行的任务
- vTaskSwitchContext()调用了函数 taskSELECT_HIGHEST_PRIORITY_TASK(), 来将pxCurrentTCB 设置为指向优先级最高的就绪态任务。
- uxSchedulerSuspended变量用于在系统运行的任意时刻标记需要进行任务切换,会在 SysTick 的中断服务函数中统一处理。
- 将 pxCurrentTCB 指向优先级最高的就绪态任务,有两种方法(滴答定时器、portYIELD()---本质是向中断控制和状态寄存器ICSR的bit28写入1挂起PendSV来启动PendSV中断), 由 FreeRTOSConfig.h 文件配置决定。
- taskSELECT_HIGHEST_PRIORITY_TASK()用于将 pcCurrentTCB 设置为优先级最高的就绪态任务, 因此该函数会使用位图的方式在任务优先级记录中查找优先级最高任务优先等级, 然后根据这个优先等级, 到对应的就绪态任务列表在中取任务。
- taskSELECT_HIGHEST_PRIORITY_TASK():全局变量 uxTopReadyPriority 以位图方式记录了系统中存在任务的优先级,将遍历的起始优先级设置为这个全局变量,而无需从系统支持优先级的最大值开始遍历,可以节约一定的遍历时间。限制了系统最大优先级数量不能超过32个。
- 依靠特定硬件指令实现的函数 taskSELECT_HIGHEST_PRIORITY_TASK()是一个宏定义。
4.PendSV异常何时触发
- PendSV 异常用于进行任务切换
- portYIELD():设置中断控制状态寄存器,以触发PendSV异常。
5.FreeRTOS时间片调度
- CPU 轮流运行优先级相同的任务, 每个任务运行的时间就是一个系统时钟节拍。
- 临界区是指那些必须完整运行的区域, 在临界区中的代码必须完整运行, 不能被打断。
- FreeRTOS 在进出临界区的时候, 通过关闭和打开受 FreeRTOS 管理的中断, 以保护临界区中的代码。