Forum: FPGA, VHDL & Co. Ansteuerung Grafic Display


von Ralf (Gast)


Lesenswert?

Hallo,

ich möchte eine grafische LCD 128x64 per
von einem FPGA ansteuern. Dieses enthält
zwei KS0108B Chips von Samsung jeweils für
eine Hälfte des Displays. Ich habe aber nun
ein Problem, dass keine Zeichen auf dem Display
erscheinen. Ich habe mich mit dem Timing
an das Datenblatt des KS0108b Chip gehalten.
Das Timing sieht auf dem Osziloskop auch
vernünftig aus. Trotzdem sieh man nichts
auf dem Display. Hat schon mal jemand
so ein grafisches Display mit einem FPGA
angesteuert und könnte mir eventuell Tips
geben was man dabei beachten muss. Oder
eventuell ein Beispiel oder Link für eine
Applikation mit einem LCD-FPGA.
Vielen Dank.


Gruß

Ralf

von Uwe N. (ex-aetzer)


Lesenswert?

Wenn du Hilfe benötigst, dann brauchen die Leute hier mehr Infos:
1. dein VHDL-Code
2. Schematic
3. wenn möglich, Foto vom Aufbau

Gruss Uwe

von Ralf (Gast)


Lesenswert?

Ja, hast natürlich recht. Ich dachte
nur es hat jemand vielleicht Erfahrung
wegen kritischem Timing oder so.
Ich habe mal den VHDL Code angehängt.
Der erste Teil ist die Befehlssequenz zum
Lesen und Schreiben. Der Zweite Teil stellt
dann die höheren Befehle zur Verfügung.

1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4
5
entity ks0108b_ctrl is
6
  generic (
7
    RESET_ACTIVE  : std_logic             := '0';
8
    WAIT_POWER_UP : unsigned(12 downto 0) := to_unsigned(3000, 13);  -- 15 ms @ 50 MHz
9
    WAIT_T1       : unsigned(12 downto 0) := to_unsigned(18, 13);    -- 360 ns @ 50 MHz
10
    WAIT_T2       : unsigned(12 downto 0) := to_unsigned(8, 13);     -- 150 ns @ 50 MHz
11
    WAIT_T3       : unsigned(12 downto 0) := to_unsigned(26, 13);    -- 510 ns @ 50 MHz
12
    WAIT_T4       : unsigned(12 downto 0) := to_unsigned(3, 13);     --  30 ns @ 50 MHz
13
    WAIT_T5       : unsigned(12 downto 0) := to_unsigned(2, 13)      --  20 ns @ 50 MHz
14
  );
15
  port (
16
    clk      : in std_logic;                    -- System Clock
17
    rst      : in std_logic;                    -- asynchronous Reset, active high
18
    data_out : in std_logic_vector(7 downto 0); -- Input data
19
    data_in  : out std_logic_vector(7 downto 0);
20
    dval     : in std_logic;                    -- Write Data command (1 clock cycle)
21
    rs       : in std_logic;                    -- Data or Command
22
    rw       : in std_logic;                    -- read or write command
23
    busy     : out std_logic;                   -- '1' if device busy
24
    -- LCD signals
25
    glcd_db_in   : in  std_logic_vector(7 downto 0);
26
    glcd_db_out  : out std_logic_vector(7 downto 0);
27
    glcd_db_enab : out std_logic;
28
    glcd_e       : out std_logic;
29
    glcd_reset   : out std_logic;
30
    glcd_rw      : out std_logic;
31
    glcd_di      : out std_logic;
32
    glcd_cs      : out std_logic
33
  );
34
end ks0108b_ctrl;
35
36
37
architecture behavioral of ks0108b_ctrl is
38
39
  type State_type is (sINIT, sIDLE, sWAIT_T1, sWAIT_T2, sWAIT_T3, sWAIT_T4, sWAIT_T5);
40
  signal ctlState : State_type;
41
42
  signal timer : unsigned(12 downto 0);
43
44
begin
45
  process (clk, rst)
46
  begin
47
    if (rst = RESET_ACTIVE) then
48
      busy         <= '1';
49
      data_in      <= (others => '0');
50
      glcd_db_out  <= (others => '1');
51
      glcd_e       <= '1';
52
      glcd_reset   <= '0';
53
      glcd_rw      <= '1';
54
      glcd_di      <= '1';
55
      glcd_db_enab <= '0';
56
      glcd_cs      <= '1';
57
      timer        <= (others => '0');
58
      ctlState     <= sINIT;
59
    elsif rising_edge(clk) then
60
      case ctlState is
61
        when sINIT =>      -- Power up wait 15 ms
62
          glcd_reset <= '0';
63
          timer      <= timer + 1;
64
          if (timer = WAIT_POWER_UP) then
65
            ctlState <= sIDLE;
66
          end if;
67
68
        when sIDLE =>
69
          glcd_reset   <= '1';
70
          busy         <= '0';
71
          glcd_e       <= '1';
72
          glcd_db_enab <= '0';
73
74
          if (dval = '1') then
75
            busy        <= '1';
76
            glcd_e      <= '0';
77
            glcd_db_out <= data_out;
78
            timer       <= (others => '0');
79
            ctlState    <= sWAIT_T1;
80
          end if;
81
82
        when sWAIT_T1 =>
83
          timer <= timer + 1;
84
          if (timer = WAIT_T1) then
85
            glcd_rw  <= rw;
86
            glcd_di  <= rs;
87
            glcd_cs  <= '0';
88
            timer    <= (others => '0');
89
            ctlState <= sWAIT_T2;
90
          end if;
91
        
92
        when sWAIT_T2 =>
93
          timer <= timer + 1;
94
          if (timer = WAIT_T2) then
95
            glcd_e <= '1';
96
            if (rw = '0') then
97
              glcd_db_enab <= '1';
98
            end if;
99
            timer    <= (others => '0');
100
            ctlState <= sWAIT_T3;
101
          end if;
102
103
        when sWAIT_T3 =>
104
          timer <= timer + 1;
105
          if (timer = WAIT_T3) then
106
            glcd_e   <= '0';
107
            if (rw = '1') then
108
              data_in <= glcd_db_in;
109
            end if;
110
            timer    <= (others => '0');
111
            ctlState <= sWAIT_T4;
112
          end if;
113
114
        when sWAIT_T4 =>
115
          timer <= timer + 1;
116
          if (timer = WAIT_T4) then
117
            glcd_cs  <= '1';
118
            glcd_di  <= '1';
119
            glcd_rw  <= '1';
120
            timer    <= (others => '0');
121
            ctlState <= sWAIT_T5;
122
          end if;
123
124
        when sWAIT_T5 =>
125
          timer <= timer + 1;
126
          if (timer = WAIT_T5) then
127
            glcd_e   <= '1';
128
            ctlState <= sIDLE;
129
          end if;
130
131
        when others =>
132
          ctlState <= sIDLE;
133
      end case;
134
    end if;
135
  end process;
136
end behavioral;


Ich hoffe ihr könnt damit was anfangen.
Laut Simulation ist auch alles in Ordnung.

1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4
5
entity ks0108b_cmd is
6
  generic (
7
    RESET_ACTIVE        : std_logic             := '0';  -- Polaritaet fuer Reset-Signal
8
    WAIT_SIXTY_US       : unsigned(13 downto 0) := to_unsigned(50, 14);  -- 1000 ns
9
    WAIT_FIVEHUNDRED_NS : unsigned(13 downto 0) := to_unsigned(25, 14);  -- 1000 ns
10
    WAIT_TWENTY_NS      : unsigned(13 downto 0) := to_unsigned(2, 14)    -- 20 ns
11
  );
12
  port (
13
    -- master signals
14
    clk      : in  std_logic;
15
    rst      : in  std_logic;
16
    cmd      : in  std_logic_vector(2 downto 0);
17
    busy     : out std_logic;
18
    st_busy  : out std_logic;
19
    st_onoff : out std_logic;
20
    st_reset : out std_logic;
21
    data_out : in  std_logic_vector(7 downto 0);
22
    data_in  : out std_logic_vector(7 downto 0);
23
    -- graphic lcd interface
24
    glcd_db_in   : in  std_logic_vector(7 downto 0);
25
    glcd_db_out  : out std_logic_vector(7 downto 0);
26
    glcd_db_enab : out std_logic;
27
    glcd_e       : out std_logic;
28
    glcd_reset   : out std_logic;
29
    glcd_rw      : out std_logic;
30
    glcd_di      : out std_logic;
31
    glcd_cs      : out std_logic
32
  );
33
end ks0108b_cmd;
34
35
architecture behavioral of ks0108b_cmd is
36
37
  component ks0108b_ctrl is
38
    generic (
39
      RESET_ACTIVE  : std_logic             := '0';
40
      WAIT_POWER_UP : unsigned(12 downto 0) := to_unsigned(3000, 13);  -- 15 ms @ 50 MHz
41
      WAIT_T1       : unsigned(12 downto 0) := to_unsigned(18, 13);    -- 360 ns @ 50 MHz
42
      WAIT_T2       : unsigned(12 downto 0) := to_unsigned(8, 13);     -- 150 ns @ 50 MHz
43
      WAIT_T3       : unsigned(12 downto 0) := to_unsigned(26, 13);    -- 510 ns @ 50 MHz
44
      WAIT_T4       : unsigned(12 downto 0) := to_unsigned(3, 13);     --  30 ns @ 50 MHz
45
      WAIT_T5       : unsigned(12 downto 0) := to_unsigned(2, 13)      --  20 ns @ 50 MHz
46
    );
47
    port (
48
      clk      : in  std_logic;                    -- System Clock
49
      rst      : in  std_logic;                    -- asynchronous Reset, active high
50
      data_out : in  std_logic_vector(7 downto 0); -- Input data
51
      data_in  : out std_logic_vector(7 downto 0);
52
      dval     : in  std_logic;                    -- Write Data command (1 clock cycle)
53
      rs       : in  std_logic;                    -- Data or Command
54
      rw       : in  std_logic;                    -- read or write command
55
      busy     : out std_logic;                    -- '1' if device busy
56
      -- Graphic LCD signals
57
      glcd_db_in   : in  std_logic_vector(7 downto 0);
58
      glcd_db_out  : out std_logic_vector(7 downto 0);
59
      glcd_db_enab : out std_logic;
60
      glcd_e       : out std_logic;
61
      glcd_reset   : out std_logic;
62
      glcd_rw      : out std_logic;
63
      glcd_di      : out std_logic;
64
      glcd_cs      : out std_logic
65
    );
66
  end component;
67
68
  -- Graphic LCD command definitions
69
  constant NO_CMD     : std_logic_vector(2 downto 0) := "000";
70
  constant READ_DD    : std_logic_vector(2 downto 0) := "001";
71
  constant WRITE_DD   : std_logic_vector(2 downto 0) := "010";
72
  constant ST_READ    : std_logic_vector(2 downto 0) := "011";
73
  constant SET_ADDR_Y : std_logic_vector(2 downto 0) := "100";
74
  constant SET_D_SL   : std_logic_vector(2 downto 0) := "101";
75
  constant SET_ADDR_X : std_logic_vector(2 downto 0) := "110";
76
  constant DISP_ONOFF : std_logic_vector(2 downto 0) := "111";
77
78
  signal dval  : std_logic := '0';  -- Write Data command (1 clock cycle)
79
  signal di    : std_logic := '0';  -- Data or Instruction
80
  signal busyi : std_logic;         -- '1' if device busy
81
  signal rw    : std_logic;         -- '1' if device busy
82
83
  signal i_data_out : std_logic_vector(7 downto 0);
84
  signal i_data_in  : std_logic_vector(7 downto 0);
85
  signal cmd_i      : std_logic_vector(2 downto 0);
86
87
  type State_type is (sIDLE, sDVAL_HIGH, sWAIT);
88
  signal State : State_type;
89
90
begin
91
  DISPLAY: ks0108b_ctrl
92
    generic map (
93
      RESET_ACTIVE => RESET_ACTIVE
94
    )
95
    port map (
96
      clk          => clk,
97
      rst          => rst,
98
      dval         => dval,
99
      rs           => di,
100
      busy         => busyi,
101
      data_in      => i_data_in,
102
      data_out     => i_data_out,
103
      rw           => rw,
104
      glcd_db_in   => glcd_db_in,
105
      glcd_db_out  => glcd_db_out,
106
      glcd_db_enab => glcd_db_enab,
107
      glcd_e       => glcd_e,
108
      glcd_reset   => glcd_reset,
109
      glcd_rw      => glcd_rw,
110
      glcd_di      => glcd_di,
111
      glcd_cs      => glcd_cs
112
    );
113
114
  LCDPrc: process (clk, rst)
115
  begin
116
    if (rst = RESET_ACTIVE) then
117
      i_data_out <= (others => '0');
118
      data_in    <= (others => '0');
119
      dval       <= '0';
120
      st_busy    <= '1';
121
      st_onoff   <= '0';
122
      st_reset   <= '0';
123
      busy       <= '1';
124
      di         <= '0';
125
      rw         <= '0';
126
      cmd_i      <= (others => '0');
127
      state      <= sIDLE;
128
    elsif rising_edge(clk) then
129
      dval <= '0';
130
131
      case state is
132
        when sIDLE =>
133
          if (busyi = '0') then
134
            busy <= '0';
135
136
            case cmd is
137
              when NO_CMD =>
138
                null;
139
140
              when READ_DD =>      -- command read display data
141
                cmd_i <= cmd;      -- store command
142
                di    <= '1';
143
                rw    <= '1';
144
                dval  <= '1';
145
                busy  <= '1';
146
                state <= sDVAL_HIGH;
147
148
              when WRITE_DD =>     -- command write display data
149
                cmd_i     <= cmd;  -- store command
150
                i_data_out <= data_out;
151
                di        <= '1';
152
                rw        <= '0';
153
                dval      <= '1';
154
                busy      <= '1';
155
                state     <= sDVAL_HIGH;
156
157
              when ST_READ =>      -- command status read
158
                cmd_i <= cmd;      -- store command
159
                di    <= '0';
160
                rw    <= '1';
161
                dval  <= '1';
162
                busy  <= '1';
163
                state <= sDVAL_HIGH;
164
165
              when SET_ADDR_Y =>   -- command set address y
166
                cmd_i     <= cmd;  -- store command
167
                i_data_out <= "01" & data_out(5 downto 0);
168
                di        <= '0';
169
                rw        <= '0';
170
                dval      <= '1';
171
                busy      <= '1';
172
                state     <= sDVAL_HIGH;
173
174
              when SET_D_SL =>     -- set display start line
175
                cmd_i <= cmd;      -- store command
176
                i_data_out <= "11" & data_out(5 downto 0);
177
                di        <= '0';
178
                rw        <= '0';
179
                dval      <= '1';
180
                busy      <= '1';
181
                state     <= sDVAL_HIGH;
182
183
              when SET_ADDR_X =>   -- set address X
184
                cmd_i     <= cmd;  -- store command
185
                i_data_out <= "10111" & data_out(2 downto 0);
186
                di        <= '0';
187
                rw        <= '0';
188
                dval      <= '1';
189
                busy      <= '1';
190
                state     <= sDVAL_HIGH;
191
192
              when DISP_ONOFF =>   -- command display on/off
193
                cmd_i     <= cmd;  -- store command
194
                i_data_out <= "0011111" & data_out(0);  -- Command Display On
195
                di        <= '0';
196
                rw        <= '0';
197
                dval      <= '1';
198
                busy      <= '1';
199
                state     <= sDVAL_HIGH;
200
201
              when others =>
202
                null;
203
            end case;
204
          end if;
205
206
        when sDVAL_HIGH =>
207
          state <= sWAIT;
208
209
        when sWAIT =>
210
          if (busyi = '0') then
211
            if (cmd_i = READ_DD) then
212
              data_in <= i_data_in;
213
            end if;
214
215
            if (cmd_i = ST_READ) then
216
              st_busy  <= i_data_in(7);
217
              st_onoff <= i_data_in(5);
218
              st_reset <= i_data_in(4);
219
            end if;
220
            cmd_i <= NO_CMD; -- store command
221
            state <= sIDLE;
222
          end if;
223
224
        when others =>
225
          state <= sIDLE;
226
      end case;
227
    end if;
228
  end process;
229
end behavioral;

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


Lesenswert?

Ralf schrieb:
1
WAIT_POWER_UP : unsigned(12 downto 0) := to_unsigned(3000, 13); -- 15 ms @ 50 MHz
Wie kommst du da auf 3000 für 15ms?
Ich würde sagen: 50MHz => 20ns
Und damit 15000ns/20ns = 750

Warum machst du die ganzen Zähler nicht einfach als integer und lässt 
den Synthesizer rechnen? Dann schreibst du da einfach:
1
 WAIT_POWER_UP : integer := 15000/20;  -- 15ms/20ns (50MHz)
2
 :
3
 :
4
  signal timer : integer range 0 to WAIT_POWER_UP;

Ich habe den Verdacht, dass du deine ganzen Zeiten nochmal anschauen und 
die Kommentare und/oder die Zeiten löschen bzw. korrigieren solltest:
1
    WAIT_SIXTY_US       : unsigned(13 downto 0) := to_unsigned(50, 14);  -- 1000 ns
2
    WAIT_FIVEHUNDRED_NS : unsigned(13 downto 0) := to_unsigned(25, 14);  -- 1000 ns
3
    WAIT_TWENTY_NS      : unsigned(13 downto 0) := to_unsigned(2, 14)    -- 20 ns


