×
单片机 > 单片机程序设计 > 详情

UCOS在S3C2410上的移植

发布时间:2020-06-06 发布时间:
|

反反复复弄了一个多星期,参考了不少资料,终于让UCOS在自己的板子上跑起来了。期间遇到了不少问题,还好坚持下来,挺 了过去.....复习一下,记录下来,以当后用:

      1.在ADS中建产工程,进入工程界面后,先建立两个组,一个为命名为UCOSII,另一个为S3C2410。

UCOSII,下再建两个组,一个为ARM,添加移植要修改的三个文件,另一个sourc则添加与处理器无关的 UCOS源文件。

S3C2410下主要存放一些与开发板初始化等有关的文件。

        

2.移植的重点主要在三个有处理器有关的文件OS_CPU.H,Os_cpu_a.s 和Os_cpu_c.c三个文件的编写。

(1)根据书上的移植说明及相关的参考文件,OS_CPU.H的编写最简单,主要是定义一些数据类型以及开关中断的 方法等;

(2) Os_cpu_c.c这个文件中,有不少钩子函数,都默认为空函数即可,无需编写.只有一个很重要的函数需要动手编写,即任务堆栈初始化函数 OSTaskStkInit,它在任务创建时用来对任务堆栈的初始化工作,可以采用软中断或函数调用的方式来完成.

OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt)
{
    OS_STK *stk;

    opt      = opt;                 /* 'opt' is not used, prevent warning                      */
    
    stk      = ptos;                /* Load stack pointer                                      */
    
    *(stk)   = (OS_STK)task;        /* Entry Point                                             */
    *(--stk) = (INT32U)0;         /* LR                                                      */
    *(--stk) = (INT32U)0;         /* R12                                                     */
    *(--stk) = (INT32U)0;         /* R11                                                     */
    *(--stk) = (INT32U)0;         /* R10                                                      */
    *(--stk) = (INT32U)0;         /* R9                                                      */
    *(--stk) = (INT32U)0;         /* R8                                                      */
    *(--stk) = (INT32U)0;         /* R7                                                      */
    *(--stk) = (INT32U)0;         /* R6                                                      */
    *(--stk) = (INT32U)0;         /* R5                                                      */
    *(--stk) = (INT32U)0;         /* R4                                                      */
    *(--stk) = (INT32U)0;         /* R3                                                      */
    *(--stk) = (INT32U)0;         /* R2                                                      */
    *(--stk) = (INT32U)0;         /* R1                                                      */
    *(--stk) = (INT32U)p_arg;   /* R0 : argument ARM的第一个参数存放在R0中                                         */
    *(--stk) = (INT32U)0x00000013L;   /* CPSR (SVC mode, Enable both IRQ and FIQ interrupts)    */                  
    return (stk);
}

(3).Os_cpu_a.s文件中需要编写四个汇编函数: OSStartHighRdy, OSCtxSw, OSTickISR , OSIntCtxSw

;*********************************************************************************************************/
IMPORT OSRunning        //在本文件中要用到别的文件中定义的变量,要IMPORT导入
IMPORT OSTCBCur       
IMPORT OSTCBHighRdy
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
IMPORT OSIntNesting

   
IMPORT OSIntEnter
IMPORT OSIntExit
IMPORT OSTaskSwHook
IMPORT OSTimeTick

IMPORT HandleEINT0

EXPORT OSStartHighRdy    //在本汇编文件中定义实现的函数或变量用EXPORT导出,在别的文件中只要用时,
EXPORT OSCtxSw              //用extern(.c文件)或IMPORT(.S文件)声明
EXPORT OSTickISR 
EXPORT OSIntCtxSw

EXPORT OSCPUSaveSR
EXPORT OSCPURestoreSR

EXPORT OS_CPU_IRQ_ISR


AREA UCOS_ARM, CODE, READONLY

;*********************************************************************************************************
;                                          START MULTITASKING
;                                       void OSStartHighRdy(void)
;
; The stack frame is assumed to look as follows:
;
;           Entry Point(Task Name)     (High memory)
;                               LR(R14)
;                               R12
;                               R11
;                               R10
;                               R9
;                               R8
;                               R7
;                               R6
;                               R5
;                               R4
;                               R3
;                               R2
;                               R1
;                               R0 : argument
; OSTCBHighRdy->OSTCBStkPtr --> CPSR         (Low memory)
;
; Note : OSStartHighRdy() MUST:
;           a) Call OSTaskSwHook() then,
;           b) Set OSRunning to TRUE,
;           c) Switch to the highest priority task.
;********************************************************************************************************** */
OSStartHighRdy 
;---------------------------------------------------------------------------------- 
; 下面的代码功能:OSRunning = TRUE;
;---------------------------------------------------------------------------------- 

