www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Universeller VGA Controller


Autor: Hans-Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
 -- Record
 type vgamode_record is
  record
    vertical_sync_pulse_time    : natural range 0 to 521;
    horizontal_sync_pulse_time  : natural range 0 to 800;
    vertical_display_time       : natural range 0 to 480;
    horizontal_display_time     : natural range 0 to 640;
    vertical_sync_pulse_width   : natural range 0 to 2;
    horizontal_sync_pulse_width : natural range 0 to 96;
  end record;
 --Initialisierung
  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.

Autor: Kest (Gast)
Datum:

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

Grüße,
Kest

Autor: Hans-Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ???

Autor: Kest (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, Du hast es verstanden :-)

Grüße,
Kest

Autor: Nephilim (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Bernhard R. (barnyhh)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Niklas G. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hans-Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


package vga_control_package is

  type polarity is (pos, neg);
   type vgamode_record is
  record
    vertical_sync_pulse_time         : natural range 0 to 625;
    horizontal_sync_pulse_time       : natural range 0 to 1056;
    vertical_display_time            : natural range 0 to 600; -- Zeilen
    horizontal_display_time          : natural range 0 to 800; -- Spalten
    vertical_sync_pulse_width        : natural range 0 to 6;
    horizontal_sync_pulse_width      : natural range 0 to 120;
    vertical_back_porch           : natural range 0 to 29;
    horizontal_back_porch         : natural range 0 to 64; 
    vertical_sync_pulse_polarity     : polarity;
    horizontal_sync_pulse_polarity   : polarity;
  end record vgamode_record;
  
  type vga_out_record is
  record
    hsync        : std_logic;
      vsync        : std_logic;
    hcount      : std_logic_vector(9 downto 0);
    vcount      : std_logic_vector(9 downto 0);
    blank       : std_logic;
  end record vga_out_record;
  
  type vgamodi is (vga480x640at60, vga600x800at72);
  -- VGA Mode 640x480@60 Hz Industry Standard (Pixel Clock 25,175 MHz)
  constant vgamode480x640at60 : vgamode_record := (521,800,480,640,2,96,29,48,neg,neg);
  -- VGA Mode 800x600@72 Hz (Pixel Clock 50 MHz)
   constant vgamode600x800at72 : vgamode_record := (625,1056,600,800,6,120,23,64,pos,pos);
  subtype horizontal_position is unsigned(9 downto 0);
  subtype vertical_position is unsigned(9 downto 0);
end vga_control_package;

package body vga_control_package is
   
end;
Und der Aufruf:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-- Generiert aus dem 50 MHz Takt einen 25 MHz Takt
-- Der VGA-Takt für eine Auflösung von 640x480 Bildpunkten
-- bei 60 Hz Bildwiederholfrequenz ist eigentlich 25,175 Hz
entity clock25_entity is
  port 
  (
  clock50 : in    std_logic;
  clock25 : out std_logic
  );
end clock25_entity;

architecture rtl of clock25_entity is
  signal counter : integer range 0 to 1;
begin
  -- Generiere einen 25 MHz Takt
  process (clock50)
  begin
    if rising_edge(clock50)
    then    
      if counter = 0
      then
        clock25 <= '1';
        counter <= counter + 1;
      else
        clock25 <= '0';
        counter <= counter - 1;
      end if;
    end if;
  end process;
  
end architecture rtl;

-------------------------------------------------------------------------------------------------------

library ieee; 
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vga_control_package.all;

-- Erzeuge die VSync und HSync Signale
-- und die aktuelle Position auf dem VGA-Bildschirm
entity universal_vga_controller is
  port(
      clock    : in   std_logic;
      vga_mode : in   vgamode_record;
      vga_out  : out   vga_out_record
    );
end universal_vga_controller;

architecture rtl of universal_vga_controller is
  
  signal     horizontal_counter         : horizontal_position := (others => '0');
  signal     vertical_counter           : vertical_position   := (others => '0');
  constant     horizontal_start_of_output    : integer range 0 to 144 := vga_mode.horizontal_sync_pulse_width + vga_mode.horizontal_back_porch;
  constant     horizontal_end_of_output      : integer range 0 to 784 := horizontal_start_of_output + vga_mode.horizontal_display_time;
  constant     vertical_start_of_output      : integer range 0 to 31 := vga_mode.vertical_sync_pulse_width + vga_mode.vertical_back_porch;
  constant     vertical_end_of_output        : integer range 0 to 511 := vertical_start_of_output + vga_mode.vertical_display_time;
begin

  process (clock) 
  begin
    if rising_edge(clock)
    then
     if (horizontal_counter >= horizontal_start_of_output) and (horizontal_counter < horizontal_end_of_output)
     and (vertical_counter >= vertical_start_of_output) and (vertical_counter < vertical_end_of_output) 
     then
      vga_out.blank <= '0';
     else
      vga_out.blank <= '1';
     end if;
     
     if (horizontal_counter >= 1) and (horizontal_counter <= vga_mode.horizontal_sync_pulse_width) 
     then
      if vga_mode.horizontal_sync_pulse_polarity = neg
      then
        vga_out.hsync <= '0';
      else
        vga_out.hsync <= '1';
      end if;
     else
      if vga_mode.horizontal_sync_pulse_polarity = neg
      then
        vga_out.hsync <= '1';
      else
        vga_out.hsync <= '0';
      end if;
     end if;
     
     if (vertical_counter >= 1) and (vertical_counter <= vga_mode.vertical_sync_pulse_width) 
     then
      if vga_mode.vertical_sync_pulse_polarity = neg
      then
        vga_out.vsync <= '0';
      else
        vga_out.vsync <= '1';
      end if;
     else
      if vga_mode.vertical_sync_pulse_polarity = neg
      then
        vga_out.vsync <= '1';
      else
        vga_out.vsync <= '0';
      end if;
     end if;
     
    -- Inkrement horizontal_counter
     horizontal_counter <= horizontal_counter + 1;
    -- Horizontal Sync Sync Pulse Time = 800 Clocks
     if (horizontal_counter = vga_mode.horizontal_sync_pulse_time) 
    then
      -- Inkrement vertical_counter
      vertical_counter <= vertical_counter + 1;
      horizontal_counter <= (others => '0');
     end if;
    -- Vertical Sync Sync Pulse Time = 521 Lines
     if (vertical_counter = vga_mode.vertical_sync_pulse_time) 
    then        
      vertical_counter <= (others => '0');
     end if;
     
     vga_out.hcount <= std_logic_vector(horizontal_counter);
     vga_out.vcount <= std_logic_vector(vertical_counter);
    end if;
  end process;

end architecture rtl;

-----------------------------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vga_control_package.all;

entity vga_controller is
  generic  (
          vgamodus   : vgamodi := vga480x640at60
        );
  port    (
          clock   : in  std_logic;      -- 50 MHz Clock
          vga_out  : out vga_out_record
        );
end vga_controller;

architecture rtl of vga_controller is

  component clock25_entity is
  port
  (
    clock50 : in std_logic;
    clock25 : out std_logic
  );
  end component clock25_entity;
  
  component universal_vga_controller is
  port
  (
    clock    : in  std_logic;
    vga_mode : in   vgamode_record;
    vga_out  : out vga_out_record
  );
  end component universal_vga_controller;
  
  signal clock25  : std_logic;
  signal vga_mode : vgamode_record;

begin

   -- Die If-Anweisung in Verbindung mit generate
  -- ... erfordert ein Label
  label1 : if vgamodus = vga480x640at60 generate
  clock25_port_map : clock25_entity
  port map
  (
    clock50 => clock,
    clock25 => clock25
  );
  end generate;
  
  label2 : if vgamodus = vga480x640at60 generate
  vga_control_port_map : universal_vga_controller
  port map
  (
    clock   => clock25,  -- 25 MHz Clock
    vga_mode  => vga_mode,
    vga_out  => vga_out
  );
  end generate;
  
  -- Bei generate kann kein else-Zweig verwendet werden
  -- ... auch keine case-Anweisung
  label3 : if vgamodus = vga600x800at72 generate
  vga_control_port_map : universal_vga_controller
  port map
  (
    clock   => clock,    -- 50 MHz Clock
    vga_mode  => vga_mode,
    vga_out  => vga_out
  );
  end generate;

  process (clock) is
  begin
    if rising_edge(clock)
    then
      case vgamodus is
        when vga480x640at60 => vga_mode <= vgamode480x640at60;
        when vga600x800at72 => vga_mode <= vgamode600x800at72;
      end case;
    end if;
  end process;
  
end architecture rtl;

Autor: Nephilim (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.