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 :)
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
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
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 :)
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
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.
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?
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,
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,
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 :)
Kannst Du die Testbench hier mit reinstellen? Dann kann man die Simulation nachvollziehen. Das macht vieles leichter. Duke
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
Ich verwende einen Block Memory Generator mit dem angehängten Initialisierungsfile.
Da muss doch trotzdem ein VHDL (oder verilog) File rausfallen. Sonst kann man das ja gra nicht simulieren. Duke
mmh ich weiß jetzt nicht welches VHDL File du meinst. Ich habe dir mal den Ordner hochgeladen...da kannst du dann mal gucken.
Der müßte es sein: VGA.srcs\sources_1\bd\Font_ROM\hdl\Font_ROM.vhd Na, schaun wir mal.
Wenn man in Zeile 29+1 (=Adresse 0x1d) des .mif-File was reinschreibt, kommt auch was raus. Duke
....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?
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.
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
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?!
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
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
mmh das verstehe ich nicht so ganz. Wie erzeugst du den dann das "Enable"? Dafür brauche ich doch auch nen Clock.
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....
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...
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.