3. Vivado Block Design 搭建 PS 与 PL 通信工程

好,咱们正式开始动手。这一章的目标很明确——把 Vivado 工程建起来,把 Zynq 的 PS 核拖进 Block Design,再把 M_AXI_GP0 接口配通。说白了,就是给 PS 和 PL 之间铺一条能跑数据的高速公路。

我记得刚接触 Zynq 那会儿,总觉得 Block Design 就是个画图工具。后来踩了几次坑才明白——这玩意儿背后生成的每一根线,都是实实在在的硬件连接。你画错了,板子就跑不起来。

3.1 创建 Vivado 工程

打开 Vivado 2020.1 或更新的版本。我个人习惯用 2020.1,稳定,坑少。

  1. 点击 Create Project → Next
  2. Project name:填 zynq_axi_gpio_demo
  3. Project location:选个路径,别带中文和空格
  4. RTL Project:勾上 Do not specify sources at this time
  5. Part:选你的板子型号。我这边用 xc7z020clg400-1(Zybo Z7-20)
小提示:如果你用的是其他板子,比如 ZedBoard 或 MicroZed,Part 选对应的就行。PS 侧的配置基本通用,差别主要在 DDR 型号和时钟频率上。

点 Finish,工程就建好了。嗯,这一步没啥技术含量,但路径别搞错——我见过有人把工程放在桌面,结果跑综合时路径太长报错。

3.2 添加 Zynq PS 核

工程建好后,咱们开始搭 Block Design。

  1. 点击左侧 Flow Navigator 里的 Create Block Design
  2. Design name 填 system,OK
  3. 在 Diagram 窗口空白处右键 → Add IP
  4. 搜索 Zynq,双击 Zynq 7 Processing System

这时候你会看到一个灰色的方块出现在画布上,上面标着 processing_system7_0。别急着连线——先双击它,进配置界面。

配置界面分好几页,咱们先配最关键的几项:

配置项 推荐值 说明
PS-PL Configuration 勾选 M_AXI_GP0 PS 主接口,用于访问 PL
Clock Configuration CPU_6x4x = 666.666 MHz PS 主频,别乱改
DDR Configuration 按板子型号选 DDR 型号必须匹配硬件
Peripheral I/O Pins UART 1 → MIO 48/49 串口打印用
注意:DDR 配置这块最容易翻车。我曾经帮一个同事排查问题,折腾了两天,最后发现是 DDR 型号选错了——板子上是 MT41K256M16,他配成了 MT41J256M16。就差一个字母,系统死活起不来。

配好之后点 OK,回到 Diagram 窗口。你会看到 PS 核上多了几个接口——M_AXI_GP0 就是咱们这次要用的。

3.3 配置 M_AXI_GP0 接口

M_AXI_GP0 是 PS 侧的一个 32 位 AXI 主接口。它负责把 PS 的读写请求发到 PL 侧。说白了,PS 想读 PL 里的寄存器,或者往 PL 写数据,都得走这条路。

咱们来看看它的具体配置:

  • 接口类型:AXI4(不带 AXI-Stream)
  • 数据位宽:32 位
  • 地址位宽:32 位
  • 最大突发长度:16
  • 时钟域:默认与 PS 的 FCLK_CLK0 同步

这些参数在 Block Design 里不用手动改——Vivado 会根据你选的 IP 自动匹配。但你要心里有数:GP0 接口的性能上限大概在 600 MB/s 左右(32bit × 150MHz)。够用,但别指望它跑 4K 视频流。

核心要点:M_AXI_GP0 是 PS 主动发起的 AXI 事务。PL 侧不需要主动发起请求,只需要响应 PS 的读写操作。这个“主-从”关系一定要搞清楚。

3.4 自动连接与验证

配好 PS 核之后,咱们加一个 AXI GPIO IP 来验证通信。

  1. 右键 → Add IP → 搜索 AXI GPIO
  2. 双击 AXI GPIO,配置:
    • GPIO Width:4
    • All Outputs:勾上
  3. 点击 Diagram 上方的 Run Block Automation
  4. Vivado 会自动连好 M_AXI_GP0 和 AXI GPIO 之间的 AXI 总线

连好之后,你的 Block Design 应该长这样:

Block Design 结构图 Zynq PS processing_system7_0 M_AXI_GP0 32bit AXI4 Master FCLK_CLK0: 100MHz AXI4 AXI GPIO axi_gpio_0 GPIO Width: 4 All Outputs S_AXI Slave LED[3:0] 外部引脚 数据流向: PS (M_AXI_GP0) → AXI4 总线 → AXI GPIO (S_AXI) → LED 引脚 PS 通过读写 AXI GPIO 的寄存器来控制 LED 亮灭

看到这个结构图,你应该能理解:PS 通过 M_AXI_GP0 发 AXI 事务,AXI GPIO 作为从设备响应。整个过程不需要 PL 逻辑参与——说白了,这就是 PS 直接操作外设。

3.5 生成顶层与导出硬件

Block Design 画好后,还有几步收尾工作:

  1. Validate Design:右键 Block Design → Validate Design。没报错就继续。
  2. Create HDL Wrapper:在 Sources 窗口右键 system.bd → Create HDL Wrapper → Let Vivado manage wrapper
  3. Generate Bitstream:点击 Flow Navigator 里的 Generate Bitstream

综合和实现需要几分钟。趁这个时间,我多说一句:第一次跑 Bitstream 时,如果报错说 Unconstrained path,别慌。八成是没加约束文件。咱们后面会专门讲时序约束,这里先跳过。

经验之谈:Bitstream 生成成功后,记得点 File → Export → Export Hardware,勾上 Include Bitstream。这个 .xsa 文件是后面 SDK/Vitis 工程的基石。我见过有人忘了勾,结果在 SDK 里死活找不到硬件描述。

3.6 本章小结

到这一步,你已经完成了:

  • 创建 Vivado 工程
  • 添加并配置 Zynq PS 核
  • 使能 M_AXI_GP0 接口
  • 添加 AXI GPIO 并自动连接
  • 生成 Bitstream 并导出硬件

嗯,看起来步骤不多,但每一步都有坑。尤其是 DDR 配置和时钟设置——这两块出问题,板子根本跑不起来。我建议你做完后,先跑个空的 SDK 工程验证一下 PS 能不能正常启动,再往下走。