Verilog design example software anti shake design of key anti shake

Blog directory

Write in front

text

Background introduction and review

We often see this kind of Verilog design on the Internet, which is to read the switch every 20ms, The so-called recognized key time is less than 20ms.

In fact, the jitter time of different keys is different. See resources: debouncing In, the author tested the jitter time of different keys:


Jitter time (in microseconds) used to turn each switch (numbers A to R) on and off. Switch E was excluded because its 157 millisecond jitter severely distorted the pattern.

If you are interested, please have a look!

A common key circuit is as follows:

When the key is not pressed, the value signal is high and the value is low. There is a short or long key jitter in physical keys! As shown in the figure below:

As mentioned above, key jitter is generally recognized as 20ms. If the jitter is eliminated by software or logic design, the edge of key signal is detected first, and then the key value is sampled every 20ms! In this way, the purpose of key shaking is realized!

Single button

The design of a key's anti shake

Take a key as an example:

The following figure is the design block diagram:

Design documents:

`timescale 1ns / 1ps
/////////////////////////////////////////////
// Engineer: Reborn Lee
// Module Name: debounce_1b
////////////////////////////////////////////

module debounce_1b(
	input clk, //50MHz
	input rst,
	input sw_in_n,
	output reg sw_out_n
    );


	reg sw_mid_r1, sw_mid_r2, sw_valid;

	always@(posedge clk or posedge rst) begin
		if(rst) begin
			sw_mid_r1 <= 1; // synchronize 1 clock 
			sw_mid_r2 <= 1; // delay 1 clock
			sw_valid <= 0; // gen negedge
		end
		else begin
			sw_mid_r1 <= sw_in_n;
			sw_mid_r2 <= sw_mid_r1;
			sw_valid <= sw_mid_r2 & (~sw_mid_r1);
		end
	end

	reg [19:0] key_cnt;

	always@(posedge clk or posedge rst) begin
		if(rst) begin
			key_cnt <= 0;
		end
		else if(sw_valid) begin
			key_cnt <= 0;
		end
		else begin
			key_cnt <= key_cnt + 1; //20ms
		end
	end

	always@(posedge clk or posedge rst) begin
		if(rst) begin
			sw_out_n <= 1;
		end
		else if(key_cnt == 20'hfffff) begin
			sw_out_n <= sw_in_n;
		end
	end

endmodule

It is easy to understand that it is to detect whether the key value changes first and detect the falling edge of the key value. If the falling edge is detected, the counter will be cleared. Otherwise, the counter will be counted to 20ms (20'dfffff), and the key value will be sampled once as the output.

Next, I design jitter to test this design.

Test documents

`timescale 1ns / 1ps
module debounce1_tb(
    );
	reg clk;
	reg rst;
	reg sw_in_n;
	wire sw_out_n;

	initial begin
		clk = 0;
		forever begin
			#5 clk = ~clk;
		end
	end

	initial begin
		rst = 1;
		sw_in_n = 1;
		#50 
		rst = 0;
		@(negedge clk)
		sw_in_n = 0;
		repeat(3) @(negedge clk);
		sw_in_n = 1;
		repeat(20000) begin
			repeat(5) @(negedge clk);
			sw_in_n = 0;
			repeat(2) @(negedge clk);
			sw_in_n = 1;
			repeat(3) @(negedge clk);
			sw_in_n = 0;
		end

		repeat(3000000) begin
			@(negedge clk);
		end
		
		sw_in_n = 1;

	end


	debounce_1b inst0(
		.clk(clk),
		.rst(rst),
		.sw_in_n(sw_in_n),
		.sw_out_n(sw_out_n)
		);


endmodule

The simulation waveform is:

Schematic diagram of RTL designed:

Other design versions of single button

It has to be said that, data The schematic diagram of jitter removal given:


In fact, it is the RTL diagram that simplifies the above-mentioned design. I think it is more exquisite than the first design.

This version design does not detect the falling edge of the key, but directly synchronizes two beats of the key value, and detects the XOR of the two beats of data. If the XOR value is 1, it means that the key value has changed, when the count value is cleared; otherwise, count, until the count value reaches the specified value, sample the key value data.

The following is the VHDL design. It is very simple. There is no need to convert verilog into it. If it is necessary, pay attention to my WeChat official account FPGA LAB, and give me a background news.

----------------------------------------------------------------
--   FileName:         debounce.vhd
--   Version History
--   Version 1.0 3/26/2012 Scott Larson
----------------------------------------------------------------

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;

ENTITY debounce IS
  GENERIC(
    counter_size  :  INTEGER := 19); --counter size (19 bits gives 10.5ms with 50MHz clock)
  PORT(
    clk     : IN  STD_LOGIC;  --input clock
    button  : IN  STD_LOGIC;  --input signal to be debounced
    result  : OUT STD_LOGIC); --debounced signal
