uCOS中任务调度时的上下文切换

uCOS中任务调度时的上下文切换

这里以STM32处理器为例,也就是Cortex-M3内核。

所谓的上下文切换呢,就是当 uC/OS转向执行另一个任务的时候,它保存了当前任务CPU 寄存器到堆栈。并从新任务的的堆栈中 CPU 寄存器载入 CPU

在这里上下文切换分为两种:一个是任务级的,一个是中断级的。

uCOS中任务调度时的上下文切换

(1) 开始执行切换,保存状态寄存器和程序指针寄存器到当前的任务堆栈。保存的顺序与中断发生时 CPU 保存寄存器的顺序相同。假定 SR 先入栈,然后其它寄存器入栈

(2) 当任务被停止时,保存 CPU 的 TSP 到该任务的OS_TCB 中,换句话说,OSTCBCurPtr->StkPtr=R14

(3) 然后将新任务 OS_TCB 的顶部地址存入 CPU TSP 中。换句话说,R14=OSTCBCurPtr->StkPtr

(4) 最后, 将新任务堆栈中 R13~~R0 关内容载入 CPU寄存器。再然后(此时的会 TSP 指向 PC,如图)通过一个中断返回指令{比如汇编中的 IRET},程序指针寄存器和状态寄存器被恢复到 CPU 的寄存器中。

 

以上是一个大概的流程分析,下面来看看其具体的代码实现过程,当然,这里是用汇编来实现。

 

PendSV_Handler

    CPSID                                                     Prevent interruption during context switch关所以中断

    MRS     R0, PSP                                             PSP is process stack pointer  PSP是当前进程堆栈的指针,将PSP赋值给R0

    CBZ     R0, PendSV_Handler_Nosave                     Skip register save the first time如果R00时跳转到PendSV_Handler_Nosave

 

    SUBS    R0, R0, #0x20                                       Save remaining regs r4-11 on process stack偏移0x20的位置用来保存R4R11

    STM     R0, {R4-R11} ;将剩下的R4R11寄存器保存在此进程的堆栈中

 

    LDR     R1, =p_OSTCBCur                                     OSTCBCur->OSTCBStkPtr SP; OSTCBCur->OSTCBStkPtr这个保存当前的栈尾,以便下次弹出

    LDR     R1, [R1]

    STR     R0, [R1]                                            R0 is SP of process being switched out

 

                                                                At this point, entire context of process has been saved此时,整个上下文的过程已经被保存

PendSV_Handler_Nosave

    PUSH    {R14}                                               Save LR exc_return value

    LDR     R0, =OSTaskSwHook                                   OSTaskSwHook();  这里的话可以删除的,用于用户扩展呵呵

    BLX     R0

    POP     {R14}

 

    LDR     R0, =OSPrioCur                                      OSPrioCur OSPrioHighRdy;

    LDR     R1, =OSPrioHighRdy ;将当前优先级变量指向最高优先级

    LDRB    R2, [R1]

    STRB    R2, [R0]

 

    LDR     R0, =p_OSTCBCur                                     OSTCBCur  OSTCBHighRdy;

    LDR     R1, =p_OSTCBHighRdy ;TCB表也一样

    LDR     R2, [R1]

    STR     R2, [R0]

;到这里,[R2]保存的是新的进程的堆栈指针SP

    LDR     R0, [R2]                                            R0 is new process SP; SP OSTCBHighRdy->OSTCBStkPtr;  将堆栈指针赋值给SP

    LDM     R0, {R4-R11}                                        Restore r4-11 from new process stack 弹出其它寄存器,和前面的是一个逆过程

    ADDS    R0, R0, #0x20 ;和前面的逆过程对比可知

    MSR     PSP, R0                                             Load PSP with new process SPR0中的SP赋值给PSP寄存器

    ORR     LR, LR, #0x04                                       Ensure exception return uses process stack确保异常返回时使用进程堆栈

    CPSIE   I ;开中断

    BX      LR                                                  Exception return will restore remaining context异常返回将恢复那些自动出栈的剩余寄存器

 

晕,排版有点乱,勉强凑合着看吧。。。

可以看出这其实是一个PendSV中断来的,也就是M3的可编程挂起中断,为什么用这个中断来进行上下文切换呢?后面将会进行说明下。

CBZ     R0, PendSV_Handler_Nosave

这句是用来判断是否第一次进入切换,也就是系统刚启动的时候,则直接跳到PendSV_Handler_Nosave这个标号来执行了,因为系统刚启动还没有当前任务嘛。

当不是刚启动的,进行上下文切换,首先是要将当前任务的寄存器保存下来,保存到当前任务的堆栈里,R4-R11手动保存到堆栈,其余会自动保存。

然后

    LDR     R0, =OSPrioCur                                      OSPrioCur OSPrioHighRdy;

    LDR     R1, =OSPrioHighRdy ;将当前优先级变量指向最高优先级

    LDRB    R2, [R1]

    STRB    R2, [R0]

 

    LDR     R0, =p_OSTCBCur                                     OSTCBCur  OSTCBHighRdy;

    LDR     R1, =p_OSTCBHighRdy ;TCB表也一样

    LDR     R2, [R1]

    STR     R2, [R0]

这里是将优先级最高的,也就是需要切换到的那个任务替换为当前任务。

然后让PSP指向任务堆栈,再然后是一个逆过程,弹出堆栈里的数据到对应的寄存器。

 

上下文切换就差不多这样。。。

关于在M3内核,为什么使用PendSV这个中断来进行上下文切换呢?其原因是这个中断拥有最低优先级的软件中断。

又问,为什么要在拥有最低优先级的软件中断中进行切换呢?这个答案在《Cortex-M3权威指南》第7章 异常   里有详细的答案。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值