当前位置:   article > 正文

ZYNQ 笔记(一):开发流程_zynq开发教程

zynq开发教程

概述

ZYNQ 的工程设计大体上可以分为 对硬件逻辑系统的设计对 CPU 软件程序的设计

  • 硬件逻辑系统设计:搭建一个满足用户需求的硬件环境,通过 Vivado 实现
  • CPU 程序设计:通过用户程序控制 CPU 工作,使整个系统达到预定的效果,该部分通过 Vitis 实现

两者间的关系及具体设计步骤如下图所示

aaa

xsa 文件为硬件资源描述文件,可以通过生成比特流或生成模块设计产生

  • 涉及到 PL 端的设计:导出 xsa 文件时需要包含比特流,因此通常使用 生成比特流(Bitstream) 的方式产生 xsa 文件
  • 纯 PS 端的设计:导出时不需要比特流,因此两种方式皆可

接下来以按键控制 led 工程为例介绍 ZYNQ 开发的基本流程,本设计实现的功能如下

  • 按下 PS 端按键 SW3,PL 端小灯 LED1 亮起,松开则小灯熄灭
  • 按下 PL 端按键 SW1,PS 端小灯 LED5 亮起,松开则小灯熄灭

硬件逻辑系统设计

创建 Vivado 工程

双击打开 Vivado,点击 Create Project

20230417161026

填写工程名称并选择保存路径,勾选 Create project subdirectory 则项目保存在 {Project location}/{Project name} 文件夹下,点击 Next

0230417161107

选择 RTL Project,点击 Next

20230417161149

根据实际情况选择芯片,笔者所用开发板型号为 MZ7035FD,芯片型号为 xc7z035ffg676-2,点击 Next

20230417161244

点击 Finish,项目创建完成

20230417161317

创建模块设计

点击 Create Block Design 创建模块设计

20230417161452

在弹出的窗口中修改设计命名(注意不能包含中文及空格),点击 OK 完成创建

20230417161511

可以看到 Design 栏出现了我们刚创建好的 system 模块设计

构建硬件系统

此时我们的设计内没有任何内容,需要点击 + 为设计添加 IP 核

在弹出的搜索栏中输入 zynq,可以看到下方出现了 ZYNQ7 Processing System,双击该 IP 核添加

ZYNQ IP 核的配置通常有两个必需配置的部分:使能外设和配置 DDR 型号。双击 ZYNQ IP 核即可打开配置界面,如下图所示

右侧栏为 ZYNQ 的图形化向导界面,绿色部分为可配置界面,单击即可快速跳转到对应项设置。左侧栏为 ZYNQ IP 核配置的导航窗口,共分为 8 个部分,对应功能如下

  • ZYNQ Block Design:图形化向导界面
  • PS-PL Configuration:PS-PL 接口配置界面,可以对 AXI、HP、DMA 等总线接口进行配置
  • Peripheral I/O Pins:I/O 外设引脚配置界面,可对 I/O 外设引脚进行 MIO 以及 EMIO 的配置,配置时需要注意 Bank 电平
  • MIO Configuration:MIO 配置界面,相较于 I/O 外设引脚配置界面功能更为复杂
  • Clock Configuration:时钟配置界面,用于配置 PS 输入时钟、外设时钟、DDR 时钟和 CPU 时钟等
  • DDR Configuration:DDR 配置界面,控制 DDR 型号以及细节参数等
  • SMC Timing Calculation:SMC 时序计算界面,可进行 SMC 时序计算
  • Interrupts:中断控制界面,可对 PS 与 PL 间的中断进行配置

ZYNQ 中的外设接口由对应控制器控制,使用时需要先进行使能。点击图形化向导界面的 I/O Peripherals 中对应的外设接口便可以跳转到相应的配置界面,点击 GPIO 即可进入相应配置界面

本设计通过 PS 与 PL 侧的按键控制另一侧的 LED 灯,每个按键和 LED 灯都需要一个 GPIO 信号。GPIO 连接到 PS 部分使用的是 MIO 接口,连接到 PL 部分使用的则是 EMIO 接口,因此我们需要使能这两个外设接口。PS 端的引脚是固定的,我们不需要分配;PL 端的按键和 LED 灯都需要一个 EMIO 信号,因此我们将 EMIO 的位宽设置为 2

设置完成后检查电平状态,将 Bank1 的电平设置为 1.8V

使能完成后返回图形化向导界面,可以看到此时在 GPIO 外设后面已经打上 √ 了,代表我们已经使能该接口

