发 帖  
原厂入驻New
[经验]

【正点原子FPGA连载】第三章按键控制LED实验-领航者ZYNQ之HLS 开发指南

2020-10-10 16:54:25  57 正点原子FPGA
分享
0
本帖最后由 正点原子运营官 于 2020-10-12 10:02 编辑

1)实验平台:正点原子领航者ZYNQ开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/FPGA/zdyz_linhanz.html
4)对正点原子FPGA感兴趣的同学可以加群讨论:876744900
5)关注正点原子公众号,获取最新资料


第三章按键控制LED实验

在第一章节我们通过LED闪烁实验学习了如何通过HLS来生成一个带有输出接口的IP核。在本章我们通过按键控制LED实验,来学习如何使用Vivado HLS工具生成一个带有输入和输出接口的IP核,并学习Vivado HLS工具仿真平台的使用,以及在Vivado中对综合结果进行验证的流程。
本章包括以下几个部分:
33.1简介
3.2实验任务
3.3HLS设计
3.4IP验证
3.5下载验证
3.1简介
在使用Vivado HLS工具进行设计的时候,如果设计完成之后发现功能不正确,然后确定问题产生的原因是非常耗时的。为了提高效率,我们使用测试平台在设计完成之后验证C函数在功能上是否正确。
Vivado HLS工具的输入和输出如下图所示:



图 3.1.1 vivado hls工具的输入和输出

从图中可以看出在Vivado HLS的设计流程中,设计的输入包括C/C++设计、Testbench(测试集)编写以及Constraints(约束)/directives(指令)的添加。Vivado HLS最主要的输出结果是以VHDL/Verilog语言描述的RTL实现,并打包成IP模块的形式以方便xilinx设计工具使用,如System Generator等。
我们可以使用C testbench在综合之前对C函数进行仿真,验证函数的输出的正确性,这一过程被称之为C仿真,对应于图中的“C Simulation”。它还可以在综合之后对综合得到的RTL设计进行仿真,这一仿真过程同样是使用C testbench进行的,这一过程被称为C/RTL协同仿真,对应于图中的“RTL Simulation”。
3.2实验任务
本章的实验任务是使用领航者底板上的 PL_KEY0 和 PL_KEY1 按键来控制底板上的 PL_LED0 和 PL_LED1 两个 LED。没有按键按下时,两个 LED 保持常亮;如果按键 0 按下,则PL_LED0熄灭;如果 按键 1 按下,则PL_LED1熄灭。要求使用C语言完成设计,然后综合得到RTL级实现并进行验证。
3.3HLS设计
我们在电脑中的“F:\ZYNQ\High_Level_Synthesis”目录下新建一个名为key_led的文件夹,作为本次实验的工程目录。然后打开Vivado HLS工具,创建一个新的工程。设置工程名为“key_led_hls”,选择工程路径为刚刚创建的文件夹。需要注意的是,工程名以及路径只能由英文字母、数字和下划线组成,不能包含中文、空格以及其他特殊字符。如下图所示:



图 3.3.1 工程配置界面

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



图 3.3.2 设置顶层函数

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



图 3.3.3 新建源文件

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



图 3.3.4 输入源文件名

我们在图 3.3.4中输入的源文件的后缀名为“.c”,即使用C语言进行设计。如果使用C++语言进行设计,那么后缀名需要设置为“.cpp”。设置好文件名和路径之后,点击“保存”。
在创建了源文件之后,在Vivado HLS工程面板中的Source目录下可以看到我们新建的源文件:key_led.c,同时信息面板自动打开了该文件的编辑界面,我们可以在里面输入C代码。如下图所示:



