Forum: FPGA, VHDL & Co. PS/2 im FPGA


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Daniel K. (daniel_k80)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

da mein VGA nun sehr zufriedenstellend funktioniert möchte ich gerne 
noch eine PS/2 Tastatur an mein FPGA anschließen.
Über einen Mikrocontroller habe ich das Auslesen schon realisiert, von 
daher weiß ich ungefähr wie das abläuft.
Im FPGA möchte ich das gerne über eine State Machine machen und habe 
dafür schon mal was gezeichnet um mir den Ablauf zu verdeutlichen (PS/2 
ist relativ einfach, das weiß ich aber das ist dann schön zur Übung :) 
).

Ist das Ablaufdiagramm so richtig? Wenn ja, dann würde ich mal versuchen 
das so in VHDL zu implementieren.

Danke schon mal :)

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Daniel K. schrieb:
> Ist das Ablaufdiagramm so richtig?
Die Daten liegen als Scancode vor. Das ist noch weit weg vom ASCII-Code. 
Dazu kommt noch ein Break-Code, der vor einer losgelassenen Taste 
gesendet wird. Und ein Timeout würde mir auch fehlen.

Ich mache solche seriellen Protokolle gerne mit einem Schieberegister 
statt einem Bitzähler:
http://www.lothar-miller.de/s9y/archives/75-PS2-Tastatur.html

: Bearbeitet durch Moderator
von Ralf (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Wenn du des Englischen maechtig bist:

Youtube-Video "Lesson 110 - Example 75: PS2 Keyboard Interface"

Schau mal diesen Link an. Da wird das ganz
gut erklaert.

Gruss

Ralf

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
Danke für die Antworten :)

Lothar Miller schrieb:
> Daniel K. schrieb:
>> Ist das Ablaufdiagramm so richtig?
> Die Daten liegen als Scancode vor. Das ist noch weit weg vom ASCII-Code.
> Dazu kommt noch ein Break-Code, der vor einer losgelassenen Taste
> gesendet wird. Und ein Timeout würde mir auch fehlen.
>
> Ich mache solche seriellen Protokolle gerne mit einem Schieberegister
> statt einem Bitzähler:
> http://www.lothar-miller.de/s9y/archives/75-PS2-Tastatur.html

Ahh sorry. Das mit dem Scancode hatte ich komplett vergessen :(
Im Mikrocontroller hatte ich das mit einer Headerdatei und einem Array 
gemacht, wo ich an die entsprechende Posi den passenden ASCII Wert 
abgelegt habe.
Das muss ich hier natürlich auch berücksichtigen.
Der Tipp mit dem Schieberegister ist gut :) Das werde ich dann direkt 
mal so umsetzen.

Danke für das Video Tutorial. Ich werde es mir speichern. Ist ganz 
praktisch ein paar Tutorials als Video zu haben :)

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Lothar,

ich habe mir mal dein Beispiel angeschaut.
Warum hast du das hier gemacht?:

DataSR    <= DataSR(0) & PS2_Data;
ClkSR     <= ClkSR(0)  & PS2_Clk;
if (ClkSR = "10") then
    RxRegister <= DataSR(1) & RxRegister(10 downto 1);
end if;

Ist das aus dem selben Grund wie im Video um das eventuell verrauschte 
PS/2-Signal zu filtern?

: Bearbeitet durch User
von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Daniel K. schrieb:
> Ist das aus dem selben Grund wie im Video um das eventuell verrauschte
> PS/2-Signal zu filtern?
Mehr oder weniger ja. Nur mit weniger Flipflops...
Zum Hintergrund die beiden dort:
http://www.lothar-miller.de/s9y/categories/18-Flankenerkennung
http://www.lothar-miller.de/s9y/categories/5-Entprellung