END debounce;

ARCHITECTURE logic OF debounce IS
  SIGNAL flipflops   : STD_LOGIC_VECTOR(1 DOWNTO 0); --input flip flops
  SIGNAL counter_set : STD_LOGIC;                    --sync reset to zero
  SIGNAL counter_out : STD_LOGIC_VECTOR(counter_size DOWNTO 0) := (OTHERS => '0'); --counter output
BEGIN

  counter_set <= flipflops(0) xor flipflops(1);   --determine when to start/reset counter
  
  PROCESS(clk)
  BEGIN
    IF(clk'EVENT and clk = '1') THEN
      flipflops(0) <= button;
      flipflops(1) <= flipflops(0);
      If(counter_set = '1') THEN                  --reset counter because input is changing
        counter_out <= (OTHERS => '0');
      ELSIF(counter_out(counter_size) = '0') THEN --stable input time is not yet met
        counter_out <= counter_out + 1;
      ELSE                                        --stable input time is met
        result <= flipflops(1);
      END IF;    
    END IF;
  END PROCESS;
END logic;

There is also an improved version of the previous version:

LIBRARY ieee;
USE ieee.std_logic_1164.all;

ENTITY debounce IS
  GENERIC(
    clk_freq    : INTEGER := 50_000_000;  --system clock frequency in Hz
    stable_time : INTEGER := 10);         --time button must remain stable in ms
  PORT(
    clk     : IN  STD_LOGIC;  --input clock
    reset_n : IN  STD_LOGIC;  --asynchronous active low reset
    button  : IN  STD_LOGIC;  --input signal to be debounced
    result  : OUT STD_LOGIC); --debounced signal
END debounce;

ARCHITECTURE logic OF debounce IS
  SIGNAL flipflops   : STD_LOGIC_VECTOR(1 DOWNTO 0); --input flip flops
  SIGNAL counter_set : STD_LOGIC;                    --sync reset to zero
BEGIN

  counter_set <= flipflops(0) xor flipflops(1);  --determine when to start/reset counter
  
  PROCESS(clk, reset_n)
    VARIABLE count :  INTEGER RANGE 0 TO clk_freq*stable_time/1000;  --counter for timing
  BEGIN
    IF(reset_n = '0') THEN                        --reset
      flipflops(1 DOWNTO 0) <= "00";                 --clear input flipflops
      result <= '0';                                 --clear result register
    ELSIF(clk'EVENT and clk = '1') THEN           --rising clock edge
      flipflops(0) <= button;                        --store button value in 1st flipflop
      flipflops(1) <= flipflops(0);                  --store 1st flipflop value in 2nd flipflop
      If(counter_set = '1') THEN                     --reset counter because input is changing
        count := 0;                                    --clear the counter
      ELSIF(count < clk_freq*stable_time/1000) THEN  --stable input time is not yet met
        count := count + 1;                            --increment counter
      ELSE                                           --stable input time is met
        result <= flipflops(1);                        --output the stable value
      END IF;    
    END IF;
  END PROCESS;
  
END logic;

If you are interested, go to the link: De jitter logic circuit (taking VHDL as an example) View (except those that cannot be opened)!

Well, that's it for a single button. Here's the design of multiple buttons.

Multiple buttons

The design of several buttons for anti shake is as follows:

A fairly simple method is used to find n consecutive stable readings of the switch, where n is a number from 1 (no bounce at all) to seemingly infinite. Usually, the code first detects a jump, and then starts to increment or decrement the counter, each time it rereads the input, until n reaches some safe, jitter free count. If the status is not stable, the counter resets to its initial value.

`timescale 1ns / 1ps
 
//Note: when one of the three independent keys is pressed, the corresponding LED is lit;
//		After pressing again, the LED goes out and the key control LED goes on and off
 
module sw_debounce(
    		clk,rst_n,
			sw1_n,sw2_n,sw3_n,
	   		led_d1,led_d2,led_d3
    		);
 
input   clk;	//Master clock, 50MHz
input   rst_n;	//Reset signal, low effective
input   sw1_n,sw2_n,sw3_n; 	//Three independent keys, low means press
output  led_d1,led_d2,led_d3;	//LED, respectively controlled by key
 
//---------------------------------------------------------------------------
reg key_rst;  
 
always @(posedge clk  or negedge rst_n)
    if (!rst_n) key_rst <= 1'b1;
    else key_rst <= sw3_n&sw2_n&sw1_n;
 
reg key_rst_r;       //The rising edge of each clock cycle will be low_sw signal latched to low_sw_r medium
 
always @ ( posedge clk  or negedge rst_n )
    if (!rst_n) key_rst_r <= 1'b1;
    else key_rst_r <= key_rst;
   
//When register key_ LED when RST changes from 1 to 0_ The value of an becomes high, maintaining a clock cycle 
wire key_an = key_rst_r & (~key_rst);
/*
key_rst     1 1 1 0 0 1
~key_rst    0 0 0 1 1 0
key_rst_r     1 1 1 0 0 1
key_an        0 0 1 0 0
*/
//---------------------------------------------------------------------------
reg[19:0]  cnt;	//Count register
 
always @ (posedge clk  or negedge rst_n)
    if (!rst_n) cnt <= 20'd0;	//Asynchronous reset
	else if(key_an) cnt <=20'd0;
    else cnt <= cnt + 1'b1;
  
reg[2:0] low_sw;
 
always @(posedge clk  or negedge rst_n)
    if (!rst_n) low_sw <= 3'b111;
    else if (cnt == 20'hfffff) 	//For 20ms, lock the key value to register low_ cnt == 20 'in SWhfffff
      low_sw <= {sw3_n,sw2_n,sw1_n};
      
//---------------------------------------------------------------------------
reg  [2:0] low_sw_r;       //The rising edge of each clock cycle will be low_sw signal latched to low_sw_r medium
 
always @ ( posedge clk  or negedge rst_n )
    if (!rst_n) low_sw_r <= 3'b111;
    else low_sw_r <= low_sw;
/*
low_sw		111 111 111 110 110 110  
~low_sw     000 000 000 001 001 001
low_sw_r        111 111 111 110 110 110
led_ctrl	000 000 000 001 000 000 
   */
//When register low_ When SW changes from 1 to 0, LED_ The value of Ctrl becomes high, maintaining a clock cycle 
wire[2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);
 
reg d1;
reg d2;
reg d3;
  
always @ (posedge clk or negedge rst_n)
    if (!rst_n) begin
        d1 <= 1'b0;
        d2 <= 1'b0;
        d3 <= 1'b0;
      end
    else begin		//When a key value changes, the LED will turn on and off
        if ( led_ctrl[0] ) d1 <= ~d1;	
        if ( led_ctrl[1] ) d2 <= ~d2;
        if ( led_ctrl[2] ) d3 <= ~d3;
      end
 
assign led_d3 = d1 ? 1'b1 : 1'b0;		//LED flip output
assign led_d2 = d2 ? 1'b1 : 1'b0;
assign led_d1 = d3 ? 1'b1 : 1'b0;
  
endmodule
 

From the beginning to here:

always @(posedge clk  or negedge rst_n)
    if (!rst_n) low_sw <= 3'b111;
    else if (cnt == 20'hfffff) 	//For 20ms, lock the key value to register low_ cnt == 20 'in SWhfffff
      low_sw <= {sw3_n,sw2_n,sw1_n};

It's over. The rest is the LED part!

Let's take a brief look at this Code:

always @(posedge clk  or negedge rst_n)
    if (!rst_n) key_rst <= 1'b1;
    else key_rst <= sw3_n&sw2_n&sw1_n;

As long as the change of key value (even jitter) is detected, the key will be lowered here_ Rst pull down!

reg key_rst_r;       //The rising edge of each clock cycle will be low_sw signal latched to low_sw_r medium
 
always @ ( posedge clk  or negedge rst_n )
    if (!rst_n) key_rst_r <= 1'b1;
    else key_rst_r <= key_rst;
   
//When register key_ LED when RST changes from 1 to 0_ The value of an becomes high, maintaining a clock cycle 
wire key_an = key_rst_r & (~key_rst);

Yes, key_ After one shot delay of RST, the falling edge detection is performed. If the falling edge key is detected_ An effective!
That is, if the key value changes, key_an works!

reg[19:0]  cnt;	//Count register
 
always @ (posedge clk  or negedge rst_n)
    if (!rst_n) cnt <= 20'd0;	//Asynchronous reset
	else if(key_an) cnt <=20'd0;
    else cnt <= cnt + 1'b1;

At key_ After an is valid, we will clear the count value and then count (key_an is invalid). If the key value is in the jitter stage during counting, the key_an will be valid again and the count will be cleared again. Until the end of jitter, count all the time, count to 20ms, take the key value signal!

always @(posedge clk  or negedge rst_n)
    if (!rst_n) low_sw <= 3'b111;
    else if (cnt == 20'hfffff) 	//For 20ms, lock the key value to register low_ cnt == 20 'in SWhfffff
      low_sw <= {sw3_n,sw2_n,sw1_n};

This program means that the count is full. If the system clock frequency is 50MHz, it means that the count is about 20ms and the key value will be sampled. Here, take three keys as an example.
So far, it's the end of the button shake!

Write at the end

In fact, for the elimination of key jitter, you can also use hardware to remove the jitter, but it is not within the scope of this article, you can refer to 5! Reference 5

reference material

Make a friend

  • Zhihu: Li ruiboon

Tags: Verilog less REST

Posted on Fri, 19 Jun 2020 06:11:23 -0400 by rock_xl1