四十.DM9000网卡搭建
一.网络模型
1.OSI(开放式系统互联模型)
我们可以看到nLAN_CS实质接在nGCS4上。再看datasheet
![](/assets/blank.gif)
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 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
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;
}
![](/assets/blank.gif)
/****************************
@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网卡搭建相关推荐
- arm平台linux的ethtool配置,ARM-Linux驱动--DM9000网卡驱动分析(四)
原标题:ARM-Linux驱动--DM9000网卡驱动分析(四) 硬件平台:FL2440 (S3C2440) 内核版本:2.6.35 主机平台:Ubuntu 11.04 内核版本:2.6.39 交叉编 ...
- 【Microsoft Azure 的1024种玩法】四十九.在Azure中使用Azure VirtualMachines 搭建Microsoft SharePoint 2016
[简介] SharePoint Server 2016 的设计.开发和测试以 Microsoft 软件即服务 (SaaS) 战略为核心.SharePoint Server 2016 广泛借鉴了该经验, ...
- 【Microsoft Azure 的1024种玩法】四十八.基于Azure Virtual Machines快速搭建SQL Server应用
[简介] SQL Server系列软件是Microsoft 公司推出的关系型数据库管理系统,本文的主要内容是围绕着Azure Virtual Machines 来快速搭建SQL Server应用,使我 ...
- 四十六、利用yarn多队列实现hadoop资源隔离
2019独角兽企业重金招聘Python工程师标准>>> 大数据处理离不开Hadoop集群的部署和管理,对于本来硬件资源就不多的创业团队来说,做好资源的共享和隔离是很有必要的,毕竟不像 ...
- 乐高小颗粒履带机器人_玩转乐高大颗粒积木(四十二)——乐高不倒翁、轮式是挖掘机、大颗粒皮筋车...
这期分享几个适合低年龄段搭建的作品,作品的器材基本上是45002和9090的积木搭建的,一起来看看这期会分享一些什么作品呢? 1. >>>乐高不倒翁<<< 百变工程 ...
- 凝思系统改时间_国产操作系统往事:四十年激变,终再起风云
在这一轮技术浪潮中,无论是底层的开发生态,算力的硬件基础,还是五花八门的商业化落地场景,中国企业都有着毋庸置疑的话语输出能力.而另一个全民皆知.中国ICT产业的长期阵痛--国产操作系统,也在2019世 ...
- 国产操作系统往事:四十年激变,终再起风云
作者 | 藏狐 本文经授权转载自脑极体(ID:unity007) 在这一轮技术浪潮中,无论是底层的开发生态.算力的硬件基础,还是五花八门的商业化落地场景,中国企业都有着毋庸置疑的话语输出能力.而另一个 ...
- 能源数字化,未来四十年看什么?
有人曾言,能量与信息是衡量人类文明进程的价值标准.因为,每一次能源/信息革命都给人类社会生产力带来跨越式发展. 如今,人类文明再次站在变革的风口."碳中和"成为全球主要经济体的共识 ...
- 劲霸男装四十年:“真男人”成“老男人”还能如何劲霸?
男装生意,好做也不好做. 长期以来,国内女装市场的竞争格外激烈,不单有海外大牌VERO MODA.ONLY虎视眈眈,还有国内品牌雅莹.哥弟.珂莱蒂尔等多方围堵:而男装市场竞争激烈程度略小,长期来是海澜 ...
最新文章
- FD.io/VPP — IPSec NAT-T
- azkaban工作流调度器及相关工具对比
- Mysql数据库常用操作整理
- python如何读取公共盘的文档_如何使用 Sphinx 给 Python 代码写文档 | Linux 中国
- 群晖218J安装mysql_ds216(群晖218j可以换内存吗)
- 《深入理解Kafka:核心设计与实践原理》笔误及改进记录
- 一步一步封装自己的HtmlHelper组件:BootstrapHelper
- linux 定时备份mysql数据库
- “理了么”app使用体验
- 拖动卡顿_教你4招,让你的ps永不卡顿
- phpstudy探针文件
- 视频教程-2020软考数据库系统工程师-基础知识培训视频-软考
- 如何用PS把背景完全扣掉,变成透明
- 圆排列公式推导_【圆面积公式计算】圆形面积计算公式
- 敏捷-《如何准备ACP考试》知识图谱
- Lftp 支持大文件,断点续传
- java毕业设计-java SSM超市积分兑换系统
- 用pyth写一个代码输入数字到列表中,直到输入空值为止 ,依次将每个数字的最大数挑出来,生成一个新的列表...
- WPF中, DataGrid表格设置标题Header文字大小和行高
- OpenFire源码学习之二十九:openfire集群配置