Chinaunix首页 | 论坛 | 博客
  • 博客访问: 493768
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-11-26 23:46:30

一、网卡工作基本原理
1.网络模型
1.1 OSI七层模型
OSI(Open SystemInterconnection),开放式系统互联参考模型 。它把网络协议从逻辑上分为了7层。
通过七个层次使不同的系统网络之间实现可靠的通讯。
1.2 Linux四层模型
OSI参考模型的过于庞大、复杂招致了许多批评。与此对照,由技术人员自己开发的TCP/IP协议栈获得了更为广泛的应用。


2.网卡硬件结构

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

2.1 DM9000硬件结构

MAC属于数据链路层,PHY数据物理层

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


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


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


3.DM9000工作特性
3.1 编程接口

DM9000只有两种接口:INDEX接口(偏移接口)、数据接口(内容接口)
2440平台片选为什么是0x2开头的,DM9000连接的2440是CS4,而CS4是片选4(nGCS4),对应的基地址是0x20000000
为什么是300:打开DM9000芯片手册,300H是芯片的基地址。
为什么是4:DM9000传输数据是用SD0~SD15,cmd位来决定使用INDEX端口或者数据端口。

二、DM9000驱动程序设计
  1. /*
  2.  * dm9000.c
  3.  *
  4.  * Created on: 2016-11-25
  5.  * Author: root
  6.  */
  7. #include "dm9000.h"

  8. #define DM_ADD (*((volatile unsigned short *)0x20000300))
  9. #define DM_DATA (*((volatile unsigned short *)0x20000304))

  10. #define BWSCON (*(volatile unsigned long*) 0x48000000)
  11. #define BANKCON4 (*(volatile unsigned long*) 0x48000014)
  12. #define GPFCON (*(volatile unsigned long*) 0x56000050)
  13. #define EXTINT0 (*(volatile unsigned long*) 0x56000088)
  14. #define INTMSK (*(volatile unsigned long*) 0X4A000008)
  15. #define EINTMASK (*(volatile unsigned long*) 0x560000A4)
  16. #define SRCPND (*(volatile unsigned long*) 0X4A000000)
  17. #define INTPND (*(volatile unsigned long*) 0X4A000010)
  18. #define EINTPEND (*(volatile unsigned long*) 0x560000A8)

  19. typedef unsigned char u8;
  20. typedef unsigned short u16;
  21. typedef unsigned int u32;

  22. u8 mac_addr[6] = {9,8,7,6,5,4};
  23. u8 buffer[1000];

  24. void cs_init()
  25. {
  26.     //设置bank4为16位长度
  27.     BWSCON = BWSCON & (~(0x3<<16));
  28.     BWSCON = BWSCON | (0x01<<16);
  29.     //设置时钟
  30.     BANKCON4 = (0x0<<13)|(0x0<<11)|(0x7<<8)|(0x1<<6)|(0x0<<4)|(0x0<<2)|(0x0<<0);
  31. }

  32. void int_init()
  33. {
  34.     //配置GPF7为EINT7
  35.     GPFCON = GPFCON & (~(0X3)<<14);
  36.     GPFCON = GPFCON | ((0X2)<<14);

  37.     EXTINT0 = EXTINT0 & (~(0X7)<<28);
  38.     EXTINT0 = EXTINT0 | ((0X1)<<28);

  39.     INTMSK = INTMSK & (~(1<<4));
  40.     EINTMASK = EINTMASK & (~(0x1<<7));

  41.     SRCPND = (1<<4);
  42.     INTPND = (1<<4);
  43. }

  44. //dm9000寄存器读取函数
  45. void dm9000_reg_write(u16 reg, u16 data)
  46. {
  47.     DM_ADD = reg;
  48.     DM_DATA = data;
  49. }

  50. //dm9000寄存器写入函数
  51. u8 dm9000_reg_read(u16 reg)
  52. {
  53.     DM_ADD = reg;
  54.     return DM_DATA;
  55. }

  56. void dm9000_reset()
  57. {
  58.     //设置成输出
  59.     dm9000_reg_write(DM9000_GPCR, GPCR_GPIO0_OUT);
  60.     //写0清零POWER_DOWN信号,使PHY使活动的
  61.     dm9000_reg_write(DM9000_GPR, 0);
  62.     //软件重启,MAC Internal loopback模式,重启
  63.     dm9000_reg_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
  64.     //重新复位(第二次)
  65.     dm9000_reg_write(DM9000_NCR, 0);
  66.     dm9000_reg_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
  67. }

  68. void dm9000_probe(void)
  69. {
  70.     u32 id_val;
  71.     //读取供应商的值,并比较
  72.     id_val = dm9000_reg_read(DM9000_VIDL);
  73.     id_val |= dm9000_reg_read(DM9000_VIDH) << 8;
  74.     id_val |= dm9000_reg_read(DM9000_PIDL) << 16;
  75.     id_val |= dm9000_reg_read(DM9000_PIDH) << 24;
  76.     if (id_val == DM9000_ID) {
  77.         printf("dm9000 is found!\n");
  78.         return;
  79.     } else {
  80.         printf("dm9000 is not found!\n");
  81.         return;
  82.     }
  83. }

  84. void dm9000_init()
  85. {
  86.     u32 i;
  87.     /*设置片选*/
  88.     cs_init();

  89.     /*中断初始化*/
  90.     int_init();

  91.     /*复位设备*/
  92.     dm9000_reset();

  93.     /*捕获dm9000*/
  94.     dm9000_probe();

  95.     /*MAC初始化*/
  96.     /* Program operating register, only internal phy supported */
  97.     dm9000_reg_write(DM9000_NCR, 0x0);
  98.         /* TX Polling clear */
  99.     dm9000_reg_write(DM9000_TCR, 0);
  100.         /* Less 3Kb, 200us */
  101.     dm9000_reg_write(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
  102.         /* Flow Control : High/Low Water */
  103.     dm9000_reg_write(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
  104.         /* SH FIXME: This looks Flow Control */
  105.     dm9000_reg_write(DM9000_FCR, 0x0);
  106.         /* Special Mode */
  107.     dm9000_reg_write(DM9000_SMCR, 0);
  108.         /* clear TX status */
  109.     dm9000_reg_write(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
  110.         /* Clear interrupt status */
  111.     dm9000_reg_write(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);

  112.     /*填充MAC地址*/
  113.     /* fill device MAC address registers */
  114.     for (i = 0; i < 6; i++)
  115.         dm9000_reg_write(DM9000_PAR + i, mac_addr[i]);
  116.     /*多播地址
  117.     for (i = 0, oft = 0x16; i < 8; i++, oft++)
  118.         dm9000_reg_write(oft, 0xff);
  119.     */

  120.     /*激活dm9000*/
  121.     /* Activate DM9000 */
  122.     /* RX enable */
  123.     dm9000_reg_write(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
  124.     /* Enable TX/RX interrupt mask */
  125.     dm9000_reg_write(DM9000_IMR, IMR_PAR);
  126. }

  127. void dm9000_tx(u8 *data,u32 length)
  128. {
  129.     u32 i;
  130.     /*禁止中断*/
  131.     dm9000_reg_write(DM9000_IMR, 0x80);
  132.     /*写入发送数据的长度*/
  133.     dm9000_reg_write(DM9000_TXPLL, length & 0xff);
  134.     dm9000_reg_write(DM9000_TXPLH, (length >> 8) & 0xff);
  135.     /*写入待发送的数据*/
  136.     DM_ADD = DM9000_MWCMD;
  137.     for(i=0;i<length;i+=2)
  138.     {
  139.         DM_DATA = data[i] | (data[i+1]<<8);
  140.     }
  141.     /*启动发送*/
  142.     dm9000_reg_write(DM9000_TCR, TCR_TXREQ);
  143.     /*等待发送结束*/
  144.     while(1)
  145.     {
  146.         u8 status;
  147.         status = dm9000_reg_read(DM9000_TCR);
  148.         if((status & 0x01) == 0x00)
  149.             break;
  150.     }
  151.     /*清除发送状态*/
  152.     dm9000_reg_write(DM9000_NSR, 0x2c);
  153.     /*恢复中断使能*/
  154.     dm9000_reg_write(DM9000_IMR, 0x81);
  155. }

  156. #define PTK_MAX_LEN 1522

  157. u32 dm9000_rx(u8 *data)
  158. {
  159.     u8 status,len;
  160.     u16 tmp;
  161.     u32 i;
  162.     /*判断是否产生中断,且清除*/
  163.     if(dm9000_reg_read(DM9000_ISR) & 0x01)
  164.         dm9000_reg_write(DM9000_ISR, 0x01);
  165.     else
  166.         return 0;
  167.     /*空读*/
  168.     dm9000_reg_read(DM9000_MRCMDX);
  169.     /*读取状态,读取包长度*/
  170.     status = dm9000_reg_read(DM9000_MRCMD);
  171.     len = DM_DATA;
  172.     /*读取包的数据*/
  173.     if(len<PTK_MAX_LEN)
  174.     {
  175.         for(i=0;i<len;i+=2)
  176.         {
  177.             tmp = DM_DATA;
  178.             data[i] = tmp & 0x0ff;
  179.             data[i+1] = tmp>>8 & 0x0ff;
  180.         }
  181.     }
  182. }

  183. void int_issue()
  184. {
  185.     u32 i;
  186.     i = dm9000_rx(buffer);

  187.     SRCPND = (1<<4);
  188.     INTPND = (1<<4);
  189.     EINTPEND |= 1<<7;
  190. }

三、ARP协议实现
1.ARP协议介绍
1.1 以太网通讯
在计算机网络中,数据发送的过程,就是一个把数据按照各层协议层层封装的过程。在这个过程中,最终要使用的协议通常是以太网协议(数据链路层协议)。


1.2 以太网包格式

目的MAC地址:接收者的物理地址
源MAC地址:发送者的物理地址
类型:标明高层的数据使用的协议类型
数据:高层的数据
CRC:校验码

1.3 ARP功能
在以太网络中,每台计算机的唯一身份标示是MAC地址(物理层的地址),两台计算机要进行通讯,也必须知道对方的MAC地址,但是用户通常只知道对方的IP地址,这个时候,就可以利用ARP(地址解析协议)来向局域网中的所有计算机发送ARP请求包,收到请求包且满足条件的计算机将回复ARP应答包,告知其MAC地址。所以ARP协议是一种利用IP地址或者MAC地址的协议。

1.4 ARP格式


ARP包分为请求包和应答包,通过OP字段来区别。(网络层)
发送包(A->B):
以太网的头部以太网目的地址、以太网源地址、帧类型。
硬件地址长度:就是MAC地址长度
发送端以太网地址、发送端IP地址:如果A发送给B,这里填写的应该是A的地址
目的以太网地址:应该填写的是全FFFFF,找的使所有的连接设备。
目的IP地址:应该是B的IP地址
应答包(B->A):
发送端以太网地址、发送端IP地址此时应该是B的地址
目的以太网地址:A的目的以太网地址(从发送包中获得)
目的IP地址:应该是A的IP地址

1.5 编写实现ARP
开发板做一台主机,PC做一台主机。
①开发板发送ARP请求包(pc),PC会往开发板回应答包。
②开发板提取PC中的MAC地址打印出来。



阅读(675) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~