先说结论RK3588S通过SPI挂W5500这个方案在Linux下完全能跑起来但它不是一条“高性能通道”。我最近在一个边缘网关项目里就用它扩展了一个备份网口折腾了一周多设备树、驱动、中断、测速全都踩了一遍。W5500在单片机圈子里很常见自带硬件TCP/IP协议栈SPI接口驱动起来不复杂但真放到RK3588S这种跑Linux的平台上坑比想象中多。这篇调试记录从硬件连接、设备树配置、驱动移植到iperf3测速方法把整个链路完整拆一遍并在最后给出典型问题的排查思路。如果你也在做类似的事情——主控是RK3588S、想用W5500补一路百兆网口或者手里有开发板想评估SPI转以太网的吞吐量这篇应该能帮你少走不少弯路。1. 方案背景为什么RK3588S会用到SPI转以太网1.1 三套以太网扩展方案的实际对比RK3588S本身是有原生千兆以太网MAC的正常情况下一颗芯片带一路千兆口完全没问题。问题往往出在硬件设计阶段某些定制板卡为了省PCB面积、绕开走线困难的RGMII信号或者GMAC引脚已经被MIPI CSI、PCIe、USB3.0等复用占满最后只剩下几路SPI引脚空着。这时候想再扩网口摆在面前的无非三条路。第一是原生RGMII加外置PHY比如常见的RTL8211F方案。性能自然最好可以跑满千兆但代价也最明显RGMII需要十几根信号线布局布线要等长、要阻抗匹配PCB面积和硬件设计周期都上去了。更麻烦的是有些板子的SoC引脚资源已经耗尽没有第二路GMAC可用。第二是USB转以太网典型芯片是AX88179、RTL8153这类。性能从百兆到千兆都有驱动在主流Linux内核里也基本齐全但是前提是板子上还有空闲的USB Host控制器。我在项目里碰到的情况恰恰是USB口被摄像头和4G模块占光了而且USB转以太网芯片在部分定制内核上也会遇到驱动兼容问题。第三就是SPI转以太网代表芯片就是W5500和ENC28J60。SPI总共就四根信号线再加一根中断、一根复位非常多引脚资源都能怼出来。W5500又内置了完整的硬件TCP/IP协议栈这意味着主控即使没有Linux协议栈甚至跑裸机程序也能实现TCP通信。放到RK3588S这种平台上它会被抽象成一张普通net_device网卡上层应用直接打socket开发体验非常友好。我最后选的W5500还有一个重要原因它的官方驱动资料和寄存器文档非常完善社区里能搜到大量踩坑记录。对于一个只用来做远程运维通道、设备状态上报的备份网口来说稳定性和易用性远比极限带宽重要。1.2 W5500硬件连接与引脚细节W5500的封装是QFN-48实际用到的核心引脚并不多。一张典型接线表如下RK3588S引脚W5500引脚信号说明注意事项SPIx_SCLKSCLKSPI时钟时钟频率由设备树spi-max-frequency控制SPIx_MOSIMOSISPI主出从入对应W5500的MOSI引脚SPIx_MISOMISOSPI主入从出对应W5500的MISO引脚GPIO/SPIx_CS0SCSNSPI片选低有效可硬件CS也可GPIO模拟GPIORSTN复位信号低有效建议RC复位或GPIO控制GPIOINTN中断信号低有效开漏输出必须外接上拉电阻先说INTN这是最容易忽略的硬件细节。W5500的中断引脚是开漏结构不是推挽输出外部一定要接上拉电阻典型值是4.7kΩ到10kΩ到3.3V。如果漏接这个上拉中断脚始终是悬空状态电平不明确Linux侧的中断触发就会时灵时不灵。再说RSTN。W5500上电之后需要等VCC稳定、晶振起振之后再释放复位这个延时最好能做到几百微秒以上。如果驱动里用GPIO控制复位可以在probe函数里先拉低复位脚、延时再拉高。如果是纯RC电路复位需要把时间常数设计得充分一些否则可能出现SPI读寄存器完全无响应的问题——不是接线接错而是芯片根本没完成复位初始化。另外注意W5500需要一颗25MHz无源晶振没有它PHY部分无法工作但SPI通用寄存器还是能读的所以这个问题不会让系统整个瘫掉只会表现为“网卡链路起不来”。2. 设备树与SPI驱动移植从一片黑到能出IP2.1 RK3588S SPI控制器设备树节点怎么写RK3588S有多个SPI控制器具体用哪个要看原理图。假设硬件把W5500挂在了spi0上、中断接GPIO3_A5、复位接GPIO3_B7设备树节点可以这样写spi0 { status okay; pinctrl-names default; pinctrl-0 spi0_pins_hs; cs-gpios gpio2 1 GPIO_ACTIVE_LOW; #address-cells 1; #size-cells 0; w55000 { compatible wiznet,w5500; reg 0; spi-max-frequency 30000000; interrupt-parent gpio3; interrupts 5 IRQ_TYPE_LEVEL_LOW; reset-gpios gpio3 15 GPIO_ACTIVE_LOW; local-mac-address [00 08 DC 00 12 34]; status okay; }; };先解释几个重点属性。spi-max-frequency是最关键的参数。W5500手册标称支持很高的SPI时钟但那是在理想短走线、良好信号完整性下得出来的。实测中我习惯从20MHz开始调试稳定后再往上调到30MHz、40MHz。每提高一次就用iperf3跑一轮长时长双向测试出现丢包或速度不升反降就退回到上一档。RK3588S的SPI控制器本身能力很强但瓶颈往往出在W5500到SoC之间的PCB走线和连接器质量上。interrupts 5 IRQ_TYPE_LEVEL_LOW里的5不是随便写的它表示GPIO bank内的引脚序号也就是GPIO3_A5对应的5号。不同板卡的GPIO号完全不同照抄会踩大坑。调试时可以用cat /proc/interrupts确认中断有没有注册成功。cs-gpios这里使用了GPIO模拟片选。这样做的原因是有些BSP里SPI控制器的硬件CS功能和W5500的中断、复位引脚存在复用冲突用GPIO反而更省心。但要注意如果CS用GPIO模拟对应的GPIO管脚不能在pinctrl里被配置成SPI功能否则驱动会写不到片选信号。local-mac-address建议一定要显式指定。W5500没有内置MAC地址存储如果没有给设备树显式赋值驱动可能会使用一个默认地址导致多台设备MAC相同。量产设备强烈建议根据序列号生成唯一MAC避免网络里的地址冲突。2.2 W5500驱动移植流程与常见编译报错W5500的Linux驱动一般不会直接编进RK3588S的默认内核需要手动加入。驱动源码优先从W5500官方仓库拿这是最稳妥的路径。拿到源码之后把它放到内核源码树的drivers/net/ethernet/wiznet/目录下然后修改同目录下的Kconfig和Makefile。Kconfig里添加config WIZNET_W5500 tristate WIZnet W5500 SPI Ethernet support depends on SPI help This driver supports the WIZnet W5500 chip.Makefile里添加obj-$(CONFIG_WIZNET_W5500) w5500.o然后在make menuconfig里找到Device Drivers - Network device support - Ethernet driver support勾选W5500支持。如果Kconfig里还关联了phy驱动依赖按提示一并打开。编译整个内核或单独编译模块都可以。这里必须提醒一下不同官方版本的驱动代码对Linux内核的API要求差异很大。早年版本基于2.6/3.x内核编写放到6.x内核上编译会大量报错。我遇到过的报错主要有三种struct net_device_ops里ndo_change_mtu等函数指针类型变了旧的赋值为eth_change_mtu的方式在新内核中编译失败。alloc_etherdev的返回值处理方式有变化新旧内核的错误判断宏不同。spi_setup、spi_sync相关的结构体成员命名在部分厂商BSP里做了扩展直接替换头文件就能解决。面对这类问题最省力的办法是先在目标BSP的内核源码里搜一下w5500很多RK3588S厂商SDK其实已经带了适配过的驱动只是默认没开启。如果SDK没有再从官方仓库搬源码但需要照着新内核的API逐一把旧写法替换掉。这部分工作没什么技术难度就是需要耐心一次编译通过的概率不高。驱动成功加载后dmesg里应该能看到类似“WIZnet W5500 Ethernet driver”的打印然后ifconfig -a会看到一个全新的ethX接口。这时候可以先给它配一个静态IP从PC端ping一下能通就说明驱动基本没问题了。2.3 用spidev快速验证SPI读写通路驱动移植过程中最怕的情况是驱动编译通过了insmod也不报错但网卡就是不工作。这大概率是SPI底层通信就没有建立成功。与其在黑盒里瞎猜不如先用spidev把W5500的寄存器读一遍。临时在设备树里加一个spidev节点spidev0 { compatible rohm,dh2228fv; reg 0; spi-max-frequency 30000000; };然后在内核配置里打开CONFIG_SPI_SPIDEV。重新编译内核后/dev/spidev0.0就会出现。接下来写一个小C程序读取W5500的版本寄存器VERSIONR地址0x0039。如果芯片正常且SPI通信正常读到的一定是0x04#include stdio.h #include stdint.h #include fcntl.h #include sys/ioctl.h #include linux/spi/spidev.h int main(void) { int fd open(/dev/spidev0.0, O_RDWR); if (fd 0) { perror(open); return -1; } uint8_t tx[4] {0x00, 0x39, 0xC0, 0x00}; uint8_t rx[4] {0}; struct spi_ioc_transfer tr {0}; tr.tx_buf (unsigned long)tx; tr.rx_buf (unsigned long)rx; tr.len 4; tr.speed_hz 30000000; tr.bits_per_word 8; if (ioctl(fd, SPI_IOC_MESSAGE(1), tr) 0) { perror(ioctl); return -1; } printf(VERSION register 0x%02X\n, rx[3]); return 0; }代码里tx[0]和tx[1]是寄存器地址高字节和低字节tx[2]是控制字节0xC0表示“读通用寄存器块”tx[3]是填充字节用于在MISO上产生时钟把数据读回来。如果打印结果是0x04说明SPI通路、W5500供电、复位时序都是正常的。如果全是0xFF基本可以断定片选没拉到、MISO接错或者芯片未复位完成。如果返回值乱变优先降低SPI频率再试并检查SPI模式是否设置正确。W5500支持SPI Mode 0和Mode 3两种设备树里如果不加spi-cpha和spi-cpol属性默认就是Mode 0也就是CPOL0、CPHA0。这个验证程序完全可以跑在驱动移植之前能把问题范围缩小一大半。3. iperf3测速方法详解与实测结果分析3.1 交叉编译iperf3并部署到RK3588Siperf3是当前最主流的网络带宽测试工具版本选择上建议PC端和板端保持完全一致否则偶尔会出现握手失败或者测试中止。我用的版本是3.12从官方Github仓库拉源码后在PC上交叉编译。RK3588S是aarch64架构交叉编译命令如下tar xf iperf-3.12.tar.gz cd iperf-3.12/ ./configure --hostaarch64-linux-gnu --disable-shared --enable-static make -j$(nproc)编译完成后可执行文件在src/iperf3目录下。如果板子的根文件系统是完整Debian/Ubuntu环境还可以直接apt install iperf3非常省事。但如果你的文件系统是裁剪过的不建议去找依赖直接用静态编译版本更干净。把编译好的二进制拷贝到板子上adb push iperf3 /usr/local/bin/ chmod x /usr/local/bin/iperf3然后分别在PC和板子两端确认版本一致iperf3 --version3.2 单线程/多线程、上行/下行测速怎么测测速拓扑很简单PC和板子接入同一个交换机或者PC直连板子网口。板子上的W5500网口协商速率是100M所以PC侧网口最好也是百兆否则可能出现协商到10M的脏问题。PC端启动服务器iperf3 -s -i 1板子端测上行带宽也就是板子往PC方向发送数据iperf3 -c 192.168.1.100 -t 30 -i 1注意这里的-t 30表示测试30秒时间太短结果波动大建议至少跑30秒并取稳定段数据。-i 1表示每1秒打印一行中间结果。测下行带宽也就是PC往板子方向发送数据需要加反向参数iperf3 -c 192.168.1.100 -t 30 -i 1 -R多连接测试可以这么写iperf3 -c 192.168.1.100 -t 30 -i 1 -P 4如果还想看UDP极限带宽和丢包率可以用iperf3 -u -c 192.168.1.100 -b 30M -t 30-b 30M表示目标带宽30Mbps跑完之后会得到一组丢包率数据。这个数据对于排查W5500在固定速率下是否稳定很有帮助。3.3 实测数据、理论计算与瓶颈定位我在SPI时钟30MHz、MTU 1500、W5500默认socket缓冲区配置下实测结果大概是这样测试项测试命令实测结果TCP上行单连接iperf3 -c 服务器 -t 30约25MbpsTCP下行单连接iperf3 -c 服务器 -t 30 -R约22MbpsTCP上行4连接iperf3 -c 服务器 -t 30 -P 4约27MbpsUDP下行30Miperf3 -u -c 服务器 -b 30M -R丢包率小于1%看到这个结果很多人第一反应是“为什么只有25MbpsW5500不是百兆芯片吗”。这个问题的答案在计算里就清楚了。SPI时钟30MHz换算成纯数据速率就是30Mbps。W5500的SPI帧格式是2字节地址加1字节控制再跟数据字节一个1500字节的MTU TCP包协议栈头部约40字节左右加上SPI帧开销有效载荷占比会低于100%。也就是说SPI本身就是物理瓶颈30MHz时钟跑出25Mbps的TCP吞吐已经属于正常偏好的水平。如果把SPI时钟提升到40MHz理论上限变成40Mbps实测大概能到30Mbps上下提升幅度有限但很可观。如果项目对吞吐有硬指标布线条件又允许尽量把spi-max-frequency调到能稳定工作的最高档位。同时要注意W5500内部socket收发缓冲区。Linux驱动在初始化时会按默认配置设置每个socket的TX/RX buffer这个值如果偏小在大窗口传输时容易出现对端重传。可以修改驱动里的缓冲区初始化代码把正在使用的socket的RX buffer调大。如果只开一个TCP连接其余7个socket完全可以把缓冲区让出来。另外MTU建议保持1500不要尝试开Jumbo Frame。W5500的硬件协议栈对超大帧处理能力有限开9000反而更容易出现丢包和性能下降。4. 调试中的典型问题与排查实录4.1 INT中断不触发、链路起不来的排查这个问题我前后折腾了一晚上最后发现是硬件上拉电阻没焊。W5500的INTN引脚开漏输出如果外部没有上拉到3.3VLinux侧的gpio中断根本检测不到低电平于是表现就是“网卡起来了、IP也配了、但完全收不到数据”。排查方法其实很简单用示波器抓INTN引脚正常通信时电平应该是有规律的脉冲拉低。平时保持高电平一旦有任何中断事件比如收到数据、握手完成都会被拉低一下。如果示波器上看到INTN一直是高电平那就是中断从来没发生过。这时候先检查复位、晶振、SPI通信再用spidev读版本寄存器确认芯片状态。如果版本寄存器能读到0x04但中断不触发再看设备树里的中断类型是不是IRQ_TYPE_LEVEL_LOW。W5500的中断输出是电平型不是单纯的边沿触发因为多个中断源合并后只要还有未处理中断INTN就会持续拉低设置成下降沿触发必然丢中断。还有一类问题是链路。ethtool eth0如果显示Link detected: no说明PHY协商根本没完成。这时候优先检查对端网口、网线再看W5500的RSTN复位时序是否存在拉低时间不够的问题。有些定制板卡会把W5500的RSTN和看门狗或电源管理芯片的GPIO接在一起软件需要额外操作才会释放复位这种隐藏依赖排查起来最费劲。4.2 吞吐量上不去的排查先确认链路速率协商到多少ethtool eth0显示Speed是100Mb/s还是10Mb/s。如果协商到10M那不管SPI多快吞吐也就几Mbps这已经不是SPI能解决的了。接下来看SPI时钟。很多板子的设备树spi-max-frequency写得很高实际因为pinctrl配置不对或者硬件线过长控制器自动降频了。如果你有逻辑分析仪直接抓SPI的SCLK数一下实际频率。没有逻辑分析仪也可以临时用spidev_test工具或者上面那段读寄存器代码把speed_hz改成不同档位做对比测试。软件层面重点检查socket buffer饱和度。iperf3测速时在PC端用tcpdump -i eth0 tcp port 5201抓包观察如果看到大量重复ACK或者连续重传说明板端接收缓冲已经满了导致对端不断重发。这时候要么调大W5500驱动里的socket RX buffer要么适当降低发送带宽或者用UDP测试确认丢包率。还有一个容易被忽略的点是内核的TCP校验和卸载。W5500驱动注册net_device时不要随便给网卡声明NETIF_F_HW_CSUM之类的能力因为W5500硬件协议栈已经独立处理了TCP/IP校验和Linux侧只需要负责数据搬运。如果驱动错误地声明了这些offload特性内核会认为硬件可以做校验和合并实际效果反而会让部分包被系统丢弃。4.3 小工具与排查命令合集整理一套我常用的排查命令按顺序执行基本能覆盖90%的问题场景# 1. 确认驱动加载状态 dmesg | grep -i w5500 # 2. 确认网口是否存在 ifconfig -a # 3. 确认中断是否注册并被触发看w5500对应的中断计数 cat /proc/interrupts # 4. 查看链路协商状态重点看Speed和Link detected ethtool eth0 ethtool -S eth0 # 5. 看当前MTU和IP配置 ip addr show eth0 ip link set dev eth0 mtu 1500 # 6. 用最大包ping测试MTU链路 ping -s 1472 PC_IP # 7. 跑iperf3前先确认单方向能ping通 ping -c 10 PC_IP # 8. 逻辑分析仪抓SPI时序确认SCLK频率ping -s 1472这个命令很有意思1472字节是1500字节MTU减去20字节IP头和8字节ICMP头之后的最大数据长度。如果这个包能通说明MTU链路没问题如果通了但大包iperf3还是掉速那重点放在SPI性能和缓冲区配置上。顺着这个排查思路往下走基本能把硬件、驱动、配置三层问题分离开。最后再分享一个我自己的使用习惯这个SPI转以太网口最终被我固定用作远程运维通道和日志上报通道产品的主要业务流量还是走原生千兆口。这样分工很合理W5500稳定、成本低、驱动成熟承担这类低带宽管理任务绰绰有余。如果哪天业务想通过这个口跑视频流或批量文件传输那就不太现实了得考虑换USB转以太网或者原生GMAC方案。调试时还有个小技巧可以试如果SPI时钟已经提到40MHz且信号质量还不错但吞吐依旧卡在30Mbps附近上不去可以把手头所有socket的TX/RX buffer都集中分配给第一个socket再跑一次iperf3有时会有意外惊喜。这个在需要单连接大吞吐的场景下比盲目调SPI时钟更有效。
阅读完成 · 觉得有帮助?