Klawiatura w VHDL

Dyskusje ogólne na temat "cyfrówki" czyli wszystko o TTL/CMOS, językach VHDL i VERILOG, bramkach, rejestrach, przerzutnikach... Dobre miejsce na pytania odnośnie uniwersalnych programatorów (np. Willem) a także podłączania własnych peryferiów do komputera PC.
ODPOWIEDZ
ciniak6
-
Posty: 1
Rejestracja: 11 cze 2009, 15:08
Lokalizacja: Jasło/Kraków

Klawiatura w VHDL

Post autor: ciniak6 » 11 cze 2009, 15:13

Witam, w ramach hobby bawię się vhdl i ze względu na możliwość dostępu do płytki altery DE2 chciałem zaprogramować sobie działanie klawiatury. Wszystko ok, ale niestety uklad nie działa, czy może mi ktoś pomóc? oto kod:

Kod: Zaznacz cały

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity klawiatura is -- zmienic kodowanie z hex na binarny !!
-- nie czyta nic z klawiatury bo piny sa przypisane w hex a na 8 bitow nie pojdzie
  
  port (
    PS2_Clk  : in std_logic;            -- PS/2
    PS2_Data : in std_logic;            -- PS/2
    CLK_14M  : in std_logic;            -- zegar
    read     : in std_logic;            -- czytaj sygnał
    reset    : in std_logic;            -- reset
    K        : out unsigned(7 downto 0) -- dekodowany sygnal
    );
end klawiatura;

architecture rtl of klawiatura is

  signal code, latched_code : unsigned(7 downto 0); -- wejście
  signal code_available     : std_logic;            -- kod na wejście
  signal ascii              : unsigned(7 downto 0);  -- przekodowanie na ascii
  signal shifted_code       : unsigned(11 downto 0); -- shift
  signal key_pressed        : std_logic;  -- jak wciśnięty to nie czytaj
  signal ctrl, shift        : std_logic;  -- ctrl, shift

  -- kody do PS/2 (piny)
  constant KEY_UP_CODE      : unsigned(7 downto 0) := X"F0";
  constant EXTENDED_CODE    : unsigned(7 downto 0) := X"E0";
  constant LEFT_SHIFT       : unsigned(7 downto 0) := X"12";
  constant RIGHT_SHIFT      : unsigned(7 downto 0) := X"59";
  constant LEFT_CTRL        : unsigned(7 downto 0) := X"14";

  type states is (IDLE,                      -- podaje stany
                  HAVE_CODE,
                  DECODE,
                  GOT_KEY_UP_CODE,
                  GOT_KEY_UP2,
                  GOT_KEY_UP3,
                  KEY_UP,
                  NORMAL_KEY
                  );

  signal state, next_state : states;

