6410实现网卡(DM9000A)收发功能及ARP协议实现

1. 网卡硬件结构(DM9000A)

image

网卡的实质就是MAC通过MII接口控制PHY的过程。

image

MAC主要负责数据帧的构建、数据差错检查、传送控制等。

PHY是物理接口收发器,属于物理层,当它收到MAC过来的数据时,它会去加上校验码,然后按照物理层的规则进行数据编码,再发送到传输介质上,接收过程则相反。

MII:媒体独立接口, “媒体独立”表明MAC一定情况下,任何类型的PHY设备都可以正常工作。

2. DM9000A硬件接口

image

image

image

image

由上图得到以下信息:

dm9000的片选信号CS#接到Xm0CSn1,Xm0CSn1选择的是Bank1,那么片选的起始地址为0x18000000;cmd引脚接到Xm0ADDR2,那么数据端口地址为0x18000004。

3. 软件设计

3.1 设置SROM Register

读写时序控制

image

3.2 设置DM9000A相关参数(初始化)

参考uboot

image

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 }
arp.c
  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 }
dm9000.c
 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 }
interrupt.c

6. 参考资料:

http://www.codeforge.cn/read/243433/dm9000.c__html?go_blog_box=1

http://blog.csdn.net/lzjsqn/article/details/42170375

原文地址:https://www.cnblogs.com/boyiliushui/p/6148077.html