📄 ps2inerface.vhd
字号:
(others => '0');
-- done signal for the couters above
-- when a counter reaches max value,the corresponding done signal is set
signal delay_100us_done, delay_20us_done, delay_63clk_done: std_logic;
-- enable signal for 100us delay counter
signal delay_100us_counter_enable: std_logic := '0';
-- enable signal for 20us delay counter
signal delay_20us_counter_enable : std_logic := '0';
-- enable signal for 63clk delay counter
signal delay_63clk_counter_enable: std_logic := '0';
-- synchronzed input for ps2_clk and ps2_data
signal ps2_clk_s,ps2_data_s: std_logic := '1';
-- control the output of ps2_clk and ps2_data
-- if 1 then corresponding signal (ps2_clk or ps2_data) is
-- put in high impedance ('Z').
signal ps2_clk_h,ps2_data_h: std_logic := '1';
-- states of the FSM for controlling the communcation with the device
-- states that begin with "rx_" are used when receiving data
-- states that begin with "tx_" are used when transmiting data
type fsm_state is
(
idle,rx_clk_h,rx_clk_l,rx_down_edge,rx_error_parity,rx_data_ready,
tx_force_clk_l,tx_bring_data_down,tx_release_clk,
tx_first_wait_down_edge,tx_clk_l,tx_wait_up_edge,tx_clk_h,
tx_wait_up_edge_before_ack,tx_wait_ack,tx_received_ack,
tx_error_no_ack
);
-- the signal that holds the current state of the FSM
-- implicitly state is idle.
signal state: fsm_state := idle;
-- register that holds the frame received or the one to be sent.
-- Its contents are shifted in from the bus one bit at a time
-- from left to right when receiving data and are shifted on the
-- bus (ps2_data) one bit at a time to the right when sending data
signal frame: std_logic_vector(10 downto 0) := (others => '0');
-- how many bits have been sent or received.
signal bit_count: std_logic_vector(3 downto 0) := (others => '0');
-- when active the bit counter is reset.
signal reset_bit_count: std_logic := '0';
-- when active the contents of the frame is shifted to the right
-- and the most significant bit of frame is loaded with ps2_data.
signal shift_frame: std_logic := '0';
-- parity of the byte that was received from the device.
-- must match the parity bit received, else error occurred.
signal rx_parity: std_logic := '0';
-- parity bit that is sent with the frame, representing the
-- odd parity of the byte currently being sent
signal tx_parity: std_logic := '0';
-- when active, frame is loaded with the start bit, data on
-- tx_data, parity bit (tx_parity) and stop bit
-- this frame will be sent to the device.
signal load_tx_data: std_logic := '0';
-- when active bits 8 downto 1 from frame are loaded into
-- rx_data register. This is the byte received from the device.
signal load_rx_data: std_logic := '0';
-- intermediary signals used to debounce the inputs ps2_clk and ps2_data
signal ps2_clk_clean,ps2_data_clean: std_logic := '1';
-- debounce counter for the ps2_clk input and the ps2_data input.
signal clk_count,data_count: std_logic_vector(3 downto 0);
-- last value on ps2_clk and ps2_data.
signal clk_inter,data_inter: std_logic := '1';
begin
---------------------------------------------------------------------
-- FLAGS and PS2 CLOCK AND DATA LINES
---------------------------------------------------------------------
-- clean ps2_clk signal (debounce)
-- note that this introduces a delay in ps2_clk of
-- DEBOUNCE_DELAY clocks
process(clk)
begin
if(rising_edge(clk)) then
-- if the current bit on ps2_clk is different
-- from the last value, then reset counter
-- and retain value
if(ps2_clk /= clk_inter) then
clk_inter <= ps2_clk;
clk_count <= (others => '0');
-- if counter reached upper limit, then
-- the signal is clean
elsif(clk_count = DEBOUNCE_DELAY) then
ps2_clk_clean <= clk_inter;
-- ps2_clk did not change, but counter did not
-- reach limit. Increment counter
else
clk_count <= clk_count + 1;
end if;
end if;
end process;
-- clean ps2_data signal (debounce)
-- note that this introduces a delay in ps2_data of
-- DEBOUNCE_DELAY clocks
process(clk)
begin
if(rising_edge(clk)) then
-- if the current bit on ps2_data is different
-- from the last value, then reset counter
-- and retain value
if(ps2_data /= data_inter) then
data_inter <= ps2_data;
data_count <= (others => '0');
-- if counter reached upper limit, then
-- the signal is clean
elsif(data_count = DEBOUNCE_DELAY) then
ps2_data_clean <= data_inter;
-- ps2_data did not change, but counter did not
-- reach limit. Increment counter
else
data_count <= data_count + 1;
end if;
end if;
end process;
-- Synchronize ps2 entries
ps2_clk_s <= ps2_clk_clean when rising_edge(clk);
ps2_data_s <= ps2_data_clean when rising_edge(clk);
-- Assign parity from frame bits 8 downto 1, this is the parity
-- that should be received inside the frame on PARITY_BIT position
rx_parity <= parityrom(conv_integer(frame(8 downto 1)))
when rising_edge(clk);
-- The parity for the data to be sent
tx_parity <= parityrom(conv_integer(tx_data)) when rising_edge(clk);
-- Force ps2_clk to '0' if ps2_clk_h = '0', else release the line
-- ('Z' = +5Vcc because of pull-ups)
ps2_clk <= 'Z' when ps2_clk_h = '1' else '0';
-- Force ps2_data to '0' if ps2_data_h = '0', else release the line
-- ('Z' = +5Vcc because of pull-ups)
ps2_data <= 'Z' when ps2_data_h = '1' else '0';
-- Control busy flag. Interface is not busy while in idle state.
busy <= '0' when state = idle else '1';
-- reset the bit counter when in idle state.
reset_bit_count <= '1' when state = idle else '0';
-- Control shifting of the frame
-- When receiving from device, data is read
-- on the falling edge of ps2_clk
-- When sending to device, data is read by device
-- on the rising edge of ps2_clk
shift_frame <= '1' when state = rx_down_edge or
state = tx_clk_l else
'0';
---------------------------------------------------------------------
-- FINITE STATE MACHINE
---------------------------------------------------------------------
-- For the current state establish next state
-- and give necessary commands
manage_fsm: process(clk,rst,state,ps2_clk_s,ps2_data_s,write,tx_data,
bit_count,rx_parity,frame,delay_100us_done,
delay_20us_done,delay_63clk_done)
begin
-- if reset occurs, go to idle state.
if(rst = '1') then
state <= idle;
elsif(rising_edge(clk)) then
-- default values for these signals
-- ensures signals are reset to default value
-- when coditions for their activation are no
-- longer applied (transition to other state,
-- where signal should not be active)
-- Idle value for ps2_clk and ps2_data is 'Z'
ps2_clk_h <= '1';
ps2_data_h <= '1';
load_tx_data <= '0';
load_rx_data <= '0';
read <= '0';
err <= '0';
case state is
-- wait for the device to begin a transmission
-- by pulling the clock line low and go to state
-- rx_down_edge or, if write is high, the
-- client of this interface wants to send a byte
-- to the device and a transition is made to state
-- tx_force_clk_l
when idle =>
if(ps2_clk_s = '0') then
state <= rx_down_edge;
elsif(write = '1') then
state <= tx_force_clk_l;
else
state <= idle;
end if;
-- ps2_clk is high, check if all the bits have been read
-- if, last bit read, check parity, and if parity ok
-- load received data into rx_data.
-- else if more bits left, then wait for the ps2_clk to
-- go low
when rx_clk_h =>
if(bit_count = NUMBITS) then
if(not (rx_parity = frame(PARITY_BIT))) then
state <= rx_error_parity;
else
load_rx_data <= '1';
state <= rx_data_ready;
end if;
elsif(ps2_clk_s = '0') then
state <= rx_down_edge;
else
state <= rx_clk_h;
end if;
-- data must be read into frame in this state
-- the ps2_clk just transitioned from high to low
when rx_down_edge =>
state <= rx_clk_l;
-- ps2_clk line is low, wait for it to go high
when rx_clk_l =>
if(ps2_clk_s = '1') then
state <= rx_clk_h;
else
state <= rx_clk_l;
end if;
-- parity bit received is invalid
-- signal error and go back to idle.
when rx_error_parity =>
err <= '1';
state <= idle;
-- parity bit received was good
-- set read signal for the client to know
-- a new byte was received and is available on rx_data
when rx_data_ready =>
read <= '1';
state <= idle;
-- the client wishes to transmit a byte to the device
-- this is done by holding ps2_clk down for at least 100us
-- bringing down ps2_data, wait 20us and then releasing
-- the ps2_clk.
-- This constitutes a request to send command.
-- In this state, the ps2_clk line is held down and
-- the counter for waiting 100us is eanbled.
-- when the counter reached upper limit, transition
-- to tx_bring_data_down
when tx_force_clk_l =>
load_tx_data <= '1';
ps2_clk_h <= '0';
if(delay_100us_done = '1') then
state <= tx_bring_data_down;
else
state <= tx_force_clk_l;
end if;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -