vxworks BSP移植(基于lpc2210)

来源:互联网 发布:linux中的touch命令 编辑:程序博客网 时间:2024/04/20 02:43
大家好,本人自学习vxworks以来,在网络上得到了许多热心网友的帮助,终于现在参照S3C44B0BSP自己也移植出了一些东西。人人为我,我为人人,所以现在也将自己在SmartArm2200下面的移植过程写出来。我的邮箱是walkingman321@163.com,希望对此感兴趣的朋友能和我互相交流,共同进步。

一、开发环境的建立
我使用的开发环境是Tornado2.2 + H-JTAG + ADS1.2。平时比较忙,没太多时间开发,所以我只能跳过bootrom的开发,直接编写了一个rom_resdient的镜像,实现的功能主要是时钟中断和串口驱动。

Vxworks的移植本身不难,其实最难的就是刚开始上手时调试环境的建立,还好在这方面网上已经有前辈把方法贴出来了。我的具体设置方法是这样的:
首先,要在BSPmakefile里面将tool=diab改为tool=gnuDiabgnu是两种不同的编译工具,前者编译效率更高,后者则是更加通用。我试了一下,好像两种工具都能在axd下调试,但使用diab编译出来的elf文件非常不稳定,用axd每三次差不多只能有一次在axd下显示出源代码;gnu则几乎是百分之百成功。
改完makefile之后,因为我是编译rom_res镜像,所以要在$(TGT_DIR)/h/make/rules.bsp下将编译目标改一下,改成

exe
: vxWorks.res_rom

最后,还需要在$(TGT_DIR)/h/tool/gnu/defs.arm文件中,添加-gdwarf规则,这样axd才能解析出elf文件中的符号。
CC_OPTIM_DRIVER
= -gdwarf -fno-builtin -fvolatile

CC_OPTIM_NORMAL
= -gdwarf -fno-builtin

CC_OPTIM_TARGET
= -gdwarf -fno-builtin –fvolatile

作了以上改动之后,axd差不多就能用了,但实际调试过程中,发现运行的时候起始pc指针不对。不知道别人是怎么解决这个问题的,我的方面比较笨,就是先在ads环境中自己另外新建一个工程,编译出一个很小的可执行文件,这个可执行文件的起始pc地址是很容易设置的。然后要调试vxworks时,先加载这个小文件,加载完成后PC指针就定位在0x80000000了(lpc2210的起始地址是0x80000000,与其它arm片子有点区别)。然后再选择load image加载vxworks,把一开始的小程序覆盖掉。这样vxworks启动时指针还是定位在原来的0x80000000上面。
此外,如果c文件是被include进去的,比如在syslib.c中有#include “sysserial.c”,那么sysserial.c文件中的函数就无法调试了,axd走到这里指针会乱。解决的方法就是修改makefile,使sysserial.c单独编译,然后将#include “sysserial.c”替换成#include “sysserial.h”

另外还有一点,就是直接在flash上烧写image效率太慢,而且无法添加软件断点。还好使用的开发板能够跳线选择从ram还是rom启动。SmartArm自带的外部ram16M,我把其中最前面的2M当作flash使用,然后再在后面分出2M作为实际的ram。运行vxworks,如果不跑大程序的话2M ram已经是绰绰有余了,所以我在开发过程中就只使用了4M空间(2M ROM + 2M RAM)。内存空间设小一些会大大提高开发效率,因为vxworks启动时会对空闲内存空间进行清0操作,如果CPU频率慢的话一下子清零16M内存浪费的时间还是蛮可观的。

二、系统启动
下面严归正传,正式进入到vxworks的移植。Vxworks上电后执行的第一个文件是在rominit.s中,函数名romInit。这个函数里主要是做一些上电的基本配置,设置栈指针,然后就跳转到romStart函数中。在这里的栈指针设置在0x802040000x80200000~~0x80204000之间的地址是特意空出来的,数据段被放在0x80204000之后。关于这个栈指针,我到现在还是有点疑惑的地方,因为我参考的bsp中是这么定义的:
#define
RESIDENT_DATA
_sdata

但实际中发现_sdata被定位在0x80204004的位置,这样会把0x80204000处的.long
FUNC(copyright_wind_river)
覆盖掉。所以最后我只能将它修改成这样:

#define
RESIDENT_DATA
wrs_kernel_data_start


运行完romInit之后,系统就进入到romStart。因为是rom_res镜像,所以这里做的主要工作是拷贝rom中的数据段到ram中(这里因为是用ram模拟rom,所以实际上就是将0x80000000DATAOFFSET处的数据复制到0x80204000处,详见config.hmakefile文件),还有清零bss和未用ram空间等。然后就进入usrInit函数。

至此,系统的初始启动差不多结束。usrInit函数中就要开始进行硬件初始化和中断向量设置了。

三、中断设置
首先要区分一下异常向量和中断向量的概念,这两个是完全不同的东西。异常向量是arm体系结构决定的,包括resetundefinedAddrSWIprefetchDataAbortIRQFIQIRQ则是由具体的arm芯片决定。中断发生时,CPU首先跳转到IRQ异常向量,这由vxworks提供,然后在异常向量的执行中,再根据中断源判断是哪个中断向量,并跳转到该中断向量对应的中断服务程序,这个中断服务程序就是我们使用intConnect函数设置的中断入口。

网上关于异常向量设置的文章有很多,主要思想都是如何将系统异常向量搬移到合适的位置,然后在中断发生时设置跳转程序跳到自己设置的异常向量表里面。之所以这么做,估计是因为大家都使用了bootrom的原因吧,arm启动处的异常向量表被bootrom占据了,不得不跳转。还好我使用的是rom_res,所以直接将异常向量表设在romInit函数的起始处就可以了:
_romInit:

LDR
PC, ResetAddr


LDR
PC, UndefinedAddr


LDR
PC, SWI_Addr



LDR
PC, PrefetchAddr


LDR
PC, DataAbortAddr


.long
0x00000000


LDR
PC, IRQ_Addr


LDR
PC, FIQ_Addr


ResetAddr:


.long
cold

UndefinedAddr:


.long
excEnterUndef

SWI_Addr:


.long
excEnterSwi

PrefetchAddr:

.long
excEnterPrefetchAbort

DataAbortAddr:
.long
excEnterDataAbort

IRQ_Addr:

.long
intEnt

FIQ_Addr:
.long
FIQ_Handler

Vxworks已经给我们提供了现成的异常向量入口函数,包括excEnterUndefexcEnterSwiexcEnterPrefetchAbortexcEnterDataAbortintEnt,直接声明然后使用就可以。FIQ vxworks没有使用,需要自己定义。在这里我们就能看出,中断发生时是跳转到intEnt函数里面。

那么,intEnt的作用是什么呢?就是判断中断源并跳转到中断向量表了。在这之前,我们还得先对中断向量表进行初始化。这里是调用lpc2210ExcVecInit函数,在sysALib.s里面。
_ARM_FUNCTION(lpc2210ExcVecInit)

stmfd sp!, {r0-r10,lr}


bl FUNC(armInitExceptionModes)



ldr r0, L$__func_armIrqHandler


ldr r1, L$_excIntHandle


str r1, [r0]



nop

ldmfd sp!, {r0-r10,pc}
armInitExceptionModes_excIntHandle都是vxworks自带的,这个函数的具体原理大家可以参照s3c44b0和网络上的其它文章,写得还是比较详细的,这里就不多说了。
另外为了使用中断,还需要在sysHwInit2中调用intLibInit和中断控制器驱动的初始化函数。intLibInit的作用是分配中断向量表的空间然后进行初始化,我们调用intConnect登记中断入口函数就是登记到这块中断向量表里面。关于中断控制器的驱动,大家可以看看网络上各种bsp移植的源代码,还是很容易理解的,主要就是登记一些回调函数入口,把这些函数入口赋给vxwroks提供的全局变量即可。这些全局变量总共有4个,分别是
sysIntLvlVecChkRtn
sysIntLvlEnableRtnsIntLvlDisableRtnsysIntLvlVecAckRtnEnableDisable是打开和关闭特定中断的函数。IntLvlChk比较重要,会在每次中断时由intEnt调用,用来判断当前是那个中断源产生了中断,它会返回一个中断向量,然后intEnt才能根据这个中断向量跳转到中断向量表中的函数入口。Ack是在每次中断结束后调用,因为我使用非抢占的中断模式,所以调用这个函数之后才能响应新的中断。


四、时钟中断,串口和其它
一旦中断的框架搭好,下面就非常简单了。时钟中断是系统的心跳,实际中应该是每秒至少20次以上,但这里我简单的把它设成每秒一次(直接从周立功的代码中复制的,懒得改了)。时钟中断中主要要调用一个tickAnnounce函数,这个函数由vxworks提供,它会完成系统心跳中必须的操作。
串口驱动则更简单了,网上资料有很多,另外还有一本讲BSP的书里面讲的也很详细,这里就不多说了。

五、结语
写到这里,似乎就没什么可以总结得了。网上关于移植的资料有很多,作为补充,我写的似乎已经足够了。最近上班比较忙,所以没有加上网络、图形等复杂模块,甚至连WDB都没有加。等有了时间一定会全部补上。整个移植过程中,个人感觉一开始的建立环境最难,所以这部分我写得最详细。推荐大家在移植之前先看看tornado自带的makefile的文档和链接脚本的语法,掌握一些比如VMALMA的概念,这对移植的帮助是非常大的。

BSP的源码地址:http://download.csdn.net/source/319315
 
原创粉丝点击