
我调过一块双存储方案的ZYNQ板卡SD卡座和eMMC都挂在PS侧SD卡在3.3V电平下跑得没什么问题eMMC的VCCQ是1.8V结果同样的SDIO接口一个正常一个罢工。后来在社区里翻帖子类似问题反复出现核心都指向同一个矛盾——3.3V与1.8V电压之争。ZYNQ双存储方案里SD/eMMC的电气兼容性从来不是靠改寄存器解决的它涉及SD规范的电平切换机制、eMMC的VCCQ供电体系、Zynq MIO Bank的固定电平域约束以及电平转换芯片的选型与时序配合。这篇内容把我调板过程中的积累整理成六个部分先是SD和eMMC电压规范差异再讲Zynq MIO Bank的电气约束然后是三种常用的电气拓扑方案接着是电平转换芯片选择再到协议与驱动的配合最后用三个真实案例说排查方法。适合正在做ZynqSD/eMMC方案的硬件工程师和嵌入式工程师也适合刚入门Zynq的开发者按图索骥。1. 为什么SD卡和eMMC会在ZYNQ上“打架”电压规范差异1.1 SD卡的“双面人生”3.3V是入场券1.8V才是高速入场券SD卡的电压设计并不像很多人想的那样“一直就是3.3V”。SD 1.0和SD 2.0时代信号电压固定为3.3V主机初始化时必须用3.3V与卡通信。到了SD 3.0规范引入了UHS-I模式为了把时钟推到SDR104的208MHz信号压摆率和功耗必须降下来于是规范规定UHS-I模式下信号电平从3.3V切到1.8V。关键点在于SD卡不是上电就用1.8V。开机后主机先以3.3V和卡建立联系通过CMD0、CMD8、ACMD41确认双方都支持1.8V切换然后主机发出CMD11卡在毫秒级窗口内把接口电平切到1.8V。这意味着主机接口本身必须支持电平的动态变化或者外电路要有一套能够跟着切换的机制。很多开发板为了省事把Zynq的SDIO接口固定在3.3V电平SD卡就只能运行在默认速度或高速模式UHS-I能力被白白浪费。反过来如果为了eMMC把MIO Bank固定在1.8VSD卡槽就必须外接电平转换而且转换电路还要处理初始化阶段的3.3V通信复杂度立刻上来了。1.2 eMMC的“出厂定终身”VCC与VCCQ两套电源eMMC是焊接在板上的芯片不需要像SD卡那样兼顾热插拔和多品牌兼容性。它的供电分成两路VCC给核心和存储阵列供电一般固定3.3VVCCQ给I/O接口供电可以是1.8V或3.3V在硬件设计时一次性定死。eMMC的信号电平从设计定稿那一刻起就不再变化它没有SD卡那种CMD11切换机制主机必须用自己的I/O电平去匹配VCCQ。eMMC 5.1规范里的HS400模式要求1.8V的VCCQ所以现在绝大多数新设计直接把VCCQ做1.8V信号电平也定在1.8V。从引脚定义看eMMC封装里除了CLK、CMD、DAT0-7、RST_n就是VCC、VCCQ、VDDi这些电源脚。153Ball、169Ball等封装都遵循JEDEC标准VCCQ引脚数量不少就是在提醒你它在整个IO域里扮演方向盘的角色。1.3 冲突的本质一条SDIO总线只能有一个信号电平SD卡座按3.3V设计eMMC按1.8V设计两个器件如果挂到同一条SDIO总线上信号电平必须先统一。有人觉得推挽输出直接连问题不大实际上一高一低两个电源域会在IO钳位二极管上形成持续灌电流轻则高电平被拉低重则直接烧引脚。更隐蔽的是上拉电阻。SDIO规范要求CMD和DAT线在空闲时保持高电平通常需要10kΩ到100kΩ上拉。如果上拉电阻接到3.3V而eMMC的IO域是1.8V那么通过eMMC内部的ESD保护二极管3.3V会倒灌到1.8V电源电流虽然不大但会在初始化时把总线高电平钳在不正常位置命令响应超时就这样出现了。所以第一步设计原则很明确先把每个设备的电压域列清楚再决定总线拓扑和上拉策略。下面展开Zynq侧的约束。2. Zynq MIO Bank的电气约束VCCIO一锤定音2.1 SDIO控制器在MIO上的Bank归属Zynq-7000 PS侧有两个SDIO控制器。SDIO0占用MIO 40到45位于MIO Bank 2SDIO1占用MIO 46到51位于MIO Bank 3。每个Bank的IO电平由对应的VCCIO_MIOx电源引脚决定外部供多少伏这个Bank上所有MIO引脚就是多少伏运行中不能改。举个例子如果SDIO0所在的Bank 2供电3.3VSDIO0所有信号就是3.3V电平如果供电1.8V信号就是1.8V电平。这个选择必须在原理图阶段定好软件只能被动适配不能动态切换。SDIO接口的CD和WP信号还要单独留意。Zynq的SDIO0 CD/WP可以映射到MIO 8/9等其它Bank如果它们和SDIO0不在同一个Bank上拉和检测电路要单独处理不能想当然跟着SDIO0的电平走。2.2 双存储方案的两种连接拓扑Zynq有两路SDIO控制器最常见做法是SDIO0接SD卡SDIO1接eMMC。这样两个Bank的电平可以独立设置比如Bank 2供电3.3V给SD卡Bank 3供电1.8V给eMMC电气上互不干扰。代价是MIO引脚消耗多并且两个Bank的VCCIO如果电压不同电源设计上就要多一路稳压和对应滤波。另一种做法是SD和eMMC共用一条SDIO总线。这里要泼一盆冷水SDIO协议本身没有片选线两个设备同时挂在总线上必然冲突。所谓的共用只是通过电源开关、复位信号或总线开关在物理上隔离同一时刻只让一个设备在线。这种拓扑省MIO但电路复杂还引入了电平转换需求只有MIO确实紧张时我才建议考虑。2.3 启动模式与存储角色的电压需求Zynq的Boot Mode引脚决定启动源。很多人让系统从QSPI Flash启动SD卡和eMMC都只是运行时的存储设备也有设计直接把启动镜像放在SD卡或eMMC上。启动链路对电压稳定性更敏感因为FSBL和U-Boot要跑在DDR里而DDR初始化前CPU只能执行片上ROM代码任何IO域电源异常都会导致启动卡死。从硬件设计角度看eMMC如果做启动盘VCCQ电平必须和对应MIO Bank的VCCIO匹配否则BootROM在枚举启动设备时就会失败。SD卡同理卡座上拉、时钟上拉都要符合所选Bank的电平。我见过板卡上SD卡单独能启动eMMC启动却失败最后发现Bank 3的VCCIO设计成1.8V而eMMC的VCCQ被一颗电阻网络拉到了3.3V附近两边完全不在一个频道上。3. 三种电气拓扑方案分离、共线转换与动态电源切换3.1 方案A双控制器分离最稳的“土办法”如果你对板面积和成本不太敏感双控制器分离是最省心的方案。SDIO0接SD卡Bank 2 VCCIO设为3.3VSDIO1接eMMCBank 3 VCCIO设为1.8V。两个存储各走各的总线协议栈互不干扰SD卡不需要为eMMC让路eMMC也不用迁就SD卡的3.3V初始化流程。这个方案的优点是调试简单SD卡出问题查SDIO0的电路eMMC出问题查SDIO1不存在共总线时那种“互相拉扯”。缺点是MIO占用多如果板上还要接UART、USB、以太网、QSPIMIO可能告急。另外两个Bank的VCCIO要分别供电电源轨数量增加布局布线要留够空间。3.2 方案B共线加双向电平转换省MIO但考验电路如果MIO实在不够让SD和eMMC走同一条SDIO总线必须加双向电平转换芯片。典型连接是Zynq侧MIO Bank固定在1.8V电平转换芯片低压侧VCCA接1.8V高压侧VCCB接3.3V连SD卡槽eMMC如果VCCQ是1.8V就挂在低压侧总线上。这样Zynq、eMMC都在1.8V域SD卡槽独立在3.3V域通过转换芯片桥接。注意这里SD卡和eMMC同一时刻只能激活一个访问SD时让eMMC的时钟保持低电平或把复位拉低访问eMMC时通过负载开关断开SD卡槽的电源。如果两个设备都一直在线CMD和DAT线的推挽驱动会在总线上打架枚举必然出错。这个方案的坑在于SD卡初始化阶段以3.3V信号通信Zynq侧1.8V的MIO通过转换芯片可以和SD卡握手但SD卡切换1.8V信号模式时主机IO域也要同步切换到1.8V此时电平转换芯片的高压侧VCCB若还接着3.3VSD卡侧高电平就会变成3.3V和后续的1.8V时序对不上。所以方案B实践上只能做到SD 2.0不支持UHS-I的1.8V动态切换。想做完整SD 3.0请看方案C。3.3 方案C共线加动态电源切换追求完整SD 3.0能力要保留SD卡UHS-I功能同时挂eMMC电路上要动真格。核心思路是让电平转换芯片的高压侧电源VCCB可切换初始化时VCCB3.3VSD卡按3.3V通信CMD11切换时主机用GPIO控制负载开关把VCCB从3.3V切到1.8V同时SD卡槽侧信号电平也降到1.8V完成双端同步。这个方案需要增加的硬件包括负载开关或可切换稳压电路响应时间要小于SD规范的切换窗口控制信号最好来自Zynq的一个MIO GPIO但Linux内核标准驱动不会自动帮你完成这个联动通常要基于pinctrl或regulator框架做定制或者干脆在裸机代码里直接控制。电平转换芯片也要能接受VCCB在运行中快速切换并且切换过程不能往数据线上吐毛刺。代价是电路复杂度和成本都上去了。如果项目不需要SD卡跑UHS-I我个人不建议上方案C很多量产板卡最终都停在方案A或方案B。4. 电平转换芯片选型速率、方向和控制逻辑缺一不可4.1 双向转换芯片的横向对比SDIO总线是双向、推挽、有时钟的并行信号电平转换芯片不是随便拿一颗就能用。下面这个表是我常用的几款芯片对照芯片位数方向控制典型速率适合场景TXS0108E8自动约110Mbps推挽SDIO 2.0高速模式、通用IO电平转换TXB01088自动约100Mbps但受负载影响低速信号、纯逻辑电平匹配SN74AVC4T2454×2DIR引脚数百Mbps级高速单向或可控方向总线SN74LVC2T452DIR引脚数百Mbps级时钟等单向信号、少量信号转换从SDIO速率看默认速度25MHz、高速模式50MHz、SDR50是100MHz、DDR50还是50MHz、SDR104则到208MHz。TXS0108E应付默认、高速、SDR50问题不大但SDR104这种200MHz档位不建议贸然上自动方向芯片。SN74AVC4T245速率够却需要DIR方向控制信号而SDIO主控制器通常不会单独拉出方向引脚工程上只能额外用逻辑电路判断总线方向复杂度会明显增加。4.2 自动方向与方向控制的取舍我的实践做法是CLK线是Zynq到卡的单向输出可以用SN74LVC2T45这类方向控制芯片固定方向CMD和DAT线是双向用TXS0108E自动方向更省事。混合使用要注意所有转换芯片的电源域必须一致而且4条DAT线的处理方式要保持一致不能有的走自动方向、有的走方向控制否则总线空闲态和turn-around时机会乱。还有一颗经常被低估的芯片是总线开关比如SN74CB3Q。它本质是模拟开关不做电平转换但可以做1.8V域和3.3V域之间的隔离。如果你采用方案B用总线开关把eMMC从总线上隔离出去再用一个电平转换芯片专门服务SD卡槽逻辑会清楚很多。缺点是总线开关有导通电阻和寄生电容高速下信号质量会下降。4.3 上拉电阻、退耦与ESD细节里藏着稳定性的另一半SDIO电路的上拉电阻到底接哪个电源域是识别失败案例的头号根源。原则只有一条上拉电阻的电源必须与它作用的那段总线电平一致。SD卡槽3.3V域的上拉接3.3VeMMC 1.8V域的上拉接1.8V经过电平转换芯片后高压侧上拉接VCCB低压侧上拉接VCCA不要跨域。电平转换芯片的VCCA和VCCB电源引脚必须加0.1uF高频退耦电容尽量靠近引脚放置。SD卡座从外部引入的静电和浪涌需要加TVS管到地TVS的结电容也要注意太大就会拖慢高速边沿。eMMC是板载芯片数据线上通常不需要放TVS但电源脚上的去耦不能省。还有一点容易被忽略SD卡座的CD引脚通常要上拉如果它连接到Zynq的MIO或GPIO上拉电源必须和那个IO的电压域一致。之前见过有人在CD引脚上拉了10kΩ到3.3V而连接的却是1.8V的Bank引脚结果系统一直检测不到卡插入。5. 协议层面的闭环CMD11、ACMD41与设备树里的电压声明5.1 SD卡1.8V切换的完整时序为什么硬件不支持时驱动会卡死SD卡的1.8V信号切换不是软件一条命令就能搞定它是一套完整握手流程。第一步主机发送CMD0卡进入Idle状态。第二步CMD8携带S18R1告诉卡“我支持1.8V切换”卡通过电压窗口响应。第三步ACMD41携带HCS和S18R1卡在OCR响应中返回S18A1表示卡也支持1.8V。第四步主机发送CMD11卡在响应后1ms窗口内切到1.8V接口电平主机也同步切换。第五步双方重新初始化进入UHS-I模式。如果Zynq MIO Bank固定在3.3V而控制器或驱动却尝试发起CMD11卡切到1.8V后主机IO还在3.3V总线电平必然错乱最常见表现就是ACMD41后无响应日志里出现-110或-95这类超时错误。所以硬件不支持1.8V切换时软件必须主动声明“我不会切”这就是设备树里no-1-8-v存在的意义。5.2 eMMC的初始化与VCCQ的关系eMMC主机复位后发CMD1也就是SEND_OP_COND来握手响应中的OCR字段表示卡支持的电压范围。这个命令的电平完全由VCCQ决定VCCQ是多少主机IO就必须匹配多少。如果Zynq Bank VCCIO是3.3V而eMMC VCCQ是1.8V不经过电平转换CMD1的响应主机根本采不到正确电平后续的CID、CSD更无从谈起。很多工程师把eMMC初始化失败归结为“软件兼容问题”实际大概率是电气层面没对上。养成一个好习惯拿到eMMC板子先用万用表量VCCQ实际电压再对照Zynq对应Bank的VCCIO两者一致才允许直连。这一步花不了两分钟却能省掉后面一整天的排查时间。5.3 设备树、U-Boot与裸机驱动中的电压配置要点Linux下Zynq的SDIO设备树节点有几个属性直接影响电压逻辑。no-1-8-v告诉内核别发起1.8V切换sd-uhs-sdr104只在硬件支持1.8V切换时启用mmc-hs200-1_8v是eMMC跑HS200时的1.8V声明non-removable表示eMMC不可热插拔broken-cd表示卡检测引脚没接或不可用。一个典型的组合是这样sdhci0 { bus-width 4; no-1-8-v; broken-cd; status okay; }; sdhci1 { bus-width 8; mmc-hs200-1_8v; non-removable; status okay; };U-Boot环境下可以用mmc dev 0、mmc info查看设备状态。如果U-Boot能识别、Linux不能优先对比两边对电压切换的默认行为差异。裸机开发用Xilinx SDK时BSP里的SDIO驱动参数也要和硬件电压域保持一致不能只改一处。6. 调试实录三个真实案例与完整排查链路6.1 案例1SD卡偶发识别失败高电平被钳在1.2V现象很随机同一张SD卡第一次上电能进U-Boot复位后却卡在“Card did not respond to voltage select”。用示波器抓CMD线ACMD41阶段的高电平只有1.2V明显不是3.3V逻辑该有的样子。排查链路是这样的先量SD卡座供电VDD3.3V正常。再量上拉电阻发现CMD线的上拉电阻一端接3.3V另一端却和一颗1.8V电源的电容相邻追网络后发现原理图里上拉电阻的电源网络名写错了画成了1.8V。修正网络后把上拉统一接到3.3V问题消失。这个案例说明上拉电源域不等于“看起来应该接到哪儿”必须沿着网络表逐段确认。尤其在SD和eMMC共存的板上人为用1.8V去上拉3.3V总线等于做了个分压器电平怎么都抬不上去。6.2 案例2U-Boot识别eMMC正常Linux下却报-110有一块板U-Boot下执行mmc dev 1能看到eMMC进入Linux后dmesg却出现mmc1: error -110 whilst initialising MMC card。同一颗芯片两个软件环境结果不同问题出在哪我按这个顺序排查先对比U-Boot和Linux的设备树配置U-Boot里eMMC初始化用3.3V电平没走1.8V切换。Linux设备树里配了mmc-hs200-1_8v内核对eMMC执行了1.8V信号切换硬件VCCQ标称也是1.8V理论上该成功。接着用示波器量VCCQ发现上电时只有1.6V纹波很大怀疑供电余量不足。换一颗输出能力更强的LDO并增大输出电容后稳定在1.8VeMMC在Linux下顺利枚举。这里要记住不要只看原理图上的标称软件声明的电压档位和硬件实测电压必须一致。eMMC对VCCQ稳定度的敏感程度比很多人想象中高得多。6.3 案例3“JTAG固化QSPI时必须接DDR”背后的电气逻辑这个热搜问题挺经典为什么JTAG固化Flash时必须接DDR其实不是必须而是固化脚本通常先把镜像加载到DDR再写入QSPIDDR没初始化、供电不稳或者焊接有问题脚本就跑不动。换句话说这不是一个纯软件问题背后是整条电源链路的稳定性。这件事和电压之争的关系在于DDR电源、SDIO电压域、eMMC的VCCQ如果共用同一颗电源芯片纹波会串扰。我遇到过SD卡和eMMC都识别失败的情况最后查出是DDR的VTT电源纹波严重导致系统整体不稳定连带IO时序全乱。排查顺序建议是先看电源纹波再看IO电平最后查软件配置不要一上来就怀疑驱动。我现在做新板卡的双存储方案固定套路是先明确每个存储设备的电压域列成一张表再决定双总线还是共总线共线方案一定把电平转换芯片、上拉电源、负载开关时序都写进原理图评审清单。最后分享一个小技巧调这类问题先拿万用表量关键上拉电阻两端的对地电压再上示波器抓ACMD41波形往往十分钟内就能定位电气故障比反复改驱动有效得多。