一、下载W5500官方提供的驱动库:
ioLibrary_Driver-master
二、库文件分析
ioLibrary_Driver-master
Application //官方提供的测试程序
loopback
multicast
Ethernet //底层配置
W5100
W5100S
W5200
W5300
W5500
Internet //网络应用层
DHCP
DNS
FTPClient
FTPServer
httpServer
MQTT
SNMP
SNTP
TFTP
三、开始配置
打开ioLibrary_Driver-master\Ethernet
文件夹下面的wizchip_conf.c
文件。
官方提供了接口,待用户补充:
void wizchip_cris_enter(void) {}
void wizchip_cris_exit(void) {}
void wizchip_cs_select(void) {}
void wizchip_cs_deselect(void) {}
iodata_t wizchip_bus_readdata(uint32_t AddrSel) { return * ((volatile iodata_t *)((ptrdiff_t) AddrSel)); }
void wizchip_bus_writedata(uint32_t AddrSel, iodata_t wb) { *((volatile iodata_t*)((ptrdiff_t)AddrSel)) = wb; }
uint8_t wizchip_spi_readbyte(void) {return 0;}
void wizchip_spi_writebyte(uint8_t wb) {}
void wizchip_spi_readburst(uint8_t* pBuf, uint16_t len) {}
void wizchip_spi_writeburst(uint8_t* pBuf, uint16_t len) {}
这里并不是每个函数都要填充,也不是一定要使用这些函数。这些函数存在的意义只是提供了一个模型,真正将我们自己的硬件配置和他们的库相连接的地方是在底下的注册函数:
//注册进入/退出临界区函数
void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void))
//注册SPI片选(CS) 选择/去选择函数
void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void))
//注册总线 读/写 函数
void reg_wizchip_bus_cbfunc(iodata_t(*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, iodata_t wb))
//注册 SPI 按字节 读/写 函数
void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), void (*spi_wb)(uint8_t wb))
//注册 SPI 按长度 读/写函数
void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t* pBuf, uint16_t len), void (*spi_wb)(uint8_t* pBuf, uint16_t len))
其中我们只需要关心三个函数:临界区、片选、SPI按字节读写。
因为程序没有跑系统,不需要临界保护,所以这里保持默认即可,无需修改。:
片选配置:
//void wizchip_cs_select(void) {};
void wizchip_cs_select(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
}
//void wizchip_cs_deselect(void) {};
void wizchip_cs_deselect(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_12);
}
SPI读写配置:
uint8_t wizchip_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);
}
//void wizchip_spi_writebyte(uint8_t wb) {};
void wizchip_spi_writebyte(uint8_t wb)
{
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI2, wb);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(SPI2);
}
注册上面的三个函数(只需要三个):
void user_reg_wizchip(void)
{
// First of all, Should register SPI callback functions implemented by user for accessing WIZCHIP
/* Critical section callback */
reg_wizchip_cris_cbfunc(wizchip_cris_enter, wizchip_cris_exit); //注册临界区函数
/* Chip selection call back */
#if _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_
reg_wizchip_cs_cbfunc(wizchip_cs_select, wizchip_cs_deselect); //注册SPI片选信号函数
#elif _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_FDM_
reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect); // CS must be tried with LOW.
#else
#if (_WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SIP_) != _WIZCHIP_IO_MODE_SIP_
#error "Unknown _WIZCHIP_IO_MODE_"
#else
reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);
#endif
#endif
/* SPI Read & Write callback function */
reg_wizchip_spi_cbfunc(wizchip_spi_readbyte, wizchip_spi_writebyte); //注册读写函数
}
然后主程序就可以调用了:
uint8_t mac[6]={0x00,0x08,0xdc,0x11,0x11,0x11};
uint8_t lip[4]={192,168,1,150};
uint8_t sub[4]={255,255,255,0};
uint8_t gw[4]={192,168,1,1};
uint8_t dns[4]={8,8,8,8};
wiz_NetInfo gWIZNETINFO;
memcpy(gWIZNETINFO.ip, lip, 4);
memcpy(gWIZNETINFO.mac, mac, 6);
memcpy(gWIZNETINFO.gw, gw, 4);
memcpy(gWIZNETINFO.sn, sub, 4);
memcpy(gWIZNETINFO.dns, dns, 4);
W5500_HalInit();
delay_ms(100); //必须要有延时
user_reg_wizchip();
wizchip_sw_reset();
ctlwizchip(CW_GET_ID,( void *)tmpstr);
ctlnetwork(CN_SET_NETINFO, ( void *)&gWIZNETINFO);
while(1);
至此,可以使用cmd工具ping通了。
C:\Users\lenovo>ping 192.168.1.150
正在 Ping 192.168.1.150 具有 32 字节的数据:
来自 192.168.1.150 的回复: 字节=32 时间<1ms TTL=128
来自 192.168.1.150 的回复: 字节=32 时间<1ms TTL=128
来自 192.168.1.150 的回复: 字节=32 时间<1ms TTL=128
来自 192.168.1.150 的回复: 字节=32 时间<1ms TTL=128
192.168.1.150 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 0ms,最长 = 0ms,平均 = 0ms
注意:W5500 socket使用resv接口时,注意该接口是无限阻塞的,如果调用了该接口,会一直等待接收到数据才会返回。
官方实现:
int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len)
{
........
while(1)
{
recvsize = getSn_RX_RSR(sn);
tmp = getSn_SR(sn);
if (tmp != SOCK_ESTABLISHED)
{
if(tmp == SOCK_CLOSE_WAIT)
{
if(recvsize != 0) break;
else if(getSn_TX_FSR(sn) == getSn_TxMAX(sn))
{
close(sn);
return SOCKERR_SOCKSTATUS;
}
}
else
{
close(sn);
return SOCKERR_SOCKSTATUS;
}
}
if((sock_io_mode & (1<<sn)) && (recvsize == 0)) return SOCK_BUSY;
if(recvsize != 0) break;
};
}
为了防止影响其他程序执行,这里修改为:
.....
if((sock_io_mode & (1<<sn)) && (recvsize == 0)) return SOCK_BUSY;
if(recvsize != 0) break;
else return 0;
然后再调用的地方增加超时检测:
int32_t Socket_Read(uintptr_t fd, char *buf, uint32_t len, uint32_t timeout_ms)
{
uint32_t index=0;
int32_t len_recv=0;
do
{
delay_ms(1);
index = recv(0, (uint8_t *)(buf+len_recv), (len-len_recv) );
if(index>0)
len_recv += index;
if(--timeout_ms < 1)
{
len_recv = 0;
return (int32_t)0;
}
}while(len_recv<len);
return (int32_t)len_recv;
}