有线通信
基于AX88796B的网络接口模块的设计与实现
网络技术应用日益普及的今天,工业现场的仪器仪表、数据采集和控制设备也日趋网络化,工业自动化和网络的结合越来越密切。而将以太网和嵌入式系统相结合应用于工业控制中已成为趋势。
AX88796B是Asix公司推出的一款为嵌入式和工业以太网应用而设计的低引脚数以太网控制芯片。其内部集成10/100Mb/s自适应的介质访问层MAC和物理层收发器PHY以及8K×16位的SRAM。AX88796B可应用于商业级0~70C和工业级-40C~85C的温度范围。AX88796B支持MCS-51系列、80186系列、ISA总线和SRAM-like接口类型。执行基于IEEE802.3/IEEE802.3u局域网标准的10Mb/s和100Mb/s以太网控制功能,并且提供发送队列功能来增强标准NE2000的发送性能。
AT91R40008微控制器是基于ARM7TDMI核的32位RISC结构的嵌入式微控制器,非常适于工业实时控制应用。AX88796B引脚的LQFP封装减少了PCB空间并且和NE2000兼容,编程简单,其驱动可以容易快速的移植到许多嵌入式系统中。因此,综合上述两种芯片的优点,我们选择AX88796B和AT91R40008作为工业实时控制中嵌入式网络应用的解决方案,具有很好的工业应用价值和前景。
图1 AX88796B内部结构图
AX88796B内部结构及工作原理
1 AX88796B的内部结构
网卡上电复位时EEPROM接口能够通过CSR中偏移为14H的SMI/EEPROM寄存器来存取数据,MAC地址由EEPROM中读取,并被自动载入地址为0000h~001fh和0400h~040fh的内部存储区中。如果没有使用EEPROM,每次上电对网卡进行初始化时候就手动给它分配一个MAC地址。
AX88796B内部有一个16KB(0x4000~0x7fff)大小的SRAM,该SRAM是双端口SRAM,可以同时被网卡读写和用户读写,这片地址空间的一部分被保留用来存放一个缓冲环结构,另一部分可以给用户使用。在本设计中,16KB的SRAM全部被用来接收和发送数据包。本地DMA正是通过这个缓冲环结构来接收报文的。这个结构由一连串相邻的固定长度为256B的缓冲区构成,每256字节称为一页,共有64页。页的地址就是地址的高8位,页地址为0x00~0xff。其中0x40~0x4B为网卡的发送缓冲区,共12页,刚好可以存储2个最大的以太网包,所以我们把发送缓冲区分成两部分进行轮流发送。使用0x4c~0x7f共52页为网卡的接收缓冲区。AX88796B的SRAM空间结构和收发缓冲区结构如图2、3所示。
图2 SRAM空间结构
图3 收发缓冲区
2 AX88796B的工作原理
由四个寄存器来控制接收缓冲区的操作。Page Start Address Register (PSTART)和Page Stop Address Register(PSTOP)定义了接收缓冲区的起始和终止页号,形成一个接收缓冲环。当前页地址寄存器(Current Page Register)指向第一个用于存储数据包的缓冲区。边界指针寄存器(Boundary Pointer Register)指向在缓冲环中第一个未被主机读取的数据包。如果本地DMA地址与Boundary Pointer Register的值相等,则接收过程中止。边界指针也被用来初始化远端DMA来移动一个数据包,当数据包被移走后,边界指针也向前增长。这样,Current Page Register如同一个写指针,Boundary Pointer如同一个读指针。接收到一个数据包时,从PSR中指定的页号开始存储,如果一个256B的缓冲区不够,DMA会执行一个前向连接来连接下一个缓冲区以存储这个数据包的剩余部分。连接的时候缓冲区必须是连续的,一个数据包总是会被存储在相邻的缓冲区里。在连接下一个缓冲区前,缓冲管理逻辑会执行两个比较,首先比较下一个缓冲区的DMA地址是否和page Stop Register相等,若相等,则DMA地址被恢复为page start address register中保存的地址。其次和boundary pointer register比较,如果相等,则接收报文过程终止。Boundary Pointer Register能够防止缓冲区里的数据还没有读出就被重写。
要发送和接收数据包就必须通过DMA读写AX88796B内部的SRAM。DMA分为远程DMA(Remote DMA)和本地DMA(Local DMA)。CPU从网卡的SRAM读写数据称为远端DMA。AX88796B读写SRAM称为本地DMA。数据包的接收过程:当数据包到达网卡的MAC层后,本地DMA先将到达MAC层的报文传送到网卡的内存中,主机CPU再通过远端DMA通道从网卡内存中读取数据包。数据包的发送过程:主机CPU通过远端DMA把要发送的数据包送到网卡的内存中,本地的DMA将该数据包传送到MAC层,再经由内部的PHY层发送至网络。
网络接口硬件设计
1 AX88796B的引脚配置
AX88796B与CPU的连接方式有MCS51模式、ISA模式、186模式,此方案使用了ISA 8bit模式。片选引脚CSn,读写信号RDn、WRn、RSTn都是低电平有效,分别和AT91r40008相应引脚相连即可。AX88796B的数据线SD0~SD15和AT91r40008的DATA[0:15]相连,可通过软件配置为16位或8位DMA数据传输方式。AX88796B的IRQ是可编程的,中断请求信号可以通过配置BTCR或EEPROM来选择其触发方式和中断I/O缓冲类型,AT91r40008中断触发方式应该和BTCR的配置相一致。其他重要引脚如IOIS16、PME、EECE、EECK在本设计中悬空处理。引脚配置应根据网卡芯片手册说明和设计方案而定。
对AX88796B控制状态寄存器(CSR)的操作,需要确定其基地址,基地址的选择应根据AT91r40008的可编程外部总线EBI的地址和片选信号来确定。AT91r40008的EBI处理位于地址空间0x00400000~0xFFC00000的访问操作,在访问过程中,它将产生外部器件的控制访问信号。当把网卡寄存器地址空间映射进EBI后,直接对EBI地址空间操作即可控制网卡的寄存器读写。对每个映射进EBI接口的外围器件,可以编程等待周期数、数据浮空时间、数据总线宽度(8位或16位)等。
2 AT91r40008与AX88796B接口电路
图4 硬件连接原理图
电路如图4所示。
AX88796B的驱动程序设计
AX88796B的网卡驱动程序是处理器CPU和网卡硬件的接口,网卡驱动程序主要包括以下几部分:网卡的初始化;数据包的接收和发送;中断处理子程序。
1 网卡初始化
在网卡的初始化过程中除了完成对相关寄存器的定义与赋值外,还要完成对接收缓冲环的构造。AX88796B的所有寄存器除了数据端口寄存器外都是8位数据宽度。数据端口寄存器可以通过配置DCR寄存器中的WTS设置成8位或16位宽。AX88796B将偏移量为01h~0fh的寄存器分为4页(Page0~Page3)进行操作。与NE2000兼容的寄存器只有3页(Page0~Page2)。初始化需要设置页0与页1的相关寄存器,页2的寄存器是只读的,不可以设置,页3的寄存器不是NE2000兼容的,不用设置。初始化函数主要要完成以下诸项工作。
/*AX88796B_init*/
/*调用复位子程序对AX88796B进行复位。有两种复位方式:一是硬件复位,通过拉高拉低RESET引脚达到复位AX88796B的目的;二是软件复位,从0x1f端口读数据使AX88796B复位。*/
ReadByte(RESET);
WriteByte(RESET,0xff);
delay(3000);
WriteByte(IMR,0);/*初始化中断屏蔽寄存器IMR,写入0x00,禁止所有中断请求。*/
WriteByte(CR,0x61);/*选中页1,停止AX88796B。*/
delay(1000);
WriteByte(CPR,0x4C);/*初始化接收缓冲环写页指针CPR=PSTART*/
WriteByte(PAR0~PAR5,MAC);/*设置网卡芯片MAC地址,清除多播地址寄存器。*/
WriteByte(MAR0~MAR7,0);
WriteByte(CR,0x21);/*停止网卡,切换到页0。*/
delay(1000);
WriteByte(BNRY,0x79);/*写边界指针寄存器(BNRY)为0x79;*/
WriteByte(PSTART,0x4c);/*设置接收缓冲区的起始页地址0x4c;*/
WriteByte(PSTOP,0x80);/*PSTOP接收缓冲区的结束页地址0x80;*/
WriteByte(TPSR,0x40);/*TPSR发送页的起始地址0x40;*/
WriteByte(DCR,0x80);/*设置数据配置寄存器为8位数据传输模式。*/
/*设置接收配置寄存器为0x4C,使接收缓冲区仅接收广播地址数据包和多点播送地址包。*/
WriteByte(RCR,0x4C);
/*设置TCR发送配置寄存器为0x80,采用全双工模式,当数据包长度小于60字节时自动填充,发送时附加CRC校验。*/
WriteByte(TCR,0x80);
WriteByte(ISR,0xFF);/*清除中断状态寄存器。*/
WriteByte(IMR,0x11);/*允许覆写中断和数据包接收中断。*/
WriteByte(BTCR,0x30);/*中断触发方式为高电平有效,IRQ输出为推挽驱动方式*/
WriteByte(CR,0x22);/*启动芯片,AX88796B初始化完成。*/
delay(1000);
wrcurpge=read(CPR);
rdnxtpge=wrcurpge;
2 数据包的发送和接收
判断AX88796B是否接收到新的数据包有两种方式:轮循和中断。单片机用轮循方式较多。为了提高CPU性能和实时性要求,这里采用中断方式。当网卡接收到新数据包时进入中断,首先判断CPR是否等于BNRY,若相等,则表示接收缓冲区已被存满,则停止接收数据包,而不会覆盖旧的数据;若不等,则将接收缓冲区中待读取的数据包的起始地址写入RSAR[0,1]寄存器,数据包的开始4字节写入RBCR[0,1]寄存器,并启动远端DMA读命令,通过读取4个信息字节得到待读取数据包的长度、接收状态和下一个将被读的页的指针信息。然后通过远端DMA读命令,将数据包从网卡SRAM中读入CPU内存中,并更新读页指针寄存器BNRY,CPU每从网卡内存中读走一页数据,BNRY便加一,这需要通过程序实现。网卡通过CPR将接收到的数据包写入接收缓冲区,每写完一页,CPR将自动加一,当加到最后的空页(这里是PSTOP=0x80)时,CPR将自动恢复为接收缓冲区的首页(PSTART=0x4c)。网卡接收关键性代码如下:
/*AX88796B_receive*/
uint8 rcvinfo[4],i;
uint16 pktlength,index;
/*得到待读取数据包的信息,并将其保存在rcvinfo数组中*/
WriteByte(RSAR0,0x00);
WriteByte(idx,RSAR1,rdnxtpge);
WriteByte(RBCR0,0x04);
WriteByte(RBCR1,0x00);
WriteByte(CR,0x0A);
for(i=0;i<4;i++)
rcvinfo[i]=*((uint8*)(DP_PORT+Base_addr));
pktlength=rcvinfo[2]+(rcvinfo[3]*256)-4;
/*根据得到的待读取数据包的长度pktlength,将数据包读入CPU内存Buf*/
WriteByte(RSAR0,0x4);
WriteByte(RSAR1,rdnxtpge);
WriteByte(RBCR0,(uint8)(pktlength&0x00ff));
WriteByte(RBCR1,(uint8)(pktlength>>8));
WriteByte(CR,0x0A);
ReadData(uint16*Buf,uint16 length);
/*更新BNRY指针,并返回pktlength值*/
rdnxtpge=rcvinfo[1];
if(rdnxtpge==PSTART)
WriteByte(idx,BNRY,PSTOP-1);
else
WriteByte(idx,BNRY,rdnxtpge-1);
return pktlength;
CPU通过远端DMA通道将网卡发送缓冲区的起始地址和要发送的字节数分别写入RSAR[0,1]和RBCR[0,1],然后启动远端DMA写命令即可将数据包写入网卡内存,此后将字节数写入TBCR[0,1]寄存器,启动发送命令就可将数据包发送到网络上。网卡发送的关键代码如下:
/*AX88796B_transmit*/
/*将数据写入网卡的发送缓冲区*/
WriteByte (RSAR0,0x00);
WriteByte (RSAR1,TX_BUF_Start);
WriteByte (RBCR0,(uint8)(len&0xFF));
WriteByte (RBCR1,(uint8)(len>>8));
WriteByte (CR,0x12);
WriteData((uint16*)addr,len);
WriteByte (idx,TPSR,TX_BUF_Start);
/*发送缓冲区的数据发送到网络*/
WriteByte (TBCR0,(uint8)(len&0xFF));
WriteByte (TBCR1,(uint8)(len>>8));
WriteByte (CR,0x26);
3 中断处理
中断的处理和CPU关联密切,在软件中必须先配置好网卡的片选线和中断信号线。数据包到来时,网卡将其保存在SARM中,同时触发一个中断。处理器接收到中断信号后,进入中断处理程序。在中断处理程序中读AX88796B的中断状态寄存器ISR来判断是什么样类型的中断,如果读出的值的最低位为1,则代表是数据包接收中断,这时需触发一个消息,进入到读网卡函数。读网卡函数的功能是将网络数据包从网卡的内存接收到主机中,接着向上层传递,进行相应的处理。
一个报文的发送过程就是通过调用写网卡函数,将报文发送到网卡的内存中去。然后将AX88796的控制寄存器(CR)的发送位TXP(Transmit packet)位置1,即将报文发送。
中断处理子程序的关键代码:
/*IRQ0_handler*/
uint8 InterruptStatus;
InterruptStatus=read(ISR);//读中断状态寄存器
write(IMR,0x00);//禁止中断
write(ISR,InterruptStatus);//清除中断状态寄存器
if(InterruptStatus&0x01)//是否为数据包接收中断
OSQPost(TcpIpMsgQ,&idx);//通知上位机接收到数据包
write(IMR,0x11);//使能接收中断和覆写中断
全部0条评论
快来发表一下你的评论吧 !