第三篇不再讲“怎么构建”,而是讲系统上电之后,怎样一步步证明它真的可用。
很多移植工作不是败在构建阶段,而是败在 bring-up 阶段:系统偶尔启动、网络偶尔通、寄存器偶尔能读、数据路径偶尔正确。工程验证的价值,就是把偶然变成可重复。
先从最小可观测性开始
第一次启动新镜像时,最重要的不是马上跑业务程序,而是建立最小可观测性。串口最好用,因为它能覆盖 FSBL、U-Boot、kernel 和用户空间;如果串口不可用,至少要准备 JTAG、SD 卡离线挂载、网络扫描三种 fallback。没有观测入口,就没有排障。
确认启动分区里有 BOOT.BIN、image.ub、boot.scr。确认 rootfs 分区可挂载,且 `/etc/fstab`、网络配置、SSH 服务符合预期。记录镜像 SHA256、XSA 版本、bit/hwh 版本和构建时间。按阶梯验证,不要跳步
新板 bring-up 最忌讳一上来就做高速数据面。正确顺序是:先确认 Linux 启动,再确认网络,再确认 PYNQ 环境,再确认 overlay,再只读寄存器,再安全写读回,最后才进入 PL DDR、DMA、ADC/DAC 或业务数据流。
| 阶梯 | 验证目标 | 通过标志 |
| 启动 | BootROM、FSBL、U-Boot、kernel 和 rootfs 连续跑通。 | 能看到登录提示或 systemd 进入 multi-user。 |
| 网络 | IP、路由、PHY、MAC 和服务监听正常。 | ping、SSH 或 HTTP health 可用。 |
| PYNQ | Python 环境和 overlay 文件存在。 | `import pynq` 成功,bit/hwh 路径正确。 |
| 控制面 | AXI-Lite 只读寄存器能返回稳定值。 | 版本、板卡类型或 ID 寄存器稳定。 |
| 安全写 | 选择无副作用寄存器写入并恢复。 | 写入、读回、恢复都符合位宽定义。 |
| 数据面 | PL DDR、DMA 或业务数据路径闭环。 | pattern、波形或块数据读回一致。 |
Linux 启动后的第一组命令
系统起来后,先不要急着加载复杂 overlay。用基础命令确认内核、设备树、网络、磁盘和服务状态。每条命令都应该能回答一个具体问题,而不是“看看有没有异常”。
如果使用了板卡配置文件,例如 `/boot/test-board.json`,建议让一个 systemd 服务在启动早期读取它,设置 hostname、网络模式和板卡角色。这样多块板可以使用同一张镜像,只通过启动分区的小文件区分差异。
PYNQ overlay 验证要看 hwh
PYNQ 加载 bitstream 只是第一步。真正影响 Python 侧开发体验的是 hwh 解析结果:`ip_dict` 是否有你的 AXI-Lite IP,`mem_dict` 是否有预期的数据窗口,地址范围是否和 Vivado address editor 一致。如果 hwh 缺失或来自旧构建,Python 代码可能找不到 IP,或者找到的是错误地址。
如果 overlay 加载失败,先看三件事:bit/hwh 是否来自同一次导出;FPGA manager 是否启用;设备树里是否保留了 FPGA manager、clock、reserved memory 或相关驱动配置。不要急着改 Python wrapper,先证明底层资源存在。
寄存器访问先只读再写
AXI-Lite 是 PS 和 PL 联调最适合的第一条路。建议先选择版本号、构建时间、板卡 ID 这类只读寄存器。读值稳定后,再选择一个不会触发 reset、trigger、DMA start、DAC enable 的配置寄存器做写读回。每次写之前保存原值,测试结束恢复原值。
❗不要拿有副作用的寄存器做首轮写测试。 reset、trigger、stream enable、DDR read enable、DAC output enable 这类位一旦被误写,现象会变复杂。首轮只选配置寄存器,并且必须恢复原值。
数据通路用闭环证明
控制面通过以后,再验证数据面。若 PS 需要访问 PL DDR,硬件上应有 PS HPM master 到 PL DDR controller 的地址通路,软件上应清楚这是 MMIO、UIO、DMA 还是用户态 mmap。验证策略从小到大:先 4KB pattern,再扩大到一帧业务数据,再进入持续读写。
如果数据不一致,不要立刻怀疑算法。先查地址单位是否一致:旧驱动可能用 word address,Linux MMIO 常用 byte offset;上位机 RPC 又可能包装了一层兼容转换。其次查缓存策略、字节序、位宽截断和突发长度。最后再看硬件状态机。
常见问题排障矩阵
| 现象 | 优先怀疑 | 第一步动作 |
| 完全无串口输出 | 启动模式、BOOT.BIN、串口线序、FSBL 未运行。 | 检查拨码和 SD 启动分区,换已知可用 BOOT.BIN 对比。 |
| 停在 U-Boot | bootcmd、image.ub、boot.scr 或启动分区文件名。 | 在 U-Boot 下 `printenv`、`ls mmc 0:1`。 |
| kernel panic | rootfs、device tree、内核配置或存储驱动。 | 抓完整 kernel log,确认 root 参数和分区 UUID。 |
| ping 不通 | PHY 地址、RGMII 时钟、MAC、静态 IP 冲突。 | 串口进系统后看 `ip addr`、`dmesg` 和 PHY log。 |
| PYNQ 找不到 IP | hwh 缺失、hwh 旧版本、overlay wrapper 路径错误。 | 打印 `ip_dict`,核对 hwh 与 bit 是否同批次。 |
| 寄存器读值异常 | 地址单位、AXI 地址映射、复位状态、位宽截断。 | 先读版本寄存器,再查 Vivado address editor。 |
| 大块数据错误 | 缓存、地址窗口、DMA 配置、突发边界。 | 从 4KB pattern 做二分,定位第一个错误偏移。 |
把验证结果写成可复用记录
每次镜像、bit/hwh、XSA、device tree 或 runtime package 变化,都应该记录版本和验证结论。最小记录包括:镜像 SHA256、构建时间、硬件导出时间、启动日志摘要、网络地址、overlay 解析结果、只读寄存器值、安全写读回结果、数据闭环结果。这样下一次异常时,你不是从记忆里排障,而是从证据里排障。
做到这里,你已经拥有一条完整的 Zynq PS Linux 移植闭环:硬件平台可导出,板级 Linux 可构建,SD 镜像可启动,PYNQ 或用户态程序可访问 PL,控制面和数据面都能被最小测试证明。后续要做的,就是把临时脚本收敛成工程化工具,把 bring-up 经验沉淀为自动测试。
参考资料
- PYNQ SD Card image 文档:https://pynq.readthedocs.io/en/v3.1/pynq_sd_card.html
- PYNQ sdbuild README:https://github.com/Xilinx/PYNQ/blob/master/sdbuild/README.md
- AMD UG1144 PetaLinux boot and packaging:https://docs.amd.com/r/2024.1-English/ug1144-petalinux-tools-reference-guide/petalinux-package