1.OSI(开放式系统互联模型)
我们可以看到nLAN_CS实质接在nGCS4上。再看datasheet
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); }
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); }
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); }
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; } }
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 */ for (i = 0, oft = 0x10; i < 6; i++, oft++) printf("%02x:", dm9000_read(oft)); printf("\n\r"); }
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() { /*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(); }
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); }
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; }
void int_issue() { packet_len = dm9000_rx(&buffer[0]); net_handle(&buffer[0],packet_len); EINTPEND |= (1 << 7); SRCPND |= (1 << 4); INTPND |= (1 << 4); }
else if(var1 == (4)){ val = (*(EINTPEND))&(1 << 7); switch(val){ case (1<<7): int_issue(); break; default: break; } }
void dm9000_arp() { while(1) arp_request(); }
--》当未知MAC地址的时候,设置为全F--》硬件类型是指硬件地址对应的类型,即以太网类型,编号为1--》协议类型是指协议地址对应的类型,在这里协议地址是IP地址,IP类型的编号是0800--》硬件地址长度即以太网地址长度,6个字节--》协议地址长度即Ip地址长度4个字节--》op为1表示请求,为0表示应答--》发送端以太网地址就是以太网源地址,事先制定的,6个字节--》发送端Ip地址是事先制定的,4个字节,注意:要和PC在同一网段--》目的以太网地址,暂时不填,要获取的就是该数据--》目的Ip地址就是PC的Ip实际地址。
#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 0x11 extern 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
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;
#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) { 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; }
/**************************** @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/LB WAIT disable Data bus width control for Memory Bank1===》16bit*/ (vi SROM_BW) &= ~(3 << 6); (vi SROM_BW) |= (1 << 4); /*Tacs = 2-cycle Tacp = 2-cycle Tcos = 2-cycle Tcoh = 2-cycle Tacc = 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); else 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 = (*(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 long typedef 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 #endif void 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 0x71300f00 void 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 0x70200028 int 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_ENABLE char getchar(void); void putchar(char c); void send_string(char* str); #else unsigned 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 0x7E00F110 void 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 271 void 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 0x11 extern 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 reset ldr pc, _Undefined_instruction ldr pc, _Software_interrupt ldr pc, _Command_abort ldr pc, _Data_abort ldr pc, _Nothing_used ldr pc, _IRQ ldr 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: nop Software_interrupt: nop Command_abort: nop Data_abort: nop Nothing_used: nop IRQ: ldr sp,=0x5E000000 sub lr,lr,#4 stmdb sp!,{r0-r12,lr} bl do_dmirq ldmia sp!,{r0-r12,pc}^ FIQ: nop @上电复位以后就执行这里 reset: bl set_svc bl set_peri_port bl disable_watchdog bl disable_interrupt bl disable_mmu bl clock_init bl mem_init bl init_stack bl clean_bss bl nand_init bl copy_to_ddr @bl light_led ldr pc, =main halt: b halt @通过读-修改-写的方式控制CPSR从而改变工作模式的svc模式 set_svc: mrs r0, cpsr bic r0,r0,#0x1F orr r0,r0,#0xD3 msr cpsr, r0 mov pc, lr @关闭看门狗 #define pWTCON 0x7E004000 disable_watchdog: ldr r0, =pWTCON mov r1, #0x00 str r1, [r0] mov pc, lr @屏蔽中断,要操作两个寄存器,目的是将使能中断寄存器的相关位清除 #define VIC0INTENCLEAR 0x71200014 #define VIC1INTENCLEAR 0x71300014 disable_interrupt: ldr r0, =VIC0INTENCLEAR mvn r1, #0x0 str r1, [r0] ldr r0, =VIC1INTENCLEAR str r1, [r0] mov pc, lr @关闭MMU和Cache disable_mmu: mcr p15,0,r0,c7,c7,0 mrc p15,0,r0,c1,c0,0 bic r0,r0,#0x07 mcr p15,0,r0,c1,c0,0 mov pc, lr @外设地址初始化,要放在进入svc模式以后的第一步操作 set_peri_port: ldr r0, =0x70000000 @对于6410来说,内存(0x00000000~0x60000000),外设(0x70000000-0x7fffffff) orr r0, r0, #0x13 @外设大小:256M mcr p15,0,r0,c15,c2,4 @把r0的值(包括了外设基地址+外设大小)告诉cpu mov 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, =0x0000FFFF str 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=0 str r1, [r0] loop_clock: ldr r0, =OTHERS ldr r1, [r0] and r1, r1, #0xf00 cmp r1, #0 bne loop_clock @ 3. 设置分频系数 ldr r0, =CLK_DIV0 @CLK_DIV0 ldr r1, =DIV_VAL str r1, [r0] @ 4. 设置PLL,放大时钟 @ 4.1 配置APLL #define APLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1)) ldr r0, =APLL_CON @ APLL_CON ldr r1, =APLL_CON_VAL @ FOUT = MDIV X FIN / (PDIV X 2SDIV) = 266*12/(3*2^1) = 532MHz str r1, [r0] @ 4.2 配置MPLL #define MPLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1)) ldr r0, =MPLL_CON @ MPLL_CON ldr r1, =MPLL_CON_VAL @ FOUT = MDIV X FIN / (PDIV X 2SDIV) = 266*12/(3*2^1) = 532MHz str r1, [r0] #define MPLL_SEL 1 #define APLL_SEL 1 @ 5.选择PLL的输出作为时钟源 ldr r0, =CLK_SRC @ CLK_SRC ldr r1, =(MPLL_SEL<<1) | (APLL_SEL<<0) str r1, [r0] mov pc, lr @将bin文件从_start开始到bss_start结束的数据搬移到_start指定的链接地址(0x50008000) copy_to_ddr: mov r0, #0x00 ldr r1, =_start ldr r2, =bss_start sub r2,r2,r1 mov ip,lr bl copy2ddr mov lr,ip mov 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,#0x1F orr r0,r0,#0xD2 msr cpsr, r0 ldr sp, =0x5F000000 @设置IRQ模式的堆栈 mrs r0, cpsr bic r0,r0,#0x1F orr r0,r0,#0xD3 msr cpsr, r0 ldr sp, =0x5FF00000@设置SVC模式的堆栈 mov pc, lr @清除BSS段 clean_bss: ldr r0, =bss_start ldr r1, =bss_end cmp r0, r1 moveq pc, lr clean_loop: mov r2, #0x0 str r2,[r0],#4 cmp r0, r1 bne clean_loop mov pc, lr @点亮LED #define GPKCON0 0x7F008800 #define GPKDAT 0x7F008808 light_led: @设置GPKCON0 ldr r1, =GPKCON0 ldr r0, =0x11110000 str r0, [r1] @设置GPKDAT点亮4颗LED ldr r0, =GPKDAT ldr r1, =0x0 str r1, [r0] @延时函数,将会使得开机的时候4颗led先亮一段时间,大约4秒钟左右,之后只亮两颗LED表明进入C语言的main函数 ldr r0, =0xFFFFFF loop_led: sub r0,r0,#1 cmp r0, #1 bne loop_led mov 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颗LED uart_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; }