MSR     CPSR_cxsf,#SVCMODE|NOINT     ;Switch to SVC mode with IRQ&FIQ disable

BL   OSTaskSwHook            ;Call user define Task switch hook

LDR   R0, =OSRunning          ; OSRunning =TRUE
MOV   R1, #1
STRB R1, [R0]

;----------------------------------------------------------------------------------  
;    SP = OSTCBHighRdy->OSTCBStkPtr;得到将要恢复运行任务的堆栈指针
;---------------------------------------------------------------------------------- 
LDR R0, =OSTCBHighRdy   ;堆栈指针在任务控制块偏移量为0的地方
LDR R0, [R0]         
LDR SP, [R0]        

;----------------------------------------------------------------------------------  
; Prepare to return to proper mode 从新任务堆栈中恢复处理器的所有寄存器
;---------------------------------------------------------------------------------- 
LDMFD SP!, {R0} 
MSR SPSR_cxsf, R0
LDMFD SP!, {R0-R12, LR, PC}^


;**********************************************************************************************************
;                                PERFORM A CONTEXT SWITCH (From task level)任务级任务切换
;                                           void OSCtxSw(void)
;
; Note(s):     1) Upon entry: 
;                 OSTCBCur      points to the OS_TCB of the task to suspend
;                 OSTCBHighRdy points to the OS_TCB of the task to resume
;
;              2) The stack frame of the task to suspend looks as follows:
;                                                   
;                                                   PC                    (High memory)
;                LR(R14)     
;                                    R12
;                                     R11
;                                    R10
;                                    R9
;                                     R8
;                                     R7
;                                     R6
;                                     R5
;                                     R4
;                                     R3
;                                     R2
;                                     R1
;                                     R0
;        OSTCBCur->OSTCBStkPtr ----> CPSR      (Low memory)
;
;
;              3) The stack frame of the task to resume looks as follows:
;
;                  PC     (High memory)
;                                                   LR(R14) 
;                                     R12
;                                    R11
;                                    R10
;                                    R9
;                                     R8
;                                     R7
;                                      R6
;                                     R5
;                                     R4
;                                     R3
;                                     R2
;                                     R1
;                                      R0
;       OSTCBHighRdy->OSTCBStkPtr ----> CPSR      (Low memory)
;*********************************************************************************************************/
OSCtxSw

STMFD SP!, {LR}           ;PC
STMFD SP!, {R0-R12, LR}   ;R0-R12 LR
MRS   R0, CPSR       ;Push CPSR
STMFD SP!, {R0} 
  
;----------------------------------------------------------------------------------
;    OSTCBCur->OSTCBStkPtr = SP 在当前任务控制块中保存当前任务的堆栈指针
;----------------------------------------------------------------------------------  
LDR   R0, =OSTCBCur
LDR   R0, [R0]
STR   SP, [R0]

;----------------------------------------------------------------------------------  
; OSTaskSwHook();
;--------------------------------------------------------------------------------- 
BL    OSTaskSwHook

;----------------------------------------------------------------------------------   
; OSTCBCur = OSTCBHighRdy; 将指向当前任务的指针指向要恢复的任务//OSTCBCur:Pointer to highest priority TCB R-to-R   
;----------------------------------------------------------------------------------  
LDR   R0, =OSTCBHighRdy
LDR   R1, =OSTCBCur
LDR   R0, [R0]
STR   R0, [R1]

;----------------------------------------------------------------------------------  
; OSPrioCur = OSPrioHighRdy; 将新任务的优先级赋给当前任务的优先级//OSPrioHighRdy: Priority of highest priority task
;----------------------------------------------------------------------------------  
LDR   R0, =OSPrioHighRdy
LDR   R1, =OSPrioCur
LDRB R0, [R0]
STRB R0, [R1]

;----------------------------------------------------------------------------------  
; OSTCBHighRdy->OSTCBStkPtr;得到将要运行的任务的堆栈指针
;----------------------------------------------------------------------------------  
LDR   R0, =OSTCBHighRdy
LDR   R0, [R0]
LDR   SP, [R0]

;---------------------------------------------------------------------------------- 
;Restore New task context 从新任务中恢复处理器的寄存器
;---------------------------------------------------------------------------------- 
LDMFD SP!, {R0}   ;POP CPSR
MSR SPSR_cxsf, R0
LDMFD SP!, {R0-R12, LR, PC}^ 

*********************************************************************************************************
;                                            TICK HANDLER
; Description: 此处为时钟节拍中断处理函数

;过程简介:当初始化时钟源(采用timer0),开始中断后。定时时间到,产生中断,CPU进入 IRQ模式,PC跳转到0X18处,经过中断源查询后,调用OS_CPU_IRQ_ISR   ,在OS_CPU_IRQ_ISR 中切换为管理模后保存处理器寄存器后,再经查询跳转到些正式进行中断服务程序处理,然后返回(中断处理及切换最难:后详解)
;     This handles all the Timer0(INT_TIMER0) interrupt which is used to generate the uC/OS-II tick.
;*********************************************************************************************************/

OSTickISR
;---------------------------------------------------------------------------------- 
;;保存处理器的值;
;----------------------------------------------------------------------------------

MOV     R5,LR 
;---------------------------------------------------------------------------------- 
;调用OSIntEnter or 将OSIintNesting加1
;---------------------------------------------------------------------------------- 

MOV R1, #1                     ;清除中断标志
MOV R1, R1, LSL #10      ; Timer0 Source Pending Reg.Timer0为位10
LDR R0, =SRCPND         ;源未决寄存器中有中断时,相应位置1,
LDR     R2, [R0]
ORR     R1, R1,R2
STR R1, [R0]

LDR   R0, =INTPND         ;中断未决寄存器中只保存未屏蔽的具有最高优先级的一位中断标志
LDR   R1, [R0]
STR   R1, [R0]  

;----------------------------------------------------------------------------------  
; OSTimeTick();
;---------------------------------------------------------------------------------- 
BL   OSTimeTick 
MOV    PC, R5           ; Return 

;*********************************************************************************************************
;                                PERFORM A CONTEXT SWITCH (From an ISR)
;                                        void OSIntCtxSw(void)
;
; Description: 1) This code performs a context switch if a higher priority task has been made ready-to-run
;               during an ISR.
;
;              2) The stack frame of the task to suspend looks as follows:
;
;                PC      (High memory)
;                                                   LR(R14)
;                                    R12
;                                     R11
;                                    R10
;                                    R9
;                                     R8
;                                     R7
;                                     R6
;                                     R5
;                                     R4
;                                     R3
;                                     R2
;                                     R1
;                                     R0
;                                    
;        OSTCBCur->OSTCBStkPtr ----> CPSR      (Low memory)
;
;
;              3) The stack frame of the task to resume looks as follows:
;
;                  PC      (High memory)
;                                                   LR(R14) 
;                                     R12
;                                    R11
;                                    R10
;                                    R9
;                                     R8
;                                     R7
;                                      R6
;                                     R5
;                                     R4
;                                     R3
;                                     R2
;                                     R1
;                                      R0
;       OSTCBHighRdy->OSTCBStkPtr ----> CPSR      (Low memory)
;*********************************************************************************************************/
OSIntCtxSw
;----------------------------------------------------------------------------------  
; Call OSTaskSwHook();
;---------------------------------------------------------------------------------- 
BL    OSTaskSwHook

;----------------------------------------------------------------------------------   
; OSTCBCur = OSTCBHighRdy;
;----------------------------------------------------------------------------------  
LDR   R0, =OSTCBHighRdy
LDR   R1, =OSTCBCur
LDR   R0, [R0]
STR   R0, [R1]

;----------------------------------------------------------------------------------  
; OSPrioCur = OSPrioHighRdy;
;----------------------------------------------------------------------------------  
LDR   R0, =OSPrioHighRdy
LDR   R1, =OSPrioCur
LDRB R0, [R0]
STRB R0, [R1]

;----------------------------------------------------------------------------------  
;    SP = OSTCBHighRdy->OSTCBStkPtr;
;----------------------------------------------------------------------------------  
LDR   R0, =OSTCBHighRdy
LDR   R0, [R0]
LDR   SP, [R0]

;---------------------------------------------------------------------------------- 
; Restore New Task context
;---------------------------------------------------------------------------------- 
LDMFD SP!, {R0}              ;POP CPSR
MSR SPSR_cxsf, R0
LDMFD SP!, {R0-R12, LR, PC}^ 


OS_CPU_IRQ_ISR

