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

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

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工具的输入和输出如下图所示:

8baa945fea22cebdabee8fad020c9bb2.png

图 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:ZYNQHigh_Level_Synthesis”目录下新建一个名为key_led的文件夹,作为本次实验的工程目录。然后打开Vivado HLS工具,创建一个新的工程。设置工程名为“key_led_hls”,选择工程路径为刚刚创建的文件夹。需要注意的是,工程名以及路径只能由英文字母、数字和下划线组成,不能包含中文、空格以及其他特殊字符。如下图所示:

e0f7d7e3fde30e7b8d56872c0b79d2fa.png

图 3.3.1 工程配置界面


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

977388db09be2e5696dcafbb54875cd6.png

图 3.3.2 设置顶层函数


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

e4fe31b97f3d0af067d372b815fab90f.png

图 3.3.3 新建源文件


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

8897af058252879987e583ca6ca72737.png

图 3.3.4 输入源文件名


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

32f005fe6b9e67586e92e8460a0ef829.png

图 3.3.5 新建的源文件


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

  1. 1 #include "key_led.h"
  2. 2
  3. 3 void key_led(uint2 key, uint2* led)
  4. 4 {
  5. 5 #pragma HLS INTERFACE ap_none port=led
  6. 6 #pragma HLS INTERFACE ap_none port=key
  7. 7 #pragma HLS INTERFACE ap_ctrl_none port=return
  8. 8
  9. 9 uint2 key_value = key;
  10. 10
  11. 11 switch(key_value)
  12. 12 {
  13. 13 case 3:
  14. 14 *led = 3;
  15. 15 break;
  16. 16 case 2:
  17. 17 *led = 2;
  18. 18 break;
  19. 19 case 1:
  20. 20 *led = 1;
  21. 21 break;
  22. 22 default:
  23. 23 *led = 0;
  24. 24 break;
  25. 25 }
  26. 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. 1 #include <ap_cint.h>
  2. 2
  3. 3 #ifndef _KEY_LED_H_
  4. 4 #define _KEY_LED_H_
  5. 5
  6. 6 void key_led(uint2 key, uint2* led);
  7. 7
  8. 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目录。

ebe901210ccabb5512648fe45486a866.png

图 3.3.6 新建测试文件


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

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


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

0cb5d98bd6b871d5885add301cb2d3be.png

图 3.3.7 运行C综合


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

2377d68d54d8eaf2037f3fe48021db3a.png

图 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 是默认的。参数类型对应支持的接口协议如下图所示:

b849c65d53837453dcf58fdbfffbe7de.png

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


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

d05c912bd7bd87ebd2d0ad1f7c501182.png

图 3.3.10 运行C仿真


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

e923738d7905a2b0e3b5644663f0dadc.png

图 3.3.11 C调试器配置界面


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

c0bb846a275a0fde0e8f594d0969b7d4.png

图 3.3.12 单步调试


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

578794a7bcf7013b5340cce2d47b04c2.png

图 3.3.13 变量观察窗口


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

8c4801221bf55f4bb66ab6a0dc096ef7.png

图 3.3.14 导出RTL


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

bea7eff9c3e4cf1fd8c1873203548dd2.png

图 3.3.15 将设计导出成IP


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

1a422d3e5a711eed25443dc25b0ccb05.png

图 3.3.16导出得到的IP


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

84ef31c351f3785bd0fb10a6d763a2de.png

图 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工程目录保持一致,如下图所示:

97d661aa8f046600e015f588db05d16d.png

图 3.4.1 创建Vivado工程


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

dc31ee8d424e5d5ad749a02dc7b63f07.png

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


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

5fecdaf10d66699489a44bce17d7fd87.png

图 3.4.3 拷贝并解压IP


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

36d8e06021aa05fa11a7de8459a7baf6.png

图 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,并在文件中添加以下管脚约束信息:

  1. set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
  2. set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
  3. set_property -dict {PACKAGE_PIN L20 IOSTANDARD LVCMOS33} [get_ports key[0]]
  4. set_property -dict {PACKAGE_PIN J20 IOSTANDARD LVCMOS33} [get_ports key[1]]
  5. set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
  6. 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熄灭。如下图所示:

a74fee2cfda92648fbec40538b7b49af.png

图 3.5.1 按键控制LED实验现象

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值