-------------------------------------------------------------------------------- -- EETAC - CSD - P6 - http://digsys.upc.edu -------------------------------------------------------------------------------- -- Demonstration of a FSM for commanding a 16-key keypad scanner and decoder -- A Synchronous Moore FSM -- This FSM VHDL schematic code is adapted from tutorials listed in P6 -------------------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; -- Only for ispLEVER and SYNPLIFY: if attributes must be placed --LIBRARY Synplify; --USE Synplify.attributes.ALL; ENTITY matrix_encoder_16key IS PORT( --> Inputs to the state register CLK, CD : IN std_logic; --> Inputs to the CS1 Columns : IN std_logic_vector (3 downto 0); --> Outputs from the CS2 Data : OUT std_logic_vector (3 downto 0); GS : OUT std_logic; Rows : OUT std_logic_vector (3 downto 0) ); END matrix_encoder_16key; ARCHITECTURE FSM_structure_design OF matrix_encoder_16key IS -- state signals declaration TYPE State_type IS (RowA, RowA_Colum_dec, RowB, RowB_Colum_dec, RowC, RowC_Colum_dec, RowD, RowD_Colum_dec); SIGNAL current_state, next_state : State_type ; SIGNAL Row_scan_E : std_logic; -- If you want to choose the FSM state's coding style: "sequential", "gray", -- "onehot", etc. Only for ispLEVER and SYNPLIFY uncomment : --ATTRIBUTE syn_encoding OF current_state : signal is "sequential"; BEGIN ----------------------------------------------------------- -- State register, normally simple D-type flip-flops ----------------------------------------------------------- state_register: PROCESS (CD,CLK, next_state) BEGIN IF (CD = '1') THEN -- reset asynchronous current_state <= RowA; ELSIF (CLK'EVENT and CLK = '1') THEN -- Synchronous register D-type flip-flop current_state <= next_state; END IF; END PROCESS state_register; ------------------------------------------------------------ -- CS1: combinational logic for determining the future state -- Using a process, state variables and the "case" sentence ------------------------------------------------------------ CS1: PROCESS (current_state,Row_scan_E) BEGIN CASE current_state IS WHEN RowA => IF (Row_scan_E = '1') THEN next_state <= RowB; -- next row scan ELSE next_state <= RowA_Colum_dec; -- a key has been pressed END IF ; WHEN RowB => IF (Row_scan_E = '1') THEN next_state <= RowC; -- next row scan ELSE next_state <= RowB_Colum_dec; -- a key has been pressed END IF ; WHEN RowC => IF (Row_scan_E = '1') THEN next_state <= RowD; -- next row scan ELSE next_state <= RowC_Colum_dec; -- a key has been pressed -- and must be decoded END IF ; WHEN RowD => IF (Row_scan_E = '1') THEN next_state <= RowA; -- next row scan, an infinite loop ELSE next_state <= RowD_Colum_dec; -- a key has been pressed END IF ; -- states for decoding columns WHEN RowA_Colum_dec => IF (Row_scan_E = '0') THEN next_state <= RowA_Colum_dec; -- looped here while -- pressing the key ELSE next_state <= RowB; -- next row scan because -- the key is released END IF ; WHEN RowB_Colum_dec => IF (Row_scan_E = '0') THEN next_state <= RowB_Colum_dec; -- pressing the key ELSE next_state <= RowC; -- if the key is released, continue END IF ; WHEN RowC_Colum_dec => IF (Row_scan_E = '0') THEN next_state <= RowC_Colum_dec; ELSE next_state <= RowD; END IF ; WHEN RowD_Colum_dec => IF (Row_scan_E = '0') THEN next_state <= RowD_Colum_dec; ELSE next_state <= RowA; END IF ; END CASE; END PROCESS CS1; --------------------------------------------------------------- -- CS2: combinational logic to determine the outputs --------------------------------------------------------------- -- Here the most important issue is to generate all the 9 outputs in every -- state, which means to define correctly the truth table, because if not, -- the synthesiser is going to add infered latches making the system unreliable. -- So, check the number of registers used to see that you have no extra memory -- added. CS2: PROCESS (current_state, Columns) BEGIN CASE current_state IS WHEN RowA => -- 9 outputs --> Ok Rows <= "0111"; Data <= "0000"; -- No code when keys aren't pressed GS <= '0'; WHEN RowA_Colum_dec => Rows <= "0111"; -- While a given key is pressed, group select (GS) -- must be active: GS <= '1'; -- The HEX code for the Data(3..0): if (Columns = "0111") then Data <= "0001"; -- key 1 elsif (Columns = "1011") then Data <= "0010"; -- key 2 elsif (Columns = "1101") then Data <= "0011"; -- key 3 elsif (Columns = "1110") then Data <= "1010"; -- key A else Data <= "0000"; -- unpredicted situations end if; -- 9 outputs --> Ok WHEN RowB => Rows <= "1011"; GS <= '0'; Data <= "0000"; WHEN RowB_Colum_dec => Rows <= "1011"; GS <= '1'; -- The HEX code: if (Columns = "0111") then Data <= "0100"; -- key 4 elsif (Columns = "1011") then Data <= "0101"; -- key 5 elsif (Columns = "1101") then Data <= "0110"; -- key 6 elsif (Columns = "1110") then Data <= "1011"; -- key B else Data <= "0000"; -- unpredicted situations end if; WHEN RowC => Rows <= "1101"; Data <= "0000"; GS <= '0'; WHEN RowC_Colum_dec => Rows <= "1101"; GS <= '1'; -- The HEX code: if (Columns = "0111") then Data <= "0111"; -- key 7 elsif (Columns = "1011") then Data <= "1000"; -- key 8 elsif (Columns = "1101") then Data <= "1001"; -- key 9 elsif (Columns = "1110") then Data <= "1100"; -- key C else Data <= "0000"; -- unpredicted situations end if; WHEN RowD => Rows <= "1110"; Data <= "0000"; GS <= '0'; WHEN RowD_Colum_dec => Rows <= "1110"; GS <= '1'; -- The HEX code: if (Columns = "0111") then Data <= "1111"; -- key F elsif (Columns = "1011") then Data <= "0000"; -- key 0 elsif (Columns = "1101") then Data <= "1110"; -- key E elsif (Columns = "1110") then Data <= "1101"; -- key D else Data <= "0000"; -- unpredicted situations end if; END CASE; END PROCESS CS2; -- Extra logic if necessary ---------------------------------------------------- -- Generating a very convenient signal: Row_Scanning_Enable (Row_scan_E) -- If no key is pressed, Row_scan_E = '1', meaning that the FSM can scan -- consecutively all the rows Row_scan_E <= '1' WHEN Columns = "1111" ELSE '0'; -- Row_scan_E <= Columns(3) AND Columns(2) AND Columns(1) AND Columns(0); END FSM_structure_design ;