Problemas con el controlador VGA en CPLD

6

Lo que estoy intentando hacer es crear un controlador VGA a partir de un CPLD Lattice MachXO en Verilog.

El problema

Estoy intentando mostrar el color rojo con una resolución de 640x480 @ 60Hz usando un reloj interno de 25.175 MHz al CPLD; sin embargo, cuando conecto el CPLD a un monitor, aparece un mensaje de "Fuera de rango"; ningún monitor que intente puede entender qué resolución me gustaría.

Lo que he intentado

He simulado el código en ModelSim (imágenes incluidas), y todo parece verse bien, salvo por un problema. Cuando cuento la cantidad de pasos de tiempo que se han producido durante la zona de visualización de V-Sync (cuando H-Sync se está dibujando) y lo dividí por la frecuencia de H-Sync, recibo 479 pulsos, uno menos que los 480 líneas que debería estar dibujando. No entiendo de dónde podría venir esto, ya que he revisado mis tiempos muchas veces, y sospecho que este puede ser un síntoma del problema, pero no estoy seguro.

Los números que estoy usando para generar mis números para los tiempos son de Tiny VGA: tinyvga.com/vga-timing/640x480@60Hz Sin embargo, en lugar de contar líneas para V_SYNC, estoy contando pulsos de reloj. Los números deben ser equivalentes (es decir, 2 800 líneas de conteo = 1600 pulsos). Puedo cambiar este comportamiento al conteo de líneas más adelante.

A continuación se muestra mi código y las imágenes de los tiempos de 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

    
pregunta Jon.H

2 respuestas

2

Finalmente me he centrado en mi problema. En la documentación para el CPLD y por las sugerencias de mis profesores, pensé que el reloj interno del CPLD era configurable. Resulta que lo que estaba leyendo era el margen de error en el reloj, no la programabilidad. Mi problema es que el oscilador interno no se ha estado ejecutando a 25.175 MHz como pensé.

En caso de que aparezca otra fuente en Google, se debe saber que el Lattice MachXO 2280 no se puede usar para la salida VGA al valor aleatorio y no programable del reloj sin usar un oscilador externo.

    
respondido por el Jon.H
5

Necesitas mantener la salida H_SYNC incluso cuando V_SYNC está activo.

    
respondido por el Dave Tweed

Lea otras preguntas en las etiquetas