-------------------------------------------------------------------------------- -- File Name : Keydecoder.vhd -- Created by Su Tarn, Lim -- Keypad driver -- -- This file contains the VHDL keyboard handling. -- -- Descriptions: -- It takes 8 inputs from a 83-BB1-002 4x4 keyboard and give a 4-bit -- binary signal to indicate which key was pressed -- -- The layout of the 4x4 Keyboard is -- -- 0 1 2 3 -- 4 5 6 7 -- 8 9 A B -- C D E F -- -- X0-X3 goes from right to left -- Y0-Y3 goes from down to top -- -- The pins from the columns will be active high, it will be high -- when one of the key in the column is pressed. The pins from the -- rows are connected active, low which will only go low when one -- of the key in the row is pressed. -- -- Ackknowledgement : Edgar Wong with help in debouncing -- -- Total logic cells used: 74/1152 ( 6%) -- -- Total logic cells used: 64/1152 ( 5%) Nov 22 -------------------------------------------------------------------------------- ------------------------- -- Package Declaration -- ------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.Constants_Package.all; package Keypad_Package is component keydecoder is port( clock: in std_logic; -- output to Control Ack : in std_logic; keyData: out std_logic_vector(KEYPAD_DATA_WIDTH-1 downto 0); keyDataAvailable: out std_logic; -- input from keyboard col_output : out std_logic_vector (3 downto 0); row_input : in std_logic_vector (3 downto 0) ); end component keydecoder; end Keypad_Package; -------------------------------------------------------------------------------- ------------------------ -- Entity Declaration -- ------------------------ LIBRARY IEEE; USE ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.Constants_Package.all; entity keydecoder is port ( clock : in std_logic; Ack : in std_logic; KeyData : out std_logic_vector (KEYPAD_DATA_WIDTH-1 downto 0); KeyDataAvailable : out std_logic; col_output : out std_logic_vector (3 downto 0); row_input : in std_logic_vector (3 downto 0) ); end keydecoder; architecture behavioural of keydecoder is type state_type1 is ( nokey, debounce, ScanX0, ScanX1, ScanX2, ScanX3, outputkey, outputAck, waitforrelease, debounce_output, keyrelease ); signal NextState : state_type1; signal keydetect : std_logic; signal yrow : std_logic_vector (KEYPAD_DATA_WIDTH-1 downto 0) := "1111"; signal key : std_logic_vector (KEYPAD_DATA_WIDTH-1 downto 0); signal deb_reset : std_logic; signal AckTrack : std_logic; signal dumb : std_logic; begin -- latch inputs latchinputs : process is begin if falling_edge(clock) then yrow(3 downto 0) <= row_input(3 downto 0); end if; end process latchinputs; delay: process(clock) variable count: std_logic_vector(14 downto 0) :=(others => '0'); begin if rising_edge(clock) then if (NextState = debounce or NextState = debounce_output) then -- if count = "110001001010111" then -- 25MHz clock if count = "11000011010100" then -- 12.5MHz clock deb_reset <= '1'; count:= "000000000000000"; else deb_reset <= '0'; -- a key is being pressed count := count + 1; end if; else count:= "000000000000000"; end if; end if; end process delay; -- signal used to detect if a key is pressed key_press_detect : process is begin keydetect <= (row_input(3) and row_input(2) and row_input(1) and row_input(0)); -- keydetect <= (yrow(0) and yrow(1)) and (yrow(2) and yrow(3)); -- active low end process key_press_detect; -- state logic to determine the current state statelogic : process (clock) is begin if rising_edge (clock) then case NextState is when nokey => -- dumb <= '0'; if keydetect = '1' then NextState <= nokey; elsif keydetect = '0' then NextState <= debounce; else NextState <= nokey; end if; when debounce => if keydetect = '0' then if deb_reset = '1' then NextState <= ScanX0; elsif deb_reset = '0' then NextState <= debounce; end if; else NextState <= keyrelease; end if; when ScanX0 => if keydetect = '0' then NextState <= ScanX1; else -- NextState <= outputkey; NextState <= waitforrelease; end if; when ScanX1 => if keydetect = '0' then NextState <= ScanX2; else -- NextState <= outputkey; NextState <= waitforrelease; end if; when ScanX2 => if keydetect = '0' then NextState <= ScanX3; else NextState <= waitforrelease; -- NextState <= outputkey; end if; when ScanX3 => if keydetect = '0' then NextState <= outputkey; -- NextState <= ScanX0; else NextState <= waitforrelease; -- NextState <= outputkey; end if; when outputkey => if keydetect = '0' then NextState <= outputAck; else NextState <= waitforrelease; end if; -- NextState <= waitforrelease; when outputAck => if keydetect = '0' then NextState <= ScanX0; else NextState <= waitforrelease; end if; when waitforrelease => if keydetect = '0' then NextState <= waitforrelease; else NextState <= debounce_output; end if; when debounce_output => if keydetect = '1' then if deb_reset = '1' then NextState <= keyrelease; elsif deb_reset = '0' then NextState <= debounce_output; end if; else NextState <= waitforrelease; end if; when keyrelease => NextState <= nokey; when others => NextState <= nokey; end case; end if; end process statelogic; with NextState select col_output <= "0001" when ScanX0, "0010" when ScanX1, "0100" when ScanX2, "1000" when ScanX3, "0000" when OTHERS; -- col_output <= "1110" when ScanX0, -- "1101" when ScanX1, -- "1011" when ScanX2, -- "0111" when ScanX3, -- "0000" when OTHERS; -- outputs a 4-bit signals representing which key was pressed EncodeOutput : process (clock, NextState) is begin if falling_edge(clock) then if NextState = ScanX0 then if yrow(0) = '0' then key <= ZERO_KEY; -- "0000", Key 0 elsif yrow(1) = '0' then key <= FOUR_KEY; -- "0110", Key 4 elsif yrow(2) = '0' then key <= EIGHT_KEY; -- "1000", Key 8 elsif yrow(3) = '0' then key <= ENT_KEY; -- "1100", Key C end if; elsif NextState = ScanX1 then if yrow(0) = '0' then key <= ONE_KEY; -- "0001", Key 1 elsif yrow(1) = '0' then key <= FIVE_KEY; -- "0101", Key 5 elsif yrow(2) = '0' then key <= NINE_KEY; -- "1001", Key 9 elsif yrow(3) = '0' then key <= LEFT_KEY; -- "1101", Key D end if; elsif NextState = ScanX2 then if yrow(0) = '0' then key <= TWO_KEY; -- "0011", Key 2 elsif yrow(1) = '0' then key <= SIX_KEY; -- "1010", Key 6 elsif yrow(2) = '0' then key <= UP_KEY; -- "1010", Key A elsif yrow(3) = '0' then key <= RIGHT_KEY; -- "1110", Key E end if; elsif NextState = ScanX3 then if yrow(0) = '0' then key <= THREE_KEY; -- "0000", Key 3 elsif yrow(1) = '0' then key <= SEVEN_KEY; -- "0110", Key 7 elsif yrow(2) = '0' then key <= DOWN_KEY; -- "1000", Key B elsif yrow(3) = '0' then key <= RST_KEY; -- "1111", Key F end if; end if; end if; end process EncodeOutput; -- latch output output : process (NextState, Ack) is begin if NextState = nokey then dumb <= '0'; AckTrack <= '0'; KeyDataAvailable <= '0'; KeyData <= (others => '0'); elsif Ack = '1' then AckTrack <= '1'; elsif (AckTrack = '0') then -- if (NextState = outputkey) then if (NextState = ScanX0 or NextState = ScanX1 or NextState = ScanX2 or NextState = ScanX3) then KeyData <= key; dumb <= '1'; -- keyDataAvailable <= '1'; -- end if; elsif (dumb = '1') then -- elsif (NextState = outputAck) then keyDataAvailable <= '1'; end if; else KeyDataAvailable <= '0'; end if; end process output; end behavioural;