任务启动与任务切换
CM3内核任务切换原理
无论是FreeRTOS还是ucos,其任务切换的实现都是用汇编来写的,在STM32上都是用的PendSV这个系统异常来进行任务切换的,参考权威手册121页有关SVC与PendSV的介绍。通过置位NVIC的ICSR中断控制及状态寄存器(131页)地址0xE000_ED04来悬起SVC及PendSV异常,在异常中进行任务切换工作。
CM3内核一共有R0-R15共16个寄存器加上四个特殊功能寄存器
其中R0-R12是用来存储程序运行时的临时存储值,R13是栈地址指针寄存器,R14是执行BL程序跳转时用来存储跳转处下一行代码地址用的寄存器,R15总是指向当前执行代码的下一行地址的寄存器。BASEPRI寄存器是用来按优先级来屏蔽中断的,向里面写入数值后会屏蔽大于该值的优先级的中断,FreeRTOS就是在这里来屏蔽中断进入临界区的,写0的话就不屏蔽。(ucos ii是用PRIMASK来屏蔽的,这个寄存器置1后会屏蔽所有可编程优先级的中断,只有几个负优先级的中断可以响应,这个屏蔽非常彻底。)
任务切换就是要先恢复任务最后运行时R0-R12寄存器的值,然后恢复栈指针的地址,xPSR状态寄存器的值,恢复LR寄存器的值,最后用BX LR来跳转到任务上次运行处的位置,此时上次运行后R0-R12的值都恢复原状,栈指针也被恢复,这样任务就会按原来的状态继续运行下去。这是任务切换的原理,无论是什么CPU(x86或者ARM),进行任务切换时,要做的事都大同小异。
FreeRTOS进行任务切换的过程
CM3内核的PendSV异常是专为操作系统用来任务切换用的,无论是FreeRTOS还是ucos在CM3上进行任务切换的过程和代码都差不多的。
当CM3开始响应一个中断时,会在它看不见的体内奔涌起三股暗流:(见权威指南中文版135页)
- 入栈: 把8个寄存器的值压入栈
- 取向量:从向量表中找出对应的服务程序入口地址
- 选择堆栈指针MSP/PSP,更新堆栈指针SP,更新连接寄存器LR,更新程序计数器PC
FreeRTOS要进行任务切换时,是使用在portmacro.h里的portYIELD()宏来实现的
/* Scheduler utilities. */
#define portYIELD() \
{
\
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* Barriers are nor