3. Vivado硬件设计实战:Block Design设计流程

好,咱们正式开始动手。这一章我会带你走一遍Vivado里Block Design的完整流程。说白了,就是把你脑子里的硬件架构,用图形化的方式搭出来。

我个人习惯,做Zynq项目时,第一步永远是先搭好PS(Processing System)部分。因为DDR、UART这些基础外设,都是挂在PS上的。PS配好了,整个系统的地基才算稳。

3.1 创建Block Design

打开Vivado,创建好工程后,在左侧Flow Navigator里找到IP Integrator,点击Create Block Design。给它起个名字,比如system。

小技巧: 名字别太长,也别用中文。Vivado对中文路径的支持...嗯,你懂的,容易出幺蛾子。

创建完成后,你会看到一个空白的画布。这就是我们搭积木的地方。

3.2 添加Zynq Processing System IP

在画布上右键,选择Add IP,搜索Zynq,双击Zynq7 Processing System。IP核就会出现在画布上。

这时候,你会看到一个绿色的方块,上面标着processing_system7_0。双击它,进入配置界面。这才是重头戏。

3.2.1 配置DDR

配置界面打开后,默认是PS-PL Configuration页面。我们先不看那些复杂的选项,直接点左侧的DDR Configuration。

这里要选你板子上实际用的DDR颗粒。我遇到过不少新手,随便选一个,结果板子跑不起来。你想想看,DDR的时序参数差一点,系统就可能不稳定。

参数 说明 常见值
Memory Type DDR类型 DDR3
Memory Part 具体型号 MT41J256M16 RE-125
Speed Grade 速度等级 -125 (800MHz)
Data Width 数据位宽 16 bit
注意: Memory Part一定要选对。选错了,轻则跑不到最高频率,重则系统直接死机。我曾经在一个项目里,因为选了个接近但不完全一样的型号,排查了整整两天。

选好型号后,其他参数保持默认就行。Vivado会根据你选的型号,自动匹配大部分时序参数。

3.2.2 配置UART

接下来配置UART。在左侧菜单里找到I/O Peripherals,往下翻,找到UART。

Zynq的PS自带两个UART控制器。我们一般用UART1,因为它的引脚默认连到了MIO(Multiplexed I/O)上,不需要额外占用PL的引脚。

  • UART1:勾选上
  • Baud Rate:115200(这是最常用的,调试够用)
  • Data Bits:8
  • Parity:None
  • Stop Bits:1

配置完UART,你会发现左侧的MIO Configuration里,UART1对应的引脚自动被分配到了MIO 48和MIO 49。这就是硬件设计的便利之处——你只需要告诉工具你要用什么功能,它帮你搞定引脚映射。

3.3 自动连线与验证

配置完PS后,点击OK退出。回到Block Design画布,你会看到PS核上多了几个接口。

这时候,Vivado有个很贴心的功能:Run Block Automation。点击画布上方的绿色链接,工具会自动帮你连好DDR、FIXED_IO(包含UART)等必须的接口。

核心逻辑: Block Automation做的事情,就是把PS的MIO/DDR接口,连接到顶层模块的对应端口上。你不需要手动去拉线,省了很多事。

自动连线完成后,你的Block Design应该长这样:

Block Design 核心结构 Zynq PS Processing System DDR + UART DDR3 MT41J256M16 UART 115200 8N1 PS通过内部硬核控制器直接管理DDR和UART 不需要额外PL逻辑,节省资源

3.4 创建顶层HDL封装

Block Design搭好后,我们需要把它变成一个可综合的HDL模块。在Sources面板里,右键你的Block Design(system.bd),选择Create HDL Wrapper。

Vivado会问你要不要自动管理这个Wrapper。我建议选Let Vivado manage wrapper and auto-update。这样以后你修改了Block Design,Wrapper会自动同步,省心。

生成的顶层文件大概长这样:

module system_wrapper
   (DDR_addr,
    DDR_ba,
    DDR_cas_n,
    DDR_ck_n,
    DDR_ck_p,
    DDR_cke,
    DDR_cs_n,
    DDR_dm,
    DDR_dq,
    DDR_dqs_n,
    DDR_dqs_p,
    DDR_odt,
    DDR_ras_n,
    DDR_reset_n,
    DDR_we_n,
    FIXED_IO_ddr_vrn,
    FIXED_IO_ddr_vrp,
    FIXED_IO_mio,
    FIXED_IO_ps_clk,
    FIXED_IO_ps_porb,
    FIXED_IO_ps_srstb);
   // ... 端口声明和内部连线
endmodule

看到没?DDR和UART的引脚都自动映射到了顶层端口。你不需要手动写任何连线代码。

3.5 综合与实现

现在,我们可以跑一下综合(Synthesis)看看有没有语法错误。在Flow Navigator里点击Run Synthesis。

综合完成后,打开Schematic,你可以看到整个设计的网表。嗯,其实就是PS核加上一些必要的I/O缓冲器。因为目前我们还没加PL逻辑,所以设计很简单。

个人经验: 我习惯在综合后先检查一下I/O Ports,确认DDR和UART的引脚分配是否正确。这一步能提前发现不少问题,比如引脚冲突或者电平标准不匹配。

如果综合通过,就可以跑实现(Implementation)了。实现完成后,生成比特流(Generate Bitstream)。

到这里,一个最基本的Zynq硬件平台就搭建好了。它包含了:

  • 一个能跑Linux或裸机程序的ARM Cortex-A9处理器
  • 512MB或1GB的DDR3内存(取决于你的板子)
  • 一个UART串口,用于打印调试信息

这个平台虽然简单,但它是所有后续开发的基础。你想想看,没有DDR,程序往哪跑?没有UART,你怎么看打印信息?

本章核心: Block Design的本质,是把复杂的硬件配置图形化、自动化。你只需要关注“我要什么功能”,而不是“我怎么连这些线”。这就是IP Integrator存在的意义。

好,硬件平台搭好了。下一件事,就是导出硬件描述文件,交给SDK去写软件。不过那是后面章节的内容了。先把这一步练熟,多建几个工程试试不同的DDR配置,你会越来越有感觉。