uC/OS-ii移植详解

来源:互联网 发布:均不是c语言关键字 编辑:程序博客网 时间:2024/06/07 13:31
uC/OS ii的移植要点:  uC/OS ii的移植相当LINUX来说是非常简单的,uC/OS ii的移植涉及到的代码很少;我们只需要修改与处理器相关的代码即可;  OS_CPU.H:设置与处理器与编译器有关的代码  OS_CPU_C.C:在这其中用C语言编写6个与操作系统相关的函数  OS_CPU.ASM:在这其中用汇编语言编写4个与处理器相关的函数  如上图,需要移植的部分就是Ports路径下的几个代码文件,其他的代码都不要移植(os_cfg.h只是用来配置系统的各个功能,做系统的裁剪而且,ucos_ii.h中提供系统所有的接口函数,os_cpu_a.asm就是OS_CPU.ASM1:修改OS_CPU.H  OS_CPU.H中定义了数据类型、处理器的堆栈数据类型的字长、堆栈增长方向、任务切换宏、临界区访问处理。  从方便移植的角度,uC/OS ii使用的数据类型,都是自己定义的那一套。      typedef unsigned char  BOOLEAN;      typedef unsigned char  INT8U;                         typedef signed   char  INT8S;                          typedef unsigned short INT16U;                         typedef signed   short INT16S;                        typedef unsigned long  INT32U;                        typedef signed   long  INT32S;                        typedef float          FP32;                          typedef double         FP64;         typedef unsigned int   OS_STK;                        typedef unsigned int   OS_CPU_SR;             M3使用的是向下生长的满栈,堆栈指针指向最后一个被压入堆栈的32位整数:      #define  OS_STK_GROWTH  1    定义开关中断的宏:      #define  OS_CRITICAL_METHOD   3      #if OS_CRITICAL_METHOD == 3      #define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}      #define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}      #endif   定义宏OS_TASK_SW执行任务切换:#define  OS_TASK_SW()         OSCtxSw()2:在OS_CPU_C.C中要求用户编写10个简单的C函数【唯一必要修改的函数是OSTaskStkInit(),其余的函数必须声明,但并不一定要包含任何代码】OSTaskStkInit():任务创建函数OSCreate()与OSCreateExt()通过调用OSTaskStkInit,初始化任务的栈结构,因此,任务的堆栈看起来就像刚发生了中断一样(所以的寄存器按一定的次序都保存在堆栈中,为什么要这样做?因为任务间的切换就是任务堆栈中保存的CPU现场的切换,所以任务被创建时,要初始化它的堆栈,为后面的切换做准备)OSTaskCreateHook(ptcb):【系统提供给用户的钩子函数】任务创建时OSCreate()与OSCreateExt()调用OS_TCBInit,OS_TCBInit会调用OSTaskCreateHook,同时传递指向刚刚建立的任务的任务控制块的指针,这样OSTaskCreateHook就可以访问任务控制块结构的所有成员,这个函数的功能有限,不是必要的函数,且需要通过OS_APP_HOOKS_EN使能,且该函数调用时中断是开着的。OSTaskDelHook(ptcb):OSTaskDel()会调用OSTaskDelHook(ptcb),即在将任务从uC/OS II的内部有效链表中删除之前被调用,同时传递一个指向被删除任务的任务控制块的指针,OSTaskDelHook可以用来检验TCB扩展部分是否已建立(一个非空指针),并可进行一些清0操作,OSTaskDelHook调用时,中断是关闭的,函数太长会影响中断响应时间。OSTaskSwHook():在任务切换时会调用OSTaskSwHook,不论是在OSCtxSw()还是OSIntCtxSw(),都会调用该函数,OSTaskSwHook可访问全局变量OSTCBCur(指向将被切换出去的任务的任务控制块)、OSTCBHiggRdy(指向新任务的任务控制块) ,OSTaskSwHook被调用时,中断是关闭的,函数太长会影响中断响应时间。OSTaskIdleHook():很多微处理器都允许执行相应的指令,将CPU置于低功耗模式,而当接收到中断信号时,CPU就会自动退出低功耗模式。OS_TaskIdle()函数可以调用OSTaskIdleHook()来实现CPU的这种低功耗模式【很好】。OSTaskStatHook():该函数每秒都会被统计任务OS_TaskStat()【统计任务每秒执行一次】调用一次,可以通过该函数扩展统计任务的功能,如可跟踪并显示每个任务的执行时间、每个任务所用的CPU份额以及每个任务执行的频率等等,该函数没有任何参数。OSTimeTickHook():该函数在每个时钟节拍都会被OSTimeTick()调用;systick中断服务程序SysTickHandler调用OSTimeTickHook,在这里面用户可以处理应急的事务。OSInitHookBegin():进入OSInit()函数后,OSInitHookBegin就会被调用,添加这个函数的原因在于想把与OS有关的初始化代码也放在OSInti()函数中,这个函数使得用户可以将自己特定的代码也放在OSInit()函数中。OSInitHookEnd():OSInitHookEnd与OSInitHookBegin相似,只是他在OSInit()函数返回之前被调用,添加这个函数的原因与OSInitHookBegin是一样的。OSTCBInitHook(ptcb):任务创建时OSCreate()与OSCreateExt()调用OS_TCBInit,OS_TCBInit会在调用OSTaskCreateHook前调用 OSTCBInitHook ,用户可以在OSTCBInitHook函数中做一些与初始化控制块OS_TCB有关的处理,在OSTaskCreateHook中做一些与初始化任务有关的处理;OSTCBInitHook收到的ptcb参数指向新添加任务的任务控制块的指针,而这个新添加任务的任务控制块绝大部分已经初始化完成,但是还没有链接到已经建立任务的链表中。OS_STK * OSTaskStkInit (void (*task)(void *p_arg),                         void *p_arg,                         OS_STK *ptos,                         INT16U opt){    OS_STK *stk;    (void)opt;                                    stk       = ptos;        *(stk)    = (INT32U)0x01000000L;           //xPSR                                     *(--stk)  = (INT32U)task;                  //Entry Point                           *(--stk) = (INT32U)0xFFFFFFFEL; // R14(LR) (init value will cause fault if ever used)        *(--stk)  = (INT32U)0x12121212L;          // R12                                      *(--stk)  = (INT32U)0x03030303L;          // R3      *(--stk)  = (INT32U)0x02020202L;           // R2       *(--stk)  = (INT32U)0x01010101L;           //  R1        *(--stk)  = (INT32U)p_arg;                 // R0 : argument     //Remaining registers saved on process stack     *(--stk)  = (INT32U)0x11111111L;           // R11      *(--stk)  = (INT32U)0x10101010L;           // R10      *(--stk)  = (INT32U)0x09090909L;           // R9        *(--stk)  = (INT32U)0x08080808L;           // R8          *(--stk)  = (INT32U)0x07070707L;           // R7         *(--stk)  = (INT32U)0x06060606L;           // R6         *(--stk)  = (INT32U)0x05050505L;           // R5         *(--stk)  = (INT32U)0x04040404L;           // R4           return (stk);}3:在OS_CPU_A.ASM中用汇编写4个与处理器相关的函数   需要移植的函数有,如下所示,   OSStartHighRdy():在调用OSStart()函数时,使就绪态任务中优先级最高的任务开始运行   OSCtxSw():   OSIntCtxSw():   OSTickISR():   OS_CPU_SR_Save()   OS_CPU_SR_Restore():OSCtxSw():可以参考学习笔记中的记录,M3中任务切换还需实现软中断的处理函数OSCtxSw   ;悬起PSV异常    LDR     R0, =NVIC_INT_CTRL                                      LDR     R1, =NVIC_PENDSVSET    STR     R1, [R0]    BX      LROSIntCtxSw():在退出中断前调用OSIntCtxSw,在ISR中执行任务的切换功能,OSIntCtxSw与OSCtxSw基本相同,M3的是一模一样的。OSPendSV 【软中断的处理函数】    MRS     R0, PSP                                                CBZ     R0, OSPendSV_nosave                                    SUBS    R0, R0, #0x20                                          STM     R0, {R4-R11}    LDR     R1, __OS_TCBCur                                        LDR     R1, [R1]    STR     R0, [R1]                                                            OSPendSV_nosave    PUSH    {R14}                                                   LDR     R0, __OS_TaskSwHook                                 ; OSTaskSwHook();    BLX     R0    POP     {R14}    LDR     R0, __OS_PrioCur                                      LDR     R1, __OS_PrioHighRdy    LDRB    R2, [R1]    STRB    R2, [R0]    LDR     R0, __OS_TCBCur                                       LDR     R1, __OS_TCBHighRdy    LDR     R2, [R1]    STR     R2, [R0]    LDR     R0, [R2]                                              LDM     R0, {R4-R11}                                            ADDS    R0, R0, #0x20    MSR     PSP, R0                                                 ORR     LR, LR, #0x04                                           BX      LR   OSTickISR在这里即SysTickHandler函数void SysTickHandler(void){    OS_CPU_SR  cpu_sr;    OS_ENTER_CRITICAL();      OSIntNesting++;    OS_EXIT_CRITICAL();      OSTimeTick();     //主要判断延时的任务是否计时到    OSIntExit();  //在os_core.c文件里定义,如果有更高优先级的任务就绪了,则执行一次任务切换}OSStartHighRdy    LDR     R0, =NVIC_SYSPRI2                                       LDR     R1, =NVIC_PENDSV_PRI    STRB    R1, [R0]               //这几句是设置PendSV优先级    MOVS    R0, #0                                                 MSR     PSP, R0          //设置PSP的初始值0(在第一次PendSV中断服务程序中不用保存CPU的各寄存器)    LDR     R0, __OS_Running                                     MOVS    R1, #1    STRB    R1, [R0]             // OSRunning = TRUE,表明操作系统已经运行     LDR     R0, =NVIC_INT_CTRL                                     LDR     R1, =NVIC_PENDSVSET    STR     R1, [R0]            //触发PendSV中断,暂时挂起    CPSIE   I                   //开总中断【一定要在这里才开总中断,如果在此之前任何一个地方开中断,系统一旦响应中断,很有可能造成系统因没有做出足够的准备而出错(比如如果在初始化systicks时就开启了中断,uC/OS此时还处于未知阶段,就会崩溃),所在在这里开启总中断才是安全的】                                       OS_CPU_SR_Save()     MRS     R0, PRIMASK   ;保存全局中断标志      CPSID   I           ;关中断    BX      LROS_CPU_SR_Restore()    MSR     PRIMASK, R0    ;恢复全局中断标志    BX      LR【到此移植完毕】
0 0
原创粉丝点击