Home > Back-end >  Button debouncing circuit full count based:
Button debouncing circuit full count based:

Time:11-19

i am trying to practice debouncing on FPGA following the approach (full count based), that introduced in the book from Volnei ("Circuit Design with VHDL third edition"). A very important feature of this circuit is the way the timer is constructed, which eliminates the need for a comparator (a large circuit). For example, for the numeric values just given, $S = 50,MHz * 20,ms= 10e6$ results, where the number of bits (DFFs) in the counter is $N= log_2(S) = 20$ implying a counter running from zero to $10e6 - 1$ = 1 1 1 1_0100_0010_00 1 1_1 1 1 1, thus requiring a comparator that is at least 12 bits wide (only the s need to be monitored), which is indeed a large circuit. This can be avoided by taking into consideration that the time does not need to be exact in debouncers, so if an extra bit (flip-flop) is included in the counter, its MSB alone can play the role of comparator; when MSB= 1 occurs, it enables the output register, so y is updated, leading subsequently to clear= 1, which zeros the counter (and therefore the MSB too) at the next positive clock edge. In summary, the counter spans a total of $ S = 2^N 1$ states, leading to $T{deb} = 2^N/f_{clk (50MHz)} = 21 ms$ for the numeric values given above.

However, testing the code given from this Example not giving the expected result.

Debouncing

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
USE IEEE.math_real.ALL;

ENTITY E13_button_debouncer IS
    GENERIC (
        T_DEB_MS : NATURAL := 25;
        f_clk : NATURAL := 50_000);
    PORT (
        clk : IN STD_LOGIC;
        rst : IN STD_LOGIC;
        b_in : IN STD_LOGIC;
        b_out : OUT STD_LOGIC
    );
END E13_button_debouncer;

ARCHITECTURE single_switch OF E13_button_debouncer IS
    CONSTANT COUNTER_BITS : NATURAL := 1   INTEGER(ceil(log2(real(T_DEB_MS * f_clk))));

    -- ! Optional :
    SIGNAL x_reg : STD_LOGIC;

BEGIN
    proc_name : PROCESS (clk)
        VARIABLE count : unsigned(COUNTER_BITS - 1 DOWNTO 0);
    BEGIN
        IF rising_edge(clk) THEN
            IF rst = '0' THEN
                count := (OTHERS => '0');
                x_reg <= '0';
                b_out <= '0';
            ELSE
                x_reg <= b_in;
                IF b_out = x_reg THEN
                    count := (OTHERS => '0');
                ELSE
                    count := count   1;
                END IF;
            END IF;
        END IF;

        IF falling_edge(clk) THEN
            IF count(COUNTER_BITS - 1) THEN
                b_out <= NOT b_out;
            END IF;
        END IF;

    END PROCESS proc_name;
END ARCHITECTURE;

Test Bench

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY E13_button_debouncer_tb IS
END E13_button_debouncer_tb;

ARCHITECTURE sim OF E13_button_debouncer_tb IS

    CONSTANT clk_hz : INTEGER := 50_000;
    CONSTANT clk_period : TIME := 1 sec / clk_hz;
    CONSTANT T_DEB_MS : NATURAL := 25;

    SIGNAL clk : STD_LOGIC := '1';
    SIGNAL rst : STD_LOGIC := '0';
    SIGNAL b_in : STD_LOGIC := '0';
    SIGNAL b_out : STD_LOGIC := '1';

BEGIN

    clk <= NOT clk AFTER clk_period / 2;
    bu_deboun : ENTITY work.E13_button_debouncer(single_switch)
        GENERIC MAP(f_clk => clk_hz, T_DEB_MS => T_DEB_MS)
        PORT MAP(
            clk => clk,
            rst => rst,
            b_in => b_in,
            b_out => b_out
        );

    SEQUENCER_PROC : PROCESS
    BEGIN
        WAIT FOR clk_period * 1;
        rst <= '1';
        b_in <= '1';
        WAIT FOR 1 ms;
        b_in <= '0';
        WAIT FOR 1 ms;
        b_in <= '1';
        WAIT FOR 100 ms;
        b_in <= '0';
        WAIT FOR 1 ms;
        b_in <= '1';
        WAIT FOR 10 ms;
        b_in <= '0';
        WAIT FOR 10 ms;

    END PROCESS;

END ARCHITECTURE;

Simulation

Simulation

I expepct that the code work like photo below: enter image description here

CodePudding user response:

to solve the problem first to avoid errors when synthesize it need the changes to the code thanks to (@thebusybee, @user16145658,@MatthiasSchweikart):

    BEGIN
        IF rising_edge(clk) THEN
            IF rst = '0' THEN
                count := (OTHERS => '0');
                x_reg <= '0';
            ELSE
                x_reg <= b_in;
                IF b_out = x_reg THEN
                    count := (OTHERS => '0');
                ELSE
                    count := count   1;
                END IF;
            END IF;
        END IF;

        IF falling_edge(clk) THEN
            IF rst = '0' THEN
                b_out <= '0';
            ELSE
                REPORT "we are in falling edge and the counter value : " & INTEGER'image(to_integer(count));
                IF count(COUNTER_BITS - 1) THEN
                    b_out <= NOT b_out;
                END IF;
            END IF;
        END IF;

    END PROCESS proc_name;
END ARCHITECTURE;

the problem was here:

    GENERIC (
        T_DEB_MS : NATURAL := 25;
        f_clk : NATURAL := 50_000);
    PORT (
        clk : IN STD_LOGIC;
        rst : IN STD_LOGIC;
        b_in : IN STD_LOGIC;
        b_out : OUT STD_LOGIC
    );
END E13_button_debouncer;

ARCHITECTURE single_switch OF E13_button_debouncer IS
    CONSTANT COUNTER_BITS : NATURAL := 1   INTEGER(ceil(log2(real(T_DEB_MS * f_clk))));

which result in N=21 that mean the debounce time will be 41 Second. so to solve it i should do it like this : 0.025 * fclk = 1250 => result in N= 10 => 1 =11. then the counter will count till 2048 resulting in debounce time von 40 ms. which is ok for my application.

enter image description here

  • Related