VHDL ile Ekran Sürme (VGA, SVGA, XGA, WXGA, FullHD)

Uzun bir aradan sonra birazda can sıkıntısından dolayı yeni bir yazı yazmaya karar verdim. Tabiri caizse ders çalışmamak için yapılan anlamsız hareketler (yazar burada ilgili ekşisözlük başlığını şiddetle tavsiye eder) serisine yeni bir soluk getirerek FPGA ile VGA ekran sürelim dedim. Önce gerekli malzemeler:

  • 1 adet NEXYS4 FPGA Kartı (Basys3,2, Ailesi de olabilir)

  • Vivado Design Suite 2014 serisi veya 2015.x serisi

  • 1 adet VGA girişli ekran

Yemek tarifi ekolünden etkilenmiş yazımıza devam edelim. Bu aralar gözdem olan kartlardan biri NEXYS4. Türkiye içerisinden www.elektrovadi.com (Beti Bilişim) üzerinden temin edilebilecek bir kart. Öğrenci iseniz bir de indirim olmakta. Güncel fiyatı öğrenciler için 680 TL civarlarında. Ya da Basys3 kartını (öğrenciler için ~370 TL civarlarında) da önerebilirim, yine Beti Bilişim’den temin edebilirsiniz.

Yazı için faydalandığım ana kaynak ise şurası:

https://learn.digilentinc.com/Documents/269

Gelelim ana konuya. FPGA üzerinde çalışırken bir yerden sonra herkes yaptığı şeyleri görselleştirmek ister. Bir resim olsun, basit bir oyun olsun ekran üzerinde bunu görmek gerçekten eğlencelidir.

VGA Standardı

VGA standardı aslında oldukça basit bir yapıdadır. Aşağıda verilen çizimden de görüleceği üzere toplamda 5 pin ile ekran sürme işlemini gerçekleştirebilmekteyiz. Bunlar Kırmızı(R),Yeşil(G) ve Mavi(B) renk pinleri ile Yatay(Horizontal Sync.), Dikey(Vertical Sync.) eşzamanlama pinleridir.

vga

RGB pinleri ile ilgili beneğe (pixel) ait renk bilgisi oluşturulurken, yatay ve dikey eşzamanlama pinleri ile de ilgili beneğin seçimi yapılmaktadır.

Ekranlar Nasıl Çalışır?

Aslında burda anlatılan bilgiler CRT ekranlar için geçerli olmakla birlikte, LCD ekranlar da geriye dönük uyumluluk sergilediği için, ekran sürme tekniği yönünden aynı mantık geçerlidir. CRT ekranlar temelde bir elektron tabancası tarafından uyarılan fosforlu yüzeylerdir. Baside indirgeyerek anlatsamda arka tarafta aslında baya bir süreç vardır.Bir CRT ekranın temel bileşenleri aşağıdaki gibidir.

screen_part

Bu elektron tabancası ekranı satır satır tarayarak görüntüyü oluşturur ve bu işlemler çok hızlı gerçekleştiği için göz tarafından algılanamaz. Bu tarama işlemine ait gösterim aşağıda verilmiştir. Farz edelim ki ekran çözünürlüğümüz 640×480 olsun.

tarama

Bu noktada dikkat edilmesi gereken bir durum var. Sistemin çalışma prensibinden kaynaklı olarak elektron tabancasının her yeni satıra geçişinde kararlı hale gelebilmesi için belirli bir süre geçmesi gerekmekte. Bunu sağlamak için “front porch” ve “back porch” adı verilen süreler kullanılıyor. Seçilen ekran çözünürlüğüne göre de bu süreler değişiyor.

Bu süreleri belirlemenin en kolayı hazır bir hesaplayıcı kullanmak. Ben bunun için çoğunlukla şu siteyi tercih ediyorum.

http://www.epanorama.net/faq/vga2rgb/calc.html