接下来开始配置 DDR,DDR 全名为双速率同步动态随机存储器(Double Data Rate Synchronous Dynamic Random Access Memory),也就是我们常说的 内存。基于 PS 端的应用,大部分都需要基于片外存储外设 DDR 上允许。点击图像化界面的 DDR 控制器即可跳转到配置界面

使能 DDR 并选择 DDR 型号,笔者使用的是 MT41K256M16 RE-125

点击 OK,可以看到此时 ZYNQ 的 IP 核如图所示

点击上方的蓝色小字 Run Block Automation 系统就会自动帮我们导出引脚,勾选 All Automation 后点击 OK 即可

导出完成后可以看到软件帮我们导出了 ZYNQ 的两个引脚,但 GPIO_0 还未导出,因此我们需要手动将其导出

点击 GPIO_0 引脚,然后右键点击 Make External 导出引脚

该设计中 ZYNQ IP 核在配置时,有几个端口信号是没有被使用到的

  • FCLK_RESET0_N:全局复位信号,低电平有效
  • M_AXI_GP0:通用 AXI 接口信号,M 代表其作为主机信号
  • M_AXI_GP0_ACLK:M_AXI_GP0 的输入时钟信号
  • FCLK_CLK0:PS 输出时钟信号

其中,M_AXI_GP0_ACLK 虽然本设计中并未使用到,但如果不给其一个输入信号,软件便会报错

为了防止出现该现象,我们只需要将 FCLK_CLK0 和 M_AXI_GP0_ACLK 连接即可。连接时只需选中其中一个引脚按住鼠标左键拖动到对应的引脚即可

端口连接完成后使用快捷键 Ctrl+S 保存设计,随后点击上方的 √ 来对设计进行验证

当出现以下弹窗时证明设计无误

生成封装

点击 sources 资源栏我们创建的 system 模块设计,右键选择 Generate Output Products 生成输出

选择 Out Of context per IP,点击 Generate

点击 sources 资源栏我们创建的 system 模块设计,右键选择 Create HDL Wrapper 以创建 HDL 封装

在弹出的窗口中选择让 Vivado 管理封装和自动更新,随后点击 OK 开始创建封装

如果工程资源栏的右上角出现 Updating 的字样表明封装正在创建和更新中,当字样消失且 Sources 栏出现蓝色名为 system_wrapper 的设计文件时,则代表封装已经创建和更新完成

管脚约束

对于涉及 PL 端的设计,在完成封装后我们需要对涉及到的管脚进行分配和约束。点击左侧导航栏的 Open Elaborated Design 进行约束和分配

点击 OK

根据实际情况绑定引脚并设置电平约束,笔者使用的 MZ7035FD 板载接口如下

板载设备ZYNQ 接口
SW1H12
SW3MIO50
LED1F13
LED5MIO51

使用快捷键 Ctrl+S 保存约束文件,在弹窗中输入约束文件名,点击 OK 即可

生成比特流

完成了管脚约束后即可开始比特流的生成,比特流中包含着对 PL 端的配置信息,其中就包括对 引脚的分配 以及 电平的约束,因此生成比特流需要在进行管脚分配和约束之后。当然如果设计并未使用到 PL 部分资源,可以直接跳过该环节。点击左侧工具栏 Generate Bitstream 开始生成比特流

此时软件会提示 ”没有可用的实现结果,是否先进行综合实现再自动生成比特流“,我们直接点击 Yes 即可

导出硬件

File > Export > Export Hardware

点击 Next

对于纯 PS 端的设计,选择哪一项都可以,而涉及到 PL 端的设计必须选择 Include bitstream,点击 Next

设置 xsa 文件名称及保存路径,点击 Next

点击 Finish 即可

启动 Vitis

硬件导出完成后 Vivado 部分的设计已经完成,接下来打开 Vitis 开始 CPU 软件程序设计。点击 Tools > Launch Vitis IDE

CPU软件程序设计

创建工程

Vitis 将芯片视为一个平台,平台的相关信息通过此前导出的 xsa 文件描述,工程间的关系如下

File > New > Application Project,点击 Next

选择 Create a new platform from hardware (XSA),点击 Browse 选择此前导出的 xsa 文件,或者从列表中选择与开发板相匹配的

等待 xsa 文件加载完成,点击 Next

设置工程名称,点击 Next

点击 Next

选择工程模板,点击 Finish 即完成创建

点击 Finish 即可完成创建

添加应用库

对于某些开发板,厂商可能提供已经编写完善的应用库,若要使用这些应用库就需要将相关文件添加到项目中。以应用库 MZ7035FD_Lib 为例,首先将文件夹复制到项目中

