← Back to Blog
FPGAZynqXilinxVivado嵌入式系统DDR3MIO时钟配置

Zynq 实战 04|PS 配置详解:时钟链、DDR timing、MIO 管脚映射全解

This article was written in Chinese and auto-translated via Google Translate.
View Chinese Original →

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 ConfigurationPLL 倍频系数、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 所需的时钟:

Pynq-Z2 PS 时钟链 PS_CLK 33.333 MHz ARM_PLL ×40 = 1333.32 MHz CPU_6x4x ÷2 = 666.66 MHz ARM Cortex-A9 核心 CPU_3x2x ÷2 = 333 MHz CPU_2x ÷3 = 222 MHz CPU_1x ÷6 = 111 MHz AXI 互联 / 外设 / 总线 IO_PLL ×30 = 1000.00 MHz PS 外设时钟 UART0 ÷10 = 100 MHz SD0 ÷20 = 50 MHz FCLK_CLK0 ÷10 = 100 MHz DDR_PLL ×32 = 1066.66 MHz DDR 时钟域 DDR_3x ÷2 = 533.33 MHz DDR_2x ÷3 = 355.55 MHz DDR3-1066 = 533 MHz 时钟 FDIV 寄存器控制倍频系数 ARM_PLL_CTRL[FDIV] @ 0xF800_0100 同一参考 时钟源
图 1. Pynq-Z2 PS 时钟链:33.333 MHz → 三个 PLL → 各时钟域

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_6x4xARM_PLL ÷ 2666.66 MHzCortex-A9 核心、SCU
CPU_3x2xCPU_6x4x ÷ 2333.33 MHzL2 Cache、OCM、AXI 高速路径
CPU_2xCPU_6x4x ÷ 3222.22 MHzDMA、GigE DMA
CPU_1xCPU_6x4x ÷ 6111.11 MHzAPB 外设总线、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 TypeDDR 3 (Low Voltage)Pynq-Z2 用的是 DDR3L (1.35V),不是标准 DDR3 1.5V
Memory PartMT41K256M16 RE-125每片芯片型号,Vivado 有内置数据库
Data Width32两片 16-bit 并联
ECCdisabledPynq-Z2 无 ECC
Row Address Bits152^15 = 32768 行
Column Address Bits102^10 = 1024 列
Bank Address Bits38 个 Bank
Effective DRAM Bus Width32同上
Effective DDR Frequency533.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)713.13读命令到数据的延迟
tRCD713.13RAS 到 CAS 的最小间隔
tRP713.13预充电命令到下一激活的最小间隔
tRAS2037.5行激活保持最短时间(≥35 ns)
tRC2750.6tRAS + tRP,同一行连续操作的最短周期
tRFC139260刷新周期(4Gb 器件,JEDEC 要求 ≥260 ns)
tFAW(×16 器件)2037.5四激活窗口(×16 宽度器件比 ×8 宽)
tRRD47.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 vs EMIO 信号路径对比 PS (Processing System) PS 外设 UART / SD / USB MIO IO Buffer Bank 500 / 501 芯片管脚 MIO[14] 等 MIO 路径 不经过 PL,不占 FPGA 资源 最高 slew = FAST,drive ≤ 8mA PS 外设 UART1 / SPI1… EMIO 信号 经 PS-PL 边界 PL (Programmable Logic) FPGA IO Buffer LVCMOS18/33,自定义 任意 FPGA 管脚 需要 XDC 约束 EMIO 路径 占用 PL 逻辑 / IO 可自定义电平标准 速度上限受 PL IO 限制
图 2. MIO 直连芯片管脚 vs EMIO 经由 PL fabric 路由到 FPGA 管脚

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 TXMIO[14]Tx data500LVCMOS33
UART0 RXMIO[15]Rx data500LVCMOS33
GigE0MIO[16:21]RGMII TXD/TX_CTL/TX_CLK501LVCMOS18
GigE0MIO[22:27]RGMII RXD/RX_CTL/RX_CLK501LVCMOS18
USB0MIO[28:39]ULPI DATA/NXT/STP/DIR/CLK501LVCMOS18
SD0 CLKMIO[40]SD 时钟501LVCMOS18
SD0 CMDMIO[41]命令线501LVCMOS18
SD0 DAT[0:3]MIO[42:45]数据线501LVCMOS18
SD0 CDMIO[47]卡检测(低有效)501LVCMOS18
GigE0 MDCMIO[52]MDIO 时钟501LVCMOS18
GigE0 MDIOMIO[53]MDIO 数据501LVCMOS18

特别说明:

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:

  1. 找到 UART 0,点击 MIO 行(不是 EMIO 行),Vivado 会自动高亮 MIO[14:15]
  2. 找到 SD 0,选 MIO,自动填 MIO[40:45]
  3. 找到 USB 0,选 MIO,自动填 MIO[28:39]
  4. 找到 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 IDLinux 中断号(通常)
[0]6129(SPI 29)
[1]6230
[7]6836
[8]8452
[9]8553
[15]9159

[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 接到这个寄存器

参考资料

文档号名称用途
UG585Zynq-7000 SoC Technical Reference ManualChapter 25(时钟);Chapter 10(DDR);Appendix B(MIO 管脚)
DS190Zynq-7000 SoC Data Sheet: Overview7Z020 速度等级与最高主频
JESD79-3FJEDEC DDR3 SDRAM StandardTable 36 tRFC;Table 3 DDR3-1066E timing
Micron MT41K256M16 DatasheetMT41K256M16TW / RE 系列具体 timing 数字来源,tRFC = 260 ns(4Gb)
UG1144PetaLinux Tools DocumentationDTS 中断节点写法

所有 AMD/Xilinx 官方文档均可在 https://docs.amd.com 免费下载。Micron 内存文档在 https://www.micron.com/products/dram 搜索型号获取。


这是《Zynq FPGA 嵌入式系统设计实战》系列第 4 篇。 有问题或者发现数字有误欢迎评论区指出——PS 配置这块细节多,难免疏漏。