Hallo Kollegen, wer hat Erfahrung mit der Ansteuerung eines Grafikdisplays mit einem SSD1289 Controller in VHDL ? In C gibt es ja massig Routinen, aber für VHDL hab ich keine einzige gefunden. Ich versuche das ganze mit einem DE0- Nano Board anzusteuern. Das Display hat die Anschlüsse D0-D15, CS, REST, RD, WR und RS. Meine Initialisierungsroutine habe ich in ein Array abgelegt. Hier ein Auszug: Ports: DispDataOUT : out STD_LOGIC_VECTOR(15 downto 0); DispRD : out STD_LOGIC; DispCS : out STD_LOGIC; DispWR : out STD_LOGIC; DispDC : out STD_LOGIC; ...... type disp_init is array (0 to 76) of std_logic_vector(19 downto 0); signal disp_init_array: disp_init:=( -- MSB <= [D15....D0, RD, CS, WR, D/C] =>LSB "00000000 00000111 1100", -- adress register 7 "00000000 00000111 1000", --CS low "00000000 00000111 1100", -- reg R07h angesprochen "00000000 00100001 1101", -- write 21h into register 7h "00000000 00100001 1001", -- cs low "00000000 00100001 1101", --21h in register 7h geschrieben usw...... In einer State-Machine: if lcd_init_counter<24 then DispDat(19 downto 0) <=disp_init_array(lcd_init_counter); end if; lcd_init_counter<=lcd_init_counter+1; Ich habe also ein 16 bit paralleles Interface, lasse bei einem Schreibbefehl RD immer auf High und steuere meine Commandos mit CS. Das Array gehe ich nacheinander mit einem langsamen Takt durch. Leider bleibt das Display dauerhaft weiß. Was mache ich falsch?? Wer kann mir helfen?
Wieso kommen mir da sofort die folgenden Fragen in den Kopf: * Was sagt die Simulation? * Hast Du Dir mal mindestens CS auf'n Scope angeschaut? * Wieso fehlt immer mehr der Elan, Fehler selbst zu finden (und dann nicht einmal alle Infos bereitzustellen: Wo ist die VHDL-Beschreibung)? Vielleicht reicht ein Zähler von 0 bis 23 auch nicht aus, wenn das Array von 0 bis 76 geht... Gruß und schöne Ostern, Thomas
Ich dachte ein Auszug des Codes wäre zielstrebender, aber bitte.....
1 | library IEEE; |
2 | use IEEE.STD_LOGIC_1164.ALL; |
3 | use IEEE.NUMERIC_STD.ALL; |
4 | |
5 | |
6 | entity SpectrumAnalyzer is |
7 | |
8 | Port ( CLOCK_50 : in STD_LOGIC; --Board Clock |
9 | DOUT : out STD_LOGIC; --ADC Channel selection |
10 | ADC_IN : in STD_LOGIC; -- ADC Data |
11 | CS : out STD_LOGIC; -- Chip Select ADC |
12 | SCLK : out STD_LOGIC; -- SERIAL CLOCK FOR ADC |
13 | LEDS : out STD_LOGIC_VECTOR(7 downto 0); -- Debugging with LEDS |
14 | |
15 | DispDataOUT : out STD_LOGIC_VECTOR(15 downto 0); |
16 | DispRD : out STD_LOGIC; |
17 | DispCS : out STD_LOGIC; |
18 | DispWR : out STD_LOGIC; |
19 | DispDC : out STD_LOGIC ); |
20 | end SpectrumAnalyzer; |
21 | |
22 | |
23 | |
24 | architecture Behavioral of SpectrumAnalyzer is |
25 | |
26 | TYPE STATE_TYPE is (default, Start, DB11, DB10, DB9, DB8, DB7, DB6, DB5, DB4, DB3, DB2, DB1, DB0); -- ADC STATE MACHINE |
27 | signal ADC_DATA : STATE_TYPE :=default; --ADC Daten state machine |
28 | |
29 | TYPE SPEICHER is array (0 to 1023) of std_logic_vector(11 downto 0); |
30 | signal FRAME : SPEICHER; --array für bilddarstellung |
31 | |
32 | TYPE STATE_TYPE2 is (ONE, TWO, THREE, FOUR, FIVE); --haupt state machine |
33 | signal STATE_MACHINE : STATE_TYPE2 := ONE; |
34 | |
35 | signal framedatumzaehler: integer range 0 to 1023:=0; --zählt hoch, bis FRAME mit adc werten voll ist |
36 | |
37 | --display initialisierung
|
38 | -- MSB <= [D15....D0, RD, CS, WR, D/C] =>LSB
|
39 | type disp_init is array (0 to 76) of std_logic_vector(19 downto 0); |
40 | signal disp_init_array: disp_init:=( |
41 | |
42 | "00000000000001111100", -- adress register 7 |
43 | "00000000000001111000", --CS low |
44 | "00000000000001111100", -- reg R07h angesprochen |
45 | |
46 | "00000000001000011101", -- write 21h into register 7h |
47 | "00000000001000011001", -- cs low |
48 | "00000000001000011101", --21h in register 7h geschrieben |
49 | --next
|
50 | |
51 | "00000000000000001100", -- adress 00h |
52 | "00000000000000001000", |
53 | "00000000000000001100", --00h adressed |
54 | |
55 | "00000000000000011101", --write 1h in 00h |
56 | "00000000000000011001", |
57 | "00000000000000011101", --1h written |
58 | --next
|
59 | |
60 | "00000000000001111100", --set R07h at 0023h |
61 | "00000000000001111000", --CS low |
62 | "00000000000001111100", |
63 | |
64 | "00000000001000111101", |
65 | "00000000001000111001", -- |
66 | "00000000001000111101", --0023h in R07h written |
67 | -- next
|
68 | |
69 | "00000000000100001100", --set R10h at 000h |
70 | "00000000000100001000", |
71 | "00000000000100001100", |
72 | |
73 | "00000000000000001101", |
74 | "00000000000000001001", |
75 | "00000000000000001101", --00h in R10h written |
76 | --next
|
77 | |
78 | "00000000000000000000", --dummy data --24 |
79 | -- 30ms warten....zähler in state machine einbauen
|
80 | --next
|
81 | |
82 | "00000000000001111100", --set R07h at 0033h |
83 | "00000000000001111000", |
84 | "00000000000001111100", |
85 | |
86 | "00000000001100111101", |
87 | "00000000001100111001", |
88 | "00000000001100111101",--0033h in R07h written |
89 | -- next
|
90 | |
91 | "00000000000100011100", --entry mode setting R11h |
92 | "00000000000100011000", |
93 | "00000000000100011100", |
94 | |
95 | "01101000001100001101", -- write data in r11h |
96 | "01101000001100001001", |
97 | "01101000001100001101", |
98 | -- next
|
99 | |
100 | "00000000000000101100", --lcd driver AC setting R02h |
101 | "00000000000000101000", |
102 | "00000000000000101100", |
103 | |
104 | "00000000000000001101", |
105 | "00000000000000001001", |
106 | "00000000000000001101",-- write data 0000000 |
107 | -- next
|
108 | ---write ram data
|
109 | |
110 | --testweise ein pixel setzen
|
111 | "00000000010011101100", --set RAM adress R4Eh (X_POS) |
112 | "00000000010011101000", |
113 | "00000000010011101100", |
114 | |
115 | "00000000000011101101", |
116 | "00000000000011101001", |
117 | "00000000000011101101",--10dec in RAM adress R4Eh |
118 | -- next
|
119 | |
120 | "00000000010011111100", --set RAM adress R4Fh (Y_POS) |
121 | "00000000010011111000", |
122 | "00000000010011111100", |
123 | |
124 | "00000000000011101101", |
125 | "00000000000011101001", |
126 | "00000000000011101101",-- 10dec in RAM adress R4Fh |
127 | -- next
|
128 | |
129 | "00000000001000101100", --adress GRAM Data R22h |
130 | "00000000001000101000", |
131 | "00000000001000101100", |
132 | |
133 | "11111000000000001101",-- start with first pixel |
134 | "11111000000000001001", |
135 | "11111000000000001101", |
136 | -- next
|
137 | |
138 | "00000111111000001101", -- start with second pixel |
139 | "00000111111000001001", |
140 | "00000111111000001101", |
141 | -- next
|
142 | |
143 | "00000000000111111101", -- start with third pixel |
144 | "00000000000111111001", |
145 | "00000000000111111101", |
146 | |
147 | "11111000000000001101",-- start with first pixel |
148 | "11111000000000001001", |
149 | "11111000000000001101", |
150 | -- next
|
151 | |
152 | "00000111111000001101", -- start with second pixel |
153 | "00000111111000001001", |
154 | "00000111111000001101", |
155 | -- next
|
156 | |
157 | "00000000000111111101", -- start with third pixel |
158 | "00000000000111111001", |
159 | "00000000000111111101", |
160 | |
161 | "00000000000000000000"); --dummy data --76 |
162 | |
163 | |
164 | |
165 | signal lcd_init_counter : integer range 0 to 76:=0; |
166 | signal lcd_wait30ms : integer range 0 to 100000:=1; |
167 | signal DispDat: std_logic_vector(19 downto 0); --signal from array to pins |
168 | |
169 | |
170 | signal CS_sig : std_logic:='1'; --chip select |
171 | signal subcounter: integer range 0 to 16:=0; --50MHz/16 = 3.125 MHz -> 195,3 kHz für Datenaustakten bei 16 bit pro datenaustaktung |
172 | signal SCLK_sig: std_logic:='1'; -- serial clock |
173 | signal counthilo: integer range 0 to 32:=0; -- Taktflankenzähler für ADC |
174 | signal DATEN: std_logic_vector(11 downto 0):="000000000000"; --ADC Daten |
175 | signal DIN : std_logic:='0'; --ADC input |
176 | signal DATAREADY: std_logic:='0'; -- ist high, wenn Datum eingelesen wurde |
177 | signal CLOCK_sig: std_logic; -- signal des board clocks |
178 | signal DOUT_sig : std_logic:='0'; -- channel output |
179 | |
180 | begin
|
181 | |
182 | |
183 | process (CLOCK_sig) |
184 | begin
|
185 | |
186 | if CLOCK_sig='1' AND CLOCK_sig'Event then |
187 | |
188 | if subcounter<15 then |
189 | subcounter<=subcounter+1; |
190 | else
|
191 | subcounter<=0; |
192 | end if; |
193 | |
194 | |
195 | case ADC_DATA is |
196 | |
197 | when default => CS_sig<='1'; |
198 | SCLK_sig<='1'; |
199 | counthilo<=0; |
200 | ADC_DATA<=Start; |
201 | |
202 | when Start => CS_sig<='0'; |
203 | if subcounter=0 then --vereinfachter Übergang |
204 | ADC_DATA<=DB11; |
205 | end if; |
206 | |
207 | when DB11 => if subcounter=0 then |
208 | SCLK_sig<= not SCLK_sig; |
209 | counthilo<=counthilo+1; |
210 | end if; |
211 | if counthilo=10 AND subcounter=0 then |
212 | Daten(11)<=DIN; |
213 | ADC_DATA<=DB10; |
214 | end if; |
215 | |
216 | when DB10=> if subcounter=0 then |
217 | SCLK_sig<= not SCLK_sig; |
218 | counthilo<=counthilo+1; |
219 | end if; |
220 | if counthilo=12 AND subcounter=0 then |
221 | Daten(10)<=DIN; |
222 | ADC_Data<=DB9; |
223 | end if; |
224 | |
225 | when DB9 => if subcounter=0 then |
226 | SCLK_sig<= not SCLK_sig; |
227 | counthilo<=counthilo+1; |
228 | end if; |
229 | if counthilo=14 AND subcounter=0 then |
230 | Daten(9)<=DIN; |
231 | ADC_Data<=DB8; |
232 | end if; |
233 | |
234 | when DB8 => if subcounter=0 then |
235 | SCLK_sig<= not SCLK_sig; |
236 | counthilo<=counthilo+1; |
237 | end if; |
238 | if counthilo=16 AND subcounter=0 then |
239 | Daten(8)<=DIN; |
240 | ADC_DATA<=DB7; |
241 | end if; |
242 | |
243 | when DB7 => if subcounter=0 then |
244 | SCLK_sig<= not SCLK_sig; |
245 | counthilo<=counthilo+1; |
246 | end if; |
247 | if counthilo=18 AND subcounter=0 then |
248 | Daten(7)<=DIN; |
249 | ADC_Data<=DB6; |
250 | end if; |
251 | |
252 | when DB6 => if subcounter=0 then |
253 | SCLK_sig<= not SCLK_sig; |
254 | counthilo<=counthilo+1; |
255 | end if; |
256 | if counthilo=20 AND subcounter=0 then |
257 | Daten(6)<=DIN; |
258 | ADC_Data<=DB5; |
259 | end if; |
260 | |
261 | when DB5 => if subcounter=0 then |
262 | SCLK_sig<= not SCLK_sig; |
263 | counthilo<=counthilo+1; |
264 | end if; |
265 | if counthilo=22 AND subcounter=0 then |
266 | Daten(5)<=DIN; |
267 | ADC_DATA<=DB4; |
268 | end if; |
269 | |
270 | when DB4 => if subcounter=0 then |
271 | SCLK_sig<= not SCLK_sig; |
272 | counthilo<=counthilo+1; |
273 | end if; |
274 | if counthilo=24 AND subcounter=0 then |
275 | Daten(4)<=DIN; |
276 | ADC_Data<=DB3; |
277 | end if; |
278 | |
279 | when DB3 => if subcounter=0 then |
280 | SCLK_sig<= not SCLK_sig; |
281 | counthilo<=counthilo+1; |
282 | end if; |
283 | if counthilo=26 AND subcounter=0 then |
284 | Daten(3)<=DIN; |
285 | ADC_Data<=DB2; |
286 | end if; |
287 | |
288 | when DB2 => if subcounter=0 then |
289 | SCLK_sig<= not SCLK_sig; |
290 | counthilo<=counthilo+1; |
291 | end if; |
292 | if counthilo=28 AND subcounter=0 then |
293 | Daten(2)<=DIN; |
294 | ADC_DATA<=DB1; |
295 | end if; |
296 | |
297 | when DB1 => if subcounter=0 then |
298 | SCLK_sig<= not SCLK_sig; |
299 | counthilo<=counthilo+1; |
300 | end if; |
301 | if counthilo=30 AND subcounter=0 then |
302 | Daten(1)<=DIN; |
303 | ADC_Data<=DB0; |
304 | end if; |
305 | |
306 | when DB0 => if subcounter=0 AND counthilo<32 then |
307 | SCLK_sig<= not SCLK_sig; |
308 | counthilo<=counthilo+1; |
309 | end if; |
310 | if counthilo=32 AND subcounter=0 then |
311 | Daten(0)<=DIN; |
312 | ADC_Data<=DB11; |
313 | DATAREADY<='1'; |
314 | counthilo<=1; |
315 | SCLK_sig<= not SCLK_sig; |
316 | end if; |
317 | |
318 | end case; |
319 | |
320 | |
321 | if subcounter=0 then -- langsamere schleife für statemachine |
322 | |
323 | case STATE_MACHINE is |
324 | |
325 | when ONE => framedatumzaehler<=0; |
326 | lcd_init_counter<=0; |
327 | lcd_wait30ms<=0; |
328 | |
329 | STATE_MACHINE<=THREE; |
330 | |
331 | |
332 | |
333 | |
334 | when TWO => if DATAREADY='1' then |
335 | FRAME(framedatumzaehler)<=Daten; --daten von adc in frame speichern |
336 | DATAREADY<='0'; |
337 | end if; |
338 | if framedatumzaehler<1023 then |
339 | framedatumzaehler<=framedatumzaehler+1; |
340 | else
|
341 | STATE_MACHINE<=THREE; --wenn frame mit adc werten voll -> next state |
342 | end if; |
343 | |
344 | |
345 | when THREE => |
346 | if lcd_init_counter<24 then |
347 | -- MSB <= [D15....D0, RD, CS, WR, D/C] =>LSB
|
348 | DispDat(19 downto 0) <=disp_init_array(lcd_init_counter); |
349 | |
350 | elsif lcd_init_counter=24 then --wait 30ms |
351 | |
352 | if lcd_wait30ms<90000 then |
353 | lcd_wait30ms<=lcd_wait30ms+1; |
354 | else
|
355 | lcd_init_counter<=lcd_init_counter+1; |
356 | end if; |
357 | |
358 | elsif lcd_init_counter>24 then |
359 | |
360 | DispDat(19 downto 0) <= disp_init_array(lcd_init_counter); |
361 | |
362 | |
363 | if lcd_init_counter=76 then |
364 | STATE_MACHINE<=FOUR; |
365 | end if; |
366 | |
367 | end if; |
368 | lcd_init_counter<=lcd_init_counter+1; |
369 | |
370 | |
371 | when FOUR => |
372 | |
373 | |
374 | |
375 | |
376 | when FIVE => STATE_MACHINE<=FIVE; |
377 | |
378 | |
379 | end case; |
380 | |
381 | end if; |
382 | |
383 | |
384 | end if; |
385 | |
386 | |
387 | end process; |
388 | |
389 | CLOCK_sig <= CLOCK_50; |
390 | DOUT <= DOUT_sig; |
391 | DIN <= ADC_IN; |
392 | CS<= CS_sig; |
393 | SCLK <= SCLK_sig; |
394 | |
395 | DispDataOUT <= DispDat(19 downto 4); |
396 | DispRD <= DispDat (3); |
397 | DispCS <= DispDat (2); |
398 | DispWR <= DispDat (1); |
399 | DispDC <= DispDat (0); |
400 | |
401 | LEDS(7) <= DispDat(7); |
402 | LEDS(6) <= DispDat(6); |
403 | LEDS(5) <= DispDat(5); |
404 | LEDS(4) <= DispDat(4); |
405 | LEDS(3) <= DispDat(3); |
406 | LEDS(2) <= DispDat(2); |
407 | LEDS(1) <= DispDat(1); |
408 | LEDS(0) <= DispDat(0); |
409 | |
410 | end Behavioral; |
:
Bearbeitet durch Moderator
Moin, ich kann nur wärmstens empfehlen, die Sache mit einer simplen CPU zu erschlagen und nur das asynchrone Memory-Interface in VHDL zu implementieren, so dass unabhängig vom Bus-Clock die Timings richtig eingehalten werden. Dann ist die Sache auch portabel und wiederverwertbar... Nicht böse sein, aber solche Code-Dumps sind anstrengend, und werden von mir prinzipiell nicht gelesen :-)
Timm A. schrieb: > if lcd_init_counter=76 then > STATE_MACHINE<=FOUR; > end if; > > end if; > lcd_init_counter<=lcd_init_counter+1; > > when FOUR => > > when FIVE => STATE_MACHINE<=FIVE; > > end case; Kann man das so machen? Fehlt hinter "when FOUR =>" nicht noch was? Was sagen denn die LEDs (wenn du Sub_Counter mal ein paar Bits mehr spendierst)?
Timm A. schrieb: > Ich dachte ein Auszug des Codes wäre zielstrebender, aber bitte..... Wenn du den Text direkt über dem Eingagefenster liest, dann siehst du das hier:
1 | Antwort schreiben |
2 | Wichtige Regeln - erst lesen, dann posten! |
3 | Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang |
Also: VHDL File anhängen mit Dateiendung .vhd oder .vhdl. Und wenn das schon nicht sein soll, dann wenigstens das hier:
1 | Formatierung (mehr Informationen...) |
2 | [vhdl]VHDL-Code[/vhdl] |
Thomas T. schrieb: > Kann man das so machen? Fehlt hinter "when FOUR =>" nicht noch was? Man kann es machen. Beim Zustand FOUR passiert aber (im Gegensatz zu C!!) rein gar nichts. Es passiert also nicht das selbe wie im Zustand FIVE. Das hier:
1 | LEDS(7) <= DispDat(7); |
2 | LEDS(6) <= DispDat(6); |
3 | LEDS(5) <= DispDat(5); |
4 | LEDS(4) <= DispDat(4); |
5 | LEDS(3) <= DispDat(3); |
6 | LEDS(2) <= DispDat(2); |
7 | LEDS(1) <= DispDat(1); |
8 | LEDS(0) <= DispDat(0); |
Kann man so abkürzen:
1 | LEDS <= DispDat(7 downto 0); |
Das sind übrigens mal echt unnütze und nichtssagende Namen:
1 | TYPE STATE_TYPE2 is (ONE, TWO, THREE, FOUR, FIVE); --haupt state machine |
Da hättest du doch gleich einfach einen "integer range 1 to 5" nehmen können...
:
Bearbeitet durch Moderator
Hallo, vielleicht liegt es ja auch nur an einer nicht korrekten UCF-Datei. Deshalb kann ich mich nur wiederholen: Beobachte mal mit einem Scope das Wackeln der Pins. Wenn kein Scope vorhanden, dann tut es auch eine LED, wenn man den Takt massiv verringert... Gruß, Thomas
Lothar Miller schrieb: > Thomas T. schrieb: >> Kann man das so machen? Fehlt hinter "when FOUR =>" nicht noch was? > Man kann es machen. Beim Zustand FOUR passiert aber (im Gegensatz zu > C!!) rein gar nichts. Es passiert also nicht das selbe wie im Zustand > FIVE. Bedeutet "es passiert rein garnichts" das auch kein Zustandsübergang passiert - die FSM also im Zustand "Four" festhängt? Wenn ja, ist das beabsichtigt? MfG, BTW: Zustand "TWO" scheint auch nie erreicht zu werden.
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.