龙空技术网

「正点原子FPGA连载」第二章LED闪烁实验

正点原子日常 133

前言:

当前各位老铁们对“c语言实验灯闪3次后熄灭”大体比较注意,同学们都想要分析一些“c语言实验灯闪3次后熄灭”的相关资讯。那么小编在网络上搜集了一些有关“c语言实验灯闪3次后熄灭””的相关文章,希望小伙伴们能喜欢,同学们快快来学习一下吧!

1)摘自【正点原子】领航者ZYNQ之HLS 开发指南

2)实验平台:正点原子领航者ZYNQ开发板

3)平台购买地址:

4)全套实验源码+手册+视频下载:

5)对正点原子FPGA感兴趣的同学可以加群讨论:876744900

6)正点原子资料更新和新品发布,请加正点原子公众号:正点原子

关注方法:微信→添加好友→公众号→输入:正点原子

第二章LED闪烁实验

在《领航者之FPGA开发指南》的第六章“LED闪烁实验”中,我们给大家介绍了如何使用硬件描述语言来完成设计,最终实现PL端LED闪烁的效果。在本章我们同样会通过LED闪烁实验,来讲解如何使用Vivado HLS工具对C语言进行高层次综合,并最终生成RTL级的实现结果,以及在Vivado中对综合结果进行验证的流程。

本章包括以下几个部分:

22.1简介

2.2实验任务

2.3HLS设计

2.4IP验证

2.5下载验证

2.1简介

出于尽快地把产品推向市场的商业需求,数字系统设计的一个明显趋势就是加速开发的周期。加速策略可以从两个方面考虑:(一)设计的重用和(二)抽象层次的提升。Xilinx Vivado开发套件中的IP集成功能可以实现设计的重用,而Vivado HLS工具则能够实现对高层次设计的综合。

Vivado High Level Synthesis(即HLS,高层次综合)工具使用C、C++或System C语言在更抽象的算法层次描述设计,并将C代码综合成RTL级的HDL描述。 使用Vivado HLS进行高层次综合的过程如下图所示:

图 2.1.1高层次综合流程图

从图 2.1.1中可以看到,设计的输入是C代码 ,Vivado HLS工具将其综合成使用VHDL或者Verilog语言描述的RTL级实现。HLS综合得到的结果将以IP集成的方式添加到Xilinx设计工具(如Vivado)中,并最终综合成网表形式的电路。

2.2实验任务

本章的实验任务是使领航者底板上的 PL LED0 和 PL LED1 以固定的频率交替闪烁,要求使用C或C++语言完成设计,然后综合得到RTL级实现并进行验证。

2.3HLS设计

首先打开Vivado HLS工具,在Windows系统中点击开始 > 所有应用 > Xilinx Design Tools > Vivado 2018.3 > Vivado HLS 2018.3,如下图所示:

图 2.3.1打开Vivado HLS

Vivado HLS打开后界面如下图所示:

图 2.3.2 Vivado HLS开始界面

如图 2.3.2中红色圆圈所示,在Vivado HLS的开始界面中点击左“Create New Project”,创建一个新的工程。然后会弹出新建Vivado HLS工程向导界面,如下图所示:

图 2.3.3 工程配置界面

在图 2.3.3中“Project name”一栏输入工程名“led_twinkle_hls”,然后在“Location”一栏通过点击右侧的“Browse…”按钮,选择工程路径。我们在电脑中的“F:\ZYNQ\High_Level_Synthesis”目录下新建一个名为led_twinkle的文件夹,作为本次实验的工程目录。需要注意的是,工程名以及路径只能由英文字母、数字和下划线组成,不能包含中文、空格以及其他特殊字符。

设置好工程名及路径之后,点击“Next”,进入如下界面:

图 2.3.4 设置顶层函数

在图 2.3.4中的“Top Function”一栏设置设计的顶层函数为“led_twinkle”,然后点击“Next”,进入如下页面:

图 2.3.5 添加C测试文件

在图 2.3.5中我们可以添加C测试文件,这里我们不需要添加,直接点击“Next”,进入如下界面:

图 2.3.6 解决方案(Solution)配置

在图 2.3.6中红色方框所指示的位置可以看到,工程默认的器件型号为“xa7a12tcsg325-1q”,我们需要将其修改为我们开发板所使用的器件型号。

点击上图中箭头所指示的位置,弹出的对话框如下图所示:

图 2.3.7 选择器件型号

