Chinaunix首页 | 论坛 | 博客
  • 博客访问: 523749
  • 博文数量: 87
  • 博客积分: 4086
  • 博客等级: 上校
  • 技术积分: 900
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-23 15:55
文章分类

全部博文(87)

文章存档

2012年(3)

2010年(13)

2009年(7)

2008年(64)

我的朋友

分类: C/C++

2008-07-03 19:50:32

由于以前在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) |
给主人留下些什么吧!~~

yqliu292008-07-07 21:32:43

最近为了参加一个电子设计大赛学的,反正有机会,不学白不学,呵呵! 我去建一个空的哈,名字就叫做讨论帖!

snfhvmtd2008-07-07 18:34:13

我是追风的沙。你建个空文章,专门在那里讨论一些东西。呵呵

snfhvmtd2008-07-07 18:28:22

你用ARM也用DSP呀,牛人。