Problem mit VGA-Controller auf CPLD

Ich versuche, einen VGA-Controller aus einem Lattice MachXO CPLD in Verilog zu erstellen.

Das Problem

Ich versuche, die Farbe Rot mit einer Auflösung von 640 x 480 bei 60 Hz anzuzeigen, indem ich einen CPLD-internen 25,175-MHz-Takt verwende. Wenn ich jedoch das CPLD an einen Monitor anschließe, erhalte ich die Meldung „Außer Reichweite“. Kein Monitor, den ich versuche, kann verstehen, welche Auflösung ich möchte.

Was ich versucht habe

Ich habe den Code in ModelSim simuliert (Bilder enthalten), und bis auf ein Problem scheint alles gut auszusehen. Wenn ich die Anzahl der Zeitschritte zähle, die während der V-Sync-Anzeigezone aufgetreten sind (wenn H-Sync zeichnet) und sie durch die H-Sync-Frequenz dividiere, erhalte ich 479 Impulse – einer weniger als 480 Linien, die ich zeichnen sollte. Ich verstehe nicht, woher das kommen könnte, da ich meine Timings viele Male überprüft habe, und ich vermute, dass dies ein Symptom des Problems sein könnte , aber ich bin mir nicht sicher.

Die Zahlen, die ich verwende, um meine Zahlen für Timings zu generieren, stammen von Tiny VGA: tinyvga.com/vga-timing/640x480@60Hz Anstatt Zeilen für V_SYNC zu zählen, zähle ich jedoch Taktimpulse. Die Zahlen sollten jedoch gleichwertig sein (dh. 2 800 Zählstriche = 1600 Impulse). Ich kann dieses Verhalten später in Zeilenzählung ändern.

Unten ist mein Code und Bilder der Timings von ModelSim.

module Top(RESET, H_SYNC, V_SYNC, RED);
    input  wire RESET;
    output wire H_SYNC;
    output wire V_SYNC;
    output wire RED;

    wire rgb_en;

    /*** Test Bench Code ***/
     //reg osc_clk, reset;
     //initial begin
         //#0 reset     = 0;
         //#0 osc_clk = 0;
         //#2 reset     = 1;
     //end

     //always #1 osc_clk = ~osc_clk;

    OSCC        OSCC_1 (.OSC(osc_clk)); /*< IP clock module for Lattice CPLD    >*/
    Controller  CNTRL(.NRST(RESET), .CLK(osc_clk), .H_SYNC(H_SYNC), .V_SYNC(V_SYNC), .RGB_EN(rgb_en));

    assign RED = (rgb_en ? 1:1'bz); 

endmodule

module Controller(CLK, NRST, H_SYNC, V_SYNC, RGB_EN);
    input  wire CLK;        /*< CLK input from Top module   >*/
    input  wire NRST;       /*< Reset input from Top module >*/
    output reg  H_SYNC;     /*< Goes to VGA Horizontal Sync >*/
    output reg  V_SYNC;     /*< Goes to VGA Verical Sync    >*/
    output reg  RGB_EN  ;   /*< Enables RGB values durning display time on H_SYNC >*/

    reg [9:0] h_counter;   /*< Tracks amount of pulses from CLK                 >*/
    reg [18:0] v_counter;  /*< Tracks amount of pulses from H_SYNC              >*/

    `define H_SYNC_PULSE        10'd96      /*< Length of Sync Pulse            >*/
    `define H_BACK_PORCH_END    10'd144     /*< Pulse len + Porch Len           >*/
    `define H_FRONT_PORCH_STRT  10'd784     /*< Front Porch Len - Max           >*/
    `define H_COUNT_MAX         10'd799     /*< Max line pulses for resolution  >*/

    `define V_SYNC_PULSE        19'd1600    /*< 2 H_SYNC lines       >*/
    `define V_BACK_PORCH_END    19'd28000   /*< 33+2 H_SYNC lines    >*/
    `define V_FRONT_PORCH_STRT  19'd412000  /*< 525-10 H_SYNC lines  >*/
    `define V_COUNT_MAX         19'd419999  /*< 525 H_SYNC lines     >*/

    /*** Logic for H_SYNC ***/
    always @(*) begin
        if (h_counter < `H_SYNC_PULSE) begin
            H_SYNC = 0;
            RGB_EN = 0;
        end
        /* If H_Sync is in the display zone, enable RGB */
        else if (h_counter > `H_BACK_PORCH_END && h_counter < `H_FRONT_PORCH_STRT) begin
            H_SYNC = 1;
            RGB_EN = 1;
        end
        /* During the Front Porch period, disable RGB */
        else begin
            H_SYNC = 1;
            RGB_EN = 0;
        end
    end

    /*** Logic for V_SYNC ***/
    always @(*) begin
        if (v_counter < `V_SYNC_PULSE) begin
            V_SYNC = 0;
        end
        else begin
            V_SYNC = 1;
        end
    end

    /*** Counter logic ***/
    always @(posedge CLK) begin
        if (h_counter >= `H_COUNT_MAX || !NRST) begin
            h_counter <= 11'b00;
        end
        else begin
            h_counter <= h_counter + 1;
        end
    end

    always @(posedge CLK) begin
        if (v_counter >= `V_COUNT_MAX || !NRST) begin
            v_counter <= 11'b00;
        end
        else begin
            v_counter <= v_counter + 1;
        end
    end

endmodule

H/V_SYNC und ihre jeweiligen Zähler zueinander

Sie sollten wirklich die mit einem Oszilloskop gemessenen tatsächlichen Wellenformen in Ihre Frage aufnehmen. Ich habe wenig Grund gefunden, programmierbaren Logiksimulationen zu vertrauen.
Ein allgemeiner Kommentar: In Ihrem Code sagen Sie, dass Sie "Zustandsmaschinen" für V_SYNC und H_SYNC erstellen, aber für mich sieht es so aus, als würden diese Immer-Blöcke nur kombinatorische Logik erstellen. Die einzige zustandsmaschinenartige Sache, die Sie derzeit haben, ist der Zähler.
Ich stimme zu. Kommentar wurde bearbeitet.

Antworten (2)

Sie müssen den H_SYNC-Ausgang auch dann aufrecht erhalten, wenn V_SYNC aktiv ist.

Danke Dave, ich habe Material gefunden, das auch Ihre Antwort bestätigt. Ich habe den Code seitdem so angepasst, dass die H_SYNC-Ausgabe immer läuft, und werde die Bilder so schnell wie möglich später heute aktualisieren. Leider besteht das Problem weiterhin; Ich erhalte immer noch "Out of Range"-Fehler.

Endlich habe ich mein Problem eingekreist. In der Dokumentation für das CPLD und gemäß den Vorschlägen meiner Professoren dachte ich, dass die interne Uhr des CPLD konfigurierbar sei. Es stellt sich heraus, dass ich die Fehlerspanne auf der Uhr gelesen habe, nicht die Programmierbarkeit. Mein Problem ist, dass der interne Oszillator nicht mit 25,175 MHz läuft, wie ich dachte.

Falls eine andere Seele dies googelt, lassen Sie es wissen, dass der Lattice MachXO 2280 nicht für die VGA-Ausgabe verwendet werden kann, da der Zufallswert und die Unprogrammierbarkeit der Uhr ohne die Verwendung eines externen Oszillators erfolgen.