Flower
Flower

Reputation: 401

De-bounced button press resulting in successive state transitions

I am programming an FPGA that uses push buttons as input signals. It has a finite state machine with 11 states that transition from state to state using specific button presses.

For example, in my design, state s0 goes to state s1 using a button press. This is the same transition case from state s1 to s2 and from state s2 to s3. This state transition system is implemented in my VHDL code using case statements.

LEDs light up in each state to keep track of which state the board is currently in.

My issue is that when my_btnL = '1' is true while in state s0, the board shows that it has moved to state s3.

What I think is happening is that it is indeed going to state s1 and s2 but the same button press in state s0 is also being read in state s1 and s2. This happens so fast that the boards doesn't have enough time to show the LED indications for state s1 and s2. It stops at state s3 because state s3 moves to state s4 using a different button.

So my question is how do I make the button press signal have a rising edge and a falling edge such that a single button press is read only in one state and not the ones that follow it?

The press button signals are de-bounced but this only makes the signal a uniform square wave.

In the following code btnC, btnL, btnR,... are the push buttons:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;


entity digital_lock is
    Port ( 
            my_btnC, clk, my_btnU, my_btnR, my_btnL, my_btnD: in std_logic;
            my_sw: in std_logic_vector(3 downto 0);
            hex0, hex1, hex2, hex3: out std_logic_vector (3 downto 0);
            my_led: out std_logic_vector(15 downto 0)
            );
end digital_lock;

architecture Behavioral of digital_lock is
type state IS (s0, s1, s2, s3, s4 ,s5  ,s6, s7, s8, s9, s10,s11);

signal my_state: state;
signal my_status: unsigned(1 downto 0);
signal num1, num2, num3, key1, key2, key3: std_logic_vector(3 downto 0);
signal number, final_key: std_logic_vector(11 downto 0);

begin

    FSM: process(clk, my_btnC)
    begin
    if(my_btnC ='1') then
        my_state <= s0;
    elsif rising_edge(clk) then
        case my_state is
            when s0 =>
                my_status <= "00";
                my_led <= "1100000000000000";
                hex3 <= "0000";
                hex2 <= "0000";
                hex1 <= "0000";
                hex0 <= "0000";
                if(my_btnL ='1') then
                    my_state <= s1;
                else
                    my_state <= s0;
                end if;
             when s1 =>
                key1 <= my_sw;
                hex0 <= key1;
                my_led <= "0000000000000001";
                if(my_btnL='1') then
                    my_state <= s2;
                else
                    my_state <= s1;
                end if;
            when s2 =>
                key2 <= my_sw;
                hex0 <= key2;
                my_led <= "0000000000000010";
                if(my_btnL ='1') then
                    my_state <= s3;
                else
                    my_state <= s2;
                end if;
            when s3 =>
                key3 <= my_sw;
                hex0 <= key3;
                my_led <= "0000000000000011";
                if(my_btnR= '1') then
                    my_state <= s4;
                else 
                    my_state <= s3;
                end if;
            when s4 =>
                final_key(11 downto 8) <= key1;
                final_key(7 downto 4) <= key2;
                final_key(3 downto 0) <= key3;
                my_led <= "0000000000000100";
                if(my_btnU ='1') then
                    my_state <= s5;
                else
                    my_state <= s4;
                end if;
            when s5 =>
                num1 <= my_sw;
                hex0 <= num1;
                my_led <= "0000000000000101";
                if(my_btnD ='1') then
                    my_state <= s0;
                elsif (my_btnL ='1') then
                    my_state <= s6;
                else
                    my_state <= s5;
                end if;
            when s6 =>
                num2 <= my_sw;
                hex0 <= num2;
                my_led <= "0000000000000110";
                if(my_btnD ='1') then
                    my_state <= s0;
                elsif(my_btnL ='1') then
                    my_state <= s7;
                else
                    my_state <= s6;
                end if;
            when s7 =>
                num3 <= my_sw;
                hex0 <= num3;
                my_led <= "0000000000000111";
                if(my_btnD ='1') then
                    my_state <= s0;
                elsif(my_btnR = '1') then
                    my_state <= s8;
                else 
                    my_state <= s7;
                end if;
            when s8 =>
                number(11 downto 8) <= num1;
                number(7 downto 4) <= num2;
                number(3 downto 0) <= num3;
                my_led <= "0000000000001000";
                if(number = final_key) then
                    my_state <= s9;
                else
                    my_state <= s10;
                end if; 
            when s9 =>
                my_led <= "1111111111111111";
                if(my_btnD = '1') then
                    my_state <= s0;
                else
                    my_state <= s9;
                end if;
            when s10 =>
                my_status <= my_status + 1;
                if(my_status >= 3) then
                    my_state <= s11;
                elsif(my_status < 3) then
                    my_state <= s5;
                end if;
            when s11 =>
                my_led <= "0000000000000000";
                hex0 <= "1111";
                hex1 <= "1111";
                hex2 <= "1111";
                hex3 <= "1111";
                my_state <= s11;
        end case;
        end if;
    end process;
end Behavioral;

Upvotes: 1

Views: 627

Answers (1)

user1155120
user1155120

Reputation:

An edge detector for a de-bounced signal in the same clock domain as the state machine can be done with a flip flop with the signal input and a gate to detect the preferred state on the input (following the input edge) while the flip flop is in the other state.

signal my_btnL_event: std_logic;
signal my_btnLd:      std_logic;  -- architecture declarative items

process (clk)
begin
    if rising_edge(clk) then
        my_btnLd <= my_btnL;  
    end if;

my_btnL_event <= my_btnL and not my_btnLd;

Where you'd use my_btnL_event in place of my_btnL for transitioning between states.

Note this would require my_btnL to go invaid before going valid again assuming adequate de-bounce.

The my_btnL_event assignment could be expressed in multiple ways, such as an by an if statement or a conditional signal assignment.

Upvotes: 2

Related Questions