Bu siteden faydalanarak farklı ekran çözünürlükleri için gerekli değerleri bulabilir ve aşağıda verilen VHDL kodundaki constant tanımlamaları ile kullanabilirsiniz. Verilen kod Nexys4 ve Basys3 kartı ile denenmiştir. Giriş bilgisi “vgaData” sinyali ile verilmekte olup renk bilgisi R|G|B şeklinde organize edilmiştir. Nexys4 kartının vga çıkışı her renk için 4 bit kullandığından toplam 12 bitlik bir sinyale ihtiyaç duyulmuştur. COLOR_BIT tanımlamasına ait değer ile bu uzunluk değiştirilebilir. “pos_x” ve “pos_y” ile o an bulunan benek (pixel) bilgisi sağlanmaktadır. İhtiyaç yoksa kullanılmayabilir.

640 x 480 Çözünürlük İçin

var quads_screen_width = document.body.clientWidth;
if ( quads_screen_width >= 1140 ) {
/* desktop monitors */
document.write('');
(adsbygoogle = window.adsbygoogle || []).push({});
}if ( quads_screen_width >= 1024  && quads_screen_width < 1140 ) {
/* tablet landscape */
document.write('');
(adsbygoogle = window.adsbygoogle || []).push({});
}if ( quads_screen_width >= 768  && quads_screen_width < 1024 ) {
/* tablet portrait */
document.write('');
(adsbygoogle = window.adsbygoogle || []).push({});
}if ( quads_screen_width < 768 ) {
/* phone */
document.write('');
(adsbygoogle = window.adsbygoogle || []).push({});
}
 
 
 
 
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.all;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.all;
 
-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity vga_core is
  generic (
    COLOR_BIT : integer := 4);
  port (
    clk     : in  std_logic;
    rst     : in  std_logic;
    vgaData : in  unsigned(3*COLOR_BIT-1 downto 0);
    pos_x   : out integer range 0 to 2047;
    pos_y   : out integer range 0 to 2047;
    data_r  : out unsigned(COLOR_BIT-1 downto 0);
    data_g  : out unsigned(COLOR_BIT-1 downto 0);
    data_b  : out unsigned(COLOR_BIT-1 downto 0);
    hs_out  : out std_logic;
    vs_out  : out std_logic
    );
end vga_core;
 
-------------------------------------------------------------------------------
-- VGA (640 x 480 @ 60Hz) Design. Required Clock Frequency = 25.125 MHz
-------------------------------------------------------------------------------
architecture VGA of vga_core is
-------------------------------------------------------------------------------
-- 640 x 480 @ 60Hz VGA Parameters
-------------------------------------------------------------------------------
  constant RES_H         : integer := 640;
  constant RES_V         : integer := 480;
  constant H_FRONT_PORCH : integer := 16;  
  constant H_SYNC_TIME   : integer := 96;
  constant H_BACK_PORCH  : integer := 48;
  constant V_FRONT_PORCH : integer := 11;  
  constant V_SYNC_TIME   : integer := 2;
  constant V_BACK_PORCH  : integer := 31;
  constant TOTAL_H       : integer := RES_H+H_FRONT_PORCH+H_SYNC_TIME+H_BACK_PORCH;
  constant TOTAL_V       : integer := RES_V+V_FRONT_PORCH+V_SYNC_TIME+V_BACK_PORCH;  
 
-------------------------------------------------------------------------------
-- Internal Signal Definiations
-------------------------------------------------------------------------------
  signal COUNTER_H : integer range 0 to TOTAL_H := 0;
  signal COUNTER_V : integer range 0 to TOTAL_V := 0;
  signal NEW_LINE  : std_logic;
  signal h_visible : std_logic;
  signal v_visible : std_logic;
  signal visible   : std_logic;
