-1

I am completly new for the FPGA and basys3 development board. I have a project for Counter on the 7 segment displays on the board. We got 3 different layers as a design.

cntr / cntr_rtl / cntr_top / cntr_top_struc / io_ctrl / io_ctrl_rtl /

And in the project it has to diplay on the 7 segment controlled by the switches : count up/count down / hold / reset options:

The priorities for these switches are:

  1. reset

  2. hold

  3. count direction

top level VHDL file cntr_top.vhd

Port Name Direction Description

clk_i In System clock (100 MHz)

reset_i In Asynchronous high active reset

sw_i(15:0) In 16 switches

pb_i(3:0) In 4 buttons

ss_o(7:0) Out Contain the value for all 7-segment digits

ss_sel_o(3:0) Out Select a 7-segment digit

io_ctrl clk_i In System clock (100 MHz)

reset_i In Asynchronous high active reset

cntr0_i(n:0) In Digit 0 (from internal logic)

cntr1_i(n:0) In Digit 1 (from internal logic)

cntr2_i(n:0) In Digit 2 (from internal logic)

cntr3_i(n:0) In Digit 3 (from internal logic)

sw_i(15:0) In 16 switches (from FPGA board)

pb_i(3:0) In 4 buttons (from FPGA board)

ss_o(7:0) Out to 7-segment displays of the FPGA board

ss_sel_o(3:0) Out Selection of a 7-segment digit

swclean_o(15:0) Out 16 switches (to internal logic)

pbclean_o(3:0) Out 4 buttons (to internal logic)

cntr.vhd

clk_i In System clock (100 MHz)

reset_i In Asynchronous high active reset

cntrup_i In Counts up if signal is ‘1’

cntrdown_i In Counts down if signal is ‘1’

cntrreset_i In Sets counter to 0x0 if signal is ‘1’

cntrhold_i In Holds count value if signal is ‘1’

cntr0_o(n:0) Out Digit 0 (from internal logic)

cntr1_o(n:0) Out Digit 1 (from internal logic)

cntr2_o(n:0) Out Digit 2 (from internal logic)

cntr3_o(n:0) Out Digit 3 (from internal logic)

I will attach also the file to the attachment. Now my code is working and do all the funcitionality correct but there is only one issue which is the DEBOUNCE code part.

I didnt use the clk signal for the code and i have to change it. The certain given clock signal has to be used.

So can any be give me suggestions how i can correct the debounce concept in the code.

io_ctrl_rtl.vhd -code down below:

library IEEE;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


architecture rtl of io_ctrl is

constant COUNTVALUE : std_logic_vector(16 downto 0):= "01100001101010000"; 

signal s_enctr : std_logic_vector(16 downto 0):="00000000000000000";
signal s_2khzen : std_logic :='0';
signal s_1hzen : std_logic :='0';
signal s_2khzcount : std_logic_vector(3 downto 0) := "0000";
signal swsync0 : std_logic_vector(15 downto 0):="0000000000000000";
signal pbsync0 : std_logic_vector(3 downto 0):="0000";
signal swsync1 : std_logic_vector(15 downto 0):="0000000000000000";
signal pbsync1 : std_logic_vector(3 downto 0):="0000";
signal swtmp : std_logic_vector(15 downto 0):="0000000000000000";
signal pbtmp : std_logic_vector(3 downto 0):="0000";
signal swdebounced : std_logic_vector(15 downto 0):="0000000000000000";
signal pbdebounced : std_logic_vector(3 downto 0):="0000";
signal s_ss_sel : std_logic_vector(3 downto 0) := "0000";
signal s_ss : std_logic_vector(7 downto 0) := "00000000";
begin -- rtl
-----------------------------------------------------------------------------
--
-- Synchronize the inputs
--
-----------------------------------------------------------------------------
p_sync: process (clk_i, reset_i)
begin 
if reset_i = '1' then 
swsync0 <= (others => '0');
pbsync0 <= (others => '0');
swsync1 <= (others => '0');
pbsync1 <= (others => '0');
elsif clk_i'event and clk_i = '1' then

    swsync0 <=    sw_i;
    pbsync0 <=    pb_i;
    swsync1 <=     swsync0;
    pbsync1    <=    pbsync0;
    else null;
end if;
end process;

-----------------------------------------------------------------------------
--
-- Generate 1 KHz enable signal.
--
-----------------------------------------------------------------------------
p_slowen: process (clk_i, reset_i)
begin
if reset_i = '1' then        
    s_enctr <= (others => '0');
    s_2khzen <= '0';

elsif clk_i'event and clk_i = '1' then 
    if s_enctr = COUNTVALUE then    -- When the terminal counter is reached, set the release flag and reset the counter
        s_enctr <= (others => '0');
        s_2khzen <= '1';
        s_2khzcount <= std_logic_vector(to_unsigned(to_integer(unsigned( s_2khzcount )) + 1, 4));
    else 
        s_enctr <= std_logic_vector(to_unsigned(to_integer(unsigned( s_enctr )) + 1, 17)); -- As long as the terminal count is not reached: increment the counter.
        if    s_2khzen = '1' then 
        s_2khzen <= '0';
        end if; 
        end if;
    if s_2khzcount = "1010" then
        s_1hzen <= not s_1hzen;
        s_2khzcount <= "0000";
    end if;
end if;
end process p_slowen;
-----------------------------------------------------------------------------
--
-- Debounce buttons and switches
--
-----------------------------------------------------------------------------
p_debounce: process (s_1hzen, reset_i)
variable dbouncecntr : integer:=0;
begin 
if reset_i = '1' then 
        swdebounced <= "0000000000000000";
        pbdebounced <= "0000";
        dbouncecntr :=0;                                 -- Change clocking the process with signal from sens list.
else
    if (dbouncecntr = 0) then
                swtmp <= swsync1;
                pbtmp <= pbsync1;
                dbouncecntr := dbouncecntr + 1;
    elsif (dbouncecntr = 1) then
                if (swtmp = swsync1) then
                    swdebounced <= swsync1;
                end if;
                if (pbtmp = pbsync1) then
                    pbdebounced <= pbsync1;
                end if;
                dbouncecntr := 0;

        end if;
     end if;
end process p_debounce;
swclean_o <= swdebounced;
pbclean_o <= pbdebounced;
-----------------------------------------------------------------------------
--
-- Display controller for the 7-segment display
--
-----------------------------------------------------------------------------
p_displaycontrol: process (clk_i, reset_i)

variable v_scancnt : std_logic_vector(1 downto 0):= "00";
variable v_output : std_logic_vector(3 downto 0):="0000"; 
begin 
if reset_i = '1' then
v_scancnt := "00";
s_ss <= "00000000";
elsif clk_i'event and clk_i = '1' then 
     if    s_2khzen = '1' then 

        case v_scancnt is
            when "00" =>    
            v_output    := cntr0_i;
            s_ss_sel    <=    "0001";
            when "01" =>
            v_output     := cntr1_i;
            s_ss_sel    <=    "0010";
            when "10" =>
            v_output     := cntr2_i;
            s_ss_sel    <=    "0100";
            when "11" =>
            v_output     := cntr3_i;
            s_ss_sel    <=    "1000";
            when others =>
            v_output    := "1111";
            s_ss_sel    <=    "0001";
        end case;

        case v_output is             --ABCDEFG,    
            when "0000" => s_ss <= "11111100";  --0
            when "0001" => s_ss <= "01100000";  --1
            when "0010" => s_ss <= "11011010";  --2
            when "0011" => s_ss <= "11110010";  --3
            when "0100" => s_ss <= "01100110";  --4
            when "0101" => s_ss <= "10110110";  --5
            when "0110" => s_ss <= "10111110";  --6
            when "0111" => s_ss <= "11100000";  --7
            when "1000" => s_ss <= "11111110";  --8
            when "1001" => s_ss <= "11110110";  --9
            when others => s_ss <= v_scancnt & "000000";
        end case;

    if v_scancnt = "11" then
    v_scancnt := "00";
    else
        v_scancnt := std_logic_vector(to_unsigned(to_integer(unsigned( v_scancnt )) + 1, 2));
    end if;

    else null;
    end if;
    else null;

end if;

end process p_displaycontrol;

ss_o <= not s_ss;
ss_sel_o <= not s_ss_sel;
end rtl;

The code for : cntr_top_struc.vhd

library IEEE;
use IEEE.std_logic_1164.all;

architecture rtl of cntr_top is

  component cntr                                                    -- component of cntr

    port (clk_i:        in  std_logic;                              -- 100 MHz system clock
          reset_i:        in  std_logic;                                -- async high active reset
          cntrup_i :    in  std_logic;                                --counts up if signal is '1'
          cntrdown_i :  in  std_logic;                                --counts down if signal is '1'
          cntrreset_i : in  std_logic;                                --sets counter to 0x0 if signal is '1'
          cntrhold_i :  in  std_logic;                                --holds count value if signal is '1'

          cntr0_o:        out std_logic_vector(3 downto 0);            --    Digit 0 (from internal logic)
          cntr1_o:        out std_logic_vector(3 downto 0);            --    Digit 1 (from internal logic)
          cntr2_o:        out std_logic_vector(3 downto 0);            --    Digit 2 (from internal logic)
          cntr3_o:        out std_logic_vector(3 downto 0));            --    Digit 3 (from internal logic)

  end component;

  component io_ctrl   ---- component io_crtl
    port (clk_i:        in  std_logic;                                -- 100 MHz system clock
          reset_i:        in  std_logic;                                -- async high active reset

          cntr0_i:        in std_logic_vector(3 downto 0);            --    Digit 0 (from internal logic)
          cntr1_i:        in std_logic_vector(3 downto 0);            --    Digit 1 (from internal logic)
          cntr2_i:        in std_logic_vector(3 downto 0);            --    Digit 2 (from internal logic)
          cntr3_i:        in std_logic_vector(3 downto 0);            --    Digit 3 (from internal logic)

          swclean_o:    out std_logic_vector(15 downto 0);
          pbclean_o:    out std_logic_vector(3 downto 0);

          ss_o:            out std_logic_vector(7 downto 0);            -- Contain the Value for All 7-Segment Digits     
          ss_sel_o:        out std_logic_vector(3 downto 0);            -- Select a 7-segment digits

          pb_i:            in std_logic_vector(3 downto 0);            --4 Buttons
          sw_i:            in std_logic_vector(15 downto 0) );              --16 Switches

  end component;

  -- Declare the signals that are used to connect the submodules.
  signal s_cntr0 : std_logic_vector(3 downto 0);
  signal s_cntr1 : std_logic_vector(3 downto 0);
  signal s_cntr2 : std_logic_vector(3 downto 0);
  signal s_cntr3 : std_logic_vector(3 downto 0);  
  signal s_cntrup         : std_logic;  
  signal s_cntrdown        : std_logic;  
  signal s_cntrreset     : std_logic; 
  signal s_cntrhold        : std_logic; 
  signal s_overflow : std_logic_vector(11 downto 0);
begin

--Instantiate the counter that is connected to the IO-Control
  i_cntr_top1 : cntr
  port map              
    (clk_i   => clk_i,
     reset_i   => reset_i,
     -- cntrdir_i  => s_cntrdir,                   --swsync_o(13);
     cntrup_i       => s_cntrup,                 --swsync_o(13);
     cntrdown_i     => s_cntrdown,                 --swsync_o(12);
     cntrreset_i    => s_cntrreset,             --swsync_o(15),
     cntrhold_i     => s_cntrhold,                 --swsync_o(14),

     cntr0_o   => s_cntr0,
      cntr1_o   => s_cntr1,
      cntr2_o   => s_cntr2,
     cntr3_o   => s_cntr3);

--Instantiate the IO control to which it is connected
  i_io_ctrl : io_ctrl
  port map
    (clk_i           => clk_i,
     reset_i           => reset_i,   
     swclean_o(12)    => s_cntrdown,
     swclean_o(13)    => s_cntrup,
     swclean_o(15)    => s_cntrreset,
     swclean_o(14)    => s_cntrhold,
     swclean_o(11 downto 0)    => s_overflow(11 downto 0),
     cntr0_i           => s_cntr0,
      cntr1_i           => s_cntr1,
      cntr2_i           => s_cntr2,
     cntr3_i           => s_cntr3,    

     ss_o            =>    ss_o,
     ss_sel_o        =>    ss_sel_o,
     sw_i            =>    sw_i,
     pb_i            =>    pb_i);

end rtl;

cntr_top.vhd

