1. 网卡硬件结构(DM9000A)
网卡的实质就是MAC通过MII接口控制PHY的过程。
MAC主要负责数据帧的构建、数据差错检查、传送控制等。
PHY是物理接口收发器,属于物理层,当它收到MAC过来的数据时,它会去加上校验码,然后按照物理层的规则进行数据编码,再发送到传输介质上,接收过程则相反。
MII:媒体独立接口, “媒体独立”表明MAC一定情况下,任何类型的PHY设备都可以正常工作。
2. DM9000A硬件接口
由上图得到以下信息:
dm9000的片选信号CS#接到Xm0CSn1,Xm0CSn1选择的是Bank1,那么片选的起始地址为0x18000000;cmd引脚接到Xm0ADDR2,那么数据端口地址为0x18000004。
3. 软件设计
3.1 设置SROM Register
读写时序控制
3.2 设置DM9000A相关参数(初始化)
参考uboot
3.3 初步测试
测试结果与设置的一样,说明读写操作正常。
测试代码:
1 //各种初始化...包括串口初始化等等 2 //下面是读取一些芯片的出厂信息 3 tmp = (unsigned char)ior(0x2c); 4 printf("CHIP Revision:%2x ", tmp); 5 tmp = (unsigned char)ior(0x28); 6 printf("Vendor ID_L:%2x ", tmp); 7 tmp = (unsigned char)ior(0x29); 8 printf("Vendor ID_H:%2x ", tmp); 9 tmp = (unsigned char)ior(0x2a); 10 printf("Product ID_L:%2x ", tmp); 11 tmp = (unsigned char)ior(0x2b); 12 printf("Product ID_H:%2x ", tmp);
4. ARP协议实现
4.1 基础知识
4.1.1 以太网的格式
目的MAC地址:接收者的物理地址;源MAC地址:发送者的物理地址;类型:标明高层的数据使用的协议类型;数据:高层的数据;CRC:校验码
4.1.2 ARP功能
在以太网络中,每台计算机的唯一身份标示是MAC地址(物理层的地址),两台计算机要进行通讯,也必须知道对方的MAC地址,但是用户通常只知道对方的IP地址,这个时候,就可以利用ARP(地址解析协议)来向局域网中的所有计算机发送ARP请求包,收到请求包且满足条件的计算机将回复ARP应答包,告知其MAC地址。所以ARP协议是一种利用IP地址或者MAC地址的协议.
4.1.3 ARP格式
ARP包分为请求包和应答包,通过OP字段来区别。
4.2 ARP收发
注意字节序!
5. 代码
1 #include "arp.h" 2 3 #define HON(n) ((((u16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8)) 4 5 /*1.发送arp请求包*/ 6 void arp_request() 7 { 8 /*1.构成arp请求包*/ 9 memcpy(arpbuf.ethhdr.d_mac,host_mac_addr,6); 10 memcpy(arpbuf.ethhdr.s_mac,mac_addr,6); 11 arpbuf.ethhdr.type = HON(0x0806); 12 13 arpbuf.hwtype = HON(1); 14 arpbuf.protocol = HON(0x0800); 15 16 arpbuf.hwlen = 6; 17 arpbuf.protolen = 4; 18 19 arpbuf.opcode = HON(1); 20 21 memcpy(arpbuf.smac,mac_addr,6); 22 memcpy(arpbuf.sipaddr,ip_addr,4); 23 memcpy(arpbuf.dipaddr,host_ip_addr,4); 24 25 packet_len = 14+28; 26 27 /*2.调用dm9000发送函数,发送应答包*/ 28 dm9000_tx(buffer,packet_len); 29 } 30 31 32 /*2.解析arp应答包,提取mac*/ 33 u8 arp_process() 34 { 35 36 u32 i; 37 38 if (packet_len<28) 39 return 0; 40 41 memcpy(host_ip_addr,arpbuf.sipaddr,4); 42 printf("host ip is : "); 43 for(i=0;i<4;i++) 44 printf("%03d ",host_ip_addr[i]); 45 printf(" "); 46 47 memcpy(host_mac_addr,arpbuf.smac,6); 48 printf("host mac is : "); 49 for(i=0;i<6;i++) 50 printf("%02x ",host_mac_addr[i]); 51 printf(" "); 52 53 }
1 #include "dm9000.h" 2 #include "printf.h" 3 #include "arp.h" 4 5 6 // SROM Controller 7 #define SROM_BW (*((volatile unsigned long*)0x70000000)) 8 #define SROM_BC1 (*((volatile unsigned long*)0x70000008)) 9 10 #define IOADDR (*((volatile unsigned short*)0x18000000)) 11 #define IODATA (*((volatile unsigned short*)0x18000004)) 12 13 u8 *buffer = &arpbuf; 14 15 u8 host_mac_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; 16 u8 mac_addr[6] = {9,8,7,6,5,4};//随意 17 u8 ip_addr[4] = {192,168,1,66}; 18 u8 host_ip_addr[4] = {192,168,1,105}; 19 u16 packet_len; 20 21 22 void delay(int n) 23 { 24 int i,j; 25 for(i=0;i<1000;i++) 26 { 27 for(j=0;j<n;j++) 28 ; 29 } 30 } 31 void iow(u16 reg,u16 data) 32 { 33 IOADDR = reg; 34 IODATA = data; 35 } 36 37 u8 ior(u16 reg) 38 { 39 IOADDR = reg; 40 return IODATA; 41 } 42 43 void dm9000_reset() 44 { 45 iow(DM9000_GPCR, GPCR_GPIO0_OUT); 46 // power on the dm9000 47 iow(DM9000_GPR, 0); 48 //dm9000_reset 49 iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); 50 iow(DM9000_NCR, 0); 51 delay(1000);//second reset 52 iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); 53 54 iow(DM9000_NCR, 0); 55 delay(1000); 56 } 57 58 int dm9000_probe(void) 59 { 60 u32 id_val; 61 id_val = ior(DM9000_VIDL); 62 id_val |= ior(DM9000_VIDH) << 8; 63 id_val |= ior(DM9000_PIDL) << 16; 64 id_val |= ior(DM9000_PIDH) << 24; 65 if (id_val == DM9000_ID) { 66 printf("dm9000 is found ! "); 67 return 0; 68 } else { 69 printf("dm9000 not found ! "); 70 return -1; 71 } 72 } 73 74 #define Tacs 2 75 #define Tcos 2 76 #define Tacc 3 77 #define Tcoh 2 78 #define Tcah 2 79 #define Tacp 0 80 int dm9000_init() 81 { 82 int i; 83 //设置SROM Register 84 SROM_BW &= (~(0xf<<4)); 85 SROM_BW |= (1<<4); 86 SROM_BC1 = (Tacs << 28) | (Tcos << 24) | 87 (Tacc << 16) | (Tcoh << 12) | 88 (Tcah << 8) | (Tacp << 4); 89 90 dm9000_reset(); 91 dm9000_probe(); 92 93 //MAC初始化 94 /* Program operating register, only internal phy supported */ 95 iow(DM9000_NCR, 0x0); 96 /* TX Polling clear */ 97 iow(DM9000_TCR, 0); 98 /* Less 3Kb, 200us */ 99 iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US); 100 /* Flow Control : High/Low Water */ 101 iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8)); 102 /* SH FIXME: This looks strange! Flow Control */ 103 iow(DM9000_FCR, 0x0); 104 /* Special Mode */ 105 iow(DM9000_SMCR, 0); 106 /* clear TX status */ 107 iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); 108 /* Clear interrupt status */ 109 iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS); 110 111 /* fill device MAC address registers */ 112 for (i = 0;i < 6; i++) 113 iow(DM9000_PAR+i, mac_addr[i]); 114 115 /* Activate DM9000 */ 116 /* RX enable */ 117 iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); 118 /* Enable TX/RX interrupt mask */ 119 iow(DM9000_IMR, IMR_PAR); 120 } 121 122 void dm9000_tx(u8 *data,u32 length) 123 { 124 int i; 125 /*禁止中断*/ 126 iow(DM9000_IMR,0x80); 127 128 /*写入发送数据的长度*/ 129 iow(DM9000_TXPLH, (length >> 8) & 0xff); //高8位 130 iow(DM9000_TXPLL, length & 0xff); //低8位 131 132 133 /*写入待发送的数据*/ 134 IOADDR = DM9000_MWCMD; 135 136 for(i=0;i<length;i+=2) 137 { 138 IODATA = data[i] | (data[i+1]<<8); 139 } 140 141 /*启动发送*/ 142 iow(DM9000_TCR, TCR_TXREQ); 143 144 /*等待发送结束*/ 145 while(1) 146 { 147 u8 status; 148 status = ior(DM9000_TCR); 149 if((status&0x01)==0x00) 150 break; 151 } 152 153 /*清除发送状态*/ 154 iow(DM9000_NSR,0x2c); 155 156 /*恢复中断使能*/ 157 iow(DM9000_IMR,0x81); 158 } 159 160 #define PTK_MAX_LEN 1522 161 u32 dm9000_rx(u8 *data) 162 { 163 u8 status,len; 164 u16 tmp; 165 u32 i; 166 167 /*判断是否产生中断,且清除*/ 168 if(ior(DM9000_ISR) & 0x01) 169 iow(DM9000_ISR,0x01); 170 else 171 return 0; 172 173 /*空读*/ 174 ior(DM9000_MRCMDX); 175 176 /*读取状态*/ 177 status = ior(DM9000_MRCMD); 178 179 /*读取包长度*/ 180 len = IODATA; 181 182 /*读取包数据*/ 183 if(len<PTK_MAX_LEN) 184 { 185 for(i=0;i<len;i+=2) 186 { 187 tmp = IODATA; 188 data[i] = tmp & 0x0ff; 189 data[i+1] = (tmp>>8)&0x0ff; 190 } 191 } 192 } 193 194 void dm9000_arp() 195 { 196 while(1) 197 { 198 arp_request(); 199 delay(100); 200 } 201 } 202 203 //初步测试 204 void dm9000_test(void) 205 { 206 char buf[100] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; 207 char c; 208 209 printf("DM9000 test : "); 210 printf("press q to exit "); 211 212 213 while( 1 ) 214 { 215 scanf("%c",&c); 216 if (c == 'q' || c == 'Q') 217 { 218 printf("%s line %d ", __FUNCTION__, __LINE__); 219 return ; 220 } 221 unsigned char tmp; 222 223 //各种初始化...包括串口初始化等等 224 //下面是读取一些芯片的出厂信息 225 tmp = (unsigned char)ior(0x2c); 226 printf("CHIP Revision:%2x ", tmp); 227 tmp = (unsigned char)ior(0x28); 228 printf("Vendor ID_L:%2x ", tmp); 229 tmp = (unsigned char)ior(0x29); 230 printf("Vendor ID_H:%2x ", tmp); 231 tmp = (unsigned char)ior(0x2a); 232 printf("Product ID_L:%2x ", tmp); 233 tmp = (unsigned char)ior(0x2b); 234 printf("Product ID_H:%2x ", tmp); 235 236 printf("%s line %d ", __FUNCTION__, __LINE__); 237 //dm9000_tx( buf, sizeof(buf) ); 238 printf("%s line %d ", __FUNCTION__, __LINE__); 239 } 240 }
1 #if 0 2 #define EXT_INT_0_CON (volatile unsigned long*)0x7f008900 3 #define EXT_INT_0_MASK (volatile unsigned long*)0x7f008920 4 #define VIC0INTENABLE (volatile unsigned long*)0x71200010 5 #define EINT0_VECTADDR (volatile unsigned long*)0x71200100 6 #define EXT_INT_0_PEND (volatile unsigned long*)0x7f008924 7 #define VIC0ADDRESS (volatile unsigned long*)0x71200f00 8 #endif 9 10 #define GPNCON (*((volatile unsigned long*)0x7F008830)) 11 #define GPNDAT (*((volatile unsigned long*)0x7F008834)) 12 13 #define EINT0CON0 (*((volatile unsigned long*)0x7F008900)) 14 #define EINT0MASK (*((volatile unsigned long*)0x7F008920)) 15 #define EINT0PEND (*((volatile unsigned long*)0x7F008924)) 16 #define VIC0INTENABLE (*((volatile unsigned long*)0x71200010)) 17 #define EINT7_VECTORADDR (*((volatile unsigned long*)0x71200104)) 18 #define EINT0_VECTADDR (*((volatile unsigned long*)0x71200100)) 19 20 #define VIC0ADDRESS (*((volatile unsigned long*)0x71200F00)) 21 #define VIC1ADDRESS (*((volatile unsigned long*)0x71300F00)) 22 23 #include "arp.h" 24 25 void key1_handle() 26 { 27 __asm__( 28 29 "sub lr,lr,#4 " 30 "stmfd sp!,{r0-r12,lr} " 31 : 32 : 33 ); 34 35 led_rol(); 36 37 EINT0PEND = ~0x0; 38 VIC0ADDRESS = 0; 39 40 __asm__( 41 "ldmfd sp!,{r0-r12,pc}^ " 42 : 43 : 44 ); 45 46 } 47 48 void dm9000_int_issue() 49 { 50 51 __asm__( 52 "sub lr,lr,#4 " 53 "stmfd sp!,{r0-r12,lr} " 54 : 55 : 56 ); 57 58 59 packet_len = dm9000_rx(buffer); 60 arp_process(); 61 62 EINT0PEND = ~0x0; 63 VIC0ADDRESS = 0; 64 //VIC1ADDRESS = 0; 65 __asm__( 66 "ldmfd sp!,{r0-r12,pc}^ " 67 : 68 : 69 ); 70 } 71 72 void init_irq() 73 { 74 EINT0CON0 |= 0B010; 75 EINT0MASK = 0; 76 VIC0INTENABLE |= 0X01; 77 EINT0_VECTADDR = (unsigned long)key1_handle; 78 79 //arp 80 GPNCON &= (~(0x2<<14)); 81 GPNCON |= (0x2<<14); 82 EINT0CON0 &= (~(0x7<<12)); 83 EINT0CON0 |= (0x1<<12); 84 EINT0MASK = 0; 85 VIC0INTENABLE |= (1<<1); 86 EINT7_VECTORADDR = (unsigned long)dm9000_int_issue; 87 88 __asm__( 89 "mrc p15,0,r0,c1,c0,0 " 90 "orr r0,r0,#(1<<24) " 91 "mcr p15,0,r0,c1,c0,0 " 92 93 "mrs r0,cpsr " 94 "bic r0, r0, #0x80 " 95 "msr cpsr_c, r0 " 96 : 97 : 98 ); 99 }
6. 参考资料:
http://www.codeforge.cn/read/243433/dm9000.c__html?go_blog_box=1