Home > Uncategorized > Key Debounce implementation in Verilog

Key Debounce implementation in Verilog

September 24th, 2015

The Circuit below show a simple push button implemented in design such as one in the Spartan 6 Evaluation board .

key-bounce1

The pin 1 of the Switch SW2 is normally high ( due to the pull up resistor R22). When the switch SW2 is pressed, the pin 1 of the switch makes connection with pin 3 of switch SW2, making Pin 1 of the Switch SW2 to make a transition from high to low.

However, this transition is rarely clean. More often than not the switch will make and break contacts several times before making a final transition from 1 o 0. Similarly, when the push button is released it will make and break several times before making a final stable transition from 0 to 1. The process is called key bouncing and the duration and number of the bounces depend upon the characteristic of the switch and typically lasts less than 20 ms. The figure shows the scheme of the key bounce.

key-bounce2

The pattern of the key bounce is not as regular as shown, but you get the idea. Getting rid of the small transitions when the key is pressed or released, is called debouncing. In this article we will show how to do it using Verilog code. It will help you in your understanding of the Verilog. But before we do that, here is an explanation of what how we implement it.

1. Use two flip flops to store the logic levels of button_in during two consecutive clock periods.

2. When these two levels are same ( by XOR gating the output of the two flip flops), we increment a counter. When this counter reaches a specified time, the button input value propagates to output.

3. When the button in changes value, the two flip flops change their values in subsequent clock cycles. In that case, the XOR values of the two counters turns high and the counter is cleared.

4. If the counter keeps incrementing, but the button_in changes the value before the counter reaches the 20 ms value, its value is cleared.

5. To keep the design simpler, the MSB of the counter is monitored.

module  DeBounce 
	(
	input 	clk, n_reset, button_in,		// inputs
	output reg DB_out
	);
	
	/*
	Parameter N defines the debounce time. Assuming 50 KHz clock,
	the debounce time is 2^(11-1)/ 50 KHz = 20 ms
	
	For 50 MHz clock increase value of N accordingly to 21.
	
	*/
	parameter N = 11 ;		

	reg  [N-1 : 0]	delaycount_reg;						
	reg  [N-1 : 0]	delaycount_next;
	
	reg DFF1, DFF2;									
	wire q_add;										
	wire q_reset;

		always @ ( posedge clk )
		begin
			if(n_reset ==  1'b0) // At reset initialize FF and counter 
				begin
					DFF1 <= 1'b0;
					DFF2 <= 1'b0;
					delaycount_reg <= { N {1'b0} };
				end
			else
				begin
					DFF1 <= button_in;
					DFF2 <= DFF1;
					delaycount_reg <= delaycount_next;
				end
		end
	
	
	assign q_reset = (DFF1  ^ DFF2); // Ex OR button_in on conecutive clocks
                                     // to detect level change 
									 
	assign  q_add = ~(delaycount_reg[N-1]); // Check count using MSB of counter			
	

	always @ ( q_reset, q_add, delaycount_reg)
		begin
			case( {q_reset , q_add})
				2'b00 :
						delaycount_next <= delaycount_reg;
				2'b01 :
						delaycount_next <= delaycount_reg + 1;
				default :
				// In this case q_reset = 1 => change in level. Reset the counter 
						delaycount_next <= { N {1'b0} };
			endcase 	
		end
	
	
	always @ ( posedge clk )
		begin
			if(delaycount_reg[N-1] == 1'b1)
					DB_out <= DFF2;
			else
					DB_out <= DB_out;
		end
		
endmodule

Code Explanation

1. At the time of reset, the two flip flops DFF1 and DFF2 are cleared. The counter register delaycount_reg is also cleared.

 always @ ( posedge clk )
        begin
            if(n_reset ==  1'b0) // At reset initialize FF and counter 
                begin
                    DFF1 <= 1'b0;
                    DFF2 <= 1'b0;
                    delaycount_reg <= { N {1'b0} };
                end
            else
                begin
                    DFF1 <= button_in;
                    DFF2 <= DFF1;
                    delaycount_reg <= delaycount_next;
                end
        end

2. At every clock cycle if there is no reset, the button_in propagates to flip flop DFF1. The DFF1 propagates to DFF2 serially. We also update the delaycount_reg. Whether, its value is incremented or becomes zero will depend upon next state logic that we will see later. Basically it will either
- Increment its value, or
- Will be cleared if the because button_in changes its value, or
- Will be cleared because counter reached certain value ( indicated by its MSB).

3. The Change is the button_in value is monitored using a variable q_reset, by XORing the two flip flops. We will later see how q_reset is used.

    assign q_reset = (DFF1  ^ DFF2); 

4. We use a variable q_add to find if the counter has reached its maximum value. This is done by monitoring the MSB of the register delaycount_reg. When the MSB of delaycount_reg is 1, q_add goes 0.

   assign  q_add = ~(delaycount_reg[N-1]); // Check count using MSB of counter

5. This is the most important piece of code. We monitor the change in the button_in value ( via variable q_reset which XORs DFF1 and DFF2, the counter reaching its max value ( via q_add which tracks its MSB) and the delaycount_reg.


always @ ( q_reset, q_add, delaycount_reg)
        begin
            case( {q_reset , q_add})
                2'b00 :
                        delaycount_next <= delaycount_reg;
                2'b01 :
                        delaycount_next <= delaycount_reg + 1;
                default :
                        delaycount_next <= { N {1'b0} };
            endcase    
        end

- If the button_in changes its value, q_reset becomes 1, and reset the delaycount_next to 0.

 default : 
 delaycount_next <= { N {1'b0} };  

- If the button_in stays same ( q_reset stats 0), and counter's MSB is still not 1 ( q_add is 1) , we increment the delaycount_next

     2'b01 :
                        delaycount_next <= delaycount_reg + 1; 

- If the button_in stays same ( q_reset stats 0), and counter's becomes 1 ( q_add is 0), delaycount_next is assigned the value of delaycount_reg;
( Question to readers - can we assign 0 to delacount_next ).

  2'b00 :
                        delaycount_next <= delaycount_reg;

6. Finally, the debounce output is assigned the value of DFF2 if the MSB of the counter becomes 1. Else, it retains its previous value.

always @ ( posedge clk )
        begin
            if(delaycount_reg[N-1] == 1'b1)
                    DB_out <= DFF2;
            else
                    DB_out <= DB_out;
        end

Here is the stimulus code for this

`timescale 1 us / 1 us

module DeBounce_tf();
    reg clk;
    reg n_reset;
    reg button_in;
    wire DB_out;

    DeBounce UUT (
        .clk(clk), 
        .n_reset(n_reset), 
        .button_in(button_in),
        .DB_out(DB_out)
        );


    initial begin
			clk = 1'b0;
            n_reset = 1'b0;
			#20 n_reset = 1'b1;      // at time 20 release the reset
            button_in = 1'b1;
			
			// We need at least twice the counter value to stabilize value of DB_out
			// before we change the button in
			#50000 button_in = 1'b0; // We pressed the key here 
			#400 button_in = 1'b1; // Key debounce to 1 after 400 micro seconds				
			#800 button_in = 1'b0;	  // Debounce after 800 ms
			#2000 button_in = 1'b1;	// Decounce after 2 ms			
			#800 button_in = 1'b0;
			#40000 button_in = 1'b1;
			#4000 button_in = 1'b0;		
			#40000 button_in = 1'b1;
			#400 button_in = 1'b0;
			#800 button_in = 1'b1;		
			#800 button_in = 1'b0;
			#800 button_in = 1'b1;
			#40000 button_in = 1'b0;		
			#4000 button_in = 1'b1;
			$finish;
    end
	always 
			#10 clk = ~clk;  // 20 mirco seconds = 50 KHz Clock cycle   

initial
      begin
      $dumpfile ("debounce.vcd");
      $dumpvars (0,DeBounce_tf);
      end
endmodule 

Let us see the waveform

key-debounce3

Uncategorized

  1. meet patel
    April 15th, 2018 at 20:47 | #1

    i need help wid the test bench of this code......bcus im not getting my output as you ve shown here....i ve done only copy nd paste .....no modification is required.....ri8?

  2. shambulinga v b
    October 29th, 2018 at 12:09 | #2

    the same problem here also, i am not getting the output waveform as you have shown above .can you please check the code and send me the correct version of the code to the above mentioned email-id asap ... i need your help

  1. No trackbacks yet.