目录
Vivado 下 LED 灯闪烁实验
1、简介
2、实验环境
3、实验任务
4、硬件设计
5、程序设计
5.1、LED 闪烁模块代码
5.2、Vivado 仿真验证
5.2.1、编写 TB 仿真代码
6、下载验证
6.1、添加约束文件 .xdc
6.2、下载验证
注意:一定要先把下载器的一端连接到了电脑、另一端连接了 JTAG 接口之后,再给开发板上电!否则,对开发板的 JTAG 接口进行带电热插拔,有一定概率会损坏 JTAG 接口!!!
LED 灯闪烁作为一个经典的入门实验,其地位堪比编程界的“Hello,World!”。对于很多电子工程师来说,LED 灯闪烁都是他们在硬件上观察到的第一个实验现象。本章我们同样通过 LED 灯闪烁实验,带你进入 FPGA 的精彩世界。
LED,又名发光二极管。LED 灯工作电流很小(有的仅零点几毫安即可发光),抗冲击和抗震性能好,可靠性高,寿命长。由于这些优点,LED 灯被广泛用在仪器仪表中作指示灯、液晶屏背光源等诸多领域。
不同材料的发光二极管可以发出红、橙、黄、绿、青、蓝、紫、白这八种颜色的光。图 7.1.1 是可以发出黄、红、蓝三种颜色的直插型二极管实物图,这种二极管长的一端是阳极,短的一端是阴极。图 7.1.2 是开发板上用的贴片二极管实物图。贴片二极管的正面一般都有颜色标记,有标记的那端就是阴极。
发光二极管与普通二极管一样具有单向导电性。给它加上阳极正向电压后,通过 5mA 左右的电流就可以使二极管发光。通过二极管的电流越大,发出的光亮度越强。不过我们一般将电流限定在 3~20mA 之间,否则电流过大就会烧坏二极管。
本节实验任务是使用 Xinlinx 黑金 FPGA 开发版上的 LED0 和 LED1 以固定的频率交替闪烁。
四个 LED 灯均有连接三极管,这是由于 LED0~LED3 连接到了 FPGA 的 IO,但是电压只有 1.35V,电压较低,所以此处连接三极管,起到放大信号的作用。当 FPGA 输出 LED0~LED3 为高电平时,三极管导通,点亮 LED 灯;当 FPGA 输出 LED0~LED3 为低电平时,三极管截止,LED 灯熄灭。
由于发光二极管的阳极与 FPGA 的管脚相连,只需要改变与 LED 灯相连的 FPGA 管脚的电平,LED 灯的亮灭状态就会发生变化。当 FPGA 管脚为高电平时,LED 灯点亮;为低电平时,LED 灯熄灭。
本次设计的模块端口及信号连接如下图所示:
其中,计数器对 50MHz 时钟进行计数,从而达到计时的目的。计数器在每次计时到 1 秒之后清零,然后重新开始计数,计数的值用于控制 LED 的显示状态。当计数器的值小于 0.5s 时,就把 LED0 点亮并把 LED1 熄灭;每当计数器的值大于 0.5s 时,就把 LED0 熄灭并把 LED1 点亮,以此实现两个 LED 的交替闪烁。
LED 闪烁模块的代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/05/09 19:57:15
// Design Name:
// Module Name: led_twinkle
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module led_twinkle(
// input sys_clk, //50MHz系统时钟
//differential system clocks//200MHz系统时钟
input sys_clk_p, //system clock positive
input sys_clk_n, //system clock negative
input sys_rst_n, //系统复位,低电平有效
output [1:0] led //2位LED灯
);
//FPGA板载50MHz时钟,所以一个时钟周期为:1/50MHz=20ns,
//计数器通过对50MHz系统时钟计数,计时到0.5s,需要累加0.5s/20ns=25000_000次。
//黑金Artix7A35t板载200MHz时钟,所以一个时钟周期为:1/200MHz=5ns,
//计时到0.5s,需要累加0.5s/5ns=100_000_000次。
//define the time counter
reg [31:0] cnt;
//*********差分时钟这么处理***START******************
wire sys_clk;
//差分输入时钟缓冲器-黑金FPGA
IBUFDS sys_clk_ibufgds //generate single end clock
(
.O (sys_clk ),
.I (sys_clk_p ),
.IB (sys_clk_n )
);
//*********差分时钟这么处理*****END*******************
//************************************************
//** main code
//************************************************
//对计数器的值进行判断,以输出LED的状态
assign led = (cnt<32'd10000_0000)?2'b01:2'b10;
//assign led = (cnt<32'd5)?2'b01:2'b10; //仅用于仿真
//计数器在0~5000_0000之间进行计数
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt<=32'd0;
else if(cnt<32'd20000_0000)
//else if(cnt<32'd10) //仅用于仿真
cnt<=cnt+1'b1;
else
cnt<=32'd0;
end
endmodule
本程序中输入时钟为 200MHz,所以一个时钟周期为 5ns(1/200MHz)。因此计数器 cnt 通过对 200MHz 系统时钟计数,计时到 1s,需要累加 1s/5ns=20000_0000 次。在代码第 67 行,每当计时到 1s 计数器清零一次。
同时,在代码的第 58 行,对根据计数器的计数值来赋值两个 LED 的状态。当计数值小于 32'd1000_0000 即计时到 1s 中的前 500ms 时,LED0 点亮 LED1 熄灭;当计数值大于等于 32'd1000_0000,即计时到 1s 中的后 500ms 时,LED0 熄灭 LED1 点亮。当计数到 1s 时,计数器又会回 0,重复此过程。以此实现两个 LED 的交替闪烁。
为了验证我们的程序,我们在 Vivado 内对代码进行仿真。为了更容易地看到仿真现象,我们将源代码中的计数器的最大计数值修改为 5,然后再仿真,如下图所示:
因为本实验我们只有系统时钟和系统复位这两个输入信号,以及两个LED 灯输出信号,所以仿真文件也只需要编写这四个信号的激励即可。
Testbench 模块仿真代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/05/09 20:40:24
// Design Name:
// Module Name: tb_led_twinkle
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_led_twinkle(); //测试模块
//parameter T = 20; //50Mhz系统时钟,周期为20ns
parameter T = 5; //黑金FPGA-差分时钟:200Mhz系统时钟,周期为5ns
//输入
//reg sys_clk;
reg sys_clk_p; //时钟信号
wire sys_clk_n;
reg sys_rst_n;
//输出
wire [1:0] led;
//***************************************
//** main code
//***************************************
//信号初始化
initial begin
// sys_clk = 1'b0;
sys_clk_p = 1'b0;
sys_rst_n = 1'b0;
#200 //延时200ns
sys_rst_n = 1'b1;
end
//生成时钟
//always #(T/2) sys_clk =~sys_clk;
always #(T/2) sys_clk_p =~sys_clk_p;
assign sys_clk_n=~sys_clk_p;
//实例化待测设计
led_twinkle u_led_twinkle(
// .sys_clk (sys_clk),
.sys_clk_p (sys_clk_p),
.sys_clk_n (sys_clk_n),
.sys_rst_n (sys_rst_n),
.led (led)
);
endmodule
从图中可以看到,计数器 cnt 的值在 0 到 10 之间循环计数。当 cnt 的值小于 5 时,led0 为高电平;大于 5 时 led0 为高电平。两个 LED 的状态随着计数器的计数循环翻转,实现 LED 闪烁的效果。
添加约束文件 led_twinkle.xdc,添加约束文件.xdc 的详细步骤见: Vivado 下 LED 流水灯实验_OliverH-yishuihan的博客-CSDN博客 中的 “4.3、添加 XDC管脚约束文件”
约束文件 breath_led.xdc 的具体内容如下:
############## clock define 时钟引脚、电平信号约束#####黑金-FPGA##################
create_clock -period 5.000 [get_ports sys_clk_p]
set_property PACKAGE_PIN R4 [get_ports sys_clk_p]
set_property IOSTANDARD DIFF_SSTL15 [get_ports sys_clk_p]
############## reset key define##########################
set_property -dict {PACKAGE_PIN F15 IOSTANDARD LVCMOS15} [get_ports sys_rst_n]
############## LED define ############################
set_property -dict {PACKAGE_PIN L13 IOSTANDARD LVCMOS15} [get_ports {led[0]}]
set_property -dict {PACKAGE_PIN M13 IOSTANDARD LVCMOS15} [get_ports {led[1]}]
##############SPI Configurate Setting##################
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
编译工程并生成比特流.bit 文件后,点击 Vivado 左侧 “Flow Navigator” 窗口最下面的 “Open Hardware Manager” 按钮如下图所示。
此时将 Xilinx 下载器一端连接电脑,另一端与开发板上的 JTAG 下载口连接,开发板连接电源线,如下图所示:
经过前面的编译和仿真,我们可以把 bit 文件下载到 FPGA 芯片中,看一下 LED 实际运行的效果(两个 LED 灯交替闪烁)。下载和调试之前先连接硬件,把 JTAG 下载器和开发板连接(如下图是 AX7A200 开发板 JTAG 连接 作为参考),然后开发板上电。
详细步骤见:“ Vivado 下 LED 流水灯实验_OliverH-yishuihan的博客-CSDN博客” 中的 “4.6 下载和调试”、“4.7、FLASH 程序固化”