📄 ps2inerface.vhd
字号:
-- with the ps2_clk line low bring ps2_data low
-- wait for 20us and then go to tx_release_clk
when tx_bring_data_down =>
-- keep clock line low
ps2_clk_h <= '0';
-- set data line low
-- when clock is released in the next state
-- the device will read bit 0 on data line
-- and this bit represents the start bit.
ps2_data_h <= '0'; -- start bit = '0'
if(delay_20us_done = '1') then
state <= tx_release_clk;
else
state <= tx_bring_data_down;
end if;
-- release the ps2_clk line
-- keep holding data line low
when tx_release_clk =>
ps2_clk_h <= '1';
-- must maintain data low,
-- otherwise will be released by default value
ps2_data_h <= '0';
state <= tx_first_wait_down_edge;
-- state is necessary because the clock signal
-- is not released instantaneously and, because of debounce,
-- delay is even greater.
-- Wait 63 clock periods for the clock line to release
-- then if clock is low then go to tx_clk_l
-- else wait until ps2_clk goes low.
when tx_first_wait_down_edge =>
ps2_data_h <= '0';
if(delay_63clk_done = '1') then
if(ps2_clk_s = '0') then
state <= tx_clk_l;
else
state <= tx_first_wait_down_edge;
end if;
else
state <= tx_first_wait_down_edge;
end if;
-- place the least significant bit from frame
-- on the data line
-- During this state the frame is shifted one
-- bit to the right
when tx_clk_l =>
ps2_data_h <= frame(0);
state <= tx_wait_up_edge;
-- wait for the clock to go high
-- this is the edge on which the device reads the data
-- on ps2_data.
-- keep holding ps2_data on frame(0) because else
-- will be released by default value.
-- Check if sent the last bit and if so, release data line
-- and go to state that wait for acknowledge
when tx_wait_up_edge =>
ps2_data_h <= frame(0);
-- NUMBITS - 1 because first (start bit = 0) bit was read
-- when the clock line was released in the request to
-- send command (see tx_bring_data_down state).
if(bit_count = NUMBITS-1) then
ps2_data_h <= '1';
state <= tx_wait_up_edge_before_ack;
-- if more bits to send, wait for the up edge
-- of ps2_clk
elsif(ps2_clk_s = '1') then
state <= tx_clk_h;
else
state <= tx_wait_up_edge;
end if;
-- ps2_clk is released, wait for down edge
-- and go to tx_clk_l when arrived
when tx_clk_h =>
ps2_data_h <= frame(0);
if(ps2_clk_s = '0') then
state <= tx_clk_l;
else
state <= tx_clk_h;
end if;
-- release ps2_data and wait for rising edge of ps2_clk
-- once this occurs, transition to tx_wait_ack
when tx_wait_up_edge_before_ack =>
ps2_data_h <= '1';
if(ps2_clk_s = '1') then
state <= tx_wait_ack;
else
state <= tx_wait_up_edge_before_ack;
end if;
-- wait for the falling edge of the clock line
-- if data line is low when this occurs, the
-- ack is received
-- else if data line is high, the device did not
-- acknowledge the transimission
when tx_wait_ack =>
if(ps2_clk_s = '0') then
if(ps2_data_s = '0') then
-- acknowledge received
state <= tx_received_ack;
else
-- acknowledge not received
state <= tx_error_no_ack;
end if;
else
state <= tx_wait_ack;
end if;
-- wait for ps2_clk to be released together with ps2_data
-- (bus to be idle) and go back to idle state
when tx_received_ack =>
if(ps2_clk_s = '1' and ps2_data_s = '1') then
state <= idle;
else
state <= tx_received_ack;
end if;
-- wait for ps2_clk to be released together with ps2_data
-- (bus to be idle) and go back to idle state
-- signal error for not receiving ack
when tx_error_no_ack =>
if(ps2_clk_s = '1' and ps2_data_s = '1') then
err <= '1';
state <= idle;
else
state <= tx_error_no_ack;
end if;
-- if invalid transition occurred, signal error and
-- go back to idle state
when others =>
err <= '1';
state <= idle;
end case;
end if;
end process manage_fsm;
---------------------------------------------------------------------
-- DELAY COUNTERS
---------------------------------------------------------------------
-- Enable the 100us counter only when state is tx_force_clk_l
delay_100us_counter_enable <= '1' when state = tx_force_clk_l else '0';
-- Counter for a 100us delay
-- after done counting, done signal remains active until
-- enable counter is reset.
delay_100us_counter: process(clk)
begin
if(rising_edge(clk)) then
if(delay_100us_counter_enable = '1') then
if(delay_100us_count = (DELAY_100US)) then
delay_100us_count <= delay_100us_count;
delay_100us_done <= '1';
else
delay_100us_count <= delay_100us_count + 1;
delay_100us_done <= '0';
end if;
else
delay_100us_count <= (others => '0');
delay_100us_done <= '0';
end if;
end if;
end process delay_100us_counter;
-- Enable the 20us counter only when state is tx_bring_data_down
delay_20us_counter_enable <= '1' when state = tx_bring_data_down else '0';
-- Counter for a 20us delay
-- after done counting, done signal remains active until
-- enable counter is reset.
delay_20us_counter: process(clk)
begin
if(rising_edge(clk)) then
if(delay_20us_counter_enable = '1') then
if(delay_20us_count = (DELAY_20US)) then
delay_20us_count <= delay_20us_count;
delay_20us_done <= '1';
else
delay_20us_count <= delay_20us_count + 1;
delay_20us_done <= '0';
end if;
else
delay_20us_count <= (others => '0');
delay_20us_done <= '0';
end if;
end if;
end process delay_20us_counter;
-- Enable the 63clk counter only when state is tx_first_wait_down_edge
delay_63clk_counter_enable <= '1' when state = tx_first_wait_down_edge else '0';
-- Counter for a 63 clock periods delay
-- after done counting, done signal remains active until
-- enable counter is reset.
delay_63clk_counter: process(clk)
begin
if(rising_edge(clk)) then
if(delay_63clk_counter_enable = '1') then
if(delay_63clk_count = (DELAY_63CLK)) then
delay_63clk_count <= delay_63clk_count;
delay_63clk_done <= '1';
else
delay_63clk_count <= delay_63clk_count + 1;
delay_63clk_done <= '0';
end if;
else
delay_63clk_count <= (others => '0');
delay_63clk_done <= '0';
end if;
end if;
end process delay_63clk_counter;
---------------------------------------------------------------------
-- BIT COUNTER AND FRAME SHIFTING LOGIC
---------------------------------------------------------------------
-- counts the number of bits shifted into the frame
-- or out of the frame.
bit_counter: process(clk)
begin
if(rising_edge(clk)) then
if(reset_bit_count = '1') then
bit_count <= (others => '0');
elsif(shift_frame = '1') then
bit_count <= bit_count + 1;
end if;
end if;
end process bit_counter;
-- shifts frame with one bit to right when shift_frame is acitve
-- and loads data into frame from tx_data then load_tx_data is high
load_tx_data_into_frame: process(clk)
begin
if(rising_edge(clk)) then
if(load_tx_data = '1') then
frame(8 downto 1) <= tx_data; -- byte to send
frame(0) <= '0'; -- start bit
frame(10) <= '1'; -- stop bit
frame(9) <= tx_parity; -- parity bit
elsif(shift_frame = '1') then
-- shift right 1 bit
frame(9 downto 0) <= frame(10 downto 1);
-- shift in from the ps2_data line
frame(10) <= ps2_data_s;
end if;
end if;
end process load_tx_data_into_frame;
-- Loads data from frame into rx_data output when data is ready
do_load_rx_data: process(clk)
begin
if(rising_edge(clk)) then
if(load_rx_data = '1') then
rx_data <= frame(8 downto 1);
end if;
end if;
end process do_load_rx_data;
end Behavioral;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -