Electronic – Trouble with VGA Controller on CPLD

latticeprogrammable-logicverilogvga

What I am attempting to do is create a VGA controller from a Lattice MachXO CPLD in Verilog.

The Problem

I am attempting to display the color red with a resolution of 640×480 @ 60Hz using a 25.175 MHz clock internal to the CPLD; however, when I plug the CPLD into a monitor I get an "Out of Range" message; no monitor I try can understand what resolution I would like.

What I've tried

I have simulated the code in ModelSim (pictures included), and everything appears to look good save for one issue. When I count the amount of time steps that have occurred from the during the V-Sync display zone (when H-Sync is drawing) and divided it by the frequency of H-Sync, I get 479 pulses — one short of the 480 lines I should be drawing. I don't understand where this could be coming from as I've check my timings many times, and I suspect that this may be a symptom of the problem, but I'm not sure.

The numbers I'm using to generate my numbers for timings is from Tiny VGA:
tinyvga.com/vga-timing/640×480@60Hz
Instead of counting lines for V_SYNC I am counting clock pulses, however, The numbers should be equivlent (ie. 2 800 count lines = 1600 pulses). I may change this behavior to line counting later.

Below is my code, and pictures of the timings from 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 and their respective counters w.r.t each other

Best Answer

You need to keep the H_SYNC output going even when V_SYNC is active.