0
\$\begingroup\$

I am back with probably a very simple fix which I cannot wrap my head around.

I've added a debounce to my button but it seems to not be working correctly.

Here are my issues:

  1. When the button is pressed the value of the counter switches, but doesnt count up.
  2. When the button is pressed, the value displayed changes displays, it doesn't continuously display on the same one.

Here is my code:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_unsigned.all;

entity Try1 is
    Port ( clock_100Mhz : in STD_LOGIC;   -- 100Mhz clock on Basys 3 FPGA board
           reset : in STD_LOGIC;         -- reset
           button : in STD_LOGIC;        -- input button to increment count
           Anode_Activate : out STD_LOGIC_VECTOR (3 downto 0); -- 4 Anode signals
           LED_out : out STD_LOGIC_VECTOR (6 downto 0));       -- Cathode patterns of 7-segment display
end Try1;

architecture Behavioral of Try1 is
signal one_second_counter: STD_LOGIC_VECTOR (27 downto 0); 
-- counter for generating 1-second clock enable
signal one_second_enable: std_logic;                       
-- one second enable for counting numbers
signal displayed_number: STD_LOGIC_VECTOR (15 downto 0);    
-- counting decimal number to be displayed on 4-digit 7-segment display
signal LED_BCD: STD_LOGIC_VECTOR (3 downto 0);
signal refresh_counter: STD_LOGIC_VECTOR (19 downto 0);     
-- creating 10.5ms refresh period
signal LED_activating_counter: std_logic_vector(1 downto 0); 
-- the other 2-bit for creating 4 LED-activating signals
-- count         0    ->  1  ->  2  ->  3
-- activates    LED1    LED2   LED3   LED4
-- and repeat
    
begin
    -- VHDL code for BCD to 7-segment decoder
    -- Cathode patterns of the 7-segment LED display 
process(LED_BCD)
begin
        case LED_BCD is
        when "0000" => LED_out <= "0000001"; -- "0"     
        when "0001" => LED_out <= "1001111"; -- "1" 
        when "0010" => LED_out <= "0010010"; -- "2" 
        when "0011" => LED_out <= "0000110"; -- "3" 
        when "0100" => LED_out <= "1001100"; -- "4" 
        when "0101" => LED_out <= "0100100"; -- "5" 
        when "0110" => LED_out <= "0100000"; -- "6" 
        when "0111" => LED_out <= "0001111"; -- "7" 
        when "1000" => LED_out <= "0000000"; -- "8"     
        when "1001" => LED_out <= "0000100"; -- "9" 
        when others => LED_out <= "1111111";
        end case;
end process;

process(clock_100Mhz, reset, button)
    variable button_state : std_logic := '0';
    variable button_counter : integer := 0;
    variable debounced_button : std_logic := '0';
begin 
    if(reset='1') then
        refresh_counter <= (others => '0');
        button_counter := 0;
        debounced_button := '0';
    elsif(rising_edge(clock_100Mhz)) then
        -- update debounced button
        if(button = '1') then
            if(button_counter < 10) then
                button_counter := button_counter + 1;
            else
                debounced_button := '1';
            end if;
        else
            debounced_button := '0';
            button_counter := 0;
        end if;

        -- increment refresh counter only if debounced button is pressed
        if(debounced_button = '1') then
            refresh_counter <= refresh_counter + 1;
        end if;

        button_state := button; -- store current button state for next clock cycle
    end if;
end process;
LED_activating_counter <= refresh_counter(19 downto 18);
-- 4-to-1 MUX to generate anode activating signals for 4 LEDs 
process(LED_activating_counter, displayed_number)
begin
    case LED_activating_counter is
    when "00" =>
        Anode_Activate <= "0111"; 
        -- activate LED1 and Deactivate LED2, LED3, LED4
        LED_BCD <= displayed_number(15 downto 12);
        -- the first hex digit of the 16-bit number
    when "01" =>
        Anode_Activate <= "1011"; 
        -- activate LED2 and Deactivate LED1, LED3, LED4
        LED_BCD <= displayed_number(11 downto 8);
        -- the second hex digit of the 16-bit number
    when "10" =>
        Anode_Activate <= "1101"; 
        -- activate LED3 and Deactivate LED2, LED1, LED4
        LED_BCD <= displayed_number(7 downto 4);
        -- the third hex digit of the 16-bit number
    when "11" =>
        Anode_Activate <= "1110"; 
        -- activate LED4 and Deactivate LED2, LED3, LED1
        LED_BCD <= displayed_number(3 downto 0);
        -- the fourth hex digit of the 16-bit number    
    end case;
end process;
-- Counting the number to be displayed on 4-digit 7-segment Display 
-- on Basys 3 FPGA board
process(clock_100Mhz, reset, Button)
begin
    if(reset='1') then
        one_second_counter <= (others => '0');
        one_second_enable <= '0'; -- set to 0 on reset
    elsif(rising_edge(clock_100Mhz)) then
        if(one_second_counter>=x"5F5E0FF") then
            one_second_counter <= (others => '0');
            one_second_enable <= '0'; -- disable counting after one second
        else
            if(Button = '1') then -- check if button is pressed
                one_second_counter <= one_second_counter + "0000001";
                one_second_enable <= '1'; -- enable counting for one second
            else
                one_second_enable <= '0'; -- disable counting if button not pressed
            end if;
        end if;
    end if;
end process;

process(clock_100Mhz, reset, button)
begin
    if (reset = '1') then
        displayed_number <= (others => '0');
    elsif (rising_edge(clock_100Mhz)) then
        if (button = '1') then
            displayed_number <= displayed_number + 1;
        end if;
    end if;
end process;
end Behavioral;
\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

Anytime you have a gpio input to vhdl it needs to be synchronized with the clock, but especially with switches because of switch bounce. Another problem is if you don't properly sequence the input you can get metastability (or unknowns in simulation) that propagate throughout the logic I'm not going to lead to incorrect results or latchups.

Use a dual rank synchronizer between your input and input to the HDL

\$\endgroup\$
2
  • \$\begingroup\$ I have also added a synchronizer to my code and no luck with the correct output being shown. Do you think it might be a logic issue? \$\endgroup\$ Mar 20 at 21:14
  • \$\begingroup\$ Are you correctly resetting the resets on all clocked logic? \$\endgroup\$
    – Voltage Spike
    Mar 20 at 21:26
0
\$\begingroup\$

When a mechanical switch is pressed or unpressed it will bounce wildly for several msec. Your button_counter only counts to 10 at 100MHz – that’s only 100ns so not nearly long enough.

But you don’t need any counters or state machines to debounce a switch in software or an FPGA.

Given that:

  1. a switch will bounce for several msec, and
  2. a pressed switch will stay pressed for at least a few hundred msec (if pressed by a human)

then all you need to do is sample the state of the button every 10-50ms or so and just use that value.

In the high resolution rendering below the green trace is the switch with about 5ms of bounce.

enter image description here

The blue marks denote the sampling of the button. Sample 1 and 2 read the button at 0, and sample 4 (and 5,6…) reads it at 1. If sample 3 falls within the bounce window it will read either 0 or 1, either of which is valid there.

Again at the falling edge sample 9, several samples before 9 read ‘1’ and several samples after 9 read ‘0’ so it doesn’t really matter which state sample 9 reads – either one is fine.

You’ll never see a 1-0-1 or 0-1-0 (bounce) sequence because you’re sampling much slower than the bounce rate.

\$\endgroup\$
2
  • \$\begingroup\$ Hi there, i understand how the button debouncing works now, however when i have made the button debounce duration longer, it sitll doesn't count correctly up, in steps of one, it keeps jumping values, im wondering if its just an issue with the logic itself? \$\endgroup\$ Mar 20 at 21:13
  • \$\begingroup\$ Your last process doesn't look right. As long as the button is pressed the displayed_number increments every 10ns? \$\endgroup\$
    – td127
    Mar 21 at 6:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.