library IEEE;
use IEEE.std_logic_1164.all;

entity cntr_top is 
  port (clk_i :     in std_logic;                           -- First Data Bit
        reset_i :   in std_logic;                           -- Second Data Bit
        sw_i :      in std_logic_vector (15 downto 0);      -- 16 Switches Input    
        pb_i :      in std_logic_vector(3 downto 0);        -- 4 Buttons Input              
        ss_o :      out std_logic_vector(7 downto 0);       -- Contain the Value for All 7-Segment Digits           
        ss_sel_o :  out std_logic_vector(3 downto 0));      -- Select a 7-segment digits


end cntr_top;

io_ctrl.vhd

library IEEE;
use IEEE.std_logic_1164.all;
entity io_ctrl is
  port (clk_i :     in std_logic;                           --  System clock (100 MHZ)
        reset_i :   in std_logic;                           --  Asynchronous high active reset
        cntr0_i :   in std_logic_vector(3 downto 0);        --  Digit 0 from internal logic
        cntr1_i :   in std_logic_vector(3 downto 0);        --  Digit 1 from internal logic
        cntr2_i :   in std_logic_vector(3 downto 0);        --  Digit 2 from internal logic
        cntr3_i :   in std_logic_vector(3 downto 0);        --  Digit 3 from internal logic
        sw_i :      in std_logic_vector(15 downto 0);       --  16 switches (from FPGA board)
        pb_i :      in std_logic_vector(3 downto 0);        --  4 buttons (from FPGA board)             
        ss_o :      out std_logic_vector(7 downto 0);       --  to 7 segment displays of the FPGA board                     
        ss_sel_o :  out std_logic_vector(3 downto 0);       --  Selection of a 7 segment digit
        swclean_o:  out std_logic_vector(15 downto 0);      --  16 switches (to internal logic)
        pbclean_o : out std_logic_vector(3 downto 0));      --  4 buttons   
end io_ctrl;

cntr_rtl.vhd

library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
architecture rtl of cntr is

constant COUNTVALUE : std_logic_vector(26 downto 0):= "000000000000000001111101000";
--constant COUNTVALUE : std_logic_vector(26 downto 0):= "101111101011110000100000000";

signal s_enctr : std_logic_vector(26 downto 0) := "000000000000000000000000000";
signal s_1hzen : std_logic :='0';
signal s_cntr0 : std_logic_vector(3 downto 0) :="0000";    -- All digits set to zero. 
signal s_cntr1 : std_logic_vector(3 downto 0) :="0000";
signal s_cntr2 : std_logic_vector(3 downto 0) :="0000";
signal s_cntr3 : std_logic_vector(3 downto 0) :="0000";

type s_state is (reset, hold, up, down);
signal s_present_state : s_state;
signal s_next_state : s_state;

begin

p_cntr: process(clk_i, reset_i)

variable v_digit0 : std_logic_vector(3 downto 0):= "0000";
variable v_digit1 : std_logic_vector(3 downto 0):= "0000";
variable v_digit2 : std_logic_vector(3 downto 0):= "0000";
variable v_digit3 : std_logic_vector(3 downto 0):= "0000";

begin

if reset_i = '1' then 

    v_digit0 := "0000";
    v_digit1 := "0000";
    v_digit2 := "0000";
    v_digit3 := "0000";
    s_enctr <= (others => '0');



elsif (clk_i'event and clk_i = '1') then
   s_present_state <= s_next_state;
   if s_enctr = COUNTVALUE then --When the number of terminals is reached, set the release flag and reset the counter
        s_enctr <= (others => '0');
        s_1hzen <= '1';

        case s_present_state is

            when up =>                                                                                      --counting up.
                if v_digit0 /= "1001" then
                    v_digit0 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit0 )) + 1, 4));     -- incrementing the bits. 
                elsif v_digit0 = "1001" and v_digit1 /= "1001" then
                    v_digit0 := "0000";
                    v_digit1 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit1 )) + 1, 4));
                elsif v_digit0 = "1001" and v_digit1 = "1001" and v_digit2 /= "1001" then
                    v_digit0 := "0000";
                    v_digit1 := "0000";
                    v_digit2 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit2 )) + 1, 4));
                elsif v_digit0 = "1001" and v_digit1 = "1001" and v_digit2 = "1001" and v_digit3 /= "1001"then
                    v_digit0 := "0000";
                    v_digit1 := "0000";
                    v_digit2 := "0000";
                    v_digit3 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit3 )) + 1, 4));
                else 
                    v_digit0 := "0000";
                    v_digit1 := "0000";
                    v_digit2 := "0000";
                    v_digit3 := "0000";
                end if;

            when down =>                                                                                    --counting down.
                if v_digit0 /= "0000" then
                    v_digit0 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit0 )) - 1, 4));     -- decrementing the bits. 
                elsif v_digit0 = "0000" and v_digit1 /= "0000" then
                    v_digit0 := "1001";
                    v_digit1 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit1 )) - 1, 4));
                elsif v_digit0 = "0000" and v_digit1 = "0000" and v_digit2 /= "0000" then
                    v_digit0 := "1001";
                    v_digit1 := "1001";
                    v_digit2 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit2 )) - 1, 4));
                elsif v_digit0 = "0000" and v_digit1 = "0000" and v_digit2 = "0000" and v_digit3 /= "0000"then
                    v_digit0 := "1001";
                    v_digit1 := "1001";
                    v_digit2 := "1001";
                    v_digit3 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit3 )) - 1, 4));
                else 
                    v_digit0 := "1001";
                    v_digit1 := "1001";
                    v_digit2 := "1001";
                    v_digit3 := "1001";
                end if;

            when hold => null;                                                                              -- holding the counting. 
            when reset =>                                                                                   -- reset all the values to zero. 
                    v_digit0 := "0000";
                    v_digit1 := "0000";
                    v_digit2 := "0000";
                    v_digit3 := "0000";

         end case;

    else 
        s_enctr <=std_logic_vector(to_unsigned(to_integer(unsigned( s_enctr )) + 1, 27)); 
        if  s_1hzen = '1' then 
        s_1hzen <= '0';
        end if; 
    end if;

    s_cntr0 <= v_digit0;
    s_cntr1 <= v_digit1;
    s_cntr2 <= v_digit2;
    s_cntr3 <= v_digit3;
end if;

end process  p_cntr;

    cntr0_o <= s_cntr0;
    cntr1_o <= s_cntr1;
    cntr2_o <= s_cntr2;
    cntr3_o <= s_cntr3;

----------------------------------------------------------------------------------------------------------------
-- State machine
----------------------------------------------------------------------------------------------------------------
p_states: process(s_present_state, cntrup_i, cntrdown_i, cntrreset_i, cntrhold_i,reset_i)
begin
case s_present_state is
when reset  =>                                                                      -- reset state conditions 

        if cntrreset_i = '1' then
            s_next_state <= reset;
        elsif cntrhold_i = '1' then
            s_next_state <= hold;
        elsif cntrup_i = '1' then
            s_next_state <= up;
        elsif cntrdown_i = '1' then
            s_next_state <= down;
        else s_next_state <= hold;
        end if;

when hold   =>                                                                      -- hold state conditions 

        if cntrreset_i = '1' then
            s_next_state <= reset;
        elsif cntrhold_i = '1' then
            s_next_state <= hold;
        elsif cntrup_i = '1' then
            s_next_state <= up;
        elsif cntrdown_i = '1' then
            s_next_state <= down;
        else s_next_state <= hold;
        end if;

when up =>                                                                          -- up count state conditions

        if cntrreset_i = '1' then
            s_next_state <= reset;
        elsif cntrhold_i = '1' then
            s_next_state <= hold;
        elsif cntrup_i = '1' then
            s_next_state <= up;
        elsif cntrdown_i = '1' then
            s_next_state <= down;
        else s_next_state <= hold;
        end if;

when down   =>                                                                      -- down count conditions 

        if cntrreset_i = '1' then
            s_next_state <= reset;
        elsif cntrhold_i = '1' then
            s_next_state <= hold;
        elsif cntrup_i = '1' then
            s_next_state <= up;
        elsif cntrdown_i = '1' then
            s_next_state <= down;
        else s_next_state <= hold;
        end if;

when others => s_next_state <= reset;
end case;

end process  p_states;

end rtl;

cntr.vhd

library IEEE;
use IEEE.std_logic_1164.all;

entity cntr is
  port (clk_i :     in std_logic;                           -- System clock (100 MHZ)
        reset_i :   in std_logic;                           -- Asysnchronous high active reset

        cntrup_i :      in std_logic;                       --counts up if signal is '1'
        cntrdown_i :    in std_logic;                       --counts down if signal is '1'
        cntrreset_i :   in std_logic;                       --sets counter to 0x0 if signal is '1'
        cntrhold_i :    in std_logic;                       --holds count value if signal is '1'

        cntr0_o :   out std_logic_vector(3 downto 0);       --  Digit 0 (from internal logic)
        cntr1_o :   out std_logic_vector(3 downto 0);       --  Digit 1 (from internal logic)
        cntr2_o :   out std_logic_vector(3 downto 0);       --  Digit 2 (from internal logic)
        cntr3_o :   out std_logic_vector(3 downto 0));      --  Digit 3 (from internal logic)
end cntr;

Please waiting for your suggestions.

Any help would be great appricated thanks for all.

here down below example for debounce but couldnt find to way to implement.

-----------------------------------------------------------------------------
--
-- Debounce buttons and switches
--
-----------------------------------------------------------------------------
p_debounce: process (clk_i, reset_i)
begin -- process debounce
if reset_i = '1' then -- asynchronous reset (active high)
elsif clk_i'event and clk_i = '1' then -- rising clock edge
end if;
end process p_debounce;
swsync_o <= swsync;
pbsync_o <= pbsync;
------------------------------------------------------------

1 Answers1

0

You're on the right track in that you need to synchronise the asynchronous inputs and debounce them.

But your debounce code needs to use a separate debouncer for each input with a timeout value of around 100 for a 1 kHz clock.

Here is a generic synchroniser and debouncer which uses parameters to specify the bus width, number of sync registers and timeout value.

Synchroniser.vhd

--
-- Synchronise an asynchronous bus input to avoid metastability problems
--

--
-- Signal Synchroniser (1 bit)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity SynchroniserBit is
    generic
    (
        reg_size: integer := 3  -- Default number of bits in sync register.
    );
    port
    (
        clock: in std_logic;
        async_in: in std_logic := '0';
        sync_out: out std_logic := '0';
        rise: out std_logic := '0';
        fall: out std_logic := '0'
    );
end;

architecture V1 of SynchroniserBit is
    constant MSB: integer := reg_size - 1;
    signal sync_reg: std_logic_vector(MSB downto 0) := (others => '0');
begin
    process (clock)
    begin
        if rising_edge(clock) then
            rise <= not sync_reg(MSB) and sync_reg(MSB - 1);
            fall <= sync_reg(MSB) and not sync_reg(MSB - 1);
            sync_reg <= sync_reg(MSB - 1 downto 0) & async_in;
        end if;
    end process;

    sync_out <= sync_reg(MSB);

end;

--
-- Bus Synchroniser (many bits)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Synchroniser is
    generic
    (
        reg_size: integer := 3;  -- Default number of bits in sync register.
        bus_size: integer := 8   -- Default bus width.
    );
    port
    (
        clock: in std_logic;
        async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
        sync_bus_out: out std_logic_vector(bus_size - 1 downto 0);
        rise_bus_out: out std_logic_vector(bus_size - 1 downto 0);
        fall_bus_out: out std_logic_vector(bus_size - 1 downto 0)
    );
end;

architecture V1 of Synchroniser is

    component SynchroniserBit is
        generic
        (
            reg_size: integer := 3  -- Default number of bits in sync register.
        );
        port
        (
            clock: in std_logic;
            async_in: in std_logic;
            sync_out: out std_logic;
            rise: out std_logic;
            fall: out std_logic
        );
    end component;

begin
    SyncGen: for i in 0 to bus_size - 1 generate
    begin
        Sync: SynchroniserBit
            generic map
            (
                reg_size => reg_size
            )
            port map
            (
                clock => clock,
                async_in => async_bus_in(i),
                sync_out => sync_bus_out(i),
                rise  => rise_bus_out(i),
                fall => fall_bus_out(i)
            );
    end generate;
end;

Debouncer.vhd

--
-- Debounce a bus.
--

