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:M14M15

    • 电平:都是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

  • 在左边NetlistNets中需要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/
作者
Shuusui
发布于
2025年3月4日
更新于
2025年3月8日
许可协议