分类: 嵌入式
2009-07-17 18:14:45
2 OS_CPU_C.C 移植相关
移植时用户最多需要对下面10个C函数进行修改。
(1) OSTaskInit();
唯一必要的函数,其它9个函数必须声明,但并不一定要包含任何代码。这个函数用于初始化任务的栈结构;将被OSTaskCreate() 和OSTaskCreateExt()调用。OSTaskCreate()调用OSTaskInit()时,需要将OSTaskInit()的opt参数设置成0X0000;
OSTaskInit()的示意性代码:
OS_SRK *OSTaskStkInit( void (*task) (void *pd) ),
void *pdata,
OS_STK *ptos,
INT_16U opt);
{
模拟带参数的(pdata)的函数调用;
模拟ISR向量;
按照预先设计的寄存器值初始化堆栈结构;
返回栈顶指针给调用该函数的函数;
}
(2) OSTaskCreateHook()
每当添加任务时,OS_TCBInit()函数就会调用OSTaskCreateHook()函数,该函数运行扩展UCOSII的功能。当UCOSII设置完成任务控制块OS_TCB初始化的绝大部分工作后,但在任务控制块被链接到相应的任务链中之前,以及该任务就绪运行之前,UCOSII会调用OSTaskCreateHook()。该函数会收到指向刚刚建立任务的任务控制块的指针。该函数调用时,中断是打开的。
(注 OS_CFG.H中的OS_CPU_HOOKS_EN 置1时,OS_CPU_C.C文件中会生成 OS???Hook()函数,置0时,在OS_CPU_C.C文件之外定义自己的Hook函数)
(3) OSTaskDelHook()
在任务从就绪表或等待列表被删除后,OSTaskDel()就会调用OSTaskDelHook()。该函数会收到一个指向正在被删除任务的任务控制块的指针。该函数被调用的时候,中断是关闭的。
(4) OSTaskSwHook()
做任务切换时,会调用OSTaskSwHook()函数。不管任务切换是通过OSCtwSw()函数实现,还是通过OSInitCtwSw()函数实现的,都会调用该函数。该函数可以访问OSTCBCur(指向将被切换出去的任务的任务控制块)和OSTCBHighRdy(指向新任务的任务控制块)这两个全局变量。该函数被调用时,中断是关闭的。
(5) OSTaskStatHook()
OSTaskStatHook()函数每秒都会被统计任务OSTaskStat()调用一次。可以用OSTaskStatHook()扩展统计任务的功能。
(6) OSTimeTickHook()
该函数每个时钟节拍都会被OSTimeTick()函数调用。该函数存在的目的是为了便于用户能优先处理紧急的事务。
(7) OSTCBInitHook()
OS_TCBInit()函数先调用OSTCBInitHook()函数,再调用OSTaskCreateHook(),该函数可以初始化OS_TCB。该函数会收到指向刚刚建立任务的任务控制块的指针。OSTCBInitHook()函数和OSTaskCreateHook()函数是否使用,完全取决与用户。
(8) OSTaskIdleHook()
OSTaskIdle()函数通过调用OSTaskIdleHook(),实现CPU的低功耗模式。
(9) OSInitHookBegin()
进入OSInit()函数后,OSInitHookBegin()函数就会被调用。添加这个函数的原因在于,想把与OS初始化有关的代码也放在OSInit()函数中。这样用户可以将自定义的代码也放在OSInit()函数中了。
OS
(10) OSInitHookEnd()
OSInit()函数返回之前时,会调用这个函数,该函数与OSInitHookBegin()函数类似。
3 OS_CPU_A.ASM移植相关
移植时,用户之需要编写4个简单的汇编语言函数:
(1) OSStartHighRdy();
OSStart()函数调用OSStartHighRdy()函数来使就绪态任务中最高优先级开始运行。
OSStartHighRdy()函数的示意性代码:
Void OSStartHighRdy(void)
{
调用用户定义的OSTaskSwHook();
OSRunning = TURE;
得到将要恢复运行任务的堆栈指针;
Stack pointer = OSTCBHighRdy->OSTCBStkPtr;
从新任务堆栈中恢复处理器的所有寄存器;
执行中断返回指令
}
需要注意的几点:
(a) OSStartHighRdy()函数只是做了切换工作的一半,只是完成了高优先级任务寄存器的恢复,而并没有保存当前任务的寄存器,OSTaskSwHook()必须检查OSRuning标志位,以确定OSTaskSwHook()函数是被OSStartHighRdy()调用,此时OSRuning为FLASH,还是正常的任务切换之中被调用。
(b) OSStartHighRdy()调用完OSTaskSwHook()之后,将OSRuning置为TURE。
(c) OSStartHighRdy()需要得到最高优先级任务的堆栈指针,这里假设OSTCBHighRdy指向最高优先级任务的任务控制块。
(d) 要想运行最高优先级任务,必须将所有处理器寄存器按顺序从任务堆栈中恢复出来。
(e) OSStartHighRdy()函数的最后一步,是执行中断返回指令,使得CPU从堆栈里面恢复程序指针以及CPU的标志寄存器(也称状态寄存器)。
(f) 切记,调用OSStart()函数之前,要已经建立至少一个应用任务。
(2) OSCtwSw();
任务级的切换是通过执行软件中断指令,或者依据处理器的不同,执行TRAP(陷阱)指令来实现的。中断服务子程序,陷阱或异常处理的向量地址必须指向OSCtwSw()。
在系统服务调用的最后,会调用OSSched()函数,OSSched()函数先将最高优先级任务的地址转入OSTCBHighRdy,再通过调用OS_TASK_SW()函数执行软中断或陷阱指令。
OSCtwSw()函数的示意性代码:
Void OSCtwSw(void)
{
保存处理器寄存器;
在当前任务的任务控制块中保存当前任务的堆栈指针;
OSTCBCur->OSTCBStkPtr = Stack pointer;
OSTaskSwHook();
OSTCBCur = OSTCBHighRdy;
OSPrioCur = OSPrioHighRdy;
得到将要重新开始运行的任务的堆栈指针;
Stack pointer = OSTCBHighRdy ->OSTCBStkPtr;
从新任务的任务堆栈中恢复处理器所有寄存器的值;
执行中断返回指令;
}
(3) OSTickISR();
UCOSII要求用户提供一个周期性的时钟源,来实现时间的延迟和超时功能。时钟节拍应该每秒发生10-100次。OSStart()运行后,用户的第一个任务中初始化节拍中断。通常容易犯的错误是,在调用OSInit()和OSStart()之间,打开了任务中断,这样导致应用程序崩溃。
OSTickISR()时钟节拍ISR的示意性代码
Void OSTickISR(void)
{
保存处理器寄存器;
调用OSIntEnter()或直接给OSIntNesting 加1;
If( OSIntNesting == 1){
OSTCBCur -> OSTCBStkPtr = Stack pointer;
}
给产生中断的设备清中断(取决于中断源,有些中断源需要在中断响应的时候清中断);
重新允许中断(可选,);
OSTimeTick();
OSIntExit();
恢复处理器寄存器;
执行中断返回指令;
}
说明:
(a) 本程序执行时,中断已经禁止。OSIntNesting(中断嵌套次数寄存器)。OSIntEnter()多了边界检查功能(看嵌套是否达到255)。
(b)OSTickISR ()通过调用OSTimeTick()来维持UCOSII内部的定时。
(c) OSIntExit()决定是否因为这个中断服务程序的执行,使得更高优先级的任务就绪。
(4) OSIntCtwSw();
OSIntExit()通过调用OSIntCtwSw(),在ISR中执行任务切换功能。
OSIntCtwSw()的示意性代码
void OSIntCtwSw(void) V2.51及以上版本
{
/* V2.51一下版本 需增加下面的代码
调整堆栈指针:
OSIntExit();
OSIntCtwSw();
在当前任务的任务控制块中保存当前任务的堆栈指针
OSTCBCur -> OSTCBStkPtr = Stack pointer;
*/
调用用户定义的OSTaskSwHook();
OSTCBCur = OSTCBHighRdy;
OSPrioCur = OSPrioHighRdy;
得到将要重新开始运行的任务的堆栈指针;
Stack pointer = OSTCBHighRdy ->OSTCBStkPtr;
从新任务的任务堆栈中恢复处理器所有寄存器的值;
执行中断返回指令;
}
验证移植UCOSII是否正常工作,这可能是移植中最复杂的一步。应该首先不加任何应用代码来测试移植好的UCOSII。因为(1)用户不希望将事情复杂化;(2)如果有些部分没有正常工作,可以明白是移植本身的问题。
可以使用不同的技术测试自己的移植,取决于用户在嵌入式系统方面的经验和理解。这里通过4个步骤测试移植代码:
(1) 确保C编译器、汇编编译器及链接器正常工作;
(2) 验证OSTaskStkInit()和OSStartHighRdy()函数;
(3) 验证OSCtwSw()函数;
(4) 验证OSIntCtwSw()和OSTickISR()函数。
到这里基本的理论方面的东西都过了下,下面开始结合具体的处理器来进行移植的尝试吧。