点亮你的 LED 灯
文章目录
1 设计流程
FPGA 的设计流程我们这里归为了九个步骤
-
设计规划
在这一步我们首先对项目的需求有一个了解,根据项目需求进行系统结构的设计,进而进行系统层次的划分,也就是进行子功能模块的划分。我们还要搞清楚各个子功能模块的输入输出信号,以及各个子功能模块之间的结构关系和信号传递的关系。那么搞清楚设计规划之后,我们就可以进入第二步 -
波形绘制
在这一步骤,我们要具体了解各个子功能模块的模块功能,绘制出子功能模块的模块框图,搞清楚如何通过输入信号和内部声明的诸多变量得到我们需要的输出信号,来实现我们的子功能,进而绘制出功能实现的时序波形图。为什么要进行波形图的绘制呢? 原因有两个- 第一是有利于模块功能实现的理解
模块功能的实现,就是通过我们的输入信号得到我们需要的输出信号。输入信号与输出信号之间的关系你可以理解为是时间与逻辑的关系,表示这种关系最清晰和直观的方式就是波形图。而且 FPGA 本身它是并行执行,当存在较多信号时,仅仅靠我们的记忆和联想很难理清各信号之间的时序与逻辑的关系。所以说我们要通过绘制波形图的方法,来将这种关系表达出来。 - 第二就是因为波形图的绘制更加方便代码的编写
参考波形图可以更加清晰直观的了解各个信号的跳变点和跳变条件,代码写起来更加轻松、准确率高,而且如果进行项目的升级,参考波形图更加的方便、直观。
- 第一是有利于模块功能实现的理解
那么波形图绘制完成之后我们进入第三步
-
代码编写
我们参照绘制的波形图可以很快完成代码的编写。那么代码编写完成之后进入第四步 -
代码编译
我们使用开发工具对编写的代码进行编译,比如说我们前面安装的 Quartus II 开发软件。编译的目的是检查代码中的语法错误,如果出现语法错误对代码进行修改再编译,直至编译通过。那么代码通过编译之后我们进入第五步 -
逻辑仿真
在这一步骤我们将编写仿真代码,对我们刚刚编写的 Verilog 代码进行逻辑仿真验证,仿真出模块各信号的波形。那么仿真出波形之后进入第六步 -
波形对比
我们将仿真波形与我们绘制的波形图进行对比,如果俩波形图存在差异,我们需要找到问题的所在。如果是绘制波形图的问题,对波形图进行修改。参照修改后的波形图对代码进行修改,然后编译、查找语法错误,再次仿真和波形对比。如果是代码编写存在问题,对代码进行修改,然后编译、查找语法错误,再次仿真,然后波形对比。直到仿真波形与绘制波形图各波形的变化一致,那么通过仿真。通过仿真之后,进入第七步 -
绑定管脚
将工程中的输入输出信号与对应的 FPGA 芯片的 IO 管脚进行绑定,这一步可以通过引脚勾选或者编写引脚约束来实现。管脚绑定之后我们进入第八步 -
分析综合、布局布线
对整个工程进行分析综合、布局布线生成网表文件。随后进入最后一步 -
上板验证
将生成的网表文件下载或者固化到板卡,验证项目功能是否实现。若达到预期目标,上板验证成功,项目基本完成;若验证不成功呢?找到问题的所在,进行修改直至上板验证通过
那么以上就是 FPGA 项目设计的一个大致流程,都是理论部分。
接下来我们就以 点亮你的LED灯 这个实验为例,实际操作一下整个流程。因为只有理论与实践相结合,我们才能够更加深刻的理解与掌握。
在实践开始之前,我们先来了解一下项目工程的文件体系。我们将不同类型的文件进行分类,存放到不同的文件夹中。这样的目的是为了方便文件的查找、管理和移植。
首先我们找一个位置,新建一个文件夹。我们是以 点亮你的LED灯 工程为例
我们新建一个文件夹,命名为 led,这个就是我们实验工程的存放位置
我们打开文件夹,我们在主体文件夹下需要新建 4 个文件夹
- 第一个文件夹是 doc 文件夹
它主要放置一些文档资料,比如说数据手册、我们绘制的波形图,你自己编写的文档或者项目日志等等 - 第二个文件夹是 quartus_prj 文件夹
这个文件夹主要放置的是工程文件,我们使用的 Quartus II 开发软件新建的工程就保存到这个文件夹下。如果你使用的是 ISE 开发工具,你就可以命名为 ise_prj,这样能够很清晰的知道你使用的开发软件 - 第三个文件夹我们新建 rtl 文件夹
rtl 文件夹主要放置可综合的代码,就是最后可以生成硬件电路的代码,那么为什么叫 rtl 呢?因为这部分代码主要是寄存器描述的寄存器传输级的代码,rtl 是寄存器传输级的英文首字母缩写。当然了,你也可以命名为 design,因为它也是我们的设计文件 - 最后一个文件夹是 sim 文件夹
它主要放置对可综合代码的仿真文件,所以说你也可以命名为 test_bench 或者 tb
主要的文件夹就这 4 个。后期的一些项目工程有可能还会用到其他的辅助开发软件,比如说 MATLAB。到时候你就可以再新建一些文件夹管理他们的文件。
以上就是文件体系的内容,下面正式开始设计流程的实践。
2 点亮你的LED灯
第一是设计规划。
2.1 设计规划
2.1.1 实现功能
我们的项目名称是点亮一个 LED 灯,怎么实现它的功能呢?
我们想到:可以使用按键控制 LED 灯的亮灭。
功能的实现确定了之后,我们进行层次的划分
2.1.2 划分层次
层次的划分就是将整个系统划分为子功能模块。
那么我们这里一个模块就可以实现功能,所以说不需要进行划分
2.1.3 硬件资源
接下来看一下硬件资源
我们使用了按键来点亮我们的 LED 灯,我们可以使用我们的按键 KEY1 来点亮我们的 LED 灯 D6
![image-20231008213117461](https://i-blog.csdnimg.cn/blog_migrate/099f0bc2bc4fecc9015068c399844d82.png)
接下来看一下原理图
![image-20231009082913766](https://i-blog.csdnimg.cn/blog_migrate/1caab54c5fb84357e1163c892e1e7b7e.png)
按键的电路部分 KEY1 这个位置是与 FPGA 芯片相连接的,它的信号作为输入,会输入到我们的 FPGA 芯片当中。3V3 处电压为高,如果按键没有被按下时,输入到 FPGA 芯片的是高电平,电流流向是标号 1 这样的;如果按键按下时,电流流向是标号 2 这样的,输入到 FPGA 芯片的就是低电平。所以说,按键未按下输入为高电平,按键按下时输入为低电平。
再来看一下 LED 灯部分
![image-20231009084013857](https://i-blog.csdnimg.cn/blog_migrate/447dbc08047cd44bd6f4163a7d8f1263.png)
我们的 LED 灯,一端连接的是高电平,另一端连接的是 FPGA 芯片。LED0 这个端口它是负责接收 FPGA 芯片传出的信号,当 FPGA 芯片传入到 LED 灯是高电平时,高电平与高电平没有电位差,LED 灯不被点亮;如果传入的是低电平,那么高电平与低电平之间有电位差,那么 LED 灯会被点亮。
以上就是硬件资源部分。
为什么不进行芯片的选型?因为我们这里只是 FPGA 的学习,并不是项目的开发,所以说我们现在不涉及芯片的选型,大家不需要考虑。
2.2 波形绘制
第一步设计规划完成之后就要进行波形的绘制,波形的绘制我们要新建一个 Visio 文件。
2.2.1 新建 Visio 绘图文件
打开我们之前新建的 led 文件夹,找到 doc 子文件夹,在这个位置我们可以存放我们的 Visio 绘图。点击鼠标右键,新建一个 Visio 绘图文件,把它的名称命名为 led
双击打开,Visio 软件打开之后,会让我们选择绘图类型,我们直接点击 取消
打开 Visio 文件之后,我们要进行波形工具箱的加载(点击我下载波形工具箱)(点击我查看波形工具箱添加方法)
2.2.2 波形工具箱
点击 更多形状,点击 我的形状,然后勾选 3 个波形工具箱,随后我们可以看到 3 个波形工具箱已经加载成功。
使用第一个波形工具箱——FPGA_DESIGN,我们可以完成波形图的绘制。里面包含很多波形工具,比如说:
![image-20231009112918780](https://i-blog.csdnimg.cn/blog_migrate/86cc78a30a5a8bb80292390d113f35fe.png)
![image-20231009112420879](https://i-blog.csdnimg.cn/blog_migrate/ed9819f4207053da3f0f0718bd2e56e6.png)
![image-20231009112507276](https://i-blog.csdnimg.cn/blog_migrate/6fd33e06256b2051b2481c9057a37129.png)
![image-20231009112527702](https://i-blog.csdnimg.cn/blog_migrate/f6cc023e23c36a2d7a4742b77f38a137.png)
如果数据存在变化之后我们可以用 数据变化 来进行表示,我们也可以用直线来表示高电平或低电平的保持
![image-20231009121022570](https://i-blog.csdnimg.cn/blog_migrate/d5aea5b3107a39f8742f31e5eadc12cc.png)
如果信号波形较长而且重复的部分较多,可以用省略线
![image-20231009121319935](https://i-blog.csdnimg.cn/blog_migrate/59e3cf6857a90ff3930f6825454b9686.png)
使用第二个波形工具箱——状态机形状,我们可以进行状态机的绘制
比如说两个状态之间可以使用连线来表示状态的跳转,然后添加批注表示状态跳转条件
![image-20231009121845398](https://i-blog.csdnimg.cn/blog_migrate/c1dfefd9d305c5669521a91b0733bb57.png)
第三个工具箱是逻辑图,里边有反相器(非门)、与门、或门等我们常用的一些逻辑图
![image-20231009122538161](https://i-blog.csdnimg.cn/blog_migrate/1aa10e3650a70487059adeb071f0f19e.png)
2.2.3 Visio 绘图的一些基本操作
如果我们想要实现框图的绘制,我们需要添加 更多形状,找到 常规,找到 基本形状。可以使用里边的各种图形进行框图的绘制,比如说我们使用 圆角矩形 表示框图
然后选择 线条,使用线条表示输入输出信号。
如果表示输入信号,我们选中输入信号,然后选择 线条,选择 箭头,这个方向可以表示输入信号
选中输出信号,选择 线条,这样就可以表示输出信号
同样的,也可以表示输入输出信号
如果进行多个框图的绘制,为了便于区分,我们可以为它进行颜色的填充
那么以上就是 Visio 绘图的一些基本操作。
下面我们就开始波形图的绘制。
2.2.4 框图绘制
首先先要绘制一个框图(就是 LED 的框图),我们选择 圆角矩形,然后鼠标双击命名为 led,可以进行字体的放大
模块有两个信号:一个是输入信号,一个是输出信号。输入信号我们添加箭头,输出信号也添加箭头
输入信号由按键输入,我们可以命名为 key_in
输出信号是输出给 LED 灯的,我们可以命名为 led_out
模块框图绘制完成。
2.2.5 波形图绘制
模块框图部分我们只需要知道输入信号、输出信号就可以,具体模块功能的实现我们是不关心的,模块功能的实现要使用波形图来表示。接下来进行波形图的绘制
首先新建两个文本框,分别命名为 key_in 和 led_out。为了对输入输出信号进行区分,我们填充不同的颜色:输入信号我们填充绿色,输出信号我们一般填充红色;如果使用了内部变量,我们可以填充为黄色(或者你喜欢的其他颜色)
在前面硬件资源部分我们已经提到了:我们的按键未按下时按键电路部分输出“1”,按键按下时按键电路部分输出“0”。我们的 LED 灯输入“0”点亮,输入“1”熄灭。那么我们就使用我们的波形来表示输入信号的高低电平变化
我们使用按键控制 LED 灯,而且结合前面硬件资源部分的知识,我们可以绘制输出波形的波形图
其实输出波形的波形变化和输入波形的波形变化是一样的。也就是说按键按下时 LED 灯点亮,松开按键时 LED 灯熄灭
2.3 代码编写
那么波形图绘制完成之后,我们进行代码的编写。
2.3.1 新建 Verilog 文件
打开 rtl 文件夹,点击鼠标右键,新建 .v 文件。
首先是新建一个文本文档,命名为 led,将后缀名改成 .v
这样就完成了 .v 文件的创立。
2.3.2 编写代码
双击打开 .v 文件,接下来进行代码的编写。
首先是模块的开始 module
,结束是 endmodule
,模块名称是 led
,输入信号是按键 key_in
,输出信号是 LED 灯 led_out
。因为输入信号和输出信号波形变化一致,我们直接使用组合逻辑 assign led_out = key_in;
将输入信号赋值给输出信号。
led.v
module led
(
input wire key_in,
output wire led_out
);
assign led_out = key_in;
endmodule
好了,代码编写完成,我们 Ctrl+s 保存。
2.4 代码编译
接下来就是代码的编译,代码编译之前先要新建工程。
我们回到桌面,鼠标左键双击开发软件快捷方式,进入了欢迎界面。
开发软件打开之后,首先出现的是快捷窗口
我们这里直接点击右上角的✗关掉。
2.4.1 新建 Quartus 工程
新建一个工程有两种方式:第一种是 File 选择 New…,第二种也是 File 选择 New Project Wizard…,我们选择第二种方式
进入了向导界面,在第一个界面点击 Next
在第二个界面的第一个选项卡中选择文件存放位置,我们选择我们之前建立的文件夹,选择 quartus_prj 文件夹
点击选择文件夹
第二个选项卡是工程名称,我们写入 led,第三个选项卡默认与第二个选项卡相同,我们直接点击下一步
第三个界面是加载我们写好的 .v 文件,我们这里不先加载,直接点击下一步
在这里进行器件的选择,我们选择 Cyclone IV E,封装方式选择 FBGA,引脚数选择 256,速度等级选择 8,经过筛选之后,选择我们的芯片型号 EP4CE10F17C8,点击下一步
下面的界面是 EDA 工具的设置,我们直接点击下一步
最后的界面可以对我们的设置进行一个检查,没有问题之后我们选择 Finish
2.4.2 加载 RTL 代码文件
工程就新建完成,我们开始代码的编译。
首先需要将我们编写的 .v 文件加载到工程当中,点击 File 选项卡,点击 Files,点击 鼠标右键,选择 Add/Remove Files in Project…(加载文件)
然后选择我们编写的 .v 文件,点击打开,点击 Add(添加),点击 Apply(应用),点击 OK
我们就可以发现我们编写的 .v 文件已经添加到项目当中
![image-20231009180539103](https://i-blog.csdnimg.cn/blog_migrate/47d981dea78d5fcd45d921676f878f60.png)
2.4.3 编译代码
接下来就是对代码进行编译,我们可以直接点击工具栏上的 Start Compilation 图标,代码编译通过,我们点击 OK
2.5 逻辑仿真
接下来要进行逻辑的仿真。
逻辑仿真是对我们编写的代码进行仿真验证,测试设计电路的整体功能、部分性能是否达到预期的目标。他就是使用仿真文件产生模拟的激励,输入到被测试模块当中,然后观察输出响应是否达到要求
![image-20231009181546204](https://i-blog.csdnimg.cn/blog_migrate/d0c14eb83a06285359a697010caf507c.png)
2.5.1 编写仿真文件
代码的逻辑仿真需要编写仿真文件,因为本章节只是学习了解一下 FPGA 的设计流程。所以说,我们直接使用编写好的测试文件 tb_led.v
`timescale 1ns/1ns
///
// Author : EmbedFire
// Create Date : 2019/03/12
// Module Name : tb_led
// Project Name : led
// Target Devices: Altera EP4CE10F17C8N
// Tool Versions : Quartus 13.0
// Description : 按键控制LED灯仿真文件
//
// Revision : V1.0
// Additional Comments:
//
// 实验平台: 野火_征途Pro_FPGA开发板
// 公司 : http://www.embedfire.com
// 论坛 : http://www.firebbs.cn
// 淘宝 : https://fire-stm32.taobao.com
//
module tb_led();
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire define
wire led_out ;
//reg define
reg key_in ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//初始化输入信号
initial key_in <= 1'b0;
//key_in:产生输入随机数,模拟按键的输入情况
always #10 key_in <= {$random} % 2; /*取模求余数,产生非负随机数0、1
每隔10ns产生一次随机数*/
//********************************************************************//
//**************************** Instantiate ***************************//
//********************************************************************//
//------------- led_inst -------------
led led_inst
(
.key_in (key_in ), //input key_in
.led_out(led_out) //output led_out
);
endmodule
2.5.2 加载测试文件
下一步是将测试文件加载到实验工程。
我们打开工程,点击 File,点击 鼠标右键,选择 Add/Remove Files in Project…(添加文件),找到我们的测试文件,点击 Add(添加),点击 Apply(应用),点击 OK,测试文件已经成功添加
2.5.3 仿真设置
接下来是仿真的设置
我们选择菜单栏上的 Assignments 菜单,点击 Settings…(设置),选择仿真选项卡,在这一选项卡中选择 ModelSim 表示我们使用第三方仿真软件 Modelsim,选择我们的语言 Verilog 语言,时间参数选择默认,仿真文件输出存放位置 可以选择默认,也可以选择我们刚刚建立的 sim 文件夹,我们这里可以选择默认
2.5.4 设置 Test Bench
接下来是仿真文件的添加,勾选 Compile test bench: 选项,点击 Test Benches…,点击 New…(新建),设置 Test Bench 名称,要与我们编写的测试文件名称相同,我们写入 tb_led。第二个名称和第一个名称一般保持一致
接下来选择 End simulation at: 选项,时间单位我们选择 us,写入 1
这表示仿真会执行 1us 然后停止
添加我们的仿真文件,选择 tb_led.v 文件,点击 Open,点击 Add(添加),点击 OK,点击 OK,点击 Apply(应用),点击 OK
2.5.5 代码仿真
接下来就可以进行代码的仿真,我们点击工具栏上的 RTL Simulation 图标,这样就可以使用开发软件调用第三方的 Modelsim 进行代码的仿真,Modelsim 软件打开后,要进行一段时间的编译
编译完成之后,我们点击 Wave 窗口,打开波形查看界面
在这个窗口我们可以进行仿真波形的查看
在仿真波形界面,我们常用的有几个选项:第一个是重新开始,点击重新开始会弹出一个重新开始对话框,我们点击 OK
![image-20231009190011996](https://i-blog.csdnimg.cn/blog_migrate/698cb2f4aad42ae3fae5eb9a62861fe8.png)
它的功能是清除之前的仿真波形
另外几个选项
![image-20231009191136308](https://i-blog.csdnimg.cn/blog_migrate/2f857e4679029286645b7629e5c05a07.png)
我们点击波形的任意位置,会添加一个参考线,点击这个位置 会以参考线为中心进行放大,点击左下角这个位置 会对参考线进行锁定,点击这个位置 会添加另外的参考线,点击这个位置 会对参考线进行删除
使用两根参考线,可以确定时间间隔,点击这个选项,会对俩参考线之间的部分进行放大,点击这个位置,可以进行参考线的删除
2.6 波形对比
我们解除锁定,对信号波形进行放大
由仿真波形我们可以看到,输出到 LED 灯的信号波形与按键输入的信号波形是一致的,这与我们绘制的波形图波形变化一致,仿真通过。
2.7 绑定管脚
接下来进行管脚的绑定。打开工程文件,点击这个工具栏上的 Pin Planner 图标可以打开管脚绑定界面
在引脚绑定的窗口有很多的列表。
- 第一个列表显示的是 代码中定义的端口名称
- 第二个列表 表示信号输入输出方向
- 第三个列表 表示管脚绑定的位置
- 第四个列表,表示引脚存在的 bank
- 第五个列表 表示电压参考
- 第六个列表 表示通过过滤选项 显示指定种类的管脚
- 第七个列表,表示 I/O 口电平约束
- 第八个列表 保留
- 第九个列表 是驱动电流强度
![image-20231009193811193](https://i-blog.csdnimg.cn/blog_migrate/d4c6ea5b768884006af92055575e853c.png)
我们开始管脚绑定,点击第三个列表。
因为“KEY1”按键与 FPGA 芯片的 M2 端口相连接,我们输入 M2,点击回车;D6 LED 灯与 FPGA 芯片的 L7 引脚相连接,我们输入 L7,点击回车,这样就完成了引脚的绑定
2.8 分析综合
回到工程我们再次进行全编译,全编译完成,界面为我们提供了很多有用的信息
![image-20231009195428826](https://i-blog.csdnimg.cn/blog_migrate/b2bc7f6a1e5e3af549c04b6fc980361e.png)
我们点击 OK
2.9 上板验证
全编译通过之后,我们可以进行上板验证
我们如图所示连接板卡的电源和下载器,下载器的另一端连接电脑
点击工具栏上的 Programmer 图标,选择 Add File…(添加文件),找到 output_files 文件夹,选择我们的 led.sof 文件,点击 Open,点击 Start(开始),文件下载完成
我们打开摄像头
按下按键 KEY1,我们的 D6 点亮,松开 KEY1,D6 熄灭,实验工程的功能实现
烧录 SOF 文件点亮 LED
接下来进行程序的固化,为什么要进行固化呢?因为我们下载到 FPGA 的程序断电之后就会丢失,但是如果进行程序的固化之后,断电后重新上电,仍可以执行固化的程序。那么如何实现程序的固化呢?
首先我们要先生成 jic 文件,选择 File(文件)选项卡,找到 Convert Programming Files…,在 Programming file type: 选项中选择我们要生成的 jic 文件,在 Configuration device: 选项选择 EPCS16,这个型号与我们板卡的 Flash 芯片型号(W25Q16)是通用的
File name: 表示的是 jic 文件将要存放的位置以及 jic 文件的名称。接下来选择 Flash Loader,点击 Add Device…(添加器件),选择我们的 FPGA 芯片,点击 OK
接下来点击 SOF Data,选择 Add File…(添加文件),找到我们的 sof 文件,点击 Open(打开),点击 Generate(生成),弹出的窗口提示我们 jic 文件生成成功,点击 OK
我们可以回到文件夹中查看我们的 jic 文件,在这个位置就生成了我们的 jic 文件
我们回到程序下载窗口,选择我们之前添加的 sof 文件,删除,然后选择 Add File…(添加文件),选择我们刚刚生成的 jic 文件,点击 Open
勾选 Program/Configure,点击 Start(开始),这样就开始了程序的固化,经过一段时间的等待,程序固化完成
我们打开我们的摄像头,程序固化完成之后要重新上电,我们先断电然后上电,点击按键 LED 灯被点亮,松开按键 LED 灯熄灭,再次断电然后重新上电,点击按键 LED 灯被点亮,松开按键 LED 灯熄灭,程序固化成功
烧录 JIC 文件点亮 LED
程序固化完成之后 我们第二部分的内容学习完毕。
参考资料: