2014-10-15 7 views
7

Ich versuche VHDL-Programmierung mit einigen Büchern und einem Altera DE1-Entwicklungskit von Terasic zu lernen.VGA-Controller mit VHDL

Das Problem hier ist, dass ich versuche, einen VGA-Controller für die Arbeit mit einer Auflösung von 640x480 zu programmieren (obwohl mein Bildschirm ein TFT-LCD mit 1280x1024 ist).

Ich habe einige Probleme mit dem Code.

Ich verwende ein FSM, um die vertikalen und horizontalen Signale, ein weiterer Block, um die RGB-Eingänge und auch eine 27 MHz-Takt von der DE1 zu fahren.

Ich denke, dass etwas mit dem Code falsch sein muss, weil das Bild, das ich auf dem Bildschirm drucke, nicht die richtige Größe (640x480) sondern größer (ca. 1174x980) hat.

Jetzt versuche ich eine einzige Farbe in den Bildschirm zu setzen, um es zu vereinfachen, bis ich den Fehler entdecken kann.

Mein Projekt hat 3 Dateien, 1 für den Block RGB, 1 für die FSM und einen anderen, um beide zu instanziieren.

Ich würde eine Art von Hilfe schätzen, um dieses Problem zu lösen, weil ich versucht habe, es herauszufinden, aber ich kann nicht sehen, wo die Fehler sind.

Vielen Dank!

Omar

VGA-Controller-Datei

library ieee; 
use ieee.std_logic_1164.all; 

entity VGA_controller is 
    port(clk, reset : in std_logic; 
     Hsync,Vsync : out std_logic; 
     R,G,B : out std_logic_vector(3 downto 0)); 
end entity; 

architecture arch of VGA_controller is 

component FSM_sync is 
    port(clk,reset : in std_logic; 
     Hsync,Vsync,VIDON : out std_logic; 
     Vcount,Hcount : out integer range 0 to 799); 
end component; 

component VGA_display is 
    port(hcount,vcount : in integer range 0 to 799; 
     r,g,b : out std_logic_vector(3 downto 0); 
     video_on : in std_logic); 
end component; 

signal video : std_logic; 
signal signal1 : integer range 0 to 799; 
signal signal2 : integer range 0 to 799; 

begin 

maquinaestado_sync : FSM_sync port map (clk=>clk, reset=>reset, Hsync=>Hsync, Vsync=>Vsync, Vcount=>signal1, Hcount=>signal2, VIDON=>video); 

salida_pantalla : VGA_display port map (r=>R, g=>G, b=>B, video_on=>video, vcount=>signal1, hcount=>signal2); 

end arch; 

FSM-Sync-Datei

library ieee; 
use ieee.std_logic_1164.all; 


entity FSM_sync is 
    port(clk,reset : in std_logic; 
     Hsync,Vsync,VIDON : out std_logic; 
     Vcount,Hcount : out integer range 0 to 799); 
end entity; 


architecture arch of FSM_sync is 
--constantes para definir los ciclos de reloj de cada señal del HSYNC 
constant counterMAX : integer := 640; 
constant counterSP : integer := 96; 
constant counterBP : integer := 48; 
constant counterHV : integer := 640; 
constant counterFP : integer := 16; 
--constantes para definir los ciclos de reloj de cada señal del VSYNC 
constant counterMAX_V : integer := 384000; -- calculamos estos valores multiplicando el numero de filas por los pixeles en cada fila horizontal (800) 
constant counterSP_V : integer := 1600;  -- de manera que cada estado de la sincronizacion vertical dure todo el recorrido de los pixeles de cada fila 
constant counterBP_V : integer := 26400; 
constant counterVV : integer := 384000; 
constant counterFP_V : integer := 8000; 
--constantes para el numero de pixeles maximo que debemos controlar en horizontal y en vertical 
constant number_pixelsMAX_H : integer := 800; 
constant number_pixelsMAX_V : integer := 525; 

type state is (SP_1,BP,HV,FP,reseteo); --4 estados para cada maquina de estado de sincronizacion (vertical y horizontal) 
signal present_state_H,next_state_H,present_state_V,next_state_V : state; 

signal timer : integer range 0 to counterMAX ; -- señal para pasar el valor counterXX al proceso secuencial para compararlo con un contador y establecer el 
               -- tiempo de duracion de cada estado 
signal timer2 : integer range 0 to counterMAX_V ; --lo mismo que la señal anterior pero para el sincronizacion vertical 

signal video_1,video_2 : std_logic; 

signal hcount_reg,vcount_reg : integer range 0 to 799; 

begin 

--============================================== 
--FSM para la sincronizacion del barrido HORIZONTAL 
--=============================================== 

lower_part_1 : process (clk,reset) 
       variable counter : integer range 0 to counterMAX - 1; --variable para crear un contador de pulsos del clk 
       variable counter2 : integer range 0 to number_pixelsMAX_H - 1;   --contador para los pixeles horizontales  
       variable counter3 : integer range 0 to number_pixelsMAX_V - 1;   --contador para los pixeles verticales 
      begin             --se cargan con 800 por que 800 son los pixeles que hay que leer en horizontal 
       if (reset = '1') then        --esto implica contadores de al menos 10 bits para llegar a ese numero. 
                    --y para que los dos contadores sean del mismo numero de bits se cargan los dos igual 
        counter := 0;         --realmente en vertical solo debemos contar hasta 521 
        counter2 := 0;   
        counter3 := 0; 
        present_state_H <= reseteo; 


       elsif (clk'event and clk = '1') then 
        counter := counter + 1; 

        if (counter2 < number_pixelsMAX_H-1) then 
         counter2 := counter2 + 1; 
        else 
         counter2 := 0; 
         if (counter3 < number_pixelsMAX_V-1) then 
          counter3 := counter3 + 1; 
         else 
          counter3 := 0; 
         end if; 
        end if; 

        hcount_reg <= counter2; 
        vcount_reg <= counter3; 

        if (counter = timer) then 
         present_state_H <= next_state_H; 
         counter := 0; 
        end if; 
       end if; 
       end process lower_part_1; 


upper_part_1 : process (next_state_H) 
      begin 

       Hsync <= '1'; 
       next_state_H <= HV; 

       case present_state_H is 
        when SP_1 => 
         Hsync <= '0'; 
         next_state_H <= BP; 
         timer <= counterSP; 

         video_1 <= '0'; 

        when BP => 
         Hsync <= '1'; 
         next_state_H <= HV; 
         timer <= counterBP; 

         video_1 <= '0'; 

        when HV => 
         Hsync <= '1'; 
         next_state_H <= FP; 
         timer <= counterHV; 

         video_1 <= '1'; 


        when FP => 
         Hsync <= '1'; 
         next_state_H <= SP_1; 
         timer <= counterFP; 

         video_1 <= '0'; 

        when reseteo => 
         Hsync <= '1'; 
         next_state_H <=HV; 



        end case; 
       end process upper_part_1; 

--============================================== 
--FSM para la sincronizacion del barrido VERTICAL 
--===============================================    


lower_part_2 : process (clk,reset) 
       variable counter2 : integer range 0 to counterMAX_V; --variable para crear un contador de pulsos del clk 
      begin 
       if (reset = '1') then 
        counter2 := 0; 
        present_state_V <= reseteo; 



       elsif (clk'event and clk = '1') then 
        counter2 := counter2 + 1; 



        if (counter2 = timer2) then 
         present_state_V <= next_state_V; 
         counter2 := 0; 
        end if; 
       end if; 
       end process lower_part_2; 


upper_part_2 : process (next_state_V) 
      begin 

       Vsync <= '1'; 
       next_state_V <= HV; 

       case present_state_V is 
        when SP_1 => 
         Vsync <= '0'; 
         next_state_V <= BP; 
         timer2 <= counterSP_V; 
         video_2 <= '0'; 
        when BP => 
         Vsync <= '1'; 
         next_state_V <= HV; 
         timer2 <= counterBP_V; 

         video_2 <= '0'; 

        when HV => 
         Vsync <= '1'; 
         next_state_V <= FP; 
         timer2 <= counterVV; 

         video_2 <= '1'; 

        when FP => 
         Vsync <= '1'; 
         next_state_V <= SP_1; 
         timer2 <= counterFP_V; 

         video_2 <= '0'; 

        when reseteo => 
         Vsync <= '1'; 
         next_state_V <=HV; 


        end case; 
       end process upper_part_2; 


VIDON <= video_1 AND video_2; 
Vcount <= vcount_reg; 
Hcount <= hcount_reg; 

     end arch; 

VGD Anzeigedatei

library ieee; 
use ieee.std_logic_1164.all; 


entity VGA_display is 
    port(hcount,vcount : in integer range 0 to 799; 
     r,g,b : out std_logic_vector(3 downto 0); 
     video_on : in std_logic); 
end entity; 



architecture arch of VGA_display is 

begin 

process (video_on) 
begin 
    if video_on = '1' then --solo activamos los pixeles cuando vidon esté a uno, es decir, esten en la fase HV y VV las sincronizaciones 
      r <= "1111"; 
      g <= "0000"; 
      b <= "0000"; 

    else 
     r <= (others => '0'); 
     g <= (others => '0'); 
     b <= (others => '0'); 
    end if; 

end process; 
end arch; 
+1

Sind Sie sicher, dass Ihr Monitor den 640x480-Eingang nicht auf 1280x960 skaliert (d. H. 2x2 Pixel), um das Panel zu füllen? – NPE

+0

Eines der großen Probleme mit der 2-Prozess-Zustandsmaschine ist die Schwierigkeit, die Empfindlichkeitsliste korrekt zu machen. Ich habe Ihren Code nicht im Detail betrachtet (ich mache keine SMs mit zwei Prozessen), aber es sieht falsch aus, 'next_state_ *' in die Sensitivitätsliste zu setzen und dann 'present_state_ *' in der case-Anweisung zu testen. Es kann auch andere Empfindlichkeitslistenprobleme geben. –

+1

Die zwei Prozesse, die Brians Empfindlichkeitsliste betreffen, sind "oberes_Teil_1" und "oberes_Teil_2". Ich glaube nicht, dass sie ein Syntheseproblem sind, Sensitivitätslisten werden eher ignoriert. Sie sollten sie alle gleich beheben. – user1155120

Antwort

0

Weitere Informationen zu VGA-Theorie und VHDL-Code für VGA-Controller finden Sie in Kapitel 15 "Schaltungsentwurf und Simulation mit VHDL", 2. Ausgabe (nur in der 2. Auflage), 2010, von V. A. Pedroni.

+0

Es gibt auch Pong Chus [FPGA Prototyping von VHDL-Beispielen: Xilinx Spartan-3 Version] (http://academic.csuohio.edu/chu_p/rtl/fpga_vhdl.html) wo die Beispiele des VGA-Controllers von Kapitel 12 in [ Code-Listing-Zip-Datei] (http://academic.csuohio.edu/chu_p/rtl/fpga_vhdl_book/fpga_vhdl_src.zip), ähnlich wie die Fragesteller geschrieben. Siehe auch 3.6.6 VGA in der [DE1-Karte] (http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=German & KategorieNo = 165 & No = 836 & Teilenummer = 4) Benutzerhandbuch und suchen Sie nach VGA im VHDL-Tag in Stack Exchange. – user1155120

+0

Danke für deine Antwort !! Ich konnte es endlich beheben, also steuere ich jetzt einen 1280x1024 Bildschirm bei 60Hz :) Das Pong Chu Buch war sehr hilfreich. – osuarez

2

Ich denke, Ihr Monitor an den Ausgang synchronisiert wird und einfach Anzeige das Video im Vollbildmodus anzeigen, ähnlich wie Ihr Fernsehgerät mit einem Auxiliary-Eingang.

Ich habe Ihre H- und V-Raten in Bezug auf Ihre gemeldeten 27 MHz (~ 37 ns) berechnet und sehen, ob ich einen 1280 x 1024 LCD-Monitor finden könnte, der sie akzeptiert.

Ihr horizontaler Zähler ist counter2, der von 0 bis number_pixelsMAX_H - 1 (799) zählt, und Ihr vertikaler Zähler ist counter3, der von 0 bis number_pixelsMAX_V - 1 (524) zählt.

Das ergibt eine horizontale Rate von 800 x 37 ns = 29.600 us und eine vertikale Rate von 15,54 ms. 33,8 kHz H, V 64 Hz.

Ohne den spezifischen Monitor zu kennen, den Sie verwenden, habe ich mich nach einer beliebigen Spezifikation umgesehen und eine SXGA AMOLED-Displayspezifikation gefunden, die den Synchronisierungsratenbereich definiert.

Auf Seite 14 gibt es eine Tabelle, die den H zeigt und V-Bereiche:

Table 6-4 AC Characteristics

Es zeigt, dass dieses spezielle LCD-Panel Ihre Framerate angezeigt werden kann. Wie der Pixeltakt dafür aus den Sync-Signalen wiederhergestellt wird, hängt von einem Monitoraufbau ab, der diese spezielle Anzeige verwendet.

Alle Versionen der DE1 Karte scheinen den gleichen ADV7123 zu verwenden, um Ihr SVGA-Signal in Analogsignale umzuwandeln, die über einen 15-poligen VGA-Anschluss übertragen werden.

Ich denke, es ist sehr wahrscheinlich, dass Ihr SXGA-Rate-Monitor SVGA anzeigen kann.

Es sieht so aus, als würde ein Acer 17 Zoll V173L mit 3 VGA-Modi (60 Hz, 72 Hz und 75 Hz) und einem Mac-Modus für 640 x 480 (66 Hz) synchronisieren.

Die Fähigkeit zur Synchronisierung mit mehreren Scan-Raten ist heutzutage in Monitoren sehr häufig.

Mein sechs Jahre alter Dell 2208WP sagt mir, ich gebe ein DVI-D-Signal von 1680x1050 bei 60 Hz ein. Ich kann meinem Mac sagen, dass er die Auflösung wechseln soll, und folgt gewissenhaft den Vorgaben der DVI-Schnittstelle, die in diesem Fall auf 1024x640 beschränkt ist (wodurch alle geöffneten Fenster angepasst und abgeflacht werden).

Abhängig von Ihrem Monitor sollten Sie eine Multi-Synchronisierung über einen größeren Bereich mit einem analogen Eingang bekommen (was der DE1 bietet).

Der Mechanismus, der es für einen analogen Videoeingang funktioniert, ist der Pixeltakt zum LCD-Panel bezieht sich auf den nicht ausgeblendeten Teil einer horizontalen Linie und liefert eine Anzahl von Pixeltakten während dieses Intervalls, die der Panelauflösung entspricht Umwandlung von analogem Video in digital mit einer Rate, die alle (oder fast alle) Bildschirmpixel ausfüllt.