---
title: "STM32 CubeIDE W5500 initialization Routine"
url: "https://maker.wiznet.io/tonywang_/projects/stm32-cubeide-w5500-initialization-routine/"
markdown_url: "https://maker.wiznet.io/tonywang_/projects/stm32-cubeide-w5500-initialization-routine/md"
type: "UCC: User Created Content"
author: "tonywang_"
author_url: "https://maker.wiznet.io/tonywang_/"
original_author: "PegasusYu"
original_url: "https://blog.csdn.net/hwytree/article/details/120156570?ops_request_misc=&request_id=&biz_id=102&utm_term=w5500%20spi%20dma&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-5-120156570.142%5ev11%5epc_search_result_control_group,1"
published: "2022-11-02"
language: "en"
likes: 6
views: 1884
comments: 1
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# STM32 CubeIDE W5500 initialization Routine

> Introduce how to setup W5500 in STM32 CubeIDE.

Original author: PegasusYu (source: https://blog.csdn.net/hwytree/article/details/120156570?ops_request_misc=&request_id=&biz_id=102&utm_term=w5500%20spi%20dma&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-5-120156570.142%5ev11%5epc_search_result_control_group,1)

## Article

STM32 W5500以太网通讯

对于内含以太网MAC部分的芯片，可以外部增加以太网PHY芯片和连接器，实现以太网通讯。对于内部没有以太网MAC部分的芯片，通过W5500 S 讯是比较好的方式, 从而STM32F0各低端系列都能实现以太网通讯。采用W5500芯片，可以不占用MCU的 内存 部分做buffer，对于MCU业务逻辑时 MCU和W5500可以通过SPI的DMA方式，实现较快的收发逻辑；W5500最大支持到80Mbps的SPI接口速度，实际情况根据MCU的SPI接口速率和PC

W5500写读Buffer 的要点笔记

1. 每个SOCKET有自己的写缓冲和读缓冲操作命令/地址，如下：

![在这里插入图片描述](https://img-blog.csdnimg.cn/005a43ede9be4f9f9c894eda3a665205.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_14,color_FFFFFF,t_70,g_se,x_16)

2. 每个SOCKET的写缓冲大小（Sn_TXBUF_SIZE）和读缓冲大小（Sn_RXBUF_SIZE）可调整，写缓冲和读缓冲分离。因为8个socket共享写缓冲 缓冲大小或读缓冲大小不超过16KB。

3. 写时可进行burst操作。因此首地址的设置，有辅助的信息寄存器： ⑴Sn_TX_FSR : 用于查阅写缓冲区域剩余自由空间，可为Sn_TX_WR和Sn_TX_RD的差值 ⑵Sn_TX_WR : 写缓冲写入的数据指针，指示已经写到的地址 ⑶Sn_TX_RD ：写缓冲发送的数据指针，指示发送改到了哪个地址

4. 读时可进行burst操作。因此首地址的设置，有辅助的信息寄存器： ① Sn_RX_RSR ：用于查阅读缓冲剩余的未读取的数据空间大小，可为Sn_RX_WR和Sn_RX_RD的差值 ② Sn_RX_WR ：接收数据的边界指针，接收到数据时，指针自动后移，指示前面的部分为已收到的数据。 ③ Sn_RX_RD ： 接收数据读取后的边界指针，当进行了接收缓冲区读取后，该指针手动升级到已读取的缓冲区后的地址

5. 写缓冲和读缓冲都是循环FIFO，因此越界后翻到0地址继续进行。

需要注意的情况：

1. 是否有不断开连接方式可以将缓冲区复位? 答：不能，且Socket端口打开和连接后的初始化地址也不是0地址，且每次初始化地址还不同。

2. 越界情况的处理？答：循环缓冲区，控制写入时序，否则会产生对还未发送数据区域的覆盖。 发送数据操作逻辑： 1. 通过读取Sn_TX_WR寄存器获得当前的写缓冲区指针，通过读取Sn_TX_RD寄存器获得当前的写缓冲区发送数据指针，初始时二者一致表示没有 2. 通过从Sn_TX_WR寄存器得到的发送缓冲区地址，写入要发送的数据，发送写数据命令和写数据之间的时间间隔不能过大，否则W5500接收SP

3. 向Sn_TX_WR寄存器写入后续发送要达到的发送缓冲区地址，即当前发送缓冲区地址+要发送的字节数。实际上，这个写操作后，Sn_TX_WR寄 到发送缓冲区数据指令发送后，才会更新。

4. 发送缓冲区数据发送指令，此时Sn_TX_WR寄存器更新，W5500从Sn_TX_RD地址开始发送数据，并实时更新Sn_TX_RD地址，等到Sn_TX_R 相同，则完成并停止发送。

读数据操作逻辑：

1. 通过读取Sn_RX_RD寄存器得到读缓冲区可读取区域首地址

2. 通过读取Sn_RX_RSR寄存器得到读缓冲区未读的接收到的数据长度

3. 通过可读取区域首地址读取读缓冲区里的数据，可小于等于Sn_RX_RSR寄存器里的长度，大于则读到无效数据

4. 向Sn_RX_RD写入新的可读取区域首地址，为之前的首地址+已读取字节数。但此时Sn_RX_RD还未更新，还需发送下述一条指令进行触发更新

5. 通过向Socket的命令寄存器（Command Register）发送RECV指令，触发Sn_RX_RD更新，同时Sn_RX_RSR也被更新。

6. 如果没有更新Sn_RX_RD寄存器指针，则再次收到数据时会继续顺序放置，同时Sn_RX_WR和Sn_RX_RSR继续增加。因此前后不同次接收到的

实际嵌入式时序控制时，需要接收中断控制和读取W5500内部状态寄存器，进行时序调度。

STM32 W5500访问逻辑设计

这里设计一个例程，采用STM32H743VIT6连接W5500, 同时实现虚拟串口（VCOM）作为测试辅助：

1. STM32上电后实现对W5500的配置，并读取特定寄存器以判断访问是否成功

2. 网络连通后，用TCP测试工具，发送任意数据到STM32, STM32接收到后转发到VCOM；另外STM32将预设的特定数据发送到TCP测试工具。注 单回环。

STM32CUBEIDE配置

采用STM32CUBEIDE进行工程配置，选择SPI1作为W5500通讯接口，STM32H743VIT6的SPI1能达到80MHz的速率，但测试环境采用短杜邦线连接 输质量，实测60MHz能够正确响应，因此相应的时钟采用120MHz的2分频实现。

使能外部8MHz晶振时钟，整体的时钟配置如下，包括了SPI和USB VCOM的部分：

![在这里插入图片描述](https://img-blog.csdnimg.cn/6f8c5c54707d4f70b89941462ef4946f.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/691efc5429664f8e9a8076219eebd31e.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_19,color_FFFFFF,t_70,g_se,x_16)

SPI1配置，W5500连接所用管脚为：

PD1: W5500_RST

PD3: W5500_SCS

PD5: W5500_INT

PB3: W5500_SCK

PB4: W5500_MISO

PB5: W5500_MOSI

![在这里插入图片描述](https://img-blog.csdnimg.cn/73db18c7bce0467899d66ceeee9e7b72.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/729884b400a54488b66f2d0f5ed76687.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/b2450be49bac42f1aff0e24e73cafa83.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/5d6be26cb1784583a40311b34ab673c4.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/616306f5c59e40f9a6e78a3884b56cf8.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/2caba3c2e5194fd4806661b3665cc9ec.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/03d3a9943d89427cbee1266e87773b59.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/451254d75fc541029b9dc3ac81122c48.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/bffa32136f504fbe8313707b635c0681.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/841ecbd63201441cb7ffc259bbd03683.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/298854591c9145e184d0593e3ec91a68.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/6ec13e87e6034c2da92401182ffdb724.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/89b007c3c80a4fa6a811a8a355defb94.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/aa97732a17334720b748e62289317e1b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

W5500访问库函数设计

这里设计W5500开通两个SOCKET端口，测试中只用到第一个SOCKET端口。

新建w5500.h文件，代码如下：

/*
* PD1: W5500_RST
* PD3: W5500_SCS
* PD5: W5500_INT
*
* PB3: W5500_SCK
* PB4: W5500_MISO
* PB5: W5500_MOSI
*
*
*/
#ifndef _W5500_H_
#define _W5500_H_

#define PY_W5500_RST {HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_RESET);HAL_Delay(5);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_SET);HAL_Delay(5);}
#define PY_W5500_CS_EN HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
#define PY_W5500_CS_DEN HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_SET);

void PY_W5500_Config(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t data);
void PY_W5500_Read(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t* data, uint16_t length);
void PY_W5500_Send(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t* data, uint16_t length);
void PY_W5500_TCPSERVER_2SOCKETS(void);
void PY_W5500_SOCKET0_CLEARRECINT(void);

#endif

新建w5500.c文件，代码如下：

#include "stm32h7xx_hal.h"
#include &lt;stdio.h>
#include &lt;string.h>
#include "w5500.h"
#include "spi.h"

void PY_W5500_Config(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t data)
{
extern uint8_t PY_SPIDMA__Status;
extern uint8_t* PY_CMD_Seg;

PY_W5500_CS_EN
PY_SPIDMA__Status=1;
PY_CMD_Seg[0]=ah;PY_CMD_Seg[1]=al;PY_CMD_Seg[2]=ctl|0x04;PY_CMD_Seg[3]=data;
HAL_SPI_Transmit_DMA(&hspi1, PY_CMD_Seg,4);
while(PY_SPIDMA__Status==1) ;
PY_W5500_CS_DEN
HAL_Delay(1);
}

void PY_W5500_Read(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t* data, uint16_t length)
{
extern uint8_t PY_SPIDMA__Status;
extern uint8_t* PY_CMD_Seg;
PY_W5500_CS_EN
PY_SPIDMA__Status=1;
PY_CMD_Seg[0]=ah;PY_CMD_Seg[1]=al;PY_CMD_Seg[2]=ctl&amp;0xfb;
HAL_SPI_Transmit_DMA(&hspi1, PY_CMD_Seg,3);
while(PY_SPIDMA__Status==1) ;

PY_SPIDMA__Status=1;
HAL_SPI_Receive_DMA(&hspi1, data, length);
while(PY_SPIDMA__Status==1) ;

PY_W5500_CS_DEN
}

void PY_W5500_Send(uint8_t ah, uint8_t al, uint8_t ctl, uint8_t* data, uint16_t length)
{
extern uint8_t PY_SPIDMA__Status;
extern uint8_t* PY_CMD_Seg;

PY_W5500_CS_EN
PY_SPIDMA__Status=1;
PY_CMD_Seg[0]=ah;PY_CMD_Seg[1]=al;PY_CMD_Seg[2]=ctl|0x04;
HAL_SPI_Transmit_DMA(&hspi1, PY_CMD_Seg,3);
while(PY_SPIDMA__Status==1) ;

PY_SPIDMA__Status=1;
HAL_SPI_Transmit_DMA(&hspi1, data, length);
while(PY_SPIDMA__Status==1) ;
PY_W5500_CS_DEN
}

void PY_W5500_TCPSERVER_2SOCKETS(void)
{
/*
* Only one socket receiving interrupt is opened for cmd recognition. Other interrupt sources are closed. To use polling for Tx status.
*/
extern uint8_t PY_SPIDMA__Status;
extern uint8_t* PY_CMD_Seg;
extern uint8_t* PY_DataR_Seg;
extern uint8_t* PY_DataW_Seg;

//Common register:mode register
PY_W5500_Config(0x00, 0x00, 0x04, 0x00);
//Common register:gateway IP address register
PY_W5500_Config(0x00, 0x01, 0x04, 192); //IP: 192.168.1.252
PY_W5500_Config(0x00, 0x02, 0x04, 168);
PY_W5500_Config(0x00, 0x03, 0x04, 1);
PY_W5500_Config(0x00, 0x04, 0x04, 252);
//Common register:subnet mask register
PY_W5500_Config(0x00, 0x05, 0x04, 255);
PY_W5500_Config(0x00, 0x06, 0x04, 255);
PY_W5500_Config(0x00, 0x07, 0x04, 255);
PY_W5500_Config(0x00, 0x08, 0x04, 0);
//Common register:source hardware address register
PY_W5500_Config(0x00, 0x09, 0x04, 0x00);
PY_W5500_Config(0x00, 0x0a, 0x04, 0x08);
PY_W5500_Config(0x00, 0x0b, 0x04, 0xdc);
PY_W5500_Config(0x00, 0x0c, 0x04, 0x01);
PY_W5500_Config(0x00, 0x0d, 0x04, 0x02);
PY_W5500_Config(0x00, 0x0e, 0x04, 0x03);
//Common register:source IP address register
PY_W5500_Config(0x00, 0x0f, 0x04, 192);
PY_W5500_Config(0x00, 0x10, 0x04, 168);
PY_W5500_Config(0x00, 0x11, 0x04, 1);
PY_W5500_Config(0x00, 0x12, 0x04, 252);
//Common register:interrupt low level interval register
PY_W5500_Config(0x00, 0x13, 0x04, 0x00);
PY_W5500_Config(0x00, 0x14, 0x04, 0x13);
//Common register:(connection) interrupt register
PY_W5500_Config(0x00, 0x15, 0x04, 0x00);
//Common register:(connection) interrupt mask register
PY_W5500_Config(0x00, 0x16, 0x04, 0xf0);
//Common register:(socket)interrupt register
PY_W5500_Config(0x00, 0x17, 0x04, 0x00);
//Common register:(socket) interrupt mask register
PY_W5500_Config(0x00, 0x18, 0x04, 0xc0);
//Common register:retry time-value register
PY_W5500_Config(0x00, 0x19, 0x04, 0x07);
PY_W5500_Config(0x00, 0x1a, 0x04, 0xd0);
//Common register:retry count register
PY_W5500_Config(0x00, 0x1b, 0x04, 0x07);

//Socket 0 register:mode register
PY_W5500_Config(0x00, 0x00, 0x0c, 0x21);
//Socket 0 register:source port number register
PY_W5500_Config(0x00, 0x04, 0x0c, 0x03); //Port:1000
PY_W5500_Config(0x00, 0x05, 0x0c, 0xe8);
//Socket 0 register:maxium segment size register
PY_W5500_Config(0x00, 0x12, 0x0c, 0x05);
PY_W5500_Config(0x00, 0x13, 0x0c, 0xb4);
//Socket 0 register:ip type of service register
PY_W5500_Config(0x00, 0x15, 0x0c, 0x5a);
//Socket 0 register:time to live register
PY_W5500_Config(0x00, 0x16, 0x0c, 64);
//Socket 0 register:rx buffer size register
PY_W5500_Config(0x00, 0x1e, 0x0c, 2);
//Socket 0 register:tx buffer size register
PY_W5500_Config(0x00, 0x1f, 0x0c, 2);
//Socket 0 register:keep alive time register
PY_W5500_Config(0x00, 0x2f, 0x0c, 0x18);

//Socket 1 register:mode register
PY_W5500_Config(0x00, 0x00, 0x2c, 0x21);
//Socket 1 register:source port number register
PY_W5500_Config(0x00, 0x04, 0x2c, 0x07); //Port:2000
PY_W5500_Config(0x00, 0x05, 0x2c, 0xD0);
//Socket 1 register:maxium segment size register
PY_W5500_Config(0x00, 0x12, 0x2c, 0x05);
PY_W5500_Config(0x00, 0x13, 0x2c, 0xb4);
//Socket 1 register:ip type of service register
PY_W5500_Config(0x00, 0x15, 0x2c, 0x5a);
//Socket 1 register:time to live register
PY_W5500_Config(0x00, 0x16, 0x2c, 64);
//Socket 1 register:rx buffer size register
PY_W5500_Config(0x00, 0x1e, 0x2c, 2);
//Socket 1 register:tx buffer size register
PY_W5500_Config(0x00, 0x1f, 0x2c, 2);
//Socket 1 register:keep alive time register
PY_W5500_Config(0x00, 0x2f, 0x2c, 0x18);

//interrupt mask registers
PY_W5500_Config(0x00, 0x16, 0x04, 0x00);
PY_W5500_Config(0x00, 0x18, 0x04, 0x01);
PY_W5500_Config(0x00, 0x2c, 0x0c, 0x04);

//Socket 0 : open
PY_W5500_Config(0x00, 0x01, 0x0c, 0x01); //open socket
HAL_Delay(10);
PY_W5500_Config(0x00, 0x01, 0x0c, 0x02); //socket server listening

//PY_W5500_Config(0x00, 0x01, 0x0c, 0x40);

//Socket 1 : open
PY_W5500_Config(0x00, 0x01, 0x2c, 0x01); //open socket
HAL_Delay(10);
PY_W5500_Config(0x00, 0x01, 0x2c, 0x02); //socket server listening

}

void PY_W5500_SOCKET0_CLEARRECINT(void)
{
PY_W5500_Config(0x00, 0x02, 0x0c, 0x04);
}

main.c文件设计

对于W5500，配置为只有接收数据中断发送到STM32的中断接收管脚（PD5）。STM32收到中断后，读取数据转发到虚拟串口，另外把预设的一组值发送到以太网口。

/* USER CODE BEGIN Header */
/
* @file : main.c
* @brief : Main program body
**
* @attention
*
* &lt;h2>&lt;center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.&lt;/center>&lt;/h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
**
*/
//SPI1 DMA buffer address can't be arranged in the region of 0x20000000 ~ 0x20020000

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "spi.h"
#include "usb_device.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "w5500.h"
#include "string.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t PY_W5500_Ver_Addr_SegH=0x00, PY_W5500_Ver_Addr_SegL=0x39;
uint8_t PY_W5500_Ver_Ctrl_Seg=0x00;

uint8_t* PY_CMD_Seg;
uint8_t* PY_DataR_Seg;
uint8_t* PY_DataW_Seg;

uint8_t PY_SPIDMA__Status = 0;

uint8_t cmd=0;

uint8_t rx_addr_h, rx_addr_l;
uint16_t rx_len;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
PY_CMD_Seg = 0x38000000;
PY_DataR_Seg = 0x38000004;
PY_DataW_Seg = 0x30000000;

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USB_DEVICE_Init();
MX_SPI1_Init();
/* USER CODE BEGIN 2 */
PY_W5500_RST

PY_CMD_Seg[0]=PY_W5500_Ver_Addr_SegH;
PY_CMD_Seg[1]=PY_W5500_Ver_Addr_SegL;
PY_CMD_Seg[2]=PY_W5500_Ver_Ctrl_Seg;

PY_DataR_Seg[0]=0; PY_DataR_Seg[1]=0;

PY_W5500_CS_EN
PY_SPIDMA__Status=1;
HAL_SPI_Transmit_DMA(&hspi1, PY_CMD_Seg, 3);
while(PY_SPIDMA__Status==1) ;
PY_SPIDMA__Status=1;
HAL_SPI_Receive_DMA(&hspi1, PY_DataR_Seg, 1);
while(PY_SPIDMA__Status==1) ;
PY_W5500_CS_DEN

if(PY_DataR_Seg[0]!=0x04)
{
while(1)
{
CDC_Transmit_FS(PY_DataR_Seg, 1);
HAL_Delay(1000);
}
}

PY_W5500_TCPSERVER_2SOCKETS();
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//CDC_Transmit_FS(PY_DataR_Seg, 2);
HAL_Delay(1000);
if(cmd==1)
{
cmd=0;
PY_W5500_SOCKET0_CLEARRECINT();

/*
* Receiving
*/
PY_W5500_Read(0x00, 0x28, 0x08, PY_DataR_Seg, 2);
rx_addr_h=PY_DataR_Seg[0];rx_addr_l=PY_DataR_Seg[1];
PY_W5500_Read(0x00, 0x26, 0x08, PY_DataR_Seg, 2);
rx_len=(((uint16_t)PY_DataR_Seg[0])&lt;&lt;8)|((uint16_t)PY_DataR_Seg[1]);
HAL_Delay(200);

PY_W5500_Read(rx_addr_h, rx_addr_l, 0x18, PY_DataR_Seg, rx_len);
CDC_Transmit_FS(PY_DataR_Seg, rx_len);

PY_W5500_Config(0x00, 0x28, 0x0c, ((((uint16_t)(rx_addr_h))&lt;&lt;8)|((uint16_t)(rx_addr_l))+rx_len)>>8);
PY_W5500_Config(0x00, 0x29, 0x0c, ((((uint16_t)(rx_addr_h))&lt;&lt;8)|((uint16_t)(rx_addr_l))+rx_len));
PY_W5500_Config(0x00, 0x01, 0x0c, 0x40);
HAL_Delay(200);

/*
* Sending
*/
PY_DataW_Seg[0]=0;PY_DataW_Seg[1]=1;PY_DataW_Seg[2]=2;PY_DataW_Seg[3]=3;PY_DataW_Seg[4]=4;PY_DataW_Seg[5]=5;PY_DataW_Seg[6]=6;PY_DataW_Seg[7]=7;

PY_W5500_Read(0x00, 0x22, 0x08, PY_DataR_Seg, 2);
PY_W5500_Read(0x00, 0x24, 0x08, PY_DataR_Seg, 2);

PY_W5500_Send(PY_DataR_Seg[0], PY_DataR_Seg[1], 0x14, PY_DataW_Seg, 8);

PY_W5500_Config(0x00, 0x24, 0x0c, ((((uint16_t)(PY_DataR_Seg[0]))&lt;&lt;8)|((uint16_t)(PY_DataR_Seg[1]))+8)>>8);
PY_W5500_Config(0x00, 0x25, 0x0c, ((((uint16_t)(PY_DataR_Seg[0]))&lt;&lt;8)|((uint16_t)(PY_DataR_Seg[1]))+8));
HAL_Delay(1);

PY_W5500_Read(0x00, 0x22, 0x08, PY_DataR_Seg, 2);
PY_W5500_Read(0x00, 0x24, 0x08, PY_DataR_Seg, 2);

HAL_Delay(1);
PY_W5500_Config(0x00, 0x01, 0x0c, 0x20);
HAL_Delay(1);

PY_W5500_Read(0x00, 0x22, 0x08, PY_DataR_Seg, 2);
PY_W5500_Read(0x00, 0x24, 0x08, PY_DataR_Seg, 2);

}
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Macro to configure the PLL clock source
*/
__HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSE);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 480;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}

/* USER CODE BEGIN 4 */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
extern uint8_t PY_SPIDMA__Status;
PY_SPIDMA__Status = 0;
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
extern uint8_t PY_SPIDMA__Status;
PY_SPIDMA__Status = 0;
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
extern uint8_t PY_SPIDMA__Status;
PY_SPIDMA__Status = 0;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
extern uint8_t cmd;

if(GPIO_Pin==GPIO_PIN_5){

cmd=1;

}

}
/* USER CODE END 4 */

/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/ (C) COPYRIGHT STMicroelectronics *END OF FILE/

编译并完成下载程序。

通讯测试

连接网线，并将本地IP做静态指定：

![在这里插入图片描述](https://img-blog.csdnimg.cn/5c73c43c1f9746188544fda2c973a238.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_16,color_FFFFFF,t_70,g_se,x_16)

芯片重启跑起来后，网络接通，然后打开TCP测试工具，STM32是以太网Server角色，这里电脑端则设置为Client角色：

![在这里插入图片描述](https://img-blog.csdnimg.cn/559accda788b403085658326635c0120.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_19,color_FFFFFF,t_70,g_se,x_16)

![在这里插入图片描述](https://img-blog.csdnimg.cn/8d87c43b447b4ef080a750eaf4834da3.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_16,color_FFFFFF,t_70,g_se,x_16)

打开一个串口工具并连接：

![在这里插入图片描述](https://img-blog.csdnimg.cn/0c16058116514a1d8dd8b3ffa12ea2a7.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

TCP工具端连接STM32, 并发送“GOOD", 接收端设置为16进制接收：

![在这里插入图片描述](https://img-blog.csdnimg.cn/0b3f05bfa6c445419b282d2a04bc4360.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGVnYXN1c1l1,size_20,color_FFFFFF,t_70,g_se,x_16)

这样，从电脑TCP发送端发送出去的"GOOD"被STM32收到后,转发到串口；STM32另外将十六进制00 01 02 03 04 05 06 07发送到电脑TCP接收端。

## **参考例程**

上述设计的例程下载：
https://download.csdn.net/download/hwytree/22007730

–End–

---

Source: https://maker.wiznet.io/tonywang_/projects/stm32-cubeide-w5500-initialization-routine/
