Zynq 实战 04|PS 配置详解:时钟链、DDR timing、MIO 管脚映射全解
Zynq 实战 04|PS 配置详解:时钟链、DDR timing、MIO 管脚映射全解
这是《Zynq FPGA 嵌入式系统设计实战》系列的第 4 篇。 板子:Pynq-Z2(XC7Z020-1CLG400C)。工具链:Vivado / Vitis 2023.2。 上一篇:《Zynq 实战 03|Block Design 基础:AXI 互联怎么连》
0. 这一篇要解决什么问题
在 Vivado 里新建 Block Design,拖入 ZYNQ7 Processing System IP,双击进去——弹出一个比你预想的复杂得多的配置界面。有人选择点击 Run Block Automation 让 Vivado 自动处理,然后继续往下走。
这个做法在 Pynq-Z2 上会踩坑:因为 Vivado 2023.2 并没有内置 Pynq-Z2 的官方 Board Preset,自动填入的默认值里 DDR 配置会留空或填错,跑 FSBL 的时候 DDR 初始化失败,表现是系统启动卡死在 FSBL 第一阶段,串口没有任何输出。
这一篇的目标是让你搞清楚 ZYNQ7 PS IP 配置界面里每个关键参数对应什么物理行为,以及在 Pynq-Z2 上应该填什么具体数字——不是”根据芯片手册设置”,就是具体数字。
本文不讲:如何在 Vivado 里新建工程(前面三篇有);PL 侧 AXI IP 的连接方式(下一篇)。
1. Block Design 里双击 ZYNQ7 PS IP:五个 Tab 概览
在 Block Design 里双击 ZYNQ7 Processing System,弹出 Re-customize IP 对话框。左侧是功能分类树,右边是配置区域。但真正需要你手动处理的东西集中在五个地方:
| Tab / 分类 | 关键参数 | 配错后果 |
|---|---|---|
| Clock Configuration | PLL 倍频系数、CPU / DDR / 外设时钟频率 | CPU 超频崩溃 / 外设时钟算错 |
| DDR Configuration | 内存型号、timing 参数 | DDR 初始化失败、系统启动不了 |
| Peripheral I/O Pins | 哪些外设走 MIO / EMIO | 外设根本不出管脚 |
| MIO Configuration | 每个 MIO 的 slew rate、drive strength、电平标准 | 信号质量差 / USB 工作异常 |
| Interrupts | 是否启用 IRQ_F2P,位宽 | PL 中断无法送达 PS |
下面逐一拆。
2. Clock Configuration:从 33.333 MHz 算起
Pynq-Z2 板上有一颗 33.333 MHz 的有源晶振,通过 PS_CLK 管脚馈入 PS。PS 内部有三个独立的 PLL,从这颗晶振倍频出所有 PS 所需的时钟:
2.1 ARM_PLL:CPU 时钟从这里来
在 Vivado 的 Clock Configuration → CPU Clock 里,你看到的 666.666 MHz 是这么算出来的:
ARM_PLL = PS_CLK × FDIV = 33.333 MHz × 40 = 1333.32 MHz
CPU_6x4x = ARM_PLL ÷ 2 = 666.66 MHz
FDIV=40 这个值存在 ARM_PLL_CTRL 寄存器(地址 0xF800_0100,UG585 B.28 节)的 bits [18:12]。Vivado GUI 里改 CPU 频率,本质上就是改这个字段。
从 CPU_6x4x 向下分频,得到 PS 内部其余时钟域(这些在 Vivado GUI 里只读,不让你改):
| 时钟名 | 来源 | Pynq-Z2 频率 | 主要用户 |
|---|---|---|---|
CPU_6x4x | ARM_PLL ÷ 2 | 666.66 MHz | Cortex-A9 核心、SCU |
CPU_3x2x | CPU_6x4x ÷ 2 | 333.33 MHz | L2 Cache、OCM、AXI 高速路径 |
CPU_2x | CPU_6x4x ÷ 3 | 222.22 MHz | DMA、GigE DMA |
CPU_1x | CPU_6x4x ÷ 6 | 111.11 MHz | APB 外设总线、SWDT、TTC |
🚧 避坑:GUI 里 CPU Clock 显示的是
CPU_6x4x频率,即 666 MHz。但 AXI 互联(S_AXI_HP)的时钟并不是 666 MHz,而是CPU_3x2x(333 MHz)或你在 Block Design 里接过来的FCLK_CLK0。很多人以为 HP 端口能跑 666 MHz,实际上 AXI 端口的工作时钟取决于你给S_AXI_HP_aclk接的是哪个时钟。
2.2 IO_PLL:外设时钟从这里来
IO_PLL_CTRL[FDIV] 默认 30 → IO_PLL = 33.333 × 30 = 1000 MHz。UART、SPI、I2C、SD 卡等 PS 外设时钟,以及给 PL 用的 FCLK_CLK0~3,都是从 IO_PLL 分频而来。
FCLK_CLK0 默认 100 MHz(IO_PLL ÷ 10)。这是 Block Design 里最常用的 PL 时钟来源,接到你的 AXI IP。
2.3 DDR_PLL:DDR 时钟从这里来
DDR_PLL_CTRL[FDIV] 默认 32 → DDR_PLL = 33.333 × 32 = 1066.66 MHz。
DDR 控制器的工作时钟 DDR_3x = DDR_PLL ÷ 2 = 533.33 MHz,这就是 DDR3-1066 里”1066”这个数字的来源(双倍数据率:533 MHz 时钟 × 2 = 1066 MT/s)。
在 Clock Configuration Tab 里,你能看到 Memory Frequencies 区域显示 533 MHz,这个数字要和 DDR Configuration Tab 里你填的内存型号所标注的速度一致,不一致时 DDR 初始化会失败。
3. DDR Configuration:Pynq-Z2 上填什么
Pynq-Z2 板上的 DDR3 内存是两片 Micron MT41K256M16(16-bit 宽),两片并联组成 32-bit 数据总线,总容量 512 MB。这是非常重要的细节,因为 Vivado 的下拉列表里有很多不同宽度和容量的 MT41K 变体,选错一个,DDR 初始化要么失败,要么出现奇怪的地址映射错误。
3.1 在 Vivado 里应该怎么填
打开 DDR Configuration Tab,按下表填写:
| 配置项 | Pynq-Z2 的值 | 说明 |
|---|---|---|
| Memory Type | DDR 3 (Low Voltage) | Pynq-Z2 用的是 DDR3L (1.35V),不是标准 DDR3 1.5V |
| Memory Part | MT41K256M16 RE-125 | 每片芯片型号,Vivado 有内置数据库 |
| Data Width | 32 | 两片 16-bit 并联 |
| ECC | disabled | Pynq-Z2 无 ECC |
| Row Address Bits | 15 | 2^15 = 32768 行 |
| Column Address Bits | 10 | 2^10 = 1024 列 |
| Bank Address Bits | 3 | 8 个 Bank |
| Effective DRAM Bus Width | 32 | 同上 |
| Effective DDR Frequency | 533.333 MHz | 对应 DDR3-1066 |
3.2 DDR3-1066 Timing 参数——数字在这里
选了 MT41K256M16 RE-125 后,Vivado 会自动从内置数据库填充 timing,但你应该知道这些数字从哪来、值不对的时候该填什么。
MT41K256M16 RE-125 在 DDR3-1066E 速度档的 JEDEC 标准参数(tCK = 1.875 ns @ 533 MHz):
| 参数 | 周期数(533 MHz) | 时间(ns) | 说明 |
|---|---|---|---|
| CL(CAS Latency) | 7 | 13.13 | 读命令到数据的延迟 |
| tRCD | 7 | 13.13 | RAS 到 CAS 的最小间隔 |
| tRP | 7 | 13.13 | 预充电命令到下一激活的最小间隔 |
| tRAS | 20 | 37.5 | 行激活保持最短时间(≥35 ns) |
| tRC | 27 | 50.6 | tRAS + tRP,同一行连续操作的最短周期 |
| tRFC | 139 | 260 | 刷新周期(4Gb 器件,JEDEC 要求 ≥260 ns) |
| tFAW(×16 器件) | 20 | 37.5 | 四激活窗口(×16 宽度器件比 ×8 宽) |
| tRRD | 4 | 7.5 | 同 Bank Group 中行激活的最短间隔 |
CL=7, tRCD=7, tRP=7 这个组合叫 7-7-7,是 DDR3-1066E 的标准时序。
🚧 避坑:tRFC 是最容易填错的参数。有人看到”CL=7”就认为所有参数都是 7,然后把 tRFC 也填成 7ns 或 7 cycles——这直接导致 DDR 刷新不完整,系统跑几秒就挂死,或者读写出现随机 bit 翻转。
tRFC 和器件容量有关:MT41K256M16 是 4Gb(512MB per chip) 器件,JEDEC spec(JESD79-3F, Table 36)规定 tRFC_min = 260 ns。在 533 MHz 下换算:⌈260 ÷ 1.875⌉ = 139 个周期。如果你手动填 timing,这个数字不能少。
3.3 地址映射:ROW-BANK-COL 还是 BANK-ROW-COL?
DDR Configuration → Address Mapping 默认是 ROW_BANK_COLUMN,这对 Zynq 跑 Linux 的场景是正确选择——Linux 内核的 DDR 访问模式偏随机,ROW-BANK-COL 对 row hit rate 更友好。
只有当你在 PL 侧做 streaming DMA(按地址线性扫描大块数据),才可能考虑调整。日常配置保持默认即可。
4. Peripheral I/O Pins + MIO Configuration:管脚分配的真实逻辑
这一 Tab 是很多人跳过的地方,但也是问题最多的地方。下面先解释清楚两个基本概念,再给出 Pynq-Z2 的真实管脚映射。
4.1 MIO vs EMIO:不只是”直接/通过 PL”的区别
MIO(Multiplexed I/O):PS 外设信号直接连到 PS 专有的 IO Buffer,出芯片引脚。不消耗 PL 任何资源。
- 共 54 个 MIO 管脚:MIO[0:15](Bank 500)和 MIO[16:53](Bank 501)
- Slew rate:可选 SLOW / FAST;Drive strength:2 / 4 / 8 / 12 mA
- 每个 Bank 的电平标准由
VCCO_MIO0(Bank 500)和VCCO_MIO1(Bank 501)决定
EMIO(Extended MIO):PS 外设信号跨过 PS-PL 边界,从 Block Design 里以普通信号的形式出现在 PL 端,然后通过 XDC 约束到任意 FPGA IO 管脚。
- 电平标准由你在 XDC 里指定(
IOSTANDARD LVCMOS33等),灵活 - 但:走的是 FPGA IO Buffer,速度上限受 PL 的 SelectIO 规格约束,且 timing 路径更长
- 必须在 XDC 里手动约束管脚,否则 Vivado 报 unrouted 错误
4.2 Pynq-Z2 上的 MIO Bank 电压
Pynq-Z2 的 PCB 设计:
- Bank 500(MIO[0:15]):
VCCO_MIO0 = 3.3V→ 该 Bank 下的所有 MIO 必须配置为 LVCMOS33 - Bank 501(MIO[16:53]):
VCCO_MIO1 = 1.8V→ 必须配置为 LVCMOS18
这不是可以自由选择的——Bank 电压是硬件决定的,你在 MIO Configuration Tab 里设置的 IO Type 必须和 PCB 走的电压匹配,否则 IO 驱动电流异常,轻则信号质量变差,重则损坏芯片。
🚧 避坑:USB0 和 GigE0 的 MIO 都在 Bank 501(1.8V)。如果你在 MIO Configuration 里把 USB 的 IO Type 误设成 LVCMOS33,USB 枚举可能失败或不稳定,但并不会立刻报错——这种 bug 很难排查。Pynq-Z2 上 Bank 501 只能用 LVCMOS18,记住这条。
4.3 Pynq-Z2 真实 MIO 管脚映射
以下是 Pynq-Z2 出厂 PS 配置中各外设的 MIO 分配(来源:TUL Pynq-Z2 schematic, UG585 Appendix B PS MIO Signal Descriptions):
| 外设 | MIO 管脚 | 具体功能 | 所在 Bank | 电平标准 |
|---|---|---|---|---|
| UART0 TX | MIO[14] | Tx data | 500 | LVCMOS33 |
| UART0 RX | MIO[15] | Rx data | 500 | LVCMOS33 |
| GigE0 | MIO[16:21] | RGMII TXD/TX_CTL/TX_CLK | 501 | LVCMOS18 |
| GigE0 | MIO[22:27] | RGMII RXD/RX_CTL/RX_CLK | 501 | LVCMOS18 |
| USB0 | MIO[28:39] | ULPI DATA/NXT/STP/DIR/CLK | 501 | LVCMOS18 |
| SD0 CLK | MIO[40] | SD 时钟 | 501 | LVCMOS18 |
| SD0 CMD | MIO[41] | 命令线 | 501 | LVCMOS18 |
| SD0 DAT[0:3] | MIO[42:45] | 数据线 | 501 | LVCMOS18 |
| SD0 CD | MIO[47] | 卡检测(低有效) | 501 | LVCMOS18 |
| GigE0 MDC | MIO[52] | MDIO 时钟 | 501 | LVCMOS18 |
| GigE0 MDIO | MIO[53] | MDIO 数据 | 501 | LVCMOS18 |
特别说明:
UART0 为什么在 MIO[14:15]?
Zynq PS 的 MIO 是多路复用的——每个 MIO 管脚可以连接多个外设信号,通过 MIO_PIN_xx_FILT 寄存器选择。UART0 固定只有两个可用的 MIO 位置:MIO[10:11] 或 MIO[14:15]。Pynq-Z2 选了 [14:15],这两个管脚连接到板子上的 USB-UART 芯片(Silicon Labs CP2104),这就是为什么 USB 数据线连上去就能在 PC 上看到串口的原因。
SD0 为什么在 MIO[40:45]?
SD 卡控制器 SD0 在 Bank 501,固定在 MIO[40:45] 这个位置(UG585 Table B-2)。SD1 如果存在,在 MIO[46:51] 或走 EMIO。Pynq-Z2 只有一个 SD 卡槽接到 SD0 的 MIO[40:45]。
4.4 在 Vivado GUI 里怎么操作
在 Peripheral I/O Pins Tab:
- 找到 UART 0,点击 MIO 行(不是 EMIO 行),Vivado 会自动高亮 MIO[14:15]
- 找到 SD 0,选 MIO,自动填 MIO[40:45]
- 找到 USB 0,选 MIO,自动填 MIO[28:39]
- 找到 Enet 0,选 MIO,并在旁边的下拉里选 MDIO 走 MIO[52:53]
然后切换到 MIO Configuration Tab,检查每个外设的 IO Type:
- MIO[0:15](Bank 500)一律设 LVCMOS 3.3V
- MIO[16:53](Bank 501)一律设 LVCMOS 1.8V
5. Interrupt:IRQ_F2P 的 16-bit 陷阱
PS 配置里的 Interrupts Tab 比较简单,但有一个坑值得单独讲。
5.1 怎么开启
在 Interrupts → PL-PS Interrupt Ports 下,勾选 Fabric Interrupts,然后在下面的 IRQ_F2P[15:0] 旁边选择你需要的位宽(1~16)。
开启后,Block Design 里的 ZYNQ7 PS IP 会多出一个 IRQ_F2P 输入端口。把 PL 中各 IP 的中断信号接到这个端口上。
5.2 Concat IP 连接与 GIC ID 映射
如果你有多个 PL 中断源(比如一个自定义 IP 的 interrupt + 一个 AXI DMA 的 mm2s_introut),需要用 Concat IP 将多个 1-bit 信号合并成 N-bit 总线接入 IRQ_F2P。
关键:IRQ_F2P[15:0] 这 16 个位映射到 PS GIC 的两段不连续 Interrupt ID:
| IRQ_F2P 位 | GIC Interrupt ID | Linux 中断号(通常) |
|---|---|---|
| [0] | 61 | 29(SPI 29) |
| [1] | 62 | 30 |
| … | … | … |
| [7] | 68 | 36 |
| [8] | 84 | 52 |
| [9] | 85 | 53 |
| … | … | … |
| [15] | 91 | 59 |
[0:7] 对应 GIC ID 61–68,[8:15] 对应 84–91,中间有个断档(ID 69–83 是 PS 内部外设中断)。这个间隔在代码里必须知道,否则你注册错 IRQ number,中断永远不会触发。
在 Linux 驱动里,通过 DTS 的 interrupts 属性指定中断号时,GIC ID 需要减去 32(SPI offset):
IRQ_F2P[0] = GIC ID 61 → DTS 里写 <0 29 1>(GIC type 0 = SPI,number 29,flags 1 = rising edge)。
🚧 避坑:Concat IP 里,In0 对应 IRQ_F2P 最低位(bit 0 = GIC ID 61)。如果你在 Block Design 里接反了——比如把 AXI DMA interrupt 接到 In1、把自定义 IP interrupt 接到 In0——那么驱动里注册的 IRQ 顺序就相反了。中断依然触发,但进了错误的 handler,现象极其迷惑(DMA 完成中断触发了自定义 IP 的 handler)。养成习惯:接 Concat 时在旁边注释每个 In 对应哪个 GIC ID。
6. Apply Board Preset 是什么,Pynq-Z2 没有怎么办
6.1 Board Preset 是什么
在 ZYNQ7 PS IP 配置界面的左上角有一个 “Presets → Apply Board Preset” 按钮(或菜单路径)。这个功能会读取 Vivado 的 Board Files(<vivado_install>/data/boards/board_files/)中对应开发板的预设文件(.xml),一键把 PS 配置填充成该板的默认值——包括 DDR 型号、MIO 分配、时钟配置等。
以 ZedBoard 为例,点这个按钮后,DDR 的 MT41K256M16 型号、MIO 的 UART/SD 分配、FCLK_CLK0 的 100 MHz 这些全部自动填好,非常方便。
6.2 Pynq-Z2 没有官方 AMD/Xilinx 的 Board Preset
Vivado 2023.2 内置的 Board Files 里,没有 Pynq-Z2(也没有 Pynq-Z1)。TUL 提供了社区版 Board Files,可以从 Pynq 项目的 GitHub 仓库获取:
# Board files 位置(Pynq-Z2 官方 board files repo)
git clone https://github.com/cathalmccabe/pynq-z2_board_files.git
# 拷贝到 Vivado board files 目录
cp -r pynq-z2_board_files/pynq-z2 \
/tools/Xilinx/Vivado/2023.2/data/boards/board_files/
安装后,重启 Vivado,在新建工程时的 Default Part 步骤里选 Boards tab,就能找到 Pynq-Z2。在 ZYNQ7 PS IP 里,Apply Board Preset 就可以用了。
如果你不想安装 board files(或者在一个没有网络的机器上),也可以手动按本文前几节描述的参数逐项填写。手动配置和 Board Preset 的结果是等价的,Board Preset 只是自动化了这个过程。
6.3 手动配置的最小步骤清单
如果你选择手动配置(不用 Board Preset),在 Pynq-Z2 上至少要做这些:
Clock Configuration:
✅ CPU 频率 → 666.666 MHz(默认通常正确)
✅ FCLK_CLK0 → 100 MHz(设计中会用到)
DDR Configuration:
✅ Memory Type → DDR 3 (Low Voltage)
✅ Memory Part → MT41K256M16 RE-125
✅ Data Width → 32
✅ 确认 Effective DDR Frequency = 533.333 MHz
✅ 确认 CL=7, tRCD=7, tRP=7, tRFC=260ns
Peripheral I/O Pins:
✅ UART0 → MIO[14:15]
✅ SD0 → MIO[40:45],CD on MIO[47]
✅ USB0 → MIO[28:39](如果需要)
✅ GigE0 → MIO[16:27],MDIO on MIO[52:53](如果需要)
MIO Configuration:
✅ MIO[0:15] → LVCMOS 3.3V
✅ MIO[16:53] → LVCMOS 1.8V
Interrupts:
✅ 如有 PL 中断需求 → 开启 IRQ_F2P,选好位宽
完成后,点左上角 OK,回到 Block Design,在空白处右键 → Validate Design(快捷键 F6),没有红色 Critical Warning 就说明 PS 配置在逻辑层面是正确的。
7. 本篇你应该带走的几个判断
完成这一篇后,再看到 Vivado ZYNQ7 PS IP 配置界面时,你应该能立刻回答:
- PS_CLK = 33.333 MHz,ARM_PLL FDIV = 40 → CPU = 666 MHz。改 FDIV 就能改 CPU 频率,-1 速度等级不要超过 667 MHz
- Pynq-Z2 的 DDR 是 MT41K256M16 × 2 = 512MB,DDR3L-1066,CL=7-7-7,tRFC=260 ns(4Gb 器件)——这几个数字不对就启动不了
- Bank 500(MIO[0:15])= 3.3V,Bank 501(MIO[16:53])= 1.8V,这是 PCB 硬件决定的,不能在软件里改
- UART0 在 MIO[14:15](Bank 500,LVCMOS33);SD0 在 MIO[40:45](Bank 501,LVCMOS18)
- IRQ_F2P[7:0] → GIC ID 61–68,IRQ_F2P[15:8] → GIC ID 84–91,两段不连续;Concat IP 的 In[N] = IRQ_F2P[N] = GIC ID (61+N)
- Pynq-Z2 没有内置 Board Preset;从 GitHub 拿 TUL 的 board files 装上,或者按本文手动填
8. 下一篇预告
下一篇 《Zynq 实战 05|AXI 自定义 IP:从 Verilog 到 PS 可访问的寄存器》,我们会从 PS 可以读写的角度,实现一个最简单的 AXI Lite 从机 IP:
- 用 Vivado 的 AXI Peripheral 向导生成骨架
- 分析生成代码里 AXI handshake 的真实时序
- 在 PS 侧用
Xil_Out32 / Xil_In32读写自定义寄存器 - 把一颗 Pynq-Z2 上的 LED 接到这个寄存器
参考资料
| 文档号 | 名称 | 用途 |
|---|---|---|
| UG585 | Zynq-7000 SoC Technical Reference Manual | Chapter 25(时钟);Chapter 10(DDR);Appendix B(MIO 管脚) |
| DS190 | Zynq-7000 SoC Data Sheet: Overview | 7Z020 速度等级与最高主频 |
| JESD79-3F | JEDEC DDR3 SDRAM Standard | Table 36 tRFC;Table 3 DDR3-1066E timing |
| Micron MT41K256M16 Datasheet | MT41K256M16TW / RE 系列 | 具体 timing 数字来源,tRFC = 260 ns(4Gb) |
| UG1144 | PetaLinux Tools Documentation | DTS 中断节点写法 |
所有 AMD/Xilinx 官方文档均可在 https://docs.amd.com 免费下载。Micron 内存文档在 https://www.micron.com/products/dram 搜索型号获取。
这是《Zynq FPGA 嵌入式系统设计实战》系列第 4 篇。 有问题或者发现数字有误欢迎评论区指出——PS 配置这块细节多,难免疏漏。