VGA-Treiber funktioniert nicht

Ich versuche gerade, einen VGA-Treiber für mein FPGA zu erstellen, aber irgendetwas läuft nicht richtig, und ich kann anscheinend nicht herausfinden, was falsch läuft ...

Der Code basiert auf diesem Codebeispiel: Beispiel VGA-Controller

Hier ist mein Code: (Ich habe nur die Auflösung und einige Variablennamen geändert, ansonsten sollte es genau gleich sein.)

    ----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 03/07/2016 08:53:44 AM
-- Design Name: 
-- Module Name: vga - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity vga is
    GENERIC(
            constant HR:integer:=640;--Horizontal Resolution
            constant HFP:integer:=16;--Horizontal Front Porch
            constant HBP:integer:=48;--Horizontal Back Porch
            constant HRet:integer:=96;--Horizontal retrace
            h_pol    :  STD_LOGIC := '0';   --horizontal sync pulse polarity (1 = positive, 0 = negative)

            constant VR:integer:=480;--Vertical Resolution
            constant VFP:integer:=10;--Vertical Front Porch
            constant VBP:integer:=33;--Vertical Back Porch
            constant VRet:integer:=2;--Vertical Retrace); 
            v_pol    :  STD_LOGIC := '0'  --vertical sync pulse polarity (1 = positive, 0 = negative)

            );
    Port ( clk : in STD_LOGIC;
           LED0: out std_logic;
           vga_r: out std_logic_vector(4 downto 0);
           vga_g: out std_logic_vector(5 downto 0);
           vga_b: out std_logic_vector(4 downto 0);
           vga_vs: out std_logic;
           vga_hs: out std_logic);
end vga;

architecture Behavioral of vga is
signal COUNT : integer range 0 to 100000000;
constant x_counter:  integer := HR + HFP + HBP + HRet;   
constant y_counter:  integer := VR + VFP + VBP + VRet;
signal newCounter: integer range 0 to 4 := 0;
signal newClk: std_logic; 
begin

alive: process(CLK)
    begin
        if rising_edge(CLK) then 
           COUNT  <= COUNT + 1;

           if COUNT = 100000000 then 
               COUNT <= 0; 
           end if;

           if COUNT < 100000000/2 then 
           --     LED0 <=  '1';
           else 
           --     LED0 <= '0';
           end if;           
        end if;
end process;

prescaler: process(clk)
begin
    if rising_edge(clk) then 
        newCounter <= newCounter +1; 
            if newCounter = 4  then 
                newClk <= ‘1’;
                newCounter <= 0;
            else    
                newClk <= ‘0’;  
            end if;
    end if; 
end process;




screen:process(newClk)
VARIABLE h_count  :  INTEGER RANGE 0 TO x_counter - 1 := 0;  --horizontal counter (counts the columns)
VARIABLE v_count  :  INTEGER RANGE 0 TO y_counter - 1 := 0;  --vertical counter (counts the rows)
begin
 -- Horizontal 640 
 -- Vertical 480
 if rising_edge(newClk) then
 -- Increase Horizontal counter
    if (h_count < x_counter - 1 ) then 
        h_count := h_count + 1;
    else 
        h_count := 0 ;    
        -- Increase Vertical counter   
        if (v_count < y_counter - 1 ) then 
            v_count := v_count + 1;
        else 
            v_count := 0 ;
        end if; 
    end if; 

     --horizontal sync signal
     IF(h_count < HR + HFP OR h_count > HR + HFP + HRet) THEN
        vga_hs <= NOT h_pol;    --deassert horiztonal sync pulse
        LED0 <= NOT h_pol; 
     ELSE
        vga_hs <= h_pol;        --assert horiztonal sync pulse
        LED0 <= h_pol;
     END IF;

     --vertical sync signal
     IF(v_count < VR + VFP OR v_count > VR + VFP + VRet) THEN
        vga_vs <= NOT v_pol;    --deassert vertical sync pulse
     ELSE
        vga_vs <= v_pol;        --assert vertical sync pulse
     END IF;       
 end if;
 end process;

 vga_r <= "11111";
 vga_g <= "000000";
 vga_b <= "00000";



end Behavioral;
"- Was geschieht?" "- Es funktioniert nicht."
Nun ... der Bildschirm wird schwarz ... Ich würde erwarten, dass rot angezeigt wird, da alle diese Pins hoch sind
Angenommen, Sie haben überprüft, ob Ihr H- und V-Sync-Timing und Ihre Polarität korrekt sind, ist es möglich, dass Ihr Monitor Sie überlistet - viele moderne Monitore weigern sich, ein VGA-Signal anzuzeigen, das keine erkennbare horizontale und vertikale Austastung aufweist analoge Videokanäle.
Der Monitor arbeitet mit VGA - Signal, ich habe es mit einer Bitdatei getestet, die funktionierte ... Die clk-Frequenz = 125 MHz Der Prescaler skaliert die Uhr auf 25 MHz herunter, was die Einstellung ist (die ich verwenden wollte) Die Auflösung Ich versuche neu zu erstellen ist 640 x 480
Das für die Ausblendung verwendete Signal im Beispiel-VGA-Controller teilt disp_enaIhnen mit, wenn Sie nicht ausgeblendet sind. Wenn disp_ena in hw_image_generator.vhd nicht '1' ist, dann sind r, g und b '0' (schwarz). In einer analogen Anzeige wird die Farbe während des horizontalen Rücklaufintervalls abgetastet, um zu bestimmen, wo Schwarz eingestellt ist.
Haben Sie tatsächlich überprüft, ob hsync und vsync mit einem Bereich korrekt sind?

