Lpc1768移植UCOS-II(二)

二、移植OS_CPU_C.C

1、头文件包含,

clip_image002

ucos_ii.h中包含了头文件os_cpu.h,os_cpu.h中有一段代码如下:

clip_image004

在OS_CPU_C.C中定义宏OS_CPU_GLOBALS,表示在编译OS_CPU_C.C时,定义os_cpu.h中的全局变量,其它C文件在引用os_cpu.h时不能定义OS_CPU_GLOBALS,编译时只是声明全局变量。

2、定义SYSTICK相关寄存器

clip_image006

3、钩子函数定义

void OSInitHookBegin (void)

void OSInitHookEnd (void)

void OSTaskCreateHook (OS_TCB *ptcb)

void OSTaskDelHook (OS_TCB *ptcb)

void OSTaskIdleHook (void)

void OSTaskReturnHook (OS_TCB *ptcb)

void OSTaskStatHook (void)

void OSTaskSwHook (void)

void OSTCBInitHook (OS_TCB *ptcb)

void OSTimeTickHook (void)

这些钩子函数必须定义,但可以是空函数。

clip_image008

在OSInitHookBegin()中把定义的CPU异常堆栈清零,并把栈顶赋给OS_CPU_ExceptStkBase。

4、移植OSTaskStkInit()

clip_image010

这个函数的功能是在新建任务时对任务的堆栈初始化。

void (*task)(void * p_arg): 定义一个函数指针变量task,这个函数指针指向的函数有一个void *类型的参数,没有返回值。

p_arg:是任务开始执行时,传递给任务的参数的指针。

Ptos:是分配给任务的堆栈栈顶的指针。

Opt:在OSTaskCreate()函数中调用 OSTaskStkInit()函数时,Opt为0。因为OSTaskCreate()函数不支持在任务的建立过程中设置选项。OSTaskCreateExt()函数支持这个选项。

OSTaskStkInit()是一个指针函数,也就是返回值是一个指针,返回初始化后的堆栈的栈顶。

CM3发生中断时的寄存器入栈顺序如下:

clip_image012

clip_image014

入栈的顺序在CM3内部是打乱过的,可以看到PC首先被压入堆栈,LR最后被压入堆栈,但是最终堆栈里数据的存储地址是按照xPSR,PC,LR,r12,r3,r4,r1,r0这个顺序来保存的。

初始化任务堆栈的目的就是让堆栈看起来像中断刚发生过一样,所以函数中也要按这个顺序来入栈。R4-R11寄存器在CM3发生中断时不会自动入栈,所以放在后面初始化。(细心的读者一定在猜测:为啥袒护R0‐R3以及R12呢,R4‐R11就是下等公民?原来,在ARM上,有一套的C函数调用标准约定(《C/C++ Procedure Call Standard for the ARM Architecture》,AAPCS, Ref5)。个中原因就在它上面:它使得中断服务例程能用C语言编写,编译器优先使用被入栈的寄存器来保存中间结果。)

在CM3中,xPSR的T位必须是1,所以xPSR压入堆栈的值为0x01000000uL

第一次执行这个任务时,要把任务函数的地址送给PC,所以压入堆栈的第二个值是任务函数地址task。

LR理论上应该为任务的返回地址,但是任务函数是无限循环,所以这里保存的值实际上是用不到的,万一出现错误,执行了这里保存的函数OS_TaskReturn,

clip_image016

OS_TaskReturn()在OS_TASK.C中定义,执行这个函数会删除任务本身(删除任务使能)或无限挂起这个任务,不再执行。这个地方目前理解的不清楚,在STM32移植范例里面这里放的是0XFFFFFFFF。如果0XFFFFFFFF赋值给PC,会产生一个fault。

R0一般用来传递函数参数,所以把p_arg放到R0的入栈位置。其它通用寄存器的值可以随便设置。

5、定义systick中断处理函数

clip_image018

在函数中调用时钟节拍函数OSTimeTick(),把延时时间到的任务置为就绪态。调用OSIntExit()函数,退出中断时,执行任务切换。

6、初始化systick

clip_image020

一般systick设置为10ms中断一次。

© 版权声明
THE END
喜欢就支持以下吧
点赞0
分享
评论 抢沙发