学习编程,最重要永远就是动手,本文将在开发板上实现FPGA的“Hello world”→流水灯。本文主要目的是熟悉在Vivado上从零到程序运行起来的基本开发流程。
1 硬件电路介绍
本人购买的开发板接在PL端的只有2个LED灯,刚好达到流水灯的最低要求。
根据原理图可知
1 这两个PL端的LED分别接在FPGA的P15脚和U12脚,另外,要点亮LED灯,FPGA应该输出低电平。
2 我们以开发板上的一个按钮作为系统的复位按钮,端口P16,取名rst_n。(reset negative的缩写,即低电平复位的意思)
3 系统的输入时钟是50MHz,即时钟周期为1s/50_000_000 = 20ns。 系统时钟的引脚为:N18。
2 时序设计
以前总听学FPGA的小伙伴说,学FPGA的时候,时序是最重要的,所以我一直着重关注时序。 本文及后续的CSDN博客我都将亲自用Wavedrom-Editor这个软件把时序图绘制一遍,加深理解。
Wavedrom-Editor的json代码如下:
{signal: [
{name: 'clk', wave: 'p.......................'},
{},
{name: 'rst_n', wave: '0.1.....................'},
{},
{name: 'cnt', wave: '2..222222222222222222222', data: ['0', '1', '2', '3','...','MAX','0','1','2','3','...','MAX','0','1','2','3','...','MAX']},
{},
{name: 'led', wave: '2.......2.....2.....2222', data: ['2b\'01','2b\'10','2b\'01']},
{name: '', },
{name: 'output', wave: '2.......2.....2.....2222', data: ['2b\'10','2b\'01','2b\'10']},
{name: '', }
]}
从时序图可知, 当系统处于复位状态时(rst_n为低电平), 计数器cnt清零,LED灯只点亮第一个当led = 2’b01时,就表示点亮第一个LED灯。由于要点亮LED灯是低电平点亮,因此在输出的时候,要给led取反,即output = ~led。 复位结束后,计数器cnt开始递增计数,当cnt计数到最大值MAX时,cnt清零,同时,对led进行移位操作,我们这里由于只有两个LED灯,所以从图中可能看不出来效果,如果是4个LED灯,那led的变化就是 4’b0001 → 4’b0010 → 4’b0100 → 4’b1000 → 4’b0001 → 4’b0010…
假设我们1s中切换一次,clk的时钟周期是20ns,那么MAX = 1s/20ns = 5000_0000;
3 从零运行VivadoFPGA项目操作流程
3.1 创建一个新的空白项目
截图警告!
3.2 添加源文件
截图警告!
往led.v添加以下代码
`timescale 1ns / 1ps
module led(
input wire clk,
input wire rst_n,
output wire [1:0] led_n
);
//==================================================================
// Parameter define
//==================================================================
parameter MAX = 5000_0000 - 1;
//==================================================================
// Internal Signals
//==================================================================
reg [1:0] led;
reg [25:0] cnt; // 2^26 = 6710_8864 > 5000_0000;
assign led_n = ~led;
//----------------------------- cnt -----------------------------
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
cnt <= 'd0;
end
else if (cnt==MAX) begin
cnt <= 'd0;
end
else begin
cnt <= cnt + 1'b1;
end
end
//----------------------------- led ------------------------
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
led <= 2'b01;
end
else if (cnt==MAX) begin
led <= {led[0],led[1]};
end
else begin
led <= led;
end
end
endmodule
3.3 添加约束文件
截图警告!
往top_pin.xdc里面添加以下代码
create_clock -period 20.000 [get_ports clk]
set_property PACKAGE_PIN N18 [get_ports clk]
set_property PACKAGE_PIN P16 [get_ports rst_n]
set_property PACKAGE_PIN P15 [get_ports {led_n[0]}]
set_property PACKAGE_PIN U12 [get_ports {led_n[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports {led_n[*]}]
3.4 编译运行程序
截图警告!
3.5 运行结果
Lab1_FPGA_led_RUN
最后愿我们共同进步! 感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。
在后续更新的博客中将会详细讲解 Verliog基础语法及添加管脚约束。本文将不在对本文提供的源代码及管脚约束进行详细的讲解。