Chinaunix首页 | 论坛 | 博客
  • 博客访问: 113351
  • 博文数量: 28
  • 博客积分: 2510
  • 博客等级: 少校
  • 技术积分: 330
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-01 15:41
文章分类

全部博文(28)

文章存档

2011年(1)

2008年(26)

2007年(1)

我的朋友

分类:

2007-10-01 16:29:37

UCOS-II移植到ARM需要做的工作如下:
1) 编写一个的与CPU相关的文件OS_CPU_A.S,此文件包含四个函数,这四个函数需用汇编编写。
a)         OSStartHighRdy( ),此函数作用为启动最高优先级任务,由OSStart( )调用。
b)        OSCtxSw( ),任务级别的切换函数,例如当前运行的任务不再是优先级最高时,这时就需要任务的切换(比如当前任务申请一个信号量而被挂起,或由于任务释放资源时,这些时候系统会进行任务的切换)。OSCtxSw( )OSSche( )调用。
c)        OSIntCtxSw( ),此函数用于由中断产生的任务切换。比如系统时钟使得一个更高优先级的任务就绪时,或者中断使得更高优先级就绪时。由于发生中断时,系统的堆栈已经保存了当前任务的上下文,而后中断处理程序又调用OSIntExit( ),最后才由OSIntExit( )调用OSIntCtxSw( )进行任务的切换,这时堆栈中就多了一些内容,需要将这些多余的内容去掉,然后调用OSCtxSw( )
d)        OSTickISR( ),为UCOS-II提供一个时钟资源来实现时间的延时和期满的功能。时钟节拍应该每秒发生10—100次。这与具体的处理器有关。
2)  编写OS_CPU_C.C文件
要求编写六个简单的函数:
OSTaskStkInit( );
OSTaskCreateHook( );
OSTaskDelHook( );
OSTaskSwHook( );
OSTaskStatHook( );
OSTimeTickHook( );
在这六个函数中最关键的是编写OSTaskStkInit( ),此函数是在任务被创建的时候,由OSTaskCreate( )调用。主要用于初始化任务堆栈,任务堆栈结构与CPU的体系结构、编译器密切相关。本次移植的任务堆栈结构如下图(一)

1OS_CPU.H
本移植是将UCOS-II移植到ARMTDMI内核,ARMTDMI7个工作模式,两个指令系统ARMTHUMB
7个工作模式中只选用用户和系统模式。本次移植将实现在用户和系统模式转换,ARMTHUMB指令系统的转换。
       当系统初始化完成后,将进入用户模式,在用户模式下进行任务的创建和运行,然后调用相应的软中断来实现用户和系统模式转换,ARMTHUMB指令系统的转换,以及任务切换等工作。也就是说任务切换是通过软中断来实现的。各个软中断(SWI)服务如下:(OS_TASK_SW( )OSStartHighRdy( )OS_CPU_A.S中实现,其他各功能实现在OS_CPU_C.C中)
__swi(0x0)    void OS_TASK_SW(void);                      /*任务级切换函数               */
__swi(0x1)    void OSStartHighRdy(void);                      /*运行优先级最高的任务    */
__swi(0x2)    void OS_ENTER_CRITICAL(void);         /*进入临界区,关中断        */
__swi(0x3)    void OS_EXIT_CRITICAL(void);             /*推出临界区,开中断        */
__swi(0x80) void ChangToSYSMode(void);                   /*任务切换到系统模式        */
__swi(0x81) void ChangToUserMode(void);                   /*任务切换到用户模式        */
__swi(0x82) void TaskIsARM(INT8U prio);                   /*任务代码是ARM指令      */
__swi(0x83) void TaskIsTHUMB(INT8U prio);              /*任务代码为THUMB指令  */
TaskIsARM( ) TaskIsTHUMB( )使用时应该注意,他们必须在任务建立后但还没运行时被调用。有以下三中解决方法:
A、 高优先级任务使用默认的指令集;
B、 改变OSTaskCreateHook( )使任务不处于就绪状态,建立任务后调用函数OSTaskResume( )来使任务进入就绪状态;
C、 建立任务时禁止任务切换,调用TaskIsARM( ) TaskIsTHUMB( )后再允许任务切换。
1、  OS_CPU_C.C
在此文件中主要是编写OSTaskStkInit( )由于任务堆栈都已经确定好了,如图(一)。很容易写出代码,其代码如下:
void *OSTaskStkInit (void (*task)(void *pd), void *pdata, void *ptos, INT16U opt)
{
    OS_STK *stk;
    opt = opt;                              /* 'opt' is not used, prevent warning        */
    stk=(OS_STK *)ptos;           /* Load stack pointer         */
    *stk = (OS_STK)task;          /* PC         (High address)           */
    *--stk = (OS_STK)task;       /* LR      */
    *--stk = 0;                             /* R12    */
    *--stk = 0;                             /* R11    */
    *--stk = 0;                             /* R10    */
    *--stk = 0;                             /* R9      */
    *--stk = 0;                             /* R8      */
    *--stk = 0;                             /* R7      */
    *--stk = 0;                             /* R6      */
    *--stk = 0;                             /* R5      */
    *--stk = 0;                             /* R4      */
    *--stk = 0;                             /* R3      */
    *--stk = 0;                             /* R2      */
    *--stk = 0;                             /* R1      */
    *--stk = (unsigned int) pdata;     /* R0, the first parameter is transfered by R0       */
    *--stk = 0x10;              /* CPSR  ,enable IRQ and FIQ interrupt     (Low address) */
    return ((void *)stk);                            
}
其余的勾挂函数,在以后具体的应用中根据具体的情况编写。
 
