1. 为什么需要从JTAG切换到QSPI启动模式
当你拿到一块PYNQ-Z2开发板开始开发时,最常用的方式就是通过JTAG接口下载程序。这种方式简单直接,修改代码后可以快速验证,特别适合开发调试阶段。但JTAG模式有个致命缺点——断电后程序就消失了,每次上电都需要重新下载。
想象一下,你开发了一个智能家居控制器,总不能每次断电重启后都连上电脑重新烧录程序吧?这时候就需要把程序"固化"到板载的QSPI Flash中。QSPI Flash就像电脑的硬盘,断电后数据不会丢失,上电自动加载程序,这才是产品部署的正确打开方式。
JTAG和QSPI两种启动模式的主要区别在于:
- JTAG模式:通过USB线连接电脑,程序临时加载到内存中运行,适合快速迭代开发
- QSPI模式:程序永久存储在Flash芯片中,上电自动加载,适合最终产品部署
我在实际项目中发现,很多开发者卡在模式切换这一步,主要是因为不熟悉Vivado和Vitis工具链的配置细节。下面我就带你完整走一遍从JTAG调试到QSPI固化的全流程。
2. 硬件准备与跳线设置
2.1 认识PYNQ-Z2的启动模式跳线
PYNQ-Z2开发板上有两个关键的跳线帽(J11和J12),它们决定了板子的启动方式。这两个跳线位于板子边缘靠近USB接口的位置,标着"Boot Mode"字样。
不同跳线组合对应的启动模式:
- JTAG模式:J11跳线帽接1-2脚,J12跳线帽接2-3脚
- QSPI模式:J11跳线帽接2-3脚,J12跳线帽接1-2脚
切换模式时有个小技巧:先断电再改跳线,改完再上电。我遇到过不少因为带电操作导致Flash无法识别的情况,都是这个细节没注意。
2.2 检查QSPI Flash硬件连接
PYNQ-Z2板载的是一颗16MB的QSPI Flash芯片(型号通常为N25Q128)。在Vivado中需要确认Zynq核的QSPI接口配置是否正确:
- 打开Block Design
- 双击ZYNQ7 Processing System IP核
- 在Peripheral I/O选项卡中勾选"Quad SPI Flash"
- 确保配置为"Single"模式(PYNQ-Z2只用了一个Flash芯片)
3. Vivado工程配置要点
3.1 使能QSPI外设接口
很多新手容易漏掉这个关键步骤。在Vivado中配置Zynq核时,除了勾选QSPI外设,还需要注意时钟配置:
- 在Clock Configuration选项卡中
- 找到"Low Speed Peripheral"时钟域
- 确保QSPI时钟使能(通常设为100MHz)
- 保存配置并生成输出产品
3.2 生成正确的比特流文件
生成比特流文件时有个坑要注意:必须包含FSBL(First Stage Bootloader)需要的初始化信息。我推荐这样做:
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] set_property BITSTREAM.CONFIG.CONFIGRATE 33 [current_design] set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design]这几行Tcl命令会确保生成的.bit文件包含QSPI启动所需的配置。把它们加到Vivado的Tcl Console中执行,或者在生成比特流前通过GUI界面配置。
4. Vitis中的关键操作步骤
4.1 创建FSBL工程
FSBL是Zynq启动过程中最先运行的代码,相当于PC的BIOS。在Vitis中创建FSBL工程时要注意:
- 选择"Create a new platform from hardware (XSA)"
- 处理器选择"ps7_cortexa9_0"
- 模板选择"Zynq FSBL"
常见错误是选错处理器或者漏选xilffs库。xilffs库是文件系统支持,必须包含在FSBL中才能正确读取QSPI Flash。
4.2 打包BOOT.bin文件
打包启动镜像是最容易出错的环节。正确的文件顺序应该是:
- fsbl.elf(FSBL可执行文件)
- system.bit(比特流文件)
- application.elf(你的应用程序)
我习惯用这个BIF文件模板:
//arch = zynq; split = false; format = BIN the_ROM_image: { [bootloader]fsbl.elf system.bit application.elf }把这个文件保存为boot.bif,然后在Vitis Terminal中执行:
bootgen -image boot.bif -arch zynq -o BOOT.bin -w on4.3 烧写QSPI Flash
烧写前务必确认:
- 开发板处于JTAG模式(这样才能连接调试器)
- BOOT.bin文件路径没有中文或空格
- Flash型号选择正确(PYNQ-Z2一般是Micron N25Q128)
在Vitis中选择"Xilinx -> Program Flash",配置界面中:
- Image File选择刚才生成的BOOT.bin
- Flash Type选择"qspi-x4-single"
- 其他保持默认即可
烧写过程中不要断电!我遇到过Flash内容损坏的情况,都是烧写中途断电报错。
5. 验证与调试技巧
5.1 切换为QSPI启动模式
烧写完成后:
- 断电
- 将跳线改为QSPI模式(J11=2-3,J12=1-2)
- 重新上电
如果一切正常,你应该能看到程序自动运行。如果没有反应,可以尝试以下排查步骤:
5.2 常见问题排查
现象1:上电后没有任何反应
- 检查跳线帽接触是否良好
- 确认BOOT.bin文件打包顺序正确
- 测量QSPI Flash的VCC电压(应该是3.3V)
现象2:程序运行但功能不正常
- 可能是应用程序本身的问题
- 尝试通过UART打印调试信息
- 检查时钟配置是否正确
现象3:偶尔启动失败
- 可能是电源不稳导致
- 在Zynq核配置中增加电源监控代码
- 考虑在FSBL中加入看门狗功能
我在实际项目中总结出一个调试技巧:准备一个带LED闪烁的测试程序先烧进去,如果LED能正常闪烁,至少说明启动流程没问题,可以专注排查应用层问题。
6. 进阶技巧与优化建议
6.1 多镜像备份策略
对于关键应用,我推荐在QSPI Flash中烧写两个镜像(A/B备份),FSBL会根据校验结果选择可用的镜像启动。这需要修改FSBL代码:
- 在FSBL中实现CRC校验功能
- 将Flash分为两个区域存储不同版本的BOOT.bin
- 启动时先尝试加载主镜像,失败则加载备份镜像
6.2 优化启动速度
Zynq的启动时间主要消耗在:
- FSBL初始化(约200ms)
- 比特流加载(取决于文件大小)
- 应用加载
可以通过这些方法优化:
- 精简FSBL功能(去掉不必要的初始化)
- 使用压缩比特流(Vivado中启用压缩选项)
- 将部分初始化工作移到应用程序中
6.3 安全考虑
如果产品需要防篡改,可以考虑:
- 启用Zynq的AES加密功能
- 在FSBL中加入签名验证
- 锁定Flash的写保护区域
这些安全措施会增加开发复杂度,建议根据实际需求权衡。我曾经在一个工控项目中使用AES加密,启动时间增加了约50%,但满足了客户的安全要求。
7. 从开发到产品的完整流程
经过上面的步骤,你应该已经掌握了从JTAG调试到QSPI固化的完整流程。在实际项目中,我建议遵循这样的工作流:
- 开发阶段:使用JTAG模式快速迭代
- 测试阶段:烧写到QSPI验证启动流程
- 生产阶段:生成最终镜像并批量烧录
对于批量生产,可以考虑:
- 制作烧录夹具(避免频繁插拔JTAG)
- 编写自动化烧录脚本
- 建立版本管理系统(记录每个发布的BOOT.bin)
我负责过的一个智能网关项目,从开发到量产共迭代了23个版本,完善的固化流程帮我们节省了大量调试时间。记住,好的工程实践不仅能提高效率,还能减少现场问题。