首页 / 资讯中心 / 文章详情

RK3576 SD卡识别异常排查:从CD检测到设备树配置实战

RK3576 SD卡识别异常排查:从CD检测到设备树配置实战 ★ FEATURED ARTICLE
1. 从一次SD卡识别异常说起RK3576的CD检测到底卡在哪拿到RK3576这块板子的时候我第一反应是这平台接口真全——双千兆网口、多路MIPI、PCIe、USB3.0一应俱全做边缘计算盒子或者工业网关都挺合适。但真正上手第一天我就被一个看起来最不起眼的功能绊住了SD卡的插拔检测。事情是这样的。板子跑的是嵌入式Linux系统本身从eMMC启动没问题串口终端也能正常登录。我插了一张32GB的TF卡准备挂载上去做数据存储。结果lsblk看不到任何新设备dmesg里也没有mmc相关的枚举日志。拔出来再插还是没反应。换了一张卡一样。这时候我意识到问题不在卡上而在板子对卡插入这件事的感知上。SD卡能不能被系统识别第一步不是看驱动而是看CDCard Detect信号有没有被正确捕获。CD是SD卡座上的一个物理引脚卡插进去时它会接地或拉高SoC通过这个电平变化判断有卡来了。如果CD信号没接对、没配置对、或者被软件屏蔽了那后面的SDIO枚举流程根本不会启动你在用户空间怎么折腾都是白费。RK3576的SDMMC控制器支持CD检测但它的实现方式和很多老平台不太一样。老平台比如一些早期的ARM SoCCD往往直接连到GPIO驱动里写个中断就行。而RK3576的CD可以走SDMMC控制器的内部CD采样逻辑也可以走外部GPIO具体取决于硬件设计和设备树怎么配。我踩的第一个坑就是没搞清楚这块板子到底用的是哪种方式直接照着网上搜到的通用RK平台SD卡配置去改结果方向完全错了。提示遇到SD卡不识别先别急着改驱动。第一步永远是确认硬件上CD信号接到了哪里是SDMMC专用CD引脚还是普通GPIO还是干脆没接靠软件轮询。这个信息决定了你后面所有配置的走向。我后来翻原理图才发现这块板子的TF卡座CD脚接的是GPIO3_B5而不是SDMMC控制器的专用CD输入。这就意味着设备树里必须把这个GPIO配成cd-gpios并且驱动要能正确处理它的中断。而我之前参考的配置里写的是broken-cd表示没有CD检测靠轮询两者行为完全不同——一个靠中断即时响应一个靠定时轮询延迟和功耗都不一样。这个发现让我重新梳理了整个链路硬件连接 → 设备树描述 → 驱动解析 → 控制器初始化 → 卡枚举。任何一环对不上卡就是认不出来。下面我把这条链路上我实际踩过的坑和验证方法按顺序拆开讲。2. 设备树里cd-gpios和broken-cd的区别以及配错之后的真实表现设备树是嵌入式Linux里硬件描述的总纲SD卡能不能被正确识别八成问题出在这一层。RK3576的SDMMC节点在arch/arm64/boot/dts/rockchip/rk3576.dtsi里定义板级dts再覆盖具体参数。我一开始犯的错就是没区分清楚几个关键属性的语义。2.1 cd-gpios、broken-cd、non-removable三者的适用场景这三个属性经常被混用但它们描述的是完全不同的硬件形态属性含义适用硬件驱动行为cd-gpios指定CD检测用的GPIO卡座CD脚接到普通GPIO注册GPIO中断插拔触发枚举/移除broken-cd声明CD信号不可用卡座无CD脚或CD未接定时轮询周期检测卡状态non-removable卡不可移除eMMC、焊接式存储启动时枚举一次不检测插拔我那块板子CD接的是GPIO3_B5正确写法应该是sdmmc { status okay; cd-gpios gpio3 RK_PB5 GPIO_ACTIVE_LOW; /* 其他参数 */ };而我最初抄来的配置写的是broken-cd;驱动就按轮询模式跑。轮询模式下如果轮询周期设得长默认可能几百毫秒到秒级插卡后要等一会儿才识别更关键的是如果硬件上CD脚是接着的但你没告诉驱动驱动可能在某些状态下误判卡的存在导致枚举失败。实测表现上broken-cd配置下插卡dmesg里会看到周期性的mmc检测日志但卡始终枚举不出来因为控制器在等待一个它认为卡已就位的稳定状态而实际电平变化它没通过中断及时捕获。换成cd-gpios后插卡瞬间就能看到mmc1: new high speed SDHC card这类日志。2.2 GPIO_ACTIVE_LOW还是HIGH取决于卡座电路GPIO_ACTIVE_LOW和GPIO_ACTIVE_HIGH这个极性很多人随手写一个结果就是插卡没反应、拔卡反而触发。它的依据是卡座CD脚的电路设计如果卡座CD脚在无卡时通过上拉电阻拉高插卡时接地那有效电平是低写GPIO_ACTIVE_LOW。反之如果无卡时下拉到地插卡时拉高写GPIO_ACTIVE_HIGH。我拿万用表量过无卡时GPIO3_B5对地电压3.3V插卡后变成0V。所以是低有效GPIO_ACTIVE_LOW正确。如果你写反了现象很诡异——系统认为卡一直插着启动时就尝试枚举但实际没卡枚举超时真插卡时反而认为卡被拔了。注意极性判断不要靠猜用万用表或示波器量一下CD脚在插拔两种状态下的电平这是最靠谱的。原理图上如果有标注CD#通常意味着低有效。2.3 引脚复用pinctrl没配对GPIO根本不工作RK3576的引脚功能高度复用GPIO3_B5要作为普通GPIO使用必须在pinctrl里把它从其他功能比如某个外设的专用脚切回来。我遇到的情况是dts里cd-gpios写了但pinctrl没配结果这个脚还停留在默认的复用功能上GPIO中断永远不触发。正确的做法是在sdmmc节点里引用一个pinctrl状态sdmmc { pinctrl-names default; pinctrl-0 sdmmc_cd_pin; }; pinctrl { sdmmc { sdmmc_cd_pin: sdmmc-cd-pin { rockchip,pins 3 RK_PB5 RK_FUNC_GPIO pcfg_pull_up; }; }; };这里RK_FUNC_GPIO表示切到GPIO功能pcfg_pull_up是上拉配置。如果漏了这段或者rockchip,pins里的bank、pin、func写错CD检测就是死的。我排查时用cat /sys/kernel/debug/gpio看GPIO3_B5的状态发现它显示的功能不是GPIO才定位到pinctrl问题。3. 从dmesg到debugfs一步步定位SD卡枚举失败的真实原因设备树改对之后我以为万事大吉结果插卡还是时好时坏。这时候就不能靠猜了得用系统提供的调试手段把整条链路的状态看清楚。我总结了一套从粗到细的排查顺序基本能覆盖SD卡不识别的绝大多数情况。3.1 第一层dmesg里的mmc日志告诉你卡走到哪一步dmesg | grep -i mmc是最快的信息来源。正常插卡应该看到类似这样的序列mmc1: SDHCI controller on ... using ADMA mmc1: new high speed SDHC card at address 0007 mmcblk1: mmc1:0007 SD32G 29.7 GiB如果只看到控制器注册没有new ... card说明卡枚举没启动或失败了。常见日志和含义mmc1: card detect gpio not foundcd-gpios没配或GPIO申请失败。mmc1: timeout waiting for hardware interrupt控制器和卡通信超时可能是时钟、电压或信号完整性问题。mmc1: error -110 whilst initialising SD card-110是ETIMEDOUT枚举阶段超时重点查供电和时钟。完全没有mmc1相关日志控制器status不是okay或者根本没使能。我那次时好时坏的现象dmesg里偶尔出现error -110偶尔又正常。这种间歇性问题最烦人但也最有排查价值。3.2 第二层debugfs看控制器和卡的实时状态内核开了CONFIG_DEBUG_FS后/sys/kernel/debug/mmc1/下面有一堆有用的文件ios当前IO设置包括时钟频率、总线宽度、电压。如果时钟是0或者电压不对枚举肯定失败。err_stats错误统计能看到CRC错误、超时次数。state卡的状态机当前状态。我通过cat /sys/kernel/debug/mmc1/ios发现正常时clock是5000000050MHz出问题时clock显示400000400kHz枚举初始频率且一直不往上走。这说明卡在识别阶段400kHz就没通过根本没进入高速模式。进一步查err_statsCRC错误计数在涨指向信号完整性问题。3.3 第三层示波器看SDIO信号确认是硬件还是软件软件层面查到最后如果怀疑信号问题就得上示波器了。SDIO的关键信号有CLK、CMD、DAT0-3。我重点看了两点CLK频率枚举阶段应该是400kHz识别后升到50MHz。如果CLK一直是400kHz说明卡没被正确识别。CMD线上的响应主机发命令后卡应该在约定时间内拉低CMD线响应。如果看不到响应要么卡没供电要么CMD线被拉死。我实测发现出问题时CMD线上主机的命令波形正常但卡的响应时有时无。结合CRC错误判断是DAT/CMD线的上拉电阻或走线有问题。后来检查PCB发现CMD线的上拉电阻焊盘有点虚焊补焊之后间歇性问题消失。提示SDIO信号对走线和上拉很敏感。CMD和DAT线通常需要10k-50k的上拉电阻CLK不需要上拉。如果硬件是自己设计的这几根线的等长和阻抗要留意。3.4 第四层供电和电压切换SD卡对电源很挑剔SD卡规范要求初始化时用3.3V高速模式可以切到1.8VUHS-I。RK3576的SDMMC控制器支持电压切换但如果供电电路LDO或负载开关响应慢或者电压切换时序不对卡就会枚举失败。我遇到过一次卡在3.3V下能识别但一切到1.8V就掉。查下来是板子上SD卡供电的LDO使能脚接错了切换时LDO被意外关断。这种问题在dmesg里表现为mmc1: switching to 1.8V failed或者直接超时。解决办法是检查供电电路的使能逻辑确保电压切换时供电不中断。排查到这里SD卡识别的问题基本能定位到具体环节了。但识别只是第一步真正让SD卡在系统里稳定可用还有挂载、性能、热插拔这些事要处理。4. 卡认出来之后挂载、性能与热插拔的连锁问题卡能被lsblk看到只说明块设备注册成功了。要真正用起来还得过挂载、文件系统、性能、热插拔这几关。这几步里也有不少坑而且很多是卡能认但用着用着出问题的类型。4.1 自动挂载udev规则还是fstab选错场景很尴尬嵌入式系统里SD卡挂载有两种常见做法fstab静态挂载在/etc/fstab里写死设备节点和挂载点。适合卡长期插着不拔的场景比如数据盘。缺点是卡不在时启动会报错需要加nofail选项。udev/mdev规则动态挂载卡插入时自动挂载拔出时自动卸载。适合需要热插拔的场景。我一开始用fstab结果卡没插的时候系统启动卡在mount那一步虽然加了nofail不阻塞启动但每次都要手动挂。后来改用udev规则KERNELmmcblk1p1, SUBSYSTEMblock, ACTIONadd, RUN/bin/mount /dev/mmcblk1p1 /mnt/sdcard KERNELmmcblk1p1, SUBSYSTEMblock, ACTIONremove, RUN/bin/umount /mnt/sdcard这里有个细节RUN里的命令要尽量简单udev环境里很多路径和变量和正常shell不一样。复杂逻辑建议写个脚本udev只负责调用脚本。4.2 文件系统选择exFAT、ext4还是FAT32SD卡用什么文件系统取决于用途FAT32兼容性最好Windows/Linux/相机都能读但单文件不能超过4GB。exFAT支持大文件跨平台好但Linux下需要额外驱动内核5.4原生支持较好。ext4Linux下性能和可靠性最好支持权限、日志但Windows不认。我做数据记录用ext4因为要频繁写入小文件ext4的日志和延迟分配能减少碎片。但要注意ext4默认的commit间隔是5秒突然断电可能丢最近几秒数据。对可靠性要求高的场景可以调小commit或者用sync挂载性能会降。4.3 性能调优SD卡在嵌入式Linux下的读写瓶颈SD卡的读写性能受几个因素影响总线宽度1bit/4bit、时钟频率、文件系统、挂载选项。RK3576的SDMMC支持4bit和50MHz理论带宽25MB/s左右实际受卡本身限制。我用dd测过# 写测试 dd if/dev/zero of/mnt/sdcard/test.bin bs1M count100 convfsync # 读测试 dd if/mnt/sdcard/test.bin of/dev/null bs1M实测写入约18MB/s读取约22MB/s对于Class10的卡算正常。如果明显偏低检查总线宽度是不是4bitcat /sys/kernel/debug/mmc1/ios看bus width。时钟是不是50MHz。挂载选项有没有加noatime减少元数据写入。4.4 热插拔拔出时正在写入怎么办热插拔最怕的是拔出瞬间还有数据在写轻则文件损坏重则文件系统崩溃。Linux的块设备层有缓存umount会先刷缓存再卸载。但用户直接拔卡缓存没刷就断了。缓解办法挂载时用sync选项每次写都同步性能差但安全。应用层定期sync比如数据记录程序每写一批就调一次。用fsck在挂载前检查ext4可以配errorsremount-ro出错时只读挂载避免扩散。我现在的做法是数据记录程序每5秒fsync一次配合ext4的日志即使直接拔卡最多丢5秒数据文件系统不会崩。5. 那些文档不会写的实操心得与避坑清单踩完这一圈我把RK3576上SD卡相关的经验整理成几条都是文档里不会明说、但实际会卡住你的点。5.1 先量电平再改代码硬件确认永远排第一我最大的教训就是一开始没量CD脚电平直接改dts来回折腾了好几轮。后来养成习惯任何和GPIO、电平相关的功能先拿万用表量确认硬件行为再动软件。这一条能省掉至少一半的无效调试时间。5.2 设备树改动后确认真的生效了dts改完编译进dtb但有时候你改的节点没被板级dts覆盖或者编译产物没更新。验证方法# 看运行时设备树里sdmmc节点的实际内容 ls /proc/device-tree/ | grep mmc cat /proc/device-tree/mmc.../cd-gpios如果/proc/device-tree里没有你加的属性说明dtb没生效检查编译和烧录流程。5.3 保留一份最小可用配置作为对照调试时我习惯保留一份确认能工作的最小dts配置出问题时切回去对比。这样能快速判断是新改的参数引入的问题还是环境本身的问题。SD卡这块最小配置就是status okay加正确的cd-gpios和pinctrl其他先不加。5.4 注意内核版本差异RK3576的支持在持续更新RK3576是比较新的平台不同内核版本比如5.10、6.1对它的SDMMC驱动支持程度不一样。我用的6.1内核某些早期版本里SDMMC的CD中断处理有bug升级到较新的小版本后问题消失。如果遇到诡异行为先确认内核版本必要时看Rockchip的官方补丁或社区提交。5.5 热插拔测试要覆盖拔出时正在写的极端场景很多人测热插拔就是插进去、读一下、拔出来这测不出问题。真正要测的是正在dd写入时直接拔卡看文件系统是否损坏、重新插入后能否正常挂载。这个测试能暴露缓存、日志、错误处理的问题。我第一次测就把一个ext4分区搞成了需要fsck修复的状态后来加了fsync才稳。5.6 供电不足的表现往往伪装成信号问题SD卡瞬时电流可能到100mA以上如果板子供电设计余量不足插卡瞬间电压跌落表现可能是枚举超时、CRC错误看起来像信号问题实际是电源问题。用示波器看SD卡供电脚在插卡瞬间的波形如果有明显跌落先解决供电。6. 写在最后嵌入式调试的耐心比技巧更重要RK3576这块板子整体素质不错接口丰富、性能也够但新平台总会有些细节需要自己趟。SD卡这个事看起来小却把硬件、设备树、驱动、文件系统、应用层串了一遍是个很好的练手案例。我现在回头看最大的收获不是解决了某个具体bug而是建立了一套排查顺序先确认硬件电平再看设备树是否生效然后dmesg定位阶段debugfs看细节最后示波器确认信号。这个顺序能覆盖大部分外设不工作的问题不只是SD卡。如果你也在RK3576或者类似平台上折腾SD卡建议从CD检测这个点切入把整条链路走通一遍。走通之后你对嵌入式Linux的存储子系统会有完全不一样的理解。至于那些热词里提到的各种初始化问题本质上都是链路某一环没对齐耐心一层层剥总能找到。
阅读完成 · 觉得有帮助?
咨询建站