本文主要演示针对Petalinux 基础功能的 Vivado 硬件工程搭建
- 此章节内容适用于下列主板
- Smart ZYNQ SP / SP2 / SL 版的板子(非标准版)(CLG484封装)(本文提供最终工程)
- Smart ZYNQ 标准版(停产) (CLG400封装7010/7020 )本文暂时只提供移植方法
- 本文在 vivado2018.3 以及 Petalinux2018.3 版本上进行演示
本章节的Petalinux 的基础硬件工程将不再细分每一个功能模块,而是将Petalinux 可能用到的基础功能包括 UART,千兆网络NET,USB HOST,SD,FLASH,LED 和按键等基础功能都一并进行添加,来方便大家在最短的时间内将Petalinux的基础功能跑起来。 等熟悉这个流程后,大家就可以在这个工程的基础上再进行其他功能的二次开发了。(本系统将从 TF 卡启动,并包含文件系统。这样,即使在断电后,文件系统的修改也能得到保存)
本次基础工程将添加下列硬件功能:
- 512MB DDR设置
- QSPI FLASH
- SD
- USB (SL不带USB功能)
- UART (SP SP2 SL :EMIO) (标准版:MIO)
- Emio X4 (LED X2 , KEY X2)
- NET (EMIO)
一、Vivado工程创建
1)打开Vivado 新建一个项目, 新建一个VIVADO 工程,打开软件 选中Create Project, 如下图所示

2)点击NEXT ,在出现的第二个对话框“Project name”中输入工程名;在“Project location”中选择保存路径;勾选“Create project subdirectory”(默认),最后点击“Next” 备注,所有的路径均不能出现中文名称

3)点击 RTL PROJECT 选项,点击NEXT

4) 第四步Add Sources 选项直接留空,NEXT
5)第五步Add Constraints 选项直接留空,NEXT
6) 选择芯片型号 (SP/SP2/SL对应的芯片是484封装的, 标准版对应400封装的,选择可以按下列列表选择)
- Smart ZYNQ (SP/SP2/SL) : XC7Z020CLG484-1 (这里可以选-2因为 板子实际贴的是-2)
- Smart ZYNQ 标准版(停产) :XC7Z020CLG400-1 / XC7Z010CLG400-1 (按7010/7020版来选择)
下图以SP SP2 SL的CLG484为例

7)确认所选信息 点击“Finish”,完成vivado的工程创建‘

之后 工程就新建好了, vivado 进入到开发界面

二、创建一个BLOCK设计
1)IP INTEGRATOR→Create Block Design,在弹出的对话框中输入设计名,最后点击“OK”,如下图所示

2) 在右侧的窗口里 ,点击加号,在选择框里搜索ZYNQ,并找到ZYNQ7 PROCESSING SYSTEM ,双击并打开

3)软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核

4)依次在弹窗里找到DDR Configuration→DDR Controller Configuration→DDR3,在Memory Part下拉菜单中根据自己板子上的DDR来选择相应的DDR3,本实验所用到型号:MT41K256M16RE-125,数据位宽选择16bit 最后点击“OK”,如下图所示。

5)因为我们Smart ZYNQ主板的PS时钟是33.33M的晶振输入的,所以这里保留默认设置就好(不需要修改 ,保留默认即可)

6)使能QSPI的功能 如下图所示(当QSPI 时钟大于40MHZ的时候 就需要勾选Feedback clk)

7) 因为我们的USB功能,SD功能能都是接在芯片的BANK501上的,而bank501在硬件上接的3.3Vbank电压,所以这里我们保留ZYNQ的BANK1(501) I/O 电压为默认的LVCMOS 3.3V。(不需要修改 ,保留默认即可)

8)使能SD 0的功能 MIO40-45

9) 使能 ENET0 和 MDIO 功能, 因为我们的Smart ZYNQ主板 网络是接在PL端,所以这里ENET和MDIO的引出方式请选择EMIO方式 (下文中还要添加RGMII2GMII模块)

10)使能zynq的USB0功能 (备注SL的主板不带USB功能,但是这里一块使能没有任何问题,)

另外 由于我们的USB PHY的信号是接在mio的46脚上 所以这里同样需要使能 MIO的USB RST信号(系统同时会默认勾选I2C复位 ,可以关闭)

