2
\$\begingroup\$

I'm trying to design a de-bouncer circuit , which is widely used in digital design . The module that I'm trying to implement is as shown below :-

enter image description here

I've written the following Verilog Module :-

`timescale 1ns / 1ps

module debounce_ckt(
input button,
input clk,
output reg result
    );

/************************************* Internal Variables **********************************/    
reg Q1;
reg Q2;
wire EN1 = 1'b1;
wire EN2 = 1'b1;
wire xor_out;
/****************************** Debounce ckt Implementation code ****************************************/

DFF FF1 (button,clk,EN1,Q1);
DFF FF2 (Q1,clk,EN2,Q2);
     
xor g1 (xor_out,Q1,Q2);

counter C1 (clk,xor_out,~Cout,Cout);     
DFF FF3 (Q2,clk,Cout,result);

endmodule


/***************************************** N-bit counter *************************************/
 module counter (clk, SCLR,EN,Cout);
     input clk;
     input SCLR;   // Clear of counter //
     input EN ; // Active 'HIGH' Enable //
     output reg [N-1:0] Cout; // Counter Output //
 
         
         // Time period of debounce ckt = T = (2^N + 2)/ f //
        // 'f' is the input clock frequency //
        // 'N' is the mod value of counter //

parameter N = 16;

            always@(posedge clk)
                    if(SCLR)    Cout <= 0;
                        else if (EN)    
                            begin
                                    if (Cout == N-1) 
                                            Cout <= 0;
                                    else
                                            Cout <= Cout + 1;
                            end
                    
endmodule       
 

/************************************* D Flip Flop Module (with Enable)**************************/

module DFF(input D,input clk,input EN ,output reg Q);

            always @(posedge clk or EN) 
                    begin
                        if(EN)
                                begin
                                   Q <= D; 
                                end 
                    end     
endmodule 

Testbench is as follows :-

`timescale 1ns / 1ps

module tb;

    // Inputs
    reg button;
    reg clk;

    // Outputs
    wire result;

    // Instantiate the Unit Under Test (UUT)
    debounce_ckt uut (
        .button(button), 
        .clk(clk), 
        .result(result)
    );

   initial begin
      clk = 1'b0; 
    end

always #5 clk = ~ clk;  

initial begin

        #12 button = 0;#10 button = 0 ; #10 button = 1 ; #10 button = 0 ;
        #12 button = 1;#10 button = 1 ; #10 button = 0 ; #10 button = 1 ;
        #12 button = 1;#10 button = 0 ; #10 button = 0 ; #10 button = 1 ;
        #12 button = 0;#10 button = 1 ; #10 button = 1 ; #10 button = 0 ;
        #10 $finish;
    end
  
endmodule


The output 'result' is going to 'X' don't care state, when I'm trying to simulate the files.

enter image description here

Can anyone point out where the issue lies and what corrections are to be made. I'm not expecting a whole working code in the answer. I'd just want to know the error in my code which is causing this.

\$\endgroup\$
5
  • \$\begingroup\$ That design is asking for trouble. Are your two flip flops meant to synchronize the asynchronous input to your FPGA clock domain? Because if so, it's bad practice to try and use the signal before it has run through both flip flops because it somewhat defeats the synchronization. You may not see problems in the simulation, but you will see problems in the real world. Instead, compare your debouncer output to your debouncer input. \$\endgroup\$
    – DKNguyen
    Jun 16 '20 at 18:31
  • \$\begingroup\$ Look at how the maximintegrated.com/en/products/interface/… does it. Don't forget to keep synchronizers on your design. The ASIC doesn't need them but yours is on an FPGA so it does. \$\endgroup\$
    – DKNguyen
    Jun 16 '20 at 18:33
  • \$\begingroup\$ The circuit mentioned in the question is the one used by digikey . A VHDL code for similar circuit has been provided by them. But I was trying to develop a Verilog equilvalent . You may refer this link. digikey.com/eewiki/display/LOGIC/… . The circuit above is not particularly intended for FPGA's in specific. I've made the changes in question. \$\endgroup\$ Jun 16 '20 at 18:35
  • \$\begingroup\$ I can't really help you on the verilog since I don't know verilog. But I still stand by what I said about the synchronizers. You should really had a chain of two flip flops before this entire circuit. But just glancing at everything, are your simulated button presses actually long enough to exceed the debounce time? Because from the looks of it, each button presses is only a few clock cycles long but your N =16 \$\endgroup\$
    – DKNguyen
    Jun 16 '20 at 18:41
  • \$\begingroup\$ There are no compile errors when I run it in Xilinx ISE 14.7. But the issue pointed by @toolic came up, when run in edaplayground . Should I reduce the N value and try ? Or how to resolve this ? \$\endgroup\$ Jun 16 '20 at 18:56
