S3C2440 VXWORKS移植笔记

2006年下半年,我们在自己设计的BCNG2440开发板上移植了VXWORKS。移植的过程参考了网络上一些BSP代码,与现有的代码不同的是,我们的BSP实现了内存的重映射,中断向量的重新分配;以及cache和MMU的开启。移植的目的是用于一个数据采集系统,ARM从FPGA读取解调数据,通过100M网络发送到服务器。经过测试,使用UDP发送速率达到了43Mbps,使用TCP发送速率为20Mbps。之前,我们在类似的项目中使用了MPC8260为CPU,当时TCP最高速率也只达到了20多Mbps,因此,我们认为在某些项目中使用ARM替代MPC8260是可行的。

      移植的过程分为一下几个部分:

     1)异常处理

     2)中断

   3)MMU

   4)DM9000网卡驱动

   5)启动参数保存问题

   6)CPU设置

   7)其他问题

 

异常处理问题

通常来讲,在嵌入式系统启动之初,CPU将从0地址处(或ffff0000处)开始执行代码,因此初始时将ROM映射在0(或ffff0000)地址处,当进行完必要的初始化并启动异常处理机制后,会将RAM映射到0(或ffff0000)地址处,而将ROM映射到其它地址。

这是因为发生异常时,CPU会跳转到0地址开始处执行异常向量表。由于RAM的访问速度远远高于ROM,因此将RAM映射到0地址后,可以减少异常处理的延迟时间还有其他好处,动态和灵活等。

地址重映射可通过不同的方式实现,例如MPC8260可通过重新为每个memory bank 分配地址空间来实现,对于AT91RM9200,可通过设置其独有的“REMAP”控制位来实现。

ARM的体系结构规定在异常发生时,要从地址开始处读取相应的处理指令,然而S3C2440A的固定地址空间管理方法在VxWorks里会遇到问题。因为从硬件上讲,S3C2440A的地址空间是不能重分配的,它也不支持所谓的REMAP功能,一旦硬件连线决定了其RAM基地址为0x30000000(nGCS6)0地址上为ROM(nGCS0),就无法再更改。因此必须采用其他办法来解决异常向量表的访问问题VxWorks管理的RAM中异常向量表结构如下图:

对于BOOTROM来说,不会使用到MMU,访问地址0就是访问ROM,因此需要将异常向量表建立在启动ROM的开始处。

基本思想是在Flash存储器的起始地址硬编码异常入口,仿vxWorks建立异常向量表。异常发生时,经Flash存储器入口,跳转到自定义函数,再跳转到RAM中异常入口,再调用vxWorks提供的异常处理函数。中断处理流程和中断向量表如下图示意。新异常向量表和原VxWorks设计完全一样。

 

romInit.c(下面是处理IRQ异常的例子,其它见源代码):

_romInit:

    B       cold

    B       _romUndef

    B       _romSwi

    B       _romPrefetch

    B       _romDataAbort

    B       _romReserved

    B       _romIRQ

    B       _romFIQ

 

