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