uCOSII移植到友善之臂mini2440

uCOSII 移植到友善之臂mini2440

1. 准备源代码

在官网或者其他地方找到源代码,也可以在我的下载资源里下到http://download.csdn.net/detail/YAOZHENGUO2006/3589107          

我所用版本为以前下载的版本号V2.51。源码有16个文件,其中体系结构无关的   

OS_CORE.C       OS_MBOX.C      OS_FLAG..C

OS_SEM.C        OS_Q.C           OS_MUTEX.C
OS_TASK.C       OS_TIME.C        OS_MEM.C
uCOS_II.C (没用到)       OS_CONFIG.H      uCOS_II.H
INCLUDE.H
与体系结构相关的文件有三个
OS_CPU.H       OS_CPU_A.S    OS_CPU_C.C
二.选取开发环境ADS 1.2。(编译器的选择要考虑是否可以生成可重入性代码)
三.修改和体系结构有关的文件。主要有OS_CPU.H OS_CPU_A.S OS_CPU_C.C
1.修改OS_CPU.H OS_CPU.H
主要是定义了一些和具体CPU相关的常量,预编译器相关的数据类型。其中需要修改的有:
OS_CRITICAL_METHOD=3 
这是关中断的方式,在这里选择OS_ENTER_CRITICAL(),而OS_ENTER_CRITICAL()  等价于(cpu_sr = OSCPUSaveSR()),这个函数在OS_CPU_A.S中,需要自己写。
#define  OS_STK_GROWTH        1
这是栈生长方向,ADS1.2开发环境arm920t的堆栈生长方向为递减的也就是说从高地址向低地址方向生长,而且是满栈型的,就是栈指针指向有效的数据。
2.修改OS_CPU_C.C
OS_CPU_C.C主要定义了OSTaskStkInit()这个函数和其他一些hook扩展函数。Hook扩展函数不用修改,保持空。OSTaskStkInit()是堆栈初始化函数,用在建立任务的函数OSTaskCreate()中,初始化任务的栈,在arm920t中需要在栈中保存的寄存器和数据为

$task;        
LR (R14)            
R12                                                     
R11                                                   
R10                                                      
R9                                              
R8                                                       
R7                                                   
R6                                                       
R5                                                     
R4                                                       
R3                                                       
R2                                                       
R1                                                       
R0 :         (argument)
CPSR      (最后栈指针指到这里,这是栈的顶部,也就是最小的地址)
所以堆栈初始化代码为下,可以看出任务堆栈不能小于16*4 byte,否则栈会溢出。

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

    opt    = opt;                   /* 'opt' is not used, prevent warning */
    stk    = (INT32U *)ptos;        /* Load stack pointer */
    *(stk)   = (OS_STK)task;        /* Entry Point            */
    *(--stk) = (INT32U)0;         	/* LR (R14)           */
    *(--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)pdata;	        /* R0 : argument      */
    *(--stk) = (INT32U)0x00000013L;     /* CPSR               */
    return ((OS_STK *)stk);
}

3.修改OS_CPU_A.S

OS_CPU_A.S 主要是操作CPU寄存器的汇编代码,需要针对编译器重写。主要有如下函数

OSCtxSw()            普通任务切换函数