选中项目,右键 Properties

选择 Paths and Symbols,点击右侧 Add 将应用库添加至头文件路径,否则编译时会提示找不到相关文件

点击 Workspace

选择应用库文件夹,点击 OK

点击 OK

点击 Apply and Close

添加用户代码

在项目 src 文件夹下创建文件 main.c

本设计示例代码如下

/* main.c
 *********************************************
 * @Vivado	2022.1
 * @Vitis 	2022.1
 * @Board	MZ7035FD
 * @Chip	xc7z035ffg676-2
 * @DDR		MT41K256M16 RE-125
 *********************************************
 */

#include "PS_GPIO/PS_GPIO.h"

#define PS_LED	51		// LED5
#define PS_KEY	50		// SW3
#define PL_LED	54 + 0 	// LED1
#define PL_KEY	54 + 1	// SW1

int main()
{
	// 初始化 PS 端 MIO 和 EMIO
	PS_GPIO_Init();

	// 设置 GPIO 模式
	PS_GPIO_SetPinMode(PS_LED, GPIO_DIR_OUTPUT, GPIO_STATE_LOW);
	PS_GPIO_SetPinMode(PS_KEY, GPIO_DIR_INPUT, GPIO_STATE_LOW);
	PS_GPIO_SetPinMode(PL_LED, GPIO_DIR_OUTPUT, GPIO_STATE_LOW);
	PS_GPIO_SetPinMode(PL_KEY, GPIO_DIR_INPUT, GPIO_STATE_LOW);

	// 循环读取按键状态
	while(1)
	{
		PS_GPIO_WritePin(PS_LED, PS_GPIO_ReadPin(PL_KEY) == GPIO_STATE_HIGH ? GPIO_STATE_LOW : GPIO_STATE_HIGH);
		PS_GPIO_WritePin(PL_LED, PS_GPIO_ReadPin(PS_KEY) == GPIO_STATE_HIGH ? GPIO_STATE_LOW : GPIO_STATE_HIGH);
	}

	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
/* PS_GPIO.h
 *********************************************
 * @Vivado	2022.1
 * @Vitis 	2022.1
 * @Board	MZ7035FD
 * @Chip	xc7z035ffg676-2
 * @DDR		MT41K256M16 RE-125
 *********************************************
 */
#ifndef __PS_GPIO_H__
#define __PS_GPIO_H__

#include "xgpiops.h"

#define GPIO_DIR_INPUT		0	// 设置 GPIO 为输入
#define GPIO_DIR_OUTPUT 	1	// 设置 GPIO 为输出

#define GPIO_OUTPUT_ENABLE	1	// 使能 GPIO 输出
#define GPIO_OUTPUT_DISABLE	0	// 禁用 GPIO 输出

#define GPIO_STATE_LOW		0	// GPIO 为低电平
#define GPIO_STATE_HIGH		1	// GPIO 为高电平

void PS_GPIO_Init();
void PS_GPIO_SetPinMode(uint8_t GPIO_Num, uint8_t GPIO_Dir, uint8_t GPIO_Default_State);
void PS_GPIO_WritePin(uint8_t GPIO_Num, uint8_t GPIO_State);
uint8_t PS_GPIO_ReadPin(uint8_t GPIO_Num);

#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
/* PS_GPIO.c
 *********************************************
 * @Vivado	2022.1
 * @Vitis 	2022.1
 * @Board	MZ7035FD
 * @Chip	xc7z035ffg676-2
 * @DDR		MT41K256M16 RE-125
 *********************************************
 */
#include "PS_GPIO.h"

// GPIO 实例对象
XGpioPs GpioPs;

/*
 * @brief 	初始化 PS 端 MIO 和 EMIO
 */
void PS_GPIO_Init()
{
	// 获取 PS 端 GPIO 配置
	XGpioPs_Config *ConfigPtr = XGpioPs_LookupConfig(XPAR_XGPIOPS_0_DEVICE_ID);

	// 初始化 PS 端 GPIO 实例
	XGpioPs_CfgInitialize(&GpioPs, ConfigPtr, ConfigPtr->BaseAddr);
}


/*
 * @brief 	设置单个 GPIO 引脚模式
 * @param 	GPIO_Num 				GPIO 编号(MIO:0~53,EMIO:54~)
 * @param 	GPIO_Dir 				GPIO 方向(输入/输出)
 * @param 	GPIO_Default_Output		GPIO 默认输出(GPIO设置为输出时有效)
 */
void PS_GPIO_SetPinMode(uint8_t GPIO_Num, uint8_t GPIO_Dir, uint8_t GPIO_Default_State)
{
	// 设置 GPIO 输入/输出方向
	XGpioPs_SetDirectionPin(&GpioPs, GPIO_Num, GPIO_Dir);

	// 输出模式需要使能并设置默认输出电平
	if(GPIO_Dir == GPIO_DIR_OUTPUT)
	{
		// 使能 GPIO 输出
		XGpioPs_SetOutputEnablePin(&GpioPs, GPIO_Num, GPIO_OUTPUT_ENABLE);

		// 设置默认输出
		XGpioPs_WritePin(&GpioPs, GPIO_Num, GPIO_Default_State);
	}
}


/*
 * @brief	写入 GPIO 电平
 * @param	GPIO_Num	GPIO 编号(MIO:0~53,EMIO:54~)
 * @param	GPIO_State	待写入的 GPIO 电平状态
 */
void PS_GPIO_WritePin(uint8_t GPIO_Num, uint8_t GPIO_State)
{
	XGpioPs_WritePin(&GpioPs, GPIO_Num, GPIO_State);
}


/*
 * @brief 	读取 GPIO 电平
 * @param 	GPIO_Num	GPIO 编号(MIO:0~53,EMIO:54~)
 * @return 	高电平输出 1,低电平输出 0
 */
uint8_t PS_GPIO_ReadPin(uint8_t GPIO_Num)
{
	return XGpioPs_ReadPin(&GpioPs, GPIO_Num);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

板级验证与调试

选择工具栏运行按钮,点击 Run Configurations…

双击 Single Application Debug (GDB) 创建配置

选择 Target Setup,取消勾选 Reset entire system,否则烧录后会报错

点击运行按钮即可自动下板运行

点击调试按钮即可下板调试

调试相关按钮(全速运行、暂停、停止、进入函数、跳过语句)

Vitis 联合 VSC 编程

Vitis 在编写代码时需要通过快捷键 Alt+? 启用代码提示,使用体验非常差。为此下面介绍如何使用 VS Code 编写代码,效果如下

首先在 VS Code 中打开 Vitis 项目文件夹

点击报错部分 > 快捷键 Alt + Enter > 编辑 “includePath” 设置

此时 VS Code 会在项目根路径下生成 .vscode 配置文件夹,我们需要在 c_cpp_properties.json 文件中添加头文件路径。其中${default} 代表 C/C++ 插件全局配置中设置的 Include,我们还需要添加该项目需要的头文件

Vitis 项目依赖的头文件均在平台工程 (Platform Project) system_wrapper 中,由上图可知 system_wrapper 和 应用工程 (Application Project) gpio_axi_system 文件夹平级,因此添加头文件路径如下 (xxx/** 会自动遍历 xxx 文件夹下的所有子文件和子文件夹)

此时按住 Ctrl 并用鼠标点击变量、函数名等已可以查看其定义,但仍然会有红色波浪线报错

在 .vscode 文件夹下创建 settings.json 配置文件,并添加如下内容

{
    "C_Cpp.intelliSenseEngineFallback": "disabled",
    "C_Cpp.intelliSenseEngine": "Tag Parser"
}
  • 1
  • 2
  • 3
  • 4

红色波浪线报错消失,开始用 VS Code 愉快地编程吧!

Vivado 联合 Modelsim 仿真

Modelsim 在仿真速度和使用体验上均要优于 Vivado 自带的 Vsim,因此接下来将介绍如何在 Vivado 中调用 Modelsim 进行仿真

编译 Vivado 仿真库

Modelsim 安装完成后并不包含 Xilinx 相关的器件库,因此需要先编译后才能使用。打开 Vivado,Tools > Compile Simulation Libraries

设置 Simulator 为 Modelsim Simulator,选择编译库存放路径和 modelsim.exe 所在文件夹,勾选 Compile Xilinx IP,点击 Compile

等待编译完成

设置仿真工具和库路径

Vivado 新建工程的默认仿真工具是 Vsim,所以要使用 Modelsim 仿真,每个新工程都要设置一次。点击 Tools > Settings

侧边栏选中 Simulation,设置 Target Simulator 为 Modelsim Simulator,点击 Yes

设置 Xilinx 编译库路径,点击 OK

点击侧边栏 Run Simulation > Run Behavioral Simulation

等待 Modelsim 仿真结果,大功告成!

参考文献

[1] 小梅哥. 基于C编程的Zynq裸机程序设计与应用教程

[2] 皮皮祥. Vivado 关联 Modelsim 进行仿真

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号