------------------------------------------------------------------------------- -- -- EE 552 Project: Driver's Ed -- -- Keydecode: A module for decoding the keypresses from a 4X4 keypad -- -- Description: A state machine for implementing a 4X4 keypad keyscanning algorithm -- The detected key is output in 4 bit binary as a registered value. -- Furthermore, the keyvalid signal will go high for one clock period -- following the detection of a valid keypress. Implemented as a -- pure Moore Machine, not a Moore/Mealy or Mealy machine, for proper -- operation on Altera FPGA's -- -- Author: Raymond Sung -- -- Compiled and Simulated with no known bugs -- -- References: Modified and corrected of errors from Student Application Note -- http://www.ee.ualberta.ca/~elliott/ee552/studentAppNotes/99w/keypad/keypad.vhd LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; library work; use work.keydecode_pkg.all; ENTITY keydecode IS PORT( clk : IN STD_LOGIC; resetn : IN STD_LOGIC; row : IN STD_LOGIC_VECTOR(3 downto 0); col : OUT STD_LOGIC_VECTOR(3 downto 0); keyvalue_registered : OUT STD_LOGIC_VECTOR(3 downto 0); keyvalid : OUT STD_LOGIC ); END keydecode; ARCHITECTURE mixed OF keydecode IS TYPE STATE_TYPE IS ( Start_State, DriveAll, KeyDetect, Delay, Drive1, Detect1, Drive2, Detect2, Drive3, Detect3, Drive4, Detect4, Decode1, Decode2, Decode3, Decode4, Latch0, Latch1, Latch2, Latch3, Latch4, Latch5, Latch6, Latch7, Latch8, Latch9, Latch10, Latch11, Latch12, Latch13, Latch14, Latch15, PrepareDrive, Capture0, Capture1, Capture2, Capture3, Capture4, Capture5, Capture6, Capture7, Capture8, Capture9, Capture10, Capture11, Capture12, Capture13, Capture14, Capture15, KeyReleaseAssert, KeyReleaseDetect ); SIGNAL state: STATE_TYPE; signal sense: std_logic; signal count_value: std_logic_vector(3 downto 0); signal count_resetn: std_logic; signal keyvalue: std_logic_vector(3 downto 0); signal register_load: std_logic; signal register_resetn: std_logic; BEGIN delay_counter: component async_counter generic map (counter_size => 4) port map ( clock => clk, resetn => count_resetn, output_count => count_value ); output_register: component registerN generic map(width => 4) port map ( d => keyvalue, load => register_load, clock => clk, resetn => resetn, q => keyvalue_registered ); sense <= row(0) and row(1) and row(2) and row(3); -- Moore Machine Next state logic PROCESS (clk) BEGIN IF resetn = '0' THEN state <= Start_State; ELSIF clk'EVENT AND clk = '1' THEN CASE state IS WHEN Start_State => state <= DriveAll; WHEN DriveAll => -- drive all cols IF count_value = "1111" THEN state <= KeyDetect; END IF; WHEN KeyDetect => -- determine if any key is pressed. If -- not, continue driving columns IF sense = '1' THEN state <= DriveAll; elsif sense = '0' then state <= Delay; END IF; WHEN Delay => -- key detected, delay IF count_value = "1111" THEN state <= PrepareDrive; END IF; when PrepareDrive => -- determine what key was pressed state <= Drive1; when Drive1 => -- Is key in column 1 if count_value = "1111" THEN state <= Detect1; end if; when Detect1 => if sense = '1' then state <= Drive2; elsif sense = '0' then state <= Decode1; end if; when Drive2 => -- Is key in column 2 if count_value = "1111" then state <= Detect2; end if; when Detect2 => if sense = '1' then state <= Drive3; elsif sense = '0' then state <= Decode2; end if; when Drive3 => -- Is key in column 3 if count_value = "1111" then state <= Detect3; end if; when Detect3 => if sense = '1' then state <= Drive4; elsif sense = '0' then state <= Decode3; end if; when Drive4 => -- Is key in column 4 if count_value = "1111" then state <= Detect4; end if; when Detect4 => if sense = '1' then state <= Drive1; elsif sense = '0' then state <= Decode4; end if; when Decode1 => -- Determine which key in column 1 is pressed if row(0) = '0' then state <= Latch0; elsif row(1) = '0' then state <= Latch4; elsif row(2) = '0' then state <= Latch8; else state <= Latch12; end if; when Decode2 => -- Determine which key in column 2 is pressed if row(0) = '0' then state <= Latch1; elsif row(1) = '0' then state <= Latch5; elsif row(2) = '0' then state <= Latch9; else state <= Latch13; end if; when Decode3 => -- Determine which key in column 3 is pressed if row(0) = '0' then state <= Latch2; elsif row(1) = '0' then state <= Latch6; elsif row(2) = '0' then state <= Latch10; else state <= Latch14; end if; when Decode4 => -- Determine which key in column 4 is pressed if row(0) = '0' then state <= Latch3; elsif row(1) = '0' then state <= Latch7; elsif row(2) = '0' then state <= Latch11; else state <= Latch15; end if; -- states to enable the output register to load the detected key on the -- next rising edge of the clock when Latch0 => state <= Capture0; when Latch1 => state <= Capture1; when Latch2 => state <= Capture2; when Latch3 => state <= Capture3; when Latch4 => state <= Capture4; when Latch5 => state <= Capture5; when Latch6 => state <= Capture6; when Latch7 => state <= Capture7; when Latch8 => state <= Capture8; when Latch9 => state <= Capture9; when Latch10 => state <= Capture10; when Latch11 => state <= Capture11; when Latch12 => state <= Capture12; when Latch13 => state <= Capture13; when Latch14 => state <= Capture14; when Latch15 => state <= Capture15; -- states when the detected key value is loaded into output register when Capture0 => state <= KeyReleaseAssert; when Capture1 => state <= KeyReleaseAssert; when Capture2 => state <= KeyReleaseAssert; when Capture3 => state <= KeyReleaseAssert; when Capture4 => state <= KeyReleaseAssert; when Capture5 => state <= KeyReleaseAssert; when Capture6 => state <= KeyReleaseAssert; when Capture7 => state <= KeyReleaseAssert; when Capture8 => state <= KeyReleaseAssert; when Capture9 => state <= KeyReleaseAssert; when Capture10 => state <= KeyReleaseAssert; when Capture11 => state <= KeyReleaseAssert; when Capture12 => state <= KeyReleaseAssert; when Capture13 => state <= KeyReleaseAssert; when Capture14 => state <= KeyReleaseAssert; when Capture15 => state <= KeyReleaseAssert; -- Wait for user to release the depressed key when KeyReleaseAssert => if count_value = "1111" then state <= KeyReleaseDetect; end if; when KeyReleaseDetect => if sense = '1' then state <= Start_State; elsif sense = '0' then state <= KeyReleaseAssert; end if; END CASE; END IF; END PROCESS; -- enable the counter reset in the state before the counter is to be used WITH state SELECT count_resetn <= '0' WHEN Start_State, '0' WHEN KeyDetect, '0' WHEN PrepareDrive, '0' when Detect1, '0' when Detect2, '0' when Detect3, '0' when Detect4, '0' when Capture0, '0' when Capture1, '0' when Capture2, '0' when Capture3, '0' when Capture4, '0' when Capture5, '0' when Capture6, '0' when Capture7, '0' when Capture8, '0' when Capture9, '0' when Capture10, '0' when Capture11, '0' when Capture12, '0' when Capture13, '0' when Capture14, '0' when Capture15, '0' when KeyReleaseDetect, '1' when others; -- assert the register load signal in the state before the keyvalue is to be -- latched into the output register with state select register_load <= '1' when latch0, '1' when latch1, '1' when latch2, '1' when latch3, '1' when latch4, '1' when latch5, '1' when latch6, '1' when latch7, '1' when latch8, '1' when latch9, '1' when latch10, '1' when latch11, '1' when latch12, '1' when latch13, '1' when latch14, '1' when latch15, '1' when capture0, '1' when capture1, '1' when capture2, '1' when capture3, '1' when capture4, '1' when capture5, '1' when capture6, '1' when capture7, '1' when capture8, '1' when capture9, '1' when capture10, '1' when capture11, '1' when capture12, '1' when capture13, '1' when capture14, '1' when capture15, '0' when others; -- outputs to determine which columns to drive during keyscanning phase with state select col <= "0111" when Drive1, "0111" when Detect1, "0111" when Decode1, "1011" when Drive2, "1011" when Detect2, "1011" when Decode2, "1101" when Drive3, "1101" when Detect3, "1101" when Decode3, "1110" when Drive4, "1110" when Detect4, "1110" when Decode4, "0000" when others; -- including DriveAll and KeyReleaseAssert -- the value of the detected key in binary with state select keyvalue <= "0000" when Latch0, "0000" when Capture0, "0001" when Latch1, "0001" when Capture1, "0010" when Latch2, "0010" when Capture2, "0011" when Latch3, "0011" when Capture3, "0100" when Latch4, "0100" when Capture4, "0101" when Latch5, "0101" when Capture5, "0110" when Latch6, "0110" when Capture6, "0111" when Latch7, "0111" when Capture7, "1000" when Latch8, "1000" when Capture8, "1001" when Latch9, "1001" when Capture9, "1010" when Latch10, "1010" when Capture10, "1011" when Latch11, "1011" when Capture11, "1100" when Latch12, "1100" when Capture12, "1101" when Latch13, "1101" when Capture13, "1110" when Latch14, "1110" when Capture14, "1111" when Latch15, "1111" when Capture15, "0000" when others; -- assert the keyvalid flag when a valid key is detected with state select keyvalid <= '1' when Capture0, '1' when Capture1, '1' when Capture2, '1' when Capture3, '1' when Capture4, '1' when Capture5, '1' when Capture6, '1' when Capture7, '1' when Capture8, '1' when Capture9, '1' when Capture10, '1' when Capture11, '1' when Capture12, '1' when Capture13, '1' when Capture14, '1' when Capture15, '0' when others; END mixed;