begin
 
  CNT_H : process (clk, rst) is
  begin  -- process CNT_H
    if rst = '0' then
      COUNTER_H <= 0;
      NEW_LINE  <= '0';
    elsif clk'event and clk = '1' then
      if (COUNTER_H = TOTAL_H-1) then
        COUNTER_H <= 0;
        NEW_LINE  <= '1';
      else
        COUNTER_H <= COUNTER_H + 1;
        NEW_LINE  <= '0';        
      end if;
    end if;
  end process CNT_H;
 
  CNT_V : process (clk, rst) is
  begin  -- process CNT_V
    if rst = '0' then
      COUNTER_V <= 0;
    elsif clk'event and clk = '1' then
      if (NEW_LINE = '1') then
        if (COUNTER_V = TOTAL_V-1) then
          COUNTER_V <= 0;          
        else
          COUNTER_V <= COUNTER_V + 1;
        end if;
      end if;
    end if;
  end process CNT_V;
 
  SYNC_H : process (clk, rst) is
  begin  -- process SYNC_H
    if rst = '0' then
      hs_out <= '0';
    elsif clk'event and clk = '1' then
      if (COUNTER_H < H_SYNC_TIME) then
        hs_out <= '0';
      else
        hs_out <= '1';
      end if;
    end if;
  end process SYNC_H;
 
  SYNC_V : process (clk, rst) is
  begin  -- process SYNC_V
    if rst = '0' then
      vs_out <= '0';
    elsif clk'event and clk = '1' then
      if (COUNTER_V < V_SYNC_TIME) then
        vs_out <= '0';
      else
        vs_out <= '1';
      end if;
    end if;
  end process SYNC_V;
 
  AREA_H : process (clk, rst) is
  begin  -- process AREA_H
    if rst = '0' then
      h_visible <= '0';
    elsif clk'event and clk = '1' then
      if (COUNTER_H > H_SYNC_TIME + H_BACK_PORCH-1) and (COUNTER_H < TOTAL_H - H_FRONT_PORCH) then
        h_visible <= '1';
        pos_x     <= COUNTER_H - (H_SYNC_TIME + H_BACK_PORCH);
      else
        h_visible <= '0';
      end if;
    end if;
  end process AREA_H;
 
  AREA_V : process (clk, rst) is
  begin  -- process AREA_V
    if rst = '0' then
      v_visible <= '0';
    elsif clk'event and clk = '1' then
      if (COUNTER_V > V_SYNC_TIME + V_BACK_PORCH-1) and (COUNTER_V < TOTAL_V - V_FRONT_PORCH) then
        v_visible <= '1';
        pos_y     <= COUNTER_V - (V_SYNC_TIME + V_BACK_PORCH);
      else
        v_visible <= '0';
      end if;
    end if;
  end process AREA_V;
 
  visible <= h_visible and v_visible;
 
  SHOW : process (clk, rst) is
  begin  -- process SHOW
    if rst = '0' then
      data_r <= (others => '0');
      data_g <= (others => '0');
      data_b <= (others => '0');
    elsif clk'event and clk = '1' then
      if (visible = '1') then
        data_r <= vgaData(3*COLOR_BIT-1 downto 2*COLOR_BIT);
        data_g <= vgaData(2*COLOR_BIT-1 downto COLOR_BIT);
        data_b <= vgaData(COLOR_BIT-1 downto 0);
      else
        data_r <= (others => '0');
        data_g <= (others => '0');
        data_b <= (others => '0');
      end if;
    end if;
  end process SHOW;
 
end VGA;

Farklı çözünürlükler içinse “architecture” kısmında verdiğim tanımlamaları şu şekilde değiştirebilirsiniz.

800 x 600 için

