STM32F1网络编程-W5500网卡驱动移植

W5500网卡驱动移植

1、W5500介绍

W5500 芯片是硬连线 TCP/IP 嵌入式以太网控制器,可提供与嵌入式系统的更轻松的 Internet 连接。 W5500 使用户只需使用嵌入了 TCP/IP 堆栈、10/100 以太网 MAC 和 PHY 的单芯片即可在其应用程序中实现 Internet 连接。

WIZnet 的硬连线 TCP/IP 是经过市场验证的技术,支持 TCP、UDP、IPv4、ICMP、ARP、IGMP 和 PPPoE 协议。 W5500 嵌入了 32Kbyte 的内部存储器缓冲区,用于以太网数据包处理。 如果您使用W5500,只需添加简单的socket程序即可实现以太网应用。 它比使用任何其他嵌入式以太网解决方案更快、更简单。 用户可以同时使用8个独立的硬件socket。

W5500提供 SPI(串行外设接口)以便于与外部 MCU 集成。 W5500 的 SPI 支持 80 MHz 速度和用于高速网络通信的新型高效 SPI 协议。 为了降低系统的功耗,W5500提供了WOL(Wake on LAN)和掉电模式。

W5500具有如下特性:

  • 支持硬连线 TCP/IP 协议:TCP、UDP、ICMP、IPv4、ARP、IGMP、PPPoE
  • 同时支持8个独立插座
  • 支持掉电模式
  • 支持通过 UDP 唤醒 LAN
  • 支持高速串行外设接口(SPI MODE 0, 3)
  • 用于 TX/RX 缓冲器的内部 32Kbytes 存储器
  • 10BaseT/100BaseTX 以太网 PHY 嵌入式
  • 支持自动协商(全双工和半双工,基于 10 和 100)
  • 不支持 IP 分片
  • 3.3V 操作,5V I/O 信号容差
  • LED 输出(全/半双工、链路、速度、活动)
  • 48 引脚 LQFP 无铅封装(7x7mm,0.5mm 间距)

在这里插入图片描述

2、W5500配置

关于STM32CubeIDE工程创建、配置请参考前面文章:

本次W5500的配置如下:

在这里插入图片描述

保存配置并生成代码。

3、W5500驱动移植

第一步,W5500的驱动代码:https://github.com/Wiznet/ioLibrary\_Driver

第二步,W5500的驱动源码配置如下:

在这里插入图片描述

第三步,驱动移植。

W5500驱动启动流程如下:

1)重置W5500

2)注册底层SPI通信函数

3)W5500网络层初始化

4)W5500芯片初始化

在STM32CubeIDE工程中添加w5500_port.hw5500_port.c文件,分别添加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/\*
\* w5500\_port.h
\*
\* Created on: 2022年6月29日
\* Author: jenson
\*/

#ifndef W5500\_PORT\_H\_
#define W5500\_PORT\_H\_

void wiznet\_register(void);
void w5500\_network\_init\_static(void);
void wiznet\_chip\_config(void);
void w5500\_restart(void);

#endif /\* W5500\_PORT\_H\_ \*/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/\*
\* w5500\_port.c
\*
\* Created on: 2022年6月29日
\* Author: jenson
\*/

#include "w5500\_port.h"
#include "main.h"
#include "spi.h"
#include <stdio.h>
#include "wizchip\_conf.h"
#include "socket.h"
#include "loopback.h"
#include "DHCP/dhcp.h"
#include <string.h>

static wiz_NetInfo gWIZNETINFO = {
.mac = { 0x00, 0x08, 0xdc, 0x11, 0x11, 0x11 },
.ip = { 192, 168, 2, 99 },
.sn = { 255, 255, 255, 0 },
.gw = { 192, 168,2, 1 },
.dns = { 8, 8, 8, 8 },
.dhcp = NETINFO_STATIC };

static void \_\_w5500\_spi\_cs\_select(void) {
HAL\_GPIO\_WritePin(W5500_CS_GPIO_Port, W5500_CS_Pin, GPIO_PIN_RESET);
}

static void \_\_w5500\_spi\_cs\_deselect(void) {
HAL\_GPIO\_WritePin(W5500_CS_GPIO_Port, W5500_CS_Pin, GPIO_PIN_SET);
}

void w5500\_restart(void) {
HAL\_GPIO\_WritePin(W5500_RST_GPIO_Port, W5500_RST_Pin, GPIO_PIN_RESET);
HAL\_Delay(1); // delay 1ms
HAL\_GPIO\_WritePin(W5500_RST_GPIO_Port, W5500_RST_Pin, GPIO_PIN_SET);
HAL\_Delay(1600); // delay 1600ms
printf("w5500 restarted\r\n");
}

/\*\*
\* @brief? 进入临界区
\* @retval None
\*/
void \_\_w5500\_spi\_cris\_enter(void)
{
\_\_set\_PRIMASK(1);
}

/\*\*
\* @brief? 退出临界区
\* @retval None
\*/
void \_\_w5500\_spi\_cris\_exit(void)
{
\_\_set\_PRIMASK(0);
}

static void \_\_w5500\_spi\_read\_buffer(uint8\_t \*buff, uint16\_t len) {
HAL\_SPI\_Receive(&hspi1, buff, len, HAL_MAX_DELAY);
}

static void \_\_w5500\_spi\_write\_buffer(uint8\_t \*buff, uint16\_t len) {
HAL\_SPI\_Transmit(&hspi1, buff, len, HAL_MAX_DELAY);
}

