ps/2 keyboard interface VHDL

user2209486 picture user2209486 · Mar 25, 2013 · Viewed 8.5k times · Source

Alright so I'm trying to implement a keyboard controller for use with an altera DE2 FPGA board, and am having some issues. I have ran this code in the quartus simulator and everything seems to be doing what I think it should be doing. However, when I try to program it onto the FPGA, nothing works. I have targeted it down to the way I'm simulating the ps/2 clock and the system clock doesn't appear to be how they are actually running.

I simulated the system clock at 50 mhz, 20ns period, and the ps2clock with a 90ns period. When setting the ps2data, to random values throughout the simulation, the correct bits are loaded into the 8 bit scan code. The problem is that when programmed to the board, the state machine never leaves the idle state. The state machine should leave the idle state on the falling edge of the ps2 clock when the data bit is zero, which seems to never happen. I have the ps2data and ps2clock pins connected to the correct inputs, but can't seem to figure out the problem.

I didn't add the top level entity that tests this, but it simply takes the output keyCode and sends it to one of the 7seg displays. I feel like the answer to this has something to do with the ps2clock, im just not sure what exactly.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity keyboard is
    Port ( Clk          :   in std_logic; --system clock
           ps2Clk       :   in std_logic; --keyboard clock
           ps2Data      :   in std_logic; --keyboard data
           reset        :   in std_logic; --system reset
           keyReady     :   out std_logic;
           DoRead       :   in std_logic; -- when to read
           keyCode      :   out std_logic_vector(7 downto 0);
           pFalling     :   out std_logic; --debugging
           pFixedClk    :   out std_logic_vector(1 downto 0); --debugging
           divClock_out : out std_logic; --debugging
           clockCount_out : out std_logic_vector(9 downto 0); --debugging
           testDiv_out     : out std_logic;
           bitCount_out : out std_logic_vector(3 downto 0);
           shiftIn_out  : out std_logic_vector(8 downto 0)); --debugging
end keyboard;

architecture Behavioral of keyboard is

component div_counter is
    Port(clk, reset : in std_logic;
                Q   : out std_logic_vector(9 downto 0));
end component div_counter;

signal shiftIn              : std_logic_vector(8 downto 0); -- shifted in data
signal ps2fixedClock        : std_logic_vector(1 downto 0); -- 2 bit shift register
signal divClock             : std_logic ; -- main clock/512 
signal clockCount           : std_logic_vector(9 downto 0); -- debugging
signal ps2falling           : std_logic ;   
signal bitCount             : std_logic_vector(3 downto 0); 
signal keyReady_sig         : std_logic;

type state_type is (idle, shift, ready);
signal state : state_type;  
begin

keyReady <= keyReady_sig;

-------------------------------
--- counter to divide the main clock by 512
-------------------------------
counter : div_counter
    Port map(clk    => Clk,
            reset   => reset,
                Q   => clockCount);

clockCount_out <= clockCount;               
divided_clock : process (clockCount)
begin
    if clockCount = "1000000001" then
        divClock <= '1';
    else
        divClock <= '0';
    end if; 
end process divided_clock;                  

testDiv_out <= divClock;
------------------------------------
------ 2 bit shift register to sync clocks
------------------------------------
ps2fixed_Clock : process (reset, divClock)
begin
    if reset = '1' then
        ps2fixedClock <= "00";  
    elsif (divClock'event and divClock = '1') then  
        ps2fixedClock(0) <= ps2fixedClock(1);
        ps2fixedClock(1) <= ps2Clk;
    end if;
end process ps2fixed_Clock;

pFixedClk <= ps2fixedClock;
-----------------------------------
-------- edge detector 
-----------------------------------
process (ps2fixedClock)
begin
    if ps2fixedClock = "01" then
        ps2falling <= '1';
        else
        ps2falling <= '0';
    end if; 
end process;

pFalling <= ps2falling;
bitCount_out <= bitCount;

--------------------------------
------- state machine
--------------------------------
state_machine : process (divClock, reset)
begin
    if (reset = '1') then
        state <= idle;
        bitCount <= "0000";
        shiftIn <= (others => '0');
        keyCode <= (others => '0');
        keyReady_sig <= '0';
    elsif (divClock'event AND divClock = '1') then

        if DoRead='1' then
            keyReady_sig <= '0';
        end if; 

        case state is
        when idle =>
            bitCount <= "0100";
            if ps2falling = '1' and ps2Data = '0' then
                state <= shift;
            end if;         
        when shift =>
                if bitCount >= 9 then
                    if ps2falling = '1' then -- stop bit
                        keyReady_sig <= '1';
                        keyCode <= shiftIn(7 downto 0);
                        state <= idle;
                    end if;
                elsif ps2falling='1' then
                    bitCount <= bitCount + 1;
                    shiftIn(7 downto 0) <= shiftIn(8 downto 1);
                    shiftIn(8) <= ps2Data;  
                end if; 
        when others =>
            state <= idle;
    end case;
    end if;
end process;    

shiftIn_out <= shiftIn;
end Behavioral;

Answer

user2209486 picture user2209486 · Aug 30, 2016

Coming back to answer this a bit later....

It turns out the reason why this wasn't working was because I was using a usb -> ps2 adapter and not an original ps2 connector keyboard.