
先说清楚这个标题里的“测速”不是小车码盘测速也不是运营商宽带测速网而是把 ESP32S3 挂上 W5500 以太网模块之后用 TCP 连接实际跑一轮数据看有线网络链路到底能吃多少吞吐量。我最近基于这套组合做了一个局域网采集网关从画接线图、调驱动到跑测速前前后后折腾了差不多两周踩了不少坑这里把完整流程和避坑记录一次性捋清楚。如果你正在做 IoT 网关、边缘控制器或者单纯想给 S3 加一个稳定的有线网络出口这篇文章应该能帮你省不少时间。1. 方案选型为什么是 S3 W5500而不是 LAN87201.1 先搞清楚 ESP32S3 到底有没有以太网控制器很多人拿到 ESP32S3 第一反应就是翻引脚手册看能不能直接引出以太网接口。但把数据手册和原理图翻到底就会发现ESP32-S3 这颗芯片本身没有内置以太网 MAC 控制器。原版 ESP32 是有 EMAC 的可以走 RMII 接口外接 LAN8720 这类 PHY 芯片STM32F4 系列也内置了 EMAC所以论坛里常见“stm32 w5500”“stm32f407以太网接口”这些搜索。可惜 S3 偏偏把这个外设砍掉了想用有线网只能靠外部扩展。这个“有没有 MAC”的差异是很多人选型时翻车的根本原因。LAN8720 只是一个 PHY 芯片它只负责物理层信号收发MAC 层和 TCP/IP 协议栈全都要主控自己出。原版 ESP32 有 EMAC接 LAN8720 才成立S3 没有 EMAC硬接 LAN8720 要么驱动写不出来要么跑起来各种不稳定热搜里“esp32连接lan8720以太网模块常遇到的3个问题”就是这波人的血泪史。所以 S3 做以太网最合理的路线是外挂一颗自带 MACPHY协议栈的芯片W5500 就是最典型的选择。1.2 三种扩以太网方案横向对比我把常见的几类做法列成一张表方便你对照自己的板子和需求来选。方案代表芯片主控要求协议栈CPU 负担适用场景SPI 外挂全硬件协议栈芯片W5500任意 SPI 主机芯片内部硬件完成很低只做数据搬运ESP32S3、普通单片机、对稳定性要求高的设备RMII 外接 PHYLAN8720、IP101主控必须内置 EMAC主控软件协议栈较高协议栈占资源原版 ESP32、STM32F407 等带 EMAC 的 MCUUSB 转以太网CH390、LAN7800主控有 USB Host驱动 系统协议栈取决于系统Linux 主机板、树莓派等W5500 最大的优势是它把 IPv4、ICMP、ARP、TCP、UDP 这些协议全部用硬件电路实现了主控只通过 SPI 读写 Socket 缓冲区。也就是说 TCP 三次握手、数据重传、ACK 应答这些脏活累活W5500 自己在内部处理完了ESP32S3 只需要关心业务数据。对于没有 EMAC 的 S3这套方案几乎是把复杂度降到了最低。1.3 W5500 硬件协议栈带来的实际好处我实际用下来W5500 的硬件协议栈有个很直观的好处代码量小且逻辑简单。做一个 TCP Server只需要初始化、监听、接收连接、读写数据不用在应用层维护很长一串 TCP 状态机也不怕某个状态处理漏了就死机。调试的时候你会发现PC 端 ping 它它回 ICMP 是硬件自动回的TCP 握手建立连接也是硬件自动完成的。你从串口打印里甚至能看到建连瞬间的时序但代码里一个 TCP 处理函数都不用写。当然它也不是没缺点。硬件协议栈是固定实现TCP 连接数上限是 8 个 Socket缓冲区总共 32KB需要手动分配。想要在 S3 上跑高速传输必须合理分配 TX/RX 缓冲这部分后面我会详细讲。我见过有人把每个 Socket 都设成 2KB 默认值就去测速结果吞吐卡在十几兆还以为是芯片不行其实是缓冲分配的问题。2. 硬件连接从引脚分配到电路细节2.1 引脚分配与接线表W5500 和 ESP32S3 之间走的是 SPI接线本身很简单但引脚选错会埋下大坑。ESP32-S3 的 SPI 外设可以通过 GPIO 矩阵映射到大部分引脚不过要避开 GPIO26 到 GPIO32这些是输入专用引脚不能当输出用另外还要避开板子上已经被占用掉的引脚比如接了 PSRAM、LCD、RGB 灯的引脚。我调试时用的这套引脚分配在 Arduino-ESP32 环境下和 W5500 模块配合很稳你可以直接抄。ESP32S3 引脚W5500 模块引脚说明GPIO12SCLKSPI 时钟GPIO13MISOSPI 主收从发GPIO11MOSISPI 主发从收GPIO10SCS/CS片选低有效GPIO14RSTN复位低有效GPIO21INTN中断输出可选3V33.3V电源GNDGND共地注意 Arduino 的SPI.begin()参数顺序是SPI.begin(SCLK, MISO, MOSI, SS)千万不要按 MOSI、MISO 的顺序填反了。我一开始顺手写成SPI.begin(12, 11, 13, 10)结果 W5500 完全没响应串口打印寄存器全是 0xFF排查了半天才发现是顺序问题。2.2 电源、复位与参考电路W5500 模块正常工作电流在 100mA 到 200mA 之间网口变压器和 RJ45 指示灯的功耗也要算进去。我建议给 W5500 单独走一路 3.3V不要直接和 S3 的 3.3V 公用一根细杜邦线。用独立 LDO 或者 DC-DC 输出 3.3V并在电源引脚附近并联一个 10uF 电解电容和一个 0.1uF 陶瓷电容这个组合能有效吸收瞬态电流波动。供电不稳造成的表现非常迷惑有时候是 ping 延时忽高忽低有时候是 TCP 速率掉一半先从电源排查不会错。复位时序也值得单独提一下。W5500 的 RSTN 引脚至少要保持低电平 500us然后拉高芯片才开始正常工作。上电瞬间电源还没稳定就释放复位芯片可能进入异常状态。代码里我习惯这样处理pinMode(W5500_RST, OUTPUT); digitalWrite(W5500_RST, LOW); delay(100); digitalWrite(W5500_RST, HIGH); delay(500);如果不想占用 GPIO也可以把 RSTN 接到 RC 复位电路上阻容值取 10K 和 1uF提供约 10ms 的上电延时更省引脚。W5500 参考电路里还有一个容易被忽视的点PHY 的工作模式由 PMODE 引脚决定市售模块一般已经固定拉好了不需要用户干预。但如果你买的是裸片自己画板一定要按数据手册把 PMODE 配成自协商或全双工模式否则可能出现“模块能初始化、能拿到 IP但 ping 不通对端”的诡异现象。2.3 焊接与模块选购建议模块接线我强烈建议先短后长。用杜邦线测试时SPI 线尽量控制在 10cm 以内而且 MOSI 和 MISO 不要扎成一捆避免信号串扰。我测试初期用 20cm 的杜邦线跑 30MHz SPI速率数据时好时坏换短线和独立接地后立马稳定了。选购模块时有几个细节可以帮你避坑一是看 RJ45 是否集成网络变压器大多数成品模块都集成了省事二是看模块上有没有 3.3V 稳压芯片有些模块支持 5V 输入说明已经带了 LDO电源兼容性更好三是看模块引出的排针间距2.54mm 最通用方便接面包板。另外焊接排针时多检查有没有虚焊特别是 MISO 和 CS 这种长期工作的引脚虚焊导致偶发断连是最难排查的。3. 软件准备开发环境、驱动库与初始化3.1 Arduino 还是 ESP-IDFS3 开发环境主要有两条路Arduino IDE 和 ESP-IDF。如果你主要目标是快速验证硬件、跑通 TCP 测速我强烈建议先用 Arduino IDE开发效率高库生态完善Ethernet3、EthernetLarge 这些库都支持 W5500。如果你要做的产品后续需要 Task 调度、深度定制协议栈或者大批量固件管理再切换到 ESP-IDF 不迟。ESP-IDF 也有官方对应的解决方案esp_eth组件里已经把 W5500 当作 SPI 以太网设备支持了官方仓库有现成例程。不过 IDF 的初始化代码量大一些新手第一次跑容易迷失在 Kconfig 和各种 driver 配置里。这篇文章所有代码都以 Arduino 环境为主线容易复现。Arduino 环境装 ESP32S3 板卡包是老生常谈在 Arduino IDE 的“开发板管理器”里搜esp32 by Espressif Systems安装即可。库方面搜Ethernet3或EthernetLarge装其中一个就能用。两者 API 基本一致下面例子拿 Ethernet3 演示。3.2 初始化代码复位、SPI、IP 一个都不能少一个最小可用的 W5500 初始化流程是这样的先初始化 SPI 引脚再软复位 W5500然后调用Ethernet.begin()设置 MAC 和 IP。我建议测试阶段直接用静态 IP别用 DHCP。DHCP 本身不是不能用但一旦路由器 DHCP 服务有波动W5500 这边表现就是长时间拿不到地址很容易让你误判成硬件问题。#include SPI.h #include Ethernet3.h #define W5500_CS 10 #define W5500_RST 14 uint8_t mac[] {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; IPAddress local_ip(192, 168, 1, 120); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); void setup() { Serial.begin(115200); delay(1000); // 注意参数顺序: SCLK, MISO, MOSI, SS SPI.begin(12, 13, 11, 10); pinMode(W5500_RST, OUTPUT); digitalWrite(W5500_RST, LOW); delay(100); digitalWrite(W5500_RST, HIGH); delay(500); Ethernet.init(W5500_CS); Ethernet.begin(mac, local_ip, gateway, subnet); Serial.print(IP: ); Serial.println(Ethernet.localIP()); }这里Ethernet.init(W5500_CS)是告诉库 CS 脚用哪个Ethernet.begin()不带 DHCP 参数时用静态 IP。MAC 地址不要和局域网其他设备冲突如果批量做设备建议用产线分配的地址段。3.3 TCP 最小收发工程跑通初始化之后我建议先写一个最简单的 TCP Server 回显程序验证双向收发都正常再上测速固件。下面这个程序监听 5201 端口收到什么就原样返回PC 端可以用任意 TCP 调试工具连上去测试。#include SPI.h #include Ethernet3.h #define W5500_CS 10 #define W5500_RST 14 #define SERVER_PORT 5201 uint8_t mac[] {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; IPAddress local_ip(192, 168, 1, 120); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); EthernetServer server(SERVER_PORT); void setup() { Serial.begin(115200); SPI.begin(12, 13, 11, 10); pinMode(W5500_RST, OUTPUT); digitalWrite(W5500_RST, LOW); delay(100); digitalWrite(W5500_RST, HIGH); delay(500); Ethernet.init(W5500_CS); Ethernet.begin(mac, local_ip, gateway, subnet); server.begin(); Serial.print(TCP server at ); Serial.println(Ethernet.localIP()); } void loop() { EthernetClient client server.available(); if (client) { while (client.connected()) { if (client.available()) { int c client.read(); client.write(c); } } client.stop(); } }这个示例虽然简单但验证了两件事SPI 通信是否正确、W5500 的 Socket 是否正常收发。我见过有人在初始化代码上花了很多时间结果问题只是对端防火墙拦了端口这时候用telnet或者串口工具连一下就能定位。3.4 确认连通性先 ping 再抓包TCP 工程跑起来后我一般按这个顺序做连通性验证先在 PC 上ping 192.168.1.120确认 ICMP 通再用 TCP 调试工具连 5201 端口发一串数据看回显最后用 Wireshark 抓包确认有没有异常重传。如果 ping 不通先看串口打印的 IP 是不是预期值再查物理接线如果 ping 通但 TCP 连不上问题多半在 Socket 配置或防火墙不在物理层。4. TCP 测速全流程从原理到实测数据4.1 网络测速到底在测什么TCP 测速的核心是测量应用层吞吐量也就是在一段时间内通过 TCP 连接成功传输的有效数据量单位通常用 Mbps。它和运营商宽带测速有点类似但有一个关键区别局域网测速排除了广域网带宽瓶颈反映的是设备本身、物理链路和协议栈处理能力。对 S3W5500 这套组合来说测出来的数字就是“这套硬件固件在实际应用里能跑多快的上限”。测速时有一点要先说清楚TCP 三次握手和四次挥手在这个过程中是不可见的因为 W5500 把握手完全硬件化了。四次挥手也一样连接拆除时的 FIN/ACK 交换由硬件完成应用层只看到client.stop()返回。但理解这些状态机对排查问题很重要比如测速过程中出现大量连接建立和拆除整体速率一定会下降这就引出了后面要讲的长连接与短连接问题。4.2 PC 端准备用 Python 脚本最稳很多人第一反应是用 iperf3 测速。但注意iperf3 有自己的一套控制协议S3 上如果只写一个普通的 TCP Server不实现 iperf3 协议iperf3 客户端连上来是会报错的。所以我更推荐用一段简单的 Python 脚本做 PC 端收发工具原理和 iperf 一样但完全可控还不挑固件。下面这段脚本是 PC 作为发送端往 S3 的 TCP Server 连续发数据持续 5 秒最后打印吞吐import socket, time def send_test(ip, port5201, duration5): s socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip, port)) payload bx * (4 * 1024) start time.time() total 0 while time.time() - start duration: s.sendall(payload) total len(payload) s.close() mbps total * 8 / duration / 1e6 print(fsend total {total} bytes, ~{mbps:.2f} Mbps) send_test(192.168.1.120)如果测 S3 作为发送端、PC 接收的“上行”方向就需要在 PC 端起一个 TCP Server 收数据S3 固件去连 PC 然后狂发数据。import socket, time def recv_test(port5201, duration5): srv socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) srv.bind((0.0.0.0, port)) srv.listen(1) print(waiting for incoming connection...) conn, _ srv.accept() start time.time() total 0 while time.time() - start duration: data conn.recv(4096) if not data: break total len(data) conn.close() srv.close() mbps total * 8 / duration / 1e6 print(frecv total {total} bytes, ~{mbps:.2f} Mbps) recv_test()4.3 S3 端测速固件Server 和 Client 两版S3 作为 TCP Server 时代码逻辑参考 3.3 的回显工程但不需要回发数据只接收并统计字节数测试结束后通过串口打印速率。这里有个容易忽略的点client.read(buf, sizeof(buf))批量读取比client.read()一个字节一个字节读要快得多因为减少了协议栈调用次数。#include SPI.h #include Ethernet3.h #define W5500_CS 10 #define W5500_RST 14 #define SERVER_PORT 5201 uint8_t mac[] {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; IPAddress local_ip(192, 168, 1, 120); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); EthernetServer server(SERVER_PORT); uint8_t buf[4096]; void setup() { Serial.begin(115200); SPI.begin(12, 13, 11, 10); pinMode(W5500_RST, OUTPUT); digitalWrite(W5500_RST, LOW); delay(100); digitalWrite(W5500_RST, HIGH); delay(500); Ethernet.init(W5500_CS); Ethernet.begin(mac, local_ip, gateway, subnet); server.begin(); Serial.print(TCP server at ); Serial.println(Ethernet.localIP()); } void loop() { EthernetClient client server.available(); if (client) { Serial.println(client connected); unsigned long start millis(); unsigned long bytes 0; while (client.connected() (millis() - start 5000)) { int n client.read(buf, sizeof(buf)); if (n 0) { bytes n; } } unsigned long elapsed millis() - start; float mbps bytes * 8.0 / (elapsed / 1000.0) / 1000000.0; Serial.printf(received %lu bytes in %lu ms, %.2f Mbps\n, bytes, elapsed, mbps); client.stop(); } }S3 作为 TCP Client 去连 PC 的接收脚本代码就更直接#include SPI.h #include Ethernet3.h #define W5500_CS 10 #define W5500_RST 14 uint8_t mac[] {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; IPAddress local_ip(192, 168, 1, 120); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); IPAddress pc_ip(192, 168, 1, 100); EthernetClient client; uint8_t buf[4096]; void setup() { Serial.begin(115200); SPI.begin(12, 13, 11, 10); pinMode(W5500_RST, OUTPUT); digitalWrite(W5500_RST, LOW); delay(100); digitalWrite(W5500_RST, HIGH); delay(500); Ethernet.init(W5500_CS); Ethernet.begin(mac, local_ip, gateway, subnet); memset(buf, A, sizeof(buf)); } void loop() { if (!client.connected()) { delay(1000); if (client.connect(pc_ip, 5201)) { Serial.println(connected); unsigned long start millis(); while (millis() - start 10000) { client.write(buf, sizeof(buf)); } client.stop(); Serial.println(done); } } }这里client.write(buf, sizeof(buf))是整块写入W5500 硬件栈会把数据切包发送应用层不需要关心。发送方向吞吐受 W5500 的 TX 缓冲影响很大如果缓冲太小write会被阻塞在等待硬件 ACK 上速率上不去。4.4 实测结果与参数调优我在同一个环境下做了多组对照测试PC 通过千兆交换机连接 S3S3 只跑一个测速任务结果如下表。注意这些是参考值不同板子、不同模块、不同接线会有波动但趋势是一致的。SPI 时钟TX/RX 缓冲KB方向实测吞吐10 MHz8 / 8PC 到 S3约 9.1 Mbps20 MHz8 / 8PC 到 S3约 17.6 Mbps30 MHz8 / 8PC 到 S3约 25.8 Mbps40 MHz8 / 8PC 到 S3约 29.5 Mbps20 MHz默认 2 / 2PC 到 S3约 12.4 Mbps30 MHz8 / 8S3 到 PC约 24.3 Mbps从数据能明显看出两件事。第一SPI 时钟从 10MHz 提升到 30MHz吞吐几乎线性增长说明 SPI 总线是主要瓶颈之一再往上提到 40MHz 收益变小因为 W5500 内部处理协议栈的时间逐渐变成新瓶颈。第二Socket 缓冲从默认 2KB 调到 8KB 后同样 20MHz 下吞吐从 12.4Mbps 涨到 17.6Mbps提升了 40% 以上。所以调优优先做两件事把 SPI 频率提到 20MHz 或 30MHz把用到的 Socket 缓冲调到 8KB 或 16KB。调整 W5500 的 Socket 缓冲是通过寄存器Sn_TXBUF_SIZE和Sn_RXBUF_SIZE完成的W5500 总缓冲是 16KB TX 加 16KB RX给 Socket0 配了 8KB 后其他 Socket 可用的空间就少了。如果你的应用同时需要多个连接要按实际需求分配不要一味给单个 Socket 开满。4.5 长连接与短连接在测速时的表现TCP 长连接和短连接在测速场景下的差异非常大。长连接只做一次三次握手之后持续传输吞吐稳定短连接每传一小段数据就要重新握手然后又要四次挥手释放连接大量时间花在状态切换上速率自然上不去。如果你在测速时把数据包拆得很碎每次建立连接只发几十字节就断开即使链路本身没有问题测出来的结果也会非常难看。有些时候 PC 端 Python 脚本报错error: listen tcp 127.0.0.1:11434: bind: only one usage of each socket address这种情况本质上就是短时间大量连接导致本地端口处于 TIME_WAIT 状态没有释放完。我在调试早期就遇到过后来改成单条长连接持续收发问题才彻底解决。测吞吐量务必用长连接这是基准条件。5. 避坑指南这些坑我全都踩过5.1 SPI 信号完整性速率上不去的隐藏杀手SPI 通信不稳定最典型的表现是初始化偶尔失败、读写寄存器返回值乱跳、测速速率忽高忽低。我踩过的坑有这么几个杜邦线过长、MOSI 和 MISO 扎捆、SCLK 和 CS 靠得太近、W5500 和 S3 之间没有良好的共地。当时我用 20cm 飞线跑 40MHz现象非常奇怪——连续读写寄存器能过但测速时 TCP 连接经常断串口打印偶尔蹦出错误数据。用示波器看 SCLK 和 MISO发现信号过冲和振铃都很严重。解决办法就是换短线、时钟降到 20MHz再在 S3 的 SPI 引脚附近对地并联一个 100nF 电容作滤波问题立刻消失。如果你没有示波器最简单的排查方法就是降 SPI 频率如果问题消失基本可以断定是信号完整性问题。5.2 长时间运行后 ping 断续、连不上的系统性排查这是 W5500 相关讨论里出现频率最高的问题设备正常跑几天突然 ping 断断续续甚至彻底连不上。我一开始以为是模块烧了重启后又能用过几天又犯。后来逐项排查发现多数情况下是这几个原因叠加。第一步查电源纹波。W5500 长时间工作发热后如果供电是从 S3 的 3.3V 引脚直接拉出来的负载变化可能导致电压跌落PHY 进入异常状态。用独立 LDO 并加大电容后我这边稳定性提升明显。第二步看 W5500 的 PHY 链接状态寄存器。W5500 提供了一个 PHYCFGR 寄存器可以读链路是否正常。如果链路断开后没有正确恢复表现就是 ping 完全不通但寄存器状态显示正常这种情况下需要软件复位 W5500 或重新初始化 Socket。我后来在固件里加了一个定时看门狗一旦检测到连续 N 秒没有收到任何数据包就自动执行一次软复位重新初始化 W5500这个问题基本根除。第三步要怀疑 ARP 缓存和 IP 冲突。之前我在局域网里手动设了静态 IP但另一个设备也用了同样 IP结果路由器的 ARP 表不停抖动外部设备一会儿能 ping 通一会儿不通。换成不冲突的地址段后恢复正常。5.3 TCP reset by peer 与连接卡死PC 端访问 S3 上的服务时偶尔会看到类似curl: (35) TCP connection reset by peer的报错。TCP reset 的本质是某一端收到了无法处理的报文直接发 RST 终止连接。最常见的原因是 S3 端的 Socket 缓冲满了或者应用层处理不过来W5500 直接丢弃了报文并触发连接重置。我在做数据采集服务时遇到过PC 端用短连接高频请求数据S3 端单线程串行处理偶尔一次请求处理超过几秒PC 端超时断开随后 S3 收到这个半开连接的报文硬件直接发 RST。解决思路有两个一是应用层尽量保证处理及时不要在回包前做耗时操作二是提升 W5500 的 Socket 缓冲给突发流量更多余量。如果设备端同时提供多个服务还要注意 W5500 只有 8 个 Socket监听的和已建立的连接都会占 Socket 资源耗尽后新连接会神秘失败这时候抓包会看到对端收到了没有任何响应的 SYN 包。5.4 常见问题速查表现象可能原因排查和处理初始化失败寄存器全 0xFFSPI 接线错误或引脚顺序反了核对 SCK/MISO/MOSI/SS用SPI.begin(SCLK, MISO, MOSI, SS)ping 不通电源不稳、PMODE 配置不对、IP 冲突独立供电检查链路寄存器换静态 IP测速吞吐偏低SPI 频率低、Socket 缓冲小提到 20-30MHz给 Socket 分配 8KB 以上缓冲TCP 连接频繁 Reset缓冲溢出、应用层处理慢提高缓冲、优化处理逻辑、避免短连接高频请求长时间运行后失联电源劣化、链路未恢复、Socket 泄漏查电源纹波加软复位看门狗监控 Socket 状态PC 端bind: address already in use短连接过多导致 TIME_WAIT 堆积改用长连接或调高本地端口范围6. 扩展场景与个人心得6.1 Modbus TCP 与多连接场景W5500 的 8 个 Socket 意味着它非常适合做多连接的服务端。比如 Modbus TCP 网关一个 Socket 做监听其他 Socket 同时处理多台设备或上位机的请求硬件协议栈保证每个连接的 TCP 状态机互不干扰。我后来在这套 S3W5500 平台上跑过一个简化版 Modbus TCP 服务稳定性和响应速度都比软件协议栈方案好很多至少不用担心任务调度被网络中断打乱。6.2 再往上提速的思路如果你对吞吐有更高要求单靠 W5500 能压榨的空间有限毕竟硬件协议栈的瓶颈摆在那里。可以考虑的思路包括用原版 ESP32 的 EMAC 接 LAN8720但那样代码复杂度上去了或者换用带以太网 MAC 的芯片平台比如 STM32H7 这类。如果坚持 S3W5500就把重点放在 SPI 频率、DMA、Socket 缓冲和单任务处理上实测到 30Mbps 左右对绝大多数局域网采集和工业通信场景已经足够。6.3 一点非常实用的建议最后分享一个我调这整套系统时总结的习惯任何网络问题先分层排查。物理层看灯、看复位时序、看电源链路层 ping 通不通传输层看 TCP 能不能建连应用层再去看业务数据对不对。不要一上来就怀疑代码。我踩过最蠢的一次坑是花了一晚上调 TCP Server 代码最后发现只是路由器把设备隔离了客户端根本找不到 S3。把 W5500 当普通网卡看待网络能通才轮得到固件背锅能省下大量无意义的调试时间。