找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7712|回复: 0
打印 上一主题 下一主题
收起左侧

LPC11C14 uCOS II 2.91移植

[复制链接]
跳转到指定楼层
楼主
ID:71922 发表于 2015-1-10 20:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
将uCOSii 加入到工程,编译,如果报以下错误错误:
compiling ucos_ii.c...
linking...
.\out\test.axf: Error: L6200E: Symbol OSEventTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSFlagTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTaskStatStk multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSRdyTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTaskIdleStk multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTCBPrioTbl multiply defined (by ucos_ii.o and os_core.o).
.\out\test.axf: Error: L6200E: Symbol OSTCBTbl multiply defined (by ucos_ii.o and os_core.o).
.... 还有很多
解决方法:将ucos_ii.c  从工程中移除。

如果出现以下未定义错误:
.\out\test.axf: Error: L6218E: Undefined symbol OSCtxSw (referred from os_core.o).
.\out\test.axf: Error: L6218E: Undefined symbol OSIntCtxSw (referred from os_core.o).
.\out\test.axf: Error: L6218E: Undefined symbol OSStartHighRdy (referred from os_core.o).
.\out\test.axf: Error: L6218E: Undefined symbol OS_CPU_SR_Restore (referred from os_core.o).
.\out\test.axf: Error: L6218E: Undefined symbol OS_CPU_SR_Save (referred from os_core.o).


是因为 os_cpu_a.s 没有加入工程,将其加入工程即可解决问题。
------------------------------------------------------------------------
移植步骤:
1、修改OS_CPU.H 文件
    1、重定义与编译器、uCOS II 有关的数据类型
typedef unsigned char  BOOLEAN;
typedef unsigned char  INT8U;                    /* Unsigned  8 bit quantity                           */
typedef signed   char  INT8S;                    /* Signed    8 bit quantity                           */
typedef unsigned short INT16U;                   /* Unsigned 16 bit quantity                           */
typedef signed   short INT16S;                   /* Signed   16 bit quantity                           */
typedef unsigned int   INT32U;                   /* Unsigned 32 bit quantity                           */
typedef signed   int   INT32S;                   /* Signed   32 bit quantity                           */
typedef float          FP32;                     /* Single precision floating point                    */
typedef double         FP64;                     /* Double precision floating point                    */

typedef unsigned int   OS_STK;                   /* Each stack entry is 32-bit wide                    */
typedef unsigned int   OS_CPU_SR;                /* Define size of CPU status register (PSR = 32 bits) */

    2、定义中断的实现方式,一般是为了实现临界区代码保护

#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

    3、定义栈的生长方式

            /*  堆栈1是从上往下长的,0-从下往上的生长方式         */
        #define  OS_STK_GROWTH        1          /* Stack grows from HIGH to LOW memory on ARM    */

    4、宏定义 优先级任务切换 函数,用于现场保护以及现场恢复实现任务切换
        #define  OS_TASK_SW()         OSCtxSw()        // 任务级任务切换


    5、定义开、关中断的函数,在保护临界区代码时会用到。

#if OS_CRITICAL_METHOD == 3           /* See OS_CPU_A.ASM   */         
OS_CPU_SR  OS_CPU_SR_Save(void);
void         OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
#endif

    6、声明函数 这些函数都是要自己实现或修改

void       OSCtxSw(void);                           // 任务级切换 触发PendSV异常
void       OSIntCtxSw(void);                        // 中断级切换 触发PendSV异常
void       OSStartHighRdy(void);                // 运行最高优先级的任务
void       OS_CPU_PendSVHandler(void);         // 发生PendSV异常时被触发,OSCtxSw()、OSIntCtxSw() 最终实现 即任务切换                                               
void       OS_CPU_SysTickHandler(void);        /* See OS_CPU_C.C                                    */
void       OS_CPU_SysTickInit(void);          // 系统时钟节拍初始化 用于任务切换                                                  
INT32U     OS_CPU_SysTickClkFreq(void);        /* See BSP.C OS_CPU_SysTickInit(void);用来获得硬件的时钟频率,这里是直接指定并没有用上。*/
OS_CPU_PendSVHandler(void)、OS_CPU_SysTickHandler(void) 需要在 startup_LPC11xx.s 定义
           



2、修改OS_CPU_C.C  文件
1、修改OSTaskStkInt()函数
    主要修改OSTaskStkInit()函数,其他的HOOK函数根据需要实现(将文件OS_CFG.H中的#define constant OS_CPU_HOOKS_EN设为1,设为0表示不使用这些函数
    用户创建任务时,OSTasKCreat()会调用OSTaskStkInt()函数初始化该任务的堆栈,并把返回的堆栈指针保存到该任务的TCB结构中
    的最前面的参数OSTCBStkPtr中,当该任务要被恢复时,任务切换函数从其TCB块中取得其任务堆栈指针,依次将堆栈内容弹到处理器
    对应的CPSR、r0、r1,…,r12,lr,pc的寄存器中,完成现场的恢复和程序指针PC的返回。


// 创建任务时被调用 初始化任务堆栈  具体实现不是很明白
OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)

{
    OS_STK *stk;
    (void)opt;                                   /* 'opt' is not used, prevent warning                 */
    stk       = ptos;                            /* Load stack pointer 获取堆栈指针                    */


                                                 /* Registers stacked as if auto-saved on exception    */
    *(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);
}



  2、实现  void  OS_CPU_SysTickInit (void)、void  OS_CPU_SysTickHandler (void)
        // 初始化SysTick 用于在固定时产生中断

void  OS_CPU_SysTickInit (void)
{
    INT32U  cnts;
    /* cnts = OS_CPU_SysTickClkFreq() / OS_TICKS_PER_SEC; */
        cnts = 48000000 / OS_TICKS_PER_SEC;        // OS_TICKS_PER_SEC 10ms 产生一次中断


    OS_CPU_CM3_NVIC_ST_RELOAD = (cnts - 1);
        OS_CPU_CM3_NVIC_ST_CURRENT = 0;


        /* Set Priority of SysTick to 2 (0-3, 0 is highest)   */
        cnts = OS_CPU_CM0_NVIC_SHPR3;
        cnts &= 0x00FFFFFF;
        cnts |= 0x80000000;
        OS_CPU_CM0_NVIC_SHPR3 = cnts;
                                                 /* Enable timer.                                      */
    OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC | OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;
                                                 /* Enable timer interrupt.                            */
    OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_INTEN;
}


    // SysTick中断服务函数 用于产生系统节拍
void  OS_CPU_SysTickHandler (void)
{
    OS_CPU_SR  cpu_sr;

    OS_ENTER_CRITICAL();                         /* Tell uC/OS-II that we are starting an ISR          */
    OSIntNesting++;
    OS_EXIT_CRITICAL();
    OSTimeTick();                                /* Call uC/OS-II's OSTimeTick()                       */
    OSIntExit();                                 /* Tell uC/OS-II that we are leaving the ISR          */
}


3、修改OS_CPU_A.S 文件
  1、定义寄存器地址
      NVIC_INT_CTRL   EQU     0xE000ED04                              ; Interrupt control state register.
NVIC_SCB_SHPR3  EQU     0xE000ED20
NVIC_PENDSV_PRI EQU     0x00FF0000
NVIC_PENDSVSET  EQU     0x10000000                              ; Value to trigger PendSV exception.

  2、实现 OS_CPU_SR_Save()、OS_CPU_SR_Restore()、OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()、OS_CPU_PendSVHandler()
  
    // 实现OS_CPU_SR_Save()、OS_CPU_SR_Restore()

    // 通过保存中断状态来禁用、启用中断 用在
OS_CPU_SR_Save                    ; 保存中断状态    MRS     R0, PRIMASK           ; Set prio int mask to mask all (except faults)    CPSID   I    BX      LR
OS_CPU_SR_Restore                 ; 恢复中断状态    MSR     PRIMASK, R0    BX      LR

// 实现 OSStartHighRdy()
// 启动优先级最高的任务
OSStartHighRdy
        ; 设置PendSV 异常优先级为最低
        ldr     r0, =NVIC_SCB_SHPR3                                               
        ldr     r1, [r0]
        ldr     r2, =NVIC_PENDSV_PRI
        orrs    r1, r1, r2
        str     r1, [r0]

    ; 初始化PSP设置为 0    MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch call    MSR     PSP, R0                                                ; PSP为0 告诉上下文切换,这是第一次运行
    ; 设置 任务运行状态为 1    LDR     R0, =OSRunning                                      ; OSRunning = TRUE    MOVS    R1, #1    STRB    R1, [R0]
    ; 触发PendSV 异常,实现任务切换     LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)    LDR     R1, =NVIC_PENDSVSET    STR     R1, [R0]
     ; PendSV 异常处理函数会关闭中断,所以需要开中断    CPSIE   I                                                   ; 使能中断 Enable interrupts at processor level