2
\$\begingroup\$

Debouncer

This debouncer assumes that its input is synchronised to the clock.

The output will only change state when the input has been in the opposite state for N clock cycles, i.e. a form of hysteresis to produce a kind of low pass filter.

The counter only counts when the input and output differ, thus reducing switching losses when the input equals the output.

module Debounce
#(
    parameter MAX_COUNT = 16
)
(
    input wire clock,
    input wire in,    // Synchronous and noisy input.
    output reg out,   // Debounced and filtered output.
    output reg edj,   // Goes high for 1 clock cycle on either edge of output. Note: used "edj" because "edge" is a keyword.
    output reg rise,  // Goes high for 1 clock cycle on the rising edge of output.
    output reg fall   // Goes high for 1 clock cycle on the falling edge of output.
);

    localparam COUNTER_BITS = $clog2(MAX_COUNT);

    reg [COUNTER_BITS - 1 : 0] counter;
    wire w_edj;
    wire w_rise;
    wire w_fall;

    initial
    begin
        counter = 0;
        out = 0;
    end

    always @(posedge clock)
    begin
        counter <= 0;  // Freeze counter by default to reduce switching losses when input and output are equal.
        edj <= 0;
        rise <= 0;
        fall <= 0;
        if (counter == MAX_COUNT - 1)  // If successfully debounced, notify what happened.
        begin
            out <= in;
            edj <= w_edj;    // Goes high for 1 clock cycle on either edge.
            rise <= w_rise;  // Goes high for 1 clock cycle on the rising edge.
            fall <= w_fall;  // Goes high for 1 clock cycle on the falling edge.
        end
        else if (in != out)  // Hysteresis.
        begin
            counter <= counter + 1;  // Only increment when input and output differ.
        end
    end

    // Edge detect.
    assign w_edj = in ^ out;
    assign w_rise = in & ~out;
    assign w_fall = ~in & out;

endmodule

Synchroniser

All asynchronous inputs, such as buttons, need to be synchronised to the clock something like this:

module Sync
#(
    parameter SYNC_BITS = 3  // Number of bits in the synchronisation buffer (2 minimum).
)
(
    input wire clock,
    input wire in,     // Asynchronous input.
    output wire out    // Synchronous output.
);

    localparam SYNC_MSB = SYNC_BITS - 1;

    reg [SYNC_MSB : 0] sync_buffer;

    assign out = sync_buffer[SYNC_MSB];

    always @(posedge clock)
    begin
        sync_buffer[SYNC_MSB : 0] <= {sync_buffer[SYNC_MSB - 1 : 0], in};
    end

endmodule

The output of the synchroniser should be connected to the input of the debouncer.

Test Bench

I increased the button timings and reduced MAX_COUNT to see the debouncing effect.