static uint8\_t \_\_w5500\_read\_byte(void) {
uint8\_t byte;
\_\_w5500\_spi\_read\_buffer(&byte, sizeof(byte));
return byte;
}

static void \_\_w5500\_write\_byte(uint8\_t byte) {
\_\_w5500\_spi\_write\_buffer(&byte, sizeof(byte));
}

void wiznet\_register(void) {
// First of all, Should register SPI callback functions implemented by user for accessing WIZCHIP
/\* Critical section callback \*/
reg\_wizchip\_cris\_cbfunc(__w5500_spi_cris_enter, __w5500_spi_cris_exit); //注册临界区函数
/\* Chip selection call back \*/
#if \_WIZCHIP\_IO\_MODE\_ == \_WIZCHIP\_IO\_MODE\_SPI\_VDM\_
reg\_wizchip\_cs\_cbfunc(__w5500_spi_cs_select, __w5500_spi_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(__w5500_read_byte, __w5500_write_byte); //注册读写函数

return;
}

/\*\*
\* @brief : w5500\_network\_init
\* @note : W5500 网络初始化
\* @param :
\* @retval :
\*/
void w5500\_network\_init\_static(void) {

uint8\_t chipid[6];
uint8\_t mac[6] = { 0x00, 0x08, 0xdc, 0x11, 0x11, 0x11 }; ///< Source Mac Address
uint8\_t ip[4] = { 192, 168, 2, 99 }; ///< Source IP Address
uint8\_t sn[4] = { 255, 255, 255, 0 }; ///< Subnet Mask
uint8\_t gw[4] = { 192, 168, 2, 1 }; ///< Gateway IP Address
uint8\_t dns[4] = { 114, 114, 114, 114 }; ///< DNS server IP Address

memcpy(gWIZNETINFO.ip, ip, 4);
memcpy(gWIZNETINFO.sn, sn, 4);
memcpy(gWIZNETINFO.gw, gw, 4);
memcpy(gWIZNETINFO.mac, mac, 6);
memcpy(gWIZNETINFO.dns, dns, 4);
printf("start init w5500(static)\r\n");
gWIZNETINFO.dhcp = NETINFO_STATIC; //< 1 - Static, 2 - DHCP
ctlnetwork(CN_SET_NETINFO, (void\*) &gWIZNETINFO);

ctlnetwork(CN_GET_NETINFO, (void\*) &gWIZNETINFO);
// Display Network Information
ctlwizchip(CW_GET_ID, (void\*) chipid);
printf("\r\n=== %s NET CONF ===\r\n", (char\*) chipid);
printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", gWIZNETINFO.mac[0],
gWIZNETINFO.mac[1], gWIZNETINFO.mac[2], gWIZNETINFO.mac[3],
gWIZNETINFO.mac[4], gWIZNETINFO.mac[5]);
printf("SIP: %d.%d.%d.%d\r\n", gWIZNETINFO.ip[0], gWIZNETINFO.ip[1],
gWIZNETINFO.ip[2], gWIZNETINFO.ip[3]);
printf("GAR: %d.%d.%d.%d\r\n", gWIZNETINFO.gw[0], gWIZNETINFO.gw[1],
gWIZNETINFO.gw[2], gWIZNETINFO.gw[3]);
printf("SUB: %d.%d.%d.%d\r\n", gWIZNETINFO.sn[0], gWIZNETINFO.sn[1],
gWIZNETINFO.sn[2], gWIZNETINFO.sn[3]);
printf("DNS: %d.%d.%d.%d\r\n", gWIZNETINFO.dns[0], gWIZNETINFO.dns[1],
gWIZNETINFO.dns[2], gWIZNETINFO.dns[3]);
printf("======================\r\n");

wizchip\_init(NULL, NULL);
printf("w5500 inited\r\n");
}

//初始化芯片参数
void wiznet\_chip\_config(void) {
uint8\_t memsize[2][8] = { { 2, 2, 2, 2, 2, 2, 2, 2 }, { 2, 2, 2, 2, 2, 2, 2,
2 } };

//WIZCHIP SOCKET缓存区初始化
if (ctlwizchip(CW_INIT_WIZCHIP, (void\*) memsize) == -1) {
printf("WIZCHIP Initialized fail.\r\n");
while (1)
;
}
printf("w5500 chip configured\r\n");
}

4、W5500驱动测试

main.c文件中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include <stdio.h>
#include "w5500\_port.h"
#include <string.h> // memcmp
/\* USER CODE END Includes \*/


int main(void) {
/\* USER CODE BEGIN 1 \*/

/\* 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\_USART1\_UART\_Init();
MX\_SPI1\_Init();
/\* USER CODE BEGIN 2 \*/
printf("-----STM32 W5500 Ethernet Demo-----\r\n");
w5500\_restart(); // hardware restart through RESET pin
wiznet\_register();
w5500\_network\_init\_static();
wiznet\_chip\_config();
/\* USER CODE END 2 \*/

/\* Infinite loop \*/
/\* USER CODE BEGIN WHILE \*/
while (1) {
/\* USER CODE END WHILE \*/
//loopback\_tcpc(0, (uint8\_t\*) recv\_buff, destip, destport);
/\* USER CODE BEGIN 3 \*/
}
/\* USER CODE END 3 \*/
}

本次实例使用静态IP配置方式。运行结果如下:

在这里插入图片描述

在这里插入图片描述

文章来源: https://iotsmart.blog.csdn.net/article/details/125887777