VHDL So entwerfen Sie einen Bildschirm (Frame)-Puffer

Ich versuche, einen Bildschirmpuffer zu verwenden, um die Bits von Videodaten zu speichern, zu ändern und an die DVI-Übertragungsschnittstelle auszugeben.

  • Ich verwende das Entwicklungskit Cyclone III von Altera.
  • Ich werde 1440x900@60Hz als Auflösung verwenden, also beträgt meine Pixeltaktrate 106,7 MHz. Die DVI-Schnittstelle wurde in einem anderen Projekt geschrieben und getestet, das keinen Bildschirmpuffer verwendet hat, aber ich denke, dass dies keine Ursache für Probleme ist.

Ich kann mich nicht entscheiden, welche Art von RAM ich als Bildschirmpuffer verwenden soll. Nach einiger Lektüre kam ich zu dem Schluss, dass abgeleiteter Dual-Port-RAM die beste Wahl wäre. Ich bin mir jedoch nicht sicher, wie ich die Lese- und Schreibports verwenden soll. Ich habe es bereits geschafft, einen RAM-Block abzuleiten und ihn mit einer Funktion zu instanziieren, die eine .mif-Datei generiert.

Meine aktuelle Entwicklung sieht wie folgt aus:

  • Wörter sind 16 Bit lang. Das bedeutet, dass RAM 81K Adressen haben wird.
  • Das Schreibfreigabesignal des READ-Ports wird immer NIEDRIG (0) sein.
  • Das Schreibfreigabesignal des SCHREIB-Anschlusses wird immer HOCH (1) sein.

Also versuche ich, GLEICHZEITIG zu schreiben und zu lesen. Die Uhr ist für beide gleich.

Ich habe der Einfachheit halber keine Codes eingebettet und versucht, so klar wie möglich zu sein. Wenn nötig oder gewünscht, werde ich Codeschnipsel posten.

Meine Frage ist folgende: Gibt es eine bessere Herangehensweise an dieses Problem, da meine bisherigen Versuche nicht erfolgreich waren. Es scheint, dass ich nicht in den RAM schreiben kann und ich kann den Grund dafür nicht finden. Irgendetwas sagt mir, dass ich Probleme mit dem Timing habe. Wenn sich jemand damit identifizieren kann, helfen Sie mir bitte.

Danke!

Bearbeiten:

Ja, ich speichere 1 Bit pro Pixel für Speicherzwecke und entscheide über die Farbe im DVI-Übertragungsblock, der danach kommt. Die Entscheidung basiert auf den Koordinaten des hcounter und vcounter des DVI. Ich instanziiere das RAM mit '1' in jeder Zelle. Ich überprüfe dies, indem ich es lese und mit einer konstanten Farbe auf dem Bildschirm ausgebe:

 if vcounter < 900 then
   if hcounter < 1440 then
        if pixel_in_sgnl = '0' then
         dviRed  <= "11111111";
         dviGreen<= "00000000";
         dviBlue <= "00000000";
         else
         dviRed   <= "00000000";
         dviBlue  <= "11111111";
         dviGreen <= "00000000";
        end if;

Wenn ich jedoch versuche, den Inhalt des RAM zu ändern und ihn dann zu lesen und auf dem Bildschirm auszugeben, lese ich sie immer noch als 1, da sich die Farbe nicht ändert. Zum Beispiel möchte ich im folgenden Code "0000000000000000" an Position 10000 schreiben, und als Ergebnis sollte ich eine andersfarbige Linie auf einem konstanten Hintergrund beobachten. Ich hoffe, ich konnte klar genug sein.

FB: FrameBuffer port map ( data_a => "0000000000000000",
                                data_b => "ZZZZZZZZZZZZZZZZ",   
                                addr_a => 10000, --address_write_sgnl,
                                addr_b => address_read_sgnl,
                                we_a  => '1',
                                we_b => '0',
                                clk_106 => DVI_clock,
                                q_a => open,
                                q_b => pixel_data_sgnl);

Dies ist der abgeleitete RAM, den ich online gefunden und leicht modifiziert habe:

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

entity FrameBuffer is
    port 
    (   
        data_a  : in std_logic_vector(15 downto 0);
        data_b  : in std_logic_vector(15 downto 0);
        addr_a  : in natural range 0 to 80999;
        addr_b  : in natural range 0 to 80999;
        we_a        : in std_logic ;
        we_b        : in std_logic ;
        clk_106     : in std_logic;
        q_a     : out std_logic_vector(15 downto 0);
        q_b     : out std_logic_vector(15 downto 0)
    );

end FrameBuffer;

architecture rtl of FrameBuffer is

    -- Build a 2-D array type for the RAM
    subtype word_t is std_logic_vector(15 downto 0);
    type memory_t is array(0 to 80999) of word_t;

    FUNCTION initialize_ram
        return memory_t is
        variable result : memory_t;
        BEGIN
            FOR i IN 0 to 80999 LOOP
                result(i) := "1111111111111111";
            END LOOP;
        RETURN result;
    END initialize_ram;


    -- Declare the RAM
    shared variable ram : memory_t :=initialize_ram ;