Antworten (2)

Sie weisen Ihren VGA-Farbleitungen konstante Werte zu, was nicht funktioniert.

Ein analoger VGA-Monitor erwartet, während eines Teils der Off-Screen-Dauer der Spur einen Referenz-"Schwarz"-Pegel zu sehen. Wenn Sie dort einen Wert im Wesentlichen ungleich Null fahren, passt sich dies an die Vorstellung an, dass diese Spannung Schwarz bedeutet, und Sie erhalten nicht das erwartete Farbrechteck (auf einigen Monitoren erhalten Sie möglicherweise zuvor beim Anschließen einen kurzen Farbblitz). ganz schwarz werden).

Sie müssen Ihre Farblinien zwischen der gewünschten Farbe und Schwarz während der Zeiträume umschalten, in denen sie Farbe im aktiven Bereich oder Schwarzbezug außerhalb davon signalisieren sollten.

Zwei sehr nützliche Werkzeuge sind ein Zeitdiagramm, wie VGA aussehen sollte, und wenn möglich ein Oszilloskop, das Ihr Signal mit dem einer VGA-Karte vergleicht, um etwas Ähnliches auszugeben (Vollfarb-Bildschirmschoner?).

Soo .. Ich bin mir nicht sicher, ob ich ganz verstehe, wann Sie möchten, dass ich die Farbe von einem Zustand in einen anderen umschalte.
Der einfachste Ansatz besteht darin, die Linien immer dann schwarz zu machen, wenn sich die Spur nicht innerhalb des Rechtecks ​​​​des Bildschirms befindet, das Sie versuchen, rot zu malen. Es ist ein bisschen einfacher, wenn Sie nur ein 640x480-Rechteck malen und nicht versuchen, den Overscan einzufärben, obwohl dies mit genauerer Beachtung eines VGA-Zeitdiagramms möglich sein kann (?).

Wie bereits von Chris Stratton et.al. erwähnt, müssen Sie während der Austastintervalle die Farbe auf Schwarz setzen. Dies wurde durch das Signal disp_enain dem in Ihrer Frage verlinkten Beispieldesign erreicht.

Um Ihrem Design ein solches Verhalten hinzuzufügen, müssen Sie:

1) Fügen Sie ein neues Signal disp_enaim Architekturdeklarationsteil hinzu:

signal disp_ena : std_logic;

2) Setzen Sie dieses Signal taktsynchron auf '1', wenn das Bild angezeigt wird, und sonst auf '0' (während der Austastung).

screen:process(newClk)
-- ... existing code
begin
  if rising_edge(newClk) then
     -- ... existing code

     --set display-enable control signal
     IF(h_count < HR and v_count < VR) THEN
        disp_ena <= '1';
     ELSE
        disp_ena <= '0';
     end IF;
  end if;
end process;

3) Farbe nur auf Rot setzen, wenn Anzeige aktiviert ist ( disp_ena = '1'), sonst Schwarz. Ändern Sie daher die vorhandenen Zeilen in:

vga_r <= "11111" when disp_ena = '1' else (others => '0');
vga_g <= "000000" when disp_ena = '1' else (others => '0');
vga_b <= "00000" when disp_ena = '1' else (others => '0');

Sie erzeugen mit einem Zähler ein neues Taktsignal. Dies ist keine gute Designpraxis. Sie sollten stattdessen eine der PLLs auf dem FPGA verwenden. Sie können eine ordnungsgemäße Instanziierung über den Xilinx IP Core Generator erstellen.

Wenn Sie beim Zähler bleiben wollen, haben Sie zwei Möglichkeiten:

1) Verwenden Sie eine BUFGKomponente, um den Versatz im Taktnetzwerk zu minimieren newclk. Um diese Komponente zu verwenden, müssen Sie Folgendes einschließen:

library unisim;
use unisim.vcomponents.all;

Instanziieren Sie dann das BUFGVia:

newclk_bufg: BUFG (I => newclk, O => newclk2);

Verwenden Sie dann newclk2zum Ansteuern der Register.

2) Verwendung newclkals Taktfreigabesignal anstelle eines Taktsignals. Der screenProzess wird dann ausgelöst CLK, aber das Laden der neuen Registerwerte erfolgt nur, wenn newclkhoch ist:

screen:process(CLK)
-- ... existing code
begin
  if rising_edge(CLK) then
     if newclk = '1' then   -- newclk used as clock-enable here
        -- ... existing code
     end if;
  end if;
end process;

Prüfen Sie auch, ob Sie in der UCF-Datei (ISE) bzw. XDC-Datei (Vivado) die richtigen Timing Constraints für die Uhr angegeben haben CLK.

funktioniert immer noch nicht..
@dfh Die Generierung von newclkkönnte ein Problem sein, wie jetzt in meiner erweiterten Antwort besprochen.
Nun ... der oben gepostete Code zeigt nichts richtig an. Der Bildschirm sagt, dass die Eingabe nicht unterstützt wird.
Welche Lösung für newclkhaben Sie versucht? Sagt der Bildschirm etwas über eine falsche Frequenz? Sind Sie sicher, dass die Eingangsfrequenz für Ihr FPGA 125 MHz beträgt?