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), вы можете сгенерировать сигнал включения (как вы это сделали) и использовать его после синхронизации часов, например, в конечном автомате!