单片机驱动DM9000网卡芯片(详细调试过程)【上】

合集下载

DM9000网卡驱动分析

DM9000网卡驱动分析

DM9000网卡驱动分析#include <linux/module.h>#include <linux/ioport.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/spinlock.h>#include <linux/crc32.h>#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/dm9000.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/irq.h>#include <asm/delay.h>#include <asm/irq.h>#include <asm/io.h>#if defined(CONFIG_ARCH_S3C2410)#include <mach/regs-mem.h>#endif#include "dm9000.h"/* Board/System/Debug information/definition ---------------- *///在EEPROM或PHY地址寄存器中要选择内部PHY,那么7-6位强制为01#define DM9000_PHY 0x40 /* PHY address 0x01 */#define CARDNAME "dm9000"#define DRV_VERSION "1.31"/** Transmit timeout, default 5 seconds.*///传输超时时间设定,当传输超时时调用函数dm9000_timeout(struct net_device *dev) static int watchdog = 5000;module_param(watchdog, int, 0400);//在驱动程序加载时可以重新设定watchdog MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");/* DM9000 register address locking.** The DM9000 uses an address register to control where data written* to the data register goes. This means that the address register* must be preserved over interrupts or similar calls.** During interrupt and other critical calls, a spinlock is used to* protect the system, but the calls themselves save the address* in the address register in case they are interrupting another* access to the device.** For general accesses a lock is provided so that calls which are* allowed to sleep are serialised so that the address register does* not need to be saved. This lock also serves to serialise access* to the EEPROM and PHY access registers which are shared between* these two devices.*//* The driver supports the original DM9000E, and now the two newer* devices, DM9000A and DM9000B.*/enum dm9000_type {TYPE_DM9000E, /* original DM9000 */TYPE_DM9000A,TYPE_DM9000B};/* Structure/enum declaration ------------------------------- */typedef struct board_info {//cmd脚决定了数据数据口还是地址索引void __iomem *io_addr; /* Register I/O base address */void __iomem *io_data; /* Data I/O address */u16 irq; /* IRQ */u16 tx_pkt_cnt;//当前待传输的数据包的数量,最多两个//第二个数据包长度存于此处,第二个数据包写入网卡SRAM中后要释放skb u16 queue_pkt_len;u16 queue_start_addr;u16 dbug_cnt;u8 io_mode; /* 0:word, 2:byte */u8 phy_addr;u8 imr_all;//在probe()函数中有db->flags = pdata->flags;unsigned int flags;unsigned int in_suspend :1;int debug_level;enum dm9000_type type;void (*inblk)(void __iomem *port, void *data, int length);void (*outblk)(void __iomem *port, void *data, int length);void (*dumpblk)(void __iomem *port, int length);struct device *dev; /* parent device */struct resource *addr_res; /* resources found */struct resource *data_res;//物理地址struct resource *addr_req; /* resources requested */struct resource *data_req;//I/O映射后的虚拟地址struct resource *irq_res;struct mutex addr_lock; /* phy and eeprom access lock *///在probe函数中初始化,处理函数dm9000_poll_work,链路连接状态改变 struct delayed_work phy_poll;struct net_device *ndev;spinlock_t lock;struct mii_if_info mii;u32 msg_enable;//网络入口信息} board_info_t;/* debug code */#define dm9000_dbg(db, lev, msg...) do { \if ((lev) < CONFIG_DM9000_DEBUGLEVEL && \(lev) < db->debug_level) { \dev_dbg(db->dev, msg); \} \} while (0)static inline board_info_t *to_dm9000_board(struct net_device *dev){//存取私有数据指针专用函数return netdev_priv(dev);}/* DM9000 network board routine ---------------------------- */static voiddm9000_reset(board_info_t * db){dev_dbg(db->dev, "resetting device\n");//NCR(00H):网络控制寄存器/* RESET device */writeb(DM9000_NCR, db->io_addr);udelay(200);writeb(NCR_RST, db->io_data);udelay(200);}/** Read a byte from I/O port*/static u8ior(board_info_t * db, int reg){//对网卡寄存器进行操作要先写该寄存器的偏移地址writeb(reg, db->io_addr);return readb(db->io_data);}/** Write a byte to I/O port*/static voidiow(board_info_t * db, int reg, int value){writeb(reg, db->io_addr);writeb(value, db->io_data);}/* routines for sending block to chip */static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count) {writesb(reg, data, count);}static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count) {writesw(reg, data, (count+1) >> 1);}static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count) {writesl(reg, data, (count+3) >> 2);}/* input block from chip to memory */static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count) {readsb(reg, data, count);}static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count) {readsw(reg, data, (count+1) >> 1);}static void dm9000_inblk_32bit(void __iomem *reg, void *data, int count) {readsl(reg, data, (count+3) >> 2);}/* dump block from chip to null *///读出没用的数据,为了改变网卡SRAM FIFO的数据指针,static void dm9000_dumpblk_8bit(void __iomem *reg, int count){int i;int tmp;for (i = 0; i < count; i++)tmp = readb(reg);}static void dm9000_dumpblk_16bit(void __iomem *reg, int count){int i;int tmp;count = (count + 1) >> 1;for (i = 0; i < count; i++)tmp = readw(reg);}static void dm9000_dumpblk_32bit(void __iomem *reg, int count){int i;int tmp;count = (count + 3) >> 2;for (i = 0; i < count; i++)tmp = readl(reg);}/* dm9000_set_io** select the specified set of io routines to use with the* device*///设定I/O线宽static void dm9000_set_io(struct board_info *db, int byte_width) {/* use the size of the data resource to work out what IO* routines we want to use*/switch (byte_width) {case 1:db->dumpblk = dm9000_dumpblk_8bit;db->outblk = dm9000_outblk_8bit;db->inblk = dm9000_inblk_8bit;break;case 3:dev_dbg(db->dev, ": 3 byte IO, falling back to 16bit\n");case 2:db->dumpblk = dm9000_dumpblk_16bit;db->outblk = dm9000_outblk_16bit;db->inblk = dm9000_inblk_16bit;break;case 4:default:db->dumpblk = dm9000_dumpblk_32bit;db->outblk = dm9000_outblk_32bit;db->inblk = dm9000_inblk_32bit;break;}}/*延时调度。

DM9000驱动移植详解及问题点

DM9000驱动移植详解及问题点

OK6410、2.6.36内核移植,dm9000 驱动移植,详细!分类:嵌入式学习Linux学习2012-04-27 00:54 3004人阅读评论(7) 收藏举报interfaceccompressionresourcesstructtable还是先来吐槽:本来我是在上一个星期的周末已经把Linux2.6.34.11 的驱动已经成功的移植到,OK6410 的开发板上的,并且能够启动主机上的NFS 根文件系统,可是我在周一的时候,开始学习LCD 的驱动程序,在修改内核文件的时候,有几处错误修改,将原来自己做的2.6.34.11 的内核源码搞的乱七八糟的,在这里还是自己在修改内核的时候没有提注重注释,并且没有记录下来自己的操作步骤,以至于我没办法,恢复2.6.34 的内核,所以也就只能重新先开始最基础的内核移植了。

这次我选择的是2.6.36.2 的内核,谁知到一开始移植就出现一大堆问题。

在这里我不得不说,飞凌开发人员对内核修改的代码,管理真的是太扯了,自己在注销任何一个设备是没有一点点注释,就把这个设备原有的线性地址分配给其它设备了,让我让我们这些菜鸟干看着一大堆的报错信息顶个什么用,真的是伤不起。

好了不乱扯了,现在开始记录。

我的开发环境是:VMware Ubuntu 10.10 。

OK6410 A版256M+2G 的开发板。

主机系统:XP。

Uboot:飞凌提供的Uboot。

