VHDL Code for PS2 Keyboard Interface: Syntax and Example
A PS2 keyboard interface in
VHDL reads serial data from the keyboard clock and data lines using a state machine to capture bits on falling clock edges. The interface decodes the 11-bit PS2 frame (start, data, parity, stop) and outputs the received scan code for further processing.Syntax
The PS2 keyboard interface in VHDL typically uses a process triggered on the falling edge of the PS2 clock line. It reads the PS2 data line bit by bit, assembling an 11-bit frame that includes a start bit, 8 data bits, a parity bit, and a stop bit. A state machine or counter tracks the bit position to know when a full byte is received.
- ps2_clk: Input clock from the keyboard, triggers data sampling.
- ps2_data: Input data line from the keyboard.
- bit_count: Counts bits received (0 to 10).
- shift_reg: Stores bits as they arrive.
- scan_code: Output byte after full frame received.
vhdl
process(ps2_clk, reset_n) begin if reset_n = '0' then bit_count <= 0; shift_reg <= (others => '0'); scan_code <= (others => '0'); elsif falling_edge(ps2_clk) then if bit_count < 11 then shift_reg(bit_count) <= ps2_data; bit_count <= bit_count + 1; else bit_count <= 0; scan_code <= shift_reg(8 downto 1); -- data bits end if; end if; end process;
Example
This example shows a complete VHDL module that interfaces with a PS2 keyboard. It captures the scan code sent by the keyboard and outputs it on scan_code. The process triggers on the falling edge of ps2_clk and uses a counter to track bits. After receiving 11 bits, it extracts the 8 data bits as the scan code.
vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ps2_keyboard is
port(
clk : in std_logic;
reset_n : in std_logic;
ps2_clk : in std_logic;
ps2_data : in std_logic;
scan_code : out std_logic_vector(7 downto 0);
data_ready: out std_logic
);
end entity;
architecture rtl of ps2_keyboard is
signal bit_count : integer range 0 to 11 := 0;
signal shift_reg : std_logic_vector(10 downto 0) := (others => '0');
signal ps2_clk_sync, ps2_clk_prev : std_logic := '1';
begin
process(clk, reset_n)
begin
if reset_n = '0' then
bit_count <= 0;
shift_reg <= (others => '0');
scan_code <= (others => '0');
data_ready <= '0';
ps2_clk_sync <= '1';
ps2_clk_prev <= '1';
elsif rising_edge(clk) then
-- Synchronize ps2_clk to system clock
ps2_clk_sync <= ps2_clk;
ps2_clk_prev <= ps2_clk_sync;
-- Detect falling edge of ps2_clk
if ps2_clk_prev = '1' and ps2_clk_sync = '0' then
if bit_count < 11 then
shift_reg(bit_count) <= ps2_data;
bit_count <= bit_count + 1;
data_ready <= '0';
else
bit_count <= 0;
scan_code <= shift_reg(8 downto 1); -- data bits
data_ready <= '1';
end if;
else
data_ready <= '0';
end if;
end if;
end process;
end architecture;Output
Outputs 8-bit scan_code when a full PS2 frame is received; data_ready pulses high for one clk cycle.
Common Pitfalls
- Not synchronizing the PS2 clock input: The PS2 clock is asynchronous to your system clock, so failing to synchronize it can cause metastability and incorrect data capture.
- Missing falling edge detection: PS2 data bits are valid on the falling edge of the PS2 clock, so sampling on the wrong edge leads to wrong data.
- Ignoring start, parity, and stop bits: The PS2 frame includes these bits; ignoring them can cause errors or misalignment.
- Not resetting counters properly: Without proper reset, the bit counter may get stuck or miscount bits.
vhdl
Wrong approach (sampling on rising edge): process(ps2_clk) begin if rising_edge(ps2_clk) then shift_reg(bit_count) <= ps2_data; -- Wrong edge bit_count <= bit_count + 1; end if; end process; Correct approach (sampling on falling edge with synchronization): -- See example code above for proper synchronization and falling edge detection.
Quick Reference
Remember these key points when writing a PS2 keyboard interface in VHDL:
- Synchronize
ps2_clkto your system clock to avoid metastability. - Sample
ps2_dataon the falling edge ofps2_clk. - Use a counter to track 11 bits: 1 start, 8 data, 1 parity, 1 stop.
- Extract the 8 data bits as the scan code after full frame reception.
- Reset counters and registers properly on system reset.
Key Takeaways
Always synchronize the PS2 clock input to your system clock before sampling.
Sample PS2 data bits on the falling edge of the PS2 clock signal.
Use a bit counter to track the full 11-bit PS2 frame including start, data, parity, and stop bits.
Extract the 8 data bits as the scan code after receiving the full frame.
Reset your state machine and counters properly to avoid data corruption.