MAC:主要负责数据帧的创建,数据差错,检查,传送控制等。
PHY:物理接口收发器,当收到MAC过来的数据时,它会加上校验码,然后按照物理层的规则进行数据编码,再发送到传输介质上,接收过程则相反。
MII:媒体独立接口,“媒体独立”表明MAC一定情况下,任何类型的PHY设备都可以正常工作。
DM9000网卡部分函数实现:
/* //实验步骤 //初始化dm900 //数据包发送 //数据包接收 */ #include "dm9000.h" #include "arp.h" #define DM_ADD (*((volatile unsigned short *)0x18000000)) #define DM_DAT (*((volatile unsigned short *)0x18000004)) /*Register*/ #define MEM_SYS_CFG (*(volatile unsigned *)0x7E00F120) #define SROM_BW (*(volatile unsigned *)0x70000000) #define SROM_BC1 (*(volatile unsigned *)0x70000008) #define GPNCON (*(volatile unsigned *)0x7F008830) /* 中断相关寄存器 */ #define EINT0CON0 (*(volatile unsigned *)0x7F008900) #define EINT0MASK (*(volatile unsigned *)0x7F008920) #define EINT0PEND (*(volatile unsigned *)0x7F008924) #define VIC0INTENABLE (*(volatile unsigned *)0x71200010) #define EINT7_VECTADDR (*(volatile unsigned *)0x71200104) #define VIC0ADDRESS *((volatile unsigned int *)0x71200f00) #define VIC1ADDRESS *((volatile unsigned int *)0x71300f00) u8 *buffer = &arpbuf; u8 host_mac_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; u8 mac_addr[6] = {9,8,7,6,5,4}; u8 ip_addr[4] = {192,168,1,113}; u8 host_ip_addr[4] = {192,168,1,101}; u16 packet_len; void cs_init() { // MEM_SYS_CFG SROM_BW &= (~(1<<4)); //设置位宽度 SROM_BW |= (1<<4); SROM_BC1 = (0x0<<28)|(0x0<<24)|(0x7<<16)|(0x0<<12)|(0x0<<8)|(0x0<<4)|(0x0<<0); //设置时序 参考uboot ok6410的网卡片选位于bank1 } void int_init() //中断初始化 { GPNCON &= (~(0x3<<14)); GPNCON |= (0x2<<14); // EINT0PEND &= (~(0x1<<7)); // EINT0PEND |= (0x1<<7); } void dm9000_reg_write(u16 reg,u16 data) { DM_ADD = reg; DM_DAT = data; } u8 dm9000_reg_read(u16 reg) { DM_ADD = reg; return DM_DAT; } void dm9000_reset() { dm9000_reg_write(DM9000_GPCR, GPCR_GPIO0_OUT); dm9000_reg_write(DM9000_GPR, 0); dm9000_reg_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); dm9000_reg_write(DM9000_NCR, 0); dm9000_reg_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); dm9000_reg_write(DM9000_NCR, 0); } void dm9000_probe(void) { u32 id_val; id_val = dm9000_reg_read(DM9000_VIDL); id_val |= dm9000_reg_read(DM9000_VIDH) << 8; id_val |= dm9000_reg_read(DM9000_PIDL) << 16; id_val |= dm9000_reg_read(DM9000_PIDH) << 24; if (id_val == DM9000_ID) { printf("dm9000 is found !\n"); return ; } else { printf("dm9000 is not found !\n"); return ; } } void dm9000_init() { u32 i; /*片选(独立芯片)*/ cs_init(); /*中断初始化*/ int_init(); /*设备复位操作*/ dm9000_reset(); /*捕获dm9000*/ dm9000_probe(); /*MAC初始化*/ /* Program operating register, only internal phy supported */ dm9000_reg_write(DM9000_NCR, 0x0); /* TX Polling clear */ dm9000_reg_write(DM9000_TCR, 0); /* Less 3Kb, 200us */ dm9000_reg_write(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US); /* Flow Control : High/Low Water */ dm9000_reg_write(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8)); /* SH FIXME: This looks strange! Flow Control */ dm9000_reg_write(DM9000_FCR, 0x0); /* Special Mode */ dm9000_reg_write(DM9000_SMCR, 0); /* clear TX status */ dm9000_reg_write(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); /* Clear interrupt status */ dm9000_reg_write(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS); /*填充MAC地址*/ for (i = 0; i < 6; i++) dm9000_reg_write(DM9000_PAR+i, mac_addr[i]); /*激活DM9000*/ dm9000_reg_write(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); /* Enable TX/RX interrupt mask */ dm9000_reg_write(DM9000_IMR, IMR_PAR); } void dm9000_tx(u8 *data,u32 length) { u32 i; /*禁止中断*/ dm9000_reg_write(DM9000_IMR,0x80); /*写入发送数据的长度*/ dm9000_reg_write(DM9000_TXPLL, length & 0xff); dm9000_reg_write(DM9000_TXPLH, (length >> 8) & 0xff); /*写入待发送的数据*/ DM_ADD = DM9000_MWCMD; // MWCMD是DM9000内部SRAM的DMA指针,根据处理器模式,写后自动增加 for(i=0;i<length;i+=2) { DM_DAT = data[i] | (data[i+1]<<8); //低8 高8 } /*启动发送*/ dm9000_reg_write(DM9000_TCR, TCR_TXREQ); /*等待发送结束*/ while(1) { u8 status; status = dm9000_reg_read(DM9000_TCR); if((status&0x01)==0x00) break; } /*清除发送状态*/ dm9000_reg_write(DM9000_NSR,0x2c); /*恢复中断使能*/ dm9000_reg_write(DM9000_IMR,0x81); // printf("dm9000_tx"); } #define PTK_MAX_LEN 1522 u32 dm9000_rx(u8 *data) { u8 status,len; u16 tmp; u32 i; /*判断是否产生中断,且清除*/ if(dm9000_reg_read(DM9000_ISR) & 0x01) dm9000_reg_write(DM9000_ISR,0x01); else return 0; /*空读*/ dm9000_reg_read(DM9000_MRCMDX); /*读取状态*/ status = dm9000_reg_read(DM9000_MRCMD); /*读取包长度*/ len = DM_DAT; /*读取包数据*/ if(len<PTK_MAX_LEN) { for(i=0;i<len;i+=2) { tmp = DM_DAT; data[i] = tmp & 0x0ff; data[i+1] = (tmp>>8)&0x0ff; } } return len; }