参考内核:飞凌提供的Forlinx 的2.6.36.2 内核操作步骤以下./ 均代表你的内核根目录1、修改./Makefile191 ARCH ?=arm // 指定cpu类型,arm后面不要有空格,要不然编译是会提醒ARCH 不能为一个目录192 CROSS_COMPILE ?=/usr/local/arm/4.2.2-eabi/usr/bin/arm-linux- // 指定交叉编译器的路径,按照你自己的进行指定路径2、先来说说nand flash 的驱动涉及到的文件:MTD 通用nand flash 驱动程序位置:./drivers/mtd/nand/.nand_base.cNAND Flash 的platform 设备信息: ./drivers/mtd/nand/s3c_nand.c有了上面的依赖驱动依赖程序、接下来修改./arch/arm/mach-s3c64xx/mach-smdk6410.c 1) nandflash 驱动,修改方法加载头文件[cpp]view plaincopyprint?1.#include <linux/mtd/mtd.h>2.#include <linux/mtd/partitions.h>3.#include <plat/nand.h> //这些头文件放在./arch/arm/plat-samsung/include/ 下面添加nand 结构体[cpp]view plaincopyprint?1.// add by acanoe first2.extern void s3c64xx_reserve_bootmem(void); //add by acanoe3.4.5.struct mtd_partition ok6410_nand_part[] = {6. {7. .name = "Bootloader",8. .offset = 0,9. .size = (1 * SZ_1M),10. .mask_flags = MTD_CAP_NANDFLASH,11. },12. {13. .name = "Kernel",14. .offset = (1 * SZ_1M),15. .size = (5*SZ_1M) ,16. .mask_flags = MTD_CAP_NANDFLASH,17. },18. {19. .name = "User",20. .offset = (6 * SZ_1M),21. .size = (120*SZ_1M) ,22. },23. {24. .name = "File System",25. .offset = MTDPART_OFS_APPEND,26. .size = MTDPART_SIZ_FULL,27. }28.};29.30.31.static struct s3c2410_nand_set ok6410_nand_sets[] = {32. [0] = {33. .name = "nand",34. .nr_chips = 1,35. .nr_partitions = ARRAY_SIZE(ok6410_nand_part),36. .partitions = ok6410_nand_part,37. },38.};39.40.41.static struct s3c2410_platform_nand ok6410_nand_info = {42. .tacls = 25,43. .twrph0 = 55,44. .twrph1 = 40,45. .nr_sets = ARRAY_SIZE(ok6410_nand_sets),46. .sets = ok6410_nand_sets,47.};48.//add by acanoe first修改 smdk6410_devices[] __initdata = {对照这个结构体将那些进行修改,注意 by acanoe 的语句为修改重点。

fpga驱动dm9000

fpga驱动dm9000

DM90001.总体介绍该DM9000 是一款完全集成的和符合成本效益单芯片快速以太网MAC 控制器与一般处理接口,一个10/100M 自适应的PHY 和4K DWORD 值的SRAM 。

它的目的是在低功耗和高性能进程的3.3V 与5V 的支持宽容。

DM9000 还提供了介质无关的接口,来连接所有提供支持介质无关接口功能的家用电话线网络设备或其他收发器。

该DM9000 支持8 位,16 位和32 -位接口访问内部存储器,以支持不同的处理器。

DM9000 物理协议层接口完全支持使用10MBps 下3 类、4 类、5 类非屏蔽双绞线和100MBps 下5 类非屏蔽双绞线。

这是完全符合IEEE 802.3u 规格。

它的自动协调功能将自动完成配置以最大限度地适合其线路带宽。

还支持IEEE 802.3x 全双工流量控制。

这个工作里面DM9000 是非常简单的,所以用户可以容易的移植任何系统下的端口驱动程序。

2.内部寄存器DM9000(A)包含一系列可被访问的控制状态寄存器,这些寄存器是字节对齐的,他们在硬件或软件复位时被设置成初始值。

以下为DM9000 的寄存器功能详解:NCR(00H):网络控制寄存器(Network Control Register )7:EXT_PHY:1 选择外部PHY,0 选择内部PHY,不受软件复位影响。

6:WAKEEN:事件唤醒使能,1 使能,0 禁止并清除事件唤醒状态,不受软件复位影响。

5:保留。

4:FCOL:1 强制冲突模式,用于用户测试。

3:FDX:全双工模式。

内部PHY 模式下只读,外部PHY 下可读写。

2-1:LBK:回环模式(Loopback)00 通常,01MAC 内部回环,10 内部PHY 100M 模式数字回环,11 保留。

0:RST:1 软件复位,10us 后自动清零。

NSR (01H):网络状态寄存器(Network Status Register )7:SPEED:媒介速度,在内部PHY 模式下,0 为100Mbps,1 为10Mbps。

DM9000网卡驱动

DM9000网卡驱动

DM9000网卡驱动笔记网卡芯片为DM9000,ARM开发板用的是S3C6410,PC机装的是RED HAT ENTERPRISE LINUX 5.5.网卡接入soc上并没有接入到专门的驱动ic上,而是接入到了SROM的控制器上,所以需要配置的寄存器就需要配置SROM的寄存器。

S3C6410支持6页的SROM,DM9000的片选连接到了SROM控制的bank1,地址线连接的是addr2,也就是以后地址线上发出去的数据,第2位为0,数据为地址,第2位为1,数据为数据(这比较难理解)。

根据这样的地址数据的读写,操作DM9000中的寄存器,配置好网卡芯片,arm端封装一个arp请求包,在PC机上用tcpdump命令看能不能接收到如果能接受,网卡配置就算比较成功了附上源码:#include "up.h"#define INDEX (0x18000000)#define DATA (0x18000004)int (*printf)(char *, ...) = 0x57e11d4c;void (*udelay)(int ) = 0x57e00a98;struct ethhdr{unsigned char dest[6];unsigned char source[6];unsigned short type;};struct arphdr{unsigned short hw_type;unsigned short pro_type;unsigned char hw_len;unsigned char pro_len;unsigned short op;unsigned char src_mac[6];unsigned char src_ip[4];unsigned char dest_mac[6];unsigned char dest_ip[4];};void write_dm9000(unsigned char reg, unsigned short val); unsigned short read_dm9000(unsigned char reg);void init_dm9000();void send_data(unsigned char *buff, int len);int create_arp(unsigned char *buff);void *memset(void *s, int c, int len);unsigned short htons(unsigned short);int main(){/*set XM0bank1*/SROM_BW = (1 << 4);SROM_BC1 = (4 << 4) | (5 << 16);unsigned char buff[1024] = {0};int len = create_arp(buff);init_dm9000();send_data(buff, len);return 0;}void write_dm9000(unsigned char reg, unsigned short val) {*(unsigned char *)INDEX = reg;*(unsigned short *)DATA = val;}unsigned short read_dm9000(unsigned char reg) {*(unsigned char *)INDEX = reg;unsigned char c = *(unsigned char *)DATA;return c;}void init_dm9000(){//application notes//step 1: p22write_dm9000(0x1f, 0x00);//step 2:write_dm9000(0x00, 0x01);udelay(10);write_dm9000(0x00, 0x00);//step 3:write_dm9000(0x00, (1 << 3));//step 4:write_dm9000(0xff, 0xff);//step 5://step 6:write_dm9000(0x10, 0x11);write_dm9000(0x11, 0x22);write_dm9000(0x12, 0x33);write_dm9000(0x13, 0x44);write_dm9000(0x14, 0x55);write_dm9000(0x15, 0x66);//step 7://step 8:write_dm9000(0x01, (1 << 2) | (1 << 3) | (1 << 5));write_dm9000(0xfe, 0x3f);printf("3\n");//step 9://step 10:write_dm9000(0xff, 0xff);//step 11:write_dm9000(0x05, 0x01);//step 12:}void send_data(unsigned char *buff, int len){//p28://step 1:unsigned char c = read_dm9000(0xfe);if(c >> 7)printf("8 bit mode\n");elseprintf("16 bit mode\n");//step 2*(unsigned char*)INDEX = 0xf8;int tmp = (len + 1) >> 1;int i = 0;for(i=0; i<tmp; i++){*(unsigned short *)DATA = ((unsigned short*)buff)[i];}//step 3write_dm9000(0xfd, (len >> 8) & 0xff);write_dm9000(0xfc, len & 0xff);//step 4write_dm9000(0x02, 0x01);}int create_arp(unsigned char *buff){int len = 0;struct ethhdr *eth = (struct ethhdr *)buff;eth->dest[0] = 0xff;eth->dest[1] = 0xff;eth->dest[2] = 0xff;eth->dest[3] = 0xff;eth->dest[4] = 0xff;eth->dest[5] = 0xff;eth->source[0] = 0x11;eth->source[1] = 0x22;eth->source[2] = 0x33;eth->source[3] = 0x44;eth->source[4] = 0x55;eth->source[5] = 0x66;eth->type = htons(0x0806);struct arphdr *arp = (struct arphdr *)(buff + sizeof(struct ethhdr));arp->hw_type = htons(1);arp->pro_type = htons(0x0800); arp->hw_len = 6;arp->pro_len = 4;arp->op = htons(1);arp->src_mac[0] = 0x11;arp->src_mac[1] = 0x22;arp->src_mac[2] = 0x33;arp->src_mac[3] = 0x44;arp->src_mac[4] = 0x55;arp->src_mac[5] = 0x66;arp->src_ip[0] = 192;arp->src_ip[1] = 168;arp->src_ip[2] = 1;arp->src_ip[3] = 2;arp->dest_mac[0] = 0xff;arp->dest_mac[1] = 0xff;arp->dest_mac[2] = 0xff;arp->dest_mac[3] = 0xff;arp->dest_mac[4] = 0xff;arp->dest_mac[5] = 0xff;arp->dest_ip[0] = 192;arp->dest_ip[1] = 168;arp->dest_ip[2] = 1;arp->dest_ip[3] = 1;len = sizeof(struct ethhdr) + sizeof(struct arphdr);return len;}void *memset(void *s, int c, int len){int i = 0;for(i=0; i<len; i++)((unsigned char *)s)[i] = c;}unsigned short htons(unsigned short data){unsigned short ret = 0;ret = ((data >> 8) & 0xff) | ((data << 8) & 0xff00);return ret;。

