-- -- -- -- keypad.vhd implements Keypad controller.The keypad works with drive -- and sense lines. -- Each of the four sense lines is pulled up with a 10kohm resister. -- The drive lines drive "011"->"101"->"110" and once a sense of '0' is -- seen on any of the sense_line then we know that a key has been pressed. -- Debouncing occurs right after a key is pressed or released. Each -- time the sense line inputs change because of a keypress or keyrelease, -- we wait 1 ms before sampling the drive_line and sense_line values. -- Hopefully, any oscillations would have died out during this time. A -- counter is used to count from 0 up to delay each time the clock -- signal goes high, since 1 ms delay is required, the maximum counter -- value depends on the clock frequency.en the -- Then the kaypad logic waits for the key to be released and for a -- signal to continue normal operation. LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; LIBRARY lpm; USE lpm.lpm_components.ALL; ENTITY keypad IS ----------------------------------------------- GENERIC(senseline_width : positive:=3; -- Width of sense line driveline_width : positive:=3; -- Width of drive line code_length : positive:=4; -- Width of code generated. output_length : positive:=10; debouncing_delay: positive:=30); -- Maximum counter value to generate ------------------------------------------------- -- required delay of debouncing. PORT( clock,reset : IN STD_LOGIC; sense_line : IN STD_LOGIC_VECTOR(senseline_width-1 DOWNTO 0); key_ack : IN STD_LOGIC; key_valid : BUFFER STD_LOGIC; drive_line : OUT STD_LOGIC_VECTOR(driveline_width-1 DOWNTO 0); key_code : BUFFER STD_LOGIC_VECTOR(code_length-1 DOWNTO 0); s_speed : BUFFER STD_LOGIC_VECTOR(output_length-1 DOWNTO 0) ); END keypad; ARCHITECTURE behaviour OF keypad IS TYPE state_type IS(start,first_row,second_row,third_row,deb_row1, deb_row2,deb_row3,key1,key2,key3,key4,key5,key6,key7,key8,key9,key_release); TYPE state_type2 IS (r_state,s_state,add_state,sub_state,wait_state); --******************************************************* --Signal Used --******************************************************** SIGNAL p_state : state_type; SIGNAL state : state_type2; SIGNAL c_enable : STD_LOGIC; SIGNAL c_reset : STD_LOGIC; SIGNAL c_done : STD_LOGIC; SIGNAL ld_reg : STD_LOGIC; SIGNAL sclr : STD_LOGIC; SIGNAL s_sclr : STD_LOGIC; SIGNAL s_ldreg : STD_LOGIC; SIGNAL operation : STD_LOGIC; SIGNAL in_release : STD_LOGIC; SIGNAL count : STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL int_code : STD_LOGIC_VECTOR(code_length-1 DOWNTO 0); SIGNAL addertoff : STD_LOGIC_VECTOR(output_length-1 DOWNTO 0); SIGNAL inc_ten : STD_lOGIC_VECTOR(output_length-1 DOWNTO 0):= "0000001010"; --********************************************************** CONSTANT UPPER_LIMIT :STD_LOGIC_VECTOR(output_length-1 DOWNTO 0):= "1111100111"; CONSTANT LOWER_LIMIT :STD_LOGIC_VECTOR(output_length-1 DOWNTO 0):= "0000000000"; -- Counter used for produncing delay before key is sampled. This delay is required to wait for -- bouncingto die. -------------------------------------------------------------------------------------------------- COMPONENT counter generic( counter_limit:positive:= 8 ); port ( reset, Clock : in std_logic; enable : In std_logic; Q : buffer std_logic_vector(7 DOWNTO 0); done : OUT STD_lOGIC ) ; END COMPONENT; --------------------------------------------------------------------------------------------------- COMPONENT bit4reg -------------------------------------------- GENERIC(shiftreg_width:positive:=8); -------------------------------------------- PORT( clock,clear : IN STD_LOGIC; load : IN STD_LOGIC; D : IN STD_LOGIC_VECTOR(shiftreg_width-1 DOWNTO 0); Q : BUFFER STD_LOGIC_VECTOR(shiftreg_width-1 DOWNTO 0) ); END COMPONENT; ------------------------------------------------------------------------------------------------------- COMPONENT adder IS ------------------------------------------ GENERIC( adder_width : integer:= 10); ------------------------------------------ PORT( a : IN STD_LOGIC_VECTOR(adder_width-1 DOWNTO 0); b : IN STD_LOGIC_VECTOR(adder_width-1 DOWNTO 0); opt : IN STD_LOGIC; result : OUT STD_LOGIC_VECTOR(adder_width-1 DOWNTO 0 ) ); END COMPONENT; ------------------------------------------------------------------------------------------------------ BEGIN inc_ten <= "0000001010"; ------------------------------------------------------------------------------------------------------ -- Counter used for produncing delay before key is sampled. This delay is required to wait for bouncing -- to die. count_deb:counter ----------------------------------------------- generic map( counter_limit => debouncing_delay) ----------------------------------------------- port map( reset => c_reset, Clock => clock, enable => c_enable, Q => open, done => c_done ) ; ----------------------------------------------------------------------------------------------------- -- A register used to hold code of the key pressed. It is cleared when key acknowledge is recieved. valid_reg:bit4reg ---------------------------------------------- GENERIC MAP(shiftreg_width => code_length) ---------------------------------------------- PORT MAP( clock => clock, clear => sclr, load => ld_reg, D => int_code, Q => key_code ); ------------------------------------------------------------------------------------------------------ -- Main FSM to accomlish keypad controller. scanner: PROCESS (clock,p_state,sense_line) IS BEGIN IF ( reset = '1' ) THEN p_state <= start; ELSIF rising_edge(clock) THEN CASE p_state IS WHEN start => -- All register and conter is intialized and clear. p_state <= first_row; WHEN first_row => -- Scan first row of key_pad by driving "011" on drine_line. IF (sense_line="011"OR sense_line= "101" OR sense_line ="110") THEN p_state <= deb_row1; ELSIF (sense_line = "111") THEN p_state <= second_row; ELSE p_state <= start; END IF; WHEN second_row => -- Scan second row of key_pad by driving "011" on drine_line. IF (sense_line="011"OR sense_line= "101" OR sense_line ="110") THEN p_state <= deb_row2; ELSIF (sense_line = "111") THEN p_state <= third_row; ELSE p_state <= start; END IF; WHEN third_row => -- Scan third row of key_pad by driving "011" on drine_line. IF (sense_line="011"OR sense_line= "101" OR sense_line ="110") THEN p_state <= deb_row3; ELSIF (sense_line = "111") THEN p_state <= first_row; ELSE p_state <= start; END IF; WHEN deb_row1 => -- Key is detected on the first row of the keypad.Stay in this -- state until any oscillations would have died out. IF ( c_done = '1' ) THEN If (sense_line="011") THEN p_state <= key1; ELSIF (sense_line="101") THEN p_state <= key4; ELSIF (sense_line <="110" ) THEN p_state <= key7; ELSE p_state <= start; END IF; ELSE p_state <= deb_row1; END IF; WHEN deb_row2 => -- Key is detected on the second row of the keypad.Stay in this -- state until any oscillations would have died out. IF ( c_done = '1' ) THEN If (sense_line="011") THEN p_state <= key2; ELSIF (sense_line="101") THEN p_state <= key5; ELSIF (sense_line <="110" ) THEN p_state <= key8; ELSE p_state <= start; END IF; ELSE p_state <= deb_row2; END IF; WHEN deb_row3 => -- Key is detected on the third row of the keypad.Stay in this -- state until any oscillations die out. IF (c_done = '1' ) THEN If (sense_line="011") THEN p_state <= key3; ELSIF (sense_line="101") THEN p_state <= key6; ELSIF (sense_line <="110" ) THEN p_state <= key9; ELSE p_state <= start; END IF; ELSE p_state <= deb_row3; END IF; WHEN key1 => -- Key 1 has been detected after oscillations died out. -- Generate code for key 1. IF sense_line = "111" THEN p_state <= key_release; ELSE p_state <= key1 ; END IF; WHEN key4=> -- Key 4 has been detected after oscillations died out. -- Generate code for key 4. IF sense_line = "111" THEN p_state <= key_release; ELSE p_state <= key4; END IF; WHEN key7=> -- Key 7 has been detected after oscillations died out. -- Generate code for key 7. IF sense_line = "111" THEN p_state <= key_release; ELSE p_state <= key7; END IF; WHEN key2=> -- Key 2 has been detected after oscillations died out. -- Generate code for key 2. IF (sense_line = "111") THEN p_state <= key_release; ELSE p_state <= key2; END IF; WHEN key5=> -- Key 5 has been detected after oscillations died out. -- Generate code for key 5. IF (sense_line = "111" ) THEN p_state <= key_release; ELSE p_state <= key5; END IF; WHEN key8=> -- Key 8 has been detected after oscillations died out. -- Generate code for key 8. IF (sense_line = "111" ) THEN p_state <= key_release; ELSE p_state <= key8; END IF; WHEN key3=> -- Key 3 has been detected after oscillations died out. -- Generate code for key 3. IF sense_line = "111" THEN p_state <= key_release; ELSE p_state <= key3; END IF; WHEN key6=> -- Key 6 has been detected after oscillations died out. -- Generate code for key 6. IF sense_line = "101" THEN p_state <= key_release; ELSE p_state <= key6; END IF; WHEN key9=> -- Key 9 has been detected after oscillations died out. -- Generate code for key 9. IF (sense_line = "111" ) THEN p_state <= key_release; ELSE p_state <= key9; END IF; WHEN key_release => -- Key has beec releaded.stay in state until any oscillations -- die out. IF (c_done = '1' ) THEN IF key_ack = '1' THEN p_state <= start; ELSE p_state <= key_release; END IF; ELSE p_state <= key_release; END IF; END case; END IF; END PROCESS scanner; ------------------------------------------------------------------------------------------------------ WITH p_state SELECT drive_line <= "111" WHEN start | key_release, "011" WHEN first_row | deb_row1 | key1 | key4 | key7, "101" WHEN second_row | deb_row2 | key2 | key5 | key8, "110" WHEN third_row | deb_row3 | key3 | key6 | key9; ------------------------------------------------------------------------------------------------------ coding: WITH p_state SELECT int_code <= "0001" WHEN key1, "0010" WHEN key2, "0011" WHEN key3, "0100" WHEN key4, "0101" WHEN key5, "0110" WHEN key6, "0111" WHEN key7, "1000" WHEN key8, "1001" WHEN key9, "0000" WHEN OTHERS; ------------------------------------------------------------------------------------------------------ validating: WITH p_state SELECT key_valid <= '1' WHEN key1 | key2 | key3 | key4 | key5 | key6 | key7 | key8 | key9 | key_release, '0' WHEN OTHERS; ------------------------------------------------------------------------------------------------------- WITH p_state SELECT c_reset <= '1' WHEN start | key1 | key2 | key3 | key4 | key5 | key6 | key7 | key8 | key9, '0' WHEN OTHERS; ------------------------------------------------------------------------------------------------------- WITH p_state SELECT c_enable <= '1' WHEN deb_row1 | deb_row2 | deb_row3 | key_release, '0' WHEN OTHERS; ------------------------------------------------------------------------------------------------------- WITH p_state SELECT ld_reg <= '1' WHEN key1 | key2 | key3 | key4 | key5 | key6 | key7 | key8 | key9, '0' WHEN OTHERS; ------------------------------------------------------------------------------------------------------- WITH p_state SELECT sclr <= '1' WHEN start, '0' WHEN OTHERS; ----------------------------------------------------------------------------------------------------------- k_reg:bit4reg GENERIC MAP(shiftreg_width => output_length) PORT MAP( clock => clock ,clear => s_sclr, load => s_ldreg, D => s_speed, Q => addertoff ); ----------------------------------------------------------------------------------------------------------- k_adder: lpm_add_sub GENERIC MAP(LPM_WIDTH => output_length, LPM_REPRESENTATION => "UNSIGNED" ) PORT MAP(dataa =>addertoff, datab => inc_ten, add_sub => operation, result => s_speed ); ---------------------------------------------------------------------------------------------------------- inc_dec: PROCESS (clock,reset,int_code) BEGIN IF ( reset = '1' ) THEN state <= s_state; ELSIF rising_edge(clock) THEN CASE state IS WHEN r_state => state <= s_state; WHEN s_state => if ( key_code = "0001" ) and (s_speed /= UPPER_LIMIT)THEN state <= add_state; elsif ( key_code = "0010" ) and (s_speed /= LOWER_LIMIT) THEN state <= sub_state; else state <= s_state; end if; WHEN add_state=> state <= wait_state; WHEN sub_state => state <= wait_state; WHEN wait_state=> if ( key_valid = '1' ) THEN state <= wait_state; else state <= s_state; end if; END CASE; END IF; END PROCESS inc_dec; ----------------------------------------------------------------------------------------------------------- WITH state SELECT s_sclr <= '1' WHEN r_state, '0' WHEN OTHERS; ----------------------------------------------------------------------------------------------------------- WITH state SELECT operation <= '0' WHEN sub_state, '1' WHEN OTHERS; ----------------------------------------------------------------------------------------------------------- WITH state SELECT s_ldreg <= '1' WHEN add_state | sub_state, '0' WHEN OTHERS; ----------------------------------------------------------------------------------------------------------- END behaviour;