Forum: FPGA, VHDL & Co. Universeller VGA Controller


von Hans-Werner (Gast)


Lesenswert?

Wie schreibe ich in VHDL einen universellen VGA Controller für 
verschiedene VGA Modi ?
Idee: Man nehme einen Prozess und übergebe diesem die Parameter als 
Record, z.B. so:
1
 -- Record
2
 type vgamode_record is
3
  record
4
    vertical_sync_pulse_time    : natural range 0 to 521;
5
    horizontal_sync_pulse_time  : natural range 0 to 800;
6
    vertical_display_time       : natural range 0 to 480;
7
    horizontal_display_time     : natural range 0 to 640;
8
    vertical_sync_pulse_width   : natural range 0 to 2;
9
    horizontal_sync_pulse_width : natural range 0 to 96;
10
  end record;
11
 --Initialisierung
12
  signal vgamode : vgamode := (521,800,480,640,2,96);
Die Typen für die einzelnen Parameter müssten dann mit den Minimal- und 
Maximalwerten über alle VGA Modi deklariert werden.
Oder geht es irgendwie generisch ?
Hoffe das ist synthetisierbar.

von Kest (Gast)


Lesenswert?

genau so geht es :-) Das Problem könnte die Clock sein. Da muss ggf. 
auch die interne PLL umkonfiguriert sein.

Grüße,
Kest

von Hans-Werner (Gast)


Lesenswert?

Wieso ist die Clock ein Problem ?
Welche PLL ?
Momentan teile ich die 50 MHz auf dem Board auf 25 MHz, zur Ansteuerung 
des VGA Monitors, runter.
Für andere VGA Modi benötige ich jedoch auch andere Taktraten und somit 
DCMs. Um keine Resourcen zu verschwenden sollte natürlich die nur 
Taktrate erzeugt werden die der entsprechende VGA Modus auch benötigt.
Soll im laufenden Betrieb ein Umschalten zwischen verschiedenen VGA Modi 
möglich sein, müssten simultan auch sämtliche erforderlichen Taktraten 
erzeugt werden um mehrere VGA Controller anzusteuern.
Soll das ganze nur generisch erfolgen ist nur jeweils der entsprechende 
Takt zu erzeugen. In Abhängigkeit des generischen Parameters müsste man 
das entsprechende Record erzeugen bzw. verwenden.
Habe ich das jetzt verstanden ???

von Kest (Gast)


Lesenswert?

Ja, Du hast es verstanden :-)

Grüße,
Kest

von Nephilim (Gast)


Lesenswert?

die schwierigkeit mit der DCM könnte aber werden, wenn du für die 
auflösung von 640x480 einen Pixelclock von 25,175 MHz, laut VESA 
spezifikation brauchst. so krumme takte erzeugen die DCMs leider nich so 
gut.

von Bernhard R. (barnyhh)


Lesenswert?

Die gesamten Spezifikationen für VGA, VESA, ... stammen aus dem 
analogen Zeitalter (TM), in dem (Frequenz-)Toleranzen im zweistelligen 
Prozentbereich durchaus zulässig und üblich waren. Die Monitore sind 
dafür ausgelegt. 25,175 MHz nominal sollte also alles im Bereich 23 ... 
28 MHz "abkönnen".

Bernhard

von Niklas G. (Gast)


Lesenswert?

Falls es dich interessiert, hier findest du einen simplen 
1024x768@60Hz-VHDL-VGA-Controller (4Bit pro Farbe) für Spartan-3A's, der 
allerdings in jeder Zeile das gleiche anzeigt; du müsstest mit einem 
externen RAM immer die jeweils nächste Zeile in den Puffer schreiben.

http://niklassolar.ni.funpic.de/vga.vhd

von Hans-Werner (Gast)


Lesenswert?

Leider finden sich im Internet teilweise unterschiedliche Werte für das 
VGA-Timing, so z.B. auf der Website von Doulos und der 
tinyvga.com-Website.
Einmal für "vertical_sync_pulse_time" 521, dann 524 und teilweise auch 
525.
Oder für "vertical_back_porch" mal 29 mal 33.
Mit einem Takt von 25 MHz (50 MHz/2) funktioniert es anstelle von 25,175 
MHz bei mir an zwei unterschiedlichen Monitoren. Welche Toleranz 
generell bzw. für andere Werte zulässig ist, ist die grosse Frage.
Nachfolgend eine Lösung (???) mit der ich den VGAModus generisch 
vorgeben kann. Also nur ein VGAModus gleichzeitig.
Nachfolgend das Package.
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4
5
6
package vga_control_package is
7
8
  type polarity is (pos, neg);
9
   type vgamode_record is
10
  record
11
    vertical_sync_pulse_time         : natural range 0 to 625;
12
    horizontal_sync_pulse_time       : natural range 0 to 1056;
13
    vertical_display_time            : natural range 0 to 600; -- Zeilen
14
    horizontal_display_time          : natural range 0 to 800; -- Spalten
15
    vertical_sync_pulse_width        : natural range 0 to 6;
16
    horizontal_sync_pulse_width      : natural range 0 to 120;
17
    vertical_back_porch           : natural range 0 to 29;
18
    horizontal_back_porch         : natural range 0 to 64; 
19
    vertical_sync_pulse_polarity     : polarity;
20
    horizontal_sync_pulse_polarity   : polarity;
21
  end record vgamode_record;
22
  
23
  type vga_out_record is
24
  record
25
    hsync        : std_logic;
26
      vsync        : std_logic;
27
    hcount      : std_logic_vector(9 downto 0);
28
    vcount      : std_logic_vector(9 downto 0);
29
    blank       : std_logic;
30
  end record vga_out_record;
31
  
32
  type vgamodi is (vga480x640at60, vga600x800at72);
33
  -- VGA Mode 640x480@60 Hz Industry Standard (Pixel Clock 25,175 MHz)
34
  constant vgamode480x640at60 : vgamode_record := (521,800,480,640,2,96,29,48,neg,neg);
35
  -- VGA Mode 800x600@72 Hz (Pixel Clock 50 MHz)
36
   constant vgamode600x800at72 : vgamode_record := (625,1056,600,800,6,120,23,64,pos,pos);
37
  subtype horizontal_position is unsigned(9 downto 0);
38
  subtype vertical_position is unsigned(9 downto 0);
39
end vga_control_package;
40
41
package body vga_control_package is
42
   
43
end;
Und der Aufruf:
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4
5
-- Generiert aus dem 50 MHz Takt einen 25 MHz Takt
6
-- Der VGA-Takt für eine Auflösung von 640x480 Bildpunkten
7
-- bei 60 Hz Bildwiederholfrequenz ist eigentlich 25,175 Hz
8
entity clock25_entity is
9
  port 
10
  (
11
  clock50 : in    std_logic;
12
  clock25 : out std_logic
13
  );
14
end clock25_entity;
15
16
architecture rtl of clock25_entity is
17
  signal counter : integer range 0 to 1;
18
begin
19
  -- Generiere einen 25 MHz Takt
20
  process (clock50)
21
  begin
22
    if rising_edge(clock50)
23
    then    
24
      if counter = 0
25
      then
26
        clock25 <= '1';
27
        counter <= counter + 1;
28
      else
29
        clock25 <= '0';
30
        counter <= counter - 1;
31
      end if;
32
    end if;
33
  end process;
34
  
35
end architecture rtl;
36
37
-------------------------------------------------------------------------------------------------------
38
39
library ieee; 
40
use ieee.std_logic_1164.all;
41
use ieee.numeric_std.all;
42
use work.vga_control_package.all;
43
44
-- Erzeuge die VSync und HSync Signale
45
-- und die aktuelle Position auf dem VGA-Bildschirm
46
entity universal_vga_controller is
47
  port(
48
      clock    : in   std_logic;
49
      vga_mode : in   vgamode_record;
50
      vga_out  : out   vga_out_record
51
    );
52
end universal_vga_controller;
53
54
architecture rtl of universal_vga_controller is
55
  
56
  signal     horizontal_counter         : horizontal_position := (others => '0');
57
  signal     vertical_counter           : vertical_position   := (others => '0');
58
  constant     horizontal_start_of_output    : integer range 0 to 144 := vga_mode.horizontal_sync_pulse_width + vga_mode.horizontal_back_porch;
59
  constant     horizontal_end_of_output      : integer range 0 to 784 := horizontal_start_of_output + vga_mode.horizontal_display_time;
60
  constant     vertical_start_of_output      : integer range 0 to 31 := vga_mode.vertical_sync_pulse_width + vga_mode.vertical_back_porch;
61
  constant     vertical_end_of_output        : integer range 0 to 511 := vertical_start_of_output + vga_mode.vertical_display_time;
62
begin
63
64
  process (clock) 
65
  begin
66
    if rising_edge(clock)
67
    then
68
     if (horizontal_counter >= horizontal_start_of_output) and (horizontal_counter < horizontal_end_of_output)
69
     and (vertical_counter >= vertical_start_of_output) and (vertical_counter < vertical_end_of_output) 
70
     then
71
      vga_out.blank <= '0';
72
     else
73
      vga_out.blank <= '1';
74
     end if;
75
     
76
     if (horizontal_counter >= 1) and (horizontal_counter <= vga_mode.horizontal_sync_pulse_width) 
77
     then
78
      if vga_mode.horizontal_sync_pulse_polarity = neg
79
      then
80
        vga_out.hsync <= '0';
81
      else
82
        vga_out.hsync <= '1';
83
      end if;
84
     else
85
      if vga_mode.horizontal_sync_pulse_polarity = neg
86
      then
87
        vga_out.hsync <= '1';
88
      else
89
        vga_out.hsync <= '0';
90
      end if;
91
     end if;
92
     
93
     if (vertical_counter >= 1) and (vertical_counter <= vga_mode.vertical_sync_pulse_width) 
94
     then
95
      if vga_mode.vertical_sync_pulse_polarity = neg
96
      then
97
        vga_out.vsync <= '0';
98
      else
99
        vga_out.vsync <= '1';
100
      end if;
101
     else
102
      if vga_mode.vertical_sync_pulse_polarity = neg
103
      then
104
        vga_out.vsync <= '1';
105
      else
106
        vga_out.vsync <= '0';
107
      end if;
108
     end if;
109
     
110
    -- Inkrement horizontal_counter
111
     horizontal_counter <= horizontal_counter + 1;
112
    -- Horizontal Sync Sync Pulse Time = 800 Clocks
113
     if (horizontal_counter = vga_mode.horizontal_sync_pulse_time) 
114
    then
115
      -- Inkrement vertical_counter
116
      vertical_counter <= vertical_counter + 1;
117
      horizontal_counter <= (others => '0');
118
     end if;
119
    -- Vertical Sync Sync Pulse Time = 521 Lines
120
     if (vertical_counter = vga_mode.vertical_sync_pulse_time) 
121
    then        
122
      vertical_counter <= (others => '0');
123
     end if;
124
     
125
     vga_out.hcount <= std_logic_vector(horizontal_counter);
126
     vga_out.vcount <= std_logic_vector(vertical_counter);
127
    end if;
128
  end process;
129
130
end architecture rtl;
131
132
-----------------------------------------------------------------------------------------------------
133
134
library ieee;
135
use ieee.std_logic_1164.all;
136
use ieee.numeric_std.all;
137
use work.vga_control_package.all;
138
139
entity vga_controller is
140
  generic  (
141
          vgamodus   : vgamodi := vga480x640at60
142
        );
143
  port    (
144
          clock   : in  std_logic;      -- 50 MHz Clock
145
          vga_out  : out vga_out_record
146
        );
147
end vga_controller;
148
149
architecture rtl of vga_controller is
150
151
  component clock25_entity is
152
  port
153
  (
154
    clock50 : in std_logic;
155
    clock25 : out std_logic
156
  );
157
  end component clock25_entity;
158
  
159
  component universal_vga_controller is
160
  port
161
  (
162
    clock    : in  std_logic;
163
    vga_mode : in   vgamode_record;
164
    vga_out  : out vga_out_record
165
  );
166
  end component universal_vga_controller;
167
  
168
  signal clock25  : std_logic;
169
  signal vga_mode : vgamode_record;
170
171
begin
172
173
   -- Die If-Anweisung in Verbindung mit generate
174
  -- ... erfordert ein Label
175
  label1 : if vgamodus = vga480x640at60 generate
176
  clock25_port_map : clock25_entity
177
  port map
178
  (
179
    clock50 => clock,
180
    clock25 => clock25
181
  );
182
  end generate;
183
  
184
  label2 : if vgamodus = vga480x640at60 generate
185
  vga_control_port_map : universal_vga_controller
186
  port map
187
  (
188
    clock   => clock25,  -- 25 MHz Clock
189
    vga_mode  => vga_mode,
190
    vga_out  => vga_out
191
  );
192
  end generate;
193
  
194
  -- Bei generate kann kein else-Zweig verwendet werden
195
  -- ... auch keine case-Anweisung
196
  label3 : if vgamodus = vga600x800at72 generate
197
  vga_control_port_map : universal_vga_controller
198
  port map
199
  (
200
    clock   => clock,    -- 50 MHz Clock
201
    vga_mode  => vga_mode,
202
    vga_out  => vga_out
203
  );
204
  end generate;
205
206
  process (clock) is
207
  begin
208
    if rising_edge(clock)
209
    then
210
      case vgamodus is
211
        when vga480x640at60 => vga_mode <= vgamode480x640at60;
212
        when vga600x800at72 => vga_mode <= vgamode600x800at72;
213
      end case;
214
    end if;
215
  end process;
216
  
217
end architecture rtl;

von Nephilim (Gast)


Lesenswert?

also die werte sind bildschirmabhängig. grundlegend sollte man von den 
VESA Standards ausgehen. wobei es auch hier mehrere verscheidene 
Standards gibt, die sich mit der zeit entwickelt haben.
wenn ein modus mit den standards dennoch nich gehen will, dann müsste 
man das panel identifizieren, auf welchem man was darstellen will, und 
im datenblatt dazu schauen was für werte gefordert werden. dort stehen 
dann auch die tolleranzen drin was z.B. den Pixelclock angeht. so 
tollerant wie oben beschrieben sind die nämlich auch bei TFTs nicht.

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.