本文主要演示针对Petalinux 基础功能的 Vivado 硬件工程搭建
- 实验内容适用于市面上功能正常的EBAZ4205的板子
- 本次实验需要连接本站点的EBAZ4205转接板
- 本次实验需要EBAZ4205主板上焊接TF卡槽
- 本次实验没有用到PL端晶振
- 本文在 vivado2018.3版本上演示
本章节的Petalinux 的基础硬件工程将不再细分每一个功能模块,而是将Petalinux 可能用到的基础功能包括 UART,网络NET,SD,FLASH,LED 和按键等基础功能都一并进行添加,来方便大家在最短的时间内将Petalinux的基础功能跑起来。 等熟悉这个流程后,大家就可以在这个工程的基础上再进行其他功能的二次开发了。(本系统将从 TF 卡启动,并包含文件系统。这样,即使在断电后,文件系统的修改也能得到保存)
本次基础工程将添加下列硬件功能:
- 256MB DDR设置
- NAND FLASH
- SD
- UART (EMIO)
- Emio X8 (LED X3 , KEY X5)
- 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) 选择芯片型号 我们板子上用的芯片是XC7Z010 ,并在列表栏中选择对应的封装型号,完整型号是XC7Z010CLG400-1 如下所示,选中后点NEXT

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,本实验所用到型号:MT41K128M16JT 125,数据位宽选择16bit 最后点击“OK”,如下图所示。

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

6) 为系统添加Nand flash 功能

对nand 参数进行设置 ( SMC )

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方式

10)添加UART的功能
下图是以EMIO 方式为示例:

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

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

14)因为网络部分EBAZ4205主板分两种类型 (分别对应不同的批次)
- 一种是网络部分自带了25M 无源晶振来为网络芯片提供时钟(对应下图的1)
- 一种是没有无源晶振,但是网络芯片时钟通过一个0欧电阻和ZYNQ的U18脚相连的(对应下图的2)

对应第一种情况,我们在ZYNQ芯片的输出端不需要提供额外的时钟,但是对应第二种情况,我们需要额外为网络芯片输出一个25M的时钟。 我们可以在PS端的PLL处添加这个时钟输出(其实两种情况我们都直接输出25M即可,如果板子有外部晶振,那R1485是会被NC的)
将 FCLK_CLK0 由默认的50M 改成25M

15)之后按下OK键完成ZYNQ的配置。回到BD界面
16) 按下 Run Block Automation ,并按下OK键

17) 将我们的EMIO GPIO ,GMII, MDIO,EMIO UART ,FCLK_CLK0 都Make External 引出


