Search code examples
keyboardvhdldelay

Finding source of PS2 keyboard delay


I have a problem that is caused by this keyboard interface. I'm trying to make a digital piano with a keyboard and an amplifier but the sound does not come as we press the button; there is a ~1 second delay. Can you help me with this problem please? Also when we change the code part

Shift2_next <= Shift1(0) & Shift2(10 downto 1);
to
Shift2_next <= PS2Df & Shift2(10 downto 1);

the key gives the sound instantly as wanted but now the sound does not stop; the break code is corrupted in that case I think. Hope you can help. Thanks.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity keyboard_ctrl is
  port(
    clk25 : in STD_LOGIC;
    PS2C : in STD_LOGIC;
    PS2D : in STD_LOGIC;
    xkey : out STD_LOGIC_VECTOR(16 downto 1)
  );
end keyboard_ctrl;

architecture keyboard of keyboard_ctrl is
  signal PS2Cf, PS2Df: std_logic;
  signal PS2Cf_next, PS2Df_next: std_logic;
  signal ps2c_filter, ps2d_filter: std_logic_vector(7 downto 0);
  signal shift1,shift2: std_logic_vector(10 downto 0);
  signal shift1_next,shift2_next: std_logic_vector(10 downto 0);
begin

  xkey <= shift1(8 downto 1)&shift2(8 downto 1);

  -- filter for PS2 clock and data
  filter: process(clk25)
  begin
    if clk25'event and clk25 = '1' then 
        ps2c_filter(7) <= PS2C;
        ps2c_filter(6 downto 0) <= ps2c_filter(7 downto 1);
        ps2d_filter(7) <= PS2D;
        ps2d_filter(6 downto 0) <= ps2d_filter(7 downto 1);

        PS2Cf <= PS2Cf_next;
        PS2Df <= PS2Df_next;
    end if;
  end process filter;
    PS2Cf_next <= '1' when ps2c_filter = X"FF" else 
                  '0' when ps2c_filter = X"00" else
                  PS2Cf;
    PS2Df_next <= '1' when ps2d_filter = X"FF" else 
                  '0' when ps2d_filter = X"00" else
                  PS2Df;

  --Shift used to clock in scan codes from PS2--
  shift: process(PS2Cf)
  begin
    if (PS2Cf'event and PS2Cf = '0') then
        shift1 <= shift1_next;
        shift2 <= shift2_next;
    end if;
  end process shift;

  Shift1_next <= PS2Df & Shift1(10 downto 1);
  Shift2_next <= Shift1(0) & Shift2(10 downto 1);
end keyboard; 

Solution

  • You have to change the design to be synchronous specially when using PS2. I recommend you check the clock for the PS2 make sure it is attached to the 25 MHz pin or try use a higher frequency clock and divide it until you get the correct timing. Attached example of dividing a clock by 3, you can change it and use it

    Best Wishes,

    library ieee;
        use ieee.std_logic_1164.all;
        use ieee.std_logic_unsigned.all;
    
    entity divide_by_3 is
        port (
            cout   :out std_logic;  -- Output clock
            clk    :in  std_logic;  -- Input clock
            reset  :in  std_logic   -- Input reset
        );
    end entity;
    
    architecture rtl of divide_by_3 is
        signal pos_cnt :std_logic_vector (1 downto 0);
        signal neg_cnt :std_logic_vector (1 downto 0);
    begin
        process (clk, reset) begin
            if (reset = '1') then
                pos_cnt <= (others=>'0');
            elsif (rising_edge(clk)) then
                if (pos_cnt = 2) then
                    pos_cnt <= pos_cnt + 1;
                end if;
            end if;
        end process;
    
        process (clk, reset) begin
            if (reset = '1') then
                neg_cnt <= (others=>'0');
            elsif (falling_edge(clk)) then
                if (neg_cnt = 2) then
                    neg_cnt <= neg_cnt + 1;
                end if;
            end if;
        end process;
    
        cout <= '1' when ((pos_cnt /= 2) and (neg_cnt /= 2)) else
                '0';
    end architecture;
    -------------------------------------------------------
    --  Testbench to check the divide_by_3 logic
    -------------------------------------------------------
    library ieee;
        use ieee.std_logic_1164.all;
        use ieee.std_logic_textio.all;
        use std.textio.all;
    
    entity div3_tb is
    end entity;
    architecture test of div3_tb is
    
        signal cout   :std_logic;
        signal clk    :std_logic := '1';
        signal reset  :std_logic := '1';
    
        component divide_by_3 is
        port (
            cout   :out std_logic;
            clk    :in  std_logic;
            reset  :in  std_logic
        );
        end component;
    begin
    
        -- Generate clock
        clk   <= not clk after 10 ns;
        reset <= '0' after 20 ns;
    
        Inst_div3 : divide_by_3
    
    
          port map (
                cout   => cout,   -- Output
                clk    => clk,    -- Input
                reset  => reset   -- Iinput
            );
        end architecture
    
    ;