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


von Daniel K. (daniel_k80)


Angehängte Dateien:

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. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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)


Lesenswert?

Wenn du des Englischen maechtig bist:

https://www.youtube.com/watch?v=EtJBqvk1ZZw

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

Gruss

Ralf

von Daniel K. (daniel_k80)


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)


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. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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)


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:
1
ClkSR     <= ClkSR(0)  & PS2_Clk;
2
3
if (ClkSR = "10") then
4
   ...
5
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)


Lesenswert?

Ja. Die "01" dient zum Erkennen der Flanke.

Duke

von Fpgakuechle K. (Gast)


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,

von Fpgakuechle K. (Gast)


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:

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)


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:

Lesenswert?

Ahh sorry.
Dachte ich hätte sie mit hoch geladen...

von Duke Scarring (Gast)


Lesenswert?

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

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

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

Duke

von Daniel K. (daniel_k80)


Lesenswert?

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

von Duke Scarring (Gast)


Lesenswert?

Zeig doch mal Deinen ROM.

Duke

von Daniel K. (daniel_k80)


Angehängte Dateien:

Lesenswert?

Ich verwende einen Block Memory Generator mit dem angehängten 
Initialisierungsfile.

von Duke Scarring (Gast)


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:

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)


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)


Lesenswert?

Quatsch. Keyboard_ROM.vhd natürlich...

von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

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

Duke

von Daniel K. (daniel_k80)


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. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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)


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:

Lesenswert?

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

PS/2-Keyboard
1
----------------------------------------------------------------------------------
2
-- Company:             www.kampis-elektroecke.de
3
-- Engineer:            Daniel Kampert
4
-- 
5
-- Create Date:         25.03.2015 07:09:28
6
-- Design Name: 
7
-- Module Name:         PS2_Keyboard_Ctrl - PS2_Keyboard_Ctrl_Arch
8
-- Project Name: 
9
-- Target Devices:      XC7Z010CLG400-1
10
-- Tool Versions:       Vivado 2014.4
11
-- Description:         PS/2-Controller for a PS/2-Keyboard
12
-- 
13
-- Dependencies: 
14
-- 
15
-- Revision:
16
-- Revision 0.01 - File Created
17
-- Additional Comments:
18
-- 
19
----------------------------------------------------------------------------------
20
21
library IEEE;
22
use IEEE.STD_LOGIC_1164.ALL;
23
24
-- Uncomment the following library declaration if using
25
-- arithmetic functions with Signed or Unsigned values
26
--use IEEE.NUMERIC_STD.ALL;
27
28
-- Uncomment the following library declaration if instantiating
29
-- any Xilinx leaf cells in this code.
30
--library UNISIM;
31
--use UNISIM.VComponents.all;
32
33
entity PS2_Keyboard_Ctrl is
34
    Port (  Clock       : in STD_LOGIC;
35
            PS2_Clock   : in STD_LOGIC;
36
            PS2_Data    : in STD_LOGIC;
37
            Data_Ready  : out STD_LOGIC := '0';
38
            Data_Read   : in STD_LOGIC;
39
            Reset       : in STD_LOGIC;
40
            Data_Out    : out STD_LOGIC_VECTOR(7 downto 0)
41
            );
42
end PS2_Keyboard_Ctrl;
43
44
architecture PS2_Keyboard_Ctrl_Arch of PS2_Keyboard_Ctrl is
45
46
    -- Eingangsschieberegister
47
    signal PS2_DataSR       : std_logic_vector(1 downto 0) := (others => '1');
48
    signal PS2_ClockSR      : std_logic_vector(1 downto 0) := (others => '1');
49
50
    signal Scancode         : std_logic_vector(7 downto 0);
51
    signal Input_Buffer     : std_logic_vector(10 downto 0) := (others=>'1');
52
53
    -- State-Machine definieren
54
    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);
55
    signal PS2_State    : PS2_StateType := RESET_STATE;
56
57
begin
58
59
    process(Clock)
60
    begin
61
        if(rising_edge(Clock)) then
62
63
            -- Eintakten des asynchronen PS/2-Signals
64
            PS2_DataSR  <= PS2_DataSR(0) & PS2_Data;
65
            PS2_ClockSR <= PS2_ClockSR(0) & PS2_Clock;
66
67
            -- Flankenerkennung am PS/2-Clock
68
            if(PS2_ClockSR = "10") then
69
                Input_Buffer <= PS2_DataSR(1) & Input_Buffer(10 downto 1);
70
            end if;
71
72
            case PS2_State is
73
                when RESET_STATE =>
74
75
                    -- Controller reseten
76
                    Data_Out <= (others => '0');
77
                    Data_Ready <= '0';
78
                    Input_Buffer <= (others => '1');
79
80
                    if(Reset = '0') then
81
                        PS2_State <= RESET_STATE; 
82
                    else
83
                        PS2_State <= WAIT_BYTE1; 
84
                    end if;                   
85
86
                when WAIT_BYTE1 =>
87
88
                    Input_Buffer <= (others => '1');
89
90
                    -- PS/2 Startbedingung erkannt
91
                    if((PS2_DataSR(1) = '0') and (PS2_ClockSR(1) = '1')) then
92
                        PS2_State <= RECEIVE_BYTE1;    
93
                    end if;   
94
95
                when RECEIVE_BYTE1 =>
96
97
                    -- Startbit bis zum Ende durchgeschoben?
98
                    if(Input_Buffer(0) = '0') then
99
                        Scancode <= Input_Buffer(8 downto 1);
100
                        PS2_State <= WAIT_BREAK1;  
101
                    end if;
102
103
                    if(Scancode = x"E0") then
104
                        PS2_State <= WAIT_BYTE2;    
105
                    end if;
106
107
                when WAIT_BYTE2 =>
108
109
                    Input_Buffer <= (others => '1'); 
110
111
                    if((PS2_DataSR(1) = '0') and (PS2_ClockSR(1) = '1')) then
112
                        PS2_State <= RECEIVE_BYTE2;    
113
                    end if; 
114
               
115
                when RECEIVE_BYTE2 =>   
116
117
                    if(Input_Buffer(0) = '0') then
118
                        Scancode <= Input_Buffer(8 downto 1);
119
                        PS2_State <= WAIT_BREAK1;  
120
                    end if;
121
122
                when WAIT_BREAK1 =>
123
124
                    Input_Buffer <= (others => '1');    
125
126
                    if((PS2_DataSR(1) = '0') and (PS2_ClockSR(1) = '1')) then
127
                        PS2_State <= RECEIVE_BREAK1;    
128
                    end if;   
129
130
                when RECEIVE_BREAK1 =>
131
132
                    if(Input_Buffer(0) = '0') then
133
                        PS2_State <= WAIT_BREAK2;  
134
                    end if;
135
                    
136
                when WAIT_BREAK2 =>
137
138
                    Input_Buffer <= (others => '1');    
139
140
                    if((PS2_DataSR(1) = '0') and (PS2_ClockSR(1) = '1')) then
141
                        PS2_State <= RECEIVE_BREAK2;    
142
                    end if;   
143
144
                when RECEIVE_BREAK2 =>
145
 
146
                    if(Input_Buffer(0) = '0') then                        
147
                        if(Input_Buffer(8 downto 1) = x"E0") then
148
                            PS2_State <= WAIT_BREAK3;
149
                        else    
150
                            PS2_State <= READY; 
151
                            Data_Ready <= '1';
152
                        end if; 
153
                    end if;                    
154
155
                when WAIT_BREAK3 =>
156
157
                    Input_Buffer <= (others => '1'); 
158
159
                    if((PS2_DataSR(1) = '0') and (PS2_ClockSR(1) = '1')) then
160
                        PS2_State <= RECEIVE_BREAK3;    
161
                    end if;    
162
 
163
                when RECEIVE_BREAK3 =>
164
165
                    if(Input_Buffer(0) = '0') then
166
                        PS2_State <= READY;
167
                        Data_Ready <= '1';  
168
                    end if;      
169
170
                when READY =>
171
172
                    -- Read-Handshake gesetzt - zurück in Ausgangszustand springen
173
                    if(Data_Read = '1') then
174
                        Data_Ready <= '0';
175
                        Data_Out <= Scancode;
176
                        PS2_State <= WAIT_BYTE1;  
177
                    end if;
178
                    
179
                    if(Reset = '0') then
180
                        PS2_State <= RESET_STATE; 
181
                    end if; 
182
183
            end case;        
184
        end if;
185
    end process;
186
end PS2_Keyboard_Ctrl_Arch;

Und die folgende TB:
1
----------------------------------------------------------------------------------
2
-- Company:             www.kampis-elektroecke.de
3
-- Engineer:            Daniel Kampert
4
-- 
5
-- Create Date:         25.03.2015 12:08:21
6
-- Design Name: 
7
-- Module Name:         PS2_Keyboard_TB - PS2_Keyboard_TB_Arch
8
-- Project Name: 
9
-- Target Devices:      XC7Z010CLG400-1
10
-- Tool Versions:       Vivado 2014.4
11
-- Description:         Testbench for PS/2-Keyboard Interface
12
-- 
13
-- Dependencies: 
14
-- 
15
-- Revision:
16
-- Revision 0.01 - File Created
17
-- Additional Comments:
18
-- 
19
----------------------------------------------------------------------------------
20
21
library IEEE;
22
use IEEE.STD_LOGIC_1164.ALL;
23
24
-- Uncomment the following library declaration if using
25
-- arithmetic functions with Signed or Unsigned values
26
--use IEEE.NUMERIC_STD.ALL;
27
28
-- Uncomment the following library declaration if instantiating
29
-- any Xilinx leaf cells in this code.
30
library UNISIM;
31
use UNISIM.VComponents.all;
32
33
entity PS2_Keyboard_TB is
34
end PS2_Keyboard_TB;
35
36
architecture PS2_Keyboard_TB_Arch of PS2_Keyboard_TB is
37
38
    -- PS/2 Sendefunktion
39
    procedure Send_PS2( signal Data :  in std_logic_vector(7 downto 0); 
40
                        signal PS2_Clock : out std_logic;
41
                        signal PS2_Data : out std_logic) is
42
43
        variable Paritaet : std_logic := '1';
44
        
45
    begin
46
47
        -- Startbit senden
48
        PS2_Data <= '0';
49
        wait for 20 us;
50
        PS2_Clock <= '0';
51
        wait for 40 us;
52
        PS2_Clock <= '1';
53
        wait for 20 us;
54
            
55
        -- Datenbits senden
56
        Paritaet := '1';
57
        for Counter in 0 to 7 loop
58
            PS2_Data <= Data(Counter);
59
                if(Data(Counter) = '1') then 
60
                   Paritaet := not Paritaet; 
61
                end if;
62
            wait for 20 us;
63
            PS2_Clock  <= '0';
64
            wait for 40 us;
65
            PS2_Clock  <= '1';
66
            wait for 20us;
67
        end loop;    
68
        
69
        -- Parität senden
70
        PS2_Data <= Paritaet;
71
        wait for 20 us;
72
        PS2_Clock  <= '0';
73
        wait for 40 us;
74
        PS2_Clock  <= '1';
75
        wait for 20 us;
76
        
77
        -- Stoppbit senden
78
        PS2_Data <= '1';
79
        wait for 20 us;
80
        PS2_Clock  <= '0';
81
        wait for 40 us;
82
        PS2_Clock  <= '1';
83
        wait for 20 us;  
84
    end procedure;
85
 
86
    -- Systemtakt
87
    constant Periode    : time := 200 ns;
88
    signal Clock        : std_logic := '0';
89
90
    -- PS/2 Signale
91
    signal PS2Clock    : std_logic := '1';
92
    signal PS2Data     : std_logic := '1';
93
    
94
    -- Steuersignale
95
    signal Ready        : std_logic := '0';
96
    signal Read         : std_logic := '0';
97
    signal Reset        : std_logic := '0';
98
    
99
    -- Scancode vom Keyboard
100
    signal Data_Out     : std_logic_vector(7 downto 0) := (others => '0');
101
    signal Scancode     : std_logic_vector(7 downto 0) := (others => '0');
102
103
    component PS2_Keyboard
104
        Port (  Clock       : in STD_LOGIC;                                     
105
                PS2_Clock   : in STD_LOGIC;                                     
106
                PS2_Data    : in STD_LOGIC;                                    
107
                Data_Ready  : out STD_LOGIC;                                   
108
                Data_Read   : in STD_LOGIC;                                     
109
                Reset       : in STD_LOGIC;                                     
110
                Data        : out STD_LOGIC_VECTOR(7 downto 0)                  
111
                );
112
    end component;    
113
    
114
begin
115
116
    Keyboard : PS2_Keyboard port map(Clock, PS2Clock, PS2Data, Ready, Read, Reset, Data_Out);
117
118
    -- 25MHz Clock
119
    Clock <= not Clock after Periode / 2;
120
    
121
    process
122
    begin   
123
  
124
        -- Controller reseten
125
        Reset <= '1';
126
        wait for 100 us;
127
        Reset <= '0';
128
        wait for 100 us;
129
        Reset <= '1';
130
        wait for 100 us;        
131
132
        -- Bustaben "W" senden
133
        Scancode <= x"1D";
134
        Send_PS2(Scancode, PS2Clock, PS2Data);
135
        wait for 100 us;           
136
137
        -- Break-Code senden
138
        Scancode <= x"F0";
139
        Send_PS2(Scancode, PS2Clock, PS2Data);
140
        wait for 100 us; 
141
        Scancode <= x"1D";
142
        Send_PS2(Scancode, PS2Clock, PS2Data);
143
        wait for 100 us; 
144
        
145
        -- Zeichen auslesen
146
        if(Ready = '1') then
147
            Read <= '1';
148
        else
149
            Read <= '0';
150
        end if;
151
        
152
        wait for 10 ms;
153
        
154
        Scancode <= x"1B";
155
        Send_PS2(Scancode, PS2Clock, PS2Data);
156
        wait for 100 us;        
157
        Scancode <= x"F0";
158
        Send_PS2(Scancode, PS2Clock, PS2Data);
159
        wait for 100 us; 
160
        Scancode <= x"1B";
161
        Send_PS2(Scancode, PS2Clock, PS2Data);
162
        wait for 100 us; 
163
        
164
        -- Zeichen auslesen
165
        if(Ready = '1') then
166
            Read <= '1';
167
        else
168
            Read <= '0';
169
        end if;
170
         
171
        wait for 10 ms;
172
         
173
        Scancode <= x"1C";
174
        Send_PS2(Scancode, PS2Clock, PS2Data);
175
        wait for 100 us;        
176
        Scancode <= x"F0";
177
        Send_PS2(Scancode, PS2Clock, PS2Data);
178
        wait for 100 us; 
179
        Scancode <= x"1C";
180
        Send_PS2(Scancode, PS2Clock, PS2Data);
181
        wait for 100 us;
182
           
183
        -- Zeichen auslesen
184
        if(Ready = '1') then
185
            Read <= '1';
186
        else
187
            Read <= '0';
188
        end if;
189
                           
190
        wait for 1000 ms;
191
192
    end process;  
193
194
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)


Lesenswert?

Hat sich erledigt. War wohl leicht spät gestern Abend....

von Daniel K. (daniel_k80)


Angehängte Dateien:

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
1
        Div_1kHz        : Clock_Divider port map (Clock_VGA, Clock_1kHz, 25000);
2
    IO              : Entprellen port map (Clock_VGA, Tasten, Tasten_Out);
3
    DCM             : Clock port map (Clock_VGA, Clock_In, Clock_Lock, Reset, Clock_System);
4
    VGA_Top         : VGA port map (Clock_VGA, Reset, Mode, Read_Write, Display_Write_Data, std_logic_vector(Display_Write_Addr), HSync, VSync, RGB);
5
    Tastatur        : PS2_Keyboard port map(Clock_System, PS2_Clock, PS2_Data, PS2_Ready, PS2_Read, Reset, PS2_Data_Out);
6
   Display_Write_Data <= x"F800" & PS2_Data_Out;
7
    
8
    process(Clock_1kHz)
9
    begin
10
        if(rising_edge(Clock_1kHz)) then
11
            if(PS2_Ready <= '1') then
12
                Display_Write_Addr <= Display_Write_Addr + 1;   
13
                Read_Write <= '1';
14
                PS2_Read <= '1';                
15
            else
16
                Read_Write <= '0';
17
                PS2_Read <= '0';      
18
            end if;  
19
        end if;    
20
    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)


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:
1
if rising_edge( clock) then
2
  if enable_1kHz then
3
    ...
4
  end if;
5
end if;

Duke

von Daniel K. (daniel_k80)


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. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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)


Lesenswert?

Hallo,

danke für die Antworten.
Der Fehler war aber was ganz anderes :)
Ich hatte
1
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. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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)


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
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.