VxWorks在EasyARM2200和SmartARM2200上的移植zz

发信人: gdtyy (gdtyy), 信区: Embedded
标  题: VxWorks在EasyARM2200和SmartARM2200上的移植
发信站: 水木社区 (Mon Jun 25 23:24:21 2007), 站内

**********************************************
* VxWorks在EasyARM2200和SmartARM2200上的移植 *
**********************************************
                          ------ 浅谈《ecos增值包》辅助开发VxWorks BSP
    2007/04/07  [email protected]  www.armecos.com

    随着《ecos增值包》用户群的增大,我们决定进一步增加对《ecos增值包》使用者的支
持力度,如果能自行解决版权问题,那么希望下面的文章能对用户您开发VxWorks BSP有帮
助。

    目前,EasyARM2200和SmartARM2200开发板已经(增值)支持uCos、uCLinux、ecos、
uITRON(ecos兼容层)、VxWorks等操作系统(Linux和WinCE需要带MMU的芯片);三款TCP/IP完
整协议栈(openBSD、FreeBSD、lwip)、若干BootLoader(redboot、u-boot、bootrom、vivi
、blob等)。有些用户用它快速开发交互式web server,有些用来作为辅助开发工具、有些
用做快速原型验证......其实,《ecos增值包》是一个开发平台,它不仅限于ARM7,也适用
于ARM15、ARM16等未来芯片,因为ecos支持对PowerPC、MIPS、X86、SH等不同体系架构的抽
象,所以,您针对ecos平台开发的软件将很少/不用改动就可以平滑移植到新的体系架构上
,保护您的投资利益。ecos平台的抽象机制(HAL层、设备文件、C++等)确保您将注意力集中
在事物的核心本质上,而不必被细节干扰。例如:您可以针对ecos抽象出的万能中断模型编
程,而不必关心具体CPU的中断体系;只对串口设备文件操作而不管UART寄存器的细节等。
即使您没有很丰富的经验,也能轻松做项目,因为ecos平台将辅助您解决稳定性、效率、功
耗、成本等棘手问题。ecos提供了FS、GUI、TCP/IP等全套功能部件,完全满足您对数据存
储、显示、网络互联、控制等方面的需求,是完整的一揽子解决方案。

    从ecos的观点看VxWorks BSP的开发,主要是平台和变种抽象层的移植,即我们要针对
ARM7变种LPC2210和其承载平台EasyARM2200、SmartARM2200进行移植。ecos和VxWorks简直
太象了(仅函数名不同):都使用组件概念(不知是谁抄谁的),都用GNU编译器编译(或diab)
,都实现差不多的功能。这为使用《ecos增值包》开发VxWorks BSP提供了便利。

    -----------------------
    | VxWorks BSP移植规划 |
    -----------------------
    1、实现硬件初始化
    2、实现LPC2210中断体系到VxWorks中断体系的映射
    3、实现心跳时钟、辅助时钟、时标
    4、实现基于查询/中断的串口驱动
    ------------------------------------------------MileStone
    5、实现NOR/NAND Flash驱动
    6、实现多种字符设备、块设备、MUX网络设备驱动程序
    7、实现TSFS/dosFS/TrueFFS文件系统、MiniGUI等
    ......

    ------------
    | 移植难点 |
    ------------
    1、工具使用:Makefile编写、反汇编、调试器使用、Tornado使用等
    2、对LPC2210工作原理、硬件体系的理解
    3、对BSP目录结构、工作流程、内存分布、ROM映像类型的理解等
    4、正确的调试分析方法、完备的调试环境、有效的技术支持

    ---------------------------------------
    | 《ecos增值包》针对BSP开发的解决方案 |
    ---------------------------------------
    《ecos增值包》本身就提供GNU开发环境,提供step by step的指导,省去了自己搭建
环境的苦恼,可以快速上手。文档中有专门章节讲解Makefile使用,中断体系、串口原理等
等,这对于攻克难点有莫大的帮助。进行嵌入式开发不能光看书,任何书本都不能面面俱到
,而且写出的书,信息量至少损失20%,理解起来又会损失20%,真正做还要再损失至少20%
,所以,比较好的方法是靠“熏”。不断在一个已经搭建好的稳定平台上反复做实验,举一
反三,天长日久,就会不知不觉熏陶出来。很多用户不懂得调试,遇到问题就问别人,其实
首先应该问计算机,掌握调试方法就相当于掌握了打渔的方法,学会了点金术,发现问题,
debug it,trace it,解决问题,It's hacker's solution。

    -----------------------
    | VxWorks BSP目录结构 |
    -----------------------
    BSP(板级支持包)就是指VxWorks的驱动程序。当然,其他一些操作系统也有自己的BSP
