一.网络模型

1.OSI(开放式系统互联模型)

从上往下依次是:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层。
2.Linux四层模型:从上往下依次是应用层,传输层,IP层,网络接口层。基于TCP/IP协议栈的模型。

二.DM9000物理结构
1.原理图

工作实质就是MAC通过MII控制PHY的过程。
2.网卡和网络模型的映射关系

MAC对应的是数据链路层,PHY对应的是物理层
3.MAC的工作原理

当网络协议栈的IP包送到网卡的时候,先要到达MAC,MAC就根据数据链路层的协议对接收到的数据进行封装,将IP包封装成以太网包,完成数据帧的构建。当然它还具备数据纠错以及传送控制等功能。
4.关于PHY
PHY是物理接口收发器。主要和实际的传输硬件打交道。他接收到来自MAC的以太网包,先加上校检码。然后按照物理层的规则进行数据编码,然后传输到物理介质,接受过程则与之相反。

5.MII即媒体独立接口。表明在MAC一定情况下,更换PHY是不会影响系统的工作的。因为他们最后都要遵循MII接口。故MII起到了MAC和PHY之间通信的桥梁作用。

三.DM9000的编程接口
1.DM9000的接口不是绝对开放的,不能像访问nand控制器那样直接按照地址去访问相关寄存器。
2.但是他提供了两个可以供CPU访问的接口,一个是index另一个是数据端口。
3.index的地址在mini2440上是0x20000300.原因是
(1)mini2440的原理图中

dm9000的片选信号AEN就是接到nLAN_CS片选。再看CPU原理图

我们可以看到nLAN_CS实质接在nGCS4上。再看datasheet

可以看到nGCS4对应的片选信号是0x20000000开头的,在0x20000000-0x28000000之间。所以index的地址开头是0x2********。即片选地址
(2)再看DM9000的datasheet

再看DM9000的TXD【2:0】的引脚接线情况
发现都是0,所以I/O base的地址是300H。即相对片选地址的位置。(相对地址,片选地址相当于基地址)。
(3)不管是index端口还是数据端口都是用SD0-SD15来传递数据。所以要区分具体某一时刻,这些数据到底是给那一个接口用。于是利用CMD引脚来区别。当CMD引脚是高电平的时候,SD上的数据是给数据接口用的,当CMD是低电平的时候,是给index接口用的。index接口是用来传递偏移量的。可以看到CMD接到CPU的ADDR2,当他为1的时候,就是为数据接口传送数据,即地址是0x20000304.当ADDR2为0的时候,SD是为index接口传送偏移量,即ADDR2为0,即地址是0x20000300.故我们找到了,片选地址,I/O base地址,以及数据接口地址。

四.DM9000初始化
1.片选信息设置
(1)数据宽度(BWSCON)
(2)时序信号填写(BANKCON4)
void dm9000_cs()
{/*1.数据宽度设置*/BWSCON &= ~(3 << 16);BWSCON |= (1 <<16);/*2.时序信号设置*/BANKCON4 = (0 << 13) | (0 << 11) | (7 << 8) | (1 << 6) | (0 << 4) | (0 << 2) | (0 << 0);}
2.中断初始化
(1)从原理图找到DM9000使用的中断源
(2)配置相应的中断引脚
(3)设置中断触发方式(高电平,EXTINT0)
(4)使能中断,设置中断屏蔽寄存器(INTMSK,EINTMSK)
(5)清除中断标志(SRCPND,INTPND,EINTPND)
void dm9000_int_init()
{/*1.设置中断引脚工作模式*/GPFCON &= ~(3 << 14);GPFCON |= (2 << 14);/*2.配置中断触发方式*/EXTINT0 &= ~(7 << 28);EXTINT0 |= (1 << 28);/*3.使能中断*/EINTMASK &= ~(1 << 7);INTMSK &= ~(1 << 4);   /*4.清除之前的中断标志*/EINTPEND |= (1 << 7);SRCPND |= (1 << 4);INTPND |= (1 << 4);
}
3.复位设备
(1)实现往DM9000读写数据的函数
(2)设置I/O为输出模式
(3)通过对GPIO0写0为内部的PHY提供电源
(4)软件复位(自动清0),MAC内部回环模式
(5)对(4)中的寄存器全部写入0
(6)重复(4)(5)
void dm9000_write(u16 reg,u16 data)
{DM_ADD = reg; DM_DAT = data;
}u8 dm9000_read(u16 reg)
{DM_ADD = reg;return DM_DAT;
}
void dm9000_reset()
{/*1.设置I/O为输出模式*/dm9000_write(DM9000_GPCR, GPCR_GPIO0_OUT);/*2.通过对GPIO0写入0为内部的PHY提供电源*/dm9000_write(DM9000_GPR, 0);/*3.软件复位(自动清0),MAC内部回环模式*/dm9000_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));/*4.对上一步的寄存器写入全0*/dm9000_write(DM9000_NCR, 0);/*5.重复(3)(4),用两次实现真正复位*/   dm9000_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));dm9000_write(DM9000_NCR, 0);
}
4.捕获网卡
(1)读取厂家ID
(2)读取product的ID
(3)将两个ID组合与之前预定义的网卡ID进行对比
u8 dm9000_probe()
{u32 id_val;/*1.读取厂家ID*/id_val = dm9000_read(DM9000_VIDL);id_val |= dm9000_read(DM9000_VIDH) << 8;/*2.读取产品ID并将其和厂家ID组合*/id_val |= dm9000_read(DM9000_PIDL) << 16;id_val |= dm9000_read(DM9000_PIDH) << 24;if (id_val == DM9000_ID) {printf("dm9000 is found !\n\r");return 0;} else {printf("dm9000 is not found !\n\r");return -1;}
}
5.MAC初始化
参照u-boot设置MAC
void dm9000_mac_init()
{/* Program operating register, only internal phy supported */dm9000_write(DM9000_NCR, 0x0);/* TX Polling clear */dm9000_write(DM9000_TCR, 0);/* Less 3Kb, 200us */dm9000_write(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);/* Flow Control : High/Low Water */dm9000_write(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));/* SH FIXME: This looks strange! Flow Control */dm9000_write(DM9000_FCR, 0x0);/* Special Mode */dm9000_write(DM9000_SMCR, 0);/* clear TX status */dm9000_write(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);/* Clear interrupt status */dm9000_write(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
}
6.填充MAC地址
利用循环分别填写六个寄存器,对应MAC地址的6个段

void dm9000_fill_macadd()
{u16 oft = 0,i = 0;/* fill device MAC address registers */for (i = 0; i < 6; i++)dm9000_write(DM9000_PAR + i, mac_addr[i]);/*maybe this is some problem*/for (i = 0, oft = 0x16; i < 8; i++, oft++)dm9000_write(oft, 0xff);/* read back mac, just to be sure */for (i = 0, oft = 0x10; i < 6; i++, oft++)printf("%02x:", dm9000_read(oft));printf("\n\r");}
7.激活DM9000
参照u-boot设置相关寄存器即可。

void dm9000_active()
{/* RX enable */dm9000_write(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);//要加上RCR_ALL,否则他会自动丢弃来自外部的广播包/* Enable TX/RX interrupt mask */dm9000_write(DM9000_IMR, IMR_PAR);}
8.初始化代码
void dm9000_init()
{/*1.片选信息设置*/dm9000_cs();/*2.中断初始化*/dm9000_int_init();/*3.复位设备*/dm9000_reset();/*4.捕获网卡*/if (dm9000_probe() < 0)return ;/*5.MAC初始化*/dm9000_mac_init();/*6.填充MAC地址*/dm9000_fill_macadd();/*7.激活DM9000*/dm9000_active();}
五.发送函数(有两个参数,待发送数据和发送长度)
1.禁止中断,避免干扰
(1)DM9000的IMR寄存器。
2.写入发送数据的长度
将长度分两次写入寄存器
3.写入待发送的数据
(1)将MWCMD赋值给地址端口,做好准备,MWCMD会自动将数据送到TX SRAM中。
(2)利用循环,将数据写入数据端口
4.启动发送
往TCR寄存器中写入命令,请求开始发送
5.等待发送结束
当发送结束的时候,TCR的0位会自动清0,所以去等待他变0即可。
6.判断发送结果是否正确,清除发送状态
往NSR寄存器中写入0x2C即可
7.打开中断,等待接收数据
将IMR的中断打开即可。(设置最后一位为1即可)

void dm9000_tx(u8* data, u32 length)
{u32 i = 0;/*1.禁止中断。避免干扰*/dm9000_write(DM9000_IMR,0x80);/*2.清除发送标志位*/dm9000_write(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR *//*3.写入发送数据长度*/dm9000_write(DM9000_TXPLL, length & 0xff);dm9000_write(DM9000_TXPLH, (length >> 8) & 0xff);/*4.写入待发送数据*/DM_ADD = DM9000_MWCMD;for(i=0;i<length;i+=2){DM_DAT = data[i] | (data[i+1]<<8);}/*5.启动发送*/dm9000_write(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete *//*6.等待发送完成*/while(dm9000_read(DM9000_TCR) & 0x01);/*7.清除发送状态*/dm9000_write(DM9000_NSR,0x2c);/*8.清除发送标志位*/dm9000_write(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR *//*9.使能接收中断*/dm9000_write(DM9000_IMR,0x81);}
六.接收函数
接收是中断处理的,接收到一个包就会产生中断。在中断处理的时候调用接收函数。
1.判断是否产生中断,是就继续,否则退出接收函数
读取ISR寄存器第0位即可。
2.清除中断
ISR寄存器第0位写1即可。
3.空读
读取MRCMDX寄存器
4.读取包的状态和长度
读取MRCMD寄存器得到状态,此时地址端口的数据就是对应MRCMD的偏移量,所以可以直接读取此时数据寄存器的值,不用再重新指定偏移量,就可以得到长度。在长度后面会自动送入有效的数据,所以后面可以页直接读数据寄存器得到有效数据。
5.读取包的数据
在读取数据之前应该对读到的长度进行检查,看是否小于以太网包的最大长度。然后利用for循环读取数据,注意数据的组合方式。

u16 dm9000_rx(u8* data)
{u32 i = 0;u16 status;u16 tmp,len;u8 ready;/*1.判断是否产生中断*/if (!(dm9000_read(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */return 0;/*2.清除中断*/dm9000_write(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 *//*3.空读*/ready = dm9000_read(DM9000_MRCMDX);/*if((ready & 0x01) != 0x01){ready = dm9000_read(DM9000_MRCMDX);if ((ready & 0x01) != 0x01)return 0;  }*//*4.读取包的状态和长度*/status = dm9000_read(DM9000_MRCMD);len = DM_DAT;/*5.读取包的数据*/if(len<DM9000_PKT_MAX){for(i=0;i<len;i+=2){tmp = DM_DAT;data[i] = tmp & 0x0ff;data[i+1] = (tmp>>8)&0x0ff;}}return len;
}
七.中断处理函数
1.调用接收函数存放接收到的数据
2.清除中断标志(SRCPND,INTPND,EINTPND)。
void int_issue()
{packet_len = dm9000_rx(&buffer[0]);net_handle(&buffer[0],packet_len); EINTPEND |= (1 << 7);SRCPND |= (1 << 4);INTPND |= (1 << 4);
}
3.中断文件的关键代码
else if(var1 == (4)){val = (*(EINTPEND))&(1 << 7);switch(val){case (1<<7):int_issue();break;default:break;    }   }       
3.关于ARP函数的实现请看下文
void dm9000_arp()
{while(1)arp_request();
}
八.ARP协议实现
1.以太网通讯格式
在计算机网络中,根据不同层的协议对要传输的数据进行封装,最重要实现的协议通常是以太网协议,即数据链路层协议。以太网包格式。

2.ARP功能简介
在计算机网络中,MAC地址是物理层的地址,是计算机唯一的身份标识。两台计算机要实现通信,必须知道彼此的MAC地址,但是一般情况用户只知道目标机的IP地址,这个时候,就可以用ARP(地址解析协议)来向局域网中的所有计算机发送ARP请求包,当然这个请求包有目标机的IP地址,符合条件的目标机接收到请求包以后,会作出应答,不符合条件的忽略该请求包。在应答包中目标机会将自己的MAC地址反馈给用户。所以ARP是一种通过IP地址获取MAC地址的协议。
3.ARP包格式

4.代码实现
(1)发送ARP请求包
--》构造请求包
--》ARP帧类型是0806
--》当未知MAC地址的时候,设置为全F
--》硬件类型是指硬件地址对应的类型,即以太网类型,编号为1
--》协议类型是指协议地址对应的类型,在这里协议地址是IP地址,IP类型的编号是0800
--》硬件地址长度即以太网地址长度,6个字节
--》协议地址长度即Ip地址长度4个字节
--》op为1表示请求,为0表示应答
--》发送端以太网地址就是以太网源地址,事先制定的,6个字节
--》发送端Ip地址是事先制定的,4个字节,注意:要和PC在同一网段
--》目的以太网地址,暂时不填,要获取的就是该数据
--》目的Ip地址就是PC的Ip实际地址。
--》调用DM9000发送函数发送包
--》可以讲上述构建的ARp请求包的地址赋值给u8 的指针,让该数组指向该请求包
--》然后发送长度为:(以太网)14 + (ARP真正请求部分)28.
--》头文件对数据结构进行创建
#ifndef __ARP_H__
#define __ARP_H__typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;#define SWAP(n) ((((u16)n & 0xff) << 8) | ((((u16)n >> 8) & 0xff)))/*以太网头部结构体*/
typedef struct eth_header{u8 d_mac[6];u8 s_mac[6];u16 frame_type;}ETH_HDR;/*ARP头部结构体*/
typedef struct arp_header{ETH_HDR ethhdr;u16 hw_type;u16 protocol;u8 hwadd_len;u8 protoc_len;u16 opcode;u8 smac[6];u8 sipaddr[4];u8 dmac[6];u8 dipaddr[4];}ARP_HDR;/*IP头部结构体*/
typedef struct ip_hdr
{ETH_HDR ethhdr;u8 vhl;u8 tos;u16 len;u16 ipid;u16 ipoffset;u8 ttl;u8 proto;u16 ipchksum;u8 srcipaddr[4];u8 destipaddr[4];
}IP_HDR;/*UDP头部结构体*/
typedef struct udp_hdr
{IP_HDR iphdr;u16 sport;u16 dport;u16 len;u16 udpchksum;
}UDP_HDR;/*TFTP数据包结构体*/
typedef struct tftp_package
{u16 opcode;u16 blocknum;u8 data[0];
}TFTP_PAK;ARP_HDR arpbuf;/*网络协议类型*/
#define PROTO_ARP 0x0806
#define PROTO_IP 0x0800
#define PROTO_UDP 0x11extern u8 host_mac_addr[6];
extern u8 mac_addr[6];
extern u8 ip_addr[4];
extern u8 host_ip_addr[4];
extern u16 packet_len;
#endif
那些extern变量在dm9000.c里定义,根据自己PC的IP来决定host_ip_addr
u8 buffer[1500];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,30};//根据自己的电脑设置,要和电脑IP在同一网段
u8 host_ip_addr[4] = {192,168,1,100};//根据自己的电脑的IP设置
u16 packet_len;
(2)在网络中默认主机是大端格式的,涉及到网络字节序。所以在发送端存储数据的时候要按照大端格式存储。所以整个包都要征对象的修改,地址可以不用改,但是数据要改。只针对由两个字节构成的数据,一个字节长度的不用改。涉及到地址都会用到memcpy函数。
#include "arp.h"void arp_request()
{/*1.构成ARP请求包*/memcpy(arpbuf.ethhdr.d_mac,host_mac_addr,6); //以太网目的地址memcpy(arpbuf.ethhdr.s_mac,mac_addr,6);        //以太网源地址arpbuf.ethhdr.frame_type = SWAP(0x0806);       //帧类型arpbuf.hw_type = SWAP(1);             //硬件类型arpbuf.protocol = SWAP(0x0800);          //协议类型arpbuf.hwadd_len = 6;                //硬件地址长度arpbuf.protoc_len = 4;             //协议地址长度arpbuf.opcode = SWAP(1);               //操作码memcpy(arpbuf.smac,mac_addr,6);            //发送端以太网地址,即以太网原地址memcpy(arpbuf.sipaddr,ip_addr,4);      //发送端IP地址memcpy(arpbuf.dipaddr,host_ip_addr,4);     //目的IP地址packet_len = 14+28;               //包的长度/*2.调用dm9000发送函数,发送请求包*/   dm9000_tx((u8*)&arpbuf,packet_len);
}
(3)解析ARP应答包,提取目标机MAC地址。
--》返回类型为u8
--》打印信息时候注意格式控制
u8 arp_respond(u8* buf,u32 len)
{ARP_HDR* p = (ARP_HDR*)buf;u32 i = 0;if(packet_len < 28)return 0;switch(SWAP(p->opcode)){case 2://对PC发到开发板的应答包解析memcpy(host_ip_addr,p->sipaddr,4);printf("host ip is : ");for(i=0;i<4;i++)printf("%03d ",host_ip_addr[i]);printf("\n\r");   memcpy(host_mac_addr,p->smac,6);printf("host mac is : ");for(i=0;i<6;i++)printf("%02X ",host_mac_addr[i]);printf("\n\r");    break;case 1://响应PC发到开发板的请求包memcpy(arpbuf.ethhdr.d_mac,p->ethhdr.s_mac,6);   //以太网目的地址memcpy(arpbuf.ethhdr.s_mac,mac_addr,6);        //以太网源地址arpbuf.ethhdr.frame_type = SWAP(0x0806);       //帧类型arpbuf.hw_type = SWAP(1);             //硬件类型arpbuf.protocol = SWAP(0x0800);          //协议类型arpbuf.hwadd_len = 6;                //硬件地址长度arpbuf.protoc_len = 4;             //协议地址长度arpbuf.opcode = SWAP(2);               //操作码memcpy(arpbuf.smac,mac_addr,6);            //发送端以太网地址,即以太网原地址memcpy(arpbuf.sipaddr,ip_addr,4);      //发送端IP地址memcpy(arpbuf.dmac,p->smac,6);memcpy(arpbuf.dipaddr,p->sipaddr,4);       //目的IP地址packet_len = 14+28;               //包的长度/*2.调用dm9000发送函数,发送请求包*/   dm9000_tx((u8*)&arpbuf,packet_len);break;default:break;  }return 1;
}
(4)抓包效果
--》我的PC的参数

--》Wireshark的效果
表明发送请求成功
--》看串口输出信息

表明解析成功。所以网卡驱动以及ARP协议都实现了。
注意:抓包的时候,必须让PC和开发板连接到用一个路由器。而且这个路由器最好不要联通外网,否则抓包效果不明显,因为很可能一旦接通外网,有很多计算机和你会在同一网段,你会接受到来自其他计算机的广播,不一定是ARP广播。
附上6410代码
/****************************
@File:dm9000.c
@
@Tiny6410裸机下学期代码
@网卡配置文件
@Author:小君君
@****************************/#include "common.h"
#include "dm9000.h"
#include "arp.h"u8 buffer[1536];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,30};//根据自己的电脑设置,要和电脑IP在同一网段
u8 host_ip_addr[4] = {192,168,1,112};//根据自己的电脑的IP设置
u16 packet_len;
u16 dm9000_rx(u8* data);extern void net_handle(u8* buf,u32 len);
void
dm9000_handle(void)
{//printf("dm9000 int\r\n");packet_len = dm9000_rx(&buffer[0]);net_handle(&buffer[0],packet_len);
}/*片选信息设置,就是SROM1的时序信息以及数据宽度的选择*/
void
dm9000_cs()
{/*Not using UB/LBWAIT disableData bus width control for Memory Bank1===》16bit*/(vi SROM_BW) &= ~(3 << 6);(vi SROM_BW) |= (1 << 4);/*Tacs = 2-cycle Tacp = 2-cycleTcos = 2-cycle Tcoh = 2-cycleTacc = 3-cycle Tcah = 2-cycle*/(vi SROM_BC1) |= ((2 << 4) | (2 << 8) | (2 << 12) | (2 << 16) | (2 << 24) | (2 << 28));
}/*中断初始化,用的是EINT7,中断处理函数在irq文件已初始化*/
void
dm9000_int_init()
{/*1.设置中断引脚的工作模式*/(vi GPNCON) &= ~(3 << 14);(vi GPNCON) |= (0x1 << 15);/*2.配置中断触发方式*/(vi EXT_INT_0_CON) &= ~(0x7 << 12);/*高电平触发*/(vi EXT_INT_0_CON) |= (1 << 12);/*3.使能中断*/(vi EXT_INT_0_MASK) = 0; /*使能EINT0--EINT27所有的外部中断*/ (vi VIC0INTENABLE) |= (1 << 1); /* bit0: eint0~3, bit1: eint4~11 ,我们用到EINT7*//*4.清除之前的中断标志*/(vi EXT_INT_0_PEND) = ~0x0;  (vi VIC0ADDRESS) = 0; /*5.注册中断处理函数*/(vi EINT1_VECTADDR) = (unsigned long)dm9000_handle;/*6.开启中断模式*/__asm__( "mov r0, #0x53\n""msr CPSR_cxsf, r0\n"           : : );
}/*向指定的寄存器写入数据*/
void
dm9000_write(u16 reg,u16 data)
{(*(volatile u16 *)DM_ADD) = reg;(*(volatile u16 *)DM_DAT) = data;
}/*读取数据*/
u8
dm9000_read(u16 reg)
{(*(volatile u16 *)DM_ADD) = reg;return (*(volatile u16 *)DM_DAT);}/*复位操作*/
void
dm9000_reset()
{int i = 1000;/*1.设置IO为输出模式*/dm9000_write(DM9000_GPCR, GPCR_GPIO0_OUT);/*2.通过对GPIO0写入0为内部的PHY提供电源*/dm9000_write(DM9000_GPR, 0);/*3.软件复位(自动清零),MAC内部回环模式*/dm9000_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));do {printf("resetting the DM9000, 1st reset\r\n");i = 1000;while(i--); /* Wait at least 20 us */} while (dm9000_read(DM9000_NCR) & 1);/*4.对上一部的寄存器写入全0*/dm9000_write(DM9000_NCR, 0);/*5.重复(3)(4),用两次实现真正复位*/dm9000_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));do {printf("resetting the DM9000, 1st reset\r\n");i = 1000;while(i--); /* Wait at least 20 us */} while (dm9000_read(DM9000_NCR) & 1);if ((dm9000_read(DM9000_PIDL) != 0x0) ||(dm9000_read(DM9000_PIDH) != 0x90))printf("ERROR: resetting DM9000 -> not responding\r\n");}u8
dm9000_probe()
{u32 id_val;/*1.读取厂家ID*/id_val = dm9000_read(DM9000_VIDL);id_val |= dm9000_read(DM9000_VIDH) << 8;/*2.读取产品ID并将其和厂家ID组合*/id_val |= dm9000_read(DM9000_PIDL) << 16;id_val |= dm9000_read(DM9000_PIDH) << 24;if (1) {printf("dm9000 i/o: 0x%X, id: 0x%X \r\n", CONFIG_DM9000_BASE,id_val);return 0;} else {printf("dm9000 is not found !\r\n");return -1;}
}
void
dm9000_mac_init()
{/* Program operating register, only internal phy supported */dm9000_write(DM9000_NCR, 0x0);/* TX Polling clear */dm9000_write(DM9000_TCR, 0);/* Less 3Kb, 200us */dm9000_write(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);/* Flow Control : High/Low Water */dm9000_write(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));/* SH FIXME: This looks strange! Flow Control */dm9000_write(DM9000_FCR, 0x0);/* Special Mode */dm9000_write(DM9000_SMCR, 0);/* clear TX status */dm9000_write(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);/* Clear interrupt status */dm9000_write(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
}
void
dm9000_fill_macadd()
{u16 oft = 0,i = 0;/* fill device MAC address registers */for (i = 0; i < 6; i++)dm9000_write(DM9000_PAR + i, mac_addr[i]);/*maybe this is some problem*/for (i = 0, oft = 0x16; i < 8; i++, oft++)dm9000_write(oft, 0xff);/* read back mac, just to be sure */printf("MAC:");for (i = 0, oft = 0x10; i < 6; i++, oft++)printf("%02X:", dm9000_read(oft));printf("\n\r");}
static u16
phy_read(int reg)
{u16 val;int i = 500000; //udelay(100);    /* Fill the phyxcer register into REG_0C */dm9000_write(DM9000_EPAR, DM9000_PHY | reg);dm9000_write(DM9000_EPCR, 0xc);  /* Issue phyxcer read command */while(i--);         /* Wait read complete */dm9000_write(DM9000_EPCR, 0x0); /* Clear phyxcer read command */val = (dm9000_read(DM9000_EPDRH) << 8) | dm9000_read(DM9000_EPDRL);/* The read data keeps on REG_0D & REG_0E */printf("phy_read(0x%x): 0x%x\r\n", reg, val);return val;
}/*Write a word to phyxcer
*/
static void
phy_write(int reg, u16 value)
{int i = 500000;/* Fill the phyxcer register into REG_0C */dm9000_write(DM9000_EPAR, DM9000_PHY | reg);/* Fill the written data into REG_0D & REG_0E */dm9000_write(DM9000_EPDRL, (value & 0xff));dm9000_write(DM9000_EPDRH, ((value >> 8) & 0xff));dm9000_write(DM9000_EPCR, 0xa);  /* Issue phyxcer write command */while(i--);            /* Wait write complete */dm9000_write(DM9000_EPCR, 0x0);    /* Clear phyxcer write command */printf("phy_write(reg:0x%x, value:0x%x)\r\n", reg, value);
}void
dm9000_active()
{/* RX enable */dm9000_write(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);//要加上RCR_ALL,否则他会自动丢弃来自外部的广播包/* Enable TX/RX interrupt mask */dm9000_write(DM9000_IMR, IMR_PAR);}
void
dm9000_init()
{int i = 0,m = 5000000,lnk;/*1.片选信息设置*/dm9000_cs();/*2.中断初始化*/dm9000_int_init();/*2.1.禁止中断。避免干扰*///dm9000_write(DM9000_IMR,0x80);/*3.复位设备*/dm9000_reset();/*4.捕获网卡*/if (dm9000_probe() < 0)return ;/*5.MAC初始化*/dm9000_mac_init();/*6.填充MAC地址*/dm9000_fill_macadd();/*7.激活DM9000*/dm9000_active();i = 0;while (!(phy_read(1) & 0x20)) {    /* autonegation complete bit */m = 5000000; //udelay(1000);while(m--);i++;if (i == 10000) {printf("could not establish link\r\n");return ;}}/* see what we've got */lnk = phy_read(17) >> 12;printf("operating at ");switch (lnk) {case 1:printf("10M half duplex ");break;case 2:printf("10M full duplex ");break;case 4:printf("100M half duplex ");break;case 8:printf("100M full duplex ");break;default:printf("unknown: %d ", lnk);break;}printf("mode\r\n");return ;}/*Hardware start transmission.Send a packet to media from the upper layer.
*/
void
dm9000_tx(u8* data, u32 length)
{u32 i = 0;/*1.禁止中断。避免干扰*/dm9000_write(DM9000_IMR,0x80);/*2.清除发送标志位*/dm9000_write(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR *//*3.写入发送数据长度*/dm9000_write(DM9000_TXPLL, length & 0xff);dm9000_write(DM9000_TXPLH, (length >> 8) & 0xff);/*4.写入待发送数据*/(*(volatile u16 *)DM_ADD) = DM9000_MWCMD;for(i=0;i<length;i+=2){(*(volatile u16 *)DM_DAT) = data[i] | (data[i+1]<<8);}/*5.启动发送*/dm9000_write(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete *//*6.等待发送完成*/while(dm9000_read(DM9000_TCR) & 0x01);/*7.清除发送状态*/dm9000_write(DM9000_NSR,0x2c);/*8.清除发送标志位*/dm9000_write(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR *//*9.使能接收中断*/dm9000_write(DM9000_IMR,0x81);//printf("transmit done\r\n\n");}u16 dm9000_rx(u8* data)
{u32 i = 0;u16 status;u16 tmp,len;u8 ready;/*1.判断是否产生中断*/if(dm9000_read(DM9000_ISR) & 0x01)dm9000_write(DM9000_ISR,0x01);elsereturn 0;/*2.清除中断*/dm9000_write(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 *//*3.空读*/ready = dm9000_read(DM9000_MRCMDX);/*if((ready & 0x01) != 0x01){ready = dm9000_read(DM9000_MRCMDX);if ((ready & 0x01) != 0x01)return 0;  }*//*4.读取包的状态和长度*/status = dm9000_read(DM9000_MRCMD);len = (*(volatile u16 *)DM_DAT);/*5.读取包的数据*/if(len<DM9000_PKT_MAX){for(i=0;i<len;i+=2){tmp = (*(volatile u16 *)DM_DAT);data[i] = tmp & 0x0ff;data[i+1] = (tmp>>8)&0x0ff;}}return len;
}void dm9000_arp()
{while(1)//可以让他每次只请求一次ARP,每输入一个字符在请求一次,看main函数的while循环就知道,但是要把你PC断开外网,否则会接收到来自其他PC的请求arp_request();
}void do_dmirq(void)
{void (*the_isr)(void);//printf("dm9000 int\r\n");// 读VICxADDRESS寄存器获得目前正在发生的中断的处理函数the_isr = (vi VIC0ADDRESS);// 调用中断处理函数the_isr();// 清中断(vi EXT_INT_0_PEND)   |= (1 << 7);(vi VIC0ADDRESS) = 0;}
/****************************
@File:arp.c
@
@Tiny6410裸机下学期代码
@ARP协议文件
@Author:小君君
@****************************/#include "arp.h"void arp_request()
{/*1.构成ARP请求包*/memcpy(arpbuf.ethhdr.d_mac,host_mac_addr,6); //以太网目的地址memcpy(arpbuf.ethhdr.s_mac,mac_addr,6);        //以太网源地址arpbuf.ethhdr.frame_type = SWAP(0x0806);       //帧类型arpbuf.hw_type = SWAP(1);             //硬件类型arpbuf.protocol = SWAP(0x0800);          //协议类型arpbuf.hwadd_len = 6;                //硬件地址长度arpbuf.protoc_len = 4;             //协议地址长度arpbuf.opcode = SWAP(1);               //操作码memcpy(arpbuf.smac,mac_addr,6);            //发送端以太网地址,即以太网原地址memcpy(arpbuf.sipaddr,ip_addr,4);      //发送端IP地址memcpy(arpbuf.dipaddr,host_ip_addr,4);     //目的IP地址packet_len = 14+28;               //包的长度/*2.调用dm9000发送函数,发送请求包*/   dm9000_tx((u8*)&arpbuf,packet_len);
}u8 arp_respond(u8* buf,u32 len)
{//printf("dm_arp int\r\n");ARP_HDR* p = (ARP_HDR*)buf;u32 i = 0;if(packet_len < 28){printf("rx failed!\r\n");return 0;}switch(SWAP(p->opcode)){case 2://对PC发到开发板的应答包解析memcpy(host_ip_addr,p->sipaddr,4);printf("host ip is : ");for(i=0;i<4;i++)printf("%03d ",host_ip_addr[i]);printf("\n\r"); memcpy(host_mac_addr,p->smac,6);printf("host mac is : ");for(i=0;i<6;i++)printf("%02X ",host_mac_addr[i]);printf("\n\r");    break;case 1://响应PC发到开发板的请求包memcpy(arpbuf.ethhdr.d_mac,p->ethhdr.s_mac,6);   //以太网目的地址memcpy(arpbuf.ethhdr.s_mac,mac_addr,6);        //以太网源地址arpbuf.ethhdr.frame_type = SWAP(0x0806);       //帧类型arpbuf.hw_type = SWAP(1);             //硬件类型arpbuf.protocol = SWAP(0x0800);          //协议类型arpbuf.hwadd_len = 6;                //硬件地址长度arpbuf.protoc_len = 4;             //协议地址长度arpbuf.opcode = SWAP(2);               //操作码memcpy(arpbuf.smac,mac_addr,6);            //发送端以太网地址,即以太网原地址memcpy(arpbuf.sipaddr,ip_addr,4);      //发送端IP地址memcpy(arpbuf.dmac,p->smac,6);memcpy(arpbuf.dipaddr,p->sipaddr,4);       //目的IP地址packet_len = 14+28;               //包的长度/*2.调用dm9000发送函数,发送请求包*/   dm9000_tx((u8*)&arpbuf,packet_len);break;default:break;  }return 1;
}
extern void tftp_process(u8* buf,u32 len,u16 port);
/*对UDP协议的包,进行处理。TFTP传输是属于UDP协议的,而UDP又是属于IP协议的*/
void udp_respond(u8* buf,u32 len)
{}/*对IP协议的包进行处理,因为可能涉及到IP协议的情况不只是TFTP传输,所以为以后程序功能升级做准备,就单独写一个判断函数*/
void ip_respond(u8* buf,u32 len)
{IP_HDR* iphdr = (IP_HDR*)buf;//printf("dm_ip int\r\n");if(iphdr->proto == PROTO_UDP)udp_respond(buf,len);
}/*对来自外部的包进行处理*/
void net_handle(u8* buf,u32 len)
{ETH_HDR* p = (ETH_HDR*)buf;//printf("dm_handle int%x\r\n",SWAP(p->frame_type));switch(SWAP(p->frame_type)){case PROTO_ARP:arp_respond(buf,len);   //ARP协议应答,目的是获取PC的MAC地址break;case PROTO_IP:ip_respond(buf,len);  //对数据传送的包进行处理break;default:break;}return;
}
/****************************
@File:common.h
@
@Tiny6410裸机下学期代码
@常用头文件定义
@Author:小君君
@****************************/#ifndef __COMMON_H__
#define __COMMON_H__#define  vi   *( volatile unsigned long * ) #define ulong unsigned longtypedef signed char s8;
typedef unsigned char u8;typedef signed short s16;
typedef unsigned short u16;typedef signed int s32;
typedef unsigned int u32;typedef signed long long s64;
typedef unsigned long long u64;/*取消使用mmu*///#define MMU_ENABLE 1
/*LED初始化*/#ifndef MMU_ENABLE#define LED_CON 0x7F008800#define LED_DAT  0x7F008808
#else#define LED_CON 0xA0008800#define LED_DAT  0xA0008808
#endifvoid mmu_init();void led_init();
void led_on();
void led_off();
void led1_on();
void led2_on();
void led3_on();
void led4_on();
void led5_on();
void led6_on();
void led7_on();
void led8_on();/*按键相关初始化*/
#define KEYCON  0x7f008830
#define KEYCON1 0x7f008814#define K1_MSK (3 << 0)
#define K2_MSK (3 << 2)
#define K3_MSK (3 << 4)
#define K4_MSK (3 << 6)
#define K5_MSK (3 << 8)
#define K6_MSK (3 << 10)
#define K7_MSK (0xF << 12)
#define K8_MSK (0xF << 16)#define K1_OK (2 << 0)
#define K2_OK (2 << 2)
#define K3_OK (2 << 4)
#define K4_OK (2 << 6)
#define K5_OK (2 << 8)
#define K6_OK (2 << 10)
#define K7_OK (0x3 << 12)
#define K8_OK (0x3 << 16)void button_init();/*中断控制器相关的寄存器地址*/
#define EXT_INT_0_CON       0x7f008900
#define EXT_INT_1_CON       0x7f008904
#define EXT_INT_0_MASK      0x7f008920
#define EXT_INT_0_PEND      0x7f008924     #define VIC0INTENABLE       0x71200010
#define VIC1INTENABLE       0x71300010#define EINT0_VECTADDR      0x71200100 /*每个中断源有一个寄存器存放相应的中断处理函数的地址,共32+32 = 64个*/
#define EINT1_VECTADDR      0x71200104
#define EINT2_VECTADDR      0x71200108
#define EINT3_VECTADDR      0x7120010C
#define EINT4_VECTADDR      0x71200110
#define EINT5_VECTADDR      0x71200114/*以上是VIC0,见6410datasheet的P414*/#define EINT19_VECTADDR     0x71300100
#define EINT20_VECTADDR     0x71300104 /*以上是VIC1*/#define VIC0ADDRESS         0x71200f00
#define VIC1ADDRESS         0x71300f00void irq_init();/*nandflash相关寄存器定义*/
#define NFCONF  0x70200000
#define NFCONT  0x70200004
#define NFCMMD  0x70200008
#define NFADDR  0x7020000C
#define NFDATA  0x70200010
#define NFDATA8 (*(volatile unsigned char *)0x70200010)
#define NFSTAT  0x70200028int nand_erase(unsigned int block_addr);
int Nand_PageWrite(unsigned long start_addr,char *buf);/*UART相关寄存器定义*/
#define UARTCON     0x7F008000
#define ULCON0      0x7F005000
#define UCON0       0x7F005004
#define UFCON0      0x7F005008
#define UMCON0      0x7F00500C
#define UTRSTAT0    0x7F005010
#define UFSTAT0     0x7F005018#define UTXH0      (*((volatile unsigned char *)0x7F005020))//注意是char类型的
#define URXH0      (*((volatile unsigned char *)0x7F005024))
#define UBRDIV0    (*((volatile unsigned short *)0x7F005028))//注意是short类型的
#define UDIVSLOT0  (*((volatile unsigned short *)0x7F00502C))#define UART_FIFO_ENABLE 1  //最好使用FIFO模式,就是必须有这个宏定义void uart_init();#ifdef  UART_FIFO_ENABLEchar getchar(void);void putchar(char c);void send_string(char* str);
#elseunsigned char getchar(void);void putchar(unsigned char c);void send_string(unsigned char* str);
#endif/*DMA相关定义*/#define UTXH0_DMA 0x7F005020
#define DMA_BASE 0x75000000#define DMACC0SrcAddr  (DMA_BASE + 0x100)
#define DMACC0DestAddr (DMA_BASE + 0x104)
#define DMACC0Control0 (DMA_BASE + 0x10C)#define DMACC0Control1 (DMA_BASE + 0x110)
#define DMACC0Configuration (DMA_BASE + 0x114)
#define DMACC0ConfigurationExp (DMA_BASE + 0x118)#define DMACC0LLI (DMA_BASE + 0x108)
#define DMACEnbldChns (DMA_BASE + 0x01C)
#define DMACConfiguration (DMA_BASE + 0x030)
#define DMACSync (DMA_BASE + 0x034)
#define DMA_SEL 0x7E00F110void dma_init();
void dma_start();/*LCD相关寄存器定义*/
#define GPECON  0x7F008080
#define GPEDAT  0x7F008084
#define GPEPUD  0x7F008088
#define GPFCON  0x7F0080A0
#define GPFDAT  0x7F0080A4
#define GPFPUD  0x7F0080A8
#define GPICON  0x7F008100
#define GPIPUD  0x7F008108
#define GPJCON  0x7F008120
#define GPJPUD  0x7F008128/* display controller */
#define MIFPCON     0x7410800C
#define SPCON           0x7F0081A0
#define VIDCON0         0x77100000
#define VIDCON1         0x77100004
#define VIDTCON0        0x77100010
#define VIDTCON1        0x77100014
#define VIDTCON2        0x77100018
#define WINCON0         0x77100020
#define VIDOSD0A        0x77100040
#define VIDOSD0B        0x77100044
#define VIDOSD0C        0x77100048
#define VIDW00ADD0B0    0x771000A0
#define VIDW00ADD1B0    0x771000D0
#define VIDW00ADD2      0x77100100
#define DITHMODE        0x77100170#define FRAME_BUFFER   0x54000000
#define ROW             272
#define COL             480
#define HSPW                (2)
#define HBPD                (40- 1)
#define HFPD                (5 - 1)
#define VSPW                (2)
#define VBPD                (8 - 1)
#define VFPD                (9 - 1)
#define LINEVAL             (271)
#define HOZVAL              (479)#define LeftTopX     0
#define LeftTopY     0
#define RightBotX   479
#define RightBotY   271void lcd_init();
void lcd_draw_pixel(int row, int col, int color);
void lcd_clear_screen(int color);
void lcd_draw_hline(int row, int col1, int col2, int color);
void lcd_draw_vline(int col, int row1, int row2, int color);
void lcd_draw_cross(int row, int col, int halflen, int color);
void lcd_draw_circle(void);#define WIDTHEIGHT   480
#define HEIGHT  272/*触摸屏相关定义*/
#define ADCCON 0x7E00B000   //ADC Control Register
#define ADCTSC 0x7E00B004   //ADC Touch Screen Control Register
#define ADCDLY 0x7E00B008   //ADC Start or Interval Delay Register
#define ADCDAT0 0x7E00B00C  //ADC Conversion Data Register
#define ADCDAT1 0x7E00B010  //ADC Conversion Data Register
#define ADCUPDN 0x7E00B014  //Stylus Up or Down Interrupt Register
#define ADCCLRINT 0x7E00B018    //Clear ADC Interrupt
#define ADCCLRINTPNDNUP 0x7E00B020  //Clear Pen Down/Up Interrupt #define ADCINT_VECTADDR     0x7130017C
#define IPDOWNINT_VECTADDR     0x71300178 /*以上是VIC1*/
#define VIC1SELECT     0x7130000C /*以上是VIC1*/void ts_init();int read_adc(int ch);/*dm9000相关寄存器定义*/
#define CONFIG_DRIVER_DM9000    1
#define CONFIG_DRIVER_DM9000_NO_EEPROM  1
#define CONFIG_DM9000_USE_16BIT 1
#define CONFIG_DM9000_BASE  0x18000300
#define DM_ADD CONFIG_DM9000_BASE
#define DM_DAT (CONFIG_DM9000_BASE+4)#define SROM_BW 0x70000000
#define SROM_BC1 0x70000008
#define GPNCON 0x7F008830
#define GPNDAT 0x7F008834
#define GPNPUD 0x7F008838
void dm9000_init();#endif
#ifndef __ARP_H__
#define __ARP_H__
#include "common.h"#define SWAP(n) ((((u16)n & 0xff) << 8) | ((((u16)n >> 8) & 0xff)))/*以太网头部结构体*/
typedef struct eth_header{u8 d_mac[6];u8 s_mac[6];u16 frame_type;}ETH_HDR;/*ARP头部结构体*/
typedef struct arp_header{ETH_HDR ethhdr;u16 hw_type;u16 protocol;u8 hwadd_len;u8 protoc_len;u16 opcode;u8 smac[6];u8 sipaddr[4];u8 dmac[6];u8 dipaddr[4];}ARP_HDR;/*IP头部结构体*/
typedef struct ip_hdr
{ETH_HDR ethhdr;u8 vhl;u8 tos;u16 len;u16 ipid;u16 ipoffset;u8 ttl;u8 proto;u16 ipchksum;u8 srcipaddr[4];u8 destipaddr[4];
}IP_HDR;/*UDP头部结构体*/
typedef struct udp_hdr
{IP_HDR iphdr;u16 sport;u16 dport;u16 len;u16 udpchksum;
}UDP_HDR;/*TFTP数据包结构体*/
typedef struct tftp_package
{u16 opcode;u16 blocknum;u8 data[0];
}TFTP_PAK;ARP_HDR arpbuf;/*网络协议类型*/
#define PROTO_ARP 0x0806
#define PROTO_IP 0x0800
#define PROTO_UDP 0x11extern u8 host_mac_addr[6];
extern u8 mac_addr[6];
extern u8 ip_addr[4];
extern u8 host_ip_addr[4];
extern u16 packet_len;
#endif
@****************************
@File:start.S
@
@Tiny6410裸机下学期代码
@
@Author:小君君
@****************************.text
.global _start@异常向量表
_start:b    resetldr    pc, _Undefined_instructionldr   pc, _Software_interruptldr  pc, _Command_abortldr   pc, _Data_abortldr  pc, _Nothing_usedldr    pc, _IRQldr pc, _FIQ@存放实际异常入口地址开辟的存储单元
_Undefined_instruction:.word Undefined_instruction_Software_interrupt:.word Software_interrupt_Command_abort:.word Command_abort_Data_abort:.word Data_abort_Nothing_used:.word Nothing_used_IRQ:.word IRQ_FIQ:.word FIQ@各种实际的异常处理函数
Undefined_instruction:nopSoftware_interrupt:nopCommand_abort:nopData_abort:nopNothing_used:nopIRQ:ldr   sp,=0x5E000000sub  lr,lr,#4stmdb   sp!,{r0-r12,lr}bl   do_dmirqldmia   sp!,{r0-r12,pc}^ FIQ:nop@上电复位以后就执行这里
reset:bl    set_svcbl   set_peri_portbl disable_watchdogbl  disable_interruptbl disable_mmubl   clock_initbl    mem_init    bl  init_stackbl    clean_bssbl nand_initbl copy_to_ddr@bl light_ledldr    pc, =mainhalt:b halt@通过读-修改-写的方式控制CPSR从而改变工作模式的svc模式
set_svc:mrs r0, cpsrbic r0,r0,#0x1Forr  r0,r0,#0xD3msr  cpsr,   r0mov   pc, lr@关闭看门狗
#define pWTCON 0x7E004000
disable_watchdog:ldr    r0, =pWTCONmov r1, #0x00str    r1, [r0]mov     pc, lr@屏蔽中断,要操作两个寄存器,目的是将使能中断寄存器的相关位清除
#define VIC0INTENCLEAR 0x71200014
#define VIC1INTENCLEAR 0x71300014
disable_interrupt:ldr   r0, =VIC0INTENCLEARmvn     r1, #0x0str r1, [r0]ldr r0, =VIC1INTENCLEARstr r1, [r0]mov     pc, lr  @关闭MMU和Cache
disable_mmu:mcr p15,0,r0,c7,c7,0mrc p15,0,r0,c1,c0,0bic r0,r0,#0x07mcr  p15,0,r0,c1,c0,0mov     pc, lr@外设地址初始化,要放在进入svc模式以后的第一步操作
set_peri_port:      ldr r0, =0x70000000                    @对于6410来说,内存(0x00000000~0x60000000),外设(0x70000000-0x7fffffff)orr r0, r0, #0x13                      @外设大小:256Mmcr p15,0,r0,c15,c2,4                 @把r0的值(包括了外设基地址+外设大小)告诉cpumov    pc, lr@时钟初始化
#define APLL_LOCK 0x7E00F000
#define CLK_DIV0 0x7E00F020
#define OTHERS 0x7E00F900
#define MPLL_CON 0x7E00F010
#define APLL_CON 0x7E00F00C
#define CLK_SRC 0x7E00F01C@#define ARM_RATIO   0                           @ARMCLK    = DOUTAPLL / (ARM_RATIO + 1)      = 532/(0+1) = 532  MHz
@#define MPLL_RATIO    0                           @ DOUTMPLL = MOUTMPLL / (MPLL_RATIO + 1)   = 532/(0+1) = 532  MHz
@#define HCLKX2_RATIO 1                        @ HCLKX2   = HCLKX2IN / (HCLKX2_RATIO + 1) = 532/(1+1) = 266  MHz
@#define HCLK_RATIO   1                        @ HCLK     = HCLKX2   / (HCLK_RATIO + 1)   = 266/(1+1) = 133  MHz
@#define PCLK_RATIO   3                        @ PCLK     = HCLKX2   / (PCLK_RATIO + 1)   = 266/(3+1) = 66.5 MHz#define DIV_VAL  ((0 << 0)|(0 << 4)|(1 << 8)|(1 << 9)|(3 << 12))   @注意这里不能用#define DIV_VAL (ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_RATIO << 12)@原因暂时未查明,不知道是不是我电脑最近鼠标抽风,把字符编码格式改变了导致的结果
clock_init:@ 1. 设置各PLL的LOCK_TIME,使用默认值  ldr    r0,     =APLL_LOCK                         @ APLL_LOCK,供cpu使用 ldr  r1,     =0x0000FFFFstr     r1,     [r0]str     r1,     [r0, #4]                            @ MPLL_LOCK,供AHB(存储/中断/lcd等控制器)/APB(看门狗,定时器,SD等)总线上的设备使用 str  r1,     [r0, #8]                            @ EPLL_LOCK,供UART,IIS,IIC使用 @ 2. 设置为异步模式 ldr   r0,     =OTHERS                            @ OTHERS@ 《linux installation for u-boot》3.7中:用MPLL作为HCLK和PCLK的Source是异步(ASYNC)模式@ 用APLL是同步(SYNC)模式ldr    r1,     [r0]bic r1, r1, #0xc0                           @ bit[6:7]清0,即SYNCMODE=0/SYNCMUXSEL=0str     r1,     [r0]
loop_clock:         ldr     r0,     =OTHERSldr     r1,     [r0]and r1, r1, #0xf00                  cmp     r1,     #0bne   loop_clock@ 3. 设置分频系数  ldr     r0,     =CLK_DIV0                          @CLK_DIV0ldr   r1, =DIV_VALstr    r1,     [r0]@ 4. 设置PLL,放大时钟  @ 4.1 配置APLL
#define APLL_CON_VAL  ((1<<31) | (266 << 16) | (3 << 8) | (1))ldr     r0,     =APLL_CON                          @ APLL_CONldr  r1,     =APLL_CON_VAL                      @ FOUT = MDIV X FIN / (PDIV X 2SDIV) = 266*12/(3*2^1) = 532MHzstr   r1,     [r0]        @ 4.2 配置MPLL
#define MPLL_CON_VAL  ((1<<31) | (266 << 16) | (3 << 8) | (1))ldr     r0,     =MPLL_CON                          @ MPLL_CONldr  r1,     =MPLL_CON_VAL                      @ FOUT = MDIV X FIN / (PDIV X 2SDIV) = 266*12/(3*2^1) = 532MHzstr   r1,     [r0]        #define MPLL_SEL 1
#define APLL_SEL 1  @ 5.选择PLL的输出作为时钟源  ldr     r0,     =CLK_SRC                           @ CLK_SRCldr   r1,     =(MPLL_SEL<<1) | (APLL_SEL<<0)str  r1,     [r0]mov     pc,     lr@将bin文件从_start开始到bss_start结束的数据搬移到_start指定的链接地址(0x50008000)
copy_to_ddr:mov r0, #0x00ldr    r1, =_startldr r2, =bss_startsub  r2,r2,r1mov ip,lrbl copy2ddrmov lr,ipmov    pc,lr@copy_loop:
@  ldr r3,[r0],#4
@  str r3,[r1],#4
@  cmp r1,r2
@  bne copy_loop@ mov pc, lr@初始化栈
init_stack:mrs  r0, cpsr@用读-修改-写 的方式设置CPU的工作模式(CPSR寄存器)bic   r0,r0,#0x1Forr  r0,r0,#0xD2msr  cpsr,   r0ldr   sp, =0x5F000000 @设置IRQ模式的堆栈mrs    r0, cpsrbic r0,r0,#0x1Forr  r0,r0,#0xD3msr  cpsr,   r0ldr   sp, =0x5FF00000@设置SVC模式的堆栈mov pc, lr@清除BSS段
clean_bss:ldr   r0, =bss_startldr  r1, =bss_endcmp    r0, r1moveq pc, lrclean_loop:mov    r2, #0x0str r2,[r0],#4cmp   r0, r1bne   clean_loopmov   pc, lr@点亮LED
#define GPKCON0 0x7F008800
#define GPKDAT  0x7F008808
light_led:  @设置GPKCON0ldr r1, =GPKCON0                    ldr r0, =0x11110000                                                                  str r0, [r1]@设置GPKDAT点亮4颗LEDldr r0, =GPKDATldr r1, =0x0str r1, [r0]@延时函数,将会使得开机的时候4颗led先亮一段时间,大约4秒钟左右,之后只亮两颗LED表明进入C语言的main函数ldr r0, =0xFFFFFF
loop_led:sub    r0,r0,#1cmp r0, #1bne   loop_ledmov pc, lr
/****************************
@File:main.c
@
@Tiny6410裸机下学期代码
@网卡测试文件
@Author:小君君
@****************************/#include "common.h"int main(void)
{int num = 1000;led_init();//LED的GPIO初始化button_init();//按键初始化led_on();//点亮4颗LEDuart_init();//串口初始化putchar('a');putchar('\r');putchar('\n');putchar('b');putchar('\r');putchar('\n');dma_init();//DMA初始化dma_start();//启动DMA发送数据到串口uart_init();//串口再次初始化,使得串口恢复中断或者轮询模式lcd_init();lcd_clear_screen(0xFFFFFF);dm9000_init();dm9000_arp();while(1){dm9000_arp();printf("=================================================\n\r");printf("===================JUN-BOOT======================\n\r");printf("0.Send the ARP to get yhe host's MAC address\n\r");printf("1.Download the linux kernel from tftp\n\r");printf("2.Boot linux OS from SDRAM\n\r");printf("3.Junjun is a houmorous\n\r");printf("=================================================\n\r");printf("===================LCD_TEST======================\n\r");printf("4.清屏\n\r");printf("5.画横线\n\r");printf("6.画竖线\n\r");printf("7.画十字架\n\r");printf("8.画同心圆\n\r");printf("9.AD转换\n\r");printf("                                                   \n\r");printf("请输入0-8任意一个数字:\n\r");scanf("%d",&num);   switch(num){case 0:printf("请支持成都国嵌\n\r");break;case 1:printf("国嵌学院=====打造你的嵌入式人生\n\r");break;case 2:printf("学ARM,学Linux,学C++,学安卓,学嵌入式,就到成都国嵌学院\n\r");break;case 3:printf("只要你肯努力,你的明天就会等你!!\n\r");break;case 4:lcd_clear_screen(0x000000);break;case 5:lcd_clear_screen(0x000000);lcd_draw_hline(HEIGHT/2, 100, WIDTHEIGHT-100, 0xff0000);break;case 6:lcd_clear_screen(0x000000);lcd_draw_vline(WIDTHEIGHT/2, 50, HEIGHT-50, 0xff0000);break;case 7:lcd_clear_screen(0x000000);lcd_draw_cross(HEIGHT/2, WIDTHEIGHT/2, 20, 0x777777);break;case 8:lcd_clear_screen(0x000000);lcd_draw_circle();break;case 9:read_adc(0);break;default:printf("只要你肯努力,你的明天就会等你!!\n\r");break;}}return 0;
}

四十.DM9000网卡搭建相关推荐

  1. arm平台linux的ethtool配置,ARM-Linux驱动--DM9000网卡驱动分析(四)

    原标题:ARM-Linux驱动--DM9000网卡驱动分析(四) 硬件平台:FL2440 (S3C2440) 内核版本:2.6.35 主机平台:Ubuntu 11.04 内核版本:2.6.39 交叉编 ...

  2. 【Microsoft Azure 的1024种玩法】四十九.在Azure中使用Azure VirtualMachines 搭建Microsoft SharePoint 2016

    [简介] SharePoint Server 2016 的设计.开发和测试以 Microsoft 软件即服务 (SaaS) 战略为核心.SharePoint Server 2016 广泛借鉴了该经验, ...

  3. 【Microsoft Azure 的1024种玩法】四十八.基于Azure Virtual Machines快速搭建SQL Server应用

    [简介] SQL Server系列软件是Microsoft 公司推出的关系型数据库管理系统,本文的主要内容是围绕着Azure Virtual Machines 来快速搭建SQL Server应用,使我 ...

  4. 四十六、利用yarn多队列实现hadoop资源隔离

    2019独角兽企业重金招聘Python工程师标准>>> 大数据处理离不开Hadoop集群的部署和管理,对于本来硬件资源就不多的创业团队来说,做好资源的共享和隔离是很有必要的,毕竟不像 ...

  5. 乐高小颗粒履带机器人_玩转乐高大颗粒积木(四十二)——乐高不倒翁、轮式是挖掘机、大颗粒皮筋车...

    这期分享几个适合低年龄段搭建的作品,作品的器材基本上是45002和9090的积木搭建的,一起来看看这期会分享一些什么作品呢? 1. >>>乐高不倒翁<<< 百变工程 ...

  6. 凝思系统改时间_国产操作系统往事:四十年激变,终再起风云

    在这一轮技术浪潮中,无论是底层的开发生态,算力的硬件基础,还是五花八门的商业化落地场景,中国企业都有着毋庸置疑的话语输出能力.而另一个全民皆知.中国ICT产业的长期阵痛--国产操作系统,也在2019世 ...

  7. 国产操作系统往事:四十年激变,终再起风云

    作者 | 藏狐 本文经授权转载自脑极体(ID:unity007) 在这一轮技术浪潮中,无论是底层的开发生态.算力的硬件基础,还是五花八门的商业化落地场景,中国企业都有着毋庸置疑的话语输出能力.而另一个 ...

  8. 能源数字化,未来四十年看什么?

    有人曾言,能量与信息是衡量人类文明进程的价值标准.因为,每一次能源/信息革命都给人类社会生产力带来跨越式发展. 如今,人类文明再次站在变革的风口."碳中和"成为全球主要经济体的共识 ...

  9. 劲霸男装四十年:“真男人”成“老男人”还能如何劲霸?

    男装生意,好做也不好做. 长期以来,国内女装市场的竞争格外激烈,不单有海外大牌VERO MODA.ONLY虎视眈眈,还有国内品牌雅莹.哥弟.珂莱蒂尔等多方围堵:而男装市场竞争激烈程度略小,长期来是海澜 ...

最新文章

  1. FD.io/VPP — IPSec NAT-T
  2. azkaban工作流调度器及相关工具对比
  3. Mysql数据库常用操作整理
  4. python如何读取公共盘的文档_如何使用 Sphinx 给 Python 代码写文档 | Linux 中国
  5. 群晖218J安装mysql_ds216(群晖218j可以换内存吗)
  6. 《深入理解Kafka:核心设计与实践原理》笔误及改进记录
  7. 一步一步封装自己的HtmlHelper组件:BootstrapHelper
  8. linux 定时备份mysql数据库
  9. “理了么”app使用体验
  10. 拖动卡顿_教你4招,让你的ps永不卡顿
  11. phpstudy探针文件
  12. 视频教程-2020软考数据库系统工程师-基础知识培训视频-软考
  13. 如何用PS把背景完全扣掉,变成透明
  14. 圆排列公式推导_【圆面积公式计算】圆形面积计算公式
  15. 敏捷-《如何准备ACP考试》知识图谱
  16. Lftp 支持大文件,断点续传
  17. java毕业设计-java SSM超市积分兑换系统
  18. 用pyth写一个代码输入数字到列表中,直到输入空值为止 ,依次将每个数字的最大数挑出来,生成一个新的列表...
  19. WPF中, DataGrid表格设置标题Header文字大小和行高
  20. OpenFire源码学习之二十九:openfire集群配置

热门文章

  1. 百看不如一练系列 32个python实战项目列表,得不到就毁掉
  2. 常见鸟的种类及特点_鸟的种类及图片(看图识鸟)
  3. 系统项目质量管理计划
  4. 记住不要学计算机,搞IT的我已经后悔了...
  5. Qt QSS基础知识学习
  6. 【Java】汉字转拼音
  7. css3 动画 线两边延长,CSS 导航栏下滑线向两边延伸动画
  8. 软件测试需要学什么?
  9. 漫步数学分析十八——紧集上连续函数的有界性
  10. MapReduce-案例共同好友分析