begin


    -- Port A
    process(clk_106)
    begin
        if(rising_edge(clk_106)) then -- Port A
            if(we_a = '1') then
                ram(addr_a) := data_a;
            -- Read-during-write on the same port returns NEW data
                q_a <= data_a;
            else
            -- Read-during-write on the mixed port returns OLD data
                q_a <= ram(addr_a);
            end if;
        end if;
    end process;

    -- Port B
    process(clk_106)
    begin
        if(rising_edge(clk_106)) then -- Port B
            if(we_b = '1') then
                ram(addr_b) := data_b;
            -- Read-during-write on the same port returns NEW data
                q_b <= data_b;
            else
            -- Read-during-write on the mixed port returns OLD data
                q_b <= ram(addr_b);
            end if;
        end if;
    end process;
end rtl;

Edit2:

Ich glaube, ich habe es geschafft, das Problem des Schreibens in den RAM zu lösen, aber ich kann immer noch darüber diskutieren, um mein Design zu verbessern. Jetzt stecke ich fest, wenn ich meinen Pufferausgang an DVI füttere. Wie ich bereits erwähnt habe, halte ich 1 Bit pro Pixel im RAM, aber die RAM-Ausgangsbreite beträgt 16 Bit. Also muss ich diese 16 Bit speichern und sie bei jeder DVI-Taktflanke nacheinander an DVI senden. Ich mache es wie folgt:

process(clk106M, locked_sgnl)
begin
  if locked_sgnl = '0' then
                address_counter <= (others => '0');
                counter <= "10000";
                pixel_in_register <= (others => '0');
  elsif rising_edge(clk106M) and (locked_sgnl = '1') then
     if (address_counter < "10011110001101000") then
                        if counter >= 16 then
                                pixel_in_register <= pixel_in;
                                address_counter <= address_counter + '1';
                                counter <= "00000";
                        else
                                pixel_in_sgnl <= pixel_in_register(0);
                                pixel_in_register <= '0' & pixel_in_register(15 downto 1);
                                counter <= counter + '1';
                        end if;
          else
                        address_counter <= (others => '0');
          end if;

 end if;
end process;

 buffer_address_dvi <= address_counter;

Ich verwende ein Register und halte die Pufferausgabe im Inneren. Dann gebe ich bei jedem Taktzyklus für 16 Zyklen das LSB des Inhalts des Registers aus und verschiebe die Daten nach rechts. Was mir im Kopf bleibt, ist, ob ich die Leseadresse früher generieren muss oder nicht.

Wenn derzeit eine 0 im Puffer vorhanden ist, entspricht dieses Pixel Grün. Wenn 1, entspricht es Blau. Was ich tue, ist, dass ich den RAM voller '1's instanziiere. Dann schreibe ich '0' in einen Teil davon und versuche, eine dicke horizontale Linie auf dem Bildschirm zu beobachten. Glücklicherweise sehe ich diese horizontale Linie, aber sie ist nicht stationär. Es wischt den Bildschirm von oben nach unten oder von unten nach oben, ich kann es nicht unterscheiden. Was könnte die Ursache für dieses spezielle Problem sein?

Ich nehme an, Sie speichern nur 1 Bit pro Pixel, 16 Pixel pro Speicherort. Wenn Sie "abgeleiteten" RAM verwenden, müssen wir den von Ihnen verwendeten Code sehen. Es wäre auch hilfreich, wenn Sie beschreiben (oder besser noch, den Code dafür bereitstellen), was das Schreiben tut, und warum Sie glauben, dass das Problem beim Schreiben und nicht beim Lesen liegt.
@DaveTweed Ich habe meine ursprüngliche Frage bearbeitet. Hoffe, ich habe genug Informationen hinzugefügt! Danke
Klingt so, als ob Sie in Ihrem vertikalen Timing ein wenig daneben liegen, höchstwahrscheinlich um 1.
@mng Ich konnte das Problem nicht lösen und bin jetzt wirklich verärgert. Irgendwelche Ratschläge, was man ändern sollte? Danke!
Sie sollten alles überprüfen, wo Sie entlang des Arrays zählen, da etwas falsch ausgerichtet wird. Versuchen Sie, die Zahlen zu ändern, und sehen Sie, wie sich dies auf das Ergebnis auswirkt. Wenn Sie nichts finden können, müssen Sie sich möglicherweise auch die DVI-Schnittstelle ansehen.

Antworten (1)

Vor ein paar Tagen gefunden:

Ich habe die Framebuffer-Adresse nicht nur während des aktiven Teils des DVI erhöht, sondern auch während der Austastperioden. Dies führte zu einer Verschiebung auf dem Bildschirm. Vielen Dank für Ihre Antworten.