Forum: FPGA, VHDL & Co. VDHL SSD1289 Display


von Timm A. (Gast)


Lesenswert?

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?

von Thomas T. (knibbel)


Lesenswert?

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

von Timm A. (Gast)


Lesenswert?

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
von Fitzebutze (Gast)


Lesenswert?

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 :-)

von Thomas T. (knibbel)


Lesenswert?

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)?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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
von Thomas T. (knibbel)


Lesenswert?

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

von Fpgakuechle K. (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.