Chinaunix首页 | 论坛 | 博客
  • 博客访问: 282416
  • 博文数量: 60
  • 博客积分: 2501
  • 博客等级: 少校
  • 技术积分: 774
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-16 13:27
文章分类

全部博文(60)

文章存档

2011年(1)

2010年(1)

2009年(58)

我的朋友

分类: 嵌入式

2009-07-17 18:14:45

                                                                                                                  2009-7-17

2 OS_CPU_C.C 移植相关

 

移植时用户最多需要对下面10C函数进行修改。

(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()调用,此时OSRuningFLASH,还是正常的任务切换之中被调用。

(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;

     从新任务的任务堆栈中恢复处理器所有寄存器的值;

     执行中断返回指令;

}

 
3移植代码的测试:
 

验证移植UCOSII是否正常工作,这可能是移植中最复杂的一步。应该首先不加任何应用代码来测试移植好的UCOSII。因为(1)用户不希望将事情复杂化;(2)如果有些部分没有正常工作,可以明白是移植本身的问题。

     可以使用不同的技术测试自己的移植,取决于用户在嵌入式系统方面的经验和理解。这里通过4个步骤测试移植代码:

(1)        确保C编译器、汇编编译器及链接器正常工作;

(2)        验证OSTaskStkInit()OSStartHighRdy()函数;

(3)        验证OSCtwSw()函数;

(4)        验证OSIntCtwSw()OSTickISR()函数。

详细的测试过程可以看邵贝贝的书,这里就不再摘录了。

    到这里基本的理论方面的东西都过了下,下面开始结合具体的处理器来进行移植的尝试吧。

阅读(3838) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~