2、  OS_CPU_A.S
对于所有的任务级的切换,都是使用SWI软中断来实现。因此首先编写如下的汇编代码,此为SWI的汇编与C
的接口代码。软中断发生后PC指向0x08处,因此可以在0x08处放一条跳转语句指向处理程序SwiFirstHandler,然后通过SwiFirstHandler调用SwiSecondHandler( )来实现其他的功能SwiFirstHandler如程序清单1
程序清单1 软中断代码的汇编部分
SwiFirstHandler    
       LDR              SP, =SVCStack                           ;
       STMFD         SP!, {R0-R3, R12, LR}               ;保护任务环境
 
       MOV             R1, SP                                       ; Set pointer to parameters
       MRS              R3, SPSR   ; SPSR保存到R3,其实SPSR就是任务运行时的CPSR
      
       TST               R3,#T_BIT                ;判断是否是THUNMB            
       LDRNEH R0, [LR, #-2]                  ; THUMB
       BICNE           R0, R0, #0xFF00
      
       LDREQ          R0, [LR, #-4]            ; ARM
       BICEQ           R0, R0, #0xFF000000
      
       ;R0 存放 SWI 功能码
             
       CMP              R0, #1                         
       LDRLO          PC,=OS_TASK_SW      ; SWI 码是 0,进行任务的切换,在
                                                                      ;OS_CPU_A.S中实现
       LDREQ          PC,=OSStartHighRdy      ; SWI 码是 1,启动任务,
                            ;在OS_CPU_A.S中实现
      
       BL                 SwiSecondHandler              ; 在在OS_CPU_C.C中实现
       LDMFD         SP!, {R0-R3,R12,PC}^     ; 没有进行任务切换返回到当前任务
注意①,我们知道在处理器处理软中断时,处理器的工作模式本来就是SVC模式,自然SP也是指向SVC模式的
指针,这里为什么还要从新把SVC模式指针赋给SP呢?这里主要是因为在启动代码程序中,将SVC模式指针修改了,所以这里要从新将SVC模式指针赋给SP。这部分启动任务程序在OS_CPU_A.S中。
       还需注意的是本段代码并不在OS_CPU_A.S实现,而被放到启动代码文件InitTarget.s实现的。
 
2.1OSStartHighRdy()的实现
用伪码描述OSStartHighRdy()如下:
void OSStartHighRdy (void)
{
    Call user definable OSTaskSwHook();
    Get the stack pointer of the task to resume:
    Stack pointer = OSTCBHighRdy->OSTCBStkPtr;
    OSRunning = TRUE;
    Restore all processor registers from the new task's stack;
    Execute a return from interrupt instruction;
}
OSStartHighRdy( )OSStart()调用,用于启动高优先级的任务。OSStartHighRdy( )所要做的工作是将图(一)中任务堆栈的初始值直接拷贝到相应寄存器中即可完成。
 
 
2.2OS_TASK_SW( )OSIntCtxSw( )
       由于arm处理器和所用编译器的特点,OS_TASK_SW( )OSIntCtxSw( )可用相同的代码编写。
虽然OS_TASK_SW( )OSIntCtxSw( )是在两个不同的模式下被调用,OS_TASK_SW( )是在SVC模式下,而OSIntCtxSw( )是在中断模式下被调用,但是还是可以用相同代码来处理。关键是两种模式堆栈所保存的任务环境要相同,所以对于IRQ模式,也需要做一些保存任务环境的工作,具体采用以下代码来实现,如程序清单2。当发生中断时PC指向0x18处,在此处放一条跳转到IsrIRQ指令。
 
程序清单2
IsrIRQ                                                     ; using I_ISPR register.
    sub      lr,lr,#4                                       ; reserved for return
    stmfd   sp!,{r0-r3,r12,lr}                         ; restore the contexts of task to interrupted
       ; IMPORTANT CAUTION
       ; if I_ISPC isn't used properly, I_ISPR can be 0 in this routine.
    ldr          r0,=OSIntNesting                 ; OSIntNesting+1
    ldrb       r1,[r0]
    add     r1,r1,#1
    strb     r1,[r0]
    ldr       r1,= I_ISPR
    ldr       r1,[r1]
   
    cmp        r1,#0x0                ; if the idel mode work_around is used r9 may 0 sometimes
    beq      %F2
    mov     r0,#0x0
0
    movs    r1,r1,lsr #1
    bcs      %F1
    add      r0,r0,#4
    b         %B0
1
    ldr       r1,=ADC  ; ADC开始是对于44B0芯片的全部中断表,这个表如程序清单3
    add      r1,r1,r0             ; r1+r0就是找到是什么发生了中断请求
    ldr       pc,[r1]                ; 调用中断处理程序
   
    mrs         r3,spsr
    bl            OSIntExit                                                       
2    
   ldmfd   sp!,{r0-r3,r12,pc}       ; 无任务切换返回
 
程序清单3
ADC         dcd 0
RTC         dcd 0
UTXD1       dcd 0
UTXD0       dcd 0
SIO         dcd 0
IIC         dcd 0
URXD1       dcd 0
URXD0       dcd 0
TIMER5      dcd 0
TIMER4      dcd 0
TIMER3      dcd 0
TIMER2      dcd 0
TIMER1      dcd 0
TIMER0      dcd OSTickISR
UERR01      dcd 0
WDT         dcd 0
BDMA1       dcd 0
BDMA0       dcd 0
ZDMA1       dcd 0
ZDMA0       dcd 0
TICK        dcd 0
EINT4567    dcd 0
EINT3       dcd 0
EINT2       dcd 0
EINT1       dcd 0
EINT0       dcd 0  
 
需要注意的是这段代码和SwiFirstHandler一样在InitTarget.s中编写,这段代码是按照S3C44B0来编写的,采用的是非向量中断模式。在具体的应用时,中断服务程序的地址自行安排。TIMER0指向OSTickISR也就是说用TIMER0来做操作系统的时钟。
经过IsrIRQSwiFirstHandler的处理,不管是在SVC模式还是在IRQ模式,任务都以图(二)的形式保存到各自的堆栈中,这样就可以用相同的程序来处理OS_TASK_SW( )OSIntCtxSw( )了。 
 
 
程序清单4将给出如何保存被切换任务的环境
 
程序清单4
        LDR     R2,[SP,#20]       ;得到 PC
        LDR     R12,[SP,#16]      ;得到R12
        MRS     R0,CPSR  ;将当前的状态保存到R0,这样就不管是SVC还是IRQ模式
       
        MSR     CPSR_c,#SYSMODE   ;切换到系统模式
        MOV     R1,LR
        STMFD   SP!,{R1-R2}       ;//保存PC,LR,R12-R4
        STMFD   SP!,{R4-R12}
       
        MSR     CPSR_c,R0         ;//返回先前的模式
        LDMFD   SP!,{R4-R7}
        MSR     R3,SPSR           ;//被切换任务的CPSR
         ADD     SP,SP,#8         ;// 因为刚才PC和R12还没弹出栈
       
        MSR     CPSR_c,#SYSMODE
        STMFD   SP!,{R4-R7}       ;//保存 PC,LR,R3-R0
        STMFD   SP!,{R3}          ;//保存 CPSR,
       
        LDR     R1,=OSTCBCur      ;//OSTCBCur->OSTCBStkPtr = Stack pointer
        LDR     R1,[R1]
        STR     SP,[R1]
以上的代码就将被挂起任务的上下文保存到了自己的堆栈中。下面的的工作就是将更高优先级的就绪任务从任务堆栈中复制出来执行。以下代码略。

                                                    ------anmnmnly
                                                    ------2007.9.29
阅读(988) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇: 要做优秀员工(摘抄)

给主人留下些什么吧!~~