驱动,还有些系统的驱动程序不叫BSP,总之,这里的BSP就是指驱动程序啦。
    安装VxWorks和其BSP开发环境后,会出现c:/Tornado2.2目录,在target子目录下的内
容就是BSP的相关内容。

                      ------config     BSP配置文件
                      |        |
                      |        |-----all     通用配置文件
                      |        |_____BspName 板级支持包
                      |
              target  |---H         头文件
                      |---Lib       库文件
                      |---Man       说明文件
                      |---Src       VxWorks特殊的源代码
                      |___Unsupport 工具及驱动

    我们实际关心的只有target/config/all和target/config/BspName两个目录。
target/config/BspName里面是我们要移植的真正的BSP程序。

    -------------------
    | VxWorks工作流程 |
    -------------------
    VxWorks分为bootrom和内核映像两部分,分别由不同文件完成功能。

    -------------------------------------------
    bootrom执行流程:
    -------------------------------------------

               romInit
    (target/config/zlgarm/romInit.s)
                 |
              romStart
     (target/config/all/bootInit.c)
                 |
              usrInit
    (target/config/all/bootConfig.c)
                 |
            bootCmdLoop
                 |
         -----------------
         |               |
     autoBoot            |_bootLoad
         |_bootLoad      |_go
         |_go

    -------------------------------------------
    VxWorks内核映像启动流程图:
    -------------------------------------------
              sysInit
    (target/config/zlgarm/sysALib.s)      硬件相关
                 |                   ----------------
              usrInit                     通用启动过程
    (target/config/zlgarm/sysALib.s)
                 |
         -----------------
         |       |       |
  usrKernelInit  |      sysHwInit
                 |      (target/config/zlgarm/sysLib.c)
             kernelInit
                 |
      Hooks-->usrRoot
                 |
                 |--------
                         |
                    sysClkConnect
                         |
                         |---------
                                  |
                              sysHwInit2

    bootrom首先执行硬件初始化romInit,它是用汇编写的,主要考虑到有些操作不能用C
语言完成,例如开关中断,特权堆栈初始化等。然后使用C语言写的程序romStart拷贝搬移
ROM映像,清RAM,解压代码(如果需要的话),这部分用C的好处是编程方便。usrInit是用来
执行最小内核初始化的,然后进入命令循环,分两种情况,如果7秒钟(可设置)内无按键就
自动执行预先烧好的程序,如果没有找到程序,就不断重复7秒等待过程。如果有按键按下
,就进入命令行界面接收用户命令。

    VxWorks内核被加载后首先执行硬件相关初始化,这部分初始化工作与bootrom中的相同
。为什么要重复执行相同的硬件初始化呢?主要是考虑到VxWorks可能被其他bootloader加
载,为了保证工作环境一致,所以这里再次重复相同的硬件初始化过程。接下来配置内核数
据、初始化内核、启动usrRoot任务、连接启动时钟心跳,OK,现在系统就活了。虽然
VxWorks一般不开源,但提供很多钩子(Hooks)函数,可以选择适当位置插入用户代码,完成
特殊需求。

    -------------------
    | VxWorks内存布局 |
    -------------------
    内存布局是VxWorks移植中需要非常准确理解的内容,它关系到config.h的配置和
Makefile的编写,如果处理不好或者概念搞错了,那就全乱了。

    --------------  0x00100000 = LOCAL_MEM_SIZE = sysMemTop()
    |            |
    |    RAM     |
    |  0 filled  |
    |            |
    |------------| = (romInit+ROM_COPY_SIZE) or binArrayStart
    | ROM image  |
    |----------- |  0x00090000  = RAM_HIGH_ADRS
    | STACK_SAVE |
    |------------|
    |            |  0x00080000  = 0.5 Megabytes
    |            |
    |            |
    | 0 filled   |
    |            |
    |            |  0x00001000  = RAM_ADRS & RAM_LOW_ADRS
    |            |
    |            |  exc vectors, bp anchor, exc msg, bootline
    |            |
    |            |
    --------------  0x00000000  = LOCAL_MEM_LOCAL_ADRS

    --------------
    |    ROM     |
    |            |  0xff8xxxxx  = binArrayStart
    |            |
    |            |  0xff800008  = ROM_TEXT_ADRS
    --------------  0xff800000  = ROM_BASE_ADRS

    上图是一个内存布局实例(1M字节RAM空间),地址值是自己编的,主要看宏定义。
    ROM_BASE_ADRS是指ROM的起始地址,例如:0x80000000。
    ROM_TEXT_ADRS是代码段的起始地址,有些CPU不能从0开始执行,所以需要一个偏移量
