原创 msOS嵌入式系统亮点之一OS部分

2015-8-25 10:38 720 3 3 分类: 消费电子

 

我们在上一篇文章简单了解到msOS系统任务的切换,但是,而任务真正切换是在中断函数里面,那么现在我们结合代码继续更深入的了解,中断函数是用汇编写的,比较难理解,我们先来解读一下代码中的汇编指令的使用。以下是中断函数切换任务的全部代码。

__asm void PendSV_Handler(void)

{

  IMPORT  CurrentTask

  IMPORT  NextTask

  IMPORT  CurrentTaskPointer

  IMPORT  NextTaskPointer

 

1CPSID   I                          

2MRS     R0, PSP                    

    3CBZ     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  

    4LDR     R0, =CurrentTask          

    5LDR     R1, =NextTask

    6LDRB    R2, [R1]

    7STRB    R2, [R0]

   

    8LDR     R0, =CurrentTaskPointer   

    9LDR     R1, =NextTaskPointer

    10LDR     R2, [R1]

    11STR     R2, [R0]

 

    12LDR     R0, [R2]                   

    13LDM     R0, {R4-R11}               

14ADDS    R0, R0, #0x20             

    15MSR     PSP, R0                    

    16ORR     LR, LR, #0x04          

       

(17)CPSIE   I                         

    (18)BX      LR                        

}

CPSIDCPS是指令,ID是取值,意思是关闭中断;

MRS:指令用亍将程序状态寄存器的内容传送到通用寄存器中如:MSR  R0PSP 是传送PSP内容到R0中;

CBZ:比较,为零则跳转如CBZ   R0, PendSV_Handler_Start 比较操作数R0是否为零,为零则跳到目标PendSV_Handler_Start

STMLDM:主要的作用或用途是现场保护、数据复制、参数传递等,如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是设置LR3位为1其他位保留;

以上是对代码一些指令的了解,现在我们来了解如何任务切换,切换任务流程如下:

 

在第一次进入中断函数时,(1)先关闭中断;(2)把SPS的内容赋给R0,之前我们给PSP0()用来判断是不是第一次进入中断函数切换任务;(3)判断R0是否为0,如果是就跳到目标PendSV_Handler_Start,因为是第一次进中断函数R00,所以函数是跳到PendSV_Handler_Start去执行下面的程序段;(4)把当前任务标记的地址放到R0;因为是第一次进入中断,我们的系统是先执行逻辑任务的,所以当前任务标记是逻辑任务的标记(5)下一个任务的标记的地址放到R1;任务标记是用来判断、切换要是执行哪个任务任务(6)再把R1的内容读入R2里;(7)再把R2的内容写入R0;这样就把下个一个任务标记(新任务标记)赋给当前任务的标记,就实现获取新任务标记,并保存;

       20141218132430921.jpg

8)把当前逻辑任务表的指针的地址赋给R0,因为表的首地址存放栈顶,所以这样就把栈顶赋给R0;(9)把下一个任务表的指针的地址赋给R1,也就是把新任务的栈顶赋给R1(10) 再把R1的内容读入R2里;(11)再把R2的内容写入R0;这样就把下个一个任务的栈顶(新任务的栈顶)赋给当前任务的栈顶,就实现获取新任务的栈顶,并保存;栈是保存数据,寄存器是在CPU里面,下面吧R12等写进栈是为了给大家好理解。

       20141218132523200.jpg

12)把R2的地址赋给R0,是把新任务的栈顶放到R0;(13)以R0为基地址从逻辑任务的栈把R4R11的数据加载到CPU中的R4R11寄存器里面去处理。(14)栈顶上升8word;(15)把R0装的栈顶再赋给PSP,让PSP指向栈顶。黑色箭头是开始栈顶位置,红色变化后栈顶位置,往后箭头颜色是一样的含义。

      20141218132559769.jpg

以上是完成第一次进入中断函数,那么第二次进来时,就是我们任务的切换过程了。

 

第二次进中断函数:我们首先要把逻辑任务在CPU处理完的数据返还保存到逻辑栈(19)栈顶先减8 word,给数据加存储空间;(20)把R4R11的数据再次入栈;(21)把当前表的指针的地址赋给R1,那么R1现在装的是逻辑任务表的指针地址;(22)把R1表的首地址赋给R1R1获取当前逻辑任务表的首地址;(23R0是装逻辑任务的栈顶,现在把R0送入R1,就是把逻辑任务栈顶送入表的首地址保存。

       20141218132645893.jpg

接下来就是重复第一次进中断函数的步骤,里面把当前逻辑任务的标记切换成新任务标记(界面任务标记),把当前逻辑任务栈顶切换成新的栈顶(界面任务栈顶)。我们通过任务标记找到表的首地址,表的首地址又装栈的栈顶,这样我们任务切换就是要把任务标记切换,来记录我们现在要执行什么样的任务。

        20141218132721921.jpg

以上内容是学习msOS嵌入式系统后本人自己的理解,自己画的图,如有不清楚或不对的地方,请大家指出来,一起学习一起进步,谢谢大家!

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
3
关闭 站长推荐上一条 /3 下一条