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.