_ARM_FUNCTION(romIRQ)

     _romIRQ:

     sub sp, sp, #4

     stmfd sp!, {r0}

 

     ldr r0, L$_promIRQ

     ldr r0, [r0]

     str r0, [sp, #4]

     ldmfd sp!, {r0, pc}

 

L$_promIRQ:

.long     S3C_EXC_BASE + 20

 

/* exception base */

#define S3C_EXC_BASE         0x30000100

config.c中定义:

#define S3C_EXC_BASE         0x30000100

sysLib.c:

添加以下函数声明

void s3cExcVecSet(void);

IMPORT VOIDFUNCPTR excEnterUndef;

IMPORT VOIDFUNCPTR excEnterPrefetchAbort;

IMPORT VOIDFUNCPTR excEnterDataAbort;

IMPORT VOIDFUNCPTR excEnterSwi;

IMPORT VOIDFUNCPTR intEnt;

添加函数s3cExcVecSet()

void s3cExcVecSet(void) 

{

    int i;

    i = (int)&excEnterUndef;

*((volatile int*)(S3C_EXC_BASE + 0x0)) = i;

i = (int)&excEnterSwi;

*((volatile int*)(S3C_EXC_BASE + 0x4)) = i;

i = (int)&excEnterPrefetchAbort;

*((volatile int*)(S3C_EXC_BASE + 0x8)) = i;

i = (int)&excEnterDataAbort;

*((volatile int*)(S3C_EXC_BASE + 0xc)) = i;

i = (int)&intEnt;

*((volatile int*)(S3C_EXC_BASE + 0x14)) = i;

return;

}

sysHwInit()中调用s3cExcVecSet()

void sysHwInit(void)

{

/* install the IRQ/SVC interrupt stack splitting routine */

_func_armIntStackSplit = sysIntStackSplit;

 

#ifdef INCLUDE_SERIAL

/* initialise the serial devices */

sysSerialHwInit ();      /* initialise serial data structure */

#endif    /* INCLUDE_SERIAL */

 

s3cExcVecTblInstall();

s3cExcVecSet();   

}

简单的描述上述代码的过程:当异常发生时,以IRQ异常为例,PC指针首先跳转到0x14处,读取指令“B       _romIRQ”,然后进入到_romIRQ函数,此函数作用是将S3C_EXC_BASE + 20地址里面的值赋给PC寄存器(S3C_EXC_BASE + 20地址里面存放vxWorksIRQ处理函数intEnt的地址,这由s3cExcVecSet建立),从而跳转到inrEnt函数处理IRQ异常。

_romIRQ函数比较复杂,其作用是将S3C_EXC_BASE + 20地址里面的值赋给PC寄存器,此段处理有一定的技巧,先将当前寄存器的内容及RAM中的中断向量的地址入栈,再从堆栈中将中断向量地址装载到PC,寄存器内容也从堆栈中恢复过来。

其实不经过堆栈直接将RAM中中断向量的地址装载到PC应该也可以,但是有人在论坛中发贴说这样做存在问题,我没有验证过,但是北理他们就是这样做的(但也通过r0转了一次),除此之外我所见到的所有s3c44b0s3c2410BSP都是采用前面描述的做法。

 

对于vxWorks映象,如果不采用MMU或者使用MMU但是进行平坦地址映射,ROM仍处于地址0,因此使用和BOOTROM同样的方式处理异常向量即可,无需对代码做其他修改。但是如果通过MMU进行非平坦地址映射(即SDRAM映射到地址0,以加快异常处理速度,ROM映射到某一空闲地址处,如0xf0000000),则需要在SDRAM起始地址处建立异常向量跳转表。

已经知道,在vxWorks内存的0x0100偏移处存在异常函数处理指针(由s3cExcVecSet()建立的),因此需要在SDRAM起始地址处填写如下代码(反汇编后形式):

ldr      pc,=0xf00000fc    /* 复位,此时无用,don't care */

ldr      pc,=0x00000100   

ldr      pc,=0x00000104   

ldr      pc,=0x00000108   

ldr      pc,=0x0000010c   

ldr      pc,=0x00000110    /* 保留,don't care */

ldr      pc,=0x00000114

ldr      pc,=0x00000118    /* vxWorks不使用FIQ,don't care */

获取上面汇编代码对应的机器码0xe59ff0f4,0xe59ff0f4,0xe59ff0f4,0xe59ff0f4,0xe59ff0f4,0xe59ff0f4,0xe59ff0f4,0xe59ff0f4(至于为什么全是一样的数据,我也没搞很清除,估计应该是ldr的实现机理决定的)。

将这8DWORD写入到SDRAM起始地址处即完成异常向量跳转表的创建;

sysLib.c中添加函数

void s3cExcVecTblInstall()

{

int i;

long excVecTbl[] = {0xe59ff0f4,0xe59ff0f4,0xe59ff0f4,0xe59ff0f4,0xe59ff0f4,0xe59ff0f4,0xe59ff0f4,0xe59ff0f4};

 

for(i=0;i<8;i++)

{

     *((volatile unsigned long*)(LOCAL_MEM_LOCAL_ADRS + i*4)) = excVecTbl[i];

}

return;

}

并在sysHwInit()中调用s3cExcVecSet()

void sysHwInit(void)

{

/* install the IRQ/SVC interrupt stack splitting routine */

_func_armIntStackSplit = sysIntStackSplit;

 

#ifdef INCLUDE_SERIAL

/* initialise the serial devices */

sysSerialHwInit ();      /* initialise serial data structure */

#endif    /* INCLUDE_SERIAL */

 

s3cExcVecTblInstall();

s3cExcVecSet();   

}

 

其他一些说明:

对于异常向量表的建立和处理,本应该由vxWorks来完成,事实上,在bootConfig.c中的usrIni ()函数中,有intVecBaseSet()excVecInit()函数调用,不过对于ARM体系的CPU来说,由于不存在vector base register,因此intVecBaseSet实际上是一个空操作(分析汇编可看出就是一个return);而由于调用excVecInit()函数时,处于0x100(异常函数处理指针)地址处的是ROM(此函数调用在MMU启用之前,因此即使在vxWorks映象中启用MMU并进行非平坦地址映射,0x100还是对应ROM),因此尽管excVecInit运行了,但是没起到实际作用,也就是没能在SDRAM偏移0x100处建立异常函数处理指针。

s3cExcVecSet()rom中写入的异常向量编码(对于BOOTROMvxworks平坦地址映射)以及s3cExcVecTblInstall(对于vxworks非平坦地址映射)实际上起到了取代excVecInit()的作用。

bootConfig.c代码中可以看出,intVecBaseSet()excVecInit ()之后紧接着调用了sysHwInit (),因此在sysHwInit调用s3cExcVecSets3cExcVecTblInstall

 

(更多关于异常向量的内容可参见 44B0xBSP是如何调成的”以及Amine的“S3C44B0X VxWorks BSP 移植笔记)

中断

ARM没有专门的中断控制器,对于中断的操作只能通过操作有限的几个寄存器实现。并且由于不同厂家生产的不同型号的ARM处理器提供的中断寄存器是不一样的,因此vxWorks没有为ARM提供中断控制的库函数,这样一来,就需要在BSP里面自己编写中断控制程序。

在我们的BSP里面,中断控制程序位于s3c2440aIntrCtl.c,程序比较简单,主要是进行中断寄存器的初始化以及实现并注册三个回调函数。但是由于中断控制实现的特殊性,有必要说明编写ISR时要注意的问题,建议编写ISR时此节必看。

1.关于中断enable/disable

对于s3c2440a,enable/disable中断本质上就是对相应中断的掩码位进行操作(INTMSK寄存器),但是在应用程序中应该调用intEnable()和intDisable()函数来实现,而不是直接操作INTMSK寄存器。

这是因为调用intEnable()和intDisable()时会通过回调函数最终调用到s3c2440aIntLvlEnable()和s3c2440aIntLvlDisable(),从源代码中可以看见,存在一个全局变量s3c2440aIntLvlEnabled,它记录了当前打开和关闭的中断的情况,enable和disable操作都是现对这个变量相应位赋值,然后将其赋给INTMSK寄存器。如果用写地址方式直接修改INTMSK寄存器,那么下一次调用intEnable()或intDisable()时会使直接修改的控制位会到以前的情况,从而使得中断控制操作无效。

这个问题在我调试中断时遇到过,当时使用直接操作INTMSK寄存器的方式,发现外部中断INT4-7对应的比特位在使能后不久就被disable了,后来使用ADS跟踪执行汇编代码,发现当执行printf语句时,由于printf向控制台打印信息会产生串口中断,在串口中断执行过程中使得INT4-7对应的比特位被disable掉,这才发现时直接操作INTMSK寄存器惹得祸。

2.带有子中断的中断操作

如串口中断等,存在发送中中断、接受中断和错误中断3个子中断。以串口中断为例,当中断发生时,会先执行s3c2440aIntLvlVecChk()函数(不是很清楚这个过程,但是跟踪汇编代码可以肯定这点),在s3c2440aIntLvlVecChk里面首先将UART中断的3个子中断全部禁止掉(通过设置INTSUBMSK对应控制位),然后清除SRCPND和INTPND寄存器中相应的比特位。接下来就进入到ISR,在ISR里面,通过读取SUBSRCPND寄存器,判断当前发生的是哪一个子中断,然后进行相应的处理并清除SUBSRCPND寄存器中相应的比特位,最后设置INTSUBMSK寄存器打开需要的子中断。

从上面的流程可以看出,中断的禁止与重新打开实际上是对子中断掩码进行操作来完成的,并没有涉及到INTMSK的操作(intEnable/intDisable)。

对于其它带有子中断的中断类型,建议也按照这个方式进行处理,具体可以参考串口驱动的相关代码。另外,由于目前不清楚其他带有子中断的中断类型的具体情况,因此s3c2440aIntLvlVecChk()函数里只有串口中断处理的相关代码,其它的情况暂时留空,如果需要编写相应的ISR,切记完善s3c2440aIntLvlVecChk()函数。

3.外部中断EINT4_7和EINT8_23

在INTMSK、INTPND和SRCPND寄存器里面,外部中断EINT4_7和EINT8_23分别只对应一个控制位,然后在EINTMASK、EINTPND再对具体是那一个外部中断进行处理。

与带有子中断的中断操作的中断操作类似,当某一外部中断产生时(以EINT6为例),先执行s3c2440aIntLvlVecChk()函数,在s3c2440aIntLvlVecChk里面首先将EINTMASK中EINT4~EINT7对应的控制位全部禁止掉,然后清除SRCPND和INTPND寄存器中相应的比特位。接下来在ISR里面进行了需要的操作之后,清除EINTPEND寄存器相应比特位,然后设置EINTMASK以打开EINT6的中断。

目前的操作是针对EINT4_7或EINT8_23中仅有一个外部中断发生的情况。以EINT4_7为例,如果存在多个外部中断源可能产生中断,则情况比较复杂,对这种情况没有做过测试,因此也无法得到切实可用的代码,但是可能的操作描述如下,仅供将来参考:在s3c2440aIntLvlVecChk()中禁止EINT4~EINT7对应的控制位(EINTMASK中)之前,先使用一个全局变量(例如eintMaskStatus)保存EINTMASK中EINT4~EINT7的当前值。对于ISR来说,需要使用一个总的ISR处理EINT4~EINT7所有的中断,在进入该ISR后,先通过读取EINTPND判断当前发生的是哪一个外部中断,接下来在完成相应操作之后清除EINTPND相应比特位,最后根据eintMaskStatus的值恢复EINTMASK中EINT4~EINT7的值(即打开相应的掩码位)。

这样做是因为EINT4~EIN T7显然处于同一优先级,当EINT4(例如)来中断时,必须禁止EINT5~EINT7。采用全局变量eintMaskStatus(在ISR所在源文件中要用extern声明)是为了确保不会误disable其它需要的外部中断。另外,在EINT4_7的ISR结束处恢复各个相应外部中断掩码时要注意不能干扰EINT8_23对应的外部中断掩码,反之亦然,以免产生误操作。

4.其它的中断(包括外部中断0、1、2、3)

其它的中断(包括外部中断0、1、2、3)在INTMSK、INTPND和SRCPND寄存器里面都有自己的控制位,因此操作相对简单。此时,若发生中断,由于s3c2440aIntLvlVecChk()中清除了SRCPND和INTPND寄存器中相应的比特位,因此在ISR中无需再做其它操作。不过在进入和退出ISR时加上intEnable和intDisable似乎也没什么问题。

5.例子

对于带有子中断的中断操作可以参照串口中断。

对于外部中断EINT4_7和EINT8_23,可以参照网络驱动(eint7)和intTest.c(eint6)。在intTest.c中,eintTestInit()、eTestInt()、eintTest()是外部中断6的测试代码。若在BOOTROM中进行测试,在syslib.c中合适位置处添加#include "intTest.c",在bootConfig.c的合适位置处添加eintTest()的声明,并在usrRoot()函数的最后一行代码(taskSpawn……)之前添加eintTest()的调用。另外必须在CPLD中将BOTTON1指定到EINT6 (EINT6 <= not BOTTON1),并焊接RP552、D551和S551。当BOOTROM进行倒数计数时按任意键进入命令行模式,此时按botton 1可以在超级中断看见打印信息“interrupt: eTestInt6,entered”。对于其它的中断,以外部中断2为例,可以参考intTest.c(eint2),其中eintTestInit2()、eTestInt2()、eintTest2()是外部中断2的测试代码。若在BOOTROM中进行测试,在syslib.c中合适位置处添加#include "intTest.c",在bootConfig.c的合适位置处添加eintTest2()的声明,并在usrRoot()函数的最后一行代码(taskSpawn……)之前添加eintTest2()的调用。另外必须在CPLD中将BOTTON2指定到EINT2 (EINT2 <= not BOTTON2),并焊接RP552、D552和S552。当BOOTROM进行倒数计数时按任意键进入命令行模式,此时按botton 2可以在超级中断看见打印信息“interrupt: eTestInt2,entered”。

关于MMU

MMU只在vxWorks中才使用,BOOTROM不会用到。在S3C2440A中使用MMU,需要异常向量处理的配合,详见“异常向量”相关部分的说明。

启用MMU时,要在TORNADO里面vxWorks组建配置串口包含hardwareàmemoryàMMUàMMU Modeàbasic MMU supportfull MMU support

sysLib.c中的sysPhysMemDesc可配置是使用平坦地址映射还是非平坦地址映射,使用非平坦地址映射时,由于异常向量跳转表存在SDRAM中,访问速度快于ROM,因此有利于提高系统性能。

若使用MMU时,需要正确配置sysPhysMemDesc数组。对任意内存空间的访问,必须在sysPhysMemDesc配置相应的项。若添加新的外设,该外设对应的内存空间必须在sysPhysMemDesc中配置。

网络驱动DM9000E

网络芯片采用DAVICOMDM9000E。驱动程序采用DAVICOM提供的v1.11版本,但是他们给的驱动是DM9000A并且基于x86的,移植自linux,并且其版本最后修正时间064月,存在不少问题,因此这方面的工作主要是对他们的驱动进行修改个完善,以适应我们的系统。

1.由于原来的驱动是基于x86的,因此对于DM9000_IN_ADDRDM9000_IN_ADDRDM9000_OUT_ADDRDM9000_IN_BYTEDM9000_OUT_BYTEDM9000_IN_WORDDM9000_OUT_WORDDM9000_OUT_CHARDM9000_IN_CHAR这些宏需要重新定义。

2.关于CPU中相关寄存器的初始化。DM9000E所占用的memory bank的访问属性在BSP中的romInit中已经设置,在其驱动里面的不再做相关工作。为DM9000分配外部中断号、设置外部中断产生方式等操作在cpuForDM9000Init()函数里定义,该函数在dm9000Start()中调用。另外在dm9000Stop()中调用cpuForDm9000disable(),作用是关闭eint7对应的外部中断掩码。

3.在configNet.h中将DM9K_LOAD_STRING改为"0x4:0x4",这是CPUEINT4-7的中断级别,另外删除dm9000end.cdm9000Parse()函数里面关于IO Base的部分。因为arm不存在IO访问的说法。

4.原来的驱动是从SROM中获取MAC地址,我们不使用MAC地址,因此在程序里面定义全局变量DM9KdefaultMacAddr,用来记录MAC地址,并在dmfe_reset_dm9000()里面将其赋给dev->enetAddr。需要注意的是,当在以太网上使用多块板子时,要注意为每块板子修改MAC地址(重烧BOOTROM和重编译vxWorks),否则多块板子会使用同一个MAC地址,从而出现网络不同的情况。

532bit对齐问题。原来的驱动是基于x86的,x86不存在对齐问题,因为x86硬件可以自动将程序中没有对齐的地方对齐。但是移植到ARM上就有问题。主要是typedef struct end_device{…}END_DEVICE这个结构。它的最后一个成员txBuf没有处于32bit对齐的位置,这样在将其强制类型转化成word时(dmfe_start_xmit()函数发送数据时)会访问到非法数据。解决办法是在END_DEVICE结构体的txBuf成员以前添加

UCHAR         dummyBytes[3];

从而使得txBuf处于32bit对齐的位置。DummyBytes不做其它用途。

typedef struct end_device

{

    END_OBJ             end;            /* The class we inherit from. */

    END_ERR             err;

         UINT     IOBase;

    int                 unit;           /* unit number */

    int                 ivec;           /* interrupt vector */

    int                 ilevel;         /* interrupt level */

    long                flags;          /* Our local flags. */

    UCHAR               enetAddr[6];    /* ethernet address */

 

    CACHE_FUNCS         cacheFuncs;     /* cache function pointers */

    CL_POOL_ID          pClPoolId;      /* cluster pool */

    BOOL                rxHandling;     /* rcv task is scheduled */

 

    UCHAR               io_mode;        /* 0:word, 2:byte */

    char                tx_pkt_cnt;

    char                device_wait_reset;

    UWORD               queue_pkt_len;

    UCHAR               reg0;           /* registers saved */

    UCHAR               nic_type;       /* NIC type */

    UCHAR               op_mode;        /* PHY operation mode */

 

    UCHAR               mcastFilter[8]; /* multicast filter */

    UCHAR          dummyBytes[3];  /* dummyBytes, for 32-bit align */

    UCHAR                 txBuf[ETHERMTU + EH_SIZE + 6 + 64 ];

} END_DEVICE;

 

6.中断处理。在ISR里面要将x86中断操作的内容删掉,然后加入ARM下处理外部中断的操作。原理可过程可参考“中断”一节的内容,另外,目前的操作是当ISR退出时先开CPU中断,再开DM9000E的片上中断,不知道反过来行不行,会不会有什么影响。

7.发送处理。通过对比发现,原来的驱动移植自linux,但是移植的却不完全,一个很大的问题体现在发送处理上面。

DM9000E有两个发送缓存,当发送一个缓存中的数据时,可以向另一个缓存写数据,以加快传送速度。而DAVICOM提供的驱动里面,只用到了一个缓存:

static int dmfe_start_xmit( PKT skb, END_DEVICE dev) /*原驱动程序发送函数*/

{

… …

… …

… …

    dev->queue_pkt_len = skb->len;

    dev->tx_pkt_cnt ++;

 

    /* Set TX length to DM9000 */

    DM9000_OUT_CHAR( 0xfc, skb->len & 0xff );

    DM9000_OUT_CHAR( 0xfd, (skb->len >> 8) & 0xff );

 

    /* Issue TX polling command */

    DM9000_OUT_CHAR( 0x2, 0x01 );        /* Cleared after TX complete */

   

    return 0;

}

这样以来,要是CPUDM9000E发送数据的速度较快时,一个缓冲区会忙不过来,就会出现“tx full”,然后网卡工作不正常,无法继续进行通信。为了实现稳定告诉的通信,需要修改发送过程,参考linuxDM9000E的驱动程序,对vxWorks驱动修改如下:

static int dmfe_start_xmit( PKT *skb, END_DEVICE *dev)

{

   … …

   … …

   … …   

    /* TX control: First packet immediately send, second packet queue */

     if (dev->tx_pkt_cnt == 0)

    {        

         /* First Packet */

         dev->tx_pkt_cnt ++;

         /* Set TX length to DM9000 */

         DM9000_OUT_CHAR( 0xfc, skb->len & 0xff );

         DM9000_OUT_CHAR( 0xfd, (skb->len >> 8) & 0xff );

    

         /* Issue TX polling command */

         DM9000_OUT_CHAR( 0x2, 0x01 );        /* Cleared after TX complete */

    }

    else /* Second packet */

    {

        dev->queue_pkt_len = skb->len;

        dev->tx_pkt_cnt ++;

    } 

    return 0;

}

还要修改dm9000Int()

static void dm9000Int( END_DEVICE  *pDrvCtrl  )  /* interrupting device */

{

   … …

   … …

   … … 

    /* TODO - handle transmit interrupts */

    if( isr_status & 2 )

    {

         DRV_LOG (DRV_DEBUG_INT, "Got an TX interrupt!", pDrvCtrl->tx_pkt_cnt, 2, 3, 4, 5, 6);       

         DRV_SP( DRV_PK,"x" );

           

         DM9000_IN_CHAR(0x1, TX_comple_status);

        /* if (TX_comple_status & 0x4) pDrvCtrl->tx_pkt_cnt--;

            if (TX_comple_status & 0x8) pDrvCtrl->tx_pkt_cnt--;  */

           

         if (TX_comple_status & 0xc)

              {

              /* One packet sent complete */

              pDrvCtrl->tx_pkt_cnt--;

             

                   /* Queue packet check & send */

              if (pDrvCtrl->tx_pkt_cnt > 0)

              {   

                            DM9000_OUT_CHAR( 0xfc, pDrvCtrl->queue_pkt_len & 0xff );

                            DM9000_OUT_CHAR( 0xfd, (pDrvCtrl->queue_pkt_len >> 8) & 0xff );

                   DM9000_OUT_CHAR( 0x2, 0x01 );        

                        }           

          }           

    }

   … …

   … …

   … … 

}

修改后,不会再出现网络不稳定的情况(并且可以ping大包了)。使用赵海涛的程序测试网络速度(TCP),发现使用MMU时(非平坦地址映射),可达22Mbps左右;关闭MMU但是使能cache时,略大于10Mbps;同时关闭MMUcache,只有略大于6Mbps的速度。使用平坦地址映射MMU模式下的网络速度没有测试。

8.延时问题。linux的驱动采用uDelay进行延时,但是DAVICON提供的vxWorks驱动对这个问题处理不好,从而使得延时过长,影响运行速度。考虑到默认情况下taskDelay(1)延时0.01s,已远大于DM9000任何操作要求的最小延时,因此在需要延时的地方改为taskDelay(1)

你可能感兴趣的:(S3C2440 VXWORKS移植笔记)