3、创建zynq最小嵌入式系统
1、简介
首先我们来了解一下 ZYNQ 嵌入式系统的开发流程。
如上图所示,开发流程大体可以分为 6 步。其中 step1 至 step4 为硬件设计部分,在 Vivado 软件中实现;step5 为软件设计部分,在 SDK 软件中实现; step6 为功能的验证。复杂的程序还涉及 Debug,这个也是在SDK 软件中实施。
在简单了解 ZYNQ 嵌入式系统的开发流程后,接下来我们来看一下什么是 ZYNQ 嵌入式最小系统。ZYNQ 嵌入式最小系统的概念包括以下两个方面:它是使系统正常工作的最小条件;它是其他系统建立的基础。
如上图 所示,以 ARM Cortex-A9 为核心、 DDR3 为内存,加上传输信息使用的 UART 串口就构成了 ZYNQ 嵌入式最小系统。可以看到,这个最小系统只包括了 ZYNQ 中的 PS 部分。
首先我们程序会加载到DDR内存中,然后CPU一条一条执行,那么执行的情况我们可以通过串口打印观察。
下面我们将按照 ZYNQ 嵌入式系统开发流程,一步步的搭建上图所示的最小系统。
2、搭建最小嵌入式系统
2.1、step1:创建 Vivado 工程
2.2、step2:使用 IP Integrator 创建 Processing System
Vivado 开发套件中提供了一个图形化的设计开发工具——IP 集成器( IP Integrator) ,在 IP 集成器中可以非常方便的插入各种功能模块( IP) 。它支持关键 IP 接口的智能自动连接、一键式 IP 子系统生成、实时 DRC 等功能, 能够帮助我们快速组装复杂系统, 加速设计流程。
接下来我们将在 IP 集成器中完成 ZYNQ 嵌入式系统的搭建。
(1)在左侧导航栏( Flow Navigator)中,单击 IP Integrator 下的 Create Block Design。然后在弹出的对话框中指定所创建的 Block Design 的名称,在 Design name 栏中输入“ system”。如下图所示:
(2)点击“OK”按钮,此时 Vivado 界面如下图所示。注意右侧的 Diagram 窗口, 我们将在该窗口中以图形化的方式完成设计。
(3)接下来在 Diagram 窗口中给设计添加 IP。点击上图中箭头所指示的加号“ +” , 会打开 IP 目录( IPCatalog) 。也可以通过快捷键 Ctrl + I,或者右键点击 Diagram 工作区中的空白位置,然后选择“ ADD IP”。
(4)打开 IP 目录后,在搜索栏中键入“ zynq”,找到并双击“ ZYNQ7 Processing System”,将 ZYNQ7处理系统 IP 添加到设计中。
(5)添加完成后, ZYNQ7 Processing System 模块出现在 Diagram 中,如下图所示:
(6)双击所添加的 ZYNQ7 Processing System 模块,进入 ZYNQ7 处理系统的配置界面。界面左侧为页面导航面板,右侧为配置信息面板。 如下图所示:
下面我们简要地介绍一下页面导航面板中各个页面的作用:
在 Zynq Block Design 页面,显示了 Zynq 处理系统( PS)的各种可配置块,其中灰色部分是固定的,绿色部分是可配置的,按工程实际需求配置。可以直接单击各种可配置块(以绿色突出显示)进入相应的配置页面进行配置,也可以选择左侧的页导航面板进行系统配置。
PS-PL Configuration 页面能够配置 PS-PL 接口,包括 AXI、 HP 和 ACP 总线接口。
Peripheral IO Pins 页面可以为不同的 I/O 外设选择 MIO/EMIO 配置。
MIO Configuration 页面可以为不同的 I/O 外设具体配置 MIO/EMIO。
Clock Configuration 页面用来配置 PS 输入时钟、外设时钟,以及 DDR 和 CPU 时钟等。
DDR Configuration 页面用于设置 DDR 控制器配置信息。
SMC Timing Calculation 页面用于执行 SMC 时序计算。
Interrupts 页面用于配置 PS-PL 中断端口。
这里使用的是最小系统,我们需要做的就是修改时钟频率,内存类型和接口输出。 需要注意的是,如果时钟频率与内存类型与我们的硬件不一致时, SDK中的程序会崩溃,运行不过来。在后续的调试中, 如果遇到程序奔溃的情况需要检查下你的DDR型号,以及时钟频率。
1)配置 PS 的时钟
PS 输入时钟频率: 33.333333MHZ,根据开发板上晶振的频率设置。
CPU PLL时钟: 666.666666MHZ(这个时钟对于MZ7035系列最大可以设置800MHZ)。
PL Fabric Clocks-FCLK_CLK0: 100MHZ 这个时钟可以用于提供给PLL使用。
点击左侧的 Clock Configuration 页面,该界面主要是配置ZYNQ PS 中的时钟频率。比如输入时钟默认是 33.33333Mhz,这与我们开发板上的 PS 端输入时钟频率相同。对于 CPU 的时钟、 DDR 的时钟以及其它外设的时钟, 我们直接保持默认设置即可。如下图所示:
注意:如果搭建 ZYNQ 的嵌入式最小系统只需要使用 ZYNQ 中的 PS 端,不需要PL端时,我们就将 PS 中与 PL 端交互的接口信号移除。
同样是在 Clock Configuration 页面,展开 PL Fabric Clocks,取消勾选 FCLK_CLK0,如下图所示:
点击左侧的 PS-PL Configuration 页面,然后在右侧展开 General 下的 Enable Clock Resets, 取消勾选其中的 FCLK_RESET0_N,如下图所示:
另外在当前界面中展开 AXI Non Secure Enablement 下的 GP Master AXI Interface,取消勾选其中的 MAXI GP0 interface,如下图所示:
2)PS DDR3内存配置
点击左侧的 DDR Configuration 页面,在右侧 DDR Controller Configuration 下的“ Memory Part”一栏选择 DDR 的器件,MZ7035 系列 PS 端的内存为 1GB,选取内存型号(兼容型号): MT41K256M16 RE-125。需要注意的是,我们在这里选择的型号并不是开发板上的 DDR3 型号,而是参数接近的型号,或者说兼容的型号。其他的配置选项保持默认即可。
3)、串口配置
配置 PS 的 UART。点击 Peripheral I/O Pins 页面,出现以下 IO 引脚配置界面。
PS 和外部设备之间的连接主要是通过复用的输入/输出( Multiplexed Input/Output, MIO)来实现的。PS 的54 个MIO 引脚可以用于连接不同的外设接口,如图 中的MIO48 和MIO49,既可以配置成UART1的引脚接口,也可以配置成 I2C1 或 CAN1的引脚接口。最终所选择的配置需要与领航者开发板的原理图相对应。
如下图所示,我们在 MIO48和 MIO49下点击 UART1,方框的颜色会变成绿色, 与此同时这两个 MIO也会变成绿色。这就表明 MIO48 和 MIO49 被配置成了 UART 接口引脚, 它们与 PS 中的串口电路 UART1相连接。
点击左侧的 MIO Configuration 页面,在右侧展开 I/O Peripherals > UART1,可以看到更具体的引脚配置信息。其中 MIO49 作为 RX 引脚、 MIO48 作为 TX 引脚, 如下图所示:
点击左侧的 PS-PL Configuration 页面,我们可以在这里设置 UART1 串口通信的波特率。在 General 目录下,可以看到 UART1 的波特率默认是 115200。通过下拉按钮可以选择其他波特率, 一般保持默认设置。
(7)配置 ZYNQ7 Processing System 完成,点击“ OK”。
注意:如果是只使用PS部分,在配置完后返回到Vivado 界面后,在 Diagram中可以看到 ZYNQ7 Processing System IP 模块发生了变化, 如下图所示。 我们将其与上图作对比可以发现, ZYNQ7 PS 模块少了四个接口,这正是因为我们在配置 ZYNQ7PS 的过程中移除了与 PL 相关的接口信号。
(8)完成配置后, 可以自动连线, 让软件自动引出接口
我们点击上图中箭头所指示的位置“Run Block Automation”,会弹出如下图所示的对话框:
在该界面中我们可以选择自动连接 IP 模块的接口, 包括导出外部端口,甚至可以自动添加模块互联过程中所需的 IP。 在我们本次设计中只有一个 IP 模块, 在左侧确认勾选 processing_system7_0,然后点击“ OK”。
此时 ZYNQ7 PS 模块引出了两组外部接口,分别是 DDR 和 FIXED_IO, 引出的接口将会被分配到 ZYNQ器件具体的引脚上。大家也可以通过点击 ZYNQ7 PS 模块接口处的加号“+”, 来展开这两组接口,观察其中都有哪些信号。 如下图所示:
(9)在Block文件中,我们进行连线,将鼠标放在引脚处,鼠标变成铅笔后进行拖拽,连线如下图所示。连线的作用就是把PS的时钟可以接入PL部分。
(10)本次实验不需要添加其它 IP,直接按快捷键 Ctrl+S 保存当前设计。接下来点击下图所指示的按钮,验证当前设计。验证完成后弹出对话框提示没有错误或者关键警告, 点击“ OK”, 如下图所示:
如果验证结果报出错误或者警告,大家需要重新检查自己的设计。
(11)如果连线比较混乱,可以点击右键,选择Regenerate Layout,如下图所示:
(3)step3:生成顶层 HDL 模块
1)在 Sources 窗口中,选中 Design Sources 下的 sysetm.bd, 这就是我们刚刚完成的 Block Design 设计。右键点击 sysetm.bd,在弹出的菜单栏中选择“ Generate Output Products”,如下图所示:
2)在对话框中 Synthesis Options 选择 Global
Run Setings 用于设置生成过程中要使用的处理器的线程数,进行多线程处理, 保持默认或设置为个人电脑处理器最大可使用线程数都可以,一般选择最大可使用线程数的一般。然后点击“Generate”来生成设计的综合、实现和仿真文件。
在“ Generate”过程中会为设计生成所有需要的输出结果。 比如 Vivado 工具会自动生成处理系统的 XDC约束文件,因此我们不需要手动对 ZYNQ PS 引出的接口( DDR 和 FIXED_IO) 进行管脚分配。
Generate 完成后,在弹出的对话框中点击“ OK”。
在 Sources 窗口中, 点击“ IP Source”标签页, 可以看到 Generate 过程生成的输出结果。
3) 在“ Hierarchy”标签页再次右键点击 system.bd,然后选择“Create HDL Wrapper”。
在弹出的对话框中确认勾选“Let vivado manager wrapper and auto-update(自动更新)”, 然后点击“ OK”。
创建完成后, Design Sources 结构如下图所示:
system_wrapper.v 为创建的 Verilog 文件, “ 品” 字形图标指示当前模块为顶层模块。 该模块使用 Verilog HDL 对设计进行封装, 主要完成了对 block design 的例化, 大家也可以双击打开该文件查看其中的内容。
另外我们在“Create HDL Wrapper”中勾选了“Let vivado manager wrapper and auto-update(自动更新)”, 这样我们在修改了 Block Design 之后就不需要再重新生成顶层模块, Vivado 工具会自动更新该文件。
2.4、step4:生成 Bitstream 文件并导出到 SDK
如果设计中使用了 PL 的资源,则需要添加引脚约束并对该设计进行综合、实现并生成 Bitstream 文件。
在左侧 Flow Navigator 导航栏中找到 PROGRAM AND DEBUG, 点击该选项中的“Generate Bitstream”,然后在连续弹出的对话框中依次点击“YES”、 “OK”。 此时, Vivado 工具开始对设计进行综合、 实现、并生成 Bitstream 文件。生成 Bitstream 完成后, 在弹出的对话框中选择“Open Implemented Design”, 如下图所示:
如果实验未用到 PL 部分,所以无需生成 Bitstream 文件,只需将硬件导出到 SDK 即可。
(1)导出硬件
在菜单栏选择 File > Export > Export hardware。
在弹出的对话框中,如果没有使用PL部分,即没有生成 bitstream 文件,就无需勾选“ Include bitstream”,直接点击“ OK” 按钮。如果使用了PL部分,就勾选“ Include bitstream”,然后点击“ OK” 按钮。
在上图中, 因为选择了“Exort to <Local to Project>”, Vivado 工具会在当前工程目录下新建一个文件夹,名为“zynq7000.sdk”, 它是我们接下来软件开发的工作空间。
在 Export Hardware 的过程中, 工具会将硬件以一个 ZIP 压缩文件的形式导出到该工作空间中, 文件名为“system_wrapper.hdf”。该文件包含了我们前面所搭建的硬件平台的配置信息, 其后缀名.hdf 的含义为“Hardware Definition File”, 即硬件定义文件。
(2)硬件导出完成后,在菜单栏中选择 File > Launch SDK,启动 SDK 开发环境。如下图所示:
在弹出对话框中,直接点击“ OK”, 如下图所示:
到这里,我们已经完成了 ZYNQ 嵌入式系统的硬件设计部分。接下来需要到 SDK 软件中进行应用程序开发,也就是软件设计部分。
在硬件设计的最后,我们启动了软件开发环境( SDK, Software Development Kit),如下图所示:
SDK 打开后, 主页面会显示硬件描述文件 system.hdf 的内容。如上图所示, system.hdf 标签页显示了整个 PS 系统的地址映射信息。
大家应该还记得, 在启动 SDK 之前,我们将硬件以一个 ZIP 压缩文件( system_wrapper.hdf) 的形式导出到软件的工作空间。 在 SDK 启动时,该文件会自动解压, 大家可以在上图的左侧看到解压后的所有文件。 其中, 前四个文件( ps7_init_gpl.c、 ps7_init_gpl.h、 ps7_init.c 和 ps7_init.h) 包含了 Zynq SOC 处理系统的初始化代码,以及 DDR、时钟、 pll 和 MIO 的初始化设置信息。在初始化过程中, SDK 使用这些信息去配置相应的模块, 使得应用程序能够在 PS 上运行。
2.5、step5:在 SDK 中创建应用工程
(1)在菜单栏选择 File > New > Application Project, 新建一个 SDK 应用工程。
在弹出的对话框中,输入工程名“ hello_world”,其它选项保持默认即可,点击“ Next”。
选择工程模版 Hello World,然后点击“ Finish”。
SDK 创建了一个 hello_world 应用工程和 hello_world_bsp 板级支持包( BSP) 工程。 同时工具会自动对工程进行编译, 并生成 ELF 文件“ hello_world.elf”, 如下图所示:
另外工程创建完成后, SDK 主界面会打开 BSP 工程目录下的 system.mss 文件。 MSS 是英文Microprocessor Software Specification 的缩写,即微处理器软件说明。 该文件包含 BSP 的操作系统信息、 硬件设计中各个外设的软件驱动等信息。
2.6、step6:板级验证
在 SDK 软件的下方,找到 SDK Terminal 窗口。 如果界面中没有找到该窗口, 或者操作过程中把该窗口给关闭了,则可以通过在菜单栏中选择 Window > Show View > Other, 在 Show View 窗口中搜索添加SDK Terminal。
如下图所示,在 SDK Terminal 窗口中点击右上角的加号“ +”连接串口,并在弹出的窗口中对串口进行设置。设置的参数需要与硬件设计过程中配置的 UART0 保持一致, 即波特率为 115200, 数据位为 8 位,停止位为 1 位。 如下图所示:
下载完成后, 应用程序会将字符串“ Hello World”通过 ZYNQ PS 端的串口模块 UART0 发送出去。在 SDK Terminal 窗口可以看到上位机接收到的字符串, 如下图所示: