PS /2 клавиатуры интерфейса VHDL

Хорошо, поэтому я пытаюсь реализовать контроллер клавиатуры для использования с платой Altera DE2 FPGA, и у меня возникли некоторые проблемы. Я запустил этот код в симуляторе квартуса, и все, кажется, делает то, что, я думаю, должно быть. Однако, когда я пытаюсь запрограммировать его на FPGA, ничего не получается. Я нацелил его на то, как я имитирую часы ps/2, а системные часы, похоже, не соответствуют тому, как они на самом деле работают.

Я смоделировал системные часы на частоте 50 МГц, период 20 нс и ps2clock с периодом 90 нс. При установке ps2data в случайные значения на протяжении всего моделирования правильные биты загружаются в 8-битный код сканирования. Проблема в том, что при программировании на плату конечный автомат никогда не покидает состояние простоя. Конечный автомат должен оставить незанятое состояние на заднем фронте тактовой частоты ps2, когда бит данных равен нулю, что, по-видимому, никогда не происходит. У меня есть контакты ps2data и ps2clock, подключенные к правильным входам, но я не могу решить проблему.

Я не добавил объект верхнего уровня, который проверяет это, но он просто берет выходной код ключа и отправляет его на один из дисплеев 7seg. Я чувствую, что ответ на этот вопрос как-то связан с ps2clock, я просто не уверен, что именно.

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;

2 ответа

Возвращаясь, чтобы ответить на это чуть позже....

Оказывается, причина, по которой это не сработало, заключалась в том, что я использовал адаптер usb -> ps2, а не оригинальную клавиатуру для разъема ps2.

Вы пытаетесь синхронизировать ps2clock с вашим divClock. однако divClock - это сигнал включения, а не часы. он активен не очень часто.

Я предлагаю вам использовать clk в процессе ps2fixed_Clock

ps2fixed_Clock : process (reset, clk)
begin
    if reset = '1' then
        ps2fixedClock <= "00";  
    elsif (rising_edge(clk)) then  
        ps2fixedClock(0) <= ps2fixedClock(1);
        ps2fixedClock(1) <= ps2Clk;
    end if;
end process ps2fixed_Clock;

также вы должны использовать clk в вашем состоянии state_machine

state_machine : process (clk, reset)
begin
    if (reset = '1') then
        ...
    elsif (rising_edge(clk)) then
        ...

если вы хотите использовать делитель часов (процесс split_clock), вы можете сгенерировать сигнал включения (как вы это сделали) и использовать его после синхронизации часов, например, в конечном автомате!

Другие вопросы по тегам