3
\$\begingroup\$

I want to start using sync reset inside my FPGA designs, and I'm new to Xilinx FPGA design.

Normally I have 5-6 clocks in every design, and the reset is driven from the push button on the board.

What is a good practice to use this asynchronous signal coming to my FPGA as synchronous reset to all the clocks in my FPGA design?

The thing I thought about is just to sync the same async push-button signal with every clock on the board in parallel, like the block diagram I draw here:

Enter image description here

The top-level code for clocks and reset generation:

`timescale 1 ns / 1 ps

module top_test1 (

    input  wire       clk_200mhz_p,     // external clock 200 MHz - p
    input  wire       clk_200mhz_n,     // external clock 200 MHz - n
    input  wire       reset             // reset push button
);

//*--------------------------------
//* Clock and reset
//*--------------------------------
// Internal 200 MHz clock - System
wire clk_200mhz_ibufg;  // internal 200 MHz clock
wire rst_200mhz_int;    // internal 200 MHz synchronous reset

// Internal 125 MHz clock - Ethernet
wire clk_mmcm_out;      // mmcm clk out - 125 MHz
wire clk_125mhz_int;    // internal 125 MHz clock
wire rst_125mhz_int;    // internal 125 MHz synchronous reset

// Internal 50 MHz clock - DSP
wire clk_bufr_out_50mhz;    // bufr 50mhz clock -> 200 MHz / 4 = 50 MHz
wire clk_50mhz_int;         // internal 50 MHz clk
wire rst_50mhz_int;         // internal 50 MHz synchronous reset


wire mmcm_rst = reset;
wire mmcm_locked;
wire mmcm_clkfb;

IBUFGDS
clk_200mhz_ibufgds_inst(
    .I    (clk_200mhz_p),
    .IB   (clk_200mhz_n),
    .O    (clk_200mhz_ibufg)
);

sync_reset #(
    .N        (4)
)
sync_reset_inst_200mhz (
    .clk    (clk_200mhz_ibufg),
    .rst    (reset),
    .out    (rst_200mhz_int)
);

MMCME2_BASE #(
    .BANDWIDTH           ("OPTIMIZED"),
    .CLKOUT0_DIVIDE_F    (8),
    .CLKOUT0_DUTY_CYCLE  (0.5),
    .CLKOUT0_PHASE       (0),
    .CLKOUT1_DIVIDE      (8),
    .CLKOUT1_DUTY_CYCLE  (0.5),
    .CLKOUT1_PHASE       (0),
    .CLKOUT2_DIVIDE      (1),
    .CLKOUT2_DUTY_CYCLE  (0.5),
    .CLKOUT2_PHASE       (0),
    .CLKOUT3_DIVIDE      (1),
    .CLKOUT3_DUTY_CYCLE  (0.5),
    .CLKOUT3_PHASE       (0),
    .CLKOUT4_DIVIDE      (1),
    .CLKOUT4_DUTY_CYCLE  (0.5),
    .CLKOUT4_PHASE       (0),
    .CLKOUT5_DIVIDE      (1),
    .CLKOUT5_DUTY_CYCLE  (0.5),
    .CLKOUT5_PHASE       (0),
    .CLKOUT6_DIVIDE      (1),
    .CLKOUT6_DUTY_CYCLE  (0.5),
    .CLKOUT6_PHASE       (0),
    .CLKFBOUT_MULT_F     (5),
    .CLKFBOUT_PHASE      (0),
    .DIVCLK_DIVIDE       (1),
    .REF_JITTER1         (0.010),
    .CLKIN1_PERIOD       (5.0),
    .STARTUP_WAIT        ("FALSE"),
    .CLKOUT4_CASCADE     ("FALSE")
)
clk_mmcm_inst (
    .CLKIN1              (clk_200mhz_ibufg),
    .CLKFBIN             (mmcm_clkfb),
    .RST                 (mmcm_rst),
    .PWRDWN              (1'b0),
    .CLKOUT0             (clk_mmcm_out),
    .CLKOUT0B            (),
    .CLKOUT1             (),
    .CLKOUT1B            (),
    .CLKOUT2             (),
    .CLKOUT2B            (),
    .CLKOUT3             (),
    .CLKOUT3B            (),
    .CLKOUT4             (),
    .CLKOUT5             (),
    .CLKOUT6             (),
    .CLKFBOUT            (mmcm_clkfb),
    .CLKFBOUTB           (),
    .LOCKED              (mmcm_locked)
);

BUFG clk_bufg_inst_125mhz (
    .I    (clk_mmcm_out),
    .O    (clk_125mhz_int)
);

sync_reset #(
    .N        (4)
)
sync_reset_inst_125mhz (
    .clk    (clk_125mhz_int),
    .rst    (reset),
    .out    (rst_125mhz_int)
);

BUFR #(
    .BUFR_DIVIDE("4"),      // Values: "BYPASS, 1, 2, 3, 4, 5, 6, 7, 8"
    .SIM_DEVICE("7SERIES")  // Must be set to "7SERIES"
)
BUFR_inst_50mhz (
    .O      (clk_bufr_out_50mhz),   // Clock output port
    .CE     (1'b1),                 // Active high, clock enable (Divided modes only)
    .CLR    (rst_int),              // Active high, asynchronous clear (Divided modes only)
    .I      (clk_200mhz_ibufg)      // Clock buffer input..
                                    // ..driven by an IBUF, MMCM or local interconnect
);

BUFG clk_bufg_inst_50mhz (
    .I    (clk_bufr_out_50mhz),
    .O    (clk_50mhz_int)
);

sync_reset #(
    .N        (4)
)
sync_reset_inst_50mhz (
    .clk    (clk_50mhz_int),
    .rst    (reset),
    .out    (rst_50mhz_int)
);

endmodule

The "sync_reset" module is just a pipeline of N registers. So is it a good way to produce all the sync resets I need for my design?

I just want to be sure.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You probably want to build something which controls reset to everything else. In particular beware that for any DLL sourced clocks you need to hold the clocked logic in reset until the clock is good - otherwise you might see surprising results, for example FPGA "ROM" can see contents corrupted if read timing is violated! \$\endgroup\$ – Chris Stratton Nov 11 '20 at 15:35
2
\$\begingroup\$

It looks fine. Normally a 2-flop synchronizer is enough for the clock frequencies you target. That's what I have used with push button resets on FPGA boards. But a 4-flop synchronizer still gives better MTBF. Since your design uses synchronous reset, both assertion and release of "push button asynchronous reset" have to be, and will be synchronised by this chain of flip-flops to the respective clock domains.

Since you have designed a synchronizer chain of your own, it's advisable to specify ASYNC_REG (page no. 9 in the document) property on the destination flops. Vivado says -

Specifying ASYNC_REG also affects optimization, placement, and routing to improve Mean Time Before Failure (MTBF) for registers that may go metastable. If ASYNC_REG is applied, the placer will ensure the flip-flops on a synchronization chain are placed closely to maximize MTBF

You can also consider adding a debouncer on the path to avoid erroneous resets. So that your circuit doesn't reset if the reset pulse width is not "long enough", say four clock cycles.

Example:

Enter image description here

The upper one is for an active-low reset.

The lower one is for an active-high reset.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ There’s a library element that does this. See my answer. \$\endgroup\$ – hacktastical Nov 11 '20 at 16:41
3
\$\begingroup\$

In general, you will want the reset release to be synchronized with the block’s clock. You also want to ensure that there actually is a running clock when that occurs, and that it’s been running long enough for the reset to have fully taken effect.

The Xilinx library includes a configurable reset block that will handle that for you. Link: https://www.xilinx.com/products/intellectual-property/proc_sys_reset.html

\$\endgroup\$
3
\$\begingroup\$

Here is an example from an FPGA design with two clock domains. One is a 33 MHz PCI interface & associated circuits, and the other is for a 50 MHz block. Note - the key here, like others have said, is to release the reset synchronously wrt the domain clock.

enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ Actually OP uses synchronous reset in his design, but the push button reset he set on the board is an asynchronous signal. So BOTH assertion as well as release of that "asynchronous reset" has to be synchronised to the clock. If the OP were using asynchronous reset in his design, then only release has to be synchronised. \$\endgroup\$ – Mitu Raj Nov 12 '20 at 2:37
1
\$\begingroup\$

Ideally a reset initializes asynchronously by a “debounced” active low state and then remains in this state until released which is synchronized to the system clock with a single flip flop.

The release is not just mechanical, but held low by a capacitor whose RC time constant is longer that the bounce time of an old worn out button switch or 15 ms or more into a Schmitt trigger.

  • button switches are expected to bounce in the 1~5 ms range and 1 A toggle switches 10~25 ms.

    : recommendation

  • all you need is a cap, a Schmitt trigger gate, and a D FF, system clock with a button switch to ground and of course your 10 kΩ to 1 MΩ pull-up.

Got it?

  • The idea is that the first button contact charges and holds the Reset low voltage and if the release bounces, the capacitor stays low anyway long enough to prevent multiple edges.

  • Just make sure you have a “state” controlled reset in your design and not “edge” controlled unless that circuit self synchronizes or does not need to be in sync.

Do I need to draw this?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ This does not answer the question, which is about how to deal with this within a multi-clocked FPGA design. \$\endgroup\$ – Graham Nov 12 '20 at 1:00
  • \$\begingroup\$ All the clocks are synchronous in frequency but may vary in latency. So my answer still holds true. You synchronize all clocks to 1 master clock reset removal. So I disagree strongly @Graham \$\endgroup\$ – Tony Stewart EE75 Nov 15 '20 at 17:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.