【uCOS-II学习笔记2】任务调度,触发执行上下文切换

若有不对请斧正,谢谢

触发中断

在这里插入图片描述

OSStartHighRdy

OSStartHighRdy()函数在OSStart()中被调用,即第一次任务调度。

  • 将PendSV中断优先级设置为最低0xFF,0xE000ED22寄存器写入0xFF
    在这里插入图片描述在这里插入图片描述在这里插入图片描述
  • 初始化PSP和MSP指针
    在这里插入图片描述
  • 将OS运行标志设置为1
  • 将ICSR寄存器第28位写1,即触发PendSV中断
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

OSCtxSw

在这里插入图片描述
OS_TASK_SW()函数在OS_Sched()任务调度函数中被调用。
OS_Sched()任务调度函数,在任务创建、消息队列、信号量、消息邮箱、时钟等函数中执行。

该任务调度一般是在任务中主动释放CPU,主动切换任务。较为常用的方式比如:OSTimeDly();OSSemPost();QSQPost();、等。

OSIntCtxSw

OSIntCtxSw()函数在OSIntExit()中被调用
在这里插入图片描述
至于OSIntExit()该函数,在移植uC/OS时,会在系统定时器中断处理函数SysTick_Handler中调用。
每次滴答时钟中断,都会判断是否执行任务切换,即实现了高优先级任务抢占低优先级任务CPU控制权。
以下是原子的SysTick_Handler函数
在这里插入图片描述

中断执行,上下文切换

中断入口可以在中断向量表中找到。

中断向量表

在这里插入图片描述

PendSV_Handler

PendSV_Handler
    CPSID   I                                                   ; Prevent interruption during context switch
    MRS     R0, PSP                                             ; PSP is process stack pointer
    CBZ     R0, PendSV_Handler_nosave                           ; Skip register save the first time

    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
    STM     R0, {R4-R11}

    LDR     R1, =OSTCBCur                                       ; OSTCBCur->OSTCBStkPtr = SP;
    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, =OSTCBCur                                       ; OSTCBCur  = OSTCBHighRdy;
    LDR     R1, =OSTCBHighRdy
    LDR     R2, [R1]
    STR     R2, [R0]

    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
    ADDS    R0, R0, #0x20
    MSR     PSP, R0                                             ; Load PSP with new process SP
    ORR     LR, LR, #0xF4                                       ; Ensure exception return uses process stack
    CPSIE   I
    BX      LR                                                  ; Exception return will restore remaining context

    END

代码流程

a)获取进程SP,如果为0,则跳过(转到d-PendSV_Handler_nosave)保存部分(第一个上下文切换);
b)将剩余的寄存器r4-r11保存在进程堆栈中;
c)将进程SP保存在其TCB中,OSTCBCur-> OSTCBStkPtr = SP;
d)调用OSTaskSwHook();
e)获得当前的高优先级,OSPrioCur = OSPrioHighRdy;
f)获取当前就绪线程TCB,OSTCBCur = OSTCBHighRdy;
g)从TCB获取新进程SP,SP = OSTCBHighRdy-> OSTCBStkPtr;
h)从新进程堆栈中还原R4-R11;
i)执行异常返回,它将恢复剩余的上下文。

堆栈

参考链接
https://blog.csdn.net/yangkuiwu/article/details/78302659

该链接中使用的uC/OS的版本应该和我的不同,PendSV_Handler代码有些差异,
下面自己梳理总结一下。

  • 在中断触发后,进入PendSV_Handler中断服务函数之前,硬件自动将xPSR, PC, LR, R12以及R3‐R0压入堆栈。
    在这里插入图片描述

  • 进入中断后,关闭中断CPSID I,再将PSP的值送给R0,判断该值不为0,则开始保存r4-r11寄存器。
    在这里插入图片描述

  • 保存r4-r11寄存器
    在这里插入图片描述
    先将R0减去32(0x20)
    在这里插入图片描述
    将R4-R11写入R0所指向的位置,每存一个寄存器R0会自动加4,所以存储完成后,R0与PSP的值仍相等。
    在这里插入图片描述

  • 保存SP的值放入栈顶
    在这里插入图片描述
    汇编指令
    在这里插入图片描述
    将当前任务 任务控制块 的地址写入R1,(OS_TCB结构体的第一个成员为OS_STK *OSTCBStkPtr;),[R1]的值为OS_STK类型的指针(栈顶指针),将其再写入R1。
    将R0中的值(即SP的值)写入R1(OS_STK类型的指针)为地址指向的存储器。即SP写入栈顶。

  • 进入Hook函数后,再回来。
    这好像是给我们DIY的,不用管
    在这里插入图片描述

  • 当前任务的优先级和控制块修改为最高就绪任务的优先级和控制块
    在这里插入图片描述

  • 修改SP指针
    在上一步中 R2最终为最高就绪任务的栈顶指针。
    在这里插入图片描述

  • 将栈顶写入R0
    根据上面的流程可以看到我们保存栈顶的指向的地方,所以TASK2(最高就绪任务)的栈顶指向如图
    在这里插入图片描述

  • 弹出R0的值到寄存器R4-R11

LDM	R0, {R4, R11}
ADDS    R0, R0, #0x20

在这里插入图片描述
这里就很惆怅,推测来看是每次传送前地址减4,传送完再加0x20,又回到了原点
在这里插入图片描述

  • 把栈顶的值送给PSP

  • 将LR寄存器的第二位写1,四到七为也写1
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 打开中断,返回LR。此时硬件自动将xPSR, PC, LR, R12以及R3‐R0弹出堆栈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值