W5500以太网控制器芯片(一):ioLibrary库实现TCP服务器

W5500 芯片是一款集成全硬件 TCP/IP 协议栈的嵌入式以太网控制器,同时也是一颗工业级以太网控制芯片。 

W5500 支持高速标准4线SPI接口与主机进行通信,该 SPI 速率理论上可以达到 80MHz。其内部还集成了以太网数据链路层(MAC)和10BaseT/100BaseTX 以太网物理层(PHY),支持自动协商(10/100-Based全双工/半双工)、掉电模式和网络唤醒功能。与传统软件协议栈不同,W5500内嵌的8个独立硬件 Socket 可以进行8路独立通信,该8路Socket的通信效率互不影响,可以通过 W5500 片上32K 字节的收/发缓存灵活定义各个Socket的大小

官方提供了ioLibrary_BSD固件库,可以很轻松的移植进各种嵌入式设备中,只要设备支持标准SPI接口(模式0、3)即可。

下面以STM32F103的MCU为例说明一下如何用W5500移植官方的固件库实现以太网通讯。

1、下载官方固件库

地址:
http://wizwiki.net/wiki/doku.php?id=products:w5500:driver

可以分别从官网和github上下载源码。

下载完注意两个部分:

(1)Ethernet文件夹
主要是W5500的驱动,实现基本的TCP通讯只要这个就行了

(2)Internet文件夹
实现各种TCP扩展的应用,比如DHCP、DNS、FTP等

先实现基本的TCP通讯,只要Ethernet文件夹下的文件


将W5500、socket、wizchip_config的c和h文件引入工程中即可(注意配置.h文件路径)

2、编写SPI接口

要写一下MCU的spi接口初始化,同时实现几个函数:

//SPI口初始化
void SPI2_Init(void)
{
    SPI_InitTypeDef  SPI_InitStructure;

	GPIO_InitTypeDef GPIO_InitStructure;
  
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
 
	//PB12->CS,PB13->SCK,PB14->MISO,PB15->MOSI	
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_13 | GPIO_Pin_14|GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
 	GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
	
	//初始化片选输出引脚
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_SetBits(GPIOB,GPIO_Pin_12);

	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
	SPI_InitStructure.SPI_Direction= SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init(SPI2,&SPI_InitStructure);
	
	SPI_Cmd(SPI2, ENABLE); //使能SPI外设
}

/**
  * @brief  写1字节数据到SPI总线
  * @param  TxData 写到总线的数据
  * @retval None
  */
void SPI_WriteByte(uint8_t TxData)
{
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);   
		SPI_I2S_SendData(SPI2, TxData);

  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);  
		SPI_I2S_ReceiveData(SPI2);
}

/**
  * @brief  从SPI总线读取1字节数据
  * @retval 读到的数据
  */
uint8_t SPI_ReadByte(void)
{
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);   
		SPI_I2S_SendData(SPI2, 0xFF);

  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);  
		return (SPI_I2S_ReceiveData(SPI2));
}

/**
  * @brief  进入临界区
  * @retval None
  */
void SPI_CrisEnter(void)
{
	__set_PRIMASK(1);
}

/**
  * @brief  退出临界区
  * @retval None
  */
void SPI_CrisExit(void)
{
	__set_PRIMASK(0);
}

/**
  * @brief  片选信号输出低电平
  * @retval None
  */
void SPI_CS_Select(void)
{
	GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}

/**
  * @brief  片选信号输出高电平
  * @retval None
  */
void SPI_CS_Deselect(void)
{
	GPIO_SetBits(GPIOB,GPIO_Pin_12);
}


(1)SPI读写
(2)进入、退出临界区
(3)片选信号输出

3、初始化W5500

#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "spi.h"
#include "socket.h"	// Just include one header for WIZCHIP

#define SOCK_TCPC        0
#define SOCK_TCPS        1

#define DATA_BUF_SIZE   2048

// Initialize Network information and display it
void network_init(void);
// Loopback TCP server				 
int32_t loopback_tcps(uint8_t, uint8_t*, uint16_t);

uint8_t gDATABUF[DATA_BUF_SIZE];


wiz_NetInfo gWIZNETINFO = { .mac = {0x00, 0x08, 0xdc,0x00, 0xab, 0xcd},
                            .ip = {10, 1, 1, 200},
                            .sn = {255,255,255,0},
                            .gw = {10, 1, 1, 1},
                            .dns = {8,8,8,8},
                            .dhcp = NETINFO_STATIC};


int main(void)
{
	delay_init();	    	 	//延时函数初始化
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2

	uart_init(115200);	 	//串口初始化

	SPI2_Init();    //SPI初始化

	// First of all, Should register SPI callback functions implemented by user for accessing WIZCHIP 
	/* Critical section callback */
	//reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit);	//注册临界区函数
	reg_wizchip_cris_cbfunc(NULL, NULL); // 注册临界区函数
		
	reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect);// 注册片选函数

	/* SPI Read & Write callback function */
	reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte);	//注册读写函数
 
	/* WIZCHIP SOCKET Buffer initialize */
	if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1){
		 printf("WIZCHIP Initialized fail.\r\n");
		 while(1);
	}

	/* PHY link status check */
	do{
		 if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1){
				printf("Unknown PHY Link stauts.\r\n");
		 }
	}while(tmp == PHY_LINK_OFF);

	/* Network initialization */
	network_init();

    while(1)
    {
		/* Loopback Test */
		// TCP server loopback test
		if( (ret = loopback_tcps(SOCK_TCPS, gDATABUF, 5000)) < 0) {
			printf("SOCKET ERROR : %ld\r\n", ret);
	}
}
}


//网络初始化(DHCP)
void network_init(void)
{
	uint8_t tmpstr[6] = {0,};
	wiz_NetInfo netinfo;

	// Set Network information from netinfo structure
	ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);

	// Get Network information
	ctlnetwork(CN_GET_NETINFO, (void*)&netinfo);

	// Display Network Information
	ctlwizchip(CW_GET_ID,(void*)tmpstr);

	if(netinfo.dhcp == NETINFO_DHCP) printf("\r\n=== %s NET CONF : DHCP ===\r\n",(char*)tmpstr);
	else printf("\r\n=== %s NET CONF : Static ===\r\n",(char*)tmpstr);

	printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",netinfo.mac[0],netinfo.mac[1],netinfo.mac[2],
			netinfo.mac[3],netinfo.mac[4],netinfo.mac[5]);
	printf("SIP: %d.%d.%d.%d\r\n", netinfo.ip[0],netinfo.ip[1],netinfo.ip[2],netinfo.ip[3]);
	printf("GAR: %d.%d.%d.%d\r\n", netinfo.gw[0],netinfo.gw[1],netinfo.gw[2],netinfo.gw[3]);
	printf("SUB: %d.%d.%d.%d\r\n", netinfo.sn[0],netinfo.sn[1],netinfo.sn[2],netinfo.sn[3]);
	printf("DNS: %d.%d.%d.%d\r\n", netinfo.dns[0],netinfo.dns[1],netinfo.dns[2],netinfo.dns[3]);
	printf("===========================\r\n");

}


/**
  * @brief  Loopback Test Example Code using ioLibrary_BSD	
  * @retval None
  */
int32_t loopback_tcps(uint8_t sn, uint8_t* buf, uint16_t port)
{
   int32_t ret;
   uint16_t size = 0, sentsize=0;
   switch(getSn_SR(sn))
   {
      case SOCK_ESTABLISHED :
         if(getSn_IR(sn) & Sn_IR_CON)
         {
            printf("%d:Connected\r\n",sn);
            setSn_IR(sn,Sn_IR_CON);
         }
         if((size = getSn_RX_RSR(sn)) > 0)
         {
            if(size > DATA_BUF_SIZE) 
							size = DATA_BUF_SIZE;
						
            ret = recv(sn,buf,size);
						
            if(ret <= 0) 
				return ret;
						
            sentsize = 0;
						
            while(size != sentsize)
            {
               ret = send(sn,buf+sentsize,size-sentsize);
							
			   printf("%s\r\n",buf);
							
               if(ret < 0)
               {
                  close(sn);
                  return ret;
               }
               sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.
            }
         }
         break;
      case SOCK_CLOSE_WAIT :
         printf("%d:CloseWait\r\n",sn);
         if((ret=disconnect(sn)) != SOCK_OK) return ret;
         printf("%d:Closed\r\n",sn);
         break;
      case SOCK_INIT :
    	  printf("%d:Listen, port [%d]\r\n",sn, port);
         if( (ret = listen(sn)) != SOCK_OK) return ret;
         break;
      case SOCK_CLOSED:
         printf("%d:LBTStart\r\n",sn);
         if((ret=socket(sn,Sn_MR_TCP,port,0x00)) != sn)
            return ret;
         printf("%d:Opened\r\n",sn);
         break;
      default:
         break;
   }
   return 1;
}

4、检验结果

到此,设备已经实现了TCP服务器通讯,下面需要检验一下:
(1)将设备的网口和电脑的网口用网线连接
(2)暂时关闭电脑的DHCP,更改电脑的本地网络的IPv4地址为固定值,改成和程序中处于同一个网段(或者把程序中的IP地址改成和电脑的同一个网段)



wiz_NetInfo gWIZNETINFO = { .mac = {0x00, 0x08, 0xdc,0x00, 0xab, 0xcd},
                            .ip = {10, 1, 1, 200},
                            .sn = {255,255,255,0},
                            .gw = {10, 1, 1, 1},
                            .dns = {8,8,8,8},
                            .dhcp = NETINFO_STATIC};

比如上文程序中的IP地址为10.1.1.200,则电脑的IP保持前3段不变,如设成10.1.1.199

(3)电脑打开一个网络调试助手,配置好连接参数,然后连接上文程序中指定的地址

 (4)发送数据





电脑客户端发送数据,W5500创建的服务器端会将数据按原样返回,同时串口会打印数据。


(5)验证完成,实现W5500的TCP回环测试(TCP服务器功能)
 

W5500相关文章专栏链接


下一篇文章:

W5500以太网控制器芯片(二):ioLibrary库实现TCP客户端

  • 2
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值