--
-- Signal Debouncer (1 bit)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity DebouncerBit is
    port
    (
        clock: in std_logic;
        counter: in integer;
        input: in std_logic;
        output: out std_logic := '0'
    );
end;

architecture V1 of DebouncerBit is
begin
    process(clock)
        variable counter_snapshot: integer := 0;
        variable previous_input: std_logic := '0';
    begin
        if rising_edge(clock) then
            -- If counter wraps around to counter_snapshot,
            -- a full debounce period has elapsed without a change in input,
            -- so output the debounced value.
            if counter_snapshot = counter then
                output <= previous_input;
            end if;
            -- If the input has changed, save a snapshot of the counter.
            if not(input = previous_input) then
                counter_snapshot := counter;
            end if;
            previous_input := input;
        end if;
    end process;
end;

--
-- Bus Debouncer (many bits)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Debouncer is
    generic
    (
        timeout: integer := 100;  -- Default timeout value.
        bus_size: integer := 8    -- Default bus width.
    );
    port
    (
        clock: in std_logic;
        bus_in: in std_logic_vector(bus_size - 1 downto 0);
        bus_out: out std_logic_vector(bus_size - 1 downto 0)
    );
end;

architecture V1 of Debouncer is

    component DebouncerBit is
        port
        (
            clock: in std_logic;
            counter: in integer;
            input: in std_logic;
            output: out std_logic
        );
    end component;

    -- One counter to be shared by all debouncers.
    -- Each debouncer takes a snapshot of the count value when its input changes value.
    signal counter: integer := 0;

begin
    -- Create the debounce period.
    process(clock)
    begin
        if rising_edge(clock) then
            if counter = timeout then
                counter <= 0;
            else
                counter <= counter + 1;
            end if;
        end if;
    end process;

    DebouncerGen: for i in 0 to bus_size - 1 generate
    begin
        Debounce: DebouncerBit
            port map
            (
                clock => clock,
                counter => counter,
                input => bus_in(i),
                output => bus_out(i)
            );
    end generate;
end;

SynchroniseDebounce.vhd

--
-- SynchroniseDebounce
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity SynchroniseDebounce is
    generic
    (
        reg_size: integer := 3;   -- Default number of bits in sync register.
        timeout: integer := 100;  -- Default timeout value.
        bus_size: integer := 8    -- Default bus width.
    );
    port
    (
        clock: in std_logic;
        async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
        db_sync_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0')
    );
end;

architecture V1 of SynchroniseDebounce is

    component Synchroniser is
        generic
        (
            reg_size: integer := 3;  -- Default number of bits in sync register.
            bus_size: integer := 8   -- Default bus width.
        );
        port
        (
            clock: in std_logic;
            async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
            sync_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0');
            rise_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0');
            fall_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0')
        );
    end component;

    component Debouncer is
        generic
        (
            timeout: integer := 100;  -- Default timeout value.
            bus_size: integer := 8    -- Default bus width.
        );
        port
        (
            clock: in std_logic;
            bus_in: in std_logic_vector(bus_size - 1 downto 0);
            bus_out: out std_logic_vector(bus_size - 1 downto 0)
        );
    end component;

    signal sync_bus_out: std_logic_vector(bus_size - 1 downto 0);
    signal rise_bus_out: std_logic_vector(bus_size - 1 downto 0);
    signal fall_bus_out: std_logic_vector(bus_size - 1 downto 0);

begin

    Synchroniser_Inst: Synchroniser
        generic map
        (
            reg_size => REG_SIZE,  -- Override default value.
            bus_size => BUS_SIZE   -- Override default value.
        )
        port map
        (
            clock => clock,
            async_bus_in => async_bus_in,
            sync_bus_out => sync_bus_out,  -- Goes to Debouncer_Inst
            rise_bus_out => rise_bus_out,
            fall_bus_out => fall_bus_out
        );

    Debouncer_Inst: Debouncer
        generic map
        (
            timeout => TIMEOUT,   -- Override default value.
            bus_size => BUS_SIZE  -- Override default value.
        )
        port map
        (
            clock => clock,
            bus_in => sync_bus_out,  -- From Synchroniser_Inst
            bus_out => db_sync_bus_out
        );

end;

Testbench.vhd

--
-- Test Bench
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;

entity testbench is
end;