11)添加UART的功能(这里各个主板设置会有区别)
- Smart ZYNQ SP / SP2 / SL 版的板子: 使能UART 0 并在IO选项里 选择EMIO方式
- Smart ZYNQ 标准版(停产):使能UART 0 并在IO选项里 选择MIO方式,下拉菜单里选择MIO50-51
下图是以EMIO 方式为示例:(MIO方式也在该页面修改,修改IO对应的选项即可)

12) 到这里,ZYNQ内核就已经按照我们的预设配置好了,接下来按照我们的预期添加4个IO口,用于2个LED灯,和2个按键,作实验用。

13 )因为工程暂时用不到 AXI功能,所以可以先禁用AXI功能

14)之后按下OK键完成ZYNQ的配置。回到BD界面
15)增加GMII 2 RGMII 网络转接模块
由于 ZYNQ的PS 调用EMIO方式 默认输出是GMII,而我们的网络部分的芯片 RTL8211是 输出RGMII的,所以这里我们需要增加一个 GMII和RGMII转换的IP模块 (Gmii to Rgmii)

打开 GMII TO RGMII模块 设置更改成下面


又因为GMII TO RGMII 是高电平复位 ,但是ZYNQ 是输出低电平复位的,所以这里需要增加一个反相器(搜索utility, 在检索出来的选项里 选择 utility vector logic)

在设置页里改成 not(反相器)将位宽改成1

按下图方式连接好各个模块(复位 时钟 网络)

并通过右键 然后选择Make external 的方式引出RGMII 和MDIO_PHY功能引脚

这里还要对Z7的模块进行一个修改,因为gmii to rgmii 模块的clkin 在手册上写要求是200mhz,所以我们这里需要对ZYNQ核的输出时钟频率进行修改

重新双击ZYNQ的核,将FCLK_CLK0的频率改成200

到这里gmii to rgmii部分添加完成。
16) 按下 Run Block Automation ,并按下OK键

17) 将我们的EMIO GPIO 通过 External 的方式映射出来,右键 External


18)将我们的UART IO 映射出来,对EMIO UART进行 External 引出 (如果上文中是MIO UART的就不需要进行此步骤)
- EMIO UART的主板(需要此步骤) :Smart ZYNQ SP / SP2 / SL 版
- MIO UART的主板(不需要此步骤): Smart ZYNQ 标准版(停产)
( 右键 UART_0选中Make External 引出UART信号接口 )

19)source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper如下图所示。

19)在弹出的对话框里保持默认

20)软件自动为我们生成HDL文件

至此,Block Design 部分已经设置完成。
三、添加我们的FPGA部分顶层TOP_module代码,并例化ZYNQ模块
其实这里我们不增加顶层模块,直接编译综合也是可以,但是考虑到我们的工程后续可能会添加PL部分(即FPGA)的代码,所以这里我们还是增加了顶层模块。
1)在主界面点击左侧 Add Sources ,点击 复选框的Add or create design sources 选项 并点击NEXT

