• 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

  • 相关阅读:
    poj 1850/poj 1496
    poj 1035
    poj 3252
    hdoj 1013
    poj 2965
    poj 1844
    poj 2309
    蓝桥杯比赛回来后计划。。。
    山大实训第二周感想
    hadoop——Map/Reduce中combiner的使用
  • 原文地址:https://www.cnblogs.com/boyiliushui/p/6148077.html
Copyright © 2020-2023  润新知