> Oder eventuell ein Beispiel oder Link für eine Applikation
> mit einem LCD-FPGA.
Hier ist was für ein Character-Display:
Beitrag "Re: EA DOG-M initialisieren"

von Ralf (Gast)


Lesenswert?

Hallo Lothar,

ja die 3000 sind nicht richtig. Kommt daher
dass ich verschieden Zeiten ausprobiert habe.
Deine Vorschläge in aller Ehren, sind eventuell
auch richtig. Aber die Zähler funktionieren so
wie sie sollen.
Auch dein Beispiel mit einem Character -Display
hilft mir leider nicht weiter. Ich habe schon
mehrere Character - Displays am FPGA laufen.
Nur jetzt habe ich zum ersten mal ein Graphik-
Display dran. Deshalb die Frage nach dem Timing
bzw. die Zeit in der man Befehle schicken kann.

Gruß

Ralf

von Duke Scarring (Gast)


Lesenswert?

Ralf schrieb:
> Deshalb die Frage nach dem Timing
> bzw. die Zeit in der man Befehle schicken kann.

Das Timing steht im Datenblatt zum Displaycontroller und nicht im 
FPGA-Forum...

Duke

von Ralf (Gast)


Lesenswert?

Das ist ja gerade das Problem.
Wenn ich mir die Signale dem Oszilloskop
anschaue passt alles. Im Datenblatt steht
aber leider keine Initialiesrungssequenz
wie z. B. bei Character Displays.

von Lattice User (Gast)


Lesenswert?

Kann an der Initialisierung liegen.

Diese Frage ist u.U. im µC Forum besser aufgehoben, eine schnelle Suche 
ergibt dass schon einige ein deartiges Display am ATMega betrieben 
haben.
z.B. hier:
Beitrag "KS0108B Displaytech 64128A"

von Harald F. (hfl)


Lesenswert?

@ Ralf

Ich habe schonmal ein grafisches LCD an einem FPGA betrieben, aber das 
hatte wenigstens einen Display-Controller. Der genannte KS0108B ist ja 
gerade mal ein "driver", braucht also eine ganze Reiher spezieller 
Eingangsignale und Spannungen. Wenn die Pegel und das Timing (mit den 
Scope gemessen) korrekt sind, dann brauchst Du den Fehler nicht im FPGA 
zu suchen. Dann bleiben nur noch:

- IC oder Display ist defekt
- Spannung ist nicht eingeschaltet
- Datenblatt ist falsch

Much fun,
Harald

P.S. Bei dem Display, das ich im Einsatz hatte, lag der letzte der 
genannten Fehler vor. Ganz groß stand im Datenblatt geschieben "Do not 
apply a signal to this pin, it must be tied to GND". Hat sich dann 
leider als falsch herausgestellt.

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


Lesenswert?

Ralf schrieb:
> Deine Vorschläge in aller Ehren, sind eventuell auch richtig.
Ja, das sind sie.
> Aber die Zähler funktionieren so wie sie sollen.
Klar, das hatte ich nicht bezweifelt. Nur könnte man sie schöner 
schreiben...  ;-)

> Im Datenblatt steht aber leider keine Initialiesrungssequenz
> wie z. B. bei Character Displays.
Und Google? Z.B. mit
KS0108B  initialize
http://forum.lcdinfo.com/viewtopic.php?t=554
http://www.geocities.com/dinceraydin/lcd/gfxintro.htm

von gnihihi (Gast)


Lesenswert?

leuchtet dein display? ich hatte mal das problem, dass augenscheinlich 
NICHTS funzte, die simulation aber fehlerfrei lief. ich habe dann 
versuchsweise den pin für die displaybeleuchtung auf masse gezogen. das 
stand leider nicht im datenblatt und war reiner zufall.
danach funktionierte alles sahne

von Ralf (Gast)


Lesenswert?

Guten Morgen,

die Ansteuerung des Display funktioniert nun.
Die Pegel der CS-Leitungen waren in meiner
Ansteuerung falsch. An diesem Display sind sie High-Aktiv.
Außerdem sind alle Pixel nach dem Initialisieren
eingeschaltet. Ich hatte fälschlicherweise angenommen
das diese nach dem Initialisieren ausgeschaltet sind
und wollte alle Pixel einschalten. Da diese schon
eingeschaltet waren, sah ich natürlich keine Reaktion.

Also vielen Dank an alle die mir mit Ratschlägen
geholfen haben.

Gruß

Ralf

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.