2)在出现的Add Sources 中 选择创建新文件 Create FILE 如下图所示,并在弹出的窗口中 选择类别为Verilog ,在FILE name中填写文件的名称,这里用TopModule代替,点击OK 并点击FINISH
3)在跳出的窗口中可以填写模块的输入输出信号,由于这部分工作在代码中可以完成,所以这里直接点OK 完成VERILOG 文件的创建。
4)双击打开刚才创建的TopModule文件 ,这里我们可以添加我们的FPGA代码,如点灯代码等,这里我们暂时不在工程中添加任何其他功能,所以我们只需要对刚刚定义的Block design中创建的ZYNQ模块进行例化即可。
5) 在TopModule程序中例化ZYNQ模块
打开刚才的TopModule.v,并在 endmodule的 上方添加ZYNQ_CORE 例化的代码,以及在模块定义上添加网络信号,如果UART是EMIO的,还需要添加UART信号(如果UART是MIO的,则不需要添加),还需要增加GPIO_EMIO信号的引出。
ZYNQ_CORE_wrapper zynq_u(
.GPIO_0_0_tri_io(GPIO_EMIO),
.MDIO_PHY_0_mdc(MDIO_PHY_mdc),
.MDIO_PHY_0_mdio_io(MDIO_PHY_mdio_io),
.RGMII_0_rd(RGMII_rd),
.RGMII_0_rx_ctl(RGMII_rx_ctl),
.RGMII_0_rxc(RGMII_rxc),
.RGMII_0_td(RGMII_td),
.RGMII_0_tx_ctl(RGMII_tx_ctl),
.RGMII_0_txc(RGMII_txc),
.UART_0_0_rxd(UART_rxd),
.UART_0_0_txd(UART_txd)
);
肯定有人会问 ZYNQ_CORE 里明明有那么多信号,为啥我都留空了只保留了这些信号,其实这里我也偷懒了,因为本章中ZYNQ只添加了一个EMIO外设,而剩下诸如DDR FIX_IO这种信号线因为本身是硬件连接的,所以即使程序例化的时候留空,这些信号线仍然是硬件同外部连接的。当然你也可以将所有的信号添加全。(备注 如果有其他的EMIO 或者AXI 等涉及到和FPGA通讯或者映射的信号,则这里例化的时候必须添加信号上去)
这样我们就在TopModule.v中增加了ZYNQ部分了。 (这里容易产生误区,ZYNQ模块是硬件存在的,并不是实例化凭空出现的,只是通过例化这种方式将PS和顶层模块PL两部分结合在一起了)
完整代码如下:(你也可以根据需求在TopModule中增加自己的内容)
代码分SP/SP2/SL 和标准版两种, SP/SP2/SL是EMIO UART的, 标准版是MIO UART的
//EMIO UART
`timescale 1ns / 1ps
module TopModule(
inout [3:0]GPIO_EMIO,
output MDIO_PHY_mdc,
inout MDIO_PHY_mdio_io,
input [3:0]RGMII_rd,
input RGMII_rx_ctl,
input RGMII_rxc,
output [3:0]RGMII_td,
output RGMII_tx_ctl,
output RGMII_txc,
input UART_rxd,
output UART_txd
);
ZYNQ_CORE_wrapper zynq_u(
.GPIO_0_0_tri_io(GPIO_EMIO),
.MDIO_PHY_0_mdc(MDIO_PHY_mdc),
.MDIO_PHY_0_mdio_io(MDIO_PHY_mdio_io),
.RGMII_0_rd(RGMII_rd),
.RGMII_0_rx_ctl(RGMII_rx_ctl),
.RGMII_0_rxc(RGMII_rxc),
.RGMII_0_td(RGMII_td),
.RGMII_0_tx_ctl(RGMII_tx_ctl),
.RGMII_0_txc(RGMII_txc),
.UART_0_0_rxd(UART_rxd),
.UART_0_0_txd(UART_txd)
);
endmodule
//MIO UART
`timescale 1ns / 1ps
module TopModule(
inout [3:0]GPIO_EMIO,
output MDIO_PHY_mdc,
inout MDIO_PHY_mdio_io,
input [3:0]RGMII_rd,
input RGMII_rx_ctl,
input RGMII_rxc,
output [3:0]RGMII_td,
output RGMII_tx_ctl,
output RGMII_txc
);
ZYNQ_CORE_wrapper zynq_u(
.GPIO_0_0_tri_io(GPIO_EMIO),
.MDIO_PHY_0_mdc(MDIO_PHY_mdc),
.MDIO_PHY_0_mdio_io(MDIO_PHY_mdio_io),
.RGMII_0_rd(RGMII_rd),
.RGMII_0_rx_ctl(RGMII_rx_ctl),
.RGMII_0_rxc(RGMII_rxc),
.RGMII_0_td(RGMII_td),
.RGMII_0_tx_ctl(RGMII_tx_ctl),
.RGMII_0_txc(RGMII_txc)
);
endmodule
四、创建约束文件,并定义管脚
1)Add Source → Add or create constraints 点Next

因为这个项目没有创建过约束文件 所以这里创建一个约束文件,并在File name 里设置约束文件的名称,并且点击FINISH 完成约束文件的创建

2)Sources → Constraints 里找到刚才创建的约束文件 双击并打开该XDC约束文件