> Ist das aus dem selben Grund wie im Video um das eventuell verrauschte
> PS/2-Signal zu filtern?
Ein "verrauschtes" Signal sollte dort gar nicht auftreten, denn sonst 
hast du prinzipiell Probleme mit instabiler Übertragung. Denn durch 
diese "Filterung" wird natürlich auch der Abtastzeitpunkt verschoben.

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Lothar,

ok, ich habe dann direkt mal noch eine Frage zu deinem Code.
Bei der PS/2 Schnittstelle handelt es sich ja um eine asynchrone 
Übertragung.
Du schreibst ja nun folgendes:
ClkSR     <= ClkSR(0)  & PS2_Clk;

if (ClkSR = "10") then
   ...
end if;

Das dient, wenn ich das richtig verstanden habe, auch zum eintakten des 
asynchronen Clock-Signals vom PS/2 oder?
Sobald dein Schieberegister den Wert "10" erreicht hat weiß du, dass ein 
Flankenwechsel geschehen ist, da zu dem Zeitpunkt t der Pegel High war 
und zu dem Zeitpunkt t+1 war der low (t ist dabei der Takt der 50MHz 
Quelle).
Sehe ich das soweit richtig :o?

von Duke Scarring (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ja. Die "01" dient zum Erkennen der Flanke.

Duke

von Fpgakuechle K. (fpgakuechle) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Daniel K. schrieb:

> Im FPGA möchte ich das gerne über eine State Machine machen und habe
> dafür schon mal was gezeichnet um mir den Ablauf zu verdeutlichen (PS/2
> ist relativ einfach, das weiß ich aber das ist dann schön zur Übung :)
> ).


Da hats hier auf Mikrocontroller.net ein Projekt wo ein PS/2 Controller 
benutzt wird:
http://www.mikrocontroller.net/svnbrowser/redz0mb1e/src/vhdl/kb2vhdl_fk.vhd?view=markup

http://www.mikrocontroller.net/articles/Retrocomputing_auf_FPGA#Tastatur_2
http://www.mikrocontroller.net/articles/Retrocomputing_auf_FPGA#Tastatur_3

Tückisch ist der Scancode da er zweimal gesendet wird, beim Drücken und 
beim Loslassen. Aber nur so kann man erkennen ob die Shifttaste 
mitgedrückt wurde.

MfG,

: Bearbeitet durch User
von Fpgakuechle K. (fpgakuechle) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Daniel K. schrieb:

> Ist das Ablaufdiagramm so richtig? Wenn ja, dann würde ich mal versuchen
> das so in VHDL zu implementieren.

Nope, das passt nicht. Der scancode kann sich auch über 3 bytes 
erstrecken (windows media keys) und ich erkenne nicht wie die FSM 
erkennen soll ob die Taste gerade gedruckt oder losgelassen wurde oder 
ob die shifttaste noch aktiv ist.

MfG,

von Daniel K. (daniel_k80)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

so ich habe mein PS/2 Controller für die Tastatur fertig (dank dem Video 
und dem Artikel vom Lothar :) ) - siehe Anhang.
Ich habe mir zudem noch ein Top-Design für das Keyboard gemacht, wo ich 
ein ROM einbinde mit dessen Hilfe ich den Scancode in ASCII Zeichen 
umwandel.
Dieses ROM ist als Blockmemory ausgeführt, lässt sich aber in der 
Simulation nicht benutzen. Ich bekomme meinen Wert vom 
Tastaturcontroller, der dann die Adresse für mein ROM ist, aber aus dem 
ROM kommt nichts raus (siehe Screenshot).

Das ROM habe ich in dem Top-Design auskommentiert, da es im fertigen 
Design ebenfalls Probleme gemacht hat und ich es erst einmal raus lassen 
wollte. Für die Simulation war es drin.

Und dann noch eine kleine Frage nebenbei...
Für mein fertiges Design habe ich ebenfalls eine TB gemacht. Da in 
meinem Design aber ein DCM ist muss ich die Auflösung des Simulators auf 
1ps stellen, da der DCM sonst keinen Takt erzeugt.
Wie kann ich das für den Vivado Simulator machen?

Danke schon mal :)

von Duke Scarring (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Kannst Du die Testbench hier mit reinstellen?
Dann kann man die Simulation nachvollziehen. Das macht vieles leichter.

Duke

von Daniel K. (daniel_k80)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ahh sorry.
Dachte ich hätte sie mit hoch geladen...

von Duke Scarring (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Kein Problem.
Erstmal passt hier PS2_Keyboard(entity) nicht zu 
PS2_Keyboard(testbench):
# ** Error: ps2_keyboard_tb.vhd(116): (vopt-1270) Bad default binding for component instance "Keyboard: PS2_Keyboard".
#  (Component port "Data" is not on the entity.)
# ** Error: ps2_keyboard_tb.vhd(116): (vopt-3473) Component instance "/PS2_Keyboard_TB/Keyboard : PS2_Keyboard" is not bound.

Hier die Ursache:
            
...
            Data_Read   : in STD_LOGIC;                                     -- Handshake - Daten wurden vom Controller gelesen und er kann neue empfangen
            Reset       : in STD_LOGIC;                                     -- Reset Eingang für die Controller Logik 
            ASCII       : out STD_LOGIC_VECTOR(7 downto 0)                  -- Eingegebenes ASCII Zeichen der Tastatur
            );
end PS2_Keyboard;
...
            Data_Read   : in STD_LOGIC;                                     
            Reset       : in STD_LOGIC;                                     
            Data        : out STD_LOGIC_VECTOR(7 downto 0)                  
            );
end component;    
Nur als Tipp:
Die Verbindung der Signale über Positionen ist auch Fehleranfällig:
  Keyboard : PS2_Keyboard port map(Clock, PS2Clock, PS2Data, Ready, Read, Reset, Data_Out);

Nun fehlt noch das Keyboard-ROM:
# ** Error: ps2_keyboard.vhd(69): (vopt-3473) Component instance "/PS2_Keyboard_TB/Keyboard/ROM : Keyboard_ROM" is not bound.
# 
# Error loading design

Duke

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
mmh das habe ich alles behoben, aber es kommt immer noch kein Wert aus 
dem ROM :(

von Duke Scarring (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Zeig doch mal Deinen ROM.

Duke

von Daniel K. (daniel_k80)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich verwende einen Block Memory Generator mit dem angehängten 
Initialisierungsfile.

von Duke Scarring (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Da muss doch trotzdem ein VHDL (oder verilog) File rausfallen. Sonst 
kann man das ja gra nicht simulieren.

Duke

von Daniel K. (daniel_k80)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
mmh ich weiß jetzt nicht welches VHDL File du meinst.
Ich habe dir mal den Ordner hochgeladen...da kannst du dann mal gucken.

von Duke Scarring (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Der müßte es sein:
VGA.srcs\sources_1\bd\Font_ROM\hdl\Font_ROM.vhd

Na, schaun wir mal.

von Duke Scarring (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Quatsch. Keyboard_ROM.vhd natürlich...

von Duke Scarring (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Wenn man in Zeile 29+1 (=Adresse 0x1d) des .mif-File was reinschreibt, 
kommt auch was raus.

Duke

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
....habe ich mich da etwa wieder verzählt :(?
Dank dir für den Hinweis!

Jetzt noch eine andere Frage.
Ich habe jetzt folgende Situation:
- Mein Top Design läuft mit 100MHz
- VGA läuft mit 25MHz
- PS/2 läuft mit 5MHz

Der PS/2 stellt ein Signal bereit, wenn er mit dem Empfangen fertig ist. 
Dieses Signal ist beim PS/2-Controller 1 Takt lang. Wenn ich dieses 
Signal nun im Top-Design verarbeiten will um z.B. die Position des 
VGA-Zeichens um eins zu erhöhen muss ich dieses langsamere Signal ja 
eintakte, da bei einer einfachen High-Abfrage würde die Abfrage ja im 
Top-Design 20x durchlaufen bis sich das Ready-Signal vom PS/2 ändert.
Soviel zum theoretischen...
Praktisch wäre das dann wieder so, dass ich ein Schieberegister baue und 
das Signal (wie in Lothars Link) eintakte und dann wieder auf "10" 
vergleiche, sprich wenn das Signal einen Wechsel von High nach Low (oder 
umgekehrt) macht.

Ist diese Überlegung korrekt?

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Daniel K. schrieb:
> Ich habe jetzt folgende Situation:
> - Mein Top Design läuft mit 100MHz
> - VGA läuft mit 25MHz
> - PS/2 läuft mit 5MHz
Lass doch einfach alles mit 100MHz laufen. Dann sind alle 
Handshakesignale einen Zyklus lang für jeweils 10ns aktiv. Einfacher 
gehts nicht.

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
> Daniel K. schrieb:
>> Ich habe jetzt folgende Situation:
>> - Mein Top Design läuft mit 100MHz
>> - VGA läuft mit 25MHz
>> - PS/2 läuft mit 5MHz
> Lass doch einfach alles mit 100MHz laufen. Dann sind alle
> Handshakesignale einen Zyklus lang für jeweils 10ns aktiv. Einfacher
> gehts nicht.

Stimmt :P
Btw. ich habe den Fehler im Initialisierungsfile gefunden.
Ich habe zwei Zahlen ausgelassen, weswegen der Versatz entstanden ist...

: Bearbeitet durch User
von Daniel K. (daniel_k80)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
mmh ich habe mal eine Frage...
Und zwar verstehe ich mein Simulationsergebnis nicht.
Ich habe folgende Dateien:

PS/2-Keyboard
----------------------------------------------------------------------------------
-- Company:             www.kampis-elektroecke.de
-- Engineer:            Daniel Kampert
-- 
-- Create Date:         25.03.2015 07:09:28
-- Design Name: 
-- Module Name:         PS2_Keyboard_Ctrl - PS2_Keyboard_Ctrl_Arch
-- Project Name: 
-- Target Devices:      XC7Z010CLG400-1
-- Tool Versions:       Vivado 2014.4
-- Description:         PS/2-Controller for a PS/2-Keyboard
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity PS2_Keyboard_Ctrl is
    Port (  Clock       : in STD_LOGIC;
            PS2_Clock   : in STD_LOGIC;
            PS2_Data    : in STD_LOGIC;
            Data_Ready  : out STD_LOGIC := '0';
            Data_Read   : in STD_LOGIC;
            Reset       : in STD_LOGIC;
            Data_Out    : out STD_LOGIC_VECTOR(7 downto 0)
            );
end PS2_Keyboard_Ctrl;

architecture PS2_Keyboard_Ctrl_Arch of PS2_Keyboard_Ctrl is

    -- Eingangsschieberegister
    signal PS2_DataSR       : std_logic_vector(1 downto 0) := (others => '1');
    signal PS2_ClockSR      : std_logic_vector(1 downto 0) := (others => '1');

    signal Scancode         : std_logic_vector(7 downto 0);
    signal Input_Buffer     : std_logic_vector(10 downto 0) := (others=>'1');

    -- State-Machine definieren
    type PS2_StateType is (RESET_STATE, WAIT_BYTE1, WAIT_BYTE2, WAIT_BREAK1, WAIT_BREAK2, WAIT_BREAK3, RECEIVE_BYTE1, RECEIVE_BYTE2, RECEIVE_BREAK1, RECEIVE_BREAK2, RECEIVE_BREAK3, READY);
    signal PS2_State    : PS2_StateType := RESET_STATE;

begin

    process(Clock)
    begin
        if(rising_edge(Clock)) then

            -- Eintakten des asynchronen PS/2-Signals
            PS2_DataSR  <= PS2_DataSR(0) & PS2_Data;
            PS2_ClockSR <= PS2_ClockSR(0) & PS2_Clock;

            -- Flankenerkennung am PS/2-Clock
            if(PS2_ClockSR = "10") then
                Input_Buffer <= PS2_DataSR(1) & Input_Buffer(10 downto 1);
            end if;

            case PS2_State is
                when RESET_STATE =>

                    -- Controller reseten
                    Data_Out <= (others => '0');
                    Data_Ready <= '0';
                    Input_Buffer <= (others => '1');

                    if(Reset = '0') then
                        PS2_State <= RESET_STATE; 
                    else
                        PS2_State <= WAIT_BYTE1; 
                    end if;                   

                when WAIT_BYTE1 =>

                    Input_Buffer <= (others => '1');

                    -- PS/2 Startbedingung erkannt
                    if((PS2_DataSR(1) = '0') and (PS2_ClockSR(1) = '1')) then
                        PS2_State <= RECEIVE_BYTE1;    
                    end if;   

                when RECEIVE_BYTE1 =>

                    -- Startbit bis zum Ende durchgeschoben?
                    if(Input_Buffer(0) = '0') then
                        Scancode <= Input_Buffer(8 downto 1);
                        PS2_State <= WAIT_BREAK1;  
                    end if;

                    if(Scancode = x"E0") then
                        PS2_State <= WAIT_BYTE2;    
                    end if;

                when WAIT_BYTE2 =>

                    Input_Buffer <= (others => '1'); 

                    if((PS2_DataSR(1) = '0') and (PS2_ClockSR(1) = '1')) then
                        PS2_State <= RECEIVE_BYTE2;    
                    end if; 
               
                when RECEIVE_BYTE2 =>   

                    if(Input_Buffer(0) = '0') then
                        Scancode <= Input_Buffer(8 downto 1);
                        PS2_State <= WAIT_BREAK1;  
                    end if;

                when WAIT_BREAK1 =>

                    Input_Buffer <= (others => '1');    

                    if((PS2_DataSR(1) = '0') and (PS2_ClockSR(1) = '1')) then
                        PS2_State <= RECEIVE_BREAK1;    
                    end if;   

                when RECEIVE_BREAK1 =>

                    if(Input_Buffer(0) = '0') then
                        PS2_State <= WAIT_BREAK2;  
                    end if;
                    
                when WAIT_BREAK2 =>

                    Input_Buffer <= (others => '1');    

                    if((PS2_DataSR(1) = '0') and (PS2_ClockSR(1) = '1')) then
                        PS2_State <= RECEIVE_BREAK2;    
                    end if;   

                when RECEIVE_BREAK2 =>
 
                    if(Input_Buffer(0) = '0') then                        
                        if(Input_Buffer(8 downto 1) = x"E0") then
                            PS2_State <= WAIT_BREAK3;
                        else    
                            PS2_State <= READY; 
                            Data_Ready <= '1';
                        end if; 
                    end if;                    

                when WAIT_BREAK3 =>

                    Input_Buffer <= (others => '1'); 

                    if((PS2_DataSR(1) = '0') and (PS2_ClockSR(1) = '1')) then
                        PS2_State <= RECEIVE_BREAK3;    
                    end if;    
 
                when RECEIVE_BREAK3 =>

                    if(Input_Buffer(0) = '0') then
                        PS2_State <= READY;
                        Data_Ready <= '1';  
                    end if;      

                when READY =>

                    -- Read-Handshake gesetzt - zurück in Ausgangszustand springen
                    if(Data_Read = '1') then
                        Data_Ready <= '0';
                        Data_Out <= Scancode;
                        PS2_State <= WAIT_BYTE1;  
                    end if;
                    
                    if(Reset = '0') then
                        PS2_State <= RESET_STATE; 
                    end if; 

            end case;        
        end if;
    end process;
end PS2_Keyboard_Ctrl_Arch;

Und die folgende TB:
----------------------------------------------------------------------------------
-- Company:             www.kampis-elektroecke.de
-- Engineer:            Daniel Kampert
-- 
-- Create Date:         25.03.2015 12:08:21
-- Design Name: 
-- Module Name:         PS2_Keyboard_TB - PS2_Keyboard_TB_Arch
-- Project Name: 
-- Target Devices:      XC7Z010CLG400-1
-- Tool Versions:       Vivado 2014.4
-- Description:         Testbench for PS/2-Keyboard Interface
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
library UNISIM;
use UNISIM.VComponents.all;

entity PS2_Keyboard_TB is
end PS2_Keyboard_TB;

architecture PS2_Keyboard_TB_Arch of PS2_Keyboard_TB is

    -- PS/2 Sendefunktion
    procedure Send_PS2( signal Data :  in std_logic_vector(7 downto 0); 
                        signal PS2_Clock : out std_logic;
                        signal PS2_Data : out std_logic) is

        variable Paritaet : std_logic := '1';
        
    begin

        -- Startbit senden
        PS2_Data <= '0';
        wait for 20 us;
        PS2_Clock <= '0';
        wait for 40 us;
        PS2_Clock <= '1';
        wait for 20 us;
            
        -- Datenbits senden
        Paritaet := '1';
        for Counter in 0 to 7 loop
            PS2_Data <= Data(Counter);
                if(Data(Counter) = '1') then 
                   Paritaet := not Paritaet; 
                end if;
            wait for 20 us;
            PS2_Clock  <= '0';
            wait for 40 us;
            PS2_Clock  <= '1';
            wait for 20us;
        end loop;    
        
        -- Parität senden
        PS2_Data <= Paritaet;
        wait for 20 us;
        PS2_Clock  <= '0';
        wait for 40 us;
        PS2_Clock  <= '1';
        wait for 20 us;
        
        -- Stoppbit senden
        PS2_Data <= '1';
        wait for 20 us;
        PS2_Clock  <= '0';
        wait for 40 us;
        PS2_Clock  <= '1';
        wait for 20 us;  
    end procedure;
 
    -- Systemtakt
    constant Periode    : time := 200 ns;
    signal Clock        : std_logic := '0';

    -- PS/2 Signale
    signal PS2Clock    : std_logic := '1';
    signal PS2Data     : std_logic := '1';
    
    -- Steuersignale
    signal Ready        : std_logic := '0';
    signal Read         : std_logic := '0';
    signal Reset        : std_logic := '0';
    
    -- Scancode vom Keyboard
    signal Data_Out     : std_logic_vector(7 downto 0) := (others => '0');
    signal Scancode     : std_logic_vector(7 downto 0) := (others => '0');

    component PS2_Keyboard
        Port (  Clock       : in STD_LOGIC;                                     
                PS2_Clock   : in STD_LOGIC;                                     
                PS2_Data    : in STD_LOGIC;                                    
                Data_Ready  : out STD_LOGIC;                                   
                Data_Read   : in STD_LOGIC;                                     
                Reset       : in STD_LOGIC;                                     
                Data        : out STD_LOGIC_VECTOR(7 downto 0)                  
                );
    end component;    
    
begin

    Keyboard : PS2_Keyboard port map(Clock, PS2Clock, PS2Data, Ready, Read, Reset, Data_Out);

    -- 25MHz Clock
    Clock <= not Clock after Periode / 2;
    
    process
    begin   
  
        -- Controller reseten
        Reset <= '1';
        wait for 100 us;
        Reset <= '0';
        wait for 100 us;
        Reset <= '1';
        wait for 100 us;        

        -- Bustaben "W" senden
        Scancode <= x"1D";
        Send_PS2(Scancode, PS2Clock, PS2Data);
        wait for 100 us;           

        -- Break-Code senden
        Scancode <= x"F0";
        Send_PS2(Scancode, PS2Clock, PS2Data);
        wait for 100 us; 
        Scancode <= x"1D";
        Send_PS2(Scancode, PS2Clock, PS2Data);
        wait for 100 us; 
        
        -- Zeichen auslesen
        if(Ready = '1') then
            Read <= '1';
        else
            Read <= '0';
        end if;
        
        wait for 10 ms;
        
        Scancode <= x"1B";
        Send_PS2(Scancode, PS2Clock, PS2Data);
        wait for 100 us;        
        Scancode <= x"F0";
        Send_PS2(Scancode, PS2Clock, PS2Data);
        wait for 100 us; 
        Scancode <= x"1B";
        Send_PS2(Scancode, PS2Clock, PS2Data);
        wait for 100 us; 
        
        -- Zeichen auslesen
        if(Ready = '1') then
            Read <= '1';
        else
            Read <= '0';
        end if;
         
        wait for 10 ms;
         
        Scancode <= x"1C";
        Send_PS2(Scancode, PS2Clock, PS2Data);
        wait for 100 us;        
        Scancode <= x"F0";
        Send_PS2(Scancode, PS2Clock, PS2Data);
        wait for 100 us; 
        Scancode <= x"1C";
        Send_PS2(Scancode, PS2Clock, PS2Data);
        wait for 100 us;
           
        -- Zeichen auslesen
        if(Ready = '1') then
            Read <= '1';
        else
            Read <= '0';
        end if;
                           
        wait for 1000 ms;

    end process;  

end PS2_Keyboard_TB_Arch;

Warum bekomme ich in der Simulation nun ein so langes Ready-Signal wie 
auf dem Screenshot zu sehen?
Normal müsste er doch sehen, dass Ready = 1 ist und beim nächsten Takt 
da rein springen und "Read" setzen.
Daraufhin springt die State-Machine in die Abfrage, löscht "Ready" und 
gibt die Daten aus. Wegen dem fehlenden Ready wird dann in der TB das 
Read-Signal gelöscht.
Das sollte doch nur 4-5 Takte dauern und nicht so lange?!

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
Hat sich erledigt. War wohl leicht spät gestern Abend....

von Daniel K. (daniel_k80)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
mmh ich habe jetzt noch ein Problem damit mehrere Buchstaben auf meinem 
Bildschirm ausgeben zu lassen.
Ich habe meinen VGA-Core und meinen PS/2-Core. Mein PS/2-Core gibt ein 
Signal aus sobald die Wandlung bereit ist (Codes im Anhang).
Jetzt habe ich aber das Problem, dass der Buchstabe an mehrere Adressen 
meines Display-RAMs geschrieben wird (das RAM besitzt pro Buchstaben auf 
dem Bildschirm einen Speicherplatz und das RAM wird vom VGA 
ausgelesen...das funktioniert 1a).
Ich habe folgenden Codeschnipsel für die Tastatur
        Div_1kHz        : Clock_Divider port map (Clock_VGA, Clock_1kHz, 25000);
    IO              : Entprellen port map (Clock_VGA, Tasten, Tasten_Out);
    DCM             : Clock port map (Clock_VGA, Clock_In, Clock_Lock, Reset, Clock_System);
    VGA_Top         : VGA port map (Clock_VGA, Reset, Mode, Read_Write, Display_Write_Data, std_logic_vector(Display_Write_Addr), HSync, VSync, RGB);
    Tastatur        : PS2_Keyboard port map(Clock_System, PS2_Clock, PS2_Data, PS2_Ready, PS2_Read, Reset, PS2_Data_Out);
   Display_Write_Data <= x"F800" & PS2_Data_Out;
    
    process(Clock_1kHz)
    begin
        if(rising_edge(Clock_1kHz)) then
            if(PS2_Ready <= '1') then
                Display_Write_Addr <= Display_Write_Addr + 1;   
                Read_Write <= '1';
                PS2_Read <= '1';                
            else
                Read_Write <= '0';
                PS2_Read <= '0';      
            end if;  
        end if;    
    end process;

Da scheint es noch ein Problem mit dem "Ready"-Signal zu geben...
Die Idee ist darauf zu warten, dass der Tastaturcontroller das 
"Ready"-Signal setzt, dann entsprechend das "Read"-Signal setzen um den 
Controller auszulesen, wodurch der Controller die Daten ausgibt und 
wieder in den ersten Zustand der State-Machine springt.
Sobald ein Zeichen ausgelesen ist, wird die Schreibadresse für das 
Display-RAM um eins erhöht (und das auch wenn ich statt dem 1kHz Clock 
den Systemclock verwende).

Aber sobald ich eine Taste drücke wird nach und nach der komplette 
Bildschirm mit dem selben Buchstaben vollgeschrieben, was bedeutet das 
er die ganze Zeit die Schreibadresse für das Display-RAM erhöht.
Aber warum?

: Bearbeitet durch User
von Duke Scarring (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Daniel K. schrieb:
> Aber warum?

Weil Du immer noch mit Clock, statt Clock-Enable arbeitest.
> if(rising_edge(Clock_1kHz)) then

Versuch mal wirklich auf nur einen Clock umzusteigen:
if rising_edge( clock) then
  if enable_1kHz then
    ...
  end if;
end if; 

Duke

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
mmh das verstehe ich nicht so ganz.
Wie erzeugst du den dann das "Enable"? Dafür brauche ich doch auch nen 
Clock.

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Daniel K. schrieb:
> Wie erzeugst du den dann das "Enable"? Dafür brauche ich doch auch nen
> Clock.
So wie dort im Lauflicht:
http://www.lothar-miller.de/s9y/archives/61-Lauflicht.html

Oder dort in der PWM (unteres Drittel der Prescaler):
http://www.lothar-miller.de/s9y/categories/47-PWM

Oder so wie dort, wo gleich 3 unterschiedliche Clock-Enables erzeugt 
werden:
http://www.lothar-miller.de/s9y/archives/85-SAB0600.html

Der Trick: jedes der Designs läuft mit 1 einzigen Takt, dem des 
Quarzoszillators....

von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke für die Antworten.
Der Fehler war aber was ganz anderes :)
Ich hatte
if(PS2_Ready <= '1') then...

geschrieben ;)
Das das einen Fehler verursacht ist klar...wenn ich einem Signal nen 
High zuweise und dann nach High abfrage ist die If-Abfrage natürlich 
immer erfüllt...

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Daniel K. schrieb:
> wenn ich einem Signal nen High zuweise und dann nach High abfrage ist
> die If-Abfrage natürlich immer erfüllt...
Wo weist du dem Signal das High zu?
In der If-Abfrage kannst du nämlich nicht so einfach was zuweisen, wir 
sind hier ja nicht bei C. Es ist eher so, dass ein std_logic Signal, das 
nur '0' oder '1' sein kann, natürlich immer auch kleiner-gleich '1' 
ist...

: Bearbeitet durch Moderator
von Daniel K. (daniel_k80)


Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
> Daniel K. schrieb:
>> wenn ich einem Signal nen High zuweise und dann nach High abfrage ist
>> die If-Abfrage natürlich immer erfüllt...
> Wo weist du dem Signal das High zu?
> In der If-Abfrage kannst du nämlich nicht so einfach was zuweisen, wir
> sind hier ja nicht bei C. Es ist eher so, dass ein std_logic Signal, das
> nur '0' oder '1' sein kann, natürlich immer auch kleiner-gleich '1'
> ist...

Ah ok :)
Dachte es wäre in dem Fall identisch wie C, dass der Wert dann dem 
Signal zugewiesen wird.
Danke für die Korrektur :o

: Bearbeitet durch Moderator

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.