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 PS-PL 耦合结构与故障域全景 PS 处理系统 APU 双核 A9 L2 Cache / SCU OCM 256KB BootROM 映射 中央互联 Central Interconnect DDR 控制器 GIC 中断控制器 外设 UART / SD / SPI / I2C / GEM SLCR 系统控制寄存器 PCAP / DevC 配置控制 PL 可编程逻辑 自定义 IP / 用户逻辑 AXI-Lite 寄存器 / 数据通路 Block RAM DSP48 MMCM / PLL 时钟生成 PL 复位逻辑 / 同步器 IO / 高速收发器 PL 配置状态寄存器 M_AXI_GP S_AXI_HP IRQ_F2P FCLK / RESET PCAP 配置 PS 域 PL 域 时钟/复位/中断耦合域 配置域 DDR/带宽共享域

二、启动链路:从上电到应用,每一级都是断点

Zynq 的启动是一条严格分级的链路,任何一级失败都会表现为"系统无反应",但根因完全不同。典型链路如下:

  1. 上电复位(POR):电源稳定后,POR 释放,BootROM 开始执行。此时 DDR 尚未初始化,只有 OCM 可用。
  2. BootROM:根据 MIO[8:2] 引脚决定的启动模式(QSPI、SD、NAND、JTAG),从对应介质读取 Boot Header,校验后把 FSBL 搬入 OCM。
  3. FSBL:初始化 DDR、时钟、MIO,配置 PL(加载 bitstream),然后加载 SSBL(如 U-Boot)或裸机应用。
  4. 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 域串口无输出、内核 panicBootROM 标记、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。这样可以避免在错误的域里反复折腾。

调试起点建议:拿到一块 Zynq 板卡后,先确认三件事——启动模式引脚是否正确、串口是否能打印 FSBL 标记、SLCR 中 FCLK 是否使能。这三项覆盖了启动链路和时钟复位树的关键节点,能快速排除大部分"系统起不来"的问题。