`timescale 1ns/1ps

module SyncDebounce_TB;

    reg clock;
    reg button;
    wire button_sync;
    wire button_sync_db;
    wire edj;
    wire rise;
    wire fall;

    Sync Sync_Inst
    (
        .clock(clock),
        .in(button),
        .out(button_sync)
    );

    Debounce
    #(
        .MAX_COUNT(4)
    )
    Debounce_Inst
    (
        .clock(clock),
        .in(button_sync),
        .out(button_sync_db),
        .edj(edj),
        .rise(rise),
        .fall(fall)
    );

    initial
    begin
        clock = 0;
    end

    always #5 clock = ~clock;

    always
    begin
        #2 button = 0; #20 button = 1; #20 button = 0;
        #22 button = 1; #20 button = 1; #20 button = 0; #20 button = 1;
        #22 button = 1; #20 button = 0; #20 button = 0; #20 button = 1;
        #22 button = 0; #20 button = 1; #20 button = 1; #20 button = 0;
        #80 $stop;
    end

endmodule

Simulation

This shows the debounced button signal with edge detect (both, rise and fall).

It takes 3 clock cycles to synchronise the input and 4 clock cycles to debounce it.

Simulation of synchroniser and debouncer

\$\endgroup\$
1
\$\begingroup\$

There's a wiring error in the instantiation of counter — you have the fourth port declared as an N-bit register, but you've connected it to the undeclared (implied 1-bit) signal Cout. Doesn't the simulator give you a warning about that?

But in any case, you'll need to let the simulation run for at least N = 16 clock cycles before anything significant happens.

Note that using the same constant N for both the width of the counter and its terminal value is at best confusing ... not to mention wasteful.


EDIT: Suggested implementation of counter:

module counter (
  input         clk,
  input         SCLR,   // Synchronous clear of counter
  input         EN,     // Active-HIGH Enable
  output        Cout    // terminal count reached
);
 
  // Time period of debounce ckt = T = (2^N + 2)/ f
  // 'f' is the input clock frequency
  // 'N' is the mod value of counter

  parameter N = 16;

  reg   [N:0] count;  // internal counter

  assign Cout = count[N];

  always @(posedge clk) begin
    if (SCLR) begin
      count <= 0;
    end else if (EN) begin
      if (count[N] == 1'b1) begin
        count <= 0;
      end else begin
        count <= count + 1;
      end
    end
  end

endmodule       
\$\endgroup\$
3
  • \$\begingroup\$ Yes, the simulator does give me a warning regarding this, and not an error. Can you please suggest me on how to rectify this warning ? \$\endgroup\$ Jun 16 '20 at 19:07
  • 1
    \$\begingroup\$ See edit above. \$\endgroup\$
    – Dave Tweed
    Jun 16 '20 at 19:19
  • \$\begingroup\$ This rectified the counter warning. But the signals Q1,Q2,xor_out are being in "X" state. Do I need to put them in any always block ? \$\endgroup\$ Jun 16 '20 at 19:28
1
\$\begingroup\$

Verilog Module :-

`timescale 1ns / 1ps

module debounce_ckt(
    input button,
    input clk,
     input reset,
    output result
    );

/*********** Internal Variables **********/

wire Q1,Q2,SCLR,Q3,Cout;
wire HIGH = 1;
wire LOW = 0;

/************** Main Code ******************/

D_FF D1(clk,reset,button,HIGH,LOW,Q1);
D_FF D2(clk,reset,Q1,HIGH,LOW,Q2);

xor g1(SCLR,Q1,Q2); 

N_bit_counter C1(clk,reset,~Cout,SCLR,Cout);

D_FF D3(clk,reset,Q2,Cout,LOW,Q3);

assign result = Q3;

endmodule

/************** D Flip Flop Module ***************/

module D_FF(
    input clk,
     input reset,
    input D,
    input enable,
    input clear,
    output reg Q
    );
     
         // Active "HIGH " clear, reset, enable signals //

always @(posedge clk) 
    begin
            if (reset) Q<=0;     
            else 
                begin
                    case({clear,enable})  
                        2'b00 : Q<=Q;
                        2'b01 : Q<=D;
                        default : Q<=0;
                    endcase
                end
    end
endmodule

/******************** Counter Module **********************/

module N_bit_counter(
    input clk,
     input reset,
    input enable,
    input clear,
     output Cout
    );
     
     // Active "HIGH " clear, reset, enable signals //

parameter N = 8; // Counts from 0 to 2^[N-1]
reg [N-1:0] count;

assign Cout = count[N-1];

always @(posedge clk) 
    begin   
        if (reset) count <= 8'b0;     
        else 
            begin
                case({clear,enable})     
                    2'b00 : count <= count;
                    2'b01 : count <= count+1;
                    default : count <= 8'b0;
                endcase
          end
    end
endmodule

Testbench :-

`timescale 1ns / 1ps

module testbench;

    // Inputs
    reg button;
    reg clk;
    reg reset;
    // resultputs
    wire result;

    // Instantiate the Unit Under Test (UUT)
    debounce_ckt uut (
        .button(button), 
        .clk(clk),
        .reset(reset),
        .result(result)
    );

    initial begin
        // Initialize Inputs
        clk = 0;
        forever #15 clk=~clk;      // Clock Time peroid T = 30 ns
        
    end
      
    initial begin 

        #6000;
        button=0; reset=1;
        #50 reset=0;
        #50 button=1;            // Fluctuations - glitch
        #200 button=0;
        #50 button=1;           // Fluctuations - glitch
        #150 button=0;
        #100 button=1;          // Pushbotton pressed
        #8000 button=0;                       
        #50 button=1;           // Fluctuations - glitch
        #200 button=0;
        #50 button=1;           // Fluctuations - glitch
        #200 button=0;
        
    end 
endmodule



In simulation wave window, make sure that the simulation is run for atleast 20 microseconds or higher .

Simulation Output :-

enter image description here

\$\endgroup\$
0
\$\begingroup\$

Well, your implementation of the DFF with enable is not quite correct, but I'll give you a chance to look at that yourself. There may be other problems with your code as well.

Since you have a working simulation you should be able to look at signals inside your modules to see why the logic behaves at it does.

Note that the output of FF3 will not be loaded with a known value until your counter reaches its final value and its COUT signal goes high. Does your simulation allow that to happen.

\$\endgroup\$
4
  • \$\begingroup\$ Can you suggest me what's the issue with the D-FF ? And yes, all the signals Cout,Q1,Q2 etc are in "X" state . How do I rectify this ? \$\endgroup\$ Jun 16 '20 at 18:46
  • \$\begingroup\$ Use the simulation to observe the signals inside FF1. Tell us how you think it should work and how it actually does behave. \$\endgroup\$ Jun 16 '20 at 18:53
  • \$\begingroup\$ I've tried simulating the. D_FF module which I've written. It seems to work fine . \$\endgroup\$ Jun 16 '20 at 19:01
  • \$\begingroup\$ Try changing the D input while EN is high but the clock is low. \$\endgroup\$ Jun 16 '20 at 20:05
0
\$\begingroup\$

Are your two flip flops meant to synchronize the asynchronous input to your FPGA clock domain? Because if so, it's bad practice to try and use the signal before it has run through both flip flops because it somewhat defeats the synchronization. You may not see problems in the simulation, but you will see problems in the real world.

Just glancing at everything, are your simulated button presses actually long enough to exceed the debounce time? Because from the looks of it, each button press is only a one or two clock cycles long but your debounce period is N = 16 clock cycles.

If that's the case, of course your output wouldn't respond because all your button presses are short enough to be interpreted bounces. Set your button presses to be 20 clock cycles long and then check that it is passed to the output on the 16th clock cycle.

\$\endgroup\$
1
  • \$\begingroup\$ I've tried the simulation with each button press being 20 clock cycles long. Still the error persists. \$\endgroup\$ Jun 16 '20 at 18:50

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.