OSStartHang    B       OSStartHang                                         ; Should never get here

[size=14.44444465637207px]// 实现 OSCtxSw() 任务级切换任务
// 触发PendSV 异常,实现任务切换
OSCtxSw    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)    LDR     R1, =NVIC_PENDSVSET    STR     R1, [R0]    BX      LR

[size=14.44444465637207px]//
实现 OSIntCtxSw() 中断级切换任务
// 触发PendSV 异常,实现任务切换

OSIntCtxSw
    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]
    BX      LR


;/* Pendsv 中断函数 */
;/* 用于实现时间片轮转法 中断级任务调度、任务级中断调度 切换上下文*/
; 进入PendSV时:
; xPSR、PC、LR、R12、R0~R3 已经在处理栈中被保存
; 处理模式切换到线程模式
; 栈是主堆栈
OS_CPU_PendSVHandler
    CPSID   I                                                      ; 关闭中断,避免上下文切换时发送中断。
    MRS     R0, PSP                             ; PSP is process stack pointer
    ;CBZ     R0, OS_CPU_PendSVHandler_nosave    ; Skip register save the first time
        cmp                r0, #0                                                            ; 如果获取任务的SP 为0 则跳到 OS_CPU_PendSVHandler_nosave
        beq                OS_CPU_PendSVHandler_nosave

        ; 保存R3~R11和SP
    SUBS    R0, R0, #0x20                       ; Save remaining regs r4-11 on process stack
        stm     r0!, {r4-r7}
        mov     r1, r8
        mov     r2, r9
        mov     r3, r10
        mov     r4, r11
        stm     r0!, {r1-r4}
        subs    r0, r0, #0x20

        ; 将当前的堆栈指针给当前进程的任务块
    LDR     R1, =OSTCBCur                       ; OSTCBCur->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    STR     R0, [R1]                            ; R0 is SP of process being switched out

                                                ; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
    ; 调用 OSTaskSwHook() 函数 用于扩展
        mov     r0, lr
        push    {r0}
        ldr     r0, =OSTaskSwHook
        blx     r0
        pop     {r0}
        mov     lr, r0

        ; 获取当前最高优先级的任务
    LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;
    LDR     R1, =OSPrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]

    ; 获取当前就绪的线程
    LDR     R0, =OSTCBCur                                       ; OSTCBCur  = OSTCBHighRdy;
    LDR     R1, =OSTCBHighRdy
    LDR     R2, [R1]
    STR     R2, [R0]

        ; 得到新任务的SP和线程恢复 R4~R11
    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
        ldm     r0!, {r4-r7}
        ldm     r0!, {r1-r3}
        mov     r8, r1
        mov     r9, r2
        mov     r10, r3
        ldm     r0!, {r1}
        mov     r11, r1

        ; 载入新的SP和返回
    MSR     PSP, R0                                             ; Load PSP with new process SP
    mov     r0, lr
        movs    r1, #0x04
        orrs    r0, r0, r1
        mov     lr, r0
        CPSIE   I                                  ; 开启中断                                                                                               
    BX      LR                                                  ; Exception return will restore remaining context
    b       .
    END

移植uCOS II 的难点在于:函数的实现。
总结:
OS_CPU_C.C:
        void  OS_CPU_SysTickInit (void)、void  OS_CPU_SysTickHandler (void)
        任务调度,产生系统时钟节拍,每一次节拍就切换一次当前就绪表中优先级最高的任务

OS_CPU_A.S:
        OS_CPU_SR_Save()、OS_CPU_SR_Restore():
        用于任务保存和恢复自身的中断状态。用于临界区代码。
       
        OSStartHighRdy():
        寻找就绪表中优先级最高的任务。

        OSCtxSw()、OSIntCtxSw()、OS_CPU_PendSVHandler()
        OSCtxSw()、OSIntCtxSw()都是通过触发PendSV异常进行任务切换
        OSCtxSw():一般是在任务调用延时函数 如OSTimeDlyHMSM(0, 0, 0, 300); 时调用的。

        OSIntCtxSw():一般用在系统时钟节拍中断时,会采用这种方式调度新的任务。
        OS_CPU_PendSVHandler() 产生异常PendSV异常就进行一次任务切换







                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表