dm9000a嵌入式网卡芯片故障调试技术相关

dm9000a嵌入式网卡芯片故障调试技术相关

DM9000AEP调试的时候注意事项:1.首先要判断芯片的真假。

常见的方法是读取芯片的ID号。

当然有些工程师朋友的寄存器设置,以及时序设置有问题,读取芯片的ID号就会错。

读取ID是最基本的操作。

2.其次确认芯片无质量问题后,再确定是硬件,还是软件方面的问题。

一般软件方面,问题很容易解决。

硬件问题,需要注意:网络变压器的CT端,一般要接DM9000AEP的管脚2,9脚输出的2.5V,输出的时候一般要加一个稳压电容以及一个滤波电容,稳压电容至少200uf。

另外可以通过10M下是否有连接,来判断网络变压器是否连接正确。

不同的网络变压器,连接电路一般有差异,要注意兼容性。

3.其次发送和接收的几个50欧姆的电阻,电阻值一定要正确,如果不正确,会有丢包现象。

或者网络时断时续。

4.DM9000AEP的datasheet,必须要看,不看的工程师,自己瞎琢磨,一般会耽误时间的。

5.在驱动程序里最好要添加打印信息,打印信息可以反馈硬件的故障,对分析问题,解决问题很有帮助。

6.一般晶振,网络变压器,最好要买真货,如果买到假的,通常很难从电路上分析出问题,通常要经过很长时间的测试,才发现。

最好不要在电子市场买东西,假的东西很多。

亲身经历。

特别是Pluse的H1102很多假冒的。

7.网络变压器的49.9的电阻,不用接任何电源。

8.PWRST复位引脚,如果是通过GPIO控制,应该是下拉电阻,不是上拉电阻。

Davicom高速以太网路晶片1、10/100/1000M 超高速以太网络芯片DM9702 - 超高速以太网络三合一单芯片. (Coming Soon)2、10/100M 高速以太网络芯片DM9000A (DM9000AE/DM9000AEP) - DM9000A Ethernet Controller With General Processor Interface DM9000E - (SMSC LAN91C111 Equivalent)ISA接口高速以太网络三合一单芯片(含 MII / RMII 接口).DM9000K - 研发套件DM9601 - USB接口高速以太网络三合一单芯片.DM9102D - PCI 接口高速以太网络三合一单芯片(Auto-MDIX). 0.25umDM9102A - PCI 接口高速以太网络三合一单芯片. 0.35um3、10/100M 高速以太网络实体层收发器DM9161 - 低功率, 高速以太网络实体层收发器. 48-pin 0.35um.DM9161A - 低功率, 高速以太网络实体层收发器. Auto-MDIX. 48-pin 0.25um.DM9331 - 100M高速以太网络光纤实体层媒体转换器. 48-pin.DM9301 - 100M高速以太网络光纤实体层媒体转换器.4、10M 以太网络芯片DM9008 - ISA接口以太网络三合一单芯片(性价比优于RTL8019AS,CS8900A )DM9009 - 最经济, 最有效率PCI 接口以太网络三合一单芯片 (含MII/RMII/7-wired GPSI 接口).DM9081 - 最经济, 最有效率以太网络 (8+2) 集线器芯片.。

u_boot移植(七)之支持dm9000网卡

u_boot移植(七)之支持dm9000网卡

u_boot移植(七)之支持dm9000网卡上一节我们已经让uboot支持了Nand Flash操作,调试的时候我们用的串口下载数据到内存,大家会发现下载的速度很慢,这一节我们就让我们的uboot支持网络功能,通过网线来下载数据内存,速度会快很多。

我们先来看看uboot中网卡的初始化代码。

一、uboot中网卡初始化代码分析打开lib_arm/board.c文件,可以看到如下代码:可以看到,我们必须定义宏CONFIG_CMD_NET ,网卡初始化相关的代码才会编译进uboot。

记录一下,需要在include/configs/fsc100.h文件中定义CONFIG_CMD_NET。

接下来,我们来看看eth_initialize()这个函数是如何实现的。

可以看到,网卡的初始化最终调用了board_eth_init()函数,我们来看看board_eth_init()函数时如何实现的。

看到上面代码,我想很多人都很奇怪,这是什么写法?board_eth_init(bd_t *bis) __attribute__((weak,alias("__def_eth_init"))) ;这是GNU的对C语言的扩展语法:(1)alias 表示给board_eth_init()函数取了一个别名叫做__def_eth_init()函数,这样如果board_eth_init函数没有实现,编译器就会使用它的别名__def_eth_init()函数。

(2)weak表示board_eth_init()函数是一个弱符号。

在gcc的世界里,如果一个函数没有用__attribute__((weak))进行修饰,就表示这个符号是一个强符号。

当强符号和弱符号同时存在的时候,编译器就会使用弱符号。

也就是说当我们重新实现了board_eth_init()函数,编译器就会使用我们实现的函数。

现在的问题来了,该怎么实现这个函数呢?我们先来看看别人是怎么实现board_eth_init()这个函数的,然后我们依葫芦画瓢,就能实现自己的board_eth_init()函数了。

成功移植U-BOOT之---- DM9000网卡驱动

成功移植U-BOOT之---- DM9000网卡驱动
保存退出
5、修改完成,开始编译
make TQ2440_config
make CROSS_COMPILE=arm-linux-
把编译后在顶层目录生成的 u-boot.bin 通过 SAMBA 拷出来,通过 JTAG 或 JLINK 烧到开发 板!
-------- -------------- -------
…… /*修改环境变量*/ #define CONFIG_ETHADDDR 00:01:02:03:04:05 #define CONFIG_NETMASK 255.255.255.0 #define CONFIG_IPADDR 192.168.0.61 #define CONFIG_SERVERIP 192.168.0.60
case 2: printf("10M case 4: printf("100M half duplex ");
break; case 8:
printf("100M full duplex "); break; default: printf("unknown: %d ", lnk); break; } p rintf("mo d e \n");
#endif
return 0; }
重新编译,再烧写,问题解除。
今天成功的在天嵌 TQ2440 的板子上完成了 U-BOOT -DM9000 网卡驱动的移植!
实验使用的是国嵌实验 4-2-4 修改过的源码(u-boot-basic.tar.gz) 废话不说,记笔记:
mkdir 4-2-4 cp u-boot-basic.tar.gz 4-2-4/ cd 4-2-4 tar zxvf u-boot-basic.tar.gz

DM9000网卡的基本工作原理

DM9000网卡的基本工作原理

DM9000⽹卡的基本⼯作原理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_CFGSROM_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 1522u32 dm9000_rx(u8 *data){u8 status,len;u16 tmp;u32 i;/*判断是否产⽣中断,且清除*/if(dm9000_reg_read(DM9000_ISR) & 0x01)dm9000_reg_write(DM9000_ISR,0x01);elsereturn0;/*空读*/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;}。

dm9000初始化过程

dm9000初始化过程

dm9000初始化过程2009-05-07 15:01drivers/dm9000x.c eth_init()函数这里的初始化并不复杂,首先对dm9000进行复位 static void dm9000_reset(void) { DM9000_DBG("resetting\n"); DM9000_iow(DM9000_NCR, NCR_RST); udelay(1000); /* delay 1ms */ } 这里将NRC寄存器的第0位置1,之后要保持至少20us的延时。

这里延时了1ms。