在红色方框所指示的搜索框中输入领航者ZYNQ开发板核心板上的ZYNQ芯片型号。

领航者核心板上的ZYNQ芯片有两种型号,XC7Z010和XC7Z020。大家可以通过查看核心板上ZYNQ芯片的私印来确认所使用的芯片型号。本文中以XC7Z020为例,在搜索框中输入“xc7z020clg400-2”。如果使用的是XC7Z010,对应的器件型号为“xc7z010clg400-1”。需要注意的是,XC7Z010型号的速度等级为“-1”,XC7Z020的为“-2”。

输入完成后选中搜索结果,然后点击“Next”,返回解决方案配置界面,如下图所示:

图 2.3.8完成器件选择

从上图中可以看到,工程的器件类型已经修改为领航者开发板上的ZYNQ芯片型号,然后点击“Finish”完成工程设置。

创建工程完成后,Vivado HLS会打开工程界面,如下图所示:

图 2.3.9 Vivado HLS工程界面

在工程面板中的“source”目录上点击右键,然后在打开的列表中选择“New File”新建源文件,如下图所示;

图 2.3.10 新建源文件

然后在弹出的对话框中输入源文件的名称“led_twinkle.c”,如图 2.3.11所示。源文件默认的保存路径为HLS工程目录,为方便源文件的管理,我们在工程目录下新建一个名为“src”的文件下,将源文件保存在src目录下。

图 2.3.11 输入源文件名

我们在图 2.3.11中输入的源文件的后缀名为“.c”,即使用C语言进行设计。如果使用c++进行设计,那么后缀名需要设置为“.cpp”。设置好文件名和路径之后,点击“保存”。

在创建了源文件之后,在Vivado HLS工程面板中的Source目录下可以看到我们新建的源文件:led_twinkle.c,同时信息面板自动打开了该文件的编辑界面,我们可以在里面输入C代码。如下图所示:

图 2.3.12 新建的源文件

在图 2.3.12中箭头所指示的位置输入本次实验的源代码:

1 #include <ap_cint.h>2 3 #define DELAY 500000004 5 void led_twinkle(uint2 *led){6 int i = 0;7 8 for(i = 0; i < DELAY; i++){9 if(i < DELAY/2)10 *led = 1;11 else12 *led = 2;13 }14 }

在代码的第1行,包含了一个名为“ap_cint.h”的头文件,该头文件包含了对任意精度整数类型的支持。在代码的第5行,我们在定义函数参数*led的类型时,就使用了这种数据类型——“uint2”,它表示2位无符号整数。那么我们为什么不使用C语言自带的数据类型呢?

C和C++语言自带的数据类型是从四个基本数值类型中派生出来的char、int、float和double,它们的位宽分别是8位、32位、32位和64位。另外还支持short int类型(16位),以及布尔类型(8位)等。

为了优化硬件实现,用于高层次综合的设计中不应该有多余的位存在,因为那样会导致额外的

硬件开销。比如在本次实验中,我们只需要控制两个LED,即需要的位宽为2。如果使用C语言自带的数据类型,即使是将其定义成位宽最小的char类型,最终综合出来的模块端口也是8位。除了模块的端口,与之相关的任何寄存器以及其他运算资源也都会超过必须的大小。因此,在HLS中需要支持任意字长来满足电路需要的任意程度的精度。

如代码第5行到第14行所示,函数led_twinkle的功能非常简单。在第8行我们定义了一个for循环,在循环中对变量i进行累加,一直累加到宏定义(第3行)DELAY所指定的值。然后在for循环内部,我们使用一个if-else条件语句来判断i是否小于DELAY/2。条件满足就将led赋值为1(二进制01),LED0点亮,LED1熄灭;否则就将led赋值为2(二进制10),即LED0熄灭,点亮LED1。当函数led_twinkle一直运行时,两个LED的状态就在点亮和熄灭之间不停的切换,从而实现两个LED交替闪烁的效果。

代码输入完成后,按快捷键Ctrl+S保存。然后点击工具栏中向右的绿色三角形对C代码进行综合,如下图所示:

图 2.3.13 运行C综合

综合完成后,会自动打开综合结果(solution)的报告,如下图所示:

图 2.3.14 综合报告

在图 2.3.14所示的综合报告中,给出了设计的性能评估、资源评估以及接口等信息。在本次实验中,我们重点关注报告中的接口信息,如下图所示:

图 2.3.15 接口信息

如图 2.3.15所示,在接口信息的各个列中分别给出了设计综合出来的RTL端口(Ports)、方向(Dir)、位宽(Bits)以及协议(Protocol)等信息。

从第二行和第三行可以看到,综合之后的模块包含了时钟ap_clk和复位ap_rst两个端口。在本设计中,这两个端口是必须的:因为模块的运算无法在一个时钟周期内完成,且模块内部的操作是同步的,因此它需要一个时钟信号;而模块需要能够从外部被重置,因此需要一个复位信号。

而图 2.3.15中蓝色方框内的一组接口用于实现模块级的协议,即Protocol一栏中的ap_ctrl_hs(Control Handshake,控制握手协议)。所谓的模块级的协议主要是用于控制模块的运行,而协议具体的内容在本次实验中并不必深究,因为我们实现的功能相对比较简单,因此可以使用一个更简单的协议——ap_ctrl_none,也就是不需要额外的控制端口。

图 2.3.15中红色方框内的一组接口是本次模块的输出端口,其中led端口用于控制开发板上的两个LED,而led_ap_vld则用于实现端口的协议,即Protocol一栏中的ap_vld。对于led端口,我们同样不需要额外的控制信号,因此可以使用ap_none协议来替换ap_vld协议。替换之后模块的接口会更加简洁明了。

接下来我们就通过插入“指令”(Directive)来指导综合的过程,从而得到使用ap_ctrl_none 和ap_none协议的综合结果。

在信息面板中回到led_twinkle.c的编辑页面,如果该页面被关闭,可以通过双击工程面板中的源文件重新打开。然后在右侧的辅助面板中,打开Directive标签页,将鼠标放在顶层函数led_twinkle上,然后右击选择“Insert Directive”,如下图所示:

图 2.3.16 插入指令

在弹出的Vivado HLS指令编辑框中作如下配置:

1、在Directive(指令)一栏选择“INTERFACE”,即选择与接口相关的指令;

2、在Destination(目标)一栏选择“Source File”,即将指令插入源文件;

3、在Options下的mode(模式)一栏选择“ap_ctrl_none”,即接口使用ap_ctrl_none协议。

设置完成后点击“OK”,如下图所示:

图 2.3.17 插入指令

插入指令完成后,源代码中多了一行语句,如下图所示:

图 2.3.18 插入指令后的源码

从图 2.3.18中可以看到,在代码的第6行多了一行以#pragma开头的指令,pragma的含义是“编译指示”。通过插入指令,设计者可以对C源码的实现过程加以控制。指令中的“INTERFACE”表示这是一条控制接口综合过程的指令,而“ap_ctrl_none”表示相应的端口在综合的过程中使用ap_ctrl_none协议。需要注意的是该指令的最后一部分“port=return”,它表示该接口指令是模块级的,而不是针对模块上的某一个端口。接下来我们就要插入一条针对端口的接口指令。

按照同样的方法,在信息面板中保持led_twinkle.c的编辑页面打开,然后在右侧的辅助面板中,打开Directive标签页,将鼠标放在函数的参数led上,然后右击选择“Insert Directive”,如下图所示:

图 2.3.19 插入指令

按照下图红色方框所示设置指令:

图 2.3.20 设置指令

设置完成后点击“OK”,然后会发现源码中又多了一句#pragma指令,如下图所示:

图 2.3.21 新增的指令

图 2.3.21红色方框所指示的是新增的指令,与第7行的指令类似,它表示综合过程中接口使用的协议为“ap_none”。与第7行指令末尾的“port=return”不同,在该指令末尾的“port=led”表明该指令是针对端口led的。

在指令添加完成后,按快捷键Ctrl+S保存源文件。然后重新点击工具栏中的绿色三角形,运行C综合过程。综合完成后,会重新打开综合报告,其中接口部分如下图所示:

图 2.3.22 插入指令后的综合报告

从图 2.3.22中可以看出,在插入了两条综合指令后,HLS重新综合之后得到的设计的端口简单了很多,只有时钟(ap_clk)、复位(ap_rst)和LED端口。

我们需要通过查看综合报告,对高层次综合得到的结果进行评估。如果不满足要求(比如速度或资源的要求),那么需要返回修改设计,然后再次进行综合。经过反复迭代得到我们满意的实现结果之后,就来到了高层次综合流程的最后一步,将设计打包成IP模块,以供Vivado开发套件中的其他工具(如IP集成器)使用。

在工具栏中点击黄色的“田”字按钮,导出RTL,如下图所示:

图 2.3.23 导出RTL

在弹出的对话框中保持默认设置,直接点击“OK”,如下图所示:

图 2.3.24 将设计导出成IP

设计导出完成后,HLS设计部分就结束了,我们在HLS工程目录下可以找到导出的IP核,如下图红色方框所示:

图 2.3.25导出得到的IP

我们到计算机工程目录所指向的文件夹中同样可以看到以ZIP压缩文件形式存在的IP核,如下图所示:

图 2.3.26 文件夹中的IP核

HLS设计结束之后,我们将在Vivado中对导出的IP核进行验证。

2.4IP验证

在IP验证环节,我们会使用Vivado工具的IP集成器将生成的IP核添加到Block Design中,然后完成设计后将程序下载到领航者开发板上进行验证。

我们在《领航者ZYNQ之嵌入式开发指南》第一章“Hello World实验”中详细介绍了如何使用Vivado创建工程,以及如何使用IP集成器(IP INTEGRATOR)创建Block Design。如果大家对这一部分内容不熟悉的话,一定要先按照《领航者ZYNQ之嵌入式开发指南》中第一章的描述,把这一流程完整的操作一遍,然后才能进行本章的IP验证环节。

在本次实验中,我们创建一个名为“led_twinkle_ip_test”的Vivado工程。为了方便工程管理,我们将Vivado工程的目录与HLS工程目录保持一致,如下图所示:

图 2.4.1 创建Vivado工程

Vivado工程创建完成之后,本次实验的工程目录如下图所示:

图 2.4.2 LED闪烁实验工程目录

图 2.4.2中,以“_hls”结尾的文件夹为Vivado HLS工程,以“_ip_test”结尾的是用于IP验证的Vivado工程。

工程创建完成后,需要先将HLS设计过程中导出的IP核拷贝到Vivado工程目录下。我们在Vivado工程目录下新建一个名为“ip_repo”的文件夹,然后将图 2.3.26中的压缩包拷贝到该文件夹中并解压,解压完成后如下图所示:

图 2.4.3 拷贝并解压IP

接下来在Vivado中将该IP添加到工程的IP库中。

点击菜单栏的“Tools”,选择“Setting”,如下图所示:

图 2.4.4 打开设置界面

点击“IP”一栏下的“Repository”,然后点击“+”来添加自定义的IP核,如下图所示:

图 2.4.5 IP库添加界面

接下来会弹出添加自定义IP核的路径,选择../custom_ip/ip_repo/breath_led_ip_1.0,点击“Select”,如下图所示:

图 2.4.6 选择IP所在目录

在弹出的界面中可以看到识别到的IP核,点击“OK”按钮添加IP核,如下图所示:

图 2.4.7 添加IP核

最后点击“OK”按钮,完成IP核的添加,如下图所示:

图 2.4.8 添加IP核完成

添加IP核完成之后,创建一个名为“system”的Block Design。在设计中添加Led_twinkle和Utility Vector Logic两个IP核,并Utility Vector Logic IP核配置成1位位宽的非门。最后连接两个IP并创建外部端口。最终完成的设计如下图所示:

图 2.4.9 完成后的Block Design

在图 2.4.9中Utility Vector Logic IP核的配置界面如下图所示:

图 2.4.10 Utility Vector Logic IP核配置

到这里我们的Block Design就设计完成了,在Diagram窗口空白处右击,然后选择“Validate Design”验证设计。验证完成后弹出对话框提示“Validation Successful”表明设计无误,点击“OK”确认。最后按快捷键“Ctrl + S”保存设计。

接下来在Source窗口中右键点击Block Design设计文件“system.bd”,然后依次执行“Generate Output Products”和“Create HDL Wrapper”。

然后我们还要为设计创建约束文件navigator.xdc,并在文件中添加以下管脚约束信息:

set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {led[0]}]set_property -dict {PACKAGE_PIN H18 IOSTANDARD LVCMOS33} [get_ports {led[1]}]

最后在左侧Flow Navigator导航栏中找到PROGRAM AND DEBUG,点击该选项中的“Generate Bitstream”,对设计进行综合、实现、并生成Bitstream文件。

2.5下载验证

连接开发板的电源和下载器,并打开电源开关。在工程编译之后,将生成的bit文件下载到开发板中。下载完成之后,我们可以看到位于底板上的两个LED灯在不断交替闪烁,如下图所示:

图 2.5.1 两个PL LED灯交替闪烁

标签: #c语言实验灯闪3次后熄灭