,不同CPU的要求不同,一般和ROM_BASE_ADRS值相同。

    LOCAL_MEM_LOCAL_ADRS是指可用RAM的起址,如:0x81000000。
    RAM_LOW_ADRS是内核在内存中的加载位置。
    RAM_HIGH_ADRS是需要拷贝到内存的ROM映像和堆栈的分界线,向下是堆栈,向上是ROM
映像的起址。
    未用的部分可以选择清零(用“0”填充)。
    大体上就是这么一个分布,但是限于篇幅,还有很多细节没有谈到。比如:堆栈保护、
解压缩代码空间、不同ROM映像类型的内存分布差异等。这些看代码可以详细了解,还是那
句话,亲自调试就能了解全部细节,写出来的内容总会有信息量的损失,从调试中你能得到
最准确全面的信息。

    ------------------------
    | VxWorks的ROM映像类型 |
    ------------------------
    VxWorks有三种ROM映像类型:
    1、ROM_RESIDENT-----驻留ROM型。在ROM中运行,只有数据段放在RAM里。
    2、ROM_COPY---------复制ROM型。把主要映像从ROM中拷贝到RAM里并跳到其RAM入口点
执行。
    3、ROM_COMPRESS-----解压ROM型。把主要映像从ROM中解压到RAM里并跳到其RAM入口点
执行。
    各种ROM映像类型的内存布局图如下:

         ROM
    --------------
    |            |
    |------------|
    |    data    |
    |------------|  0xff8xxxxx  = ROM_DATA_ADRS
    |    text    |
    |            |  0xff800008  = ROM_TEXT_ADRS
    --------------  0xff800000  = ROM_BASE_ADRS

        RAM
    --------------  0x00100000 = LOCAL_MEM_LOCAL_ADRS + LOCAL_MEM_SIZE
    |            |
    |            |
    |------------|        = RAM_DATA_ADRS + data segment size
    |            |
    |data segment|
    |            |
    |------------|  0x00001000  = RAM_DATA_ADRS
    | initial sp |
    |------------|        = RAM_DATA_ADRS - STACK_SAVE
    |            |
    |            |
    --------------  0x00000000  = LOCAL_MEM_LOCAL_ADRS

    上图是驻留ROM型映像的内存分布,可见,只有数据段拷贝到了RAM内存里,当然堆栈也
在RAM内存中。

        ROM
    --------------
    |            |
    |------------|  0xff8xxxxx    = binArrayEnd
    |  subImage  |
    |------------|  0xff8xxxxx    = binArrayStart
    |    data    |
    |------------|  0xff8xxxxx  = ROM_DATA_ADRS
    |    text    |
    |            |  0xff800008  = ROM_TEXT_ADRS
    --------------  0xff800000  = ROM_BASE_ADRS

        RAM
    --------------  0x00100000 = LOCAL_MEM_LOCAL_ADRS + LOCAL_MEM_SIZE
    |            |
    |            |
    |------------|
    | temp data  |
    |------------|  0x00090000  = RAM_DATA_ADRS
    | initial sp |
    |------------|              = RAM_DATA_ADRS - STACK_SAVE
    |            |
    |            |
    |------------|
    |            |
    |  subimage  |
    |            |
    |------------|  0x00001000  = RAM_DST_ADRS (for non-resident images)
    |            |
    |            |
    --------------  0x00000000  = LOCAL_MEM_LOCAL_ADRS

    上图是复制ROM型和解压ROM型映像的内存分布,他们比驻留ROM型稍微有点复杂。复制
ROM型和解压ROM型映像的主要差别的是subimage是否压缩,一般压缩率能超过55%,允许在
ROM中烧写更大的系统,唯一的代价是增加了几秒钟的启动延迟,而复制ROM型映像没有解压
过程,所以启动速度更快。subimage是由make产生的中间映像,并被make插在ROM映像文件
中。代码段、初始化数据段、subimage在ROM中的排列顺序就如上图所示。

    复制ROM型映像直接把binArrayStart处的subimage拷贝到RAM_DST_ADRS,没有上面的
temp data部分。

    对于解压ROM型映像,首先拷贝压缩的代码数据段到RAM_DATA_ADRS位置(即temp data部
分),然后运行解压缩例程把解压后的subimage放置在RAM_DST_ADRS。

    RAM_DST_ADRS和RAM_DATA_ADRS宏均来自定义于make的链接地址,缺省值分别为
Makefile文件中的RAM_LOW_ADRS和RAM_HIGH_ADRS。关于如何改变链接地址的信息,参见“
target/h/make/rules.bsp”文件。

    ---------------
    | BSP移植详述 |
    ---------------
    罗嗦了那么多,终于开始正式移植了。还是前面那句话,写出来的东西总是挂一漏万,
无论我怎么组织语言,总有说不完的话,数不清的注意事项,虽然心里很明白,但如果每一
点都指出来,那会让读者更晕,云里雾里的,没有实际做过,很难理解我说的细节,有些妙
处真的是只可意会不可言传,我也不知道怎么表达出来,并非留一手。我希望帮你“熏”一
下,能帮多少算多少,最重要的是你要亲自实践,光看游泳书是学不会游泳的。

    ==========
    硬件初始化
    ==========
    硬件初始化直接抄板子自带的汇编初始化源码,改进一下执行效率即可。

    ======
     中断
    ======
    中断需要提供:初始化、返回向量号、中断使能、中断禁止函数。
    中断初始化真是妙不可言,因为LPC2210提供VIC映射,所以一步就可以得到向量号,不
必查询,所以初始化做得好,中断响应效率可以很高。中断使能只要对
LPC2XXX_VIC_INT_ENABLE寄存器对应位置1即可;中断禁止时对
LPC2XXX_VIC_INT_ENABLE_CLR寄存器对应位置1。

    在调试BSP时,运行后总是没有动静,通过内存打印技术,发现程序死在了
excVecInit()函数处。见名知意,这个函数肯定和中断向量初始化有关,但它到底是如何工
作的呢?虽然有源码,但那个是for X86的,对于ARM体系相关的函数部分没有指导意义啊,
怎么办呢?此时,需要祭出战无不胜,攻无不克,见神杀神,见鬼杀鬼的利器---反汇编调
试。

    《ecos增值包》提供了GNU开发环境,使用“arm-elf-objdump -d
vxWorks_romResident > 1.txt”就可以得到VxWorks的汇编列表文件1.txt,里面有地址和
汇编信息,可用于和AXD汇编对照调试。