int dm9000_probe(void) { u32 id_val; id_val = DM9000_ior(DM9000_VIDL);id_val |= DM9000_ior(DM9000_VIDH) << 8; id_val |= DM9000_ior(DM9000_PIDL) << 16; id_val |= DM9000_ior(DM9000_PIDH) << 24; if (id_val == DM9000_ID) { printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE, id_val); return 0; } else { printf("dm9000 not found at 0x%08x id: 0x%08x\n", CONFIG_DM9000_BASE, id_val); return -1; } } 复位结束后到网卡的vendor ID 寄存器和product ID寄存器读取id,检测此网卡是否是dm9000。

static void identify_nic(void) { struct board_info *db = &dmfe_info; /* Point a board information structure */ u16 phy_reg3; DM9000_iow(DM9000_NCR,NCR_EXT_PHY); phy_reg3 = phy_read(3); switch (phy_reg3 & 0xfff0) { case 0xb900: if (phy_read(31) == 0x4404) { db->nic_type = HOMERUN_NIC; program_dm9801(phy_reg3); DM9000_DBG("found homerun NIC\n"); } else { db->nic_type = LONGRUN_NIC; DM9000_DBG("found longrun NIC\n"); program_dm9802(); } break; default: db->nic_type = FASTETHER_NIC; break; } DM9000_iow(DM9000_NCR, 0); } 接着是检测网卡类型,是FASTETHER, HOMERUN 或LONGRUN类型。

移植调试dm9000网卡驱动(U-Boot)

移植调试dm9000网卡驱动(U-Boot)

这样就到了 DM9000A 的驱动部分代码。 DM9000A 的接收数据函数: eth_rx(void) { u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0]; u16 RxStatus, RxLen = 0; u32 tmplen, i;
// DM9000A 接收缓冲区中的数据格中格式是 4 字节的包头+真正的数据. // 其中 4 字节包头分别位为: rxbyte, status, count_low, count_hight // 说明如下: // rxbyte: 0-没有接收到数据, 1-有新的数据包 // status: 状态 // count_low, count_hight: 接收到的数据长度
/*******************************************************/ 包含两部分内容:配置说明和调试。
1 配置说明 Uboot 可以使用 RS232 和主机进行通讯,但其最大的波特率不过是 115200,1 秒最多只能 传送 11,520byte 的数据,如果说是传输 1.5M 的内核文件,计算下来将需要 133 秒,2 分钟的 时间,如果是传送 32M 的根文件系统文件,那么传输时间将是非常惊人的! 为了提高效率我们选用以太网传输,Uboot 本身也提供了网络的支持。 本系统中使用的网络芯片是 DM9000A,Uboot 的 driver 目录中包含了该芯片的驱动,文件 名为 dm9000x.c 和 dm9000x.h。要加入驱动的支持,必须在 config 文件中增加对 DM9000A
在这里#define CONFIG_DM9000_BASE 的定义最为重要。不同的板子只要修改这个参数即可。友善之臂的 SBC2440V4 上的 DM9000 在 BANK4 上所以定义为“0x20000300”。有 的板子是在 BANK1 上,就为“0x08000300”。

基于mini2440的DM9000网卡驱动

基于mini2440的DM9000网卡驱动

s3c2440的网卡接口扩展网络对于嵌入式系统来说必不可少。

可是s3c2440没有集成以太网接口,所以要想使s3c2440具备以太网的功能,就必须扩展网卡接口。

在这里,我们外接DM9000,使其可以与以太网相连接。

DM9000可以直接与ISA总线相连,也可以与大多数CPU相连。

在这里,我们当然是要让DM9000与s3c2440相连接了。

DM9000对外来说只有两个端口——地址口和数据口,地址口用于输入内部寄存器的地址,而数据口则完成对某一寄存器的读写。

DM9000的CMD引脚用来区分这两个端口,当CMD引脚为0时,DM9000的数据线上传输的是寄存器地址,当CMD 引脚为1时,传输的是读写数据。

我们把DM9000的A8和A9接为高电平,把A4~A7接为低电平,并且把DM9000的AEN接到s3c2440的nGCS4引脚上,则DM9000的端口基址为0x20000300,如果再把DM9000的CMD引脚接到s3c2440的ADDR2引脚上,则我们就可以定义DM9000的这两个端口地址,它们分别为:#define DM_ADDR_PORT(*((volatile unsigned short*)0x20000300))//地址口#define DM_DATA_PORT(*((volatile unsigned short*)0x20000304))//数据口如果要写入DM9000中的某个寄存器,则先把该寄存器的地址赋予DM_ADDR_PORT,然后再把要写入的数据赋予DM_DATA_PORT即可。

读取DM9000中的某个寄存器也类似。

下面的函数的作用分别是DM9000的读、写寄存器操作://写DM9000寄存器void__inline dm_reg_write(unsigned char reg,unsigned char data){DM_ADDR_PORT=reg;//将寄存器地址写到地址端口DM_DATA_PORT=data;//将数据写到数据端口}//读DM9000寄存器unsigned char__inline dm_reg_read(unsigned char reg){DM_ADDR_PORT=reg;return DM_DATA_PORT;//将数据从数据端口读出}完成了对DM9000寄存器的读写函数的编写,下面我们就可以初始化DM9000,它的过程就是适当配置DM9000寄存器的过程。

DM9000调试血泪总结http...

DM9000调试血泪总结http...

DM9000调试血泪总结http...因为需要使用DM9000,因此就有了这条血泪之路。

话说那是一个月前,板子刚回来,感觉难度不大,因为此前搞过F4板子上的网络,对LWIP的移植和使用相对比较熟悉,所以花了3天的时间就把DM9000的驱动写好了,其实就是FSMC的配置,然后就是内部寄存器的读写,这个不难,驱动写完以后就是LWIP的移植,花了2个小时左右就移植成功了,成功以后开ping,ping成功,兴奋啊!但是在做webserver的时候发现网速很慢,而且很容易就会挂掉的!因此做了一次稳定性测试,就是连续的ping好几个小时,但是发现ping到0.5-2个小时的时候就会挂掉!!心碎啊,没办法,度娘,找各种DM9000在STM32上的程序,发现就那么几个,大多是就与RTT的DM9000例程修改的,就是在RTT例程的基础上修改一下IO口而已。

而RTT对LWIP做了修改,而且移植方法和常用的不同,因此就排除了RTT的例程。

但是将RTT的例程做了小修改,在我的板子上可以跑下去,这样可以确定板子硬件有没有问题!经过测试ping很稳定,时间基本小于1ms的。

这说明什么?说明我的代码有问题啊,初步怀疑是接收和发送函数有问题,接着又是各种度娘啊,还是没有什么用啊,当时那个心情啊!本以为很容易的一件事结果拖了好几个星期了!!心急啊,但是又有什么办法啊,面对庞大的UCOSII和LWIP协议栈,顿时慌了手脚啊,当时感觉那个无助啊,就像被抛弃到了一个荒岛一样!前两天再看其他参考例程的时候突然灵光一现,发现虽然其他代码都使用了DM9000的中断,但是却没有一个在DM9000的中断中接收数据,而是在中断中发送一个信号量(参考的代码都是带系统的),其他的任务接收该信号量,做任务同步,数据的接收在专门的接收任务中完成!!而我的数据接收是直接放在了DM9000的中断服务函数中,在进入中断的时候是要关闭中断的,这样有新的数据来时就会塞进MD9000的RX SRAM中,很容易导致overflow!接着就是死掉!昨天把数据的接收放到了一个任务中,中断里面也只是发送一个信号量,这样关中断时间就大大减小了,经过测试,ping好几个小时都没有挂掉,ping的时间基本也小于等于1ms。

单片机驱动DM9000网卡芯片(详细调试过程)

单片机驱动DM9000网卡芯片(详细调试过程)

单片机驱动DM9000网卡芯片(详细调试过程)【上和下】和其它网卡芯片不同,DM9000系列网卡芯片在嵌入式开发板上很常见,尤其是有关ARM-Linux 的开发板上的网络连接部分几乎都是采用该芯片完成的。

当然,其它网卡芯片,如RTL8019的应用也很常见,在很多开发板上得到应用然而RTL8019的介绍在网上可以找到非常详细的介绍,尤其是用单片机对其做底层驱动的介绍非常丰富。

下面的网站就介绍了用AVR驱动RTL8019网卡芯片的非常详细的过程,有兴趣的朋友可以参考一下。

http://members.home.nl/bzijlstra/software/examples/RTL8019as.htm AVR驱动RTL8019网卡芯片的详细介绍。

言归正传。