begin

  ps2_controller : entity work.PS2_Ctrl port map (
    Clk       => CLK_14M,
    Reset     => reset,
    PS2_Clk   => PS2_Clk,
    PS2_Data  => PS2_Data,
    DoRead    => code_available,
    Scan_DAV  => code_available,
    Scan_Code => code);

  K <= key_pressed & "00" & ascii(4 downto 0) when ctrl = '1' else
       key_pressed & ascii(6 downto 0);

  shift_ctrl : process (CLK_14M, reset)
  begin
    if reset = '1' then
      shift <= '0';
      ctrl <= '0';
    elsif rising_edge(CLK_14M) then
      if state = HAVE_CODE then
        if code = LEFT_SHIFT or code = RIGHT_SHIFT then
          shift <= '1';
        elsif code = LEFT_CTRL then
          ctrl <= '1';
        end if;
      elsif state = KEY_UP then
        if code = LEFT_SHIFT or code = RIGHT_SHIFT then
          shift <= '0';
        elsif code = LEFT_CTRL then
          ctrl <= '0';
        end if;
      end if;
    end if;
  end process shift_ctrl;

  fsm : process (CLK_14M, reset)
  begin
    if reset = '1' then
      state <= IDLE;
      latched_code <= (others => '0');
      key_pressed <= '0';
    elsif rising_edge(CLK_14M) then
      state <= next_state;
      if read = '1' then key_pressed <= '0'; end if;
      if state = NORMAL_KEY then
        latched_code <= code ;
        key_pressed <= '1';
      end if;
    end if;
  end process fsm;

  fsm_next_state : process (code, code_available, state)
  begin
    next_state <= state;
    case state is
      when IDLE =>
        if code_available = '1' then next_state <= HAVE_CODE; end if;
        
      when HAVE_CODE =>
        next_state <= DECODE;
        
      when DECODE =>
        if code = KEY_UP_CODE then
          next_state <= GOT_KEY_UP_CODE;
        elsif code = EXTENDED_CODE then  -- extend = normal
          next_state <= IDLE;
        elsif code = LEFT_SHIFT or code = RIGHT_SHIFT or code = LEFT_CTRL then
          next_state <= IDLE;
        else
          next_state <= NORMAL_KEY;
        end if;
        
      when GOT_KEY_UP_CODE =>
        next_state <= GOT_KEY_UP2;
        
      when GOT_KEY_UP2 =>
        next_state <= GOT_KEY_UP3;
        
      when GOT_KEY_UP3 =>
        if code_available = '1' then
          next_state <= KEY_UP;
        end if;
        
      when KEY_UP | NORMAL_KEY =>
        next_state <= IDLE;
    end case;
  end process fsm_next_state;

  -- sygnal PS/2 na ascii (w hexadecymalnym) 16 

  shifted_code <= "000" & shift & latched_code;
  
  with shifted_code select
    ascii <=
     X"08" when X"066", -- Backspace ("backspace" klawisz)
     X"08" when X"166", -- Backspace ("backspace" klawisz)
     X"09" when X"00d", -- Horizontal Tab
     X"09" when X"10d", -- Horizontal Tab
     X"0d" when X"05a", -- Carriage return ("enter" klawisz)
     X"0d" when X"15a", -- Carriage return ("enter" klawisz)
     X"1b" when X"076", -- Escape ("esc" klawisz)
     X"1b" when X"176", -- Escape ("esc" klawisz)
     X"20" when X"029", -- Space
     X"20" when X"129", -- Space
     X"21" when X"116", -- !
     X"22" when X"152", -- "
     X"23" when X"126", -- #
     X"24" when X"125", -- $
     X"25" when X"12e", --
     X"26" when X"13d", --
     X"27" when X"052", --
     X"28" when X"146", --
     X"29" when X"145", --
     X"2a" when X"13e", -- *
     X"2b" when X"155", -- +
     X"2c" when X"041", -- ,
     X"2d" when X"04e", -- -
     X"2e" when X"049", -- .
     X"2f" when X"04a", -- /
     X"30" when X"045", -- 0
     X"00110
     001" when X"016", -- 1
     X"32" when X"01e", -- 2
     X"33" when X"026", -- 3
     X"34" when X"025", -- 4
     X"35" when X"02e", -- 5
     X"36" when X"036", -- 6
     X"37" when X"03d", -- 7
     X"38" when X"03e", -- 8
     X"39" when X"046", -- 9
     X"3a" when X"14c", -- :
     X"3b" when X"04c", -- ;
     X"3c" when X"141", -- <
     X"3d" when X"055", -- =
     X"3e" when X"149", -- >
     X"3f" when X"14a", -- ?
     X"40" when X"11e", -- @
     X"41" when X"11c", -- A
     X"42" when X"132", -- B
     X"43" when X"121", -- C
     X"44" when X"123", -- D
     X"45" when X"124", -- E
     X"46" when X"12b", -- F
     X"47" when X"134", -- G
     X"48" when X"133", -- H
     X"49" when X"143", -- I
     X"4a" when X"13b", -- J
     X"4b" when X"142", -- K
     X"4c" when X"14b", -- L
     X"4d" when X"13a", -- M
     X"4e" when X"131", -- N
     X"4f" when X"144", -- O
     X"50" when X"14d", -- P
     X"51" when X"115", -- Q
     X"52" when X"12d", -- R
     X"53" when X"11b", -- S
     X"54" when X"12c", -- T
     X"55" when X"13c", -- U
     X"56" when X"12a", -- V
     X"57" when X"11d", -- W
     X"58" when X"122", -- X
     X"59" when X"135", -- Y
     X"5a" when X"11a", -- Z
     X"5b" when X"054", -- [
     X"5c" when X"05d", -- \
     X"5d" when X"05b", -- ]
     X"5e" when X"136", -- ^
     X"5f" when X"14e", -- _
     X"60" when X"00e", -- `
     X"41" when X"01c", -- A
     X"42" when X"032", -- B
     X"43" when X"021", -- C
     X"44" when X"023", -- D
     X"45" when X"024", -- E
     X"46" when X"02b", -- F
     X"47" when X"034", -- G
     X"48" when X"033", -- H
     X"49" when X"043", -- I
     X"4a" when X"03b", -- J
     X"4b" when X"042", -- K
     X"4c" when X"04b", -- L
     X"4d" when X"03a", -- M
     X"4e" when X"031", -- N
     X"4f" when X"044", -- O
     X"50" when X"04d", -- P
     X"51" when X"015", -- Q
     X"52" when X"02d", -- R
     X"53" when X"01b", -- S
     X"54" when X"02c", -- T
     X"55" when X"03c", -- U
     X"56" when X"02a", -- V
     X"57" when X"01d", -- W
     X"58" when X"022", -- X
     X"59" when X"035", -- Y
     X"5a" when X"01a", -- Z
     X"7b" when X"154", -- {
     X"7c" when X"15d", -- |
     X"7d" when X"15b", -- }
     X"7e" when X"10e", -- ~
     X"7f" when X"071", -- (Delete OR DEL na numerycznej klawiaturze)
     X"15" when X"074", -- prawa strzałka (cntrl U)
     X"08" when X"06b", -- lewa strzałka (BS)
     X"0B" when X"075", -- do góry strzałka
     X"0A" when X"072", -- na dół strzałka
     X"7f" when X"171", -- (Delete OR DEL na numerycznej klawiaturze)
     X"00" when others; -- kiedy inne (RESET)

end rtl;
Dodatkowo do tego na PS/2

Kod: Zaznacz cały

 library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Numeric_Std.all;


Entity PS2_Ctrl is

  generic (FilterSize : positive := 8);
  port( Clk       : in  std_logic;  		 -- zegar systemu
        Reset     : in  std_logic;  		 -- reset systemu
        PS2_Clk   : in  std_logic;  		 -- zegar klawiatury
        PS2_Data  : in  std_logic;  		 -- data klawiatury
        DoRead    : in  std_logic;  		 -- zewnatrz jak czyta kody skanujace
        Scan_Err  : out std_logic;  		 -- do środka : Parity or Overflow error
        Scan_DAV  : out std_logic;  		 -- do środka jak kod skanujacy się pojawił
        Scan_Code : out unsigned(7 downto 0) -- 8 bitowe wyjście data
        );
end PS2_Ctrl;


Architecture ALSE_RTL of PS2_Ctrl is


  signal PS2_Datr  : std_logic;

  subtype Filter_t is std_logic_vector(FilterSize-1 downto 0);
  signal Filter    : Filter_t;
  signal Fall_Clk  : std_logic;
  signal Bit_Cnt   : unsigned(3 downto 0);
  signal Parity    : std_logic;
  signal Scan_DAVi : std_logic;

  signal S_Reg     : unsigned(8 downto 0);

  signal PS2_Clk_f : std_logic;

  Type   State_t is (Idle, Shifting);
  signal State : State_t;

begin

Scan_DAV <= Scan_DAVi;

-- Ten filter zmienia sygnał z klawiatury na cyfrowy do procesora (skorzystano z zewnętrznego pomysłu)
-- Osiem kolejnych PS2_Clk=1 sprawia filtered_clock idzie na wysoki
-- Osiem kolejnych PS2_Clk=0 sprawia filtered_clock idzie na niski
-- Implikuje (FilterSize+1) x Tsys_clock opóźnienie na Fall_Clk wrt Data
-- Również ponownie synchronizuje PS2_Data


process (Clk,Reset)
begin
  if Reset='1' then
    PS2_Datr  <= '0';
    PS2_Clk_f <= '0';
    Filter    <= (others=>'0');
    Fall_Clk  <= '0';
  elsif rising_edge (Clk) then
    PS2_Datr <= PS2_Data and PS2_Data; -- także zmienia 'H' na '1'
    Fall_Clk <= '0';
    Filter   <= (PS2_Clk and PS2_CLK) & Filter(Filter'high downto 1);
    if Filter = Filter_t'(others=>'1') then
      PS2_Clk_f <= '1';
    elsif Filter = Filter_t'(others=>'0') then
      PS2_Clk_f <= '0';
      if PS2_Clk_f = '1' then
        Fall_Clk <= '1';
      end if;
    end if;
  end if;
end process;

-- Ta prosta maszyna stanów czyta Serial Data pochodzącą z peryferii PS/2


process(Clk,Reset)
begin

  if Reset='1' then
    State     <= Idle;
    Bit_Cnt   <= (others => '0');
    S_Reg     <= (others => '0');
    Scan_Code <= (others => '0');
    Parity    <= '0';
    Scan_Davi <= '0';
    Scan_Err  <= '0';

  elsif rising_edge (Clk) then

    if DoRead='1' then
      Scan_Davi <= '0'; -- to może być wyłączone = '0'
    end if;

    case State is

      when Idle =>
        Parity  <= '0';
        Bit_Cnt <= (others => '0'); -- nie musimy czyścić rejestru dla Shift
        
        if Fall_Clk='1' and PS2_Datr='0' then -- Start bit
          Scan_Err <= '0';
          State <= Shifting;
        end if;

      when Shifting =>
          if Bit_Cnt >= 9 then
            if Fall_Clk='1' then -- Stop Bit 
				-- Błąd jak (wrong Parity) lub (Stop='0') lub Overflow(przeplyw)              
              Scan_Err  <= (not Parity) or (not PS2_Datr) or Scan_DAVi;
              Scan_Davi <= '1';
              Scan_Code <= S_Reg(7 downto 0);
              State <= Idle;
            end if;
          elsif Fall_Clk='1' then
            Bit_Cnt  <= Bit_Cnt + 1;
            S_Reg <= PS2_Datr & S_Reg (S_Reg'high downto 1); -- Shift prawy
            Parity <= Parity xor PS2_Datr;
          end if;

      when others => -- nigdy nie osiągalne
        State <= Idle;

    end case;

	--Scan_Err <= '0'; -- aby spowodować błąd dla Scan_Err


  end if;

end process;

end ALSE_RTL;

Układ kompiluje się ale nic się nie dzieje po wgraniu na płytkę. Oczywiście jako wyjście przypisałem 8 diod na płytce żebym coś widział. Dla osób zainteresowanych pomocą dla mnie mogę wysłać na maila cały projekt. Pozdrawiam :)

ODPOWIEDZ