反反复复弄了一个多星期,参考了不少资料,终于让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初始等....后继续
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』