在网上也能找到许多关于DM9000网卡芯片的介绍,然而这些介绍大多是关于Linux或WinCE下的驱动程序或移植,很少有介绍单片机驱动DM9000的例子。

因此我在这里把我调试DM9000E的过程详细说明一下,仅供参考。

本文主要介绍单片机驱动DM9000E网卡芯片的详细过程。

从网卡电路的连接,到网卡初始化相关程序调试,再到ARP协议的实现,一步一步详细介绍调试过程。

如果有时间也会把UDP和TCP通讯实验过程写出来。

当然,会用单片机编写DM9000的驱动,再想编写ARM下的Linux的驱动就容易的多了。

在调试之前,应该先参考两份技术文档,可以从下面网站中下载。

DM9000E.pdf(芯片数据资料)和 DM9000 Application Notes Ver 1_22 061104.pdf(应用手册)或者DM9000 Datasheet VF03:/userfile/24247/DM9000-DS-F03-041906_1.pdfDM9000A Datasheet:/userfile/24247/DM9000A-DS-F01-101906.pdfDM9000 Application Notes V1.22/big5/download/Data%20Sheet/DM9000_Application_Notes_Ver_1 _22%20061104.pdf一、电路连接DM9000E网卡芯片支持8位、16位、32位模式的处理器,通过芯片引脚EEDO(65脚)和WAKEUP(79脚)的复位值设置支持的处理器类型,如16位处理器只需将这两个引脚接低电平即可,其中WAKEUP内部有60K下拉电阻,因此可悬空该引脚,或作为网卡芯片唤醒输出用。

DM9000网卡调试教程

DM9000网卡调试教程

DIY_DE2之DM9000A网卡调试系列例程(一)——准备工作一、摘要根据最近一段时间的工作,将DIY_DE2中的网卡DM9000A所涉及到的例程做了调试,接下来几篇博文将循序渐进的阐述这些例程的实现过程,涉及到的具体原理及理论将会另开博文叙述。

本篇主要阐述一下调试例程前的准备工作。

二、准备工作1、网线经常接触的网线叫双绞线,双绞线有2种,直通线和交叉线,通常又把后者叫做双机互联线。

前者用于连接计算机与交换机、HUB等,后者用于连接计算机与计算机,交换机与交换机等。

上图即是交叉线的制作方法,有时别人给制作并不是严格按照上图的对应颜色,但只要RJ-45水晶头满足1和3对调,2和6对调即可。

后续的几篇例程除了用到这种交叉线外,DM9000A自收发的例程还用到另外一种线,这种线也极为简单,只留网线的一边水晶头,另外一头剪掉,对照留下的那头的线序,将剪掉那头的线1和3连接,2和6连接,为了测试连线是否正常,可以将水晶头插入电脑RJ-45里面,若网口灯亮,则说明连接正常。

定义该种网线为网线A,交叉线为网线B。

2、Altera不同版本软件的安装NIOS II中有TCP/IP模板程序,根据Altera不同版本软件,实现TCP/IP所使用的协议栈却不同;低版本(7.2版本以下)使用的是LWIP协议栈,而高版本中摒弃了LWIP协议栈,使用的是NicheStack 协议栈,前者不需要授权,而后者需要授权。

后续的几篇博文中,分别实现了LWIP协议栈和NicheStack协议栈,因此需要安装不同版本的Altera 软件。

Altera的软件,高版本兼容低版本。

如果安装了6.0版本的,再安装了9.0版本的,则6.0版本的就不能用了。

这里有个处理技巧:(1)在安装完6.0版本之后,记录一下跟其相关的系统变量。

(2)之后安装9.0版本的软件,记录一下跟其相关的系统变量。

(3)使用9.0的时候,将系统变量的值修改成9.0的即可。

dm9000网卡驱动分析

dm9000网卡驱动分析

