Volver al inicio

Tarjeta VGA FPGA: Verilog y temporizaciones

El artículo describe la implementación de una tarjeta de video VGA en FPGA basada en los principios de Ben Eater. Cubre módulos Verilog para divisor de reloj, contadores, señales de sincronización y ROM con color de 2 bits de BMP. Incluye código del convertidor de imagen C++.

VGA en FPGA: desde Verilog hasta la pantalla
Advertisement 728x90

Implementación de una tarjeta gráfica VGA en FPGA siguiendo los principios de Ben Eater

Los desarrolladores familiarizados con HDL apreciarán el paso de las simulaciones en Turing Complete a la implementación en hardware real. Inspirado en las ideas de Ben Eater de sus cursos en video sobre lógica discreta, este proyecto construye una simple tarjeta gráfica en un FPGA. Utiliza el chip Altera EP4CE15F23C8N con 15 000 elementos lógicos, conectado a VGA mediante temporizaciones estándar de 800x600@60Hz. El reloj del sistema de 50 MHz se divide por 5 para generar 10 MHz, coincidiendo con el proyecto original.

El módulo ClockDivider maneja la división del reloj:

module ClockDivider
( 
	input wire clk,
	output reg clk_out
);

	reg [2:0] DATA;

	always @(posedge clk) 
	begin 
		if(DATA == 3'd4)
		begin
			DATA <= 3'd0; 
			clk_out <= 1'd1;
		end
		else
		begin
			clk_out <= 1'd0;
			DATA <= DATA + 1'd1;
		end
	end
endmodule 

Características de Verilog para el desarrollo en FPGA

Verilog se distingue de los lenguajes imperativos por su ejecución paralela. Las variables se dividen en dos categorías: reg (que mantienen estado) y wire (simples cables sin almacenamiento). Los operadores de asignación generan distintos circuitos de hardware:

Google AdInline article slot
  • assign para lógica combinacional:
wire a,b,c;
assign c = a & b;
  • always @(...) = (bloqueante) para ejecución secuencial dentro de un bloque.
  • always @(posedge clk) <= (no bloqueante) para registros con reloj:
reg A;
always @(posedge clk) 
begin
	A <= ~A;
end

Los parámetros de módulo se definen con #() con valores predeterminados y se pasan por nombre durante la instanciación. La directiva `define se desaconseja por problemas del preprocesador.

Contadores para temporizaciones VGA

El contador horizontal cuenta los píxeles en una línea:

module HorizontalCounter
#(
	parameter ENDSTRING = 0
)
( 
	input wire clk,
	output reg [8:0] DATA
);

	always @(posedge clk ) 
	begin 
		if(DATA == ENDSTRING) DATA <= 9'd0;
		else DATA <= DATA + 1'd1; 
	end
endmodule 

El contador vertical se incrementa al final de cada línea:

Google AdInline article slot
module VerticalCounter
#(
	parameter ENDFRAME = 0,
	parameter ENDSTRING = 0
)
( 
	input wire clk, 
	input reg [8:0] Hor_count,
	output reg [10:0] DATA
);

	always @(posedge clk ) 
	begin 
		if(DATA == ENDFRAME) DATA <= 11'd0;
		else if (Hor_count == ENDSTRING)  DATA <= DATA + 1'd1; 
	end
endmodu

Señales como Hsync, Vsync, Hblank y Vblank se activan según las temporizaciones de tinyvga.com (los valores de porche frontal y posterior se especifican en sentencias case para H_count y V_count).

Generación de datos de video

El área visible tiene una resolución de 100x75 píxeles con profundidad de color de 2 bits (4 niveles por canal RGB, empaquetados en 6 bits). Las imágenes se preparan en Photoshop: redimensionar a 100x75, convertir a Color indexado con una paleta personalizada (0x00/0x55/0xaa/0xff) y exportar como BMP de 8 bits.

Una utilidad en C++ convierte el BMP en un array de memoria Verilog mem[]:

Google AdInline article slot
#include <windows.h>
#include <iostream>
// ... (full code parsera BMP with SetPixCollor for mappinga palitry in 6-bitnye values)

La función SetPixCollor codifica los valores RGB en bits (R2R1 G2G1 B2B1). El archivo de salida mem_block.txt se carga en una ROM del FPGA, direccionada con Hor_count[6:0] y V_count[6:0].

  • Cargar el BMP y validar los encabezados (bfType=0x4D42, biBitCount=8).
  • Leer la paleta RGBQUAD[256].
  • Procesar los píxeles y mapearlos a valores de 6 bits.
  • Generar código Verilog junto con una visualización ASCII.

Integración y depuración

El ensamblaje se realiza en Quartus Prime: los módulos se instancian con parámetros como ENDSTRING=799 y ENDFRAME=624. USB Blaster requiere firmware personalizado para un funcionamiento confiable. El simulador de Quartus sustituye a los depuradores tradicionales, mostrando oscilogramas de señales como clk_out, H_count y RGB.

Puntos clave:

  • El paralelismo de Verilog exige asignaciones no bloqueantes al trabajar con registros.
  • Las temporizaciones VGA son críticas: reloj de píxeles de 10 MHz para 800x600@60Hz.
  • El color de 2 bits mantiene la ROM simple (7500x6 bits) preservando gradientes.
  • La configuración de FPGA es económica: placa mínima sin extras + cables VGA estándar.
  • La depuración se realiza por completo en simulación, evitando problemas en tiempo de ejecución.

— Editorial Team

Advertisement 728x90

Leer después