图 3.3.5 新建的源文件

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

  • 1 #include "key_led.h"
  • 2
  • 3 void key_led(uint2 key, uint2* led)
  • 4 {
  • 5 #pragma HLS INTERFACE ap_none port=led
  • 6 #pragma HLS INTERFACE ap_none port=key
  • 7 #pragma HLS INTERFACE ap_ctrl_none port=return
  • 8
  • 9 uint2 key_value = key;
  • 10
  • 11 switch(key_value)
  • 12 {
  • 13 case 3:
  • 14 *led = 3;
  • 15 break;
  • 16 case 2:
  • 17 *led = 2;
  • 18 break;
  • 19 case 1:
  • 20 *led = 1;
  • 21 break;
  • 22 default:
  • 23 *led = 0;
  • 24 break;
  • 25 }
  • 26 }


在代码的第1行,包含了一个名为“key_led.h”的头文件,这个是我们自己创建的头文件。“key_led.h”的创建方式和“key_led.c”的创建方式相同。创建此头文件的目的是为了函数声明,以便在测试文件中引入此头文件,从而在测试文件中可以调用我们所编写的函数。在代码的第3行,我们在定义函数参数类型时,使用了“uint2”这种数据类型,它表示2位无符号整数。
在代码的第5行到代码的第6行,#pragma为HLS优化指令,它表示led和key使用的是ap_none协议。在代码的第7行ap_ctrl_none表明没有添加包级别的协议,而是完全在端口接口级别用端口级别协议来做控制。在代码的第9行我们定义了一个key_value变量来寄存按键的值。
在第11行到第25行我们根据按键的不同值,来控制LED的状态。这是一个switch case语句。它根据不同的按键key的状态来切换LED的数值。比如:当两个按键的值是3(二进制11),表示没有按键按下,则给LED赋值为3(二进制11),从而点亮两个LED。
头文件“key_led.h”的代码如下:

  • 1 #include <ap_cint.h>
  • 2
  • 3 #ifndef _KEY_LED_H_
  • 4 #define _KEY_LED_H_
  • 5
  • 6 void key_led(uint2 key, uint2* led);
  • 7
  • 8 #endif


在代码的第1行我们引入了“ap_cint.h”的头文件来包含任意精度数据类型。在代码的第3行到第4行表示如果没有定义“key_led.h”头文件则定义这个头文件,这样可以避免头文件的重复定义。在代码第6行,我们声明了按键控制LED函数,从而在测试文件中可以调用此函数。
在工程面板中的“Test Bench”目录上点击右键,然后在打开的列表中选择“New File”新建测试文件, 在弹出的对话框中输入测试文件的名称“key_led_tb.c”,如图1.3.6所示。测试文件的保存路径为src目录。



图 3.3.6 新建测试文件

在测试文件中编写如下代码:

  • 1 #include "key_led.h"
  • 2
  • 3 int main()
  • 4 {
  • 5 uint2 key,led;
  • 6
  • 7 key_led(0,&led);
  • 8 key_led(1,&led);
  • 9 key_led(2,&led);
  • 10 key_led(3,&led);
  • 11
  • 12 return 0;
  • 13 }


在测试文件中,我们通过调用按键控制函数,并给按键赋不同的值,来实现按键控制的仿真。
代码输入完成后,按快捷键Ctrl+S保存。然后点击工具栏中向右的绿色三角形对C代码进行综合,如下图所示:



图 3.3.7 运行C综合

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



图 3.3.8 综合报告

在图1.3.8所示的综合报告中,给出了设计的性能评估、资源评估以及接口等信息。本次实验中,我们重点关注综合工具为我们生成的两个接口,分别为 “key”、“led”。 从接口信息中,我们可以看到按键key的C语言类型是变量,在RTL级别中被映射为输入端口。led的C语言类型是指针,在RTL级别中被映射为输出端口。
这是因为HLS规定了协议、端口类型和方向之间的相关性,在Vivado HLS开发过程中,考虑C/C++函数参数的类型是很重要的。Vivado HLS规定可以传入/传出C/C++函数的值有四种不同的数据类型,分别是:变量、指针、数组和引用。这也就是说,一种特定的参数类型只对应于有限的几种协议。比如,传入一个数组作为形参输入,能使用的协议就只有:ap_hs、ap_memory、bram、 ap_fifo、ap_bus、axis 和 m_axi,其中 ap_memory 是默认的。参数类型对应支持的接口协议如下图所示:



