W5500问题

  • Post author:
  • Post category:其他




网口 W5500芯片



1 定义网络服务器的地址和端口

uint8 server_ip[4]={192,168,1,87};
uint16 server_port=5000;
uint16 local_port=6000;
uint16 len=0;

定义了服务器地址 server_ip,服务器端口 server_port,本地端口 local_port,以及缓存字节长度 len



2 对DSP芯片相关功能的初始化

  InitSpiaGpio();//初始化W5500的复位的GPIO
  gpio_config();//GPIO配置
  DINT;//关中断
  InitPieCtrl(); //初始化PIE
  IER = 0x0000;   //清除中断
  IFR = 0x0000;
  InitPieVectTable();//初始化中断向量



3 对W5500芯片相关功能的初始化

Reset_W5500();//复位W5500
set_default();//设置网络属性
set_network();//对W5500设置,ip那些,到这一步就能Ping通了



3.1 Reset_W5500();

其中

Reset_W5500();

函数,主要对W5500芯片引脚RSTn进行操作

void Reset_W5500(void)
{
	GpioDataRegs.GPBDAT.bit.GPIO52 = 0;
	delay_loop();
	GpioDataRegs.GPBDAT.bit.GPIO52 = 1;
	delay_loop();
}

在这里插入图片描述
将其至低后拉高,完成W5500的复位。



3.2 set_default();

设置默认的W5500芯片的物理地址 MAC、IP地址 IP、网关 GW、子网掩码 SUB、服务器 DNS。

void set_default(void)									// 设置默认MAC、IP、GW、SUB、DNS
{  
  uint8 mac[6]={0x00,0x08,0xdc,0x11,0x11,0x12};
  uint8 lip[4]={192,168,1,150};
  uint8 sub[4]={255,255,255,0};
  uint8 gw[4]={192,168,1,1};
  uint8 dns[4]={8,8,8,8};
  memcpy(ConfigMsg.lip, lip, 4);
  //printf("lip: %d.%d.%d.%d\r\n",lip[0],lip[1],lip[2],lip[3]);
  memcpy(ConfigMsg.sub, sub, 4);
 // printf("sub: %d.%d.%d.%d\r\n",sub[0],sub[1],sub[2],sub[3]);
  memcpy(ConfigMsg.gw,  gw, 4);
  //printf("gw: %d.%d.%d.%d\r\n",gw[0],gw[1],gw[2],gw[3]);
  memcpy(ConfigMsg.mac, mac,6);
  memcpy(ConfigMsg.dns,dns,4);
  //printf("dns: %d.%d.%d.%d\r\n",dns[0],dns[1],dns[2],dns[3]);
  ConfigMsg.dhcp=0;
  ConfigMsg.debug=1;
  ConfigMsg.fw_len=0;
  ConfigMsg.state=NORMAL_STATE;
  ConfigMsg.sw_ver[0]=FW_VER_HIGH;
  ConfigMsg.sw_ver[1]=FW_VER_LOW;
}



3.3 set_network();

设置网络,将第二步中的默认设置,通过SPI的方式,将这些数据写入W5500设置。可以理解为,第二步是定义,第三步才是真正的设置。

void set_network(void)			// 配置初始化IP信息并打印,初始化8个Socket
{
  uint8 ip[4];
  setSHAR(ConfigMsg.mac);
  //printf("mac:");
  setSUBR(ConfigMsg.sub);
  setGAR(ConfigMsg.gw);
  setSIPR(ConfigMsg.lip);

  sysinit(txsize, rxsize); 											// 初始化8个socket
  setRTR(2000);														// 设置超时时间
  setRCR(3);														// 设置最大重新发送次数

  
  getSIPR (ip);
  printf("IP : %d.%d.%d.%d\r\n", ip[0],ip[1],ip[2],ip[3]);
  getSUBR(ip);
  printf("SN : %d.%d.%d.%d\r\n", ip[0],ip[1],ip[2],ip[3]);
  getGAR(ip);
  printf("GW : %d.%d.%d.%d\r\n", ip[0],ip[1],ip[2],ip[3]);
}

此函数可配置每个socket通道的缓存大小,超时时间,已经最大重新发送次数。



4 状态寄存器Sn_SR 4个状态组成switch函数

此时,芯片W5500有了自己的IP地址,物理地址等。未进行任何操作的情况下,其状态寄存器 Sn_SR 应该为0x00



4.1 SOCK_CLOSED

最初经初始化后,W5500的状态应该是SOCK_CLOSED(0x00),进行第一步操作:

设置W5500的模式。包括TCP UDP等

case SOCK_CLOSED://第一步,设置模式
		socket(0,Sn_MR_TCP,local_port,Sn_MR_ND);
break;

此代码含义为,对W5500芯片SOCKET 0 通道,设置为TCP模式。其中会使用到OPEN命令



4.2 SOCK_INIT 0x13

在这里插入图片描述
第一步中,设置为了TCP模式,并且使用了OPEN命令。故Sn_SR寄存器将变为SOCK_INIT 0x13。若使用LISTEN命令,则此芯片为服务器,若使用CONNECT,此芯片为客户端。

case SOCK_INIT://第二步,初始化,连接服务器
		connect(0, server_ip,server_port);
break;

从代码看出,芯片为TCP模式的客户端。并且使用connect命令,连接服务器。



4.3 SOCK_ESTABLISHED 0x17

在这里插入图片描述
当 CONNECT 命令配置成功时,Sn_SR变为 SOCK_ESTABLISHED。这个状态下,就代表可以进行send或者receive了。



4.3 SOCK_CLOSE_WAIT 0x1C

最后一个状态是关闭通道的状态,如文字描述。

case SOCK_CLOSE_WAIT:
		close_socket(0);
break;

在这里插入图片描述

注意:正常工作时,W5500芯片一般都在SOCK_ESTABLISHED 状态



5 SOCK_ESTABLISHED 状态



5.1 第一步,判断 Sn_IR (Socket n 中断寄存器)

if(getSn_IR(0) & Sn_IR_CON)
{
	setSn_IR(0, Sn_IR_CON);
}

在这里插入图片描述
Sn_IR_CON=0x01的 也就是说,此时Sn_IR这个八位寄存器的第0位 CON=1。表明是建立了连接。setSn_IR(0, Sn_IR_CON); 这个又相当于初始化了Sn_IR,把他的中断标志初始化。



5.2 第二步,读取接收缓存的字节大小 Sn_RX_RSR

Sn_RX_RSR 显示了 Socket n 接收缓存中已接收和保存的数据大小。

len=getSn_RX_RSR(0);

读取len,如果有缓存,就是电脑服务器端发过来数据了,就会进行处理;如果没有,len=0,就会进行while1循环,继续进行switch判断。并且到这一步只会进行 SOCK_ESTABLISHED 状态。换句话说,就是只会一直判断len是否大于0,len大于0了,就会进行接下来的操作。如果没有大于0,就会一直判断len。



5.3 第三步,len>0 之后的操作

这部分就是真正的对fpga寄存器等的操作,这部分的程序包括对cmddata[]命令的解析,和数据的下发,以及对数据的上传。单开一张说明,保证逻辑性,先跳过这部分的具体操作。

其包括,接收命令,命令解析,设置编码模式,下发命令,设置解码模式,读取数据,上传数据。



6 len>0后的操作



6.1 首先明确命令的组成

一条命令包括:0xaa+cmddata[0] cmddata[1] cmddata[2] cmddata[3] cmddata[4] cmddata[5] cmddata[6] + (cmddata[6])个数据

一般来说一条命令只有8个16位数据,分为两个字节发送,特殊的命令会加上(cmddata[6])个数据

0xaa:数据头

cmddata[0]:采集命令

cmddata[1]:延时时间

cmddata[2]:送数命令

cmddata[3] :M2通道上传个数

cmddata[4] :M5通道上传个数

cmddata[5] :M7通道上传个数

cmddata[6] :送数命令后跟的送数命令。也就是多个送数命令

拿通信测试命令举例:

0x00 0xaa 0x99 0x1e 0x00 0x1e 0x99 0x4e 0x00 0x08 0x00 0x11 0x00 0x11 0x00 0x00 共16个字节,

其实是也就是8个参数:

0xaa:数据头 00aa

cmddata[0]:采集命令

991e


cmddata[1]:延时时间

001e


cmddata[2]:送数命令

994e


cmddata[3] :M2通道上传个数

0008


cmddata[4] :M5通道上传个数

0011


cmddata[5] :M7通道上传个数

0011


cmddata[6] :送数命令后跟的送数命令。也就是多个送数命令

0000



6.2 数据回环(最终时不需要send命令)

memset(buffer,0,sizeof(buffer));
memset(buffer16,0,sizeof(buffer16));//将两个数组清零
recv(0,buffer,len);
send(0,buffer,len);//将W5500的数据写入数组buffer

将buffer数组和buffer16数组清零

接收recv命令,DSP芯片通过SPI接口,将W5500缓存的数据存到buffer数组。

注:send只是测试用,方便在网口观察现象。最终测试时,不能加send命令。

此时数据已经到了buffer数组,为8位的。



6.3 命令解析

for(i=0,j=0;j<1024;i++,j++)//将buffer的八位的数据转换成buffer16数组的16位数据
{
	temp1=buffer[i];
	temp1=(temp1<<8);
	temp1=temp1&0xff00;
	temp2=buffer[i+1];
	temp2=temp2&0x00ff;
	buffer16[j]=temp1|temp2;
	i++;
}

if(buffer16[0]!=0x00aa)
{
	break;
}

for(i=0,j=1;i<7;i++,j++)//命令第2到8个字,分别为cmddata[0]~cmddata[6],共7个字
{
  	cmddata[i]=buffer16[j];
} 

第一个for循环:将buffer数组的8位的数据,转存到buffer16里,变为16位的数据

if语句:如果命令的头不是0xaa。则说明是无效命令,直接break,然后程序将重新运行switch循环

第二个for循环:解析出cmddata命令,也就是cmddata[0]~cmddata[6]



版权声明:本文为big_face_fat原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。