完成主控板W5500初始化(静态IP配置),并能使用局域网电脑ping通,同时W5500可以ping通互联网站点;通过抓包软件(Wireshark、Sniffer等)抓取本地PC的ping报文,展示并分析
环境搭建
Pico SDK 环境搭建
参考来源:官方文档
W5500-EVB-Pico 开发板官方提供了 RP2040-HAT-LWIP-C 和 RP2040-HAT-C 两个仓库的 SDK 这里以 RP2040-HAT-LWIP-C
使用 git 拉取仓库,指定分支 v1.0.0,最新版本的文档与仓库内容有些出入,所以选择 1.0.0 版本,然后进入目录,更新 submodule
git clone https:
cd RP2040-HAT-LWIP-C
git submodule update --init
这还没完,需要执行几个 patch,对部分的代码进行替代
cd libraries/pico-extras
git apply
cd ..
cd ..
cd libraries/pico-extras/lib/lwip
git apply
git apply
然后直接编译,把所有例程全部编译,当然也可以 cmake 生成 makefile 后选择部分编译
STM32H7 环境搭建
STM32 的环境搭建就相对容易许多了,打开 CubeMX 软件,按照如下操作获取到官方提供的 LWIP 的 Example
这个例程官方提供有 Keil、IAR、CubeIDE 的工程,我这里选择 Keil来进行操作,ST 官方提供的这个 LWIP 的例程是带操作系统的,而 Pico 开发板的例程是裸机的,LWIP 分为裸机和 OS 两种使用方式,看来可以进行同步学习了。
局域网内互相 ping
lwip 的 app 中是没有提供 ping 的,但是开源社区的 contrib 包中提供有 ping 的 app 代码。
http://download.savannah.nongnu.org/releases/lwip/
可以看到其中有 ping 的代码,复制到工程即可,准备工作就完成了
pico
下面的工程是把 lwiperf 的代码复制一份,重命名为 static_ip,同时对 CMakeLists.txt 稍作修改得来的,当然也可以直接在 lwiperf 基础上修改
lwiperf 例程是用的静态 IP,这里修改一下 IP 地址为 192.168.0.188,其中 g_pcip 为电脑的 IP
IP4_ADDR(&g_picoip, 192, 168, 0, 188);
IP4_ADDR(&g_mask, 255, 255, 255, 0);
IP4_ADDR(&g_gateway, 192, 168, 0, 1);
IP4_ADDR(&g_pcip, 192, 168, 0, 103);
然后在 while (1) 的上面一行添加启动 ping 电脑的代码
printf(">>>> W5500 Pico <<<<\n");
printf("LWIP Test\n");
ping_init(&g_pcip);
编译烧录,可以看到开发板不断的 ping 电脑的 IP 并显示延迟
当然也可以反过来,使用电脑来 ping 开发板,这个延迟还不错,打游戏应该挺流畅的
STM32
首先,需要在 lwipopts.h 文件中失能 DHCP 并且设置其他的几个宏定义
#define LWIP_DHCP 0
#define LWIP_DNS 1
#define LWIP_RAW 1
#define LWIP_DEBUG 1
在 main.h 中修改开发板的 IP 为 192.168.0.177
#define IP_ADDR0 ((uint8_t)192U)
#define IP_ADDR1 ((uint8_t)168U)
#define IP_ADDR2 ((uint8_t)0U)
#define IP_ADDR3 ((uint8_t)177U)
然后在 BSP_Config 函数中添加调试串口的初始化,官方例程默认没有初始化调试串口
COM_InitTypeDef com1_config = {
.BaudRate = 115200,
.WordLength = COM_WORDLENGTH_8B,
.StopBits = COM_STOPBITS_1,
.Parity = COM_PARITY_NONE,
.HwFlowCtl = COM_HWCONTROL_NONE,
};
BSP_COM_Init(COM1, &com1_config);
然后修改 Netif_Config 函数,在尾部添加 pico 的 IP 地址作为 ping 的目标
static void Netif_Config(void)
{
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gw;
#if LWIP_DHCP
ip_addr_set_zero_ip4(&ipaddr);
ip_addr_set_zero_ip4(&netmask);
ip_addr_set_zero_ip4(&gw);
#else
IP_ADDR4(&ipaddr,IP_ADDR0,IP_ADDR1,IP_ADDR2,IP_ADDR3);
IP_ADDR4(&netmask,NETMASK_ADDR0,NETMASK_ADDR1,NETMASK_ADDR2,NETMASK_ADDR3);
IP_ADDR4(&gw,GW_ADDR0,GW_ADDR1,GW_ADDR2,GW_ADDR3);
#endif /* LWIP_DHCP */
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input);
netif_set_default(&gnetif);
ethernet_link_status_updated(&gnetif);
#if LWIP_NETIF_LINK_CALLBACK
netif_set_link_callback(&gnetif, ethernet_link_status_updated);
osThreadDef(EthLink, ethernet_link_thread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE *2);
osThreadCreate (osThread(EthLink), &gnetif);
#endif
#if LWIP_DHCP
osThreadDef(DHCP, DHCP_Thread, osPriorityBelowNormal, 0, configMINIMAL_STACK_SIZE * 2);
osThreadCreate (osThread(DHCP), &gnetif);
#endif
ip_addr_t pico;
IP_ADDR4(&pico,IP_ADDR0,IP_ADDR1,IP_ADDR2, 188);
printf(">>>> STM32H743 <<<<\n");
printf("LWIP Test\n");
ping_init(&pico);
}
编译运行,STM32 成功 ping 通 w5500 pico 开发板
wireshark 抓包分析
对于 W5500 Pico 开发板和电脑互相 ping,可以使用 wireshark 来抓包查看,使用过滤器来过滤出含有开发板 IP 的项目,无论是源地址还是目标地址
ip.src == 192.168.0.188 || ip.dst == 192.168.0.188
可以看到 ping 是基于 ICMP 协议的,开发板和电脑不断的收发
双击数据,可以看到十分详细的通信细节,从上到下是各个层级的详细数据
- 物理层:即为抓包的目标接口,这里的硬件设备是 Wi-Fi 网卡
- 数据链路层:显示的是开发板和电脑的 MAC 地址,Wiznet 开头的是开发板,Intel 开头的是电脑的 Wi-Fi 网卡,这个 MAC 地址也是可以在port/lwip/w5x00_lwip.c 中修改的
- IP 层:使用的是 ipv4,可以查看到源 IP 和目标 IP,协议类型等信息,可以看到开发板的 ipv4地址是刚才设置的 192.168.0.188
- ICMP:可以看到具体的数据内容
- 发送时的报文应该是 Type: 8 (Echo (ping) request)
- 正常的回复报文应该是 Type: 0 (Echo (ping) reply)
对于请求的报文,消息包的解析如下图,可以看到各个字段的释义,打开 ping.c 组包的代码,可以看到有 16 位的加和校验、ID 等等信息,关于这些的详细定义可以在 RFC Editor 网站中查询文档,https://www.rfc-editor.org/ ,ICMP 对应的是 RFC 792
下面是 RFC 792 中对请求/应答包的详细说明
ping 公网域名
DNS设置
ping 公网的域名时候,需要一个 DNS 服务器来负责域名的解析任务,比如常用的 8.8.8.8、114.114.114.114 等,当然最常用的就是路由器作 DNS 了
pico
使用 LWIP 来设置静态 IP 地址的时候,DNS 是需要手动设置的,在 RP2040-HAT-LWIP-C/port/lwip/lwipopts.h 中启用 DNS,在末尾添加如下代码,指定 DNS 地址为网关的地址就可以使用 DNS 了
dns_setserver(0, &g_gateway);
现在来 ping 一下 baidu.com,定义几个全局变量
static uint8_t g_dns_target_domain[] = "baidu.com";
static uint8_t g_dns_get_ip_flag = 0;
static ip_addr_t g_resolved;
在 while(1) 的末尾添加如下代码
if ((dns_gethostbyname(g_dns_target_domain, &g_resolved, NULL, NULL) == ERR_OK) && (g_dns_get_ip_flag == 0))
{
g_ip = g_resolved.addr;
printf(" DNS success\n");
printf(" Target domain : %s\n", g_dns_target_domain);
printf(" IP of target domain : [%03d.%03d.%03d.%03d]\n", g_ip & 0xFF, (g_ip >> 8) & 0xFF, (g_ip >> 16) & 0xFF, (g_ip >> 24) & 0xFF);
ping_init(&g_resolved);
g_dns_get_ip_flag = 1;
}
编译烧录,可以看到已经可以对 baidu.com 进行 DNS 解析,并且 ping 通
STM32
STM32 端也是类似,ping 一下 baidu.com
网络优化、iperf 测速
网络延迟和网速是评价网速的两个直观的指标,在上文中使用 ping 来测试了网络延迟,下面使用 iperf 来测试
测试的代码只需要两行代码,放在 while(1) 之前即可,把两个开发板都作为 iperf 的server,因为 Windows 是没有 iperf 工具的,所以我直接使用局域网内的 RK3568 小主机来作为 iperf 的 client 来测试
static lwiperf_report_fn fn;
lwiperf_start_tcp_server_default(fn, NULL);
当然也不能忘了包含头文件
W5500 Pico 在主频 133MHz、SPI 50MHz,DMA 开启的情况下测试结果 15-16Mbps,这个瓶颈还是 SPI 导致的,不过能跑到这个速度,Pico+W5500 的方案还是很不错的
STM32 端就不用说了,H743 内置 MAC,板载的 phy 芯片是 LAN8742A,几乎百兆满速