驱动网卡芯片DM9000调试过程及其具体的单片机程序Word下载.docx

上传人:b****8 文档编号:21954344 上传时间:2023-02-01 格式:DOCX 页数:21 大小:283.97KB
下载 相关 举报
驱动网卡芯片DM9000调试过程及其具体的单片机程序Word下载.docx_第1页
第1页 / 共21页
驱动网卡芯片DM9000调试过程及其具体的单片机程序Word下载.docx_第2页
第2页 / 共21页
驱动网卡芯片DM9000调试过程及其具体的单片机程序Word下载.docx_第3页
第3页 / 共21页
驱动网卡芯片DM9000调试过程及其具体的单片机程序Word下载.docx_第4页
第4页 / 共21页
驱动网卡芯片DM9000调试过程及其具体的单片机程序Word下载.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

驱动网卡芯片DM9000调试过程及其具体的单片机程序Word下载.docx

《驱动网卡芯片DM9000调试过程及其具体的单片机程序Word下载.docx》由会员分享,可在线阅读,更多相关《驱动网卡芯片DM9000调试过程及其具体的单片机程序Word下载.docx(21页珍藏版)》请在冰豆网上搜索。

驱动网卡芯片DM9000调试过程及其具体的单片机程序Word下载.docx

1、读、写寄存器

其实,INDEX端口和DATA端口的就是由芯片上的CMD引脚来区分的。

低电平为INDEX端口,高电平为DATA端口。

所以,要想实现读写寄存器,就必须先控制好CMD引脚。

若使用总线接口连接DM9000的话,假设总线连接后芯片的基地址为0x800300(24根地址总线),只需如下方法:

#defineDM_ADD(*((volatileunsignedint*)0x8000300))

#defineDM_CMD(*((volatileunsignedint*)0x8000304))

//向DM9000寄存器写数据

voiddm9000_reg_write(unsignedcharreg,unsignedchardata)

{

udelay(20);

//之前定义的微妙级延时函数,这里延时20us

DM_ADD=reg;

//将寄存器地址写到INDEX端口

DM_CMD=data;

//将数据写到DATA端口,即写进寄存器

}

//从DM9000寄存器读数据

unsignedintdm9000_reg_read(unsignedcharreg)

returnDM_CMD;

//将数据从寄存器中读出

只得注意的是前面的两个宏定义DM_ADD和DM_CMD,定义的内容表示指向无符号整形变量的指针,在这里0x800300是DM9000命令端口的地址,对它的赋值操作就相当于把数据写到该地址中,即把数据写到DM9000的命令端口中。

读的道理也一样。

这是一种很常见的宏定义,一般在处理器中定义通用寄存器也是这样定义的。

若没有总线接口的话,可以使用IO口模拟总线时序的方法实现寄存器的读写。

这里只说明实现步骤。

首先将处理器的I/O端口与DM9000的IOR等引脚直接相连(电平匹配的情况下),又假设已经有宏定义“IOR”I/O端口控制DM9000的IOR引脚,其它端口控制DM9000引脚的命名相同,“PIO1”(根据处理器情况,可以是8位、16位或32位的I/O端口组成)控制数据端口。

这样宏命名更直观些。

写寄存器的函数如下:

PIO1=reg;

AEN=0;

CMD=0;

IOR=1;

IOW=0;

udelay

(1);

AEN=1;

IOW=1;

udelay(20);

PIO1=data;

读寄存器的写法类似,这里就略一下了。

这一过程看上去有些复杂,呵呵,其实执行起来也蛮有效率的,执行时间差不多。

这种模拟总线时序的方式实际并不复杂,只是把总线方式下自动执行的过程手动的执行了一遍而已。

在DM9000中,还有一些PHY寄存器,也称之为介质无关接口MII(MediaIndependentInterface)寄存器。

对这些寄存器的操作会影响网卡芯片的初始化和网络连接,这里不对其进行操作,所以对这些寄存器的访问方法这里也略了(在上篇文章中有介绍)。

操作不当反而使网卡不能连接到网络。

至此,我们已经写好了两个最基本的函数:

dm9000_reg_write()和dm9000_reg_read(),以及前面的宏定义DM_ADD和DM_CMD。

下面将一直用到。

2、初始化DM9000网卡芯片。

初始化DM9000网卡芯片的过程,实质上就是填写、设置DM9000的控制寄存器的过程,这里以程序为例进行说明。

其中寄存器的名称宏定义在DM9000.H中已定义好。

注:

一下函数中unsignedchar为一个字节unsignedint为两个字节

//DM9000初始化

voidDM9000_init(void)

unsignedinti;

IO0DIR|=1<

<

8;

IO1CLR|=1<

udelay(500000);

IO2SET|=1<

/*以上部分是利用一个IO口控制DM9000的RST引脚,使其复位。

这一步可以省略,可以用下面的软件复位代替*/

dm9000_reg_write(GPCR,0x01);

//设置GPCR(1EH)bit[0]=1,使DM9000的GPIO3为输出。

dm9000_reg_write(GPR,0x00);

//GPRbit[0]=0使DM9000的GPIO3输出为低以激活内部PHY。

udelay(5000);

//延时2ms以上等待PHY上电。

dm9000_reg_write(NCR,0x03);

//软件复位

udelay(30);

//延时20us以上等待软件复位完成

dm9000_reg_write(NCR,0x00);

//复位完成,设置正常工作模式。

//第二次软件复位,为了确保软件复位完全成功。

此步骤是必要的。

/*以上完成了DM9000的复位操作*/

dm9000_reg_write(NSR,0x2c);

//清除各种状态标志位

dm9000_reg_write(ISR,0x3f);

//清除所有中断标志位

/*以上清除标志位*/

dm9000_reg_write(RCR,0x39);

//接收控制

dm9000_reg_write(TCR,0x00);

//发送控制

dm9000_reg_write(BPTR,0x3f);

dm9000_reg_write(FCTR,0x3a);

dm9000_reg_write(RTFCR,0xff);

dm9000_reg_write(SMCR,0x00);

/*以上是功能控制,具体功能参考上一篇文章中的说明,或参考数据手册的介绍*/

for(i=0;

i<

6;

i++)

dm9000_reg_write(PAR+i,mac_addr[i]);

//mac_addr[]自己定义一下吧,6个字节的MAC地址

/*以上存储MAC地址(网卡物理地址)到芯片中去,这里没有用EEPROM,所以需要自己写进去*/

/*关于MAC地址的说明,要参考网络相关书籍或资料*/

/*为了保险,上面有清除了一次标志位*/

dm9000_reg_write(IMR,0x81);

/*中断使能(或者说中断屏蔽),即开启我们想要的中断,关闭不想要的,这里只开启的一个接收中断*/

/*以上所有寄存器的具体含义参考上一篇文章,或参考数据手册*/

这样就对DM9000初始化完成了,怎么样,挺简单的吧。

3、发送、接收数据包

同样,以程序为例,通过注释说明。

//发送数据包

//参数:

datas为要发送的数据缓冲区(以字节为单位),length为要发送的数据长度(两个字节)。

voidsendpacket(unsignedchar*datas,unsignedintlength)

unsignedintlen,i;

dm9000_reg_write(IMR,0x80);

//先禁止网卡中断,防止在发送数据时被中断干扰

len=length;

dm9000_reg_write(TXPLH,(len>

>

8)&

0x0ff);

dm9000_reg_write(TXPLL,len&

/*这两句是将要发送数据的长度告诉DM9000的寄存器*/

DM_ADD=MWCMD;

//这里的写法是针对有总线接口的处理器,没有总线接口的处理器要注意加上时序。

len;

i+=2)//16bitmode

{

DM_CMD=datas[i]|(datas[i+1]<

8);

}

/*上面是将要发送的数据写到DM9000的内部SRAM中的写FIFO中,注意没有总线接口的处理器要加上适当的时序*/

/*只需要向这个寄存器中写数据即可,MWCMD是DM9000内部SRAM的DMA指针,根据处理器模式,写后自动增加*/

dm9000_reg_write(TCR,0x01);

//发送数据到以太网上

while((dm9000_reg_read(NSR)&

0x0c)==0);

//等待数据发送完成

//清除状态寄存器,由于发送数据没有设置中断,因此不必处理中断标志位

//DM9000网卡的接收中断使能

以上是发送数据包,过程很简单。

而接收数据包确需要些说明了。

DM9000从网络中接到一个数据包后,会在数据包前面加上4个字节,分别为“01H”、“status”(同RSR寄存器的值)、“LENL”(数据包长度低8位)、“LENH”(数据包长度高8位)。

所以首先要读取这4个字节来确定数据包的状态,第一个字节“01H”表示接下来的是有效数据包,若为“00H”则表示没有数据包,若为其它值则表示网卡没有正确初始化,需要从新初始化。

如果接收到的数据包长度小于60字节,则DM9000会自动为不足的字节补上0,使其达到60字节。

同时,在接收到的数据包后DM9000还会自动添加4个CRC校验字节。

可以不予处理。

于是,接收到的数据包的最小长度也会是64字节。

当然,可以根据TCP/IP协议从首部字节中出有效字节数,这部分在后面讲解。

下面为接收数据包的函数。

//接收数据包

datas为接收到是数据存储位置(以字节为单位)

//返回值:

接收成功返回数据包类型,不成功返回0

unsignedintreceivepacket(unsignedchar*datas)

unsignedinti,tem;

unsignedintstatus,len;

unsignedcharready;

ready=0;

//希望读取到“01H”

status=0;

//数据包状态

len=0;

//数据包长度

/*以上为有效数据包前的4个状态字节*/

if(dm9000_reg_read(ISR)&

0x01)

dm9000_reg_write(ISR,0x01);

/*清除接收中断标志位*/

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

/*这个地方遇到了问题,下面的黑色字体语句应该替换成成红色字体,也就是说MRCMDX寄存器如果第一次读不到数据,还要读一次才能确定完全没有数据。

在做PING实验时证明:

每个数据包都是通过第二次的读取MRCMDX寄存器操作而获知为有效数据包的,对初始化的寄存器做了多次修改依然是此结果,但是用如下方法来实现,绝不会漏掉数据包。

*/

ready=dm9000_reg_read(MRCMDX);

//第一次读取,一般读取到的是00H

if((ready&

0x0ff)!

=0x01)

ready=dm9000_reg_read(MRCMDX);

//第二次读取,总能获取到数据

0x01)!

=0x00)//若第二次读取到的不是01H或00H,则表示没有初始化成功

//屏幕网卡中断

DM9000_init();

//重新初始化

//打开网卡中断

retrun0;

/*ready=dm9000_reg_read(MRCMDX);

//readabytewithoutpointerincrement

if(!

(ready&

0x01))

return0;

}*/

/*以上表示若接收到的第一个字节不是“01H”,则表示没有数据包,返回0*/

status=dm9000_reg_read(MRCMD);

len=DM_CMD;

(status&

0xbf00)&

&

(len<

1522))

i+=2)//16bitmode

tem=DM_CMD;

datas[i]=tem&

0x0ff;

datas[i+1]=(tem>

8)&

else

/*以上接收数据包,注意的地方与发送数据包的地方相同*/

if(len>

1000)return0;

if((HON(ETHBUF->

type)!

=ETHTYPE_ARP)&

(HON(ETHBUF->

=ETHTYPE_IP))

packet_len=len;

/*以上对接收到的数据包作一些必要的限制,去除大数据包,去除非ARP或IP的数据包*/

returnHON(ETHBUF->

type);

//返回数据包的类型,这里只选择是ARP或IP两种类型

注意:

上面的函数用到了一些宏定义,已经在头文件中定义过,这里说明一下:

其中uint16定义为两个字节的变量,根据C编译器进行定义。

unsignedcharBuffer[1000];

//定义了一个1000字节的接收发送缓冲区

uint16packet_len;

//接收、发送数据包的长度,以字节为单位。

structeth_hdr//以太网头部结构,为了以后使用方便

unsignedchard_mac[6];

//目的地址

unsignedchars_mac[6];

//源地址

uint16type;

//协议类型

};

structarp_hdr//以太网头部+ARP首部结构

structeth_hdrethhdr;

//以太网首部

uint16hwtype;

//硬件类型(1表示传输的是以太网MAC地址)

uint16protocol;

//协议类型(0x0800表示传输的是IP地址)

unsignedcharhwlen;

//硬件地址长度(6)

unsignedcharprotolen;

//协议地址长度(4)

uint16opcode;

//操作(1表示ARP请求,2表示ARP应答)

unsignedcharsmac[6];

//发送端MAC地址

unsignedcharsipaddr[4];

//发送端IP地址

unsignedchardmac[6];

//目的端MAC地址

unsignedchardipaddr[4];

//目的端IP地址

structip_hdr//以太网头部+IP首部结构

unsignedcharvhl, 

//4位版本号4位首部长度(0x45)

tos;

//服务类型(0)

uint16len, 

//整个IP数据报总字节长度

ipid, 

//IP标识

ipoffset;

//3位标识13位偏移

unsignedcharttl, 

//生存时间(32或64)

proto;

//协议(1表示ICMP,2表示IGMP,6表示TCP,17表示UDP)

uint16ipchksum;

//首部校验和

unsignedcharsrcipaddr[4], 

//源IP

destipaddr[4];

//目的IP

以上定义的三种首部结构,是根据TCP/IP协议的相关规范定义的,后面会对ARP协议进行详细讲解。

【上半部分完】

4、验证初始化中的各个函数。

下面我们来看一下,上面所写的初始化函数是否可用。

以上我们写好了三个函数,分别为

DM9000_init(),sendpacket()和receivepacket(),保存并命名为dm9000.c。

既然我们要进行调试,当

然要有结果输出,根据自己的处理器的情况写一个串口程序,这些函数是学某个单片机的基础,这里不

做详细介绍,用到是时候会在函数里注释一下。

接下来我们来写个主函数,新建C文件,命名为mian.c,填写如下函数:

voidmain(void)

unsignedcharc;

uart0_init();

//初始化串口,调试时用到

//初始化网卡

print_regs();

/*通过串口,将DM9000中的寄存器打印出来,显示在超级终端上。

此函数根据自己

的处理器进行修改,功能仅仅是读DM9000寄存器dm9000_reg_read(),再通过串口打印出来而已*/

函数写好,保存文件,连接硬件,连接网线到电脑上或局域网上,运行结果如下图所示:

图4显示寄存器值

这里首先检查,各个控制寄存器是否是自己写进去的值,在检查状态寄存器是否正确,其中主要要

看NSR寄存器的bit[5]是否为“1”,该位表示是否连接成功。

本例中NSR的值为40H,括号里

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 学习总结

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1