⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ps2inerface.vhd

📁 actel BASYs开发板自带的demo程序
💻 VHD
📖 第 1 页 / 共 3 页
字号:
                                          (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 + -