-------------------------------------------------------------------------------
-- SVGA (800 x 600 @ 60Hz) Design. Requires Clock Frequency = 40 MHz.
-------------------------------------------------------------------------------
architecture SVGA of vga_core is
-------------------------------------------------------------------------------
-- 800 x 600 @ 60Hz SVGA Parameters
-------------------------------------------------------------------------------
  constant RES_H         : integer := 800;
  constant RES_V         : integer := 600;
  constant H_FRONT_PORCH : integer := 40;  
  constant H_SYNC_TIME   : integer := 128;
  constant H_BACK_PORCH  : integer := 88;
  constant V_FRONT_PORCH : integer := 1;  
  constant V_SYNC_TIME   : integer := 4;
  constant V_BACK_PORCH  : integer := 23;
  constant TOTAL_H       : integer := RES_H+H_FRONT_PORCH+H_SYNC_TIME+H_BACK_PORCH;
  constant TOTAL_V       : integer := RES_V+V_FRONT_PORCH+V_SYNC_TIME+V_BACK_PORCH;

1024 x 768 için

-------------------------------------------------------------------------------
-- XGA (1024 x 768 @ 60Hz) Design. Required Clock Frequency = 65 MHz
-------------------------------------------------------------------------------
architecture XGA of vga_core is
-------------------------------------------------------------------------------
-- 1024 x 768 @ 60Hz XGA Parameters
-------------------------------------------------------------------------------
  constant RES_H         : integer := 1024;
  constant RES_V         : integer := 768;
  constant H_FRONT_PORCH : integer := 24;  
  constant H_SYNC_TIME   : integer := 136;
  constant H_BACK_PORCH  : integer := 160;
  constant V_FRONT_PORCH : integer := 3;  
  constant V_SYNC_TIME   : integer := 6;
  constant V_BACK_PORCH  : integer := 29;
  constant TOTAL_H       : integer := RES_H+H_FRONT_PORCH+H_SYNC_TIME+H_BACK_PORCH;
  constant TOTAL_V       : integer := RES_V+V_FRONT_PORCH+V_SYNC_TIME+V_BACK_PORCH;

1280 x 800 İçin

-------------------------------------------------------------------------------
-- WXGA (1280 x 800 @ 60Hz) Design. Required Clock Frequency = 83.46 MHz
-------------------------------------------------------------------------------
architecture WXGA of vga_core is
-------------------------------------------------------------------------------
-- 1280 x 800 @ 60Hz WXGA Parameters
-------------------------------------------------------------------------------
  constant RES_H         : integer := 1280;
  constant RES_V         : integer := 800;
  constant H_FRONT_PORCH : integer := 64;  
  constant H_SYNC_TIME   : integer := 136;
  constant H_BACK_PORCH  : integer := 200;
  constant V_FRONT_PORCH : integer := 1;  
  constant V_SYNC_TIME   : integer := 3;
  constant V_BACK_PORCH  : integer := 24;
  constant TOTAL_H       : integer := RES_H+H_FRONT_PORCH+H_SYNC_TIME+H_BACK_PORCH;
  constant TOTAL_V       : integer := RES_V+V_FRONT_PORCH+V_SYNC_TIME+V_BACK_PORCH;

1920 x 1080 İçin

-------------------------------------------------------------------------------
-- FHD (1920 x 1080 @ 60Hz) Design. Required Clock Frequency = 148.5 MHz
-------------------------------------------------------------------------------
architecture FHD of vga_core is
-------------------------------------------------------------------------------
-- 1920 x 1080 @ 60Hz FHD Parameters
-------------------------------------------------------------------------------
  constant RES_H         : integer := 1920;
  constant RES_V         : integer := 1080;
  constant H_FRONT_PORCH : integer := 88;  
  constant H_SYNC_TIME   : integer := 44;
  constant H_BACK_PORCH  : integer := 148;
  constant V_FRONT_PORCH : integer := 4;  
  constant V_SYNC_TIME   : integer := 5;
  constant V_BACK_PORCH  : integer := 36;
  constant TOTAL_H       : integer := RES_H+H_FRONT_PORCH+H_SYNC_TIME+H_BACK_PORCH;
  constant TOTAL_V       : integer := RES_V+V_FRONT_PORCH+V_SYNC_TIME+V_BACK_PORCH;

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir