好吧,我正在尝试实现一个与 altera DE2 FPGA 板一起使用的键盘控制器,但遇到了一些问题。我已经在 quartus 模拟器中运行了这段代码,一切似乎都在做我认为应该做的事情。然而,当我尝试将其编程到 FPGA 上时,却没有任何效果。我已将其目标定为模拟 ps/2 时钟的方式,而系统时钟似乎与它们实际运行的方式不同。
我模拟了 50 mhz、20 ns 周期的系统时钟和 90 ns 周期的 ps2clock。当将 ps2data 设置为整个模拟过程中的随机值时,正确的位将加载到 8 位扫描代码中。问题是,当编程到板上时,状态机永远不会离开空闲状态。当数据位为零时,状态机应该在 ps2 时钟的下降沿离开空闲状态,但这似乎永远不会发生。我将 ps2data 和 ps2clock 引脚连接到正确的输入,但似乎无法找出问题所在。
我没有添加测试此功能的顶级实体,但它只是获取输出 keyCode 并将其发送到 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;
稍后回来回答这个问题......
事实证明这不起作用的原因是因为我使用的是 USB -> PS2 适配器而不是原始的 PS2 连接器键盘。
您尝试将 ps2clock 同步到您的 divClock。然而,divClock 是一个使能信号,而不是一个时钟。它不经常活跃。
我建议你在ps2fixed_Clock进程中使用clk
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;
你也应该在你的state_machine进程中使用clk
state_machine : process (clk, reset)
begin
if (reset = '1') then
...
elsif (rising_edge(clk)) then
...
如果您想使用时钟分频器(divided_clock 进程),您可以生成一个使能信号(就像您所做的那样)并在同步时钟后使用它,例如在状态机中!