__asm void PendSV_Handler(void)
{
IMPORT CurrentTask
IMPORT NextTask
IMPORT CurrentTaskPointer
IMPORT NextTaskPointer
(1)CPSID I
(2)MRS R0, PSP
(3)CBZ R0, PendSV_Handler_Start
(19)SUBS R0, R0, #0x20
(20)STM R0, {R4-R11}
(21)LDR R1, =CurrentTaskPointer
(22)LDR R1, [R1]
(23)STR R0, [R1]
PendSV_Handler_Start
(4)LDR R0, =CurrentTask
(5)LDR R1, =NextTask
(6)LDRB R2, [R1]
(7)STRB R2, [R0]
(8)LDR R0, =CurrentTaskPointer
(9)LDR R1, =NextTaskPointer
(10)LDR R2, [R1]
(11)STR R2, [R0]
(12)LDR R0, [R2]
(13)LDM R0, {R4-R11}
(14)ADDS R0, R0, #0x20
(15)MSR PSP, R0
(16)ORR LR, LR, #0x04
(17)CPSIE I
(18)BX LR
}
CPSID:CPS是指令,ID是取值,意思是关闭中断;
MRS:指令用亍将程序状态寄存器的内容传送到通用寄存器中如:MSR R0,PSP 是传送PSP内容到R0中;
CBZ:比较,为零则跳转如CBZ R0, PendSV_Handler_Start 比较操作数R0是否为零,为零则跳到目标PendSV_Handler_Start;
STM和LDM:主要的作用或用途是现场保护、数据复制、参数传递等,如STM R0, {R4-R11}是以寄存器R0为基地址寄存器加载数据,R0装有传送数据的初始地址;
LDR R1, =CurrentTaskPointer是将CurrentTaskPointe这个变量的地址放到R1中;
STR R0, [R1] 是将R0中的字数据写入以R1为地址的存储器中
LDRB R2, [R1]是将存储器地址为R1的字节数据读入寄存器R2,并将R2的高24位清零。STRB R2, [R0] 是将寄存器R2中的字节数据写入以R0为地址的存储器中;
MSR PSP, R0是将CPSR中的内容传送至R0;
ORR LR, LR, #0x04是设置LR的3位为1其他位保留;
以上是对代码一些指令的了解,现在我们来了解如何任务切换,切换任务流程如下:
在第一次进入中断函数时,(1)先关闭中断;(2)把SPS的内容赋给R0,之前我们给PSP赋0(零)用来判断是不是第一次进入中断函数切换任务;(3)判断R0是否为0,如果是就跳到目标PendSV_Handler_Start,因为是第一次进中断函数R0为0,所以函数是跳到PendSV_Handler_Start去执行下面的程序段;(4)把当前任务标记的地址放到R0;因为是第一次进入中断,我们的系统是先执行逻辑任务的,所以当前任务标记是逻辑任务的标记(5)下一个任务的标记的地址放到R1;任务标记是用来判断、切换要是执行哪个任务任务(6)再把R1的内容读入R2里;(7)再把R2的内容写入R0;这样就把下个一个任务标记(新任务标记)赋给当前任务的标记,就实现获取新任务标记,并保存;
(8)把当前逻辑任务表的指针的地址赋给R0,因为表的首地址存放栈顶,所以这样就把栈顶赋给R0;(9)把下一个任务表的指针的地址赋给R1,也就是把新任务的栈顶赋给R1;(10) 再把R1的内容读入R2里;(11)再把R2的内容写入R0;这样就把下个一个任务的栈顶(新任务的栈顶)赋给当前任务的栈顶,就实现获取新任务的栈顶,并保存;栈是保存数据,寄存器是在CPU里面,下面吧R12等写进栈是为了给大家好理解。
(12)把R2的地址赋给R0,是把新任务的栈顶放到R0;(13)以R0为基地址从逻辑任务的栈把R4到R11的数据加载到CPU中的R4到R11寄存器里面去处理。(14)栈顶上升8个word;(15)把R0装的栈顶再赋给PSP,让PSP指向栈顶。黑色箭头是开始栈顶位置,红色变化后栈顶位置,往后箭头颜色是一样的含义。
以上是完成第一次进入中断函数,那么第二次进来时,就是我们任务的切换过程了。
第二次进中断函数:我们首先要把逻辑任务在CPU处理完的数据返还保存到逻辑栈(19)栈顶先减8 word,给数据加存储空间;(20)把R4到R11的数据再次入栈;(21)把当前表的指针的地址赋给R1,那么R1现在装的是逻辑任务表的指针地址;(22)把R1表的首地址赋给R1,R1获取当前逻辑任务表的首地址;(23)R0是装逻辑任务的栈顶,现在把R0送入R1,就是把逻辑任务栈顶送入表的首地址保存。
接下来就是重复第一次进中断函数的步骤,里面把当前逻辑任务的标记切换成新任务标记(界面任务标记),把当前逻辑任务栈顶切换成新的栈顶(界面任务栈顶)。我们通过任务标记找到表的首地址,表的首地址又装栈的栈顶,这样我们任务切换就是要把任务标记切换,来记录我们现在要执行什么样的任务。
以上内容是学习msOS嵌入式系统后本人自己的理解,自己画的图,如有不清楚或不对的地方,请大家指出来,一起学习一起进步,谢谢大家!
文章评论(0条评论)
登录后参与讨论