STMFD   SP!, {R1-R3}    ; use R1-R3 as temporary registers,push R1-R3 to IRQ stack
;----------------------------------------------------------------------------
;   R1--SP
; R2--PC 
;   R3--SPSR
;------------------------------------------------------------------------
MOV     R1, SP
ADD     SP, SP, #12             ;Adjust IRQ stack pointer,因为保存了R1-R3,,SP_irq往下移了,为了以后中断使用

                                              ;要用到中断堆栈,故此处需要调整回去到其开始定义的地方
SUB     R2, LR, #4              ;Adjust PC for return address to task

MRS     R3, SPSR                 ; Copy SPSR (Task CPSR)

  

MSR     CPSR_cxsf, #SVCMODE|NOINT   ;Change to SVC mode

                                                                   ; SAVE TASK''S CONTEXT ONTO OLD TASK''S STACK
         
STMFD   SP!, {R2}               ; Push task''s PC 
STMFD   SP!, {R4-R12, LR}   ; Push task''s LR,R12-R4

LDMFD   R1!, {R4-R6}    ; Load Task''s R1-R3 from IRQ stack 
STMFD   SP!, {R4-R6}    ; Push Task''s R1-R3 to SVC stack
STMFD   SP!, {R0}       ; Push Task''s R0 to SVC stack

STMFD   SP!, {R3}     ; Push task''s CPSR

LDR     R0,=OSIntNesting        ;OSIntNesting++,将中断嵌套层数加1
LDRB    R1,[R0]
ADD     R1,R1,#1
STRB    R1,[R0] 
//下面几句此处为2.5以上实现中断嵌套 与编译器无关的精彩改进之处。可以中断嵌套后无需调整堆栈指针SP

;其原理就是在最外层中断时,把SP保存到任务控制块的堆栈中:OSTCBCur->OSTCBStkPtr=SP,把SP所指堆栈赋给OSTCBStkPtr即OSTCBCur->OSTCBStkPtr指向的刚发生中断时的堆栈,以后不管是否发生中断嵌套,使得SP发 生变化。都只需要任务恢复时从此恢复任务的SP,使用有用的堆栈,而不用去理后面中断嵌套发生的堆栈变化(对任务来说无用)

CMP     R1,#1              ;{if(OSIntNesting==1){; 则将被中断任务的堆栈指针保存在被中断任务的任务任务控制块中 
BNE     %F1

LDR     R4,=OSTCBCur            ;OSTCBCur->OSTCBStkPtr=SP;以免中断退出调用高优先级任务后破坏堆栈指针,

                                                   ;避免调整堆栈指针的麻烦
LDR     R5,[R4]
STR     SP,[R5]                 ;}

1
MSR    CPSR_c,#IRQMODE|NOINT    ;Change to IRQ mode to use IRQ stack to handle interrupt
LDR     R0, =INTOFFSET          ;根据中断偏移寄存器中的值为查到中断源号,再跳转到相应的中断服务中程序中去;

   LDR     R0, [R0]     
   LDR     R1, IRQIsrVect
    MOV     LR, PC                                 ; Save LR befor jump to the C function we need return back
    LDR     PC, [R1, R0, LSL #2]            ; Call OS_CPU_IRQ_ISR_handler();   
    
    MSR   CPSR_c,#SVCMODE|NOINT   ;Change to SVC mode
    BL    OSIntExit                                   ;Call OSIntExit
    
    LDMFD   SP!,{R4}                          ;POP the task''s CPSR 
    MSR   SPSR_cxsf,R4
    LDMFD   SP!,{R0-R12,LR,PC}^      ;POP new Task''s context

IRQIsrVect DCD HandleEINT0

;*********************************************************************************************************

;采用第三种方法处理开关中断
OSCPUSaveSR
MRS     R0, CPSR     ; Set IRQ and FIQ bits in CPSR to disable all interrupts
ORR     R1, R0, #0xC0
MSR     CPSR_c, R1
MRS     R1, CPSR     ; Confirm that CPSR contains the proper interrupt disable flags
AND     R1, R1, #0xC0
CMP     R1, #0xC0
BNE     OSCPUSaveSR     ; Not properly disabled (try again)
MOV     PC, LR      ; Disabled, return the original CPSR contents in R0

OSCPURestoreSR
MSR     CPSR_c, R0
MOV     PC, LR
         
END

上述为编写与处理器有关的三个文件,要使OCOS在板上运行起来,还得做一些板子初始化方面的工作。如2410的启动加载文件就是必需的,还有 MMU初始等....后继续





『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
stm32 总线矩阵介绍