DM9000 驱动程序分析1. 模块注册static int __init dm9000_init(void){printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME,DRV_VERSION);return platform_driver_register(&dm9000_driver);}static struct platform_driver dm9000_driver = {.driver = {.name = "dm9000",.owner = THIS_MODULE,},.probe = dm9000_probe,.remove = __devexit_p(dm9000_drv_remove),.suspend = dm9000_drv_suspend,.resume = dm9000_drv_resume,};2. 驱动初始化static int __devinitdm9000_probe(struct platform_device *pdev){struct dm9000_plat_data *pdata = pdev->dev.platform_data;struct board_info *db; /* Point a board information structure */struct net_device *ndev;const unsigned char *mac_src;int ret = 0;int iosize;int i;u32 id_val;/* Init network device */ndev = alloc_etherdev(sizeof(struct board_info));if (!ndev) {dev_err(&pdev->dev, "could not allocate device.\n");return -ENOMEM;}SET_NETDEV_DEV(ndev, &pdev->dev);dev_dbg(&pdev->dev, "dm9000_probe()\n");/* setup board info structure */db = netdev_priv(ndev);memset(db, 0, sizeof(*db));db->dev = &pdev->dev;db->ndev = ndev;spin_lock_init(&db->lock);mutex_init(&db->addr_lock);INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);if (db->addr_res == NULL || db->data_res == NULL ||db->irq_res == NULL) {dev_err(db->dev, "insufficient resources\n");ret = -ENOENT;goto out;}iosize = res_size(db->addr_res);db->addr_req = request_mem_region(db->addr_res->start, iosize,pdev->name);if (db->addr_req == NULL) {dev_err(db->dev, "cannot claim address reg area\n");ret = -EIO;goto out;}db->io_addr = ioremap(db->addr_res->start, iosize);if (db->io_addr == NULL) {dev_err(db->dev, "failed to ioremap address reg\n");ret = -EINVAL;goto out;}iosize = res_size(db->data_res);db->data_req = request_mem_region(db->data_res->start, iosize,pdev->name);if (db->data_req == NULL) {dev_err(db->dev, "cannot claim data reg area\n");ret = -EIO;goto out;}db->io_data = ioremap(db->data_res->start, iosize);if (db->io_data == NULL) {dev_err(db->dev, "failed to ioremap data reg\n");ret = -EINVAL;goto out;}/* fill in parameters for net-dev structure */ndev->base_addr = (unsigned long)db->io_addr;ndev->irq = db->irq_res->start;/* ensure at least we have a default set of IO routines */dm9000_set_io(db, iosize);/* check to see if anything is being over-ridden */if (pdata != NULL) {/* check to see if the driver wants to over-ride the* default IO width */if (pdata->flags & DM9000_PLATF_8BITONLY)dm9000_set_io(db, 1);if (pdata->flags & DM9000_PLATF_16BITONLY)dm9000_set_io(db, 2);if (pdata->flags & DM9000_PLATF_32BITONLY)dm9000_set_io(db, 4);/* check to see if there are any IO routine* over-rides */if (pdata->inblk != NULL)db->inblk = pdata->inblk;if (pdata->outblk != NULL)db->outblk = pdata->outblk;if (pdata->dumpblk != NULL)db->dumpblk = pdata->dumpblk;db->flags = pdata->flags;}#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLLdb->flags |= DM9000_PLATF_SIMPLE_PHY;#endifdm9000_reset(db);/* try multiple times, DM9000 sometimes gets the read wrong */for (i = 0; i < 8; i++) {id_val = ior(db, DM9000_VIDL);id_val |= (u32)ior(db, DM9000_VIDH) << 8;id_val |= (u32)ior(db, DM9000_PIDL) << 16;id_val |= (u32)ior(db, DM9000_PIDH) << 24;if (id_val == DM9000_ID)break;dev_err(db->dev, "read wrong id 0x%08x\n", id_val);}if (id_val != DM9000_ID) {dev_err(db->dev, "wrong id: 0x%08x\n", id_val);ret = -ENODEV;goto out;}/* Identify what type of DM9000 we are working on */id_val = ior(db, DM9000_CHIPR);dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);switch (id_val) {case CHIPR_DM9000A:db->type = TYPE_DM9000A;break;case CHIPR_DM9000B:db->type = TYPE_DM9000B;break;default:dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);db->type = TYPE_DM9000E;}/* from this point we assume that we have found a DM9000 *//* driver system function */ether_setup(ndev);ndev->open = &dm9000_open;ndev->hard_start_xmit = &dm9000_start_xmit;ndev->tx_timeout = &dm9000_timeout;ndev->watchdog_timeo = msecs_to_jiffies(watchdog);ndev->stop = &dm9000_stop;ndev->set_multicast_list = &dm9000_hash_table;ndev->ethtool_ops = &dm9000_ethtool_ops;ndev->do_ioctl = &dm9000_ioctl;#ifdef CONFIG_NET_POLL_CONTROLLERndev->poll_controller = &dm9000_poll_controller;#endifdb->msg_enable = NETIF_MSG_LINK;db->mii.phy_id_mask = 0x1f;db->mii.reg_num_mask = 0x1f;db->mii.force_media = 0;db->mii.full_duplex = 0;db->mii.dev = ndev;db->mii.mdio_read = dm9000_phy_read;db->mii.mdio_write = dm9000_phy_write;mac_src = "eeprom";/* try reading the node address from the attached EEPROM */for (i = 0; i < 6; i += 2)dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {mac_src = "platform data";memcpy(ndev->dev_addr, pdata->dev_addr, 6);}if (!is_valid_ether_addr(ndev->dev_addr)) {/* try reading from mac */mac_src = "chip";for (i = 0; i < 6; i++)ndev->dev_addr[i] = ior(db, i+DM9000_PAR);}if (!is_valid_ether_addr(ndev->dev_addr))dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please ""set using ifconfig\n", ndev->name);platform_set_drvdata(pdev, ndev);ret = register_netdev(ndev);if (ret == 0)printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",ndev->name, dm9000_type_to_char(db->type),db->io_addr, db->io_data, ndev->irq,ndev->dev_addr, mac_src);return 0;out:dev_err(db->dev, "not found (%d).\n", ret);dm9000_release_board(pdev, db);free_netdev(ndev);return ret;}3.打开网卡static int dm9000_open(struct net_device *dev){board_info_t *db = netdev_priv(dev);unsigned long irqflags = db->irq_res->flags &IRQF_TRIGGER_MASK;if (netif_msg_ifup(db))dev_dbg(db->dev, "enabling %s\n", dev->name);/* If there is no IRQ type specified, default to something that* may work, and tell the user that this is a problem */if (irqflags == IRQF_TRIGGER_NONE)dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");irqflags |= IRQF_SHARED;if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))return -EAGAIN;/* Initialize DM9000 board */dm9000_reset(db);dm9000_init_dm9000(dev);/* Init driver variable */db->dbug_cnt = 0;mii_check_media(&db->mii, netif_msg_link(db), 1);netif_start_queue(dev);dm9000_schedule_poll(db);return 0;}4.数据发送static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) {unsigned long flags;board_info_t *db = netdev_priv(dev);dm9000_dbg(db, 3, "%s:\n", __func__);if (db->tx_pkt_cnt > 1)return 1;spin_lock_irqsave(&db->lock, flags);/* Move data to DM9000 TX RAM */writeb(DM9000_MWCMD, db->io_addr);(db->outblk)(db->io_data, skb->data, skb->len);dev->stats.tx_bytes += skb->len;db->tx_pkt_cnt++;/* TX control: First packet immediately send, second packet queue */ if (db->tx_pkt_cnt == 1) {/* Set TX length to DM9000 */iow(db, DM9000_TXPLL, skb->len);iow(db, DM9000_TXPLH, skb->len >> 8);/* Issue TX polling command */iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */dev->trans_start = jiffies; /* save the time stamp */ } else {/* Second packet */db->queue_pkt_len = skb->len;netif_stop_queue(dev);}spin_unlock_irqrestore(&db->lock, flags);/* free this SKB */dev_kfree_skb(skb);return 0;}5.数据接收static irqreturn_t dm9000_interrupt(int irq, void *dev_id){struct net_device *dev = dev_id;board_info_t *db = netdev_priv(dev);int int_status;unsigned long flags;u8 reg_save;dm9000_dbg(db, 3, "entering %s\n", __func__);/* A real interrupt coming *//* holders of db->lock must always block IRQs */spin_lock_irqsave(&db->lock, flags);/* Save previous register address */reg_save = readb(db->io_addr);/* Disable all interrupts */iow(db, DM9000_IMR, IMR_PAR);/* Got DM9000 interrupt status */int_status = ior(db, DM9000_ISR); /* Got ISR */iow(db, DM9000_ISR, int_status); /* Clear ISR status */if (netif_msg_intr(db))dev_dbg(db->dev, "interrupt status %02x\n", int_status);/* Received the coming packet */if (int_status & ISR_PRS)dm9000_rx(dev);/* Trnasmit Interrupt check */if (int_status & ISR_PTS)dm9000_tx_done(dev, db);if (db->type != TYPE_DM9000E) {if (int_status & ISR_LNKCHNG) {/* fire a link-change request */schedule_delayed_work(&db->phy_poll, 1);}}/* Re-enable interrupt mask */iow(db, DM9000_IMR, db->imr_all);/* Restore previous register address */writeb(reg_save, db->io_addr);spin_unlock_irqrestore(&db->lock, flags);return IRQ_HANDLED;}static voiddm9000_rx(struct net_device *dev){board_info_t *db = netdev_priv(dev);struct dm9000_rxhdr rxhdr;struct sk_buff *skb;u8 rxbyte, *rdptr;bool GoodPacket;int RxLen;/* Check packet ready or not */do {ior(db, DM9000_MRCMDX); /* Dummy read *//* Get most updated data */rxbyte = readb(db->io_data);/* Status check: this byte must be 0 or 1 */if (rxbyte > DM9000_PKT_RDY) {dev_warn(db->dev, "status check fail: %d\n", rxbyte);iow(db, DM9000_RCR, 0x00); /* Stop Device */iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */return;}if (rxbyte != DM9000_PKT_RDY)return;/* A packet ready now & Get status/length */GoodPacket = true;writeb(DM9000_MRCMD, db->io_addr);(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));RxLen = le16_to_cpu(rxhdr.RxLen);if (netif_msg_rx_status(db))dev_dbg(db->dev, "RX: status %02x,length %04x\n",rxhdr.RxStatus, RxLen);/* Packet Status check */if (RxLen < 0x40) {GoodPacket = false;if (netif_msg_rx_err(db))dev_dbg(db->dev, "RX: Bad Packet (runt)\n");}if (RxLen > DM9000_PKT_MAX) {dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);}/* rxhdr.RxStatus is identical to RSR register. */if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |RSR_PLE | RSR_RWTO |RSR_LCS | RSR_RF)) {GoodPacket = false;if (rxhdr.RxStatus & RSR_FOE) {if (netif_msg_rx_err(db))dev_dbg(db->dev, "fifo error\n");dev->stats.rx_fifo_errors++;}if (rxhdr.RxStatus & RSR_CE) {if (netif_msg_rx_err(db))dev_dbg(db->dev, "crc error\n");dev->stats.rx_crc_errors++;}if (rxhdr.RxStatus & RSR_RF) {if (netif_msg_rx_err(db))dev_dbg(db->dev, "length error\n");dev->stats.rx_length_errors++;}}/* Move data from DM9000 */if (GoodPacket&& ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {skb_reserve(skb, 2);rdptr = (u8 *) skb_put(skb, RxLen - 4);/* Read received packet from RX SRAM */(db->inblk)(db->io_data, rdptr, RxLen);dev->stats.rx_bytes += RxLen;/* Pass to upper layer */skb->protocol = eth_type_trans(skb, dev);netif_rx(skb);dev->stats.rx_packets++;} else {/* need to dump the packet's data */(db->dumpblk)(db->io_data, RxLen);}} while (rxbyte == DM9000_PKT_RDY);}。

DM9000网卡芯片详细调试过程

DM9000网卡芯片详细调试过程

DM9000网卡芯片详细调试过程1.硬件接入:将DM9000芯片与主控芯片相连接。

DM9000芯片需要与主控芯片通过SPI、I2C或8位数据总线相连接。

同时,还需要给DM9000芯片供电。

2.芯片驱动:需要编写相关的DM9000驱动程序,确保主控芯片可以与DM9000芯片进行通信。

驱动程序一般会提供一些API函数,可以通过调用这些函数来操作DM9000芯片。

3.软件配置:使用DM9000驱动程序进行软件配置,以设置一些基本参数,例如MAC地址、IP地址、子网掩码等。

这些参数在网络通信中是必须的。

4.连接网络:确保主控芯片与DM9000芯片所在的嵌入式系统已经连接到网络中,可以通过路由器进行连接。

5.测试通信:编写通信测试程序,利用DM9000芯片进行网络通信测试。

可以测试网卡是否可以正常接收和发送数据包。

通过打印调试信息,可以了解网络通信的过程和结果。

以上是DM9000网卡芯片的详细调试过程的基本步骤。

下面将更加详细地介绍每个步骤:1.硬件接入:根据DM9000芯片的硬件接口,将其与主控芯片连接。

