网络关于嵌入式体系来说必不可少。但是s3c2440没有集成以太网接口,所以要想使s3c2440具有以太网的功用,就有必要扩展网卡接口。在这儿,咱们外接DM9000,使其能够与以太网相衔接。
DM9000能够直接与ISA总线相连,也能够与大多数CPU相连。在这儿,咱们当然是要让DM9000与s3c2440相衔接了。DM9000对外来说只需两个端口——地址口和数据口,地址口用于输入内部寄存器的地址,而数据口则完结对某一寄存器的读写。DM9000的CMD引脚用来委任这两个端口,当CMD引脚为0时,DM9000的数据线上传输的是寄存器地址,当CMD引脚为1时,传输的是读写数据。咱们把DM9000的A8和A9接为高电平,把A4~A7接为低电平,而且把DM9000的AEN接到s3c2440的nGCS4引脚上,则DM9000的端口基址为0x20000300,假如再把DM9000的CMD引脚接到s3c2440的ADDR2引脚上,则咱们就能够界说DM9000的这两个端口地址,它们分别为:
#define DM_ADDR_PORT(*((volatile unsigned short *) 0x20000300))//地址口
#define DM_DATA_PORT(*((volatile unsigned short *) 0x20000304))//数据口
假如要写入DM9000中的某个寄存器,则先把该寄存器的地址赋予DM_ADDR_PORT,然后再把要写入的数据赋予DM_DATA_PORT即可。读取DM9000中的某个寄存器也类似。下面的函数的效果分别是DM9000的读、写寄存器操作:
//写DM9000寄存器
void __inline dm_reg_write(unsigned char reg, unsigned char data)
{
DM_ADDR_PORT = reg;//将寄存器地址写到地址端口
DM_DATA_PORT = data;//将数据写到数据端口
}
//读DM9000寄存器
unsigned char __inline dm_reg_read(unsigned char reg)
{
DM_ADDR_PORT = reg;
return DM_DATA_PORT;//将数据从数据端口读出
}
完结了对DM9000寄存器的读写函数的编写,下面咱们就能够初始化DM9000,它的进程便是恰当装备DM9000寄存器的进程。DM9000的内部寄存器在这儿就不做介绍,而且DM9000的使用数据手册也有怎么初始化DM9000的过程,咱们这儿只给出详细的程序:
void dm_init(void)
{
dm_reg_write(DM9000_NCR,1);//软件复位DM9000
delay(30);//延时至少20μs
dm_reg_write(DM9000_NCR,0);//铲除复位位
dm_reg_write(DM9000_NCR,1);//为了保证复位正确,再次复位
delay(30);
dm_reg_write(DM9000_NCR,0);
dm_reg_write(DM9000_GPCR,1);//设置GPIO0为输出
dm_reg_write(DM9000_GPR,0);//激活内部PHY
dm_reg_write(DM9000_NSR,0x2c);//清TX状况
dm_reg_write(DM9000_ISR,0xf);//清中止状况
dm_reg_write(DM9000_RCR,0x39);//设置RX操控
dm_reg_write(DM9000_TCR,0);//设置TX操控
dm_reg_write(DM9000_BPTR,0x3f);
dm_reg_write(DM9000_FCTR,0x3a);
dm_reg_write(DM9000_FCR,0xff);
dm_reg_write(DM9000_SMCR,0x00);
dm_reg_write(DM9000_PAR1,0x00);//设置MAC地址:00-01-02-03-04-05
dm_reg_write(DM9000_PAR2,0x01);
dm_reg_write(DM9000_PAR3,0x02);
dm_reg_write(DM9000_PAR4,0x03);
dm_reg_write(DM9000_PAR5,0x04);
dm_reg_write(DM9000_PAR6,0x05);
dm_reg_write(DM9000_NSR,0x2c);//再次清TX状况
dm_reg_write(DM9000_ISR,0xf);//再次清中止状况
dm_reg_write(DM9000_IMR,0x81);//翻开承受数据中止
}
DM9000内部有0x3FF巨细的SRAM用于承受和发送数据缓存。在发送或接纳数据包之前,数据是暂存在这个SRAM中的。当需求接连发送或接纳数据时,咱们需求分别把DM9000寄存器MWCMD或MRCMD赋予数据端口,这样就指定了SRAM中的某个地址,而且在传输完一个数据后,指针会指向SRAM中的下一个地址,然后完结了接连拜访数据的意图。但当咱们在发送或承受一个数据后,指向SRAM的数据指针不需求变化时,则要把MWCMDX或MRCMDX赋予数据端口。下面的程序为DM9000发送数据的函数,它的两个输入参数分别为要发送数据数组首地址和数据数组长度。在这儿咱们现已知道数据的宽为16位,它是由DM9000的硬件引脚设置完结的。
void dm_tran_packet(unsigned char *datas, int length)
{
int i;
dm_reg_write(DM9000_IMR, 0x80);//在发送数据进程中制止网卡中止
dm_reg_write(DM9000_TXPLH, (length>>8) & 0x0ff);//设置发送数据长度
dm_reg_write(DM9000_TXPLL, length & 0x0ff);
DM_ADDR_PORT = DM9000_MWCMD;//发送数据缓存赋予数据端口
//发送数据
for(i=0;i
delay(50);
DM_DATA_PORT = datas[i]|(datas[i+1]<<8);//8位数据转换为16位数据输出
}
dm_reg_write(DM9000_TCR, 0x01);//把数据发送到以太网上
while((dm_reg_read(DM9000_NSR) & 0x0c) == 0)
;//等候数据发送完结
delay(50);
dm_reg_write(DM9000_NSR, 0x2c);//铲除TX状况
dm_reg_write(DM9000_IMR, 0x81);//翻开DM9000接纳数据中止
}
发送数据比较简略,接纳数据就略显杂乱,咱们它是有必定格局要求的。在接纳到的一包数据中的首字节假如为0x01,则一共这是一个能够接纳的数据包;假如为0x0,则一共没有可接纳的数据包。因而在读取其他字节时,必定要先判别首字节是否为0x01。数据包的第二个字节为数据包的一些信息,它的高字节的格局与DM9000的寄存器RSR完全一致。第三个和第四个字节为数据包的长度。后边的数据便是真实要接纳的数据了。下面便是DM9000接纳数据的程序,其间输入参数为寄存输入数据数组的首地址,输出参数为接纳数据的长度。
int dm_rec_packet(unsigned char *datas)
{
unsigned char int_status;
unsigned char rx_ready;
unsigned short rx_status;
unsigned short rx_length;
unsigned short temp;
int i;
int_status = dm_reg_read(DM9000_ISR);//读取ISR
if(int_status & 0x1)//判别是否有数据要承受
{
rx_ready = dm_reg_read(DM9000_MRCMDX);//先读取一个无效的数据
rx_ready = (unsigned char)DM_DATA_PORT;//真实读取到的数据包首字节
if(rx_ready == 1)//判读首字节是否为1或0
{
DM_ADDR_PORT = DM9000_MRCMD;//接连读取数据包内容
rx_status = DM_DATA_PORT;//状况字节
rx_length = DM_DATA_PORT;//数据长度
if(!(rx_status & 0xbf00) && (rx_length < 10000))//判读数据是否符合要求
{
for(i=0; i
delay(50);
temp = DM_DATA_PORT;
datas[i] = temp & 0x0ff;
datas[i + 1] = (temp >> 8) & 0x0ff;
}
}
}
else if(rx_ready !=0)//中止设备
{
//dm_reg_write(DM9000_IMR,0x80);//中止中止
//dm_reg_write(DM9000_ISR,0x0F);//清中止状况
//dm_reg_write(DM9000_RCR,0x0);//中止接纳
//还需求复位体系,这儿暂时没有处理
}
}
dm_reg_write(DM9000_ISR, 0x1);//清中止
return rx_length;
}
关于DM9000的设置咱们就介绍到这儿,下面便是s3c2440的设置。在这儿,网卡发送数据使用的是查询方法,接纳数据使用的是中止方法,因而咱们把DM9000的INT引脚衔接到了s3c2440的EINT7上。别的咱们仍是用UART0接口来操控和显现网卡数据。这两个接口的初始化为:
//uart0 port
rGPHCON = 0x00faaa;
rGPHUP= 0x7ff;
rULCON0 = 0x3;
rUCON0 = 0x5;
rUFCON0 = 0;
rUMCON0 = 0;
rUBRDIV0 = 26;
rSRCPND = (0x1<<27)|(0x1<<28);
rSUBSRCPND = 0x1;
rINTPND = (0x1<<27)|(0x1<<28);
rINTSUBMSK = ~(0x1);
rINTMSK = ~((0x1<<27)|(0x1<<28));
pISR_UART0 = (U32)uartISR;
//EINT7
rGPFCON = 2<<14;
rEXTINT0 = (rEXTINT0 & (~(0x07<<28))) | (0x01<<28);
rEINTMASK &= ~(1<<7);
rSRCPND = rSRCPND | (0x1<<4);
rINTPND = rINTPND | (0x1<<4);
rINTMSK &= ~(1<<4);
pISR_EINT4_7 = (U32)DM9000ISR;
下面就使用DM9000来进行简略的网卡传输数据的检验。咱们以太网传输数据都是根据某种协议的,因而要传输数据,有必要遵从必定的协议格局。这儿咱们完结较为简略的ARP协议。用于以太网的ARP恳求/应对分组格局为:14个字节的以太网首部+28个字节ARP恳求/应对。以太网首部的格局为:6个字节的以太网方针地址+6个字节以太网源地址+2个字节帧类型,关于ARP来说,帧类型为0x0806。ARP恳求/应对的格局为:2个字节的硬件类型+2个字节的协议类型+1个字节的硬件地址长度+1个字节的协议地址长度+2个字节的操作码+6个字节的发送端以太网地址+4个字节的发送端IP地址+6个字节的方针以太网地址+4个字节的方针IP地址。硬件类型为1一共的是以太网,协议类型为0x0800一共的是IP地址,硬件地址长度和协议地址长度分别为6和4,它们都是以字节为单位的,操作码为1一共的是ARP恳求,为2一共的是ARP应对。
鄙人面的测验程序中,咱们用穿插网线把开发板与PC机(操作体系为Windows XP,网卡的IP地址为192.168.1.120)相衔接,咱们经过UART宣布一个指令,让开发板宣布一个ARP恳求数据包,然后接纳来自PC机的应对,并把该应对信息经过UART显现出来。其间UART的中止复位程序为:
void __irq uartISR(void)
{
char ch;
rSUBSRCPND |= 0x1;
rSRCPND |= 0x1<<28;
rINTPND |= 0x1<<28;
ch=rURXH0;
if(ch == 0x33)
comm=3;//一共发送一个ARP数据恳求包
rUTXH0=ch;
}
别的咱们还要事前界说一个遵从ARP协议格局的数组:
unsigned char arpsendbuf[42]={
0xff,0xff,0xff,0xff,0xff,0xff,//以太网方针地址,全1一共为播送地址
0x00,0x01,0x02,0x03,0x04,0x05,//以太网源地址
0x08,0x06,//帧类型:ARP帧
0x00,0x01,//硬件类型:以太网
0x08,0x00,//协议类型:IP协议
0x06,//硬件地址长度:6字节
0x04,//协议地址长度:4字节
0x00,0x01,//操作码:ARP恳求
0x00,0x01,0x02,0x03,0x04,0x05,//发送端以太网硬件地址
192, 168, 1, 50,//发送端IP协议地址
0x00,0x00,0x00,0x00,0x00,0x00,//接纳端以太网硬件地址
192, 168, 1, 120//接纳端IP协议地址
};
其间发送端硬件地址,即以太网源地址(00-01-02-03-04-05)是咱们初始化DM9000时界说的。而发送端IP协议地址是咱们恣意界说的。
该测验程序的主程序为:
void Main(void)
{
…………
//一些必要的初始化
comm=0;//指令
flag=0;//发送ARP恳求包标识
dm_init();//DM9000初始化
while(1)
{
if(comm.==3)
{
comm=0;
dm_tran_packet(arpsendbuf, 42 );//发送ARP恳求包
flag=1;//置标识
}
}
}
接纳网络上的数据是经过外部中止方法的,在这个中止处理程序中,首要完结的是接纳网卡数据,并把接纳到的数据发送到UART,让其显现到PC机上。这儿咱们还需处理一个问题,那便是当咱们发送一个ARP恳求包的时分,XP体系并不会应对一个ARP数据包,而是应对一个IP协议数据包,当再屡次宣布ARP恳求包后,才会得到ARP应对包。因而当s3c2440发送ARP恳求包后,它首要要查看所接纳到的数据包,假如不是ARP应对包,它就要再次发送ARP恳求包,直到得到ARP应对包学校。因而中止处理程序为:
void __irq DM9000ISR(void)
{
int i;
rSRCPND = rSRCPND | (0x1<<4);
rINTPND = rINTPND | (0x1<<4);
if(rEINTPEND&(1<<7))
{
rEINTPEND = rEINTPEND | (0x1<<7);
packet_len = dm_rec_packet(buffer);//接纳网卡数据
if((buffer[12]==0x08)&&(buffer[13]==0x06))//是ARP协议
{
//经过UART显现出来
for(i=0;i
while(!(rUTRSTAT0 & 0x2)) ;
rUTXH0 = buffer[i];
}
flag=0;//清标志
}
else if(flag==1)//假如在宣布ARP恳求包后,接纳到的数据不是ARP协议
{
comm=3;//持续发送ARP恳求包
}
}
}
这样,整个网卡程序就编写结束。为了使咱们对程序的因果关系认识得愈加明晰,咱们再叙说一遍程序的流程:首要初始化UART0,使其用中止方法接纳数据,查询方法发送数据;初始化EINT7,这是咱们DM9000的数据中止引脚INT是衔接到s3c2440的外部中止7引脚上的;然后初始化DM9000,首要是装备一些它的寄存器,并使其用中止方法接纳网卡数据,查询方法发送数据,这与UART0类似,最终是死循环等候UART0接纳中止服务程序中得到的发送ARP恳求包指令。当得到发送ARP恳求包指令后,调用DM9000发送数据指令,发送事前准备好的一组数据。在发送完ARP数据后,PC时机应对该恳求,然后引发s3c2440外部中止7中止,在该中止服务程序中,首要是完结接纳ARP应对包的使命,并把它经过UART0显现出来。
当程序被执行完,并在PC机上经过串口调试软件显现出了一个正确的ARP应对包后,咱们还能够经过下列方法来进一步验证该程序的正确性:翻开Windows XP体系只带的“指令提示符”小软件,在提示符下输入:arp –a,会呈现咱们所设置的开发板的MAC地址(00-01-02-03-04-05)和IP地址(192.168.1.50),则阐明Windows XP体系现已把咱们开发板上的网卡信息增加到了它的静态列表中。
咱们对该体系进一步剖析还会发现,当开发板上电而且DM9000初始化完结后,Windows XP体系会向该开发板发送一些方针地址为播送地址(FF-FF-FF-FF-FF-FF)的ARP数据包和IP数据包,只需咱们正确读取它们,就能够在开发板上电后,主动知道与其相连的体系的MAC地址和IP地址了。别的,假如对这一部分感兴趣,还能够编写ICMP协议的数据包,这样就能够让PC机ping通咱们的开发板了。