因为ZYNQ的PS 是同时支持MII 和RMII的 而MII是8bit 传输 RMII是4Bit传输的, 网上大家的资料都是通过添加Concat来实现位宽的转换,我觉得没必要, 这里就不添加了, 后面将增加一个顶层模块来直接映射低4位的管脚
18)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信号和GPIO_EMIO信号的引出。
ZYNQ_CORE_wrapper u_ZYNQ(
.FCLK_CLK0_0(FCLK_CLK),
.GMII_ETHERNET_0_0_rx_clk(GMII_ETHERNET_rx_clk),
.GMII_ETHERNET_0_0_rx_dv(GMII_ETHERNET_rx_dv),
.GMII_ETHERNET_0_0_rxd(GMII_ETHERNET_rxd_wire),
.GMII_ETHERNET_0_0_tx_clk(GMII_ETHERNET_tx_clk),
.GMII_ETHERNET_0_0_tx_en(GMII_ETHERNET_tx_en),
.GMII_ETHERNET_0_0_txd(GMII_ETHERNET_txd_wire),
.MDIO_ETHERNET_0_0_mdc(MDIO_ETHERNET_mdc),
.MDIO_ETHERNET_0_0_mdio_io(MDIO_ETHERNET_mdio_io),
.UART_0_0_rxd(UART_rxd),
.UART_0_0_txd(UART_txd),
.GPIO_0_0_tri_io(GPIO_EMIO)
);
肯定有人会问 ZYNQ_CORE 里明明有那么多信号,为啥我都留空了只保留了这些信号,其实这里我也偷懒了,因为本章中ZYNQ只添加了一个EMIO外设,而剩下诸如DDR FIX_IO这种信号线因为本身是硬件连接的,所以即使程序例化的时候留空,这些信号线仍然是硬件同外部连接的。当然你也可以将所有的信号添加全。(备注 如果有其他的EMIO 或者AXI 等涉及到和FPGA通讯或者映射的信号,则这里例化的时候必须添加信号上去)
这样我们就在TopModule.v中增加了ZYNQ部分了。 (这里容易产生误区,ZYNQ模块是硬件存在的,并不是实例化凭空出现的,只是通过例化这种方式将PS和顶层模块PL两部分结合在一起了)
完整代码如下:(你也可以根据需求在TopModule中增加自己的内容)
//www.hellofpga.com
`timescale 1ns / 1ps
module TopModule(
inout [7:0]GPIO_EMIO,
output FCLK_CLK,
input GMII_ETHERNET_rx_clk,
input GMII_ETHERNET_rx_dv,
input [3:0]GMII_ETHERNET_rxd,
input GMII_ETHERNET_tx_clk,
output [0:0]GMII_ETHERNET_tx_en,
output [3:0]GMII_ETHERNET_txd,
output MDIO_ETHERNET_mdc,
inout MDIO_ETHERNET_mdio_io,
input UART_rxd,
output UART_txd
);
wire [7:0]GMII_ETHERNET_txd_wire;
wire [7:0]GMII_ETHERNET_rxd_wire;
assign GMII_ETHERNET_rxd=GMII_ETHERNET_rxd_wire[3:0];
assign GMII_ETHERNET_txd=GMII_ETHERNET_txd_wire[3:0];
ZYNQ_CORE_wrapper u_ZYNQ(
.FCLK_CLK0_0(FCLK_CLK),
.GMII_ETHERNET_0_0_rx_clk(GMII_ETHERNET_rx_clk),
.GMII_ETHERNET_0_0_rx_dv(GMII_ETHERNET_rx_dv),
.GMII_ETHERNET_0_0_rxd(GMII_ETHERNET_rxd_wire),
.GMII_ETHERNET_0_0_tx_clk(GMII_ETHERNET_tx_clk),
.GMII_ETHERNET_0_0_tx_en(GMII_ETHERNET_tx_en),
.GMII_ETHERNET_0_0_txd(GMII_ETHERNET_txd_wire),
.MDIO_ETHERNET_0_0_mdc(MDIO_ETHERNET_mdc),
.MDIO_ETHERNET_0_0_mdio_io(MDIO_ETHERNET_mdio_io),
.UART_0_0_rxd(UART_rxd),
.UART_0_0_txd(UART_txd),
.GPIO_0_0_tri_io(GPIO_EMIO)
);
endmodule
代码里还有个功能就是通过下面两句映射PS网络部分 rxd和txd 8位信号线中的低4位的管脚(RMII 只需要4位进行通讯)
assign GMII_ETHERNET_rxd=GMII_ETHERNET_rxd_wire[3:0];
assign GMII_ETHERNET_txd=GMII_ETHERNET_txd_wire[3:0];
四、创建约束文件,并定义管脚
1)Add Source → Add or create constraints 点Next

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

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

在约束文件里面复制下面代码来对输出的GPIO进行管脚。
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports FCLK_CLK]
set_property -dict {PACKAGE_PIN U14 IOSTANDARD LVCMOS33} [get_ports GMII_ETHERNET_rx_clk]
set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports GMII_ETHERNET_rx_dv]
set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {GMII_ETHERNET_rxd[0]}]
set_property -dict {PACKAGE_PIN V16 IOSTANDARD LVCMOS33} [get_ports {GMII_ETHERNET_rxd[1]}]
set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {GMII_ETHERNET_rxd[2]}]
set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {GMII_ETHERNET_rxd[3]}]
set_property -dict {PACKAGE_PIN U15 IOSTANDARD LVCMOS33} [get_ports GMII_ETHERNET_tx_clk]
set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVCMOS33} [get_ports {GMII_ETHERNET_tx_en[0]}]
set_property -dict {PACKAGE_PIN W18 IOSTANDARD LVCMOS33} [get_ports {GMII_ETHERNET_txd[0]}]
set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports {GMII_ETHERNET_txd[1]}]
set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {GMII_ETHERNET_txd[2]}]
set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33} [get_ports {GMII_ETHERNET_txd[3]}]
set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS33} [get_ports MDIO_ETHERNET_mdc]
set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports MDIO_ETHERNET_mdio_io]
set_property -dict {PACKAGE_PIN V20 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[7]]
set_property -dict {PACKAGE_PIN U19 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[6]]
set_property -dict {PACKAGE_PIN U20 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[5]]
set_property -dict {PACKAGE_PIN P19 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[4]]
set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[3]]
set_property -dict {PACKAGE_PIN E19 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[2]]
set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[1]]
set_property -dict {PACKAGE_PIN H18 IOSTANDARD LVCMOS33} [get_ports GPIO_EMIO[0]]
set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports UART_rxd]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports UART_txd]
约束中,我们将GPIO_EMIO2-0 分别对应LED3-LED1 。 GPIO_EMIO7-3 对应按键的KEY5-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中所命名的工程名

至此我们的硬件工程的准备工作已经完成了。
- 本文的完整工程下载 : 01_PetaLinuxSystem
- VIVADO的版本:2018.3