由于以前在arm上面移植过ucos2,这次在2407上面移植这个感觉比较容易。
根据邵贝贝翻译的教材,移植过程中需要添加三个文件:os_cpu.h、os_cpu_a.asm和os_cpu_c.c。
下面分别分析这三个文件。
os_cpu.h
这个文件的全部内容如下:
#ifndef OS_CPU_H #define OS_CPU_H
typedef unsigned char BOOLEAN; typedef unsigned char INT8U; /* Unsigned 8 bit quantity, but actually 16 bit */ typedef signed char INT8S; /* Signed 8 bit quantity, but actually 16 bit */ typedef unsigned int INT16U; /* Unsigned 16 bit quantity */ typedef signed int INT16S; /* Signed 16 bit quantity */ typedef unsigned long INT32U; /* Unsigned 32 bit quantity */ typedef long INT32S; /* Signed 32 bit quantity */ typedef float FP32; /* Single precision floating point */ typedef double FP64; /* Double precision floating point, but actually single */
typedef unsigned int OS_STK; /* Each stack entry is 16-bit wide */ typedef unsigned int OS_CPU_SR;
#define OS_CRITICAL_METHOD 1
#if OS_CRITICAL_METHOD == 1 #define OS_ENTER_CRITICAL() asm(" SETC INTM") /* Disable interrupts */ #define OS_EXIT_CRITICAL() asm(" CLRC INTM") /* Enable interrupts */ #endif
#define OS_STK_GROWTH 0 /* Stack grows from LOW to HIGH memory */ #define OS_TASK_SW() asm(" INTR 8") /* use software INT 8 to do context switch */
#endif
|
由文件内容可见,改文件主要定义了和编译器相关的数据类型。另外还有两个宏:OS_ENTER_CRITICAL() 和OS_EXIT_CRITICAL() 。这两个宏用汇编来实现开关中断。
OS_STK_GROWTH 定义堆栈的增长方向。
OS_TASK_SW() 定义一个软件中断,用来切换任务。
os_cpu_a.asm
这个文件主要有一下几个函数:
_OSStartHighRdy: CALL _OSTaskSwHook LAR AR1,#1 SAR AR1,_OSRunning LAR AR1,#_OSTCBCur LAR AR1,* LAR AR1,* B I$$REST
|
这个函数被OSTaskCreat函数调用。它首先调用用户定义的OSTaskSwHook 函数,然后将OSRunning这个全局变量设为1,然后得到当前任务控制块的堆栈指针,最后通过库函数I$$REST来将堆栈中的内容取出来,并执行任务。
关于任务切换的函数:
_OSCtxSw: call I$$SAVE _OSCtxSw_0: call _OSTaskSwHook lar AR2,#_OSTCBCur larp AR2 lar AR0,*,AR0 sar AR1,* lar AR0,#_OSTCBHighRdy lar AR0,* lar AR1,*,AR2 sar AR0,* lar AR2,#_OSPrioCur lar AR0,#_OSPrioHighRdy larp AR2 sar AR0,*,AR1 b I$$REST _OSIntCtxSw: pop sbrk #3 b _OSCtxSw_0
|
上面的函数用于任务的切换,包括正常的任务切换和中断级别的任务切换,此处不作详细分析。
上面的函数是要求的最少的函数。在真正应用的时候,往往还需要添加和用户目标板相关的函数。比如移植到lf2407上的时候,就需要时钟中断的处理函数,我们也把它添加到这个文件中:
_OSTickISR: CALL I$$SAVE CALL _OSIntEnter CALL _OSTimeTickHook CALL _OSTimeTick CALL _OSIntExit B I$$REST
|
这个函数用来处理时钟中断,为系统提供时钟源。它只是简单地调用几个函数,见源代码。需要说明的是OSTimeTickHook这个函数,我们将它定义在os_cpu_c.c中,见后面的说明。其余的几个函数都是系统函数或者库函数。
os_cpu_c.c
这个文件其实就一个函数比较关键,代码如下:
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) { OS_STK *stk; opt=opt; stk = ptos; /* Load stack optointer */ *stk++ =(OS_STK) pdata; /* arg 0 */ stk++; /* next word for use. Task assembly code will pop return address to here. */ *stk++ = (OS_STK) 0x2000; /* ST1 = ARB = AR1. */ *stk++ = (OS_STK) 0x2200; /* ST0 = AR1 is current Aux. Reg, */ *stk++ = (OS_STK) 0x0000; /* Accumulator high is 0. */ *stk++ = (OS_STK) 0x0000; /* Accumulator low is 0. */ *stk++ = (OS_STK) 0x0000; /* Product High is 0. */ *stk++ = (OS_STK) 0x0000; /* T is 0. */ *stk++ = (OS_STK) 0x0000; /* Product Low is 0. */ *stk++ = (OS_STK) 0x0000; /* AR0 = 0. b.p. = ? */ *stk++ = (OS_STK) 0x0000; /* AR2 = 0 */ *stk++ = (OS_STK) 0x0000; /* AR3 = 0 */ *stk++ = (INT16U) 0x0000; /* AR4 = 0 */ *stk++ = (OS_STK) 0x0000; /* AR5 = 0 */ *stk++ = (OS_STK) 0x0000; /* AR6 = 0 */ *stk++ = (OS_STK) 0x0000; /* AR7 = 0 */ *stk++ = (OS_STK) task; /* Interrupt return address = start of task */ *stk++ = (OS_STK) task; *stk++ = (OS_STK) task; *stk++ = (OS_STK) task;
*stk++ = (OS_STK) task; /* Initialize the h/w stack. */ *stk++ = (OS_STK) task; *stk++ = (OS_STK) task; /* reset if an unbalanced return. */
return stk; }
|
这个函数完成堆栈的初始化。
另外这个文件中还有刚才在OSTickISR函数中调用的OSTimeTickHook,列出如下:
void OSTimeTickHook (void) { EVAIFRB = EVAIFRB & 0x0001; /* clear T2PINT flag */ }
|
它只是简单地将时钟中断的标志清除掉。
上面介绍了需要移植的三个文件,但是这样还不能把系统运行起来,还需要根据自己的系统加入系统的初始化代码。下面是一个应用程序的例子:
#include "lf2407.h" #include "ucos_ii.h"
OS_STK Main_TaskStk[32]; void Main_Task(void *data);
void InitCPU(void) { SCSR1 = 0x00fd; SCSR2 = (SCSR2|0x000b) & 0x000f; WDCR = 0x00e8; WSGR = 0x0040; MCRA = 0x0FFF; PBDATDIR = PBDATDIR|0x0F000; T2CON = 0x0000; GPTCONA = 0x0000; T2CNT = 0x0000; T2PR = 50000; T2CON = 0xd340; IMR = 0x0000; IFR = 0x003f; IMR = 0x0004; EVAIFRA = 0xFFFF; EVAIFRB = 0xFFFF; EVAIFRC = 0xFFFF; EVAIMRA = 0x0000; EVAIMRB = 0x0001; EVAIMRC = 0x0000;
EVBIFRA = 0xFFFF; EVBIFRB = 0xFFFF; EVBIFRC = 0xFFFF; EVBIMRA = 0x0000; EVBIMRB = 0x0000; EVBIMRC = 0x0000;
asm(" CLRC INTM"); }
int main(void) { InitCPU(); OSInit(); OSTaskCreate(Main_Task, (void *)0, &Main_TaskStk[31],0); OSStart(); return 0; }
void Main_Task(void *p_arg) { unsigned long j,k; while(1) { PBDATDIR |= 0x00f0; OSTimeDlyHMSM(0, 0, 0, 500); PBDATDIR &= 0x0ff0f; OSTimeDlyHMSM(0, 0, 0, 500); } }
|
函数InitCPU初始化cpu,主要包括我们需要为系统提供的周期性时钟。这个程序实现了对gpio的控制。可以在gpb的5-8脚上接一个led,观察情况。
希望对大家有帮助。我的qq:371310524,邮箱:
欢迎大家交流。
阅读(2851) | 评论(3) | 转发(0) |