目录

1. 简介

1.1 要点

1.2 buffer 介绍

2. vivado 工程

2.1 Block Design

2.2 IBUFDS

2.3 BUFGCE_DIV

2.4 Processor System Reset

2.5 key_mod

2.6 led_drv

3. 编译与调试

3.1 XDC

3.2 Debug

4. 总结


1. 简介

1.1 要点

  • 了解 Utility Buffer v2.2 中的 Buffer,重点分析 IBUFDS 和 BUFGCE_DIV
  • 分析 Processor System Reset v5.0
  • 分析按键消抖模块(key_mod)
  • 了解与 ILA 相关自动生成的约束

1.2 buffer 介绍

  • IBUFDS:差分输入缓冲器,用于接收差分信号并将其转换为单端信号。
  • OBUFDS:差分输出缓冲器,用于将单端信号转换为差分信号输出。
  • IOBUFDS:差分输入/输出缓冲器,支持双向差分信号。
  • IBUFDSGTE:专用于 GTP/GTX 收发器的差分输入缓冲器。
  • BUFG:全局时钟缓冲器,用于将时钟信号分配到 FPGA 的全局时钟树中,减少时钟偏斜。
  • BUFGCE:带有时钟使能(Clock Enable)的全局时钟缓冲器,可以控制时钟信号的启用和禁用。
  • BUFGCE_DIV:带有时钟使能和分频功能的全局时钟缓冲器,可以对时钟信号进行分频。
  • BUFG_GT:专用于 GT 收发器的全局时钟缓冲器。
  • IOBUF:输入/输出缓冲器,支持双向信号。
  • OBUFDS_GTE:专用于 GTP/GTX 收发器的差分输出缓冲器。
  • OBUFDS_GTE_ADV:高级差分输出缓冲器,提供更高性能的差分信号输出。
  • BUFG_PS:专用于处理器系统的全局时钟缓冲器。

2. vivado 工程

2.1 Block Design

2.2 IBUFDS

差分输入缓冲器,用于接收差分信号并将其转换为单端信号。

在 Language Templates 中,可以找到 verilog 例化模板。

IBUFDS #(
.DIFF_TERM("FALSE"), // 差分端接
.IBUF_LOW_PWR("TRUE"), // 低功耗="TRUE",最高性能="FALSE"
.IOSTANDARD("DEFAULT") // 指定输入 I/O 标准
) IBUFDS_inst (
.O(O), // 缓冲器输出
.I(I), // Diff_p 缓冲器输入(直接连接到顶层端口)
.IB(IB) // Diff_n 缓冲器输入(直接连接到顶层端口)
);

2.3 BUFGCE_DIV

  • BUFGCE_DIV:能够进行简单分频的 BUFG,可进行1~8 分频
  • BUFG:全局时钟缓冲器,可以走专门的时钟资源,增强驱动能力,减少传播延迟
  • Fout = Fin / div,div = 1 to 8;

在 Language Templates 中,也可以找到 verilog 例化模板。