DM9000芯片可以通过SPI、I2C或8位数据总线进行连接,具体的连接方式需根据系统需求进行选择。

同时,还需要正确连接DM9000芯片的供电引脚,确保芯片正常工作。

2.芯片驱动:编写DM9000驱动程序,确保主控芯片可以与DM9000芯片进行通信。

驱动程序一般需要提供一些API函数,例如初始化函数、发送数据函数和接收数据函数等。

这些API函数会通过SPI、I2C或8位数据总线来操作DM9000芯片,以完成相应的功能。

3.软件配置:在驱动程序中提供相应的函数,用于配置DM9000芯片的相关参数。

例如,设置MAC地址、IP地址和子网掩码等。

这些参数在网络通信中是必须的,可以通过调用驱动程序提供的函数进行配置。

4.连接网络:确保主控芯片与DM9000芯片所在的嵌入式系统已经连接到网络中,可以通过路由器进行连接。

【驱动】DM9000A网卡驱动框架源码分析

【驱动】DM9000A网卡驱动框架源码分析

【驱动】DM9000A⽹卡驱动框架源码分析Linux⽹络设备结构 ⾸先看⼀下Linux⽹络设备的结构,如下图:1. ⽹络协议接⼝层向⽹络层协议提供提供统⼀的数据包收发接⼝,不论上层协议为ARP还是IP,都通过dev_queue_xmit()函数发送数据,并通过netif_rx()函数接受数据。

这⼀层的存在使得上层协议独⽴于具体的设备。

2. ⽹络设备接⼝层向协议接⼝层提供统⼀的⽤于描述具体⽹络设备属性和操作的结构体net_device,该结构体是设备驱动功能层中各函数的容器。

实际上,⽹络设备接⼝层从宏观上规划了具体操作硬件的设备驱动功能层的结构。

3. 设备驱动功能层各函数是⽹络设备接⼝层net_device数据结构的具体成员,是驱使⽹络设备硬件完成相应动作的程序,他通过hard_start_xmit()函数启动发送操作,并通过⽹络设备上的中断触发接受操作。

4. ⽹络设备与媒介层是完成数据包发送和接受的物理实体,包括⽹络适配器和具体的传输媒介,⽹络适配器被驱动功能层中的函数物理上驱动。

对于Linux系统⽽⾔,⽹络设备和媒介都可以是虚拟的。

上⾯的结构还可以细分,如下图⽹络协议接⼝层 这⾥主要进⾏数据包的收发,使⽤函数原型为:dev_queue_xmit(struct sk_buff *skb);int netif_rx(struct sk_buff *skb); 这⾥使⽤了⼀个skb_buff结构体,定义于include/linux/skbuff.h中,它的含义为“套接字缓冲区”,⽤于在Linux⽹络⼦系统各层间传输数据。

它是⼀个双向链表,在⽼的内核中会有⼀个list域指向sk_buff_head也就是链表头,但是在linux2.6.30.4内核后已经不存在了,如下图:操作套接字缓冲区的函数1.分配struct sk_buff *alloc_skb(unsigned int len, int priority);struct sk_buff *dev_alloc_skb(unsigned int len); 分配⼀个缓冲区。

经典DM9000驱动详解

经典DM9000驱动详解

DM9000 驱动移植及源码简析(1)/whs08/blog/item/384fee175781f1094a90a7a5.html转自/User/lvembededsys/Article/6856_1.htm在成功移植Dm9000驱动到我的EIEVK-100(SMDK2440)开发板的前提下,本文从以下几个方面说明相关原理及过程:1.硬件情况2.Dm9000驱动移植详细过程3.Platform_device与platform_driver4.Dm9000驱动代码简要分析一. 硬件情况DM9000在电路板上的连接中与编程相关的如下:1)EECS拉高:16bit模式;2)EECK拉高,INT连接到2440 EINT7:INT脚为低时为有效中断信号,中断线为EINT73)cs连接到2440的nGCS2,CMD连接2440地址总线ADDR[2]:INDEX和DATA端口地址分别为0x1000_0000和0x1000_0004。

知道上面这些信息已经足够移植驱动了。

二. Dm9000驱动移植详细过程1.在内核编译配置选项中,driver-->net-->10/100M net-->DM9000 support 选项选中。

2.在arch/arm/mach-s3c2410/devs.c 中添加dm9000的platform_device。

/* Add Dm9000 platform_device beelike@ */#includestatic struct resource eievk_dm9000_resource[] = {[0]= {.start = 0x10000000, //this is based on EIEVK board.end = 0x10000003,.flags = IORESOURCE_MEM,},[1]={.start = 0x10000004,.end = 0x10000007,.flags = IORESOURCE_MEM,},[2]={.start = IRQ_EINT7,.end = IRQ_EINT7,.flags = IORESOURCE_IRQ,}};static struct dm9000_plat_data eievk_dm9000_platdata ={.flags = DM9000_PLATF_16BITONLY,//work in 16bit mode};struct platform_device eievk_dm9000_device = {.name = "dm9000",.id = -1,.num_resources = 3,.resource = eievk_dm9000_resource,.dev = {.platform_data = &eievk_dm9000_platdata,}};EXPORT_SYMBOL(eievk_dm9000_device);/*end add beelike@ */3.在arch/arm/mach-s3c2410/devs.h中声明平台设备eievk_dm9000_device :extern struct platform_device eievk_dm9000_device;4.在arm/arm/mach-s3c2410/mach-smdk2410.c中将eievk_dm9000_device添加到平台设备列表中:static struct platform_device *smdk2440_devices[] __initdata = {&s3c_device_usb,&s3c_device_lcd,&s3c_device_wdt,&s3c_device_i2c,&s3c_device_iis,&eievk_dm9000_device, //add dm9000 by beelike&s3c_device_nand,};5.OK,经过上述努力,Dm9000设备已经成功注册进入驱动核心。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

单片机驱动DM9000网卡芯片(详细调试过程)【上】2008年05月19日星期一 18:02和其它网卡芯片不同,DM9000系列网卡芯片在嵌入式开发板上很常见,尤其是有关ARM-Linux的开发板上的网络连接部分几乎都是采用该芯片完成的。

当然,其它网卡芯片,如RTL8019的应用也很常见,在很多开发板上得到应用然而RTL8019的介绍在网上可以找到非常详细的介绍,尤其是用单片机对其做底层驱动的介绍非常丰富。

下面的网站就介绍了用AVR驱动RTL8019网卡芯片的非常详细的过程,有兴趣的朋友可以参考一下。

http://members.home.nl/bzijlstra/software/examples/RTL8019as.htm AVR驱动RTL8019网卡芯片的详细介绍。

言归正传。

在网上也能找到许多关于DM9000网卡芯片的介绍,然而这些介绍大多是关于Linux或WinCE下的驱动程序或移植,很少有介绍单片机驱动DM9000的例子。

因此我在这里把我调试DM9000E的过程详细说明一下,仅供参考。

本文主要介绍单片机驱动DM9000E网卡芯片的详细过程。

从网卡电路的连接,到网卡初始化相关程序调试,再到ARP协议的实现,一步一步详细介绍调试过程。

如果有时间也会把UDP和TCP通讯实验过程写出来。

当然,会用单片机编写DM9000的驱动,再想编写ARM下的Linux的驱动就容易的多了。

在调试之前,应该先参考两份技术文档,可以从下面网站中下载。

DM9000E.pdf(芯片数据资料)和 DM9000 Application Notes Ver 1_22 061104.pdf(应用手册)或者DM9000 Datasheet VF03:/userfile/24247/DM9000-DS-F03-041906_1.pdfDM9000A Datasheet:/userfile/24247/DM9000A-DS-F01-101906.pdfDM9000 Application Notes V1.22/big5/download/Data%20Sheet/DM9000_Application_Notes_Ver_1 _22%20061104.pdf一、电路连接DM9000E网卡芯片支持8位、16位、32位模式的处理器,通过芯片引脚EEDO(65脚)和WAKEUP(79脚)的复位值设置支持的处理器类型,如16位处理器只需将这两个引脚接低电平即可,其中WAKEUP内部有60K下拉电阻,因此可悬空该引脚,或作为网卡芯片唤醒输出用。

其它型号请参考相应的数据手册。

图1 DM9000引脚如图所示,对处理器驱动网卡芯片来说,我们比较关心的有以下几个引脚:IOR、IOW、AEN、CMD(SA2)、INT、RST,以及数据引脚SD0-SD15-SD31和地址引脚SA4-SA9。

其中,地址引脚配合AEN引脚来选通该网卡芯片,对于大多数的应用来说没有意义,因为在我们的应用中一般只用一个网卡芯片,而这些地址引脚主要用于在多网卡芯片环境下选择其中之一。

DM9000工作的默认基地址为0x300,这里我们按照默认地址选择,将SA9、SA8接高电平,SA7-DA4接低电平。

多网卡环境可以根据TXD0-TXD3配置SA4-SA7来选择不同的网卡,这里不做介绍,有兴趣的朋友请参考应用手册和数据手册。

数据引脚SD0-SD31则根据前面所讲的配置处理器模式与处理器的数据总线进行选择连接即可,没用到的引脚悬空。

那么,除了地址、数据引脚外,剩下的与处理器有关引脚对我们来说及其重要了,而与处理器无关的引脚,只需按照应用手册连接即可。

IOR和IOW是DM9000的读写选择引脚,低电平有效,即低电平时进行读(IOR)写(IOW)操作;AEN是芯片选通引脚,低电平有效,该引脚为低时才能进行读写操作;CMD的命令/数据切换引脚,低电平时读写命令操作,高电平时读写数据操作。

图2 读时序图3 写时序这些引脚接口和其它单片机外围器件的引脚接口基本相同,其使用也一样。

对于有总线接口的单片机来说,如51系列,ARM等直接连接即可。

对于没有总线接口的来说,如AVR mega32等可以直接用I/O引脚模拟总线时序进行连接。

连接时要参考读写时序,如上图所示。

具体连接电路,有时间我再画出来,暂时先略了。

二、编写驱动程序在这,我使用C语言编写驱动程序,这需要非常注意一点,即处理器所用的C编译器使用“大端格式”还是“小端格式”,这可以在相应处理器的C编译器说明上找到。

一般比较常见的是小端格式。

而对于8位处理器来说,在编写驱动程序时,可以不考虑,但是在编写网络协议的时候,一定好考虑,因为网络协议的格式是大端格式,而大部分编译器或者我们习惯的是小端格式,这一点需要注意。

在DM9000中,只有两个可以直接被处理器访问的寄存器,这里命名为CMD端口和DATA端口。

事实上,DM9000中有许多控制和状态寄存器(这些寄存器在上一篇文章中有详细的使用说明),但它们都不能直接被处理器访问,访问这些控制、状态寄存器的方法是:(1)、将寄存器的地址写到CMD端口;(2)、从DATA端口读写寄存器中的数据;1、读、写寄存器其实,INDEX端口和DATA端口的就是由芯片上的CMD引脚来区分的。

低电平为INDEX端口,高电平为DATA端口。

所以,要想实现读写寄存器,就必须先控制好CMD引脚。

若使用总线接口连接DM9000的话,假设总线连接后芯片的基地址为0x800300(24根地址总线),只需如下方法:#define DM_ADD (*((volatile unsigned int *) 0x8000300))#define DM_CMD (*((volatile unsigned int *) 0x8000304))//向DM9000寄存器写数据void dm9000_reg_write(unsigned char reg, unsigned char data){udelay(20);//之前定义的微妙级延时函数,这里延时20usDM_ADD = reg;//将寄存器地址写到INDEX端口udelay(20);DM_CMD = data;//将数据写到DATA端口,即写进寄存器}//从DM9000寄存器读数据unsigned int dm9000_reg_read(unsigned char reg){udelay(20);DM_ADD = reg;udelay(20);return DM_CMD;//将数据从寄存器中读出}只得注意的是前面的两个宏定义DM_ADD和DM_CMD,定义的内容表示指向无符号整形变量的指针,在这里0x800300是DM9000命令端口的地址,对它的赋值操作就相当于把数据写到该地址中,即把数据写到DM9000的命令端口中。

读的道理也一样。

这是一种很常见的宏定义,一般在处理器中定义通用寄存器也是这样定义的。

若没有总线接口的话,可以使用IO口模拟总线时序的方法实现寄存器的读写。

这里只说明实现步骤。

首先将处理器的I/O端口与DM9000的IOR等引脚直接相连(电平匹配的情况下),又假设已经有宏定义“IOR”I/O端口控制DM9000的IOR引脚,其它端口控制DM9000引脚的命名相同,“PIO1”(根据处理器情况,可以是8位、16位或32位的I/O端口组成)控制数据端口。

这样宏命名更直观些。

写寄存器的函数如下:void dm9000_reg_write(unsigned char reg, unsigned char data){PIO1 = reg;AEN = 0;CMD = 0;IOR = 1;IOW = 0;udelay(1);AEN = 1;IOW = 1;udelay(20);PIO1 = data;AEN = 0;CMD = 0;IOR = 1;IOW = 0;udelay(1);AEN = 1;IOW = 1;}读寄存器的写法类似,这里就略一下了。

这一过程看上去有些复杂,呵呵,其实执行起来也蛮有效率的,执行时间差不多。

这种模拟总线时序的方式实际并不复杂,只是把总线方式下自动执行的过程手动的执行了一遍而已。

在DM9000中,还有一些PHY寄存器,也称之为介质无关接口MII(Media Independent Interface)寄存器。

对这些寄存器的操作会影响网卡芯片的初始化和网络连接,这里不对其进行操作,所以对这些寄存器的访问方法这里也略了(在上篇文章中有介绍)。

操作不当反而使网卡不能连接到网络。

至此,我们已经写好了两个最基本的函数:dm9000_reg_write()和dm9000_reg_read(),以及前面的宏定义DM_ADD和DM_CMD。

下面将一直用到。

2、初始化DM9000网卡芯片。

初始化DM9000网卡芯片的过程,实质上就是填写、设置DM9000的控制寄存器的过程,这里以程序为例进行说明。

其中寄存器的名称宏定义在DM9000.H中已定义好。

注:一下函数中unsigned char为一个字节unsigned int为两个字节//DM9000初始化void DM9000_init(void){unsigned int i;IO0DIR |= 1 << 8;IO1CLR |= 1 << 8;udelay(500000);IO2SET |= 1 << 8;udelay(500000);IO1CLR |= 1 << 8;udelay(500000);/*以上部分是利用一个IO口控制DM9000的RST引脚,使其复位。

这一步可以省略,可以用下面的软件复位代替*/dm9000_reg_write(GPCR, 0x01);//设置 GPCR(1EH) bit[0]=1,使DM9000的GPIO3为输出。

dm9000_reg_write(GPR, 0x00);//GPR bit[0]=0 使DM9000的GPIO3输出为低以激活内部PHY。

udelay(5000);//延时2ms以上等待PHY上电。

dm9000_reg_write(NCR, 0x03);//软件复位udelay(30);//延时20us以上等待软件复位完成dm9000_reg_write(NCR, 0x00);//复位完成,设置正常工作模式。

dm9000_reg_write(NCR, 0x03);//第二次软件复位,为了确保软件复位完全成功。

此步骤是必要的。

udelay(30);dm9000_reg_write(NCR, 0x00);/*以上完成了DM9000的复位操作*/dm9000_reg_write(NSR, 0x2c);//清除各种状态标志位dm9000_reg_write(ISR, 0x3f);//清除所有中断标志位/*以上清除标志位*/dm9000_reg_write(RCR, 0x39);//接收控制dm9000_reg_write(TCR, 0x00);//发送控制dm9000_reg_write(BPTR, 0x3f);dm9000_reg_write(FCTR, 0x3a);dm9000_reg_write(RTFCR, 0xff);dm9000_reg_write(SMCR, 0x00);/*以上是功能控制,具体功能参考上一篇文章中的说明,或参考数据手册的介绍*/for(i=0; i<6; i++)dm9000_reg_write(PAR + i, mac_addr[i]);//mac_addr[]自己定义一下吧,6个字节的MAC地址/*以上存储MAC地址(网卡物理地址)到芯片中去,这里没有用EEPROM,所以需要自己写进去*//*关于MAC地址的说明,要参考网络相关书籍或资料*/dm9000_reg_write(NSR, 0x2c);dm9000_reg_write(ISR, 0x3f);/*为了保险,上面有清除了一次标志位*/dm9000_reg_write(IMR, 0x81);/*中断使能(或者说中断屏蔽),即开启我们想要的中断,关闭不想要的,这里只开启的一个接收中断*//*以上所有寄存器的具体含义参考上一篇文章,或参考数据手册*/}这样就对DM9000初始化完成了,怎么样,挺简单的吧。

相关文档
最新文档