AT91RM9200开发调试手记

自己的AT91RM9200的板子已经调试了一段时间了,从开始动手制作PCB到现在,差不多有半年的时间了。在这期间一直忙着查资料,画板布线,联系制板厂家,联系购买器件(呵呵,大小活全包),一直没有时间写写总结之类的东西,另外平时也没有养成随时总结的好习惯。以前搞硬件基本上是以8位的51单片机为主,偶尔也用用PC104,AVR之类的控制器,其他16位、32位的控制器从没用过,对其感觉甚为神秘。因此在做这块板子之前,自己查阅了很多资料(网上资料为主,资源丰富,比较方便),在做了各种权衡利弊之后(做方案,选芯片是比较令人头疼的事情,有过系统设计经历的朋友可能有这种体会),最后才痛下决心,决定选用atmel的AT91RM9200做为控制芯片。因为在此之前从来没有搞过32位的东东,所以当时心里一点底都没有。[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    1. 制订方案[!21ki@][@21ki!]
     选定AT91RM9200之后,接下来就是围绕它设计外围电路了。因为我做的这个东西应用场合比较特殊:野外应用,因此在设计方案的时候尽量选用工业级的芯片。第一次用这款控制器,设计电路的时候最好的参考就是由atmel官方提供的开发板:AT91RM9200DK。但是这块板上的网络PHY部分采用的是DM9161E,查资料发现这个PHY非工业级产品,后来决定把它换成intel的LXT971A。另外我的应用中还需要一个网络接口,在非PCI接口的网络控制芯片中选来选去,最后决定用SMSC公司的LAN91C111I-NE,也是一款工业级别的芯片(网上资料反映其功耗较大,power hungry,但其他工业级的片子当时没有查到,缪办法呀)。其他的电路基本上都是参考AT91RM9200DK的原理图设计的,除了复位电路采用了阻容电路(开发板上那个复位芯片国内很难买得到)。[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    2. 画图制板[!21ki@][@21ki!]
     方案确定之后接下来就是画原理图,布线,制板了。之前一直都用protel,在网上查阅资料的时候发现了有关allegro和mentor公司的相关产品,当时听说是比较牛的软件,比protel强多了,当时就有了放弃protel的想法(先不说功能,光是速度就让我很郁闷,可能是因为以前的机器比较破的关系吧)。那学什么新软件呢?当时在一个ftp上发现了allegro以及相关的一本书(台湾出的那本),而mentor的没找到多少相关资料。OK,就allegro了。全新的开始。[!21ki@][@21ki!]
     因为用了allegro的原因,从画原理图到最后画完PCB,前后将近2个月的时间。有关allegro的应用,以后有时间再写个总结吧,我当时也是现学现卖。PCB画完之后,因为制板工艺的原因,颇费一般周折之后才把板子交出去(拿到深圳做的,很羡慕在深圳工作的朋友,买器件制板都很方便)。一周之后,终于拿到了样板。做工看上去蛮不错,比在本地做的强多了。[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    3.焊接检查[!21ki@][@21ki!]
     板子做完了,器件也买好了,下面就要焊接调试了。当时心里是比较紧张的,因为我做的PCB是双面板,当时网上有朋友告诉我说双面板可能会不稳定(9200能跑到200MHz),另外对自己的布线水平也没信心(我对自己的定位是:啥都会,啥都不精)。板子上除了一个按键和几个接插件,全部都是表贴。本地有专门提供焊接服务的,找到他们之后,2个小时半块板子搞定(为什么是半块?因为有一部分件没有买齐,就是那个LAN91C111I-NE)。板子焊接完之后拿回来,在上电测试之前,按照我以前的习惯,先用万用表量了一下板子的电源和地。这一量不要紧,惊出我一身冷汗:短路!心情一下子就#!!#@!#@!,怎么搞的嘛!没别的办法,检查吧。首先确定是不是焊接的原因导致的,样板一共做了10块,拿另外一块空板量了一下,晕倒!也是短路![!21ki@][@21ki!]
    板子上到处是电源和地,怎么检查呢?我心里知道这种错误最难检查了,要命的是我的板子已经焊接好了,要是万一短路的地方在表贴件的下面,那岂不是太残酷了?我心里一边暗自祷告,一边找来一块板做我的牺牲品,各位可能知道我下一步要做什么了,嘿嘿,从电源输入的地方开始,逐条把分支割断。一共割了6刀,终于找到了短路的地方(其中有一处是凭俺肉眼瞅出来的)。短路原因是铺的铜跟电源线太近而短路(这其中有加工方面的因素,另一方面也是因为我设置的间距太小了,0.3mm,以后还是用1mm好了)。又在焊接好的板子上割了两刀,万用表一测,OK!这次是运气好,以后在焊接之前可要好好测试板子有没有问题了。[!21ki@][@21ki!]
     上面的短路故障是因为加工的原因导致的。后来又焊接了一块板,也出现了短路的问题,是复位线和地线短路,与上面不同的是,这次短路是因为焊接导致的。所以在焊接前后一定要检查。这两次都算我运气好,没有出现烧毁芯片的问题。虽然是比较低级的错误,但有时却是致命的。[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    4.初步调试[!21ki@][@21ki!]
    确定板子没有问题之后(至少自己感觉是这样),下一步就是检查板子工作是否正常了。根据手头掌握的资料,9200从片内启动之后,会通过DEBGUG串口向外发送‘CCCCC‘字符(至于这个C字符代表什么含义,接下来会有描述)。OK,先从这里入手。首先启动超级终端,参数设置为115200,8,no,1,no; [!21ki@][@21ki!]
    将调试串口连到PC串口,给板子上电。[!21ki@][@21ki!]
    超级终端无反应,按复位键,涛声依旧![!21ki@][@21ki!]
    再检查原理图。首先看复位,晕倒,竟然没有把复位电路里面用的7404焊上!断电,找来烙铁,我焊![!21ki@][@21ki!]
    再上电,超级终端还是没有反应,又狂按复位键,还是没反应。 [!21ki@][@21ki!]
    当时心情真是郁闷到了极点!检查了一下调试串口的接口芯片,应该没有问题。又仔细检查了一下电路图,先从串口部分看起,突然发现调试串口的2,3脚连接顺序跟手头的开发板不一样,又仔细检查了一下用的串口连接线(别的开发板上的),原来是直连的,而并非交叉线,还好,手头有9针的串口接插头,马上作了一个转接的。[!21ki@][@21ki!]
    连接好以后,再上电,终于在超级终端上看到了久违的CCCCCCCCCC.......[!21ki@][@21ki!]
     OK,下面可以用U-BOOT和arm-linux来测试了。[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    5. U-BOOT移植篇[!21ki@][@21ki!]
    确定板子可以工作之后,接下来的工作就是把U-BOOT移植到我的板子上。因为有AT91RM9200DK板移植好的例子,所以移植工作要相对容易一些。在移植之前,我先用AT91RM9200DK板子上的U-BOOT做了一下测试,因为当时还没有仔细研究U-BOOT的结构,而现在对U-BOOT也不是很了解,只能说是皮毛而已,等以后研究明白了再写一些有关U-BOOT的文字。首先把现成的U-BOOT下载到我的板子上:[!21ki@][@21ki!]
    A. 将串口连接好,打开超级终端,串口参数设置为115200,8,none, 1, none。[!21ki@][@21ki!]
    B. 接通板子电源,超级终端出现“CCCCC”。[!21ki@][@21ki!]
    C. 在超级终端中选择菜单 transfer=>send file, 传送协议选择xmodem或者1K xmodem,传送文件选择loader.bin,文件传送完毕后超级终端出现以下提示:[!21ki@][@21ki!]
    loader 1.0 (Aug 8 2003 - 12:01:07)[!21ki@][@21ki!]
    XMODEM: Download U-BOOT[!21ki@][@21ki!]
    然后继续显示“CCCC”[!21ki@][@21ki!]
    D. 在超级终端中选择菜单 transfer=>send file, 传送协议选择xmodem或者1K xmodem,传送文件选择u-boot.bin,文件传送完毕后超级终端出现u-boot提示符: U-BOOT>[!21ki@][@21ki!]
    E. 由于我的板子上的PHY接口芯片由DM9161E换成了LXT971A,因此此时在U-BOOT中网络接口是不能使用的,这给下载linux内核测试带来了麻烦。但为了进一步确定板子可以正常工作,我还是用U-BOOT中的串口下载命令loadb将linux内核和ramdisk下载到了板子上:[!21ki@][@21ki!]
    U-BOOT> loadb 21000000 uImage[!21ki@][@21ki!]
    U-BOOT> loadb 21100000 ramdisk-rmk7[!21ki@][@21ki!]
    U-BOOT> setenv bootargs root=/dev/ram rw initrd=0x21100000,6000000 ramdisk_size=15360 console=ttyS0,115200 mem=32M[!21ki@][@21ki!]
    U-BOOT> bootm 21000000[!21ki@][@21ki!]
    整个过程用了一个多小时,呵呵,太慢了。下载后linux可以启动,基本上应该没有问题了。下面的首要任务就是修改U-BOOT代码,让其支持LXT971A,要不然下载linux太费时间了。[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    6. U-BOOT移植初步[!21ki@][@21ki!]
    经过上述准备工作之后,基本上确定硬件没有问题,下一步首要的任务就是要把板子上的以太网调通,以方便以后的下载调试工作.[!21ki@][@21ki!]
    6.1 准备工作[!21ki@][@21ki!]
    在移植之前,我手头已经有一个Atmel官方提供的U-BOOT源代码,但不是最新的版本. 因此我首先到U-BOOT的站点下载了最新的版本(http://sourceforge.net/projects/u-boot), 当时的最新版本是1.1.2 . 另外还需要一个交叉编译器. 当时手头上有arm-linux-gcc-2.95.3版本, 后来又从http://www.handhelds.org下载了3.3.2的版本. 版本并不是越高越好,因为存在兼容性的问题. 后来在用3.3.2版本编译atmel提供的linux-2.4.19的时候,就出现了一堆错误,但改成2.95.3后就没有问题了.[!21ki@][@21ki!]
    *****小插曲****** [!21ki@][@21ki!]
    在做移植准备的过程中还出现了一个小小的插曲. 因为在此之前的硬件测试工作都是在windows环境下用超级终端进行的.而交叉编译需要linux环境(当然在windows下用cygwin也可以,但兼容性不是很好),因此就需要一个linux环境下的"超级终端",我对linux并不熟悉,从网上查了一些资料,决定用minicom. 自己经过摸索,可以操纵minicom了,但是在用xmodem协议向板上下载程序的时候遇到问题: 总是提示错误,下载无法进行. 急忙到google上面搜索相关资料,结果发现这是一个共性的问题,很多朋友都反映xmodem下载协议有问题, 据说是时序上的原因. 怎么办呢? 最初从网上当了一些有关xmodem的资料以及一些源代码, 后来决定自己编写一个xmodem下载的程序. 下面就做一个小小的总结.[!21ki@][@21ki!]
    A. xmodem协议简介[!21ki@][@21ki!]
    XMODEM协议是一种使用拨号调制解调器的个人计算机通信中广泛使用的异步文件运输协议。这种协议以128字节块的形式传输数据,并且每个块都使用一个校验和过程来进行错误检测。如果接收方关于一个块的校验和与它在发送方的校验和相同时,接收方就向发送方发送一个认可字节。然而,这种对每个块都进行认可的策略将导致低性能,特别是具有很长传播延迟的卫星连接的情况时,问题更加严重。[!21ki@][@21ki!]
     使用循环冗余校验的与XMODEM相应的一种协议称为XMODEM-CRC。还有一种是XMODEM-1K,它以1024字节一块来传输数据。ZMODEM是最有效的一个XMODEM版本,它不需要对每个块都进行认可。事实上,它只是简单地要求对损坏的块进行重发。ZMODEM对按块收费的分组交换网络是非常有用的。不需要认可回送分组在很大程度上减少了通信量。YMODEM也是一种XMODEM的实现。它包括XMODEM-1K的所有特征,另外在一次单一会话期间为发送一组文件,增加了批处理文件传输模式。[!21ki@][@21ki!]
    有不少产品的维护和软件升级都是采用XMODEM协议来进行的.[!21ki@][@21ki!]
    B.xmodem协议的数据包格式[!21ki@][@21ki!]
    首先看几个定义: SOH---> 0x01 STX--->0x02 ACK--->0x06 NAK--->0x15 EOT--->0x04 CRC--> 'C' 其中SOH代表一个数据包的开始标志,而STX与SOH有相同的含义,不过它是用在1K-XMODEM协议中的. ACK是确认标志,NAK是非确认标志(要求重发),EOT是传送结束标志,CRC是使用CRC校验标志.一个完整数据包的格式如下:[!21ki@][@21ki!]
    <SOH> <数据包长度> <255-数据包长度> <128字节数据> <校验字>[!21ki@][@21ki!]
    在1K-XMODEM协议中,数据长度由128字节提高到1K字节.[!21ki@][@21ki!]
    在XMODEM协议中,对数据包进行校验的方式有两种,一种是采用校验和,另一种是CRC校验.那么收发双方如何确认对方的校验方式呢?[!21ki@][@21ki!]
    C.传输建立过程[!21ki@][@21ki!]
    在早期采用校验和的XMODEM协议中,接收方准备就绪之后,会间隔一段时间发送"NAK"信号,每发送一个NAK,接收方就等待一段时间并检查是否收到SOH信号,若接收到则开始数据传送; 而发送方接收到NAK信号之后,便认为接收方已经准备好并开始数据传送,这样一个数据传输过程就建立起来了.在这种方式下采用的是校验和的方式.[!21ki@][@21ki!]
    在采用CRC校验的XMODEM协议中,为了保持兼容性,接收方若支持CRC校验,间隔发送的不是NAK而是CRC标志,也就是'C',看到这里大家可能明白了AT91RM9200片内启动之后,为什么向外发送'CCC'而不是其他的字符. 发送方接收到CRC标志之后,若支持CRC校验方式,便开始数据的传输,否则不做任何响应. 若接收方两种校验方式都支持的话(取决于程序编写),若对方不支持CRC,它就会转到校验和方式.[!21ki@][@21ki!]
    D.数据传输过程[!21ki@][@21ki!]
    下面是一个采用CRC校验方式进行数据传递的过程示意图:[!21ki@][@21ki!]
    发送方 接收方[!21ki@][@21ki!]
    <----------------------------------------------------- 'C'[!21ki@][@21ki!]
    <SOH> <01> <fe> <128字节> <CRC高字节> <CRC低字节> ------------>[!21ki@][@21ki!]
    <------------------------------------------------------ <ACK>[!21ki@][@21ki!]
    <SOH> <02> <fd> <128字节> <CRC高字节> <CRC低字节> ------------->[!21ki@][@21ki!]
    <----------------------------------------------------- <NAK>[!21ki@][@21ki!]
    <SOH> <02> <fd> <128字节> <CRC高字节> <CRC低字节> ------------->[!21ki@][@21ki!]
    <------------------------------------------------------ <ACK>[!21ki@][@21ki!]
    ....................................................................................[!21ki@][@21ki!]
    <EOT> ----------------------------------------------------------->[!21ki@][@21ki!]
    <------------------------------------------------------<NAK>[!21ki@][@21ki!]
    <EOT> ----------------------------------------------------------->[!21ki@][@21ki!]
    <------------------------------------------------------<ACK>[!21ki@][@21ki!]
    传送结束[!21ki@][@21ki!]
    E. 程序编写[!21ki@][@21ki!]
    有了上面的了解,就可以编写利用XMODEM协议进行数据传送的程序了. 这里面涉及到linux下的串口编程,还有就是16位CRC校验的生成.下面把我写的源程序给出,供大家参考,程序在RedHat9.0下编译测试通过.[!21ki@][@21ki!]
    /***A simple program using xmodem/1kxmode send file*/[!21ki@][@21ki!]
    #include <stdio.h>[!21ki@][@21ki!]
    #include <stdlib.h>[!21ki@][@21ki!]
    #include <unistd.h>[!21ki@][@21ki!]
    #include <sys/types.h>[!21ki@][@21ki!]
    #include <sys/stat.h>[!21ki@][@21ki!]
    #include <fcntl.h>[!21ki@][@21ki!]
    #include <termios.h>[!21ki@][@21ki!]
    #include <errno.h>[!21ki@][@21ki!]
    /*[!21ki@][@21ki!]
    Xmodem Frame form: <SOH><blk #><255-blk #><--128 data bytes--><CRC hi><CRC lo>[!21ki@][@21ki!]
    */[!21ki@][@21ki!]
    #define XMODEM_SOH 0x01[!21ki@][@21ki!]
    #define XMODEM_STX 0x02[!21ki@][@21ki!]
    #define XMODEM_EOT 0x04[!21ki@][@21ki!]
    #define XMODEM_ACK 0x06[!21ki@][@21ki!]
    #define XMODEM_NAK 0x15[!21ki@][@21ki!]
    #define XMODEM_CRC_CHR 'C'[!21ki@][@21ki!]
    #define XMODEM_CRC_SIZE 2 /* Crc_High Byte + Crc_Low Byte */[!21ki@][@21ki!]
    #define XMODEM_FRAME_ID_SIZE 2 /* Frame_Id + 255-Frame_Id */[!21ki@][@21ki!]
    #define XMODEM_DATA_SIZE_SOH 128 /* for Xmodem protocol */[!21ki@][@21ki!]
    #define XMODEM_DATA_SIZE_STX 1024 /* for 1K xmodem protocol */[!21ki@][@21ki!]
    #define USE_1K_XMODEM 0 /* 1 for use 1k_xmodem 0 for xmodem */[!21ki@][@21ki!]
    #if (USE_1K_XMODEM)[!21ki@][@21ki!]
    #define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_STX[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     #define XMODEM_HEAD XMODEM_STX[!21ki@][@21ki!]
     [!21ki@][@21ki!]
    #else[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     #define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_SOH[!21ki@][@21ki!]
    #define XMODEM_HEAD XMODEM_SOH[!21ki@][@21ki!]
    #endif[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    /*********/[!21ki@][@21ki!]
    #define SERIAL_DEVICE "/dev/ttyS0"[!21ki@][@21ki!]
    #define BAUDRATE B115200;[!21ki@][@21ki!]
    /***************SUB PROGRAM*******/[!21ki@][@21ki!]
    unsigned short GetCrc16 ( char *ptr, unsigned short count )[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    unsigned short crc, i;[!21ki@][@21ki!]
    crc = 0;[!21ki@][@21ki!]
    while(count--)[!21ki@][@21ki!]
     [!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    crc = crc ^ (int) *ptr++ << 8;[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     for(i = 0; i < 8; i++)[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    if (crc & 0x8000)[!21ki@][@21ki!]
    crc = crc << 1 ^ 0x1021;[!21ki@][@21ki!]
    else[!21ki@][@21ki!]
    crc = crc << 1;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    [!21ki@][@21ki!]
     }[!21ki@][@21ki!]
    return (crc & 0xFFFF);[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    /*******************************/[!21ki@][@21ki!]
    int Initial_SerialPort(void)[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    [!21ki@][@21ki!]
     int fd;[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     struct termios options;[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     fd = open( SERIAL_DEVICE , O_RDWR &line; O_NOCTTY &line; O_NDELAY );[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     if ( fd == -1 )[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     {[!21ki@][@21ki!]
    /*open error!*/[!21ki@][@21ki!]
    perror("port can't open!");[!21ki@][@21ki!]
    return -1;[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     }[!21ki@][@21ki!]
    /*Get the current options for the port...*/[!21ki@][@21ki!]
    tcgetattr(fd, &options);[!21ki@][@21ki!]
    /*Set the baud rates to BAUDRATE...*/[!21ki@][@21ki!]
    cfsetispeed(&options, BAUDRATE);[!21ki@][@21ki!]
    cfsetospeed(&options, BAUDRATE);[!21ki@][@21ki!]
    tcsetattr(fd, TCSANOW, &options);[!21ki@][@21ki!]
    if (0!= tcgetattr(fd, &options))[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    perror("SetupSerial 1");[!21ki@][@21ki!]
    return -1;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    /*[!21ki@][@21ki!]
     * 8bit Data,no partity,1 stop bit...[!21ki@][@21ki!]
     */[!21ki@][@21ki!]
    options.c_cflag &= ~PARENB;[!21ki@][@21ki!]
    options.c_cflag &= ~CSTOPB;[!21ki@][@21ki!]
    options.c_cflag &= ~CSIZE;[!21ki@][@21ki!]
    options.c_cflag &line;= CS8;[!21ki@][@21ki!]
    tcflush(fd,TCIFLUSH);[!21ki@][@21ki!]
    /***Choosing Raw Input*/[!21ki@][@21ki!]
    options.c_lflag &= ~(ICANON &line; ECHO &line; ECHOE &line; ISIG);[!21ki@][@21ki!]
    options.c_oflag &= ~OPOST;[!21ki@][@21ki!]
    /*[!21ki@][@21ki!]
     * Set the new options for the port...[!21ki@][@21ki!]
     */[!21ki@][@21ki!]
    if(0!=tcsetattr(fd, TCSANOW, &options))[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    perror("SetupSerial error");[!21ki@][@21ki!]
    return -1 ;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    return fd ;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    //******************************[!21ki@][@21ki!]
    void ClearReceiveBuffer(int fd)[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    unsigned char tmp;[!21ki@][@21ki!]
    while((read(fd,&tmp,1))>0);[!21ki@][@21ki!]
    return;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    //********************************[!21ki@][@21ki!]
    int main(int argc,char *argv[])[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    int fd;[!21ki@][@21ki!]
    char data_file_name[80];[!21ki@][@21ki!]
    char packet_data[ XMODEM_DATA_SIZE ];[!21ki@][@21ki!]
    char frame_data[ XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1 ];[!21ki@][@21ki!]
    unsigned char tmp;[!21ki@][@21ki!]
    FILE *datafile;[!21ki@][@21ki!]
    int complete,retry_num,pack_counter,read_number,write_number,i;[!21ki@][@21ki!]
    unsigned short crc_value;[!21ki@][@21ki!]
    unsigned char ack_id;[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    //**open serial port1[!21ki@][@21ki!]
    if ( (fd = Initial_SerialPort()) == -1) return -1 ;[!21ki@][@21ki!]
    data_file_name = argv[1];[!21ki@][@21ki!]
    if ((datafile=fopen(data_file_name,"rb"))==NULL)[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    perror("file can't open!");[!21ki@][@21ki!]
    return -1 ;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    //*******************************[!21ki@][@21ki!]
    pack_counter = 0;[!21ki@][@21ki!]
    complete = 0;[!21ki@][@21ki!]
    retry_num = 0;[!21ki@][@21ki!]
    ClearReceiveBuffer(fd);[!21ki@][@21ki!]
    while((read(fd,&ack_id,1))<=0);[!21ki@][@21ki!]
    printf("%c ",ack_id);[!21ki@][@21ki!]
    ack_id = XMODEM_ACK;[!21ki@][@21ki!]
    while(!complete)[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    switch(ack_id)[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    case XMODEM_ACK:[!21ki@][@21ki!]
    retry_num = 0;[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     pack_counter++;[!21ki@][@21ki!]
    read_number = fread( packet_data, sizeof(char), XMODEM_DATA_SIZE, datafile);[!21ki@][@21ki!]
    if(read_number>0)[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     {[!21ki@][@21ki!]
    if (read_number<XMODEM_DATA_SIZE_SOH)[!21ki@][@21ki!]
    { [!21ki@][@21ki!]
     [!21ki@][@21ki!]
     printf("Start filling the last frame! ");[!21ki@][@21ki!]
    for(;read_number<XMODEM_DATA_SIZE;read_number++)[!21ki@][@21ki!]
    packet_data[read_number] = 0x00;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    frame_data[0] = XMODEM_HEAD;[!21ki@][@21ki!]
    frame_data[1] = (char)pack_counter;[!21ki@][@21ki!]
    frame_data[2] = (char)(255-frame_data[1]);[!21ki@][@21ki!]
    for(i=0;i<XMODEM_DATA_SIZE;i++)[!21ki@][@21ki!]
    frame_data[i+3]=packet_data[i];[!21ki@][@21ki!]
    crc_value = GetCrc16(packet_data,XMODEM_DATA_SIZE);[!21ki@][@21ki!]
    frame_data[XMODEM_DATA_SIZE_SOH+3]=(unsigned char)(crc_value >> 8);[!21ki@][@21ki!]
    frame_data[XMODEM_DATA_SIZE_SOH+4]=(unsigned char)(crc_value);[!21ki@][@21ki!]
    write_number = write( fd, frame_data, XMODEM_DATA_SIZE_SOH + 5);[!21ki@][@21ki!]
    printf("waiting for ACK,%d,%d,...",pack_counter,write_number);[!21ki@][@21ki!]
    while((read(fd,&ack_id,1))<=0);[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     if(ack_id == XMODEM_ACK)[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     printf("Ok! ");[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     else[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     printf("Error! ");[!21ki@][@21ki!]
    break;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    else[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    ack_id = XMODEM_EOT;[!21ki@][@21ki!]
    complete = 1;[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     printf("Waiting for complete ACK ...");[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     while(ack_id != XMODEM_ACK) ;[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    ack_id = XMODEM_EOT; [!21ki@][@21ki!]
     [!21ki@][@21ki!]
     write_number=write(fd,&ack_id,1);[!21ki@][@21ki!]
    while((read(fd,&ack_id,1))<=0);[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     }[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     printf("ok! ");[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     printf("Sending file complete! ");[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     break;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    case XMODEM_NAK:[!21ki@][@21ki!]
    if( retry_num++ > 10)[!21ki@][@21ki!]
    {[!21ki@][@21ki!]
    printf("Retry too many times,Quit! ");[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     complete = 1;[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     break;[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     }[!21ki@][@21ki!]
    write_num = write(fd,frame_data,XMODEM_DATA_SIZE + 5);[!21ki@][@21ki!]
    printf("Retry for ACK,%d,%d...",pack_counter,write_number);[!21ki@][@21ki!]
    while((read(fd,&ack_id,1))<=0);[!21ki@][@21ki!]
    if( ack_id == XMODEM_ACK )[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     printf("Ok! ");[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     else[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     printf("Error! ");[!21ki@][@21ki!]
    break;[!21ki@][@21ki!]
    default:[!21ki@][@21ki!]
    printf("Fatal Error! ");[!21ki@][@21ki!]
     [!21ki@][@21ki!]
     complete = 1;[!21ki@][@21ki!]
    break;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    fclose(datafile);[!21ki@][@21ki!]
    close(fd);[!21ki@][@21ki!]
    return 0;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    7. U-BOOT移植之LXT971篇[!21ki@][@21ki!]
     移植和测试都是在linux下进行的(Redhat 9.0). 首先将以前下载的U-BOOT-1.1.2源代码解压到/usr/local/u-boot-1.1.2, arm-linux-gcc-3.3.2解压到/usr/local/arm/3.3.2, 设置好路径:[!21ki@][@21ki!]
    export PATH=/usr/local/arm/3.3.2/bin:$PATH ( 告诉系统去哪里找 arm-linux- )[!21ki@][@21ki!]
    打开u-boot-1.1.2下面的readme文件, 根据里面的提示, 要将U-BOOT移植到一个新板上,需要做以下改动:[!21ki@][@21ki!]
     A. 修改根目录下的Makefile以及MAKEFILE文件,向其中增加对你要新添加的板子的支持. 因为有AT91RM9200DK项做参考,所以这一步并不困难;[!21ki@][@21ki!]
     B. 在/board下面新建一个目录,里面包含你要增加的板子的信息. 我给我的板起名为at91rm9200my(呵呵,不够响亮), 那么我要做的就是在/board下新建一个at91rm9200my的目录, 根据readme里面的提示, 至少要包含这几个文件: Makefile , at91rm9200my.c, flash.c 和 u-boot.lds, 有at91rm9200DK做参考,这一步也不困难. (拷贝过来就OK了,我还没有根据我的板子做修改)[!21ki@][@21ki!]
     C. 在 /include/configs/ 下面建一个新板的配置文件, 我的是 at91rm9200my.h, 至于里面的内容,当然是参考at91rm9200dk.h了.[!21ki@][@21ki!]
     D. 做完上面这些, 下面就是要做LXT971A的工作了. at91rm9200dk上用的是DM9161E, 在/board/at91rm9200dk里面我找到了dm9161.c 这个文件, 那么我需要做的就是要改动这个文件了. 另外在Makefile里面我还看到了这么一行: OBJS := at91rm9200dk.o at45.o dm9161.o flash.o 我想这两个文件是需要我改动的了.首先把dm9161.c文件另存为lxt971a.c, 把Makefile里面的那行改为:[!21ki@][@21ki!]
    OBJS := at91rm9200dk.o at45.o lxt971a.o flash.o[!21ki@][@21ki!]
    根据我的了解,DM9161是RMII接口,LXT971A是MII接口,而对PHY的控制是通过MDI来进行的,在DM9161.C里面,主要有这么几个函数: [!21ki@][@21ki!]
    dm9161_IsPhyConnected() [!21ki@][@21ki!]
    dm9161_GetLinkSpeed() [!21ki@][@21ki!]
    dm9161_InitPhy() [!21ki@][@21ki!]
    dm9161_AutoNegotiate() [!21ki@][@21ki!]
    at91rm92000_GetPhyInterface()[!21ki@][@21ki!]
    除了最后一个外,前四个函数都是通过at91rm9200提供的MDI接口对PHY进行控制,那么我要做的工作就是根据LXT971A的手册对这个函数改写. DM9161与LXT971A内部的寄存器地址大部分都是相同的,只有少数几个的地址和位定义不同,改写比较容易. 下面是我改写完的 lxt971a.c : [!21ki@][@21ki!]
    #include <at91rm9200_net.h>[!21ki@][@21ki!]
    #include <net.h>[!21ki@][@21ki!]
    #include <lxt971a.h> /***这个头文件u-boot源文件里面有***/[!21ki@][@21ki!]
    #ifdef CONFIG_DRIVER_ETHER[!21ki@][@21ki!]
    #if (CONFIG_COMMANDS & CFG_CMD_NET)[!21ki@][@21ki!]
    static unsigned int lxt971a_IsPhyConnected (AT91PS_EMAC p_mac)[!21ki@][@21ki!]
    { [!21ki@][@21ki!]
     unsigned short Id1, Id2;[!21ki@][@21ki!]
     at91rm9200_EmacEnableMDIO (p_mac);[!21ki@][@21ki!]
     at91rm9200_EmacReadPhy (p_mac, PHY_COMMON_ID1, &Id1);[!21ki@][@21ki!]
     at91rm9200_EmacReadPhy (p_mac, PHY_COMMON_ID2, &Id2);[!21ki@][@21ki!]
     at91rm9200_EmacDisableMDIO (p_mac);[!21ki@][@21ki!]
     if ((Id1 == PHY_LXT971A))[!21ki@][@21ki!]
     return TRUE;[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    static UCHAR lxt971a_GetLinkSpeed (AT91PS_EMAC p_mac)[!21ki@][@21ki!]
    { [!21ki@][@21ki!]
     unsigned short stat1, stat2;[!21ki@][@21ki!]
     if (!at91rm9200_EmacReadPhy (p_mac, PHY_COMMON_STAT, &stat1))[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     if (!(stat1 & PHY_COMMON_STAT_LNK_STAT)) /* link status up? */[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     if (!at91rm9200_EmacReadPhy (p_mac, PHY_LXT971_STAT2, &stat2))[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     if ((stat1 & PHY_COMMON_STAT_100BXFD) && (stat2 & PHY_LXT971_STAT2_100BTX) && (stat2 & PHY_LXT971_STAT2_DUPLEX_MODE)) { [!21ki@][@21ki!]
     /*set Emac for 100BaseTX and Full Duplex */[!21ki@][@21ki!]
     p_mac->EMAC_CFG |= AT91C_EMAC_SPD | AT91C_EMAC_FD;[!21ki@][@21ki!]
     return TRUE;[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
     if ((stat1 & PHY_COMMON_STAT_10BTFD) && !(stat2 & PHY_LXT971_STAT2_100BTX) && (stat2 & PHY_LXT971_STAT2_DUPLEX_MODE)) { [!21ki@][@21ki!]
     /*set MII for 10BaseT and Full Duplex */[!21ki@][@21ki!]
     p_mac->EMAC_CFG = (p_mac->EMAC_CFG &[!21ki@][@21ki!]
     ~(AT91C_EMAC_SPD | AT91C_EMAC_FD))[!21ki@][@21ki!]
     | AT91C_EMAC_FD;[!21ki@][@21ki!]
     return TRUE;[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
     if ((stat1 & PHY_COMMON_STAT_100BXHD) && (stat2 & PHY_LXT971_STAT2_100BTX) && !(stat2 & PHY_LXT971_STAT2_DUPLEX_MODE)) { [!21ki@][@21ki!]
     /*set MII for 100BaseTX and Half Duplex */[!21ki@][@21ki!]
     p_mac->EMAC_CFG = (p_mac->EMAC_CFG &[!21ki@][@21ki!]
     ~(AT91C_EMAC_SPD | AT91C_EMAC_FD))[!21ki@][@21ki!]
     | AT91C_EMAC_SPD;[!21ki@][@21ki!]
     return TRUE;[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
     if ((stat1 & PHY_COMMON_STAT_10BTHD) && !(stat2 & PHY_LXT971_STAT2_100BTX) && !(stat2 & PHY_LXT971_STAT2_DUPLEX_MODE)) { [!21ki@][@21ki!]
     /*set MII for 10BaseT and Half Duplex */[!21ki@][@21ki!]
     p_mac->EMAC_CFG &= ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);[!21ki@][@21ki!]
     return TRUE;[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    static UCHAR lxt971a_InitPhy (AT91PS_EMAC p_mac)[!21ki@][@21ki!]
    { [!21ki@][@21ki!]
     UCHAR ret = TRUE;[!21ki@][@21ki!]
     unsigned short IntValue;[!21ki@][@21ki!]
     at91rm9200_EmacEnableMDIO (p_mac);[!21ki@][@21ki!]
     if (!lxt971a_GetLinkSpeed (p_mac)) { [!21ki@][@21ki!]
     /* Try another time */[!21ki@][@21ki!]
     ret = lxt971a_GetLinkSpeed (p_mac);[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
     /* Disable PHY Interrupts */[!21ki@][@21ki!]
     at91rm9200_EmacReadPhy (p_mac, PHY_LXT971_INT_ENABLE, &IntValue);[!21ki@][@21ki!]
     /* clear FDX, SPD, Link, INTR masks */[!21ki@][@21ki!]
     IntValue &= ~(PHY_LXT971_INT_ENABLE_DUPLEXMSK | PHY_LXT971_INT_ENABLE_SPEEDMSK |[!21ki@][@21ki!]
     PHY_LXT971_INT_ENABLE_LINKMSK | PHY_LXT971_INT_ENABLE_TINT);[!21ki@][@21ki!]
     at91rm9200_EmacWritePhy (p_mac, PHY_LXT971_INT_ENABLE, &IntValue);[!21ki@][@21ki!]
     at91rm9200_EmacDisableMDIO (p_mac);[!21ki@][@21ki!]
     return (ret);[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    static UCHAR lxt971a_AutoNegotiate (AT91PS_EMAC p_mac, int *status)[!21ki@][@21ki!]
    { [!21ki@][@21ki!]
     unsigned short value;[!21ki@][@21ki!]
     unsigned short PhyAnar;[!21ki@][@21ki!]
     unsigned short PhyAnalpar;[!21ki@][@21ki!]
     /* Set lxt971a control register */[!21ki@][@21ki!]
     if (!at91rm9200_EmacReadPhy (p_mac, PHY_COMMON_CTRL, &value))[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     value &= ~PHY_COMMON_CTRL_AUTO_NEG; /* remove autonegotiation enable */[!21ki@][@21ki!]
     value |= PHY_COMMON_CTRL_ISOLATE; /* Electrically isolate PHY */[!21ki@][@21ki!]
     if (!at91rm9200_EmacWritePhy (p_mac, PHY_COMMON_CTRL, &value))[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     /* Set the Auto_negotiation Advertisement Register */[!21ki@][@21ki!]
     /* MII advertising for Next page, 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3 */[!21ki@][@21ki!]
     PhyAnar = PHY_COMMON_AUTO_ADV_NP | PHY_COMMON_AUTO_ADV_100BTXFD | PHY_COMMON_AUTO_ADV_100BTX |[!21ki@][@21ki!]
     PHY_COMMON_AUTO_ADV_10BTFD | PHY_COMMON_AUTO_ADV_10BT | PHY_COMMON_AUTO_ADV_802_3;[!21ki@][@21ki!]
     if (!at91rm9200_EmacWritePhy (p_mac, PHY_COMMON_AUTO_ADV, &PhyAnar))[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     /* Read the Control Register */[!21ki@][@21ki!]
     if (!at91rm9200_EmacReadPhy (p_mac, PHY_COMMON_CTRL, &value))[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     value |= PHY_COMMON_CTRL_SPD_100 | PHY_COMMON_CTRL_AUTO_NEG | PHY_COMMON_CTRL_DUPLEX;[!21ki@][@21ki!]
     if (!at91rm9200_EmacWritePhy (p_mac, PHY_COMMON_CTRL, &value))[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     /* Restart Auto_negotiation */[!21ki@][@21ki!]
     value |= PHY_COMMON_CTRL_RES_AUTO;[!21ki@][@21ki!]
     if (!at91rm9200_EmacWritePhy (p_mac, PHY_COMMON_CTRL, &value))[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     /*check AutoNegotiate complete */[!21ki@][@21ki!]
     udelay (30000);[!21ki@][@21ki!]
     at91rm9200_EmacReadPhy (p_mac, PHY_COMMON_STAT, &value);[!21ki@][@21ki!]
     if (!(value & PHY_COMMON_STAT_AN_COMP))[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     /* Get the AutoNeg Link partner base page */[!21ki@][@21ki!]
     if (!at91rm9200_EmacReadPhy (p_mac, PHY_COMMON_AUTO_LNKB, &PhyAnalpar))[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
     if ((PhyAnar & PHY_COMMON_AUTO_ADV_100BTXFD) && (PhyAnalpar & PHY_COMMON_AUTO_LNKB_100BTXFD)) { [!21ki@][@21ki!]
     /*set MII for 100BaseTX and Full Duplex */[!21ki@][@21ki!]
     p_mac->EMAC_CFG |= AT91C_EMAC_SPD | AT91C_EMAC_FD;[!21ki@][@21ki!]
     return TRUE;[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
     if ((PhyAnar & PHY_COMMON_AUTO_ADV_10BTFD) && (PhyAnalpar & PHY_COMMON_AUTO_LNKB_10BTFD)) { [!21ki@][@21ki!]
     /*set MII for 10BaseT and Full Duplex */[!21ki@][@21ki!]
     p_mac->EMAC_CFG = (p_mac->EMAC_CFG &[!21ki@][@21ki!]
     ~(AT91C_EMAC_SPD | AT91C_EMAC_FD))[!21ki@][@21ki!]
     | AT91C_EMAC_FD;[!21ki@][@21ki!]
     return TRUE;[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
     return FALSE;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    /*[!21ki@][@21ki!]
     * Name:[!21ki@][@21ki!]
     * at91rm92000_GetPhyInterface[!21ki@][@21ki!]
     * Description:[!21ki@][@21ki!]
     * Initialise the interface functions to the PHY[!21ki@][@21ki!]
     * Arguments:[!21ki@][@21ki!]
     * None[!21ki@][@21ki!]
     * Return value:[!21ki@][@21ki!]
     * None[!21ki@][@21ki!]
     */[!21ki@][@21ki!]
    void at91rm92000_GetPhyInterface(AT91PS_PhyOps p_phyops)[!21ki@][@21ki!]
    { [!21ki@][@21ki!]
     p_phyops->Init = lxt971a_InitPhy;[!21ki@][@21ki!]
     p_phyops->IsPhyConnected = lxt971a_IsPhyConnected;[!21ki@][@21ki!]
     p_phyops->GetLinkSpeed = lxt971a_GetLinkSpeed;[!21ki@][@21ki!]
     p_phyops->AutoNegotiate = lxt971a_AutoNegotiate;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    #endif /* CONFIG_COMMANDS & CFG_CMD_NET */[!21ki@][@21ki!]
    #endif /* CONFIG_DRIVER_ETHER */[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    8. 关于板子的配制文件[!21ki@][@21ki!]
     改写完网络部分以后,我将U-BOOT用arm-linux-gcc-3.3.2做了编译:[!21ki@][@21ki!]
     $ make mrproper[!21ki@][@21ki!]
     $ make at91rm9200my_config[!21ki@][@21ki!]
     $ make all[!21ki@][@21ki!]
     将生成的u-boot.bin下载到我的板子上,结果发现网络部分还是不能用. 仔细考虑了一下可能出问题的几个地方:[!21ki@][@21ki!]
     A. 硬件问题? 网线插上之后LAX971A的三个状态指示都正常,应该不是PHY问题, 又想会不会是自己做的板子的问题(2层板,100M的网卡速度比较高), 后来又否定了自己的想法, 不应该一点反应都没有,因为U-BOOT没有提示MII方面的错误, 如果是板子布线方面的问题的话, 应该是出现不稳定现象.[!21ki@][@21ki!]
     B. 软件问题? 后来想如果真的是板子的原因,那可真是惨了,因为网卡是必须要用的. 因此我决定先从软件方面找原因. 既然LXT971和DM9161接口方式不同(一个是MII,一个是RMII),那么在U-BOOT中应该有这方面的设置选项,在什么地方呢? 首先想到的就是移植板子的时候在/include/configs/下面添加的配制文件 at91rm9200my.h, 这个文件我是从at91rm9200dk复制过来的,里面有这么一个与RMII接口有关的配制项 #define CONFIG_AT91C_USE_RMII, 当时我是把它改成了#define CONFIG_AT91C_USE_RMII 0, 会不会是这里的问题呢? 那么这个选项影响哪个文件呢? 因为在dm9161.c里面没有发现与这个定义有关的语句, 后来用sourceinsight( 阅读源代码的好工具哦) 在/cpu/at91rm9200/下面找到了这个文件: at91rm9200_eth.c 在这个文件里面有个函数 eth_init() 是用来对MAC进行初始化的, 应该就是它了,很快就找到了与RMII相关的那条语句: [!21ki@][@21ki!]
    #if defined(CONFIG_AT91C_USE_RMII) && !defined(CONFIG_CMC_PU2)[!21ki@][@21ki!]
     *AT91C_PIOB_PDR = AT91C_PB25_EF100 |[!21ki@][@21ki!]
     AT91C_PB19_ERXCK | AT91C_PB18_ECOL | AT91C_PB17_ERXDV |[!21ki@][@21ki!]
     AT91C_PB16_ERX3 | AT91C_PB15_ERX2 | AT91C_PB14_ETXER |[!21ki@][@21ki!]
     AT91C_PB13_ETX3 | AT91C_PB12_ETX2;[!21ki@][@21ki!]
    而其上面的语句是:[!21ki@][@21ki!]
     *AT91C_PIOA_PDR = AT91C_PA16_EMDIO | AT91C_PA15_EMDC | AT91C_PA14_ERXER |[!21ki@][@21ki!]
     AT91C_PA13_ERX1 | AT91C_PA12_ERX0 | AT91C_PA11_ECRS_ECRSDV |[!21ki@][@21ki!]
     AT91C_PA10_ETX1 | AT91C_PA9_ETX0 | AT91C_PA8_ETXEN |[!21ki@][@21ki!]
     AT91C_PA7_ETXCK_EREFCK;[!21ki@][@21ki!]
    这两段语句都是与设置PIO有关的,也就是将PIO设置成MAC的工作方式, 通过分析可以看出第二段是RMII和MII都需要进行的,而第一段是根据CONFIG_AT91C_USE_RMII是否定义来判断的,而不是我最初理解的将CONFIG_AT91C_USE_RMII定义为0就可以了(呵呵,比较菜) , 重新对at91rm9200my.h做修改,将[!21ki@][@21ki!]
    #define CONFIG_AT91C_USE_RMII 改成 #undef CONFIG_AT91C_USE_RMII[!21ki@][@21ki!]
    然后重新编译,下载, OK, 板上的网口终于起来了.[!21ki@][@21ki!]
    另外在用U-BOOT提供的tftp下载linux内核和根文件系统的时候,还遇到一个问题,就是在linux下, tftp服务默认设置是不自动启动的,所以要修改/etc/xinet.d/ 下面的tftp配制文件,将里面的 disable = yes 改为 no或者把这一行注释掉. 另外还有一个问题,就是记得把linux的防火墙(我用的是redhat9.0)关掉,要不然也无法用tftp下载. 详细的下载过程后面接着说. [!21ki@][@21ki!]
    [!21ki@][@21ki!]
    9. linux内核移植[!21ki@][@21ki!]
    对U-BOOT 做了简单的修改,使其网络部分可以使用之后,接下来就是让linux也能认出我的PHY来.[!21ki@][@21ki!]
    9.1 内核修改[!21ki@][@21ki!]
    我用的内核源文件是atmel提供的linux-2.4.19-rmk7, 在对源文件做修改之前, 首先编译试验了一下,结果发现用arm-linux-gcc-3.3.2编译有问题(U-BOOT是用3.3.2编译的),没办法,又把2.95.3装上,再试,没有问题.[!21ki@][@21ki!]
    接下来就是要确定要修改哪些文件了. linux内核源文件的层次还是比较清楚的,我很快在/drivers/at91/net/下面找到了at91_ether.h 和 at91_ether.c 这两个个文件, 把这两个文件打开看了一些, 觉得这就是我要找的. 在at91_ether.h里面找到了这么几行定义:[!21ki@][@21ki!]
    #define MII_DM9161_ID 0x0181b880 /*****PHY的ID***/[!21ki@][@21ki!]
    #define MII_DSCSR_REG 17 /***PHY的内部寄存器地址***/[!21ki@][@21ki!]
    #define MII_DSINTR_REG 21 /****PHY的内部寄存器地址***/[!21ki@][@21ki!]
    根据前面在修改U-BOOT的时候的得到的信息, 这三个定义是与LXT971A不同的,根据LXT971A的手册, 做了以下修改,增加了下面几行定义:[!21ki@][@21ki!]
    #define MII_LXT971A_ID 0x001378e0 /****对应MII_DM9161_ID[!21ki@][@21ki!]
    #define MII_LXT971_INT_ENABLE 0x12 /***对应MII_DSCSR_REG[!21ki@][@21ki!]
    #define MII_LXT971_INT_STATUS 0x13 /***对应MII_DSINTR_REG[!21ki@][@21ki!]
    然后对 at91_ether.c 里面的PHY管理部分做相应修改如下:[!21ki@][@21ki!]
    static int update_linkspeed(struct net_device *dev, AT91PS_EMAC regs) { [!21ki@][@21ki!]
     unsigned int bmsr, bmcr, lpa, mac_cfg;[!21ki@][@21ki!]
     unsigned int speed, duplex;[!21ki@][@21ki!]
    /* Link status is latched, so read twice to get current value */[!21ki@][@21ki!]
     read_phy(regs, MII_BMSR, &bmsr);[!21ki@][@21ki!]
     read_phy(regs, MII_BMSR, &bmsr);[!21ki@][@21ki!]
     if (!(bmsr & BMSR_LSTATUS)) return -1; /* no link */[!21ki@][@21ki!]
    read_phy(regs, MII_BMCR, &bmcr);[!21ki@][@21ki!]
     if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */[!21ki@][@21ki!]
     if (!(bmsr & BMSR_ANEGCOMPLETE)) return -2; /* auto-negotitation in progress */[!21ki@][@21ki!]
    read_phy(regs, MII_LPA, &lpa);[!21ki@][@21ki!]
     if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;[!21ki@][@21ki!]
     else speed = SPEED_10;[!21ki@][@21ki!]
     if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;[!21ki@][@21ki!]
     else duplex = DUPLEX_HALF;[!21ki@][@21ki!]
     } else { [!21ki@][@21ki!]
     speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;[!21ki@][@21ki!]
     duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
    /* Update the MAC */[!21ki@][@21ki!]
     mac_cfg = regs->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);[!21ki@][@21ki!]
     if (speed == SPEED_100) { [!21ki@][@21ki!]
     if (duplex == DUPLEX_FULL) /* 100 Full Duplex */[!21ki@][@21ki!]
     regs->EMAC_CFG = mac_cfg | AT91C_EMAC_SPD | AT91C_EMAC_FD;[!21ki@][@21ki!]
     else /* 100 Half Duplex */[!21ki@][@21ki!]
     regs->EMAC_CFG = mac_cfg | AT91C_EMAC_SPD;[!21ki@][@21ki!]
     } else { [!21ki@][@21ki!]
     if (duplex == DUPLEX_FULL) /* 10 Full Duplex */[!21ki@][@21ki!]
     regs->EMAC_CFG = mac_cfg | AT91C_EMAC_FD;[!21ki@][@21ki!]
     else /* 10 Half Duplex */[!21ki@][@21ki!]
     regs->EMAC_CFG = mac_cfg;[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
    printk(KERN_INFO "%s: Link now %i-%s ", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");[!21ki@][@21ki!]
     return 0;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    /*[!21ki@][@21ki!]
     * Handle interrupts from the PHY[!21ki@][@21ki!]
     */[!21ki@][@21ki!]
    void at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)[!21ki@][@21ki!]
    { [!21ki@][@21ki!]
     struct net_device *dev = (struct net_device *) dev_id;[!21ki@][@21ki!]
     AT91PS_EMAC emac = (AT91PS_EMAC) dev->base_addr;[!21ki@][@21ki!]
     int status;[!21ki@][@21ki!]
     unsigned int phy;[!21ki@][@21ki!]
    enable_mdi(emac);[!21ki@][@21ki!]
    read_phy(emac, MII_LXT971_INT_STATUS, &phy); /* acknowledge interrupt in PHY */[!21ki@][@21ki!]
     status = AT91_SYS->PIOC_ISR; /* acknowledge interrupt in PIO */[!21ki@][@21ki!]
    status = update_linkspeed(dev, emac);[!21ki@][@21ki!]
     if (status == -1) { /* link is down */[!21ki@][@21ki!]
     netif_carrier_off(dev);[!21ki@][@21ki!]
     printk(KERN_INFO "%s: Link down. ", dev->name);[!21ki@][@21ki!]
     } else if (status == -2) { /* auto-negotiation in progress */[!21ki@][@21ki!]
     /* Do nothing - another interrupt generated when negotiation complete */[!21ki@][@21ki!]
     } else { /* link is operational */[!21ki@][@21ki!]
     netif_carrier_on(dev);[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
     disable_mdi(emac);[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    /*[!21ki@][@21ki!]
     * Initialize and enable the PHY interrupt when link-state changes[!21ki@][@21ki!]
     */[!21ki@][@21ki!]
    void enable_phyirq(struct net_device *dev, AT91PS_EMAC regs)[!21ki@][@21ki!]
    { [!21ki@][@21ki!]
     struct at91_private *lp = (struct at91_private *) dev->priv;[!21ki@][@21ki!]
     unsigned int dsintr, status;[!21ki@][@21ki!]
    static int first_init = 0;[!21ki@][@21ki!]
    if (first_init == 0) { [!21ki@][@21ki!]
     // TODO: Check error code. Really need a generic PIO (interrupt)[!21ki@][@21ki!]
     // layer since we're really only interested in the PC4 line.[!21ki@][@21ki!]
     (void) request_irq(4, at91ether_phy_interrupt, 0, dev->name, dev);[!21ki@][@21ki!]
    /* AT91_SYS->PIOC_ODR = AT91C_PIO_PC4; Configure as input */[!21ki@][@21ki!]
     AT91_SYS->PIOC_ODR = AT91C_PIO_PB29;[!21ki@][@21ki!]
     first_init = 1;[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
     else { [!21ki@][@21ki!]
     status = AT91_SYS->PIOC_ISR; /* clear any pending PIO interrupts */[!21ki@][@21ki!]
     AT91_SYS->PIOC_IER = AT91C_PIO_PB29; /* Enable interrupt */[!21ki@][@21ki!]
    spin_lock_irq(&lp->lock);[!21ki@][@21ki!]
     enable_mdi(regs);[!21ki@][@21ki!]
     read_phy(regs, MII_LXT971_INT_ENABLE, &dsintr);[!21ki@][@21ki!]
     dsintr = dsintr | 0x00f2; /* set bits 7..4 and 1 */[!21ki@][@21ki!]
     write_phy(regs, MII_LXT971_INT_ENABLE, dsintr);[!21ki@][@21ki!]
     disable_mdi(regs);[!21ki@][@21ki!]
     spin_unlock_irq(&lp->lock);[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    /*[!21ki@][@21ki!]
     * Disable the PHY interrupt[!21ki@][@21ki!]
     */[!21ki@][@21ki!]
    void disable_phyirq(struct net_device *dev, AT91PS_EMAC regs)[!21ki@][@21ki!]
    { [!21ki@][@21ki!]
     struct at91_private *lp = (struct at91_private *) dev->priv;[!21ki@][@21ki!]
     unsigned int dsintr;[!21ki@][@21ki!]
    spin_lock_irq(&lp->lock);[!21ki@][@21ki!]
     enable_mdi(regs);[!21ki@][@21ki!]
     read_phy(regs, MII_LXT971_INT_ENABLE, &dsintr);[!21ki@][@21ki!]
     dsintr = dsintr & 0x00f2; /* clear bits 8..11 */[!21ki@][@21ki!]
     write_phy(regs, MII_LXT971_INT_ENABLE, dsintr);[!21ki@][@21ki!]
     disable_mdi(regs);[!21ki@][@21ki!]
     spin_unlock_irq(&lp->lock);[!21ki@][@21ki!]
    AT91_SYS->PIOC_IDR = AT91C_PIO_PB29; /* Disable interrupt */[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    int at91ether_probe(struct net_device *dev)[!21ki@][@21ki!]
    { [!21ki@][@21ki!]
     AT91PS_EMAC regs = (AT91PS_EMAC) AT91C_VA_BASE_EMAC;[!21ki@][@21ki!]
     unsigned int phyid1, phyid2;[!21ki@][@21ki!]
     int detected = -1;[!21ki@][@21ki!]
    /* Configure the hardware - RMII vs MII mode */[!21ki@][@21ki!]
    #ifdef CONFIG_AT91_ETHER_RMII[!21ki@][@21ki!]
     AT91_CfgPIO_EMAC_RMII();[!21ki@][@21ki!]
    #else[!21ki@][@21ki!]
     AT91_CfgPIO_EMAC_MII();[!21ki@][@21ki!]
    #endif[!21ki@][@21ki!]
    AT91_SYS->PMC_PCER = 1 << AT91C_ID_EMAC; /* Enable Peripheral clock */[!21ki@][@21ki!]
    /* Read the PHY ID registers */[!21ki@][@21ki!]
     enable_mdi(regs);[!21ki@][@21ki!]
     read_phy(regs, MII_PHYSID1, &phyid1);[!21ki@][@21ki!]
     read_phy(regs, MII_PHYSID2, &phyid2);[!21ki@][@21ki!]
     disable_mdi(regs);[!21ki@][@21ki!]
    if (((phyid1 << 16) | (phyid2 & 0xfff0)) == MII_LXT971A_ID) { [!21ki@][@21ki!]
     detected = at91ether_setup(dev);[!21ki@][@21ki!]
     }[!21ki@][@21ki!]
    AT91_SYS->PMC_PCDR = 1 << AT91C_ID_EMAC; /* Disable Peripheral clock */[!21ki@][@21ki!]
    return detected;[!21ki@][@21ki!]
    }[!21ki@][@21ki!]
    另外,是否使用RMII接口在/include/config/at91/ether下面的rmii.h中定义[!21ki@][@21ki!]
    #define CONFIG_AT91_ETHER_RMII 1 将其改为[!21ki@][@21ki!]
    #undef CONFIG_AT91_ETHER_RMII[!21ki@][@21ki!]
    做完上述修改之后,就可以进行编译了.[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    9.2 内核的编译下载和执行[!21ki@][@21ki!]
    内核编译过程如下:[!21ki@][@21ki!]
    $ make at91rm9200dk_config[!21ki@][@21ki!]
    $ make oldconfig[!21ki@][@21ki!]
    如果想调整内核, $ make menuconfig[!21ki@][@21ki!]
    $ make bzImage[!21ki@][@21ki!]
    编译完后在/arch/arm/boot下生成映像文件. 如果想生成供U-BOOT下载使用的uImage文件, 接着执行:[!21ki@][@21ki!]
    $ /usr/local/arm/2.95.3/bin/arm-linux-objcopy -O binary -S vmlinux linux.bin[!21ki@][@21ki!]
    $ gzip -v9 linux.bin[!21ki@][@21ki!]
    $ mkimage -A arm -O linux -C gzip -a 0x20008000 -e 0x20008000 -d linux.bin.gz uImage[!21ki@][@21ki!]
    生成uImage以后,就可以用U-BOOT来下载并启动linux内核了,过程如下:(假设U-BOOT已经运行)[!21ki@][@21ki!]
    在linux主机下将uImage和ramdisk-rmk7拷贝到/tftpboot下[!21ki@][@21ki!]
    U-BOOT> setenv ethaddr 00:11:22:33:44:55:66[!21ki@][@21ki!]
    U-BOOT> setenv ipaddr 10.10.155.200[!21ki@][@21ki!]
    U-BOOT> setenv serverip 10.10.155.211[!21ki@][@21ki!]
    U-BOOT> tftp 21000000 uImage[!21ki@][@21ki!]
    U-BOOT> tftp 21100000 ramdisk-rmk7[!21ki@][@21ki!]
    U-BOOT> setenv bootargs root=/dev/ram rw initrd=0x21100000,6000000 ramdisk_size=15360 console=ttyS0,115200 mem=32M[!21ki@][@21ki!]
    U-BOOT> bootm 21000000[!21ki@][@21ki!]
    如果没有问题,就会看到linux的启动信息.linux内核启动之后, 用root (无密码) 登录. 如果想使用网络,还需要进行一些配置,例如:[!21ki@][@21ki!]
    [root@AT91RM9200DK /root]$ ifconfig eth0 down[!21ki@][@21ki!]
    [root@AT91RM9200DK /root]$ ifconfig eth0 10.10.155.2 up[!21ki@][@21ki!]
    另外,默认情况下是不可以更改9200的MAC地址的,如果想更改,在编译内核的时候,需要修改相应的头文件.[!21ki@][@21ki!]
    [!21ki@][@21ki!]
    花了两天的时间对前面的调试工作做了总结, 虽然这其中的很多东西对我来说都是第一次, 但总的来说过程还算顺利, 虽然遇到了不少的问题, 但都得到了比较好的解决, 在这里特别感谢网络上不知名的朋友们的帮助. 到现在为止, 工作才刚刚开始, 软件方面还有大量的工作需要去做, 希望自己能延续自己在前一段时间的好运气, 尽快将软件写完调通. 这也是我第一次使用linux, 第一次接触开源软件, 虽然以前也用C,但是接触了linux,读了其他优秀的源代码,突然感觉以前自己的写的C是多么的native, 多么的缺乏组织,呵呵. 就先写这么多了,以后有时间再写吧.[!21ki@][@21ki!]
posted @ 2007-08-04 21:52  曹立松  阅读(5451)  评论(2)    收藏  举报