BUFGCE_DIV #(
.BUFGCE_DIVIDE(1), // 1-8
// 可编程反相属性:指定特定引脚上内置的可编程反相
.IS_CE_INVERTED(1'b0), // CE 的可选反相
.IS_CLR_INVERTED(1'b0), // CLR 的可选反相
.IS_I_INVERTED(1'b0), // I 的可选反相
.SIM_DEVICE("ULTRASCALE_PLUS") // ULTRASCALE, ULTRASCALE_PLUS
)
BUFGCE_DIV_inst (
.O(O), // 1位输出:缓冲器
.CE(CE), // 1位输入:缓冲器使能
.CLR(CLR), // 1位输入:异步清除
.I(I) // 1位输入:缓冲器
);

2.4 Processor System Reset

IP 用途

  • 同步异步复位信号:将异步外部复位(External Reset)和辅助复位(Auxiliary Reset)信号与时钟同步。
  • 配置复位信号:可以选择外部和辅助复位信号是低电平有效还是高电平有效,并设置复位信号的最小脉宽。
  • DCM 锁定输入:支持 DCM(数字时钟管理器)的锁定输入信号。
  • 生成上电复位信号:在系统上电时生成复位信号,确保系统在上电时处于已知状态。

外部/辅助复位有效宽度:复位信号有效电平需要持续指定的若干时钟周期才被视为有效信号,才会有复位输出。

复位信号的顺序输出:

  • 总线结构复位解除(互连和桥接)
  • 外设在 16 个时钟周期后复位解除(UART、SPI、IIC)
  • MicroBlaze 处理器在外设后 16 个时钟周期复位解除

Auxiliary Reset(辅助复位)信号通常用于提供额外的复位控制,除了主复位信号之外。它可以连接到系统中的其他复位源,例如调试器或其他控制逻辑。具体连接位置取决于你的设计需求和系统架构。

2.5 key_mod

按键消抖模块,用于消除由于机械或者接触不良造成的按键电信号的跳动(抖动)。

module key_mod (
    input   wire    i_sys_clk       ,
    input   wire    i_rst_n         ,
    input   wire    i_button        ,

    output  reg     o_pb_state      ,
    output  wire    o_pb_negedge    ,
    output  wire    o_pb_posedge
);

 ---------------- internal parameter ---------------
parameter       N               = 32    ; // debounce timer bitwidth
parameter       FREQ            = 200   ; // model clock :Mhz
parameter       MAX_TIME        = 20    ; // ms

 ---------------- internal localparam --------------
localparam      TIMER_MAX_VAL   =   MAX_TIME * 1000 * FREQ; // 20ms

//====================================================
// 按键下降沿检测:
//--              _   _   _   _   _   _   _   _   _
//-- CLK         | |_| |_| |_| |_| |_| |_| |_| |_| |
//--             ____
//-- button_r[1]     |______________________________
//--             ____                     __________
//-- PB_idle         |___________________|
//--                  ___________________
//-- add_PB_cnt  ____|                   |__________
//--                      ___ ___ ___ ___
//-- PB_cnt      ________/___X___X___X___\__________
//--                                  ___
//-- end_PB_cnt  ____________________|   |__________
//--             ________________________
//-- PB_state                            |__________
//--                                  ___
//-- PB_negedge  ____________________|   |__________
//====================================================

//====================================================
// 按键上升沿检测:
//--              _   _   _   _   _   _   _   _   _
//-- CLK         | |_| |_| |_| |_| |_| |_| |_| |_| |
//--                  ______________________________
//-- button_r[1] ____|
//--             ____                     __________
//-- PB_idle         |___________________|
//--                  ___________________
//-- add_PB_cnt  ____|                   |__________
//--                      ___ ___ ___ ___
//-- PB_cnt      ________/___X___X___X___\__________
//--                                  ___
//-- end_PB_cnt  ____________________|   |__________
//--                                      __________
//-- PB_state    ________________________|
//--                                  ___
//-- PB_posedge  ____________________|   |__________
//====================================================

//====================================================
// 消除亚稳态
//
//====================================================
reg     [1:0]   button_r;
always @(posedge i_sys_clk or negedge i_rst_n) begin
    if (!i_rst_n) begin
        button_r <= 2'b11;
    end
    else begin
        button_r <= {button_r[0], i_button};
    end
end

//====================================================
// 定义空闲状态 PB_idle,可以一直是高电平,
// 也可以一直是低电平
// 按键按下和松开,均开始计时
//====================================================
reg [N-1:0] PB_cnt;
wire        PB_idle = (o_pb_state==button_r[1]);
wire        add_PB_cnt;
wire        end_PB_cnt;

always @(posedge i_sys_clk or negedge i_rst_n) begin
    if (!i_rst_n) begin
        PB_cnt <= 16'b0;
    end
    else if (add_PB_cnt) begin
        if (end_PB_cnt)
            PB_cnt <= 16'd0;
        else
            PB_cnt <= PB_cnt + 16'd1;
    end
end

assign add_PB_cnt = ~PB_idle;
assign end_PB_cnt = add_PB_cnt && PB_cnt==TIMER_MAX_VAL-1;

always @(posedge i_sys_clk or negedge i_rst_n) begin
    if (!i_rst_n) begin
        o_pb_state <= 1'b1;
    end
    else if (end_PB_cnt) begin  //到达设定数值,认为按键稳定,改变PB_state状态
        o_pb_state <= ~o_pb_state;
    end
end

//====================================================
// 计时器到达设定值时,进行事件判断:
// PB_state常为高电平状态
// 下降沿:非空闲 && 计数完毕 && 当前状态为1
// 上升沿:非空闲 && 计数完毕 && 当前状态为0
// 注:PB_state会在end_PB_cnt脉冲后反转,故此处引用了
//     PB_state的当前状态
//====================================================
assign o_pb_negedge = ~PB_idle && end_PB_cnt && (o_pb_state==1'b1);
assign o_pb_posedge = ~PB_idle && end_PB_cnt && (o_pb_state==1'b0);

endmodule

2.6 led_drv

pulse 接口,每收到一个脉冲,led 翻转一次。

module led_drv (
    input           clk         ,
    input           rst_n       ,

    input           pulse       ,
    output reg      led
);

    always @(posedge clk or negedge rst_n)
    begin
        if (rst_n == 1'b0)
            led <= 1'b0;
        else if (pulse)
            led <= ~led;
        else
            led <= led;
    end

endmodule

3. 编译与调试

3.1 XDC

set_property PACKAGE_PIN K22        [get_ports {CLK_IN_D_0_clk_p[0]}]
set_property IOSTANDARD DIFF_SSTL12 [get_ports {CLK_IN_D_0_clk_p[0]}]

set_property PACKAGE_PIN H13     [get_ports ext_reset_in_0]
set_property IOSTANDARD LVCMOS33 [get_ports ext_reset_in_0]

set_property PACKAGE_PIN J13     [get_ports i_button_0]
set_property IOSTANDARD LVCMOS33 [get_ports i_button_0]

set_property PACKAGE_PIN H12     [get_ports led_0]
set_property IOSTANDARD LVCMOS33 [get_ports led_0]

set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]
set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]
set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]
connect_debug_port dbg_hub/clk [get_nets clk]

重点解释下与 ILA 相关的约束,它们用于配置调试核心(debug core)和连接调试端口。

1)set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]

  • 这条命令设置调试核心的输入时钟频率为300 MHz(300,000,000 Hz)。这意味着调试核心将以300 MHz的频率运行。

2)set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]

  • 这条命令禁用时钟分频器。也就是说,调试核心将直接使用输入时钟频率,而不会进行分频。

3)set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]

  • 这条命令设置用户扫描链的数量为1。扫描链用于调试和测试目的,允许多个调试核心串联在一起。

4)connect_debug_port dbg_hub/clk [get_nets clk]:

  • 这条命令将调试核心的时钟端口(dbg_hub/clk)连接到设计中的时钟网络(clk)。这确保调试核心能够接收到正确的时钟信号。

3.2 Debug

抓取按键下降沿:

抓取按键上升沿:

4. 总结

本文档提供了在 Vivado 中对 FPGA 设计中常用的几个简单模块和功能的详细分析,包括输入输出缓冲器、全局时钟缓冲器、处理器系统复位以及按键消抖模块。

  • 了解 Utility Buffer v2.2 中的 Buffer,重点分析 IBUFDS 和 BUFGCE_DIV
  • 分析 Processor System Reset v5.0
  • 分析按键消抖模块(key_mod)
  • 了解与 ILA 相关自动生成的约束

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