Powrót do strony głównej

Karta VGA FPGA: Verilog i timingi

Artykuł opisuje implementację karty wideo VGA na FPGA według zasad Bena Eatera. Omówiono moduły Verilog dla clock divider, liczników, sygnałów synchronizacji i ROM z 2-bitowym kolorem z BMP. Podano kod C++ konwertera obrazów.

VGA na FPGA: od Verilog do ekranu
Advertisement 728x90

# Realizacja karty graficznej VGA na FPGA według zasad Bena Eatera

Deweloperzy zaznajomieni z HDL docenią przejście od symulacji w Turing Complete do rzeczywistej implementacji sprzętowej. Na podstawie idei Bena Eatera z jego kursów wideo z logiki dyskretnej powstaje prosta karta graficzna na FPGA. Wykorzystano układ Altera EP4CE15F23C8N z 15 000 elementami logicznymi, podłączony do VGA za pomocą standardowych timingów 800x600@60Hz. Częstotliwość systemowego zegara 50 MHz dzielona jest przez 5, aby uzyskać 10 MHz zgodne z oryginalnym projektem.

Modul ClockDivider zapewnia dzielenie częstotliwości:

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 

Cechy Verilog w projektowaniu FPGA

Verilog różni się od języków imperatywnych równoległym wykonywaniem. Zmienne dzielą się na reg (zachowują stan) i wire (przewody bez przechowywania). Operatory przypisania generują różne schematy:

Google AdInline article slot
  • assign do logiki kombinacyjnej:
wire a,b,c;
assign c = a & b;
  • always @(...) = (blokujące) do sekwencyjnego wykonywania wewnątrz bloku.
  • always @(posedge clk) <= (nieblokujące) do rejestrów z taktowaniem:
reg A;
always @(posedge clk) 
begin
	A <= ~A;
end

Parametry modułu ustawia się za pomocą #() z wartościami domyślnymi, przekazywanie przy instancjonowaniu odbywa się nazwowo. Dyrektywa `define nie jest zalecana ze względu na problemy preprocesora.

Liczniki do timingów VGA

Poziomy licznik śledzi piksele w linii:

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 

Pionowy licznik inkrementuje się po zakończeniu linii:

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

Sygnały Hsync, Vsync, Hblank, Vblank aktywowane są według timingów z tinyvga.com (front/back porch podane w case dla H_count/V_count).

Generowanie danych wideo

Rozdzielczość obszaru widocznego — 100x75 pikseli, 2-bitowy kolor (4 poziomy na kanał RGB, kodowanie w 6 bitach). Obraz przygotowuje się w Photoshopie: zmiana rozmiaru do 100x75, Indexed Color z niestandardową paletą (0x00/0x55/0xaa/0xff), eksport BMP 8-bit.

Narzędzie w C++ konwertuje BMP na tablicę Verilog mem[]:

Google AdInline article slot
#include <windows.h>
#include <iostream>
// ... (pełny kod parsera BMP z SetPixCollor do mapowania palety na wartości 6-bitowe)

Funkcja SetPixCollor koduje RGB w bity (R2R1 G2G1 B2B1). Wyjście mem_block.txt używane jest w ROM FPGA do adresowania według Hor_count[6:0] i V_count[6:0].

  • Wczytanie BMP, sprawdzenie nagłówków (bfType=0x4D42, biBitCount=8).
  • Odczyt palety RGBQUAD[256].
  • Parsowanie pikseli, mapowanie na 6-bit.
  • Generowanie kodu Verilog i wizualizacja ASCII.

Integracja i debugowanie

Kompilacja w Quartus Prime: moduły instancjonowane z parametrami (ENDSTRING=799, ENDFRAME=624). USB Blaster wymaga niestandardowego firmware'u dla stabilności. Symulator Quartus zastępuje zwykłe debuggery — oscylogramy sygnałów clk_out, H_count, RGB.

Co ważne:

  • Równoległość Verilog wymaga nieblokujących przypisań dla rejestrów.
  • Timingi VGA są krytyczne: 10 MHz zegar pikselowy dla 800x600@60Hz.
  • 2-bitowy kolor upraszcza ROM (7500x6 bitów), ale zachowuje gradienty.
  • Oszczędność FPGA: minimalna płytka bez peryferii + osobne kable VGA.
  • Debugowanie przez symulację, bez błędów w runtime.

— Editorial Team

Advertisement 728x90

Czytaj dalej