这两年折腾存储外设,我最有感触的一点是:做“单卡”的读卡方案满地都是,做“双卡”的也有,但很多双卡读卡器只是把两路卡接到同一个控制器上轮流操作,真要一边读A卡一边写B卡,立刻露馅。CH379M双卡读卡器这套方案不一样,它的核心卖点就写在名字里:“双通道并行”。一个USB口接主机,板子上两路独立的SD/TF卡通道,两个通道各有独立的数据通路,主机端看到的是两个可以同时发命令、同时传数据的块设备,而不是一个在两个卡位之间来回切换的单通道设备。
这套方案能干什么?最常见的场景是批量产测:一个工位同时烧录两张卡;数据迁移:把旧卡的数据直接搬进新卡,不必先缓存到硬盘;还有双卡互备、内容比对这类必须同时操作两张卡的活。硬件工程师、嵌入式开发、产测设备开发人员都可以拿它当参考;如果你正打算把整套读卡器方案从进口芯片迁到国产方案,CH379M也是一个值得摆上台面认真对比的样本。
1. 方案思路与选型拆解
1.1 双通道并行到底解决什么问题
先想清楚一件事:USB读卡器本质上是一个“块设备网关”,主机通过USB Bulk传输发SCSI命令,读卡器芯片把SCSI命令翻译成SD卡协议操作。单通道方案的流程是:主机想读A卡,控制器就先操作A卡;主机想读B卡,控制器就切到B卡。切换本身有开销,更麻烦的是两卡之间共享同一个控制器状态机,遇到长命令(比如卡内部做垃圾回收)时,另一张卡只能干等。
双通道并行解决的不是“两张卡同时满速”这种理想情况,而是“一张卡忙的时候另一张卡不用等我”。A卡在写大数据块,B卡的读命令可以走另一条通道独立完成。实际使用中最直观的收益是:从A卡读镜像、往B卡写镜像,两个方向的数据流同时在走,不会出现“读一会儿、停一下、写一会儿”的锯齿状速度曲线。做产测的人应该都懂,这种停顿在批量流水线上非常讨厌,会显著拉长单工位节拍。
还有一个容易忽略的点:并行通道能显著降低随机小文件操作的延迟。两张卡各自维护队列,互不干扰,主机发一个4K读命令给A卡的同时,可以发一个4K写命令给B卡,两笔操作在设备端是可以同时进行的。单通道方案遇到这种交叉指令流,只能顺序执行,延迟直接翻倍。
1.2 单芯片双通道对比“MCU加Hub”方案的取舍
也有人问我:这东西能不能用MCU加两个普通的读卡器模块自己拼?当然能,我早期也这么干过,但踩完坑之后我劝你谨慎。
方案一:MCU直接接管SD卡协议。SD卡有完整的命令集、状态机和初始化时序,SDSC、SDHC、SDXC的模式判断,UHS-I模式下高达104MHz的时钟,还要处理热插拔、写保护、电压切换。这些代码全部自己写,调试周期轻松以周为单位。就算写好了,普通MCU的DMA带宽和内存带宽也是瓶颈,很难跑到UHS-I的速率,最终做出来可能还不如一颗成熟读卡器芯片。
方案二:USB Hub外接两个独立读卡器芯片。功能上确实实现了“双读卡器”,但你要在板子上放两颗芯片加一颗Hub芯片,还要处理Hub的电源分配、过流保护、拓扑枚举,物料成本、PCB面积、出问题时的排查难度都上去了。更难受的是,两颗芯片如果固件版本不一致,Windows下枚举顺序一变,盘符可能来回跳,产测脚本就乱了。
CH379M这类单芯片双通道方案的逻辑很简单:把两个通道的控制逻辑、DMA、时钟管理、电源管理放进同一颗芯片,对外只暴露一个USB Device接口。驱动层面只需要枚举一次,系统看到的就是一个包含两个LUN的复合存储设备。板子设计也简单,电源域更集中,调试时只需要盯一颗芯片的状态。
1.3 国产芯片迁移需要看哪些点
从进口方案往国产方案迁,千万不要抱着“引脚对引脚、寄存器对寄存器”的幻想。芯片不可能完全一样,真正核心的迁移点是下面这几个。
第一,USB描述符和设备类型。CH379M走的是标准Mass Storage类,主机端不需要额外装驱动,这一点很关键。如果某方案用了厂商私有类或私有BOT变种,迁移到国产芯片后,要么改驱动,要么改应用层枚举逻辑。我在项目里吃过亏,上一版方案用了私有SCSI指令做加密卡格式化,换芯片直接废掉一半工具链。
第二,LUN数量的呈现方式。双卡方案必须确认芯片把两路卡表述成同一设备下的两个LUN,还是各自独立的设备。操作系统对这两种方式的处理完全不同。前者在设备管理器里是一个设备带两个盘符,后者是两个设备各带一个盘符。别小看这个区别,你的批量脚本、盘符映射逻辑、自动挂载规则全都会受影响。
第三,量产配置工具的兼容性。进口方案一般有成熟的量产工具,可以设置VID/PID、序列号、写保护位等。换芯片后要看新的工具有没有同等能力,特别是序列号生成规则和批量烧录脚本的接口。这一点在产测场景里比芯片本身性能还重要。
2. 核心细节解析与硬件实操要点
2.1 硬件连接与电源设计
CH379M最小系统不算复杂,但有几个地方值得单独拎出来说。芯片供电一般走3.3V核心和USB VBUS两路,具体以手册为准。我的习惯是USB VBUS进来后先放一个ESD保护器件,再做限流,然后进DC-DC或LDO转3.3V。读卡器这种设备经常热插拔,瞬态电流很大,电源设计不能抠门。
两路卡座建议用自弹式卡座,比翻盖式更耐操,产测工位上一天几百次插拔,翻盖式容易塑料疲劳。卡座的CD(Card Detect)引脚一定要接,并配上合适的上拉电阻。CD信号在双通道方案里很有用:芯片靠它判断卡有没有到位,从而决定LUN是否上线。如果CD不接或者电平钳死,系统里可能长期挂着一个“空盘符”,高级格式化时报错能把你心态搞崩。
SD信号线包括CLK、CMD、D0-D3等,总线频率在UHS-I模式下上百兆赫兹,PCB布线不能再当普通低速信号来画。CLK和CMD、数据线尽量等长,走线距离控制在合理范围,参考地要连续。卡座远离大电感、开关电源这类噪声源。另外SD卡插座属于用户可直接接触的接口,每一根对外信号线都建议加TVS管或ESD阵列,这个钱不能省,修一台返修设备的成本足够买几百颗防护器件。
去耦电容按常规来:芯片电源引脚放100nF加10uF,VBUS入口放一个大一点的电解电容或钽电容吸收热插拔冲击。我见过有人省掉卡供电电容,结果写入大文件时UHS-I模式掉速度,实际上是卡供电在写入瞬间被拉低,卡主动降速保护。
2.2 卡协议支持与速率模型的正确理解
双通道方案对卡的支持基本覆盖SDSC、SDHC、SDXC,模式能到UHS-I,具体以芯片数据手册为准。SDR50、SDR104这类模式下的卡速,是很多人在意的东西,但我要泼一盆冷水:USB端和SD端是两条完全不同的带宽链路。
USB 2.0 High-Speed的理论速率是480Mbps,刨去协议开销,实际Bulk传输能跑到30到40MB/s已经算不错。UHS-I SDR104的SD总线速率是104MB/s,单卡满速都吃不满USB这头。所以双通道并行的真实带宽模型是:两张卡各自的分时占用叠加,受限于USB单通道的峰值吞吐。
那“并行”的意义在哪?在于时延,而不是聚合带宽的翻倍。比如一张卡在向芯片内部缓冲灌数据时,另一张卡的DMA可以在间隙期把上一批数据搬到USB端点;真正让整体吞吐受益的是交错效率。实测里,一读一写这种非对称操作提升最明显,总吞吐能拉得很高,因为读和写两个大方向天然可以流水。而双卡同向持续读写时,总带宽终究会被USB卡住。
所以做产品宣传或者写验收报告时,别指望效率翻倍,更准确的说法是“消除通道互斥带来的等待,提升非对称操作的并发效率”。把预期放正,后面调参心里才有底。
2.3 USB枚举、LUN与操作系统的真实视角
接上电脑后,CH379M在主机侧表现为一个USB复合设备,内部两个LUN分别映射两路SD卡。Windows下磁盘管理里会出现两个可移动磁盘,Linux下出现两个SD设备节点,例如/dev/sdb和/dev/sdc。
这里的“在线/离线”行为和物理插卡状态绑定:插入一张卡,对应LUN上线;拔出后LUN下线。如果你的系统没有正确下发“介质移除”事件,盘符可能残留,这时候多半是CD检测没做好或者固件里热插拔处理没开。
还有一个使用习惯问题:主机端不要把两个LUN同时mount成同一个文件系统后做并发文件操作。块设备层面双通道是独立的,但文件系统层的缓存同步是另一码事。跨卡拷贝文件,我的建议是用块设备级别工具,或者干脆按“源卡挂载、目标卡不挂载”的方式处理,直接操作/dev节点,既绕开缓存一致性问题,速度也更快。
顺带一提传输协议。CH379M这类芯片基本走BOT(Bulk-Only Transport),不是UAS。BOT协议下每个时刻只允许一个命令在传输,但注意,这是指“USB总线上同一时刻只有一个BOT命令流”。芯片内部通过DMA交错执行两张卡的实际数据搬运,所以宏观上你仍然感觉两张卡在同时工作。UAS协议虽然支持更深的命令队列,但对USB线缆、主机控制器、系统驱动栈都有额外要求,很多老平台兼容性反而差,量产设备上用BOT反而省心。
3. 完整实操:从焊接调试到并行读写
3.1 搭建最小系统并完成枚举
我这边的搭建步骤基本是固定的,分享给第一次上手的人。
第一步,准备硬件。CH379M芯片或集成模块一片,两个SD/TF卡座,一个USB座,3.3V供电电路,再加上必要的ESD器件和去耦电容。如果只是想先验证功能,可以直接买双卡读卡器模块,省去焊接SD卡座的麻烦。
第二步,焊接和检查。焊完先用万用表量电源对地阻值,确认没有短路;再上电量核心供电,确认电压稳定。一定要先做静态检查再插USB,不然芯片冒烟了都不知道哪一步的问题。
第三步,插入USB线,观察系统日志。Linux下直接dmesg,Windows下打开设备管理器。正常情况是枚举出一个大容量存储设备,磁盘管理里出现两个空盘。如果只有一个盘,优先查CD引脚和卡座弹片,不要急着怀疑芯片坏了。卡座弹片虚焊是这类板子返修率最高的地方。
第四步,格式化并做连通性验证。两张卡都格式化为FAT32或exFAT,各写入一个较大的测试文件,再把文件读回来做校验。能通过这一步,说明硬件链路基本通了。
# Linux下查看枚举结果 lsusb -t # 会看到类似 Mass Storage 设备下挂两个 scsi 节点的结构3.2 双通道并行读写性能实测方法
性能测试不能只看一个盘符的读写,双通道方案一定要做交叉场景对比。我的测试矩阵是四组:单卡读、单卡写、双卡同时读、双卡同时写、以及A卡读B卡写。
Linux下用dd或fio,Windows下用CrystalDiskMark。dd的用法很简单,但注意一定要加oflag和iflag的direct模式,跳过缓存,不然测出来是内存速度。
# 单卡读测速:源卡 dd if=/dev/sdb of=/dev/null bs=4M count=256 iflag=direct # 单卡写测速:目标卡 dd if=/dev/zero of=/dev/sdb bs=4M count=256 oflag=direct # 双卡并发:开两个终端同时执行 # 终端1 dd if=/dev/sdb of=/dev/null bs=4M count=256 iflag=direct # 终端2 dd if=/dev/sdc of=/dev/null bs=4M count=256 iflag=direct # 一读一写:A卡读到B卡 dd if=/dev/sdb of=/dev/sdc bs=4M count=256 iflag=direct oflag=direct conv=fsync我看过的样本板数据大概是这样的(注意这是具体板子、具体卡的实测,不是芯片标称值):
| 测试场景 | 单通道方案实测 | 双通道CH379M实测 |
|---|---|---|
| 单卡读 | 33 MB/s | 33 MB/s |
| 单卡写 | 28 MB/s | 28 MB/s |
| 双卡同时读 | 约33 MB/s(交替处理) | 约36 MB/s(交错调度) |
| A卡读+B卡写 | 约30 MB/s(锯齿严重) | 约33 MB/s且曲线平滑 |
双卡同时读的聚合带宽并没有翻倍,这是正常的,USB 2.0的物理瓶颈在那里。但注意最后一行的“锯齿”问题:单通道方案一读一写时速度忽高忽低,双通道方案明显平稳。对产测来说,稳定吞吐比瞬时峰值更有价值,节拍计算和工时评估都容易做。
3.3 一拖二克隆与批量产测实战
做批量产测时,我最常用的操作是两卡克隆:一张母卡,一张目标卡,把母卡完整镜像到目标卡里。脚本层可以直接用dd做流式拷贝,源卡读出来的数据直接落入目标卡的写入通道。
# 流式克隆:从源卡到目标卡 dd if=/dev/sdb bs=4M iflag=direct | dd of=/dev/sdc bs=4M oflag=direct status=progress conv=fsync双通道方案的优点是这条管道里的水是持续流动的。源卡DMA往USB端点送数据的同时,芯片内部另一通道已经把从主机收到的数据写进目标卡。单通道方案做同样的事,数据流必须“一进一出”地轮流走,管道上要反复倒腾缓冲,一旦缓冲区撑不住就可能丢速。
实战中还要注意两张卡容量可能不一致。克隆前先用lsblk确认容量,目标卡可以比源卡大,但不能小。克隆后如果目标卡比源卡大,剩余空间需要进分区工具里去扩,不能靠dd自动处理。
产测场景里我还会给两张卡分别绑定固定盘符。Windows下可以用盘符管理脚本按卷标或序列号分配,避免反复插拔后盘符错乱。序列号可以通过芯片的量产工具烧进去,另一个通道单独设置规则。这里强调一下:如果你要在产线上量产,务必花时间把序列号管理规则定好,不然返工成本非常高。
4. 常见故障排查与避坑记录
4.1 只识别到一张卡,另一张无反应
遇到最多的问题就是插上两张卡只出来一个盘符。先别怀疑芯片,按下面顺序排查。
第一步,物理接触。自弹式卡座用久了弹片氧化,或者引脚虚焊,CD信号一直没拉低,芯片就认为卡位是空的。用万用表量CD引脚的电平就知道有没有触发。
第二步,单独插卡验证。只插卡A正常出盘,只插卡B也正常出盘,插两张不行,大概率是两路通道的电源或地共用部分有问题,某个通道占据了过大的电流导致另一通道启动失败。这时候量一下卡供电电压在插入瞬间的跌落。
第三步,确认芯片的通道使能配置。有些芯片默认只开一路通道,另一路要通过配置引脚或寄存器打开。自己画板子的时候最容易漏这个,因为我见过不少评估板默认是双LUN全开的,但正式芯片出厂可能走不同配置,买芯片的时候一定确认固件版本。
4.2 双卡并发写盘时出现掉盘或I/O错误
这个坑多见于给两张卡同时做格式化或同时写大文件。现象是写一会儿后某个盘符消失,Windows弹“延迟写入失败”,Linux下dmesg能看到大量reset错误。
核心原因大概率是供电。两张卡在写入峰值时电流叠加,如果卡供电由USB VBUS直接供给,很容易在瞬时被拉低,芯片为了自我保护会终止当前命令,主机端就表现为设备断开。解决方法是卡供电独立稳压,至少预留足够的余量;USB线也要选粗一点的,劣质线内阻大,压降非常明显。
还有一种可能是两张卡本身状态不一致。比如卡A是UHS-I模式,卡B是普通模式,并发命令下发后,芯片在切换两路时序时可能因为卡B响应慢而超时。遇到这种情况,尝试把两路都固定到兼容模式(SDR25或DS模式)测试,如果恢复正常,说明是模式切换和命令超时的问题,需要更新固件或调整主机端队列深度。
4.3 读写速度明显低于预期
速度不达标是读卡器类产品最常见的“软故障”。先把芯片问题排除掉,用基准卡测试。
先测缓冲:单卡单通道只测一路,如果速度正常,说明芯片链路没问题,问题出在双通道并发或卡本身。再换卡:同一张卡在不同读卡器上跑一遍,如果其他读卡器也慢,说明卡已经降速或寿命到了。最后换线:USB线要用短而粗的,电源和信号都在同一根线里,劣质线材会让BOT协议频繁重传,速度直接掉一半。
信号质量方面,如果PCB是自己画的,检查SD_CLK走线有没有过长过细、有没有跨分割。UHS-I模式下信号边缘变差会导致采样错误,卡可能自动降级到低速率模式。用示波器看CLK波形是最直接的,如果没有示波器,用不同卡交叉验证也能大致定位。
还有一个很隐蔽的点:不要同时跑系统自带索引和杀毒软件扫描。Windows在读到新磁盘时会做自动扫描、建立索引,双卡同时插入时,后台任务会占掉大量带宽。测速前先把这些关掉,不然数据很难看。
4.4 国产方案迁移后的兼容性检查清单
迁到CH379M这类国产芯片后,建议按这张表逐项验证,能省掉很多现场问题。
| 验证项 | 检查内容 |
|---|---|
| 枚举兼容 | Windows 7/10/11、Linux、macOS 能否都识别两个LUN |
| 盘符表现 | 两张卡是否稳定分配独立盘符,热插拔后盘符是否错乱 |
| 大文件读写 | Windows下向两张卡同时写入大于4GB文件是否报错 |
| 休眠唤醒 | 系统待机再唤醒后,两个盘符是否还能正常访问 |
| 引导环境 | BIOS/UEFI下能否识别到设备(某些老主板对复合存储设备支持差) |
| 量产工具 | VID/PID、序列号、写保护位是否都能通过配置工具写入 |
| 私有命令 | 原有应用层是否有厂商私有SCSI指令依赖,需不需要适配 |
我实际迁移过一个产测工具,最耗时间的不是读写性能,而是宿主机的环境差异。有的老电脑主板USB控制器实现不规范,复合设备枚举顺序偶尔会乱,导致两张卡盘符互换。这种情况下不要慌,盘符映射逻辑写成“按序列号匹配”而不是“按盘符序号匹配”,就绕过去了。
另外,如果你的应用层原本依赖读卡器芯片的“写保护”功能,迁移后一定要重点验证。写保护位的开启方式每个芯片都不一样,有的靠硬件引脚,有的靠配置寄存器,有的靠量产工具烧写。我在这个点上面栽过跟头,原方案是硬件写保护脚,新方案默认完全不受控,差点把母卡内容冲掉,后来专门做了写保护测试用例才拦住。
5. 应用扩展与个人体会
5.1 这套方案还能往哪些方向扩展
双通道读卡方案的可玩性其实很高,不限于“读卡器”一个形态。比如接入到嵌入式主控,做成一个双卡数据采集节点,两张SD卡轮流写,一张在写数据的时候另一张可以取出带走,适合长时间无人值守的采集场景。再比如结合OTA升级,把固件同时写入主备两卡,提高升级容错。
产测方向如果做大,可以扩展成一拖四、一拖八,就是多个CH379M通过Hub并联,每个节点独立双通道,一个工位同时管理更多卡。这种方案比多台USB读卡器串联更干净,也更容易做脚本化控制。做这种扩展时注意每个节点的供电分离,以及USB Hub的电源预算,别让几十张卡的浪涌电流同时砸到主板上。
5.2 我在实际操作中的几点体会
用这套双通道方案跑了快半年,最大的体会是:双通道的价值要配合真实场景才体现得出来,单看峰值速度很容易误判。如果只是在家插两张卡测个速,你很难感受到它和单通道方案的差别;但一旦放到批量产线、长时间读写、大文件流式传输里,稳定性带来的收益会非常明显。
最后分享一个小技巧:双卡并行时尽量让两张卡的速度等级一致。Channel A是UHS-I U3,Channel B是Class 4,并发写入时总吞吐会被慢卡拖住,而且快的卡不会帮慢的卡分担,最终效果比两张卡都是Class 10更差。我在量产配置里会先把卡按速度等级分档,同档的卡放在同一个工位批次里,整体节拍能稳定很多。
如果你正准备做双卡设备选型,或者手头有进口读卡器方案要迁移,建议先把手里的卡、电脑、应用场景都捋一遍,按本文的验证清单逐项过一遍,再决定方案要不要换。芯片参数再漂亮,最后还是要落到“在你的产线上能不能稳定跑三个月”这件事上。做硬件选型,稳字当头,真的不亏。