任务切换,又称上下文切换(context switch)是实现操做系统的基础。bash
基于CM3实现任务切换必需要有如下2点概念认识函数
PendSV叫作可悬起系统调用,与之相对的叫作系统服务调用(SVC)。操作系统
二者的区别是SVC异常必须在执行SVC指令后当即获得响应,若是由于优先级或者其余缘由没法当即响应,就会上访成硬fault。而PendSV则能够像普通中断同样被悬起(pending),从而等待其余优先级更高的中断被响应完毕后执行。rest
在实现任务切换的操做系统中,每每会把PendSV的中断优先级设为最低。这样在进行任务切换时,只须要将PendSV悬起寄存器置位便可。PendSV的中断处理子程序会在全部高优先级中断响应完后开始进行任务切换。code
在ucos中任务切换代码十分简单:it
OSCtxSw LDR R0, =NVIC_INT_CTRL LDR R1, =NVIC_PENDSVSET //trigger PendSV STR R1, [R0] BX LR
相对应的PendSV处理函数:class
OS_PendSV_Handler CPSID I /* 寄存器保存和恢复 */ Save & Restore registers CPSIE I BX LR
任务切换的本质是实现寄存器的保存和恢复。在CM3中经过堆栈操做能快速的进行任务切换,为OS节约下不小的开销。基础
1. 中断入栈硬件
当CM3开始响应一个中断时,会硬件自动把xPSR、PC、LR、R十二、R3 - R0压入堆栈中程序
2. 手动入栈
除了自动入栈的寄存器外,在任务切换中断子程序(PendSV ISR)中,咱们还须要手动把R4 - R11压入堆栈中,从而实现完整现场保护。
旧SP(N - 0) 原先已压栈的内容 (N - 4) xPSR (N - 8) PC (N - 12) LR (N - 16) R12 (N - 20) R3 (N - 24) R2 (N - 28) R1 (N - 32) R0 --------------------------- 手动入栈 (N - 36) R11 (N - 40) R10 (N - 44) R9 (N - 48) R8 (N - 52) R7 (N - 56) R6 (N - 60) R5 (N - 64) R4 ---> 新SP
在ucos能够看到响应的实现
OS_PendSV_Handler: .......... //save SUBS R0, R0, #0x20 ;8 registers STM R0, {R4-R11} .......... //restore LDM R0, {R4-R11} ADDS R0, R0, #0x20