在约束文件里面复制下面代码来对输出的GPIO进行管脚。
- 管脚约束:
- Smart ZYNQ SP/SP2/SL : 可直接复制下面约束内容
- Smart ZYNQ 标准版 : 实际的原理图管脚定义进行修改,另外标准版UART是MIO的,所以约束中请删除UART引脚部分
set_property -dict {PACKAGE_PIN J20 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[3]]
set_property -dict {PACKAGE_PIN K21 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[2]]
set_property -dict {PACKAGE_PIN P21 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[1]]
set_property -dict {PACKAGE_PIN P20 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[0]]
set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS33} [get_ports UART_rxd]
set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports UART_txd]
set_property -dict {PACKAGE_PIN G21 IOSTANDARD LVCMOS33} [get_ports MDIO_PHY_mdc]
set_property -dict {PACKAGE_PIN H22 IOSTANDARD LVCMOS33} [get_ports MDIO_PHY_mdio_io]
set_property -dict {PACKAGE_PIN A22 IOSTANDARD LVCMOS33} [get_ports {RGMII_rd[0]}]
set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports {RGMII_rd[1]}]
set_property -dict {PACKAGE_PIN A19 IOSTANDARD LVCMOS33} [get_ports {RGMII_rd[2]}]
set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {RGMII_rd[3]}]
set_property -dict {PACKAGE_PIN A21 IOSTANDARD LVCMOS33} [get_ports RGMII_rx_ctl]
set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports RGMII_rxc]
set_property -dict {PACKAGE_PIN E21 IOSTANDARD LVCMOS33} [get_ports {RGMII_td[0]}]
set_property -dict {PACKAGE_PIN F21 IOSTANDARD LVCMOS33} [get_ports {RGMII_td[1]}]
set_property -dict {PACKAGE_PIN F22 IOSTANDARD LVCMOS33} [get_ports {RGMII_td[2]}]
set_property -dict {PACKAGE_PIN G20 IOSTANDARD LVCMOS33} [get_ports {RGMII_td[3]}]
set_property -dict {PACKAGE_PIN G22 IOSTANDARD LVCMOS33} [get_ports RGMII_tx_ctl]
set_property -dict {PACKAGE_PIN D21 IOSTANDARD LVCMOS33} [get_ports RGMII_txc]
set_property SLEW FAST [get_ports {RGMII_td[0]}]
set_property SLEW FAST [get_ports {RGMII_td[1]}]
set_property SLEW FAST [get_ports {RGMII_td[2]}]
set_property SLEW FAST [get_ports {RGMII_td[3]}]
set_property SLEW FAST [get_ports RGMII_tx_ctl]
set_property SLEW FAST [get_ports RGMII_txc]
create_clock -period 8 -name RGMII_rxc [get_ports RGMII_rxc]
约束中,我们将GPIO_EMIO1-0 分别对应LED2-LED1 。 GPIO_EMIO3-2 对应按键的KEY2-KEY1。 后续实验中我们将会用到。
五、编译综合,并导出hdf文件
1)按下绿色箭头对工程进行编译

2)按下Generate Bitstream 完成综合以及生成bit文件 (需要等待很久)

3)File→Export→Export hardware…在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。


4)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。

5) 系统将自动打开SDK开发环境

其中SDK工程platform 下的hdf文件就是我们需要的系统硬件描述文件,这个需要交给petalinux 进行交叉编译用。(可以在这个界面下直接右键system.hdf进行复制)

备注:如果不打开SDK工程文件我们仍能找到这个hdf文件。一般在 下列路径中
<project_name>.sdk<project_name>_wrapper.hdf
其中<project_name>为你在Vivado中所命名的工程名

至此我们的硬件工程的准备工作已经完成了。
下列工程适用于SP/SP2/SL, 如果是标准版的硬件,请
- 本文的完整工程下载:
- Smart ZYNQ SP / SP2 /SL :01_PetaLinuxSystem
- Smart ZYNQ 标准版 ( 停产 ) :本文暂不提供,大家请根据本文内容自行生成
- VIVADO的版本:2018.3
- 工程创建目录:E:\Smart_ZYNQ_SP_SL\PETALINUX\01_PetaLinuxSystem