0x01
摘要
前面对任务调度系统的主要内容进行了详细的介绍,剩下任务调度的最后一部分,也就是任务调度的汇编实现,这部分和具体的平台有关,也是ucos移植需要修改的地方。一般这部分都有别人已经移植成功的,如果大家只是拿来用的,不是具体研究其实现的机理的话,可以不必深究,因为这部分涉及到具体的平台。本文以stm32为例。
0x02
引言
汇编是最接近芯片工作原理的部分,也是最难学习的部分,对于汇编大家只需要根据自己需要进行学习,不必完整学习,因为完整学习花费的代价很高。
因为汇编语言的高效性,所以一般对于像任务调度这种很频繁的操作才建议使用汇编来实现,这样可以极大的提高系统的效率。对于汇编的分析涉及到芯片的具体工作方式,这里我们仅对汇编的功能进行分析,其涉及到的芯片深层工作原理大家自行翻阅芯片手册。
0x03
原理
首先我们看一下任务调度函数OS_CPU_PendSVHandler,这是PendSV的中断函数,前面我们说了,ucos是通过出发PendSV中断实现的任务调度。因为PendSV在所有芯片级的中断中级别最小,不会对芯片级的其他中断造成影响,以便等到芯片其他的重要中断完成后才进行调度,保证了芯片工作的稳定性和可靠性。我们对其代码进行分段讲解
OS_CPU_PendSVHandler
CPSID I
MRS R0, PSP
CBZ R0, OS_CPU_PendSVHandler_nosave
这一段是关闭系统的中断避免在任务切换时被其他中断打扰,并将PSP中的内容加载到R0中,判断R0是否为零,若为零则表示第一次切换任务,直接跳转到OS_CPU_PendSVHandler_nosave而不需要进行下面的寄存器存储操作。
SUBS R0, R0, #0x20
STM R0, {R4-R11}
LDR R1, =OSTCBCur
LDR R1, [R1]
STR R0, [R1]
这一段表示对当前任务的寄存器R4-R11进行存储,这里R0~R3、LR、PC指针会自动存储到PSP指向的堆栈,这是由芯片自动完成的,无需进行人工操作。然后将当前堆栈的栈顶指针存放到TCB中的OSTCBStkPtr变量中。
OS_CPU_PendSVHandler_nosave
PUSH {R14}
LDR R0, =OSTaskSwHook
BLX R0
POP {R14}
这一段主要是为了实现systick的钩子函数OSTaskSwHook的实现,现将R14入栈然后执行函数,返回,将R14出栈。
LDR R0, =OSPrioCur
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
这一段主要是将最高优先级赋值给当前优先级。
LDR R0, =OSTCBCur
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]
这一段是将最够优先级的任务TCB赋值给当前任务的TCB。
LDR R0, [R2]
LDM R0, {R4-R11}
ADDS R0, R0, #0x20
MSR PSP, R0
ORR LR, LR, #0x04
CPSIE I
BX LR
这一段将最高优先级任务的R4-R11寄存器内容恢复,然后将R0地址跳过芯片自动存储的区域,并将地址赋值给PSP,然后将LR寄存器4字节对其,打开全局中断,跳转到调用函数的位置。
0x04
结论
这一篇将ucos任务切换的汇编实现进行了详细的讲解,这些汇编代码和具体的平台有关,有时候相同的芯片代码可能也不同,但是其思路是一样的,都是存储当前任务的寄存器值,然后恢复将要调用任务的寄存器值。
OS
你的努力
我的付出
大家的支持
终将化作生命辉煌
如有任何疑问请后台回复
或添加作者Waiting_B_H
知识传播是一种美德
让更多人少走弯路
才能有更多人与你携手前进
欢迎扫码一起分享经验
|