先交代一下背景。EBAZ4205这名字听着很工业,其实就是当年比特币矿机上的Zynq-7020控制板,矿难之后大量板子流进二手市场,几十块钱一块,却能凑出XC7Z020、512MB DDR3和一颗并行NAND Flash的配置,于是被不少人拿来当穷人版Zynq开发板。但多数人第一次上电就卡住了:这块板默认从NAND启动,里面装的是矿机原厂固件,既不会给你Linux,也不会给你FPGA工程,最多在串口里吐一串莫名其妙的字符。想从NAND启动切到JTAG模式,表面看只是改个启动选择,实际牵扯到MIO引脚电平、BootROM的决策逻辑、JTAG线缆的状态检测,还有后续烧写NAND时的DDR初始化问题,每一步都有坑。
这篇文章把我实际走过的路完整理一遍:怎么确认和修改EBAZ4205的启动模式,怎么让JTAG成功连上,怎么通过JTAG把固件写回NAND,又怎么验证板子真的能从NAND自举。下文按这个顺序操作,大部分我在草稿里遇到的坑你都不用再踩。
1. 这块矿板的来路与NAND启动的设定
1.1 硬件底子:便宜大碗的Zynq开发平台
EBAZ4205本身是矿机上的控制板,硬件选型相当“大方”。搞清楚它有多少东西,你后面做任何决策都有底气。
| 组件 | 常见配置 | 说明 |
|---|---|---|
| SoC | Xilinx Zynq XC7Z020-1CLG400I | 双核Cortex-A9 + PL,PL接近Artix-7级别 |
| DDR3 | 512MB | 颗粒型号随批次有差异,板载焊接 |
| NAND | 并行SLC NAND,常见256MB档 | 原厂启动介质,具体型号以板面丝印为准 |
| 以太网 | 千兆PHY | 矿机里的主要通信口 |
| 调试接口 | USB转串口 | 只做串口,不要指望它给整板供电 |
| 主供电 | 12V | 必须外部供电,USB带不动整板 |
XC7Z020放在正儿八经的开发板上至少要上千,这块矿板只要几十上百,所以圈子里的玩法是把它的原厂逻辑清掉,自己重新做启动链。价位决定容错率低,坏了不心疼,非常适合练手。
1.2 原厂NAND里到底是什么
矿机固件走的是Zynq典型启动链:BootROM -> FSBL -> U-Boot -> 矿机App,后两者都塞在NAND里。对玩板子的人来说,原厂App基本是无用数据,但我不建议一上来就整片erase。NAND里可能存有网口MAC、量产校准信息、原厂U-Boot环境变量,万一你以后想把它恢复成原矿机出手或者对照原厂行为,备份比后悔管用。
先用后面提到的JTAG或者U-Boot手段把整片NAND读出来存成文件,扔硬盘里吃灰就好。这一步花不了多少时间,但能让你后续操作心态完全不同。
1.3 为什么非要JTAG模式
JTAG对Zynq来说是“上帝模式”:可以绕过NAND、SD、QSPI这几个常规启动源,不管里面固件好坏,都能拿到芯片控制权。你可以通过JTAG加载FPGA bitstream、单步调试ARM核、烧写各种Flash,也可以在看门狗乱跳之前强制把系统停住。
对一块来路不明的矿板,JTAG是你验证硬件完好的第一工具,也是从零构建启动链的起点。很多人跳过了启动模式这一步,直接在Vivado Hardware Manager里反复刷新,永远看不到设备。原因很简单:板子还停在NAND boot状态,BootROM上电后立刻执行脏固件,ARM核早就跑飞了,调试器根本halt不住。
2. 启动模式不是软件菜单:MIO引脚上的硬逻辑
2.1 上电瞬间的决定权在BootROM
Zynq一上电,最先执行的不是NAND里的U-Boot,也不是SDK里的FSBL,而是芯片内部固化的BootROM。BootROM要决定第一件事就是“我从哪里取第一段可执行代码”。它不看配置文件,直接读取MIO[2:4]三个引脚的电平状态,这就是所谓的strap pin,对应关系大致如下:
| MIO[4:2] 电平 | 启动源 | 典型用途 |
|---|---|---|
| 000 | JTAG | 调试、烧录 |
| 010 | QSPI | SPI NOR Flash启动 |
| 100 | NAND | 并行NAND启动,EBAZ4205默认值 |
| 110 | SD/MMC | TF卡启动 |
当MIO[4:2]为000时,BootROM不尝试从任何非易失介质加载代码,ARM核被保持在一个可以被调试器接管的暂停状态。而EBAZ4205出厂时焊死了NAND启动的组合,也就是MIO4被上拉到高电平,MIO3和MIO2保持低电平。
所以这里要形成一个关键认知:启动模式由板子上的上下拉网络决定,不是Vivado里勾一个选项就能改的。你不动硬件,工具界面里点再多也白搭。
2.2 EBAZ4205上如何把NAND改JTAG
EBAZ4205默认NAND=100,具体到引脚就是MIO4=1、MIO3=0、MIO2=0。要改成JTAG=000,核心工作就是把MIO4从高拉低。实际操作时别急着动烙铁,按这个顺序走:
- 先用万用表量MIO4、MIO3、MIO2引脚或相连测试点的电压,确认默认状态。
- 找到MIO4相连的上拉电阻或0欧电阻。不同批次的板子丝印差异很大,别记死某一个编号,一定要以实测导通网络为准。
- 最稳妥的办法是把MIO4的上拉通道断开,或者增加一个下拉电阻。如果想要可复现,就把它引到一支排针上,用跳线帽选择接VCC还是接GND。
- 临时调试时,也可以用杜邦线把MIO4信号强行拉低。前提是原上拉电阻阻值够大,否则相当于对上拉电源短路,不建议长期这么干。
- 改完再量一遍:MIO4=0、MIO3=0、MIO2=0,确认无误再上电。
这里有个很容易混淆的点,值得单独强调:启动模式引脚和JTAG专用引脚是两套东西。JTAG的TCK/TDI/TDO/TMS在芯片上有专用引脚,不是MIO,也不存在“JTAG引脚被复用成GPIO导致连不上”的玩法。所以网上搜到“STM32禁用JTAG”“GD32F4关闭JTAG引脚”之类的文章,在这个场景里是另一码事,别被带偏。Zynq的JTAG调试口始终挂在芯片上,启动模式只是决定BootROM是否让ARM核执行介质代码,跟JTAG引脚本身是否被占用没有关系。
2.3 改成JTAG模式后,NAND固件还在吗
在。MIO strap只是影响BootROM的取指去向,不会擦除NAND内容。你把模式切到JTAG后,原厂固件还是原封不动躺在那里。改回NAND模式,上电它照样跑矿机残留代码。
这个特性请善用:JTAG模式下你随时可以回头查看NAND内容,而不是一开始就必须做“擦掉重来”的抉择。先切JTAG,摸清硬件,备份好原厂数据,再决定要不要覆盖NAND。这个顺序最安全。
3. JTAG接线与死活连不上的排查链路
3.1 线缆和10针座的辨别
EBAZ4205上的JTAG接口一般是2.54mm间距的2x5排针或预留焊盘,包含TCK、TDI、TDO、TMS、GND和VREF。市面上USB-JTAG适配器很多,比如Digilent的JTAG-HS3、Xilinx Platform Cable USB II,还有廉价的FT232H方案,都能接Zynq。
但2x5座的引脚顺序不是全球统一标准,不同线缆的定义可能不同。我第一次就是凭感觉插,结果完全没反应。正确做法是:
- 用万用表蜂鸣档找出GND引脚。
- 对照手头适配器的引脚图,确认TCK、TDI、TDO、TMS四根信号的位置。
- VREF要接板上的3.3V域。很多适配器靠VREF电压判断链路是否建立,VREF不对时指示灯根本不亮。注意VREF只是电平参考,不进主电源,但必须接对。
不要迷信网上某个“标准定义”,因为矿板批次多、座子来源杂,只有实测最可靠。
3.2 只插USB不工作的供电陷阱
EBAZ4205板上的USB接口是给上位机做串口调试用的,带不动整板。只插USB不接12V,Vivado Hardware Manager里当然找不到设备;就算侥幸识别到IDCODE,后续访问DDR、加载FSBL也会因为PS电源域不完全而失败。
正确上电顺序:
- 按正确引脚接好JTAG线。
- 确认12V电源输出正常,再给板上电。
- 打开Vivado Hardware Manager,等它自动Refresh识别。
- 调试过程中需要重启时,先断电等几秒再上电,避免DDR状态在反复热复位中变得不可靠。
如果板子有电源指示灯,亮不代表所有电源轨都正常。用手摸一下DDR、网口附近的稳压节点是否发热,这个方法土,但能最快发现供电链路问题。
3.3 “Could not stop Cortex-M device”的完整排查路径
这个报错很有迷惑性,因为Zynq的ARM明明是Cortex-A9,不是Cortex-M。实际上这是Xilinx工具在访问ARM-DAP调试接口时的通用描述,不用纠结名字。遇到它,按顺序检查:
- 启动模式:万用表再确认MIO[4:2]是不是000。如果还是100,BootROM可能已经从NAND读了一段代码让ARM跑飞,调试器自然halt不住。
- 时钟:Zynq需要PS_CLK输入,EBAZ4205板上有晶振。如果晶振没起振,ARM无法进入可调试状态。
- 供电:确认VREF有3.3V,PS_PLL电源域正常。
- 线序:TDI和TDO方向弄反是常见错误。IDCODE能读到,但回环校验不过时,优先把TDx两根对调。
- 菊花链:如果同一根线缆上还串了其他板子,地址冲突也会导致halt失败。
- 工具版本:太旧的Vivado/Vitis对后期批次板子识别可能有兼容问题,换个新版本试试。
图形界面排查不出来时,用命令行会暴露更多信息。在XSDB里手动走一遍:
connect targets targets -set -filter {name =~ "Cortex-A9*"} rst -system dow fsbl.elf con在Vitis里也可以打开Xilinx XSCT控制台执行。能走到dow这一步,说明JTAG链路已经通了。如果手动下载也失败,那大概率不是JTAG本身的问题,而是FSBL与板载DDR颗粒不匹配,或者FSBL里初始化了错误的DDR时序,进入下一节处理。
4. JTAG不是终点:回写NAND时的DDR与镜像问题
4.1 用Program Flash Image烧NAND的完整操作
JTAG连接成功后,最终目标不是只在RAM里跑,而是把板子恢复成“上电即启动”的完整系统。典型构成是BOOT.BIN,里面按顺序打包了FSBL、bitstream、U-Boot。在Vitis里选择Xilinx -> Program Flash Image,Flash Type选NAND,Image File选BOOT.BIN。
如果没有现成的BOOT.BIN,可以通过BIF文件生成:
the_ROM_image: { [bootloader]fsbl.elf bitstream.bit u-boot.elf }BIF里顺序非常关键:第一段必须是FSBL,中间放PL位流,最后是裸机程序或U-Boot。老版本工具对并行NAND的支持不算好,烧写前先确认Flash Type下拉里真的有NAND选项,而不是只有QSPI/BPI。如果工具不认,优先升级Vivado/Vitis版本,不要在旧工具里跟它硬磕。
4.2 固化NAND时必须用DDR吗:镜像尺寸与工具链逻辑
很多人问“用JTAG固化flash时必须使用DDR吗”,这个问题在这块板子上特别现实。直接说结论:通过SDK/Vitis的Program Flash流程,实际很难绕开DDR。
原因是:SDK会把FSBL和烧写客户端都加载到DDR或者OCM里,FSBL负责初始化DDR,烧写工具再把镜像从DDR拿出去写NAND。这个流程里,“NAND需要DDR”不是硬件强制,而是工具链路径强制。你的BOOT.BIN如果很大,OCM那256KB根本放不下,不初始化DDR整个流程就跑不动。
可以按场景记结论:
| 场景 | 是否需要DDR | 说明 |
|---|---|---|
| 只加载PL bitstream,不写Flash | 不需要 | Vivado直接配置PL |
| 烧写很小的裸机程序 | 工具链通常也会初始化DDR | SDK按既有流程走 |
| 烧写U-Boot/Linux | 必须 | 镜像尺寸和运行都需要DDR |
所以EBAZ4205上做正经启动链,DDR初始化是躲不掉的。它不是“可选优化”,而是整个烧录链路的底座。少数人用XSDB直接操作NAND控制器寄存器,确实可以避开DDR,但那是把Zynq当单片机操作,开发成本高、排错难,不推荐给大多数人。
4.3 烧完不启动:坏块、ECC与Boot Header
NAND不能像NOR那样写完直接执行,BootROM对NAND启动镜像有几个硬要求:
- Boot Header要放在第一个块的有效页内,里面包含镜像偏移、长度、校验等信息。
- BootROM只读前几页,剩下的工作交给FSBL,FSBL带着NAND驱动继续读取。
- SLC NAND通常很皮实,但一样有坏块。擦除全片后,坏块表必须重建,工具和U-Boot要能维护BBT块。
“烧完不启动”的原因按概率排:
- 启动模式还停在JTAG:MIO[4:2]仍是000,板子当然不会自动从NAND取代码。
- BOOT.BIN里FSBL不认板载NAND芯片型号,卡在NAND读取阶段。
- BIF打包顺序或地址错误,缺少bootloader标记。
- 烧写过程中供电掉电,NAND写入不完整。
- 镜像写到了坏块上,而BootROM访问的正好是坏块。
排查时先看串口打印。如果连FSBL打印都没有,说明BootROM没找到合法header;如果FSBL打印后卡住,多半是在初始化DDR或NAND控制器。
5. 用nand read命令确认板子真的活了
5.1 U-Boot下的nand系列命令
无论你通过JTAG烧进了U-Boot,还是后面改用SD卡引导U-Boot,NAND验证最方便的手段就是U-Boot的nand命令。进入Zynq>提示符后,执行:
nand info nand device 0 nand bad nand read 0x20000000 0x0 0x100000 md.b 0x20000000 0x100nand info会列出NAND容量、页大小、块大小,确认FSBL驱动认到了芯片;nand bad查看坏块表;nand read把NAND从偏移0x0开始的一段数据读到DDR地址0x20000000,再用md.b观察内存内容。如果看到的是boot header和后续可执行数据,说明NAND可读;如果全是0xFF或者直接报错,说明要么没识别芯片,要么块已坏,要么写入根本不对。
进一步验证可以用md5sum把读出的数据和原始文件做比对,一致才能说烧写完整。这一步比任何“工具提示Success”都可靠。
5.2 串口log里的启动各阶段
串口是EBAZ4205最划算的调试窗口,波特率最常见是115200。不同启动阶段在log里的特征如下:
| 启动阶段 | 典型log | 含义 |
|---|---|---|
| FSBL | Xilinx Zynq FSBL | FSBL已运行,DDR初始化开始 |
| U-Boot | U-Boot 2020.xx ... | U-Boot开始执行 |
| 内核 | Starting kernel ... | Linux或RTOS接管 |
从NAND启动全程会有FSBL/U-Boot的打印。如果卡在“Xilinx Zynq FSBL”,问题多半在DDR初始化或bitstream加载;如果U-Boot打印出来了,但autoboot后死掉,就去看它停在哪条命令上,是读NAND分区还是加载dtb。这种看图说话的方式,能很快把问题定位到具体阶段。
5.3 切回NAND启动的最终检查
确认NAND内容没问题后,把MIO[4:2]从000改回100,让板子恢复NAND boot。改法就是前面步骤的逆操作:MIO4恢复上拉,MIO3/MIO2保持低电平。
别改完忘记复位,直接上电看串口。如果能看到完整的FSBL到U-Boot的启动log,才说明最终链路是通的。如果用排针做切换,这一步只需要拨一下跳线帽,这也是我一直建议用“排针+跳线帽”而不是直接焊死电阻的原因。断电、改跳线、上电、看串口,这个顺序干净利落。
6. 不烧NAND的玩法,以及一个值得做的小改造
6.1 JTAG模式下只加载PL位流
如果你现在还只做PL逻辑验证,完全不用碰NAND。把启动模式拨到JTAG,打开Hardware Manager,Program Device选一个bitstream。此时PL被配置,PS端不动,DDR也不用初始化。以这块板子的PL资源,跑软核、做HDMI输出、扩展GPIO、写各种外设,都能在PL里完成。
这种状态最舒服的地方是不损坏任何Flash。烧写错了重新加载一个bitstream就行,板子怎么折腾都不会坏。所以对纯FPGA玩家来说,JTAG模式可以一直是默认留驻状态。
6.2 关于Verilog直接读写NAND的一个纠偏
有个高频搜索词是“verilog实现nand flash读写”,很多人看到板载NAND就想用Verilog写个控制器直接拉时序。但EBAZ4205的这颗并行NAND挂在PS侧的NAND控制器地址空间,不是PL的普通IO口,Verilog很难直接看到这组引脚。
如果你想练Verilog读写Flash,更现实的做法是在PL上外扩一颗SPI NOR或SPI NAND,用标准SPI接口自己写控制器;或者通过AXI总线访问PS的NAND控制器,让PS侧先把数据准备好,PL再通过总线读写。前者是标准外设练习,后者是异构SoC架构的典型玩法。不要一上来就对着板载NAND写HDL时序,光是MIO约束和总线访问顺序就够你消磨大量时间。
6.3 给MIO strap做一个可切换的排针开关
综合前面所有操作,我最推荐的改造不是纠结MIO4那颗电阻,而是把MIO2、MIO3、MIO4各引出一根排针,用跳线帽按组合接地或接电源。这样随时可以在JTAG、NAND、SD、QSPI几种模式间切换,调试和固化互不干扰。
组合状态贴一张小纸条到板子上:
| 跳线组合 | 模式 | 用途 |
|---|---|---|
| 000 | JTAG | 调试、烧录 |
| 100 | NAND | 恢复正常启动 |
插拔跳线前先断电,改完再上电。这个习惯至少能省掉一半“怎么又连不上”的暴躁时刻。
最后再分享一条我实际体会很深的经验:烧写工具提示Success,只说明数据写到了NAND,不说明BootROM愿意认它。启动模式没改对、BIF顺序错了、FSBL驱动不认NAND颗粒,任何一个问题都能让“成功”变成“变砖”。所以完整链路一定要验证到位:MIO电平测量、JTAG连接、nand read回读比对、串口log出现U-Boot,环环相扣。从NAND启动切到JTAG,再安全地切回NAND启动,整个过程能用一套可靠的验证方法闭环,这块矿板才算真正变成你说了算的开发板。