ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RK3588平台接入SDIO WiFi模组O9201SB:从设备树到驱动的完整实践指南

RK3588平台接入SDIO WiFi模组O9201SB:从设备树到驱动的完整实践指南 去年年底接了块RK3588的开发板项目板载方案里WiFi模组用的是O9201SB走的是SDIO接口。当时觉得挺简单毕竟RK3588的SDIO控制器在Linux内核里支持得挺成熟了结果真调起来才发现从设备树写法到驱动加载策略到处都有需要注意的细节。这篇文章就把我在RK3588平台上把O9201SB WiFi模组接入Linux系统的完整过程记录下来包括硬件设计要点、内核配置、设备树修改、常见坑位排查和性能测试方法希望能帮你绕开我踩过的那些坑。这个内容主要面向做RK3588方案评估或产品开发的嵌入式工程师也适合正在调试其他SDIO接口WiFi模组的同学参考。如果你手头正好有O9201SB这颗模组或者正在梳理RK3588的SDIO设备树配置逻辑这篇文章可以直接照着做。1. 项目背景与方案选型思考1.1 O9201SB模组定位与核心参数O9201SB是一颗支持WiFi 6协议的SDIO接口模组在RK3588这类高性能ARM平台上主要承担无线网络接入功能。它给我的第一印象是封装比较紧凑RF前端和基带集成度很高外围电路要求不复杂对板级设计来说压力不大。从实际规格来看它支持2.4GHz和5GHz双频段在5GHz频段理论速率可以到1200Mbps级别这个吞吐能力配合RK3588的多核CPU和高速外设做视频推流或者数据采集传输是完全够用的。不过这里要提醒一句标称速率只是理论上限实际吞吐受天线设计、板级布线和驱动配置影响很大。我在测试中发现同一个模组在不同板卡上跑出来的TCP吞吐能差出30%以上后面会专门聊这块。1.2 为什么选SDIO而不是USB或PCIe很多人在RK3588上接WiFi模组会优先考虑USB接口因为Linux下的USB WiFi方案最省事插上就能用。但实际产品化的时候SDIO接口的优势就体现出来了首先是延迟更低SDIO是CPU侧的总线协议和USB这种外部设备总线相比中断路径更短其次是功耗控制更精细WiFi模组在待机时可以通过SDIO的时钟停振机制进入低功耗状态这对电池供电的设备很重要再有就是带宽稳定性SDIO 3.0在4-bit模式下就可以跑到SDR104的104MB/s实际WiFi数据流根本不会把这条总线打满不会像USB那样出现带宽竞争问题。代价就是配置复杂度高了不少。SDIO WiFi模组不仅需要正确的内核驱动还需要设备树里把电源、时钟、中断、复位等引脚全对上任何一个环节出错模组都起不来或者不稳定。下面的内容就是围绕着如何把这些配置一次做对展开的。2. 硬件层面的SDIO接口设计要点2.1 引脚定义与最小连接拓扑O9201SB的SDIO接口用的是标准4-bit模式信号引脚一共6根SDIO_CLK、SDIO_CMD、SDIO_D0、SDIO_D1、SDIO_D2、SDIO_D3。除此之外模组还有几个控制引脚包括WIFI_REG_ON硬件复位/使能脚、WIFI_HOST_WAKE中断唤醒脚、以及供电引脚VBAT、VDDIO。我当时设计的连接拓扑是这样的SDIO_CLK、SDIO_CMD、SDIO_D0~D3直接连到RK3588的SDIO控制器引脚上WIFI_REG_ON接到一个GPIO上这样驱动里可以通过GPIO控制模组的上下电时序WIFI_HOST_WAKE接到RK3588的一个可唤醒中断引脚用做WiFi模组主动唤醒主控的信号线。这里有个细节值得注意WIFI_HOST_WAKE的极性以及是否需要上拉必须以模组手册为准不同厂商的设计逻辑不太一样接反了会导致休眠唤醒功能完全失效。硬件上还有一个容易忽略的地方是SDIO_CLK的走线长度。SDIO时钟频率在SDR104模式下可以跑到200MHz这个频率下时钟线的回沟、过孔带来的寄生电容都会影响信号质量严重时直接导致数据不稳定。我当时布板的时候把CLK线控制在和CMD、DATA线尽量等长且在CLK线旁边铺了地线隔离后面调试过程中几乎没有出现过信号问题。2.2 电源、复位与上电时序电源设计这块O9201SB需要两路电源一路是VBAT主供电通常为3.3V给射频前端和内部电路供电瞬间峰值电流在WiFi发射时能到500mA以上另一路是VDDIO为SDIO接口的电平转换电路供电可以和主控的IO电平一致一般也是3.3V或1.8V。我在RK3588开发板上用的是两路独立的LDO/DCDC分别供电避免WiFi发射时电流波动干扰主控的其他外设。比供电更需要注意的是上电时序。SDIO WiFi模组对上电顺序特别敏感如果VDDIO先于VBAT上电可能导致模组内部电平转换电路工作异常轻则第一次驱动加载失败重则烧坏模组。合理的时序是先给VBAT供电等电源稳定后再拉高WIFI_REG_ON最后等模组内部的复位完成信号输出正常后再去初始化SDIO总线。我在实际调试中遇到过一次很典型的时序问题把WIFI_REG_ON直接接在了RK3588的某个上电默认为高的GPIO上导致系统启动时模组提前上电等到SDIO驱动初始化时模组已经进入了一个异常状态dmesg里反复报mmc1: error -110的错误。后来把WIFI_REG_ON改到了上电默认拉低的GPIO配合驱动里的GPIO控制问题就解决了。2.3 布线层面的三个注意点板级布线直接决定WiFi射频性能和SDIO信号稳定性这里分享三个经验第一SDIO数据信号线要远离射频天线区域。SDIO时钟和数据的谐波会和WiFi射频信号产生互扰影响灵敏度。我当时在天线下方区域禁止了所有SDIO信号线走线保留完整的参考地平面。第二SDIO_CLK线上建议串接22欧姆左右的电阻。这个电阻可以抑制时钟信号过冲同时减少信号振铃。调试初期不确定走线寄生参数时先串一个22欧姆电阻是比较稳妥的做法后面如果发现信号质量没问题可以再移除。第三天线馈点周围要留足净空区。O9201SB的RF输出引脚到天线馈点之间的微带线阻抗要控制在50欧姆周围不要铺铜否则射频性能会大幅下降。实测过同样的模组和驱动配置天线处净空良好的板子比净空不足的板子5GHz频段的吞吐率能高出接近一倍。3. 内核与设备树配置实操3.1 内核驱动配置项RK3588平台在Linux内核里对SDIO WiFi模组的支持已经比较完善前提是内核配置选项打开对了。我用的内核版本是5.10需要确保以下几个配置项被开启CONFIG_MMCy CONFIG_MMC_SDHCIy CONFIG_MMC_SDHCI_PLTFMy CONFIG_MMC_SDHCI_OF_DWCMSHCy CONFIG_MMC_SDHCI_ROCKCHIPy CONFIG_WIRELESSy CONFIG_CFG80211y CONFIG_MAC80211y CONFIG_BRCMFMACy CONFIG_BRCMFMAC_SDIOyO9201SB使用的驱动框架是Broadcom的brcmfmac所以连接WiFi功能的关键是CONFIG_BRCMFMAC和CONFIG_BRCMFMAC_SDIO被编译进内核或编译成模块。如果用的是模块方式还需要确保对应的固件文件放到了文件系统的/lib/firmware/brcm/目录下比如brcmfmac43455-sdio.bin和对应的txt配置文件。这里踩过的一个坑是最初编译内核时只开了CONFIG_BRCMFMAC没开CONFIG_BRCMFMAC_SDIO导致SDIO总线上的驱动根本没注册设备树配得再对也没用。检查的方法很简单启动后执行find /sys/bus/sdio/devices -type l如果能列出设备说明SDIO枚举成功否则需要回到内核配置排查。3.2 设备树节点编写与参数解释设备树这块是整个SDIO WiFi接入的重头戏我把最终可用的节点贴出来然后逐段解释关键参数的含义sdio { status okay; bus-width 4; cap-sdio-irq; non-removable; keep-power-in-suspend; pinctrl-names default; pinctrl-0 sdio_clk sdio_cmd sdio_bus4; sd-uhs-sdr104; #address-cells 1; #size-cells 0; wifi1 { compatible brcm,bcm43455; reg 1; interrupts-extended gpio3 RK_PB5 IRQ_TYPE_LEVEL_LOW; interrupt-parent gpio3; interrupts RK_PB5 IRQ_TYPE_LEVEL_LOW; pinctrl-names default; reset-gpios gpio0 RK_PC4 GPIO_ACTIVE_LOW; }; };这个节点里bus-width 4表示使用SDIO 4-bit模式cap-sdio-irq表示支持通过SDIO的命令线来传输中断这是SDIO WiFi模组常用的异步中断方式。non-removable是因为WiFi模组是焊接在板上的不会热插拔告诉内核不要做热插拔检测。sd-uhs-sdr104开启的是SDIO 3.0的高速模式最高时钟200MHz。这里有个调优经验如果发现模组在高速模式下不稳定可以先去掉这行强制降低传输速率来定位问题。reset-gpios就是前面提到的WIFI_REG_ON引脚驱动加载时会通过这个GPIO控制模组的上下电。3.3 编译烧录与驱动加载验证设备树和内核配置改好之后就可以编译烧录了。RK3588的SDK一般提供了一键编译脚本直接用脚本编出boot.img和resource.img然后通过RKDevTool烧录到开发板。烧录完成后重启系统用下面几个命令验证驱动加载情况# 查看SDIO总线上的设备枚举情况 find /sys/bus/sdio/devices -type l # 查看WiFi网卡是否注册成功 ip link show # 查看驱动加载日志 dmesg | grep -E brcmfmac|mmc1|sdio正常情况下find命令能看到类似/sys/bus/sdio/devices/mmc1:0001:1的设备ip link show能出现wlan0dmesg里能看到brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac43455-sdio.bin这样的固件加载信息。如果这些输出都正常说明驱动已经起来了剩下的就是连接测试了。如果dmesg里有报错但设备又出现了多半是固件版本或者nvram配置的问题后面我专门开一节讲排查方法。4. 调试实录五大常见坑与排查4.1 坑一SDIO设备无法枚举报mmc1: error -110这是我遇到的第一个拦路虎。启动日志里不停刷mmc1: error -110这个错误码对应的是超时意味着SDIO控制器和模组之间的通信一直没有建立起来。排查思路是逐层往上游找。首先测量WIFI_REG_ON引脚的电压确认模组上电了然后用示波器看SDIO_CLK引脚有没有时钟信号输出。我当时测下来发现CLK有波形、电压正常但依然报超时最后定位到是VDDIO供电的LDO输出只有1.2V而模组要求VDDIO是3.3V电平不匹配导致SDIO信号无法正确识别。把LDO输出电压调整到3.3V后设备枚举立刻正常了。这类问题的排查有一个很有效的分层方法先硬件后软件先电压后信号先时钟后数据。不要一上来就怀疑设备树写错了把万用表、示波器拿出来把每个引脚的静态状态确认一遍往往能快速缩小范围。4.2 坑二设备能枚举但扫描不到热点设备枚举成功wlan0也出现了但iw dev wlan0 scan的结果是空列表。这个问题我排查了很久最后发现问题出在板级天线匹配上。O9201SB模组的射频输出到天线的走线阻抗如果不匹配回波损耗会非常大导致射频信号发不出去也收不进来。我当时用的还是半成品的测试板天线部分是手工焊接的馈线长度和走线宽度都没按50欧姆设计导致射频链路几乎全反射。重新按参考设计做了天线匹配之后扫描热点就正常了。另一个可能导致扫描不到热点的原因是国家码或信道设置问题。可以试试用iw reg set CN设置国家码然后重新扫描。如果你的AP刚好在某个信道而模组固件里的信道列表没有包含这个信道也会出现扫描为空的情况。4.3 坑三连接成功但频繁掉线扫描正常、也能连上AP但过一会儿就掉线这种情况多数和电源纹波及功耗管理策略有关。WiFi发射时电流波动很大如果电源的瞬态响应能力不足电压跌落会导致模组内部自动重启表现为掉线后立刻重新关联。解决方法是检查VBAT供电线路上的去耦电容是否足够通常需要预留一个100uF的钽电容或大容量MLCC靠近模组的VBAT引脚放置。另外Linux内核自带的电源管理框架可能会在系统空闲时把SDIO设备挂起导致WiFi模组的tcp连接被断开。调试阶段可以先用下面的命令临时停掉WiFi的电源管理确认掉线问题是否由电源管理策略引起iw dev wlan0 set power_save off如果关掉电源管理后掉线频率明显下降就说明是电源管理策略配置的问题需要检查设备树里的keep-power-in-suspend和cap-sdio-irq配置是否正确。4.4 坑四吞吐率远低于标称值WiFi连接正常、ping稳定但TCP吞吐率只有几十Mbps和标称的1200Mbps差很远。我当时的测试结果是下行只有80Mbps左右问题出在SDIO总线的速率模式没有跑起来。查看/sys/kernel/debug/mmc1/ios里的时钟和总线模式发现时钟只有50MHz远低于SDR104的200MHz。这是因为设备树里的sd-uhs-sdr104没有生效或者内核在启动时因为检测到信号质量问题自动降级到了较低速率。把设备树的sd-uhs-sdr104配置确认好之后时钟频率提升到了200MHz吞吐率也提高到了400Mbps以上。如果确认SDR104已经生效吞吐率还是不够可以检查TCP窗口大小和中断处理效率。SDIO WiFi模组通常会产生大量中断如果中断亲和性设置不合理会导致所有中断都集中在一个CPU核上处理形成瓶颈。我后来通过配置中断亲和性把WiFi中断分散到多个核心上吞吐率又提升了一截。4.5 坑五休眠唤醒后WiFi丢失在默认配置下系统进入深度睡眠后再唤醒时wlan0消失了必须重启系统才能恢复。这个问题的核心是设备树里缺少电源管理相关配置。需要在SDIO节点里加上keep-power-in-suspend同时在WiFi子节点里确认中断唤醒配置正确。这里的原理是系统休眠时SDIO控制器会切断对模组的供电和时钟如果没有特殊标记内核会认为设备已经移除唤醒后自然就找不到wlan0了。我最终的设备树方案里除了keep-power-in-suspend还把WIFI_HOST_WAKE引脚配置成了唤醒源这样模组在接收到AP的唤醒帧后可以主动唤醒主控而不是仅仅靠主控侧的定时唤醒来恢复连接。这个配置对功耗和体验都有明显改善。5. 验收测试与性能优化建议5.1 稳定性验证三板斧接入完成后不能只测试能连上WiFi就结束了尤其是要量产或做长时间运行场景的话下面三个测试建议都要做第一压力传输测试。用iperf3跑持续30分钟以上的双向传输观察吞吐率是否平稳、有无掉线重连、延迟有无突增。如果一个方向跑不满多半是链路质量问题需要回到射频和SDIO配置去排查。第二休眠唤醒测试。反复让系统进入休眠再唤醒每次唤醒后都要检查wlan0是否存在、能否自动重新关联AP。我测试时会写一个脚本自动执行50次休眠唤醒循环把每次的结果记录下来彻底排除偶发性问题。第三弱信号场景测试。在远离AP的位置RSSI在-70dBm以下测试连接稳定性和重连能力。很多模组在强信号下表现很好但弱信号下就频繁断开这时候需要调整天线增益、增加外部PA或者优化驱动里的漫游阈值参数。5.2 几个值得尝试的优化方向如果测试结果都正常有几个方向可以继续挖掘性能潜力一个方向是调整SDIO总线频率和命令超时参数。在SDR104模式下如果信号质量允许可以把时钟配到200MHz甚至更高如果不太稳定牺牲一点频率换取稳定性反而更划算。另一个方向是检查WiFi驱动的TX队列和NAPI调度参数适当增大网卡队列深度可以减少高负载下的丢包率。还有一点容易被忽略O9201SB模组的固件和nvram配置参数不同版本对性能影响很大。我在测试中发现使用原厂提供的最新固件可以修复一些旧版固件里偶发的断流问题而且扫描速度也有明显提升。量产前一定要去模组原厂或代理那边确认最新的固件版本并集成到你的系统镜像里。如果你做的是对功耗有要求的产品还可以深入调一下WiFi的DTIM和PS策略。通过iw命令调整wlan0的功率节省参数可以让设备在待机状态下的网卡功耗降到一个很低的水平同时保持网络连接的可达性。这个调整需要结合实际场景反复测试没有通用的最优参数但是值得花时间去做。我在实际调试RK3588的SDIO WiFi时最大的体会是SDIO WiFi接入工作看起来是纯软件配置但真正决定成败的往往是硬件细节。设备树写错了一个pinctrl或者电源时序差了那么几十毫秒都会让驱动无法正常初始化。建议大家在动手之前把模组的手册和数据手册完整看一遍把电源时序、引脚定义、推荐走线这些硬件要求先用图表梳理清楚再开始写设备树和调驱动。另外调试过程中建议保留一份问题排查日志把每个异常现象对应的解决方案记录下来后续做别的平台或者别的模组时这份日志就是最宝贵的经验库。
返回列表