0

I'm programming an FPGA board w/ Lattice XP2-5E chip. On board are also 4 rows and 2 columns of LED lights which I'm trying to control with 4 directional push-buttons and one reset push-button. For instance, if (1st row/1st column) LED is turned on and if I press button right, (1st row/2nd column) LED would turn on and (1st row/1st column) LED would turn off.

Since there is no built-in hardware debouncing circuit implemented, I need to implement a VHDL solution. Tick rate is 25 MHz and minimal button hold time is 25 ms. Code is shown below:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity SKLOP is
port (  btn_center : in std_logic;
        btn_left : in std_logic;
        btn_right : in std_logic;
        btn_up : in std_logic;
        btn_down : in std_logic;

        clk_25m : in std_logic;

        led : out std_logic_vector (7 downto 0));
end SKLOP;

architecture behv of SKLOP is

    type state_type is (s0, s1, s2, s3, s4, s5, s6, s7);
    signal CurS : state_type := s0;
    signal NxtS : state_type := s0;
    signal counter : std_logic_vector (22 downto 0) := (others => '0');
    signal is_ok : std_logic := '0';
    signal btn_press : std_logic := '0';
    signal start_cnt : std_logic := '0';

begin

    process(is_ok)                                -- state switching
    begin

        if(btn_left = '1' and rising_edge(is_ok)) then
            case CurS is
                when s0 =>
                    NxtS <= s0;
                when s1 =>
                    NxtS <= s1;
                when s2 =>
                    NxtS <= s2;
                when s3 =>
                    NxtS <= s3;
                when s4 =>
                    NxtS <= s0;
                when s5 =>
                    NxtS <= s1;
                when s6 =>
                    NxtS <= s2;
                when s7 =>
                    NxtS <= s3;
            end case;
        end if;

        if(btn_right = '1' and rising_edge(is_ok)) then
            case CurS is
                when s0 =>
                    NxtS <= s4;
                when s1 =>
                    NxtS <= s5;
                when s2 =>
                    NxtS <= s6;
                when s3 =>
                    NxtS <= s7;
                when s4 =>
                    NxtS <= s4;
                when s5 =>
                    NxtS <= s5;
                when s6 =>
                    NxtS <= s6;
                when s7 =>
                    NxtS <= s7;
            end case;
        end if;

        if(btn_up = '1' and rising_edge(is_ok)) then
            case CurS is
                when s0 =>
                    NxtS <= s0;
                when s1 =>
                    NxtS <= s0;
                when s2 =>
                    NxtS <= s1;
                when s3 =>
                    NxtS <= s2;
                when s4 =>
                    NxtS <= s4;
                when s5 =>
                    NxtS <= s4;
                when s6 =>
                    NxtS <= s5;
                when s7 =>
                    NxtS <= s6;
            end case;
        end if;

        if(btn_down = '1' and rising_edge(is_ok)) then
            case CurS is
                when s0 =>
                    NxtS <= s1;
                when s1 =>
                    NxtS <= s2;
                when s2 =>
                    NxtS <= s3;
                when s3 =>
                    NxtS <= s3;
                when s4 =>
                    NxtS <= s5;
                when s5 =>
                    NxtS <= s6;
                when s6 =>
                    NxtS <= s7;
                when s7 =>
                    NxtS <= s7;
            end case;
        end if;

        if(btn_center = '1' and rising_edge(is_ok)) then
            NxtS <= s0;
        end if;

    end process;

    process(CurS)                                   -- output of state machine
    begin
        case CurS is
            when s0 =>
                led <= "10000000";
            when s1 =>
                led <= "01000000";
            when s2 =>
                led <= "00100000";
            when s3 =>
                led <= "00010000";
            when s4 =>
                led <= "00001000";
            when s5 =>
                led <= "00000100";
            when s6 =>
                led <= "00000010";
            when s7 =>
                led <= "00000001";
        end case;
    end process;

    process(clk_25m)                                -- debouncing
    begin
        if(btn_center = '1' or btn_right = '1' or btn_left = '1' or btn_up = '1' or btn_down = '1') then
            btn_press <= '1';
        else
            btn_press <= '0';
        end if;

        if(rising_edge(btn_press)) then
            start_cnt <= '1';
        end if;
        if(falling_edge(btn_press)) then
            start_cnt <= '1';
        end if;

        if(rising_edge(clk_25m)) then
            if(counter /= "10111110101111000010000" and start_cnt = '1') then
                counter <= counter + '1';
                is_ok <= '0';
            elsif(start_cnt = '1' and btn_press = '1') then
                is_ok <= '1';
                CurS <= NxtS;
                start_cnt <= '0';
                counter <= "00000000000000000000000";
            end if;
        end if;

    end process;

end behv;

Sometimes the code works as intended but often times there are multiple LED lights turned on or no LED are turned on - I wonder how can this be even possible - and sometimes the state doesn't change when pushing a button (even when holding a button for much longer than 25 ms).

What seems to be the problem. I am running out of ideas.

kreso
  • 11
  • 1
  • 4
  • `rising_edge` can not be used on normal signals, only on clock signals e.g. `clk_25m`. You'll need a edge detection circuit (1× NOT + 1× AND gate + 1×D-FF) as a replacement. Your state machine is no state machine -> I bet your synthesis tool will not recognize a FSM in your code. Plaese use one of the many FSM patterns for VHDL. Your counter solution is not a debounce circuit. Additionally all button inputs are not synchronized (e.g. 2 FF synchronizer) to clk_25m. – Paebbels Sep 29 '15 at 23:02
  • There are many existing answers concerning debouncing, for example here http://stackoverflow.com/questions/32589963/vhdl-button-debounce-inside-a-mealy-state-machine/32590732#32590732 . If your state machine doesn't work, that's probably a separate question, but have a go at following a standard state machine template first (again, many existing answers for this) – scary_jeff Sep 30 '15 at 08:20
  • Thank you for your responses. I have implemented modified version of state machine and debouncing code and it works as intended. `rising_edge` is working for all signals. – kreso Sep 30 '15 at 22:36
  • 2
    @kreso - `rising_edge` "works" with any signal in the sense that you will no get compilation errors but you should however consider the synthesis semantics of the language if you want to synthesize. If you use `rising_edge` the way you do in the presented code, the result will not be what you want. It may "work" by chance but learning a programming language should target a bit better than "works by accident". – Renaud Pacalet Oct 01 '15 at 05:17
  • @kreso As Renaud said, this code is not a proper way of writting VHDL code. Any process should have one and only one RISING_EDGE for the signal that will be used as the clock for all the signals in the block. In your code, if you write (if (rising_edge(clk_25m)) and then inside that, you put the if statement for EACH botton, you will get a working solution. But you have to remember that all if-then-elese statements must cover all the signals in the group, if oyu don't do that, you will get latches instead of flipflops! – FarhadA Oct 01 '15 at 10:27
  • @RenaudPacalet - I get now that using `rising_edge` in a process not sensitive to the signal used with the `rising_edge` operator is not a good practice. However, I'd like to know if it's ok to use `rising_edge` with non-clock signal if the process is sensitive to said signal? – kreso Oct 07 '15 at 13:23
  • @kreso If you want to synthesize, no, it's not a good idea. In most hardware targets clocks are managed in a special way. To make it short: clocks are buffered by a special network of buffer gates. This network tries to avoid long slopes on this usually heavily loaded signal and it also tries to balance the branches of the network such that the destination flip-flops or latches all see the clock edges at the same time (no or small clock skew). So using as a clock a signals that is not handled as a clock in your hardware target exposes you to severe disappointments. – Renaud Pacalet Oct 07 '15 at 15:29
  • You may want to edit your question to avoid misleading the readers: "Since there is no hardware debouncing circuit implemented, I need to implement a software solution." Maybe it would be better to say "Since there is no *built-in* hardware debouncing circuit implemented, I need to implement a *VHDL* solution." VHDL is not software, not in this context, at least. – rick Oct 17 '15 at 13:26

0 Answers0