图 3.3.9 参数类型和接口协议的对应图

本实验中,我们规定接口所使用的协议为ap_none。图中的“D”表示“default”,表示Vivado HLS工具默认综合出来的接口。“S”表示“support”,表示Vivado HLS工具支持综合出来的接口。从图中我们可以看出,使用ap_none时,当变量作为形参时,接口只能被综合成输入而不能被综合成输出,当指针变量作为形参时,接口可以被综合成输入、输出和双向端口。本节实验中,我们定义按键key的类型为变量,led的类型指针,从而实现了将按键key作为输入接口,led作为输出接口。
下面我们进行仿真,来测试HLS设计是否满足要求。点击工具栏中的仿真按钮,进入仿真,如下图所示:



图 3.3.10 运行C仿真

弹出仿真配置界面,我们在配置界面中启动C调试器,并清除编译残留文件。设置如下图所示:



图 3.3.11 C调试器配置界面

点击“OK”按钮,打开C调试器,在C调试器工具栏中点击单步调试按钮,如下图所示:



图 3.3.12 单步调试

执行单步调试,在右侧变量观察窗口中可以看到当按键值key为1的时候,*LED值变为了1。如下图所示:



图 3.3.13 变量观察窗口

继续执行单步调试,可以看到当按键值key为2的时候,*led的值变为了2。当按键值key为3的时候,*led的值变为了3。这意味着我们已经可以通过按键来控制LED的状态,至此仿真设计完成,通过仿真我们验证了HLS设计的正确性。下面我们将设计打包成IP模块,以供Vivado开发套件中的其他工具(如IP集成器)使用。
在工具栏中点击黄色的“田”字按钮,导出RTL,如下图所示:



图 3.3.14 导出RTL

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



图 3.3.15 将设计导出成IP

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



图 3.3.16导出得到的IP

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



图 3.3.17 文件夹中的IP核

HLS设计结束之后,我们将在Vivado中对导出的IP核进行验证。
3.4IP验证
在IP验证环节,我们会使用Vivado工具的IP集成器将生成的IP核添加到Block Design中,然后完成设计后将程序下载到领航者开发板上进行验证。
我们在《领航者ZYNQ之嵌入式开发指南》第一章“Hello World实验”中详细介绍了如何使用Vivado创建工程,以及如何使用IP集成器(IP INTEGRATOR)创建Block Design。如果大家对这一部分内容不熟悉的话,一定要先按照《领航者ZYNQ之嵌入式开发指南》中第一章的描述,把这一流程完整的操作一遍,然后才能进行本章的IP验证环节。
在本次实验中,我们创建一个名为“key_led_ip_test”的Vivado工程。为了方便工程管理,我们将Vivado工程的目录与HLS工程目录保持一致,如下图所示:



图 3.4.1 创建Vivado工程

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



图 3.4.2 按键控制LED实验工程目录

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



图 3.4.3 拷贝并解压IP

接下来在Vivado中将该IP添加到工程的IP库中。添加IP核完成之后,创建一个名为“system”的Block Design。在设计中添加key_led IP核,最终完成的设计如下图所示:



图 3.4.4 完成后的Block Design

到这里我们的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 L20 IOSTANDARD LVCMOS33} [get_ports key[0]]
  • set_property -dict {PACKAGE_PIN J20 IOSTANDARD LVCMOS33} [get_ports key[1]]
  • 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文件。
3.5下载验证
连接开发板的电源和下载器,并打开电源开关。在工程编译之后,将生成的bit文件下载到开发板中。下载完成之后,底板上两个 PL LED 处于点亮状态。然后按下 PL_KEY0,可以看到PL LED 0熄灭;按下PL_KEY1,可以看到PLLED1熄灭。如下图所示:



图 3.5.1 按键控制LED实验现象






相关经验

评论

高级模式
您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发经验
关闭

站长推荐 上一条 /7 下一条

快速回复 返回顶部 返回列表