FPGA
1. Vivado
1.1 设计流程
新建工程,添加设计文件。
module led_twinkle( input sys_clk, // 系统时钟 input sys_rst_n, // 系统复位,低电平有效 output [1 : 0] led // LED灯 ); reg [25 : 0] cnt; assign led = (cnt < 26'd2500_0000) ? 2'b01 : 2'b10; always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) cnt <= 26'd0; else if(cnt < 26'd5000_0000) cnt <= cnt + 1'b1; else cnt <= 26'd0; end endmodule
分析:打开
RTL ANALYSIS
可以查看原理图。在右上角选择I/O Planning
设置引脚约束,从原理图中查找每个端口对应的引脚。时钟:
U18
按键:
N15
LED:
M14
、M15
电平:都是
LVCMOS33
配置结果如下图,然后Ctrl+S保存约束文件(xdc文件)。
也可以不用图形界面,直接创建xdc文件,下面几行是简写。
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk] set_property -dict {PACKAGE_PIN N15 IOSTANDARD LVCMOS33} [get_ports sys_rst_n] set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {led[1]}] set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
综合、实现、下载到开发板。
1.2 ILA
ILA:Integrated Logic Analyzer
1.2.1 通过IP核添加ILA
在
IP Catalog
中搜索ILA,进行端口数、深度、位宽的配置。实例化ILA,可以从
IP Sources
中ILA的源码中复制实例化模板。ila_0 my_ila ( .clk(sys_clk), // input wire clk .probe0(sys_rst_n), // input wire [0:0] probe0 .probe1(led), // input wire [1:0] probe1 .probe2(cnt) // input wire [25:0] probe2 );
综合、实现、下载、触发。
1.2.2 通过网表添加ILA
综合后,打开综合界面,右上角选择
Debug
。在左边
Netlist
的Nets
中需要debug的信号上右键选择Mark Debug
(需要是IBUF或OBUF的信号)。如果信号被优化了,可以在代码中添加如下语句使之不被优化,添加该语句也会自动将该信号加入debug。
(* mark_debug = "true" *) reg [25 : 0] cnt;
点击左边的
Set Up Debug
进入向导,设置信号的时钟、ILA的深度等。然后保存,xdc文件会多出一些调试用的语句。综合、实现、下载、触发。
1.3 仿真
- 仿真单位:延迟时间的单位。比如单位为
1ns
,则#10
是延迟10ns
。 - 仿真精度:如下面的代码,表示延迟时间可以精确到
ps
,比如可以写#100.123
。
`timescale 1ns / 1ps // 仿真单位 / 仿真精度
module tb_led_twinkle;
reg sys_clk;
reg sys_rst_n;
wire [1:0] led;
initial begin
sys_clk = 1'b0;
sys_rst_n = 1'b0;
#200
sys_rst_n = 1'b1;
end
always #10 sys_clk = ~sys_clk;
led_twinkle u_led_twinkle(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.led (led)
);
endmodule
1.4 时序约束
具体操作:在综合或实现界面点击左边的Edit Timing Constraints
,添加时钟即可,记得保存。或直接在xdc文件中添加如下语句:
create_clock -period 20.000 -name sys_clk -waveform {0.000 10.000} [get_ports sys_clk]
2. 按键消抖
module key_debounce(
input sys_clk,
input sys_rst_n,
input key, // 按键按下为0
output reg key_flag // 检测到按下时输出1,只持续1周期
);
// 对于50MHz的时钟来说是20ms
localparam CNT_MAX = 20'd100_0000;
reg [19:0] cnt;
always @(posedge sys_clk) begin
if (!sys_rst_n) cnt <= 20'd0;
// 按键按下,cnt递增到最大值
else if (!key) begin
if (cnt >= CNT_MAX) cnt <= cnt;
else cnt <= cnt + 20'd1;
end
else cnt <= 20'd0;
end
always @(posedge sys_clk) begin
if (!sys_rst_n) key_flag <= 1'd0;
// 减1是为了保证只持续1周期
if (cnt == CNT_MAX - 20'd1) key_flag <= 1'd1;
else key_flag <= 1'd0;
end
endmodule
FPGA
https://shuusui.site/blog/2025/03/04/fpga/