FPGA ile VGA Monitör Kontrolü

VGA(Video Graphics Array), IBM tarafında geliştirilen ve bilgisayarlarda görüntüyü analog olarak aktarmakta kullanılan bir protokoldür. Görüntü sinyali R, G, B, HSync ve VSync olmak üzere 5 tel üzerinde gerçekleşir. RGB sinyalleri 0.7Vpp aralığında analog sinyallerdir. HSync ve VSync sinyalleri ise TTL yapıdadır. RGB sinyallerinin analog yapıda olmasından dolayı uzun mesafelerde ve yüksek çözünürlük, yenileme oranı, renk derinliğinde dijital protokollere göre başarısız kalmıştır.

HSync(Horizontal Sync) ve VSync(Vertical Sync) sinyalleri RGB sinyallerini senkronize etmek için kullanılır. Aşağıda bir frame görüntü oluşturulurken HSync ve VSync sinyallerinin durumu görülebilir.

Yukarıda da görüdüğü gibi HSync ve VSync sinyalleri belirli zamanlarda ve belirli polaritede pulse sinyalleri üreterek RGB sinyallerini senkronize etmiş olur.

Bütün zamanlama ve polarite parametreleri istenilen çözünürlüğe ve yenileme süresine göre belirlenmiştir. Bütün parametrelere buradan ulaşabilirsiniz.

HVA ve VVA alanlarında görüntü RGB sinyallerinden gönderilir.

FPGA VGA Modülü:

--Kütüphaneler
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; 

entity VGA is
    generic(RGBLength : integer := 1);                               --R, G, B sinyallerinin genişliği
                                                                     --(Renk derinliği)
                                                                                          
    port(Clk : in std_logic;                                         --Clk girişi
    
        X, Y : out std_logic_vector(15 downto 0);                     --X,Y koordinatları
                                                                      --Bu sinyaller o an hangi pixelin DAC'ye
                                                                                          --gönderileceğini belirtir.
        Rin, Gin, Bin : in std_logic_vector(RGBLength - 1 downto 0);  --R, G, B bilgileri
                                                                      --Okunan X, Y sinyallerine göre istenen 
                                                                                          --RGB verisi bu sinyaller tarafında gönderilir.
        
                                                                      --Monitöre giden sinyaller
        R, G, B : out std_logic_vector(RGBLength - 1 downto 0);       --DAC'ye gönderilercek RGB sinyalleri
        HSync, VSync : out std_logic);                                --Yatay ve Dikey senkronizasyon sinyalleri
end VGA;

architecture Behavioral of VGA is
    
--108Mhz'e ayarlanmış PLL (1024x1280 @60Hz)
component pll
    PORT
    (
        inclk0        : IN STD_LOGIC  := '0';
        c0        : OUT STD_LOGIC ;
        locked        : OUT STD_LOGIC 
    );
end component;    
    
    signal PixelClk, PLLLocked : std_logic;
    signal HSyncSignal, VSyncSignal : std_logic;
    
    --Timing Parametreleri (1024x1280 @60Hz)

    constant HorizontalVisibleArea : integer := 1280;
    constant HorizontalFrontPorch : integer := 48;
    constant HorizontalSyncPulse : integer := 112;
    constant HorizontalBackPorch : integer := 248;
    
    constant VerticalVisibleArea : integer := 1024;
    constant VerticalFrontPorch : integer := 1;
    constant VerticalSyncPulse : integer := 3;
    constant VerticalBackPorch : integer := 38;
    
    constant HorizontalSyncPolarity : std_logic := '1'; --Sync polariteleri pozitif
    constant VerticalSyncPolarity : std_logic := '1';
    
    constant HorizontalWholeLine : integer := HorizontalVisibleArea +
                                                            HorizontalFrontPorch +
                                                            HorizontalSyncPulse +
                                                            HorizontalBackPorch;
                                                            
    constant VerticalWholeLine : integer := VerticalVisibleArea +
                                                         VerticalFrontPorch +
                                                         VerticalSyncPulse +
                                                         VerticalBackPorch;
    
    
begin

    --Sync Polarity '1' ise Sync sinyali terslenir
    with HorizontalSyncPolarity select
        HSync <= HSyncSignal when '0',
                    not HsyncSignal when others;
                    
    with VerticalSyncPolarity select
        VSync <= VSyncSignal when '0',
                    not VsyncSignal when others;

    VGAPLL : pll
        port map(Clk, PixelClk, PLLLocked);
        
        
    process(PixelClk)
    variable H, V : integer range 0 to 2047 := 0;
    begin
    
        --PixelClk'un yükselen kenarı ile H değişkeninin
        --değeri 1 arttırılır. H değeri toplam Horizontal zamanına 
        --ulaşınca H değişkeni resetlenir ve V değeri 1 arttırılır.
        --V değeri toplam Vertical zamana ulaşınca resetlenir.
        if rising_edge(PixelClk) and PLLLocked = '1' then
            if H < HorizontalWholeLine - 1 then
                H := H + 1;
            else
                H := 0;
                if V < VerticalWholeLine - 1 then
                    V := V + 1;
                else
                    V := 0;
                end if;
            end if;
        end if;
        
        
        --HSync kontrolü
        
        --Visible area
        if H < HorizontalVisibleArea - 1 then
            HSyncSignal <= '1';
        
        --Front porch
        elsif H < HorizontalVisibleArea + 
                        HorizontalFrontPorch - 1 then
            HSyncSignal <= '1';
        
        --Sync pulse
        elsif H < HorizontalVisibleArea +
                        HorizontalFrontPorch +
                        HorizontalSyncPulse - 1 then
            HSyncSignal <= '0';
        
        --Back porch
        elsif H < HorizontalWholeLine - 1 then
            HSyncSignal <= '1';
        
        end if;
        
        
        
        --VSync kontrolü
        
        --Visible area
        if V < VerticalVisibleArea - 1 then
            VSyncSignal <= '1';
        
        --Front porch
        elsif V < VerticalVisibleArea + 
                        VerticalFrontPorch - 1 then
            VSyncSignal <= '1';
        
        --Sync pulse
        elsif V < VerticalVisibleArea +
                        VerticalFrontPorch +
                        VerticalSyncPulse - 1 then
            VSyncSignal <= '0';
        
        --Back porch
        elsif V < VerticalWholeLine - 1 then
            VSyncSignal <= '1';
        
        end if;
        
        
        --H ve V değerleri görüntü alanı içerisinde ise
        --R, G, B sinyalerine görüntü bilgileri gönderilir.
        
        if H < HorizontalVisibleArea and V < VerticalVisibleArea then
            
            R <= Rin;
            G <= Gin;
            B <= Bin;
            
            X <= std_logic_vector(to_unsigned(H, X'length));
            Y <= std_logic_vector(to_unsigned(V, X'length));

        else
        
            R <= (others => '0');
            G <= (others => '0');
            B <= (others => '0');
            
            X <= (others => '0');
            Y <= (others => '0');
            
        end if;
            
    end process;

end Behavioral;

Quartus II programı tarafından oluşturulan RTL şeması:

1-Bit Renk Paleti Oluşturma:

--Kütüphaneler
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; 

entity VGA_Test is
    generic(RGBLength : integer := 1);
    port(Clk : in std_logic;                                    --Clk girişi
        R, G, B : out std_logic_vector(RGBLength - 1 downto 0);  --VGA R, G, B sinyalleri
        HSync, VSync : out std_logic);                           --VGA HSync, VSync sinyalleri
end VGA_Test;

architecture Behavioral of VGA_Test is
    
--VGA sürücü componenti    
component VGA
    generic(RGBLength : integer := 1);                               --R, G, B sinyallerinin genişliği
                                                                     --(Renk derinliği)
                                                                                          
    port(Clk : in std_logic;                                         --Clk girişi
    
        X, Y : out std_logic_vector(15 downto 0);                     --X,Y koordinatları
                                                                      --Bu sinyaller o an hangi pixelin DAC'ye
                                                                                          --gönderileceğini belirtir.
        Rin, Gin, Bin : in std_logic_vector(RGBLength - 1 downto 0);  --R, G, B bilgileri
                                                                      --Okunan X, Y sinyallerine göre istenen 
                                                                                          --RGB verisi bu sinyaller tarafında gönderilir.
        
                                                                      --Monitöre giden sinyaller
        R, G, B : out std_logic_vector(RGBLength - 1 downto 0);       --DAC'ye gönderilercek RGB sinyalleri
        HSync, VSync : out std_logic);                                --Yatay ve Dikey senkronizasyon sinyalleri
end component;    


    signal Xs, Ys : std_logic_vector(15 downto 0);
    
    signal X, Y : integer range 0 to 2**20-1;
    signal Rin, Gin, Bin : std_logic_vector(0 downto 0);

begin

    --Xs, Xs sinyalleri integer'a dönüştürülür
    X <= to_integer(unsigned(Xs));
    Y <= to_integer(unsigned(Ys));

    VGADriver : VGA
        generic map(1)
        port map(Clk, Xs, Ys, Rin, Gin, Bin, R, G, B, HSync, VSync);
        
    process(X, Y)
    begin
        
        --Renk Paleti
        Bin(0) <= std_logic_vector(to_unsigned(X / 160, 3))(0);
        Gin(0) <= std_logic_vector(to_unsigned(X / 160, 3))(1);
        Rin(0) <= std_logic_vector(to_unsigned(X / 160, 3))(2);
                
    end process;
        
end Behavioral;

Daireler:

--Kütüphaneler
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; 

entity VGA_Test is
    generic(RGBLength : integer := 1);
    port(Clk : in std_logic;                                    --Clk girişi
        R, G, B : out std_logic_vector(RGBLength - 1 downto 0);  --VGA R, G, B sinyalleri
        HSync, VSync : out std_logic);                           --VGA HSync, VSync sinyalleri
end VGA_Test;

architecture Behavioral of VGA_Test is
    
--VGA sürücü componenti    
component VGA
    generic(RGBLength : integer := 1);                               --R, G, B sinyallerinin genişliği
                                                                     --(Renk derinliği)
                                                                                          
    port(Clk : in std_logic;                                         --Clk girişi
    
        X, Y : out std_logic_vector(15 downto 0);                     --X,Y koordinatları
                                                                      --Bu sinyaller o an hangi pixelin DAC'ye
                                                                                          --gönderileceğini belirtir.
        Rin, Gin, Bin : in std_logic_vector(RGBLength - 1 downto 0);  --R, G, B bilgileri
                                                                      --Okunan X, Y sinyallerine göre istenen 
                                                                                          --RGB verisi bu sinyaller tarafında gönderilir.
        
                                                                      --Monitöre giden sinyaller
        R, G, B : out std_logic_vector(RGBLength - 1 downto 0);       --DAC'ye gönderilercek RGB sinyalleri
        HSync, VSync : out std_logic);                                --Yatay ve Dikey senkronizasyon sinyalleri
end component;    


    signal Xs, Ys : std_logic_vector(15 downto 0);
    
    signal X, Y : integer range 0 to 2**20-1;
    signal Rin, Gin, Bin : std_logic_vector(0 downto 0);
    
    type integer_array is array (7 downto 0) of integer range 0 to 2**10-1;

begin

    --Xs, Xs sinyalleri integer'a dönüştürülür
    X <= to_integer(unsigned(Xs));
    Y <= to_integer(unsigned(Ys));

    VGADriver : VGA
        generic map(1)
        port map(Clk, Xs, Ys, Rin, Gin, Bin, R, G, B, HSync, VSync);
        
    process(Clk)
    variable ClkCnt : integer range 0 to 2**18-1 := 0;
    
    --Çemberlerin yarıçaplarının tutulduğu dizi
    variable R : integer_array := (0, 100, 200, 300, 400, 500, 600, 700);
    
    --O anki X ve Y değerlerinde çemberlerin bir noktasının
    --olup olmadığını tutan dizi
    variable N : std_logic_vector(7 downto 0);
    begin
        
        --Her 10ms'de çemberlerin yarıçapı 1 arttırılır
        if rising_edge(Clk) then
            if ClkCnt < 249999 then
                ClkCnt := ClkCnt + 1;
            else
                ClkCnt := 0;
                
                --Her bir çemberin yarıçapı 1 arttırılır
                for i in 0 to 7 loop
                    if R(i) < 800 then
                        R(i) := R(i) + 1;
                    --Eğer yarıçap 799 dan büyük ise resetlenir. 
                    else
                        R(i) := 0;
                    end if;
                end loop;
                
            end if;
        end if;
        
        --Her bir çemberin o anki X, Y değerleri üzerinde bir
        --noktası olup olmadığını hesaplayan döngü
        for i in 0 to 7 loop
            if ((R(i) - 5)**2) < ((X - 640)**2 + (Y - 512)**2) and
            ((X - 640)**2 + (Y - 512)**2) < ((R(i) + 5)**2) then
                N(i) := '1';
            else
                N(i) := '0';
            end if;
        end loop;
        
        --O anki X, Y koordinatlarında, herhangi bir çemberin
        --noktası bulunuyor ise kırmızı rengi gönderilir.
        if N /= X"00" then
            Rin <= "1";
            Gin <= "0";
            Bin <= "0";
            
        --Bulunmuyor ise cam göbeği rengi gönderilir.
        else
            Rin <= "0";
            Gin <= "1";
            Bin <= "1";
        end if;
                
    end process;
        
end Behavioral;

 

 

Yeni Versiyon (4.10.2017):

----------------------------- VGA.vhd --------------------------------
--                         Bertan Taşkın
--                           4.10.2017
--                          Versiyon 2.0
--
-- VGA kontrolcüsü. Zamanlama parametreleri generic kısmından ayarlanabilir.
-- BufferAddress sinyali o anki pixelin buffer'daki adresini belirtir.
-- BufferAddress belirtildikten 1 cycle sonra BufferData'dan veriler okunur.
--
--
-- Versiyon Notları:
--
-- Versiyon 1.0 (23.4.2017): İlk sürüm.
--
-- Versiyon 2.0 (4.10.2017): HSync ve VSync'deki zamanlama hataları
-- 	düzeltildi.
--		Zamanlama parametreleri generic kısmına taşındı.
--    DE(Data Enabe) çıkışı eklendi.
--    BufferAddress(eski X, Y) ile BufferData(eski R, G, B) arasına
--    1 cycle eklendi.
--    Kod daha sade bir şekilde tekrar yazıldı.
--

--Kütüphaneler
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL; 

entity VGA is
	generic(HorizontalVisibleArea : natural := 1440; --Zamanlama Parametreleri
		HorizontalFrontPorch : natural := 80;
		HorizontalSyncPulse : natural := 152;
	   HorizontalBackPorch : natural := 232;
		VerticalVisibleArea : natural := 900;
		VerticalFrontPorch : natural := 1;
		VerticalSyncPulse : natural := 3;
		VerticalBackPorch : natural := 28;	
		HorizontalSyncPolarity : std_logic := '1';   --Sync Polariteleri
		VerticalSyncPolarity : std_logic := '1';
		RGBLength : integer := 8);																					  
	port(PixelClk, Enable : in std_logic;                              --Pixel Clock ve Enable Girişi
		Red, Green, Blue : out unsigned(RGBLength - 1 downto 0);       --RGB Çıkışları
		HSync, VSync : out std_logic;                                  --HSync ve VSync Çıkışı
		DE : out std_logic;                                            --Data Enable Çıkışı
		BufferAddress : out std_logic_vector(31 downto 0);             --Buffer Address Çıkışı
		BufferData : in std_logic_vector(RGBLength * 3 - 1 downto 0)); --Buffer Data Girişi
end VGA;

architecture Behavioral of VGA is
	
	--Toplam yatay pixel
	constant HorizontalWholeLine : integer := HorizontalVisibleArea +
															HorizontalFrontPorch +
															HorizontalSyncPulse +
															HorizontalBackPorch;
	
	--Toplam dikey pixel
	constant VerticalWholeLine : integer := VerticalVisibleArea +
														 VerticalFrontPorch +
														 VerticalSyncPulse +
														 VerticalBackPorch;
	
	signal HCount : natural range 0 to HorizontalWholeLine - 1 := 0;
	signal VCount : natural range 0 to VerticalWholeLine - 1 := 0;
	
	signal HPulse, VPulse : std_logic;
	signal HVisible, VVisible : std_logic;
	
begin

	--BufferAddress'in hesaplanması
	BufferAddress <= std_logic_vector(to_unsigned(VCount * HorizontalVisibleArea + HCount, 32));
	
	process(PixelClk)
	begin
		
		if rising_edge(PixelClk) and Enable = '1' then
			
			--HCount arttırılır
			if HCount < HorizontalWholeLine - 1 then
				HCount <= HCount + 1;
			else
				--HCount sona ulaştığında resetlenir ve VCount arttırılır
				HCount <= 0;
				if VCount < VerticalWholeLine - 1 then
					VCount <= VCount + 1;
				else
					VCount <= 0;
				end if;
			end if;	
			
			--HCount visible area içindeyse HVisible setlenir
			if HCount < HorizontalVisibleArea then
				HPulse <= '0';
				HVisible <= '1';
			elsif HCount < HorizontalVisibleArea + 
								HorizontalFrontPorch then
				HPulse <= '0';
				HVisible <= '0';
			--HCount pulse alanı içindeyse HPulse setlenir.
			elsif HCount < HorizontalVisibleArea +
								HorizontalFrontPorch +
								HorizontalSyncPulse then
				HPulse <= '1';
				HVisible <= '0';	
			elsif HCount < HorizontalWholeLine then
				HPulse <= '0';
				HVisible <= '0';
			end if;
			
			--VCount visible area içindeyse VVisible setlenir
			if VCount < VerticalVisibleArea then
				VPulse <= '0';
				VVisible <= '1';
			elsif VCount < VerticalVisibleArea + 
								VerticalFrontPorch then
				VPulse <= '0';
				VVisible <= '0';
			--VCount pulse alanı içindeyse VPulse setlenir.
			elsif VCount < VerticalVisibleArea +
								VerticalFrontPorch +
								VerticalSyncPulse then
				VPulse <= '1';	
				VVisible <= '0';
			elsif VCount < VerticalWholeLine then
				VPulse <= '0';	
				VVisible <= '0';
			end if;	
			
			--Horizontal pulse üretimi
			if HPulse = '1' then
				HSync <= HorizontalSyncPolarity;
			else
				HSync <= not HorizontalSyncPolarity;
			end if;
			
			--Vertical pulse üretimi
			if VPulse = '1' then
				VSync <= VerticalSyncPolarity;
			else
				VSync <= not VerticalSyncPolarity;
			end if;
					
			--Her iki yönde de visible alan içindeyse RGB sinyalleri gönderilir ve
			--Data Enable setlenir
			if HVisible = '1' and VVisible = '1' then		
				Red <= unsigned(BufferData(RGBLength * 3 - 1 downto RGBLength * 2));
				Green <= unsigned(BufferData(RGBLength * 2 - 1 downto RGBLength));
				Blue <= unsigned(BufferData(RGBLength - 1 downto 0));
				DE <= '1';
			--Her iki yönde en az biri visible alan dışındaysa RGB ve Data Enable
			--resetlenir
			else			
				Red <= to_unsigned(0, RGBLength);
				Green <= to_unsigned(0, RGBLength);
				Blue <= to_unsigned(0, RGBLength);
				DE <= '0';				
			end if;
						
		end if;
		
	end process;

end Behavioral;

5 thoughts on “FPGA ile VGA Monitör Kontrolü”

  1. İyi günler.
    Bu faydalı paylaşımınız için teşekkür ederim.
    Acaba pll kodunuzu paylaşır mısınız?

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.