OSIntCtxSw()          中断返回时任务切换函数
OSStartHighRdy()      OSStart()函数中启动第一个高优先级任务
OS_CPU_IRQ_ISR()    中断处理程序
OSTickISR()           定时器节拍中断服务程序
OSCPUSaveSR()       关中断函数
OSCPURestoreSR()     开中断函数
(1)OSStartHighRdy() 
设置cpu为SVC模式,禁止中断
执行OSTaskSwHook
OSRunning =TRUE
SP = OSTCBHighRdy->OSTCBStkPtr
出栈恢复CPU模式(其实还是SVC)
全部出栈,从栈顶到栈低分别将数据保存到 R0-R12, LR, PC
然后程序跳转到PC指的地址执行
(2)OSCtxSw() :
(首先清楚,在任务代码中C语言可能用了SP使得SP在任务切换的时候 不指向当前任务栈的栈低,因为是任务调用的OSCtxSw,所以程序返回地址保存在LR中,也就是下次切回来时要返回的地址)
将 PC LR R12-R0 CPSR 压入任务栈
OSTCBCur->OSTCBStkPtr = SP (以前认为这个是不需要的,因为OSTCBCur->OSTCBStkPtr就没有变过,但是SP在任务执行过后可能不指向栈低了,也就是说原来分配的栈发生了内部偏移,必须再次定位一下栈顶)
执行OSTaskSwHook
改变OSTCBCur  OSTCBCur = OSTCBHighRdy
改变OSPrioCur   OSPrioCur = OSPrioHighRdy
使SP指向新的任务栈 SP=OSTCBHighRdy->OSTCBStkPtr
(注意 只要获得了指向TCB的指针就会找到任务栈,因为任务栈的指针保存在TCB的第一个元素中)
LDR R0, =OSTCBHighRdy
OSTCBHighRdy是一个指针变量,这个只是取得OSTCBHighRdy的地址保存在R0中
LDR R0, [R0]
取得TCB的地址
LDR SP, [R0]
取得TCB的第一个元素,也就是任务栈的指针
全部出栈,从栈顶到栈低分别将数据保存到 R0-R12, LR, PC
然后程序跳转到PC指的地址执行
(3)OSIntCtxSw() 
这个函数主要是中断处理程序中,中断返回所调用OSIntExit()中的任务切换函数。因为中断处理函数中已经保存了现场,所以这里就没有必要在做无用功了。只需要将SP指向下一个需要运行的任务的任务栈,恢复现场就可以了。
执行OSTaskSwHook
改变OSTCBCur  OSTCBCur = OSTCBHighRdy
改变OSPrioCur   OSPrioCur = OSPrioHighRdy
使SP指向新的任务栈 SP=OSTCBHighRdy->OSTCBStkPtr
全部出栈,从栈顶到栈低分别将数据保存到 R0-R12, LR, PC
然后程序跳转到PC指的地址执行
(4)OSCPUSaveSR():
保存CPSR到形参中(ATPCS标准规定,形参保存在R0中)
设置CPSR相应的位 关中断
(5)OSCPURestoreSR ()
从R0中提取CPSR 的值,恢复以前中断的状态
(6)OSTickISR()
是时钟节拍中断服务函数,主要是清中断标志位,主要有两个寄存器SRCPND,INTPND。跳转到OSTimeTick()执行。
(7)OS_CPU_IRQ_ISR()
这个函数主要是中断处理函数,所有的IRQ 中断都需要这个函数处理。首先要理解ARM920T中断过程。大体中断过程主要分为以下几步:
ⅰ 外部器件中断线产生中断信号,传给中断控制器。中断控制器识别是那种类型的中断,给CPU IRQ或FIQ中断线信号,同时INTOFFSET 产生中断偏移量。
ⅱ CPU接收到中断信号后,首先自动保存PC到LR,将CPSR保存到相应模式下的SPSR,设置CPSR为相应的模式,程序跳转到逻辑地址0X00处的异常向量。(因为程序是在0X30000000处运行的,当中断发生时,并不能在0X00处找到中断向量,所以需要MMU的帮助,将0X30000000映射到0X00。这样才可以保证中断的正常响应)。
ⅲ 在中断向量处,我们保存了HandlerIRQ的地址,所以程序到HandlerIRQ处执行。
ⅳ 在HandlerIRQ处,使用了宏展开,目的是是程序跳转到HandleIRQ 标号处执行
ⅴ HandleIRQ 这里是个内存缓冲池,存放着我们的中断处理程序的地址,这里是OS_CPU_IRQ_ISR,就是我们要写的中断处理程序。
ⅵ 以上实现在2440init.s中,接下来OS_CPU_IRQ_ISR这个函数就是我们要写的。注意现在已经在IRQ模式,SP物理地址已经是IRQ模式的了(这个在2440init.s中初始化过了)。
这里有三次模式切换。
第1次, 由IRQ MODE 到SVC MODE 目的是保存中断现场,如果是首层中断,那么保存了任务的返回地址,以及SVC模式下中断时个寄存器的状态。如果不是首层中断那么保存了中断服务程序中的返回地址,以及IRQ模式下的各寄存器的状态。然后将OSIntNesting加1,判断是否为1,如果是1那么说明是首层中断,与特定的任务相关,OSTCBCur->OSTCBStkPtr=SP,如果不保存SP,那么在中断返回时如果被抢占,那么就切不回来了。注意不管是首层中断还是多层中断,中断现场都保存在当前任务栈中,所以如果允许中断嵌套那么保证任务栈足够大。
第2次, 由SVC MODE 到 IRQ MODE 目的是装载中断服务程序入口地址,执行中断服务程序。
第3次, 由IRQ MODE 到 SVC MODE 目的是执行OSIntExit,判断是否首层中断返回和是否需要任务切换。中断返回,有可能是返回上一层中断有可能是返回任务。
(注意:中断服务执行的时候中断是禁止的,所以如果想中断嵌套那么重新打开中断即可)
四 修改配置文件
    主要是修改OS_CFG.H,这个文件主要是配置和裁剪系统提供的功能,根据系统RAM的大小和项目的要求进行适当的裁剪,保证系统能够高效正常的运行。这里可不用修改,因为mini2440足够承受所有的功能。
五 建立ADS工程文件,编译调试
根据需要建立相应的 Group:uCOS_II (内核) BdInit (板级初始化) OsDir (驱动) API 然后加入相应的文件,编译,下载。测试。编译主要是排错,遇到很多问题,需要仔细分析,不要一味的钻死牛角尖。比如出现这样的错误

在uCOS_II.H 中加入

#ifndef   UCOS_II_H
#define   UCOS_II_H
     ......
#endif
就会消除,有时候的错误是我们用编译器还不熟悉,所以感觉无从下手。要仔细分析。还有你的文件名字是大写的但是加入到ADS后编译就会变成小写的了,还有头文件包含不区分大小写。

移植后的代码下载http://download.csdn.net/detail/YAOZHENGUO2006/3329174

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值