architecture V1 of testbench is

    component SynchroniseDebounce is
        generic
        (
            reg_size: integer := 3;   -- Default number of bits in sync register.
            timeout: integer := 100;  -- Default timeout value.
            bus_size: integer := 8    -- Default bus width.
        );
        port
        (
            clock: in std_logic;
            async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
            db_sync_bus_out: out std_logic_vector(bus_size - 1 downto 0)
        );
    end component;

    constant NUM_SWITCHES: integer := 16;
    constant NUM_PUSH_BUTTONS: integer := 4;
    signal switches_async, switches_db_sync: std_logic_vector(NUM_SWITCHES - 1 downto 0) := (others => '0');
    signal push_buttons_async, push_buttons_db_sync: std_logic_vector(NUM_PUSH_BUTTONS - 1 downto 0) := (others => '0');

    constant REG_SIZE: integer := 3;
    constant BUS_SIZE: integer := NUM_SWITCHES + NUM_PUSH_BUTTONS;
    signal async_bus_in, db_sync_bus_out, rise_bus_out, fall_bus_out: std_logic_vector(BUS_SIZE - 1 downto 0) := (others => '0');

    constant TIMEOUT: integer := 10;  -- Number of clock cycles in debounce period.

    signal clock: std_logic;
    constant PERIOD: time := 10 ns;  -- System clock frequency.
    signal stop_clock: boolean := false;

begin
    ClockGenerator: process
    begin
        while not stop_clock loop
            clock <= '0';
            wait for PERIOD / 2;
            clock <= '1';
            wait for PERIOD / 2;
        end loop;
        wait;
    end process ClockGenerator;

    Stimulus: process
        variable seed1, seed2: positive;
        variable rrand: real;
        variable irand: integer;

    begin
        switches_async <= (others => '0');
        push_buttons_async <= (others => '0');
        wait for 23 ns;

        -- Some noisy inputs.
        seed1 := 1;
        seed2 := 1;
        for n in 1 to 500 loop
            for i in 0 to NUM_PUSH_BUTTONS - 1 loop
                uniform(seed1, seed2, rrand);
                irand := integer(round(rrand));
                if irand = 0 then
                    push_buttons_async(i) <= '0';
                else
                    push_buttons_async(i) <= '1';
                end if;
            end loop;
            for i in 0 to NUM_SWITCHES - 1 loop
                uniform(seed1, seed2, rrand);
                irand := integer(round(rrand));
                if irand = 0 then
                    switches_async(i) <= '0';
                else
                    switches_async(i) <= '1';
                end if;
            end loop;
            wait for 1 ns;
        end loop;

        -- Pulse the push buttons.
        for i in 0 to NUM_PUSH_BUTTONS - 1 loop
            push_buttons_async(i) <= '1';
            wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
            push_buttons_async(i) <= '0';
        end loop;

        -- Pulse the switches.
        for i in 0 to NUM_SWITCHES - 1 loop
            switches_async(i) <= '1';
            wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
            switches_async(i) <= '0';
        end loop;
        wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
        stop_clock <= true;
        wait;
    end process Stimulus;

    DUT: SynchroniseDebounce
        generic map
        (
            reg_size => REG_SIZE,  -- Override default value.
            timeout => TIMEOUT,    -- Override default value.
            bus_size => BUS_SIZE   -- Override default value.
        )
        port map
        (
            clock => clock,
            async_bus_in => async_bus_in,
            db_sync_bus_out => db_sync_bus_out
        );

    -- Connect the input switches and input push buttons to the asynchronous bus input.
    async_bus_in <= switches_async & push_buttons_async;

    -- Connect the debounced and synchronised output bus to the debounced synchronised switches and push buttons.
    switches_db_sync <= db_sync_bus_out(NUM_SWITCHES + NUM_PUSH_BUTTONS - 1 downto NUM_PUSH_BUTTONS);
    push_buttons_db_sync <= db_sync_bus_out(NUM_PUSH_BUTTONS - 1 downto 0);
end;

Testbench Waveforms

Bit 2 of the debounced synchronous bus (db_sync_bus_out) goes high only when a long enough pulse is applied to the input (async_bus_in).

Testbench waveforms of Bit 2 of synchroniser and debouncer

tim
  • 482
  • 3
  • 12