1. Zynq复杂系统调试全景
Zynq 系列芯片(如 XC7Z020、XC7Z045)把一颗双核 ARM Cortex-A9 处理系统(PS)与一片可编程逻辑(PL)集成在同一硅片上,二者通过 AXI 互联、中断控制器、DMA 与共享存储耦合。调试这类系统时,最容易犯的错误是把它当成"ARM 加 FPGA"两块独立板卡来排查:一旦系统起不来,就先去量 PL 的时钟,或者反过来在 PS 里反复改设备树,却忽略了二者共享电源域、复位域和时钟源这一事实。本章先建立一张"全景地图":PS-PL 的耦合结构、从上电到应用运行的启动链路、时钟与复位树的层级关系,以及由此划分出的故障域。后续所有章节的定位手段,都建立在这张地图之上。
一、PS-PL 异构架构:耦合点在哪里
PS 侧包含 APU(双核 Cortex-A9 + L2 Cache + SCU)、片上存储器 OCM(256 KB)、DDR 控制器、中央互联(Central Interconnect)、外设(UART、SPI、I2C、SD、USB、GEM 等)以及系统级控制寄存器(SLCR)。PL 侧是 FPGA 逻辑资源与 DSP48、Block RAM。真正决定调试难度的,是两者之间的四类耦合通道:
- AXI 高性能/通用接口:PS 作为主设备通过 M_AXI_GP 访问 PL 的寄存器;PL 通过 S_AXI_HP 直接读写 DDR,带宽高、时序敏感。
- 中断:PL 的 16 路 IRQ 经 IRQ_F2P 进入 PS 的 GIC,是软硬件协同最常见的"信号断点"。
- 时钟与复位:PL 的时钟可由 PS 的 FCLK 提供,也可由外部晶振经 MMCM/PLL 生成;复位同样可能来自 PS 的 FCLK_RESET 或 PL 内部逻辑。
- 配置与状态:PCAP、DevC、SLCR 寄存器让 PS 能读取 PL 的配置状态、控制 PL 复位。
这四类通道意味着:一个"PL 不工作"的现象,根因可能在 PS 的时钟配置、AXI 互联地址映射、GIC 中断使能,甚至 DDR 带宽争用。因此故障定位的第一步不是"看哪块坏了",而是"判断故障落在哪个域"。
二、启动链路:从上电到应用,每一级都是断点
Zynq 的启动是一条严格分级的链路,任何一级失败都会表现为"系统无反应",但根因完全不同。典型链路如下:
- 上电复位(POR):电源稳定后,POR 释放,BootROM 开始执行。此时 DDR 尚未初始化,只有 OCM 可用。
- BootROM:根据 MIO[8:2] 引脚决定的启动模式(QSPI、SD、NAND、JTAG),从对应介质读取 Boot Header,校验后把 FSBL 搬入 OCM。
- FSBL:初始化 DDR、时钟、MIO,配置 PL(加载 bitstream),然后加载 SSBL(如 U-Boot)或裸机应用。
- SSBL / 应用:U-Boot 加载 Linux 内核与设备树,或直接跳转到裸机入口。
调试时,这条链路的价值在于"分段隔离"。例如:串口完全无输出,说明问题在 BootROM 或更早(启动模式引脚、QSPI 镜像、电源);串口打印 FSBL 版本后卡住,说明 DDR 初始化或 PL 配置失败;U-Boot 能起来但内核 panic,则问题在设备树或内核镜像。一个实用的判断依据是:FSBL 阶段会打印 "FSBL Version" 和 "DDR init done" 等关键标记,这些标记就是链路的分段点。
三、时钟与复位树:最容易被忽视的耦合源
PS 的时钟源通常来自外部晶振(PS_CLK,常见 33.333 MHz),经 PLL 倍频后产生 ARM、DDR、IO 等时钟。PL 的时钟有三种来源:PS 的 FCLK_CLK[0:3](由 SLCR 的 FPGA0_CLK_CTRL 等寄存器分频)、PL 内部 MMCM/PLL、外部时钟引脚。复位同样分层:POR、非 POR 复位、FCLK_RESET[0:3]、PL 内部复位。
这里有一个高频故障模式:PL 逻辑依赖 FCLK,而 FCLK 的使能与分频由 PS 的 SLCR 寄存器控制。如果 FSBL 或设备树没有正确使能 FCLK,PL 逻辑会"看起来配置成功但完全不工作"。判断方法是读取 SLCR 的 FPGA0_CLK_CTRL 寄存器,确认 CLKACT 位和 DIVISOR 是否符合预期。另一个模式是复位释放顺序错误:PL 逻辑在时钟稳定前就退出复位,导致状态机跑飞。正确做法是让复位信号同步到目标时钟域,并保证时钟先稳定、复位后释放。
四、故障域划分:把"哪里坏了"变成"哪个域坏了"
基于上述结构,可以把 Zynq 复杂系统的故障划分为五个域,每个域有独立的观察点和判断依据:
| 故障域 | 典型现象 | 首要观察点 | 判断依据 |
|---|---|---|---|
| PS 域 | 串口无输出、内核 panic | BootROM 标记、DDR 初始化日志 | 能否进入 FSBL / U-Boot |
| PL 域 | bitstream 加载失败、逻辑不响应 | DevC 状态、PL 配置完成信号 | DONE 引脚、PCAP 状态寄存器 |
| 时钟/复位域 | PL 逻辑时好时坏、状态机跑飞 | SLCR FCLK 寄存器、MMCM 锁定 | CLKACT 位、LOCKED 信号 |
| 中断/数据通路域 | PL 有数据但 CPU 收不到 | GIC 使能位、AXI 地址映射 | 中断计数、AXI 读写返回值 |
| DDR/带宽共享域 | 高负载下随机错误、DMA 超时 | DDR 控制器性能计数器 | 带宽占用率、AXI 响应延迟 |
这张表的用法是:先根据现象锁定候选域,再在候选域内用最小代价的观察点验证。例如"PL 有数据但 CPU 收不到",优先查 GIC 使能位和 AXI 地址映射,而不是去重新综合 PL。这样可以避免在错误的域里反复折腾。