在LPC2468上移植vxWorks系统
林先贤
{辽宁,沈阳,110000}
[摘要] NXP的LPC2468是具有丰富资源的ARM7TDIMI系列CPU,使用片内资源就满足移植vxWorks的条件,文章列举了在LPC2468上移植vxWorks嵌入式操作系统的特殊之处及其解决方法,最后经验总结了移植vxWorks的一般步骤和调试方法。
[关键词] LPC2468,移植,vxWorks
Transplanting vxWorks system into the LPC2468
[Abstract] NXP's LPC2468 is a rich resource ARM7TDIMI ries CPU, the u of on-chip resources will meet the conditions for transplanting vxWorks。 This article lists the special features of the LPC2468 for transplanting vxWorks and according solutions,finally summarize the general steps and debugging methods in transplanting vxWorks.
[Keywords] LPC2468,Transplanting,vxWorks
NXP半导体设计的LPC2468微控制器是基于16/32位的ARM7TDMI-S CPU内核。LPC2468具有512kB片内高速Flash存储器,该Flash存储器具有特殊的128位宽度的存储器接口以及加速器架构,可以使CPU以高达72MHz的系统时钟速度来按顺序执行Flash存储器的指令。片内98kB RAM(包括64kB局部SRAM、16kB以太网SRAM、16kB通用DMA SRAM和2kB电池供电SRAM),4个UART,4个定时器,仅利用这些片内资源就可以移植vxWorks系统。内部可用的SRAM不是很大,如果需要更大的内存空间,LPC2468的外部存储器控制器可以支持外扩的SDRAM或SRAM。自带的ISP功能通过交叉串口线就可以进行Flash编程。以下针对512KB抉择作文的片内Flash和64K的SRAM存储器资源移植过程进行描述。
移植的开始是寻找一个尽量接近目标板的BSP,LPC2468的BSP官方网站没有提供,这里是利用Tornado for ARM自带的wrSbcArm7目录代码进行修改。
首先说明一下,为了节省内存使用,同时也是充分利用内部高速Flash存储器,将vxWorks编译成Text段驻留Flash的,目标文件是vxWork_romResident.bin,bootRom的目标文件是bootrom_res.bin,这个只是编译选项,具体代码并不需要做任何改动。
将wrSbcArm7复制成LPC2468目录,删除不用的文件,仅留下sngks32cIntrCtl.c,sngks32cSio.c,sngks32cTimer.c,sysLib.c,sysSerial.c,romInit.s,sysALib.s面粉怎么做饼源文件及其依赖的头文件。Config.h文件需要对各功能宏定义做修改,比如#undef INCLUDE_NETWORK,#undefi INCLUDE_FLASH等。Makefile文件中的MACH_EXTRA去除sngks32cEnd.o模块。否则无法通过编译。
添加LPC2468.h替代sngks32c.h,该文件应包括所有用到的片内设备的接口定义。另外添加一个usrfunc.c文件,包括启动底层设备初始化的代码,比如晶振,中断向量映射,外设功率设置,管脚功能配置等。同时Makefile中的MACH_EXTRA添加usrfunc.o模块。
文件组成结构到这里就完成了,接下来是对具体内容的修改调试。
在config.h和Makefile文件中,修改RAM,ROM相应的配置,需要注意RAM的低64Bytes保留为异常向量,高32Bytes保留为IAP程序。SRAM的基址为0x4000 0000,相关设置如下:
#define ROM_BASE_ADRS 0x00000000 /* ba of Flash */
#define ROM_TEXT_ADRS 0x00000000 /* code start addr in ROM */
#define ROM_SIZE 0x0007E000 /* 504K,8K供固化的Boot Block使用 */
#define RAM_LOW_ADRS 0x40001000 /* vxWorks_romResident的data段基址亡字组词 */
#define RAM_HIGH_ADRS 0x40002000 /* bootrom_res的data段基址 */
将中断模式设置为非抢占的,因而可以减小ISR栈大小。定义如下:
#define INT_MODE INT_NON_PREEMPT_MODEL
#define ISR_STACK_SIZE 1024
romInit.s作为入口汇编程序,LPC2468不能对整个内存重映射,需要考虑各异常向量的处理。采用如下语句:
LDR PC, RetAddr
LDR PC, UndefinedAddr
LDR PC, SWI_Addr
LDR PC, PrefetchAddr
LDR PC, DataAbortAddr
.long 0xb8a06f60 /*满足前8条指令的累加和为0的Flash启动条件*/
LDR PC, IRQ_Addr
LDR PC, FIQ_Addr
RetAddr:
.long cold
UndefinedAddr:
.long excEnterUndef
SWI_Addr:
.long excEnterSwi
PrefetchAddr:
.long excEnterPrefetchAbort
DataAbortAddr:
.long excEnterDataAbort
IRQ_Addr:
.long intEnt
FIQ_Addr:
.long FIQ_Handler
其中excEnterUndef,excEnterSwi,excEnterPrefetchAbort,excEnterDataAbort,intEnt都是vxWorks提供的5个异常入口,而vxWorks系统不支持FIQ。这样就实现异常向量与vx
Works系统异常处理的关联。
初始化底层设备的代码也可以在汇编里实现,不过还是建议在c代码中实现,便于编程。在usrfunc.c文件编写的初始化函数作文摘抄lpc2468Init( ),在汇编跳转到c入口程序romStart( )前先调用。代码如下:
stmdb sp!, {r0} /* r0入栈 */
BL FUNC(lpc2468Init) /* 带连接的跳转到底层设备初始化c代码 */
ldmia sp!, {r0} /* 恢复r0 */
LDR pc, L$_rStrtInRom /* 跳转到romStart( ) */
对r0操作说明一下,r0是保存冷启动或热启动的信息,作为romStart( )函数的传参,原有的代码是将r0保存到r13,跳转romStart( )前从r13恢复到r0,不过由于r13作为栈指针,在调用lpc2468Init前被初始化,调用之后r0的值已遭破坏,因此这里采用出入栈的办法保存r0的值。与LPC2468初始化无关的汇编代码都删除,这样就完成了汇编到c的入口。这里有
一个方法确定汇编到c入口的正确跳转,用Tornado自带的查看编译后的汇编信息,格式如下
objdumparm –D [目标elf文件] > [输出文件]
通过输出文件查看,romStart的地址是否就是LDR pc, L$_rStrtInRom语句装载的地址。
修改串口,中断,时钟程序,将一个个函数与硬件相关程序的“翻译”成LPC2468相应的操作,这个过程最重要的是查阅CPU手册,了解各控制单元的编程接口。
接下来可以先调通电路板上LED的亮灭程序,通过LED指示状态可以确定代码按正确分支运行或定位代码问题所在。移植过程中就是通过LED状态发现执行excVecInit( )异常向量初始化时死机。由于excVecInit是鸟的天堂作者是谁vxWorks内部的一个函数,没有源代码,只能使用前面提到的objdumparm输出汇编信息查看,发现excVecInit调用了armInitExceptionModes( )函数,并且将异常向量与excEnterUndef,excEnterSwi,excEnterPrefetchAbort,excEnterDataAbort,intEnt入口挂接。这些异常向量挂接操作修改基址为0的内存数据,适用于孔乙己读后感RAM位于0地址开始的情况;对于LPC2468玫瑰的意思来说就是对Flash写操作,情况不可预料。从c代码上这一语句
intVecBaSet ((FUNCPTR *) VEC_BASE_ADRS); /* t vector ba table */
应该是设置异常向量的基地址,但是对于ARM CPU来说,通过反汇编跟踪,该函数是直接返回的空函数。excVecInit函数也不会调用intVecBaGet来获得基址。vxWorks系统为了尽量保持不同体系CPU的源码一致性而保留了这些统一命名的函数框架,因此有些函数只是以空壳存在的无实际意义的操作,可以将intVecBaSet语句直接删除。
那么如何解决这一异常向量挂接问题呢?好在romInit.s汇编入口已经完成了这些异常向量跳转功能,因此可以直接去除这里的操作。armInitExceptionModes函数进一步跟踪查看发现是对ARM不同状态下栈指针初始化,需要保留此代码。可以直接将excVecInit语句改成armInitExceptionModes,但是在利用Tornado工程编译环境重编译时会自动重新生成代码,覆盖用户的手动修改。需要保证不手动修改编译环境自动产生的文件,利用config.h(自动产生的文件包含config.h存在汪峰文件)的宏定义是比较好的解决方法。