8101a644 <excVecInit>:
8101a644:    e92d4800     stmdb    sp!, {fp, lr}
8101a648:    e24dd008     sub    sp, sp, #8    ; 0x8
8101a64c:    eb002d4e     bl    81025b8c <armInitExceptionModes>
8101a650:    e59fb4d4     ldr    fp, [pc, #1236]    ; 8101ab2c <$d> fp=81301524
 excEnterTbl
8101a654:    e3a01005     mov    r1, #5    ; 0x5
8101a658:    e59f04d0     ldr    r0, [pc, #1232]    ; 8101ab30 <$d+0x4>  r0 =
e59ff0f4
8101a65c:    e24bb008     sub    fp, fp, #8    ; 0x8

8101a660:    e59b3008     ldr    r3, [fp, #8]
8101a664:    e2511001     subs    r1, r1, #1    ; 0x1
8101a668:    e5830000     str    r0, [r3]
8101a66c:    e59bc008     ldr    ip, [fp, #8]
8101a670:    e59b300c     ldr    r3, [fp, #12]
8101a674:    e28bb008     add    fp, fp, #8    ; 0x8
8101a678:    e58c30fc     str    r3, [ip, #252]
8101a67c:    1afffff7     bne    8101a660 <excVecInit+0x1c> 8101a660
8101a680:    e3a0c000     mov    ip, #0    ; 0x0
8101a684:    e59f34a8     ldr    r3, [pc, #1192]    ; 8101ab34 <$d+0x8> r3 =
e7fddefe
8101a688:    e58c3000     str    r3, [ip]
8101a68c:    e59fc4a4     ldr    ip, [pc, #1188]    ; 8101ab38 <$d+0xc> ip =
813087C8
8101a690:    e59cb01c     ldr    fp, [ip, #28]     fp = [813087E4]
8101a694:    e35b0000     cmp    fp, #0    ; 0x0
8101a698:    0a000003     beq    8101a6ac <excVecInit+0x68>  8101a6ac
8101a69c:    e3a00000     mov    r0, #0    ; 0x0
8101a6a0:    e3a0101c     mov    r1, #28    ; 0x1c
8101a6a4:    e1a0e00f     mov    lr, pc
8101a6a8:    e1a0f00b     mov    pc, fp

8101a6ac:    e59f3488     ldr    r3, [pc, #1160]    ; 8101ab3c <$d+0x10>  r3 =
8101a6dc
8101a6b0:    e59fc488     ldr    ip, [pc, #1160]    ; 8101ab40 <$d+0x14>  ip =
813102a4  _func_armIrqHandler
8101a6b4:    e58c3000     str    r3, [ip]
_func_armIrqHandler = 8101a6dc excIntHandle
8101a6b8:    e3a00000     mov    r0, #0    ; 0x0
8101a6bc:    e28dd008     add    sp, sp, #8    ; 0x8
8101a6c0:    e8bd8800     ldmia    sp!, {fp, pc}

8101b494 <intVecBaseSet>:
8101b494:    e1a0f00e     mov    pc, lr

    通过反复分析,intVecBaseSet在ARM体系上屁用也没有,是空的,根本不能指望通过它
改变中断向量基址VEC_BASE_ADRS。这段汇编的大概意思是:在0地址开始处填写中断向量表
跳转语句,在100H处写跳转地址,没有中断服务子程序的入口填写0xE59FF9F4(未定义指令
,用于引发异常)。怪不得死机,LPC2210重映射到0地址的RAM空间只有64字节,向100H只读
地址写数据会引发异常(44B0向ROM里写数据不会引发异常,顶多写不进去就是了,看来
LPC2210在地址空间防护上做了一些工作,能识别出向只读空间里写数据的错误。虽然是好
事,但给我们移植BSP带来了困难,怎么办呢?)。VxWorks考虑得真是周到,这部分是用源
码提供的,那就咔嚓了excVecInit(),换成自己的myExcVecInit(),齐活。

    VxWorks提供的中断处理函数不能动,因为要使用VxWorks的中断体系,由它来调用我们
提供的处理函数,这样,就把LPC2210的中断体系映射到了VxWorks上。

    既然可以替换成自己的代码,那就不用仿照VxWorks向量表原来的构造了,把它推翻,
换个和LPC2210匹配更好的结构。我用LPC2210内部IRAM保存向量表和ISR服务程序入口地址
,因为内部IRAM快,还可节省一些外部XRAM空间,然后把它映射到0地址即可(真是绝配啊!
)。汇编源程序如下:(target/config/zlgarm/sysALib.s)

    .globl     FUNC(myExcVecInit)    /* own code for armInitExceptionModes()
---zk */

    .extern    FUNC(excEnterUndef)
    .extern    FUNC(excEnterSwi)
    .extern    FUNC(excEnterPrefetchAbort)
    .extern    FUNC(excEnterDataAbort)
    .extern    FUNC(intEnt)

    .extern    FUNC(armInitExceptionModes)

    .extern    FUNC(_func_armIrqHandler)
    .extern    FUNC(excIntHandle)

_ARM_FUNCTION(myExcVecInit)

    stmfd   sp!, {r0-r10,lr}
    bl   FUNC(armInitExceptionModes)

copy_vector:
    adr     r0, real_vectors
    add     r2, r0, #64
    ldr     r1, =0x40000000       /*前面的初始化程序已经把此RAM的前64字节重映射
到了0地址*/
/*add    r1, r1, #0x08*/
vector_copy_loop:
    ldmia   r0!, {r3-r10}
    stmia   r1!, {r3-r10}
    cmp     r0, r2
    ble     vector_copy_loop

    /*反汇编的程序在此处判断了一个内存中的变量,但我没找到该变量名,没判断变量是
否为0就直接赋值了。*/
    /*看效果没有任何不良影响。*/
    ldr     r0, L$__func_armIrqHandler
    ldr     r1, L$_excIntHandle
    str     r1, [r0]

    nop
    ldmfd   sp!, {r0-r10,pc}


/*************************************************/
/*    interrupt vectors                     */
/*************************************************/
real_vectors:
        ldr     pc,.reset                  //0x00
    ldr     pc,.undefined_instruction  //0x04
    ldr     pc,.software_interrupt     //0x08
    ldr     pc,.prefetch_abort         //0x0C
    ldr     pc,.data_abort             //0x10
    ldr     pc,.not_used               //0x14
    ldr     pc,.irq                    //0x18
    ldr     pc,.fiq                    //0x1C

/*************************************************/

.reset:                 .word     0xE59FF9F4
.undefined_instruction: .word     FUNC(excEnterUndef)
.software_interrupt:    .word     FUNC(excEnterSwi)
.prefetch_abort:        .word     FUNC(excEnterPrefetchAbort)
.data_abort:            .word     FUNC(excEnterDataAbort)
.not_used:              .word     0xE59FF9F4  /* not use */
.irq:                   .word     FUNC(intEnt)
.fiq:                   .word     0xE59FF9F4 /* fiq */

    注意噢:子程序要压栈保存所有改变的寄存器(除非明确需要改变,如传参数值,才不
需要保存恢复),不然不要怪我没有提醒你ARM编译器会优化程序,使用寄存器传值,如果你
的子程序内部改变了寄存器值又没有恢复原先的值,那么插入你自编的函数,会发生很多奇
妙的事哦!
    stmfd   sp!, {r0-r10,lr}
    ldmfd   sp!, {r0-r10,pc}

    ============================
    调试器、内存打印、点灯的异同
    ============================
    这三者都是很好的调试方法,尤其在调试BSP类程序时很有用,此时,串口还没有工作
,但又想看到信息以便进行分析,怎么办?凉拌。
    点灯比较简单,看看灯的亮灭和组合就知道程序现在跑到哪了,适合问题定位。
    内存打印可以表达更多信息,但需要bootloader支持,通过命令行查看内存。
    调试器功能最强,有些支持源码调试,相当方便。打印语句调试是让被调程序牵着鼻子
走,调试器是牵着被调程序鼻子走(可以任意修改走向),想牵谁的鼻子自己决定。
    《ecos增值包》提供的调试环境适合粗调,尽管需要被被调程序牵着鼻子走,配合AXD
调试(不适合粗调,容易陷在细节中,最好先粗调定位问题,再对问题点用调试器细调),还
是很快的。

    ========
    时钟驱动
    ========
    时钟驱动需要实现:系统时钟和辅助时钟中断、连接、禁止、使能、读、写,时标中断
、连接、禁止、使能、读周期、读频率、读tick值、锁中断读tick值。
    需要注意的是,每次时钟中断ISR处理时都别忘了清时钟中断,不然,CPU一直陷入中断
,就不能做别的事情了。具体代码可以参照其他BSP模板(在target/config/目录下就是各种
ARM板子的BSP移植源码)并结合LPC2210开发板的时钟驱动范例自行写出。

    ========
    串口驱动
    ========
    VxWorks的串口驱动比较特别,与其他驱动不同。
    VxWorks串口驱动同时支持基于查询和中断的驱动,可以在运行时通过IOCTL配置运行模
式和属性。
    查询方式很简单,这里主要说下基于中断的驱动。

    LPC2210的UART收发中断共用同一个中断号,我们在中断服务程序里先收后发,通过状
态寄存器判断是收中断还是发中断亦或是超时、错误中断。

    (void) intConnect(INUM_TO_IVEC(devParas[i].vector), zlgarmInt, (int)
&zlgarmChan[i] );
    intEnable(INUM_TO_IVEC(devParas[i].vector));
    把串口中断ISR服务程序挂在相应中断号devParas[i].vector上并使能中断。这样每次
UART中断都会调用zlgarmInt函数。

void zlgarmInt(ZLGARM_CHAN *pChan)
{
    zlgarmIntRcv(pChan);
    zlgarmIntTx(pChan);
}
    在zlgarmInt里先调用收函数,再调用发函数,实现收发操作共用同一个中断号的目的

LOCAL int zlgarmTxStartup
    (
    SIO_CHAN * pSioChan                 /* channel to start */
    )
    {
    ZLGARM_CHAN * pChan = (ZLGARM_CHAN *)pSioChan;
    unsigned int stat;

    unsigned char * base = (unsigned char *)pChan->regs;

    zlgarmIntTx(pChan);

    HAL_READ_UINT8(base+LPC2XXX_UART_IER, stat);
    stat = stat | LPC2XXX_UART_IER_TXE;
    HAL_WRITE_UINT8(base+LPC2XXX_UART_IER, stat);

    return (OK);
    }
    每次发送前,VxWorks先调用zlgarmTxStartup激活中断,使后续发送自动化。

void zlgarmIntTx
    (
    ZLGARM_CHAN *    pChan        /* channel generating the interrupt */
    )
    {
    unsigned int stat;
    char     outChar;
    unsigned char * base = (unsigned char *)pChan->regs;

    HAL_READ_UINT8(base + LPC2XXX_UART_LSR, stat);
    if((stat & LPC2XXX_UART_STAT_TXE) == 0)
        return;
    if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
        HAL_WRITE_UINT8(base + LPC2XXX_UART_THR, outChar);
    else
        {
        HAL_READ_UINT8(base+LPC2XXX_UART_IER, stat);
        stat = stat & (~LPC2XXX_UART_IER_TXE);
        HAL_WRITE_UINT8(base+LPC2XXX_UART_IER, stat);
        }
    }
    在发送时先判断是否正在发送,如果发送FIFO不为空,那么,肯定正在发送数据,程序
退出,等到发送结束,发送中断会自动调用这个程序再次发送的。如果发送FIFO为空,说明
已发送完毕,此时上层回调函数getTxChar从VxWorks管理的循环队列中取出一个字节数据继
续发送,只要字符在发送状态,发送中断就会消失,一旦发送完毕会再次触发。如果循环队
列中已无字符,一定要记住关闭发送中断使能,不然,由于发送FIFO为空,发送中断总是有
效,CPU会反复陷入发送中断。

void zlgarmIntRcv
    (
    ZLGARM_CHAN *    pChan        /* channel generating the interrupt */
    )
    {
    unsigned int stat;
    unsigned int c;
    unsigned char * base = (unsigned char *)pChan->regs;

    HAL_READ_UINT8(base + LPC2XXX_UART_LSR, stat);
    if ((stat & LPC2XXX_UART_STAT_RDR) != 0)
        {
        HAL_READ_UINT8(base+LPC2XXX_UART_RBR, c);
        (*pChan->putRcvChar) (pChan->putRcvArg, c);
        }
    }
    接收中断比较简单,只要判断接收状态即可,调用上层回调函数putRcvChar把收到的字
符存入VxWorks管理的循环队列。

    总体感觉VxWorks串口架构设计得非常合理和灵活,获益良多!妙不可言!

    =========
    flash驱动
    =========
    略

    ===========
    MUX网络驱动
    ===========
    略

    =====================
    Makefile和onfig.h配置
    =====================
    见《VxWorks内存布局》节

    ========
    编译方法
    ========
    ---------------
    bootrom编译方法
    ---------------
    拷贝c:/Tornado2.2/host/x86-win32/bin/torVars.bat到
c:/Tornado2.2/target/config/zlgarm目录并改名为zlgarmmake.bat。增加语句,最终内容
如下:

rem Command line build environments
set WIND_HOST_TYPE=x86-win32
set WIND_BASE=C:/Tornado2.2
set PATH=%WIND_BASE%/host/%WIND_HOST_TYPE%/bin;%PATH%

rem Diab Toolchain additions
set DIABLIB=%WIND_BASE%/host/diab
set PATH=%DIABLIB%/WIN32/bin;%PATH%

make clean
make bootrom_res.bin

    以后只要双击该文件就可以编译驻留ROM型bootrom映像。

    ---------------
    vxworks编译方法
    打开Tornado编译器,选择build标签,右键设定default_romResident为激活编译类型
。以后只要点击编译图标即可。
    注意:
        每次修改Makefile和config.h后都要重新生成项目,因为Tornado使用的是上一次
配置的项目,本次修改配置无效。
        注释使用“/* */”,不要使用“//”。

    ========
    使用方法
    ========
    把bootrom或vxworks程序烧写到flash里,启动后就可以看到logo启动界面。enjoy
it!     ^_^
    有了BSP,就可以专心开发VxWorks应用程序了,只要在生成项目时指定BSP即可。


    《ecos增值包》用户(需提供识别码)对VxWorks BSP在EasyARM2200和SmartARM2200上移
植有任何疑问均可来信询问([email protected]),不提供源码,提供文档支持。
--

※ 来源:·水木社区 http://newsmth.net·[FROM: 61.149.56.*]
 

你可能感兴趣的:(c,汇编,vector,FP,makefile,编译器)