DVI Arayüzü ve FPGA Üzerinde Tasarımı

DVI(Digital Visual Interface), DDWG tarafından geliştirilen dijital video görüntü arayüzüdür. İlk olarak 1999'da kullanılmaya başlanmıştır. Dijital bir arayüz olduğundan dolayı VGA gibi analog arayüzlerden, aktarım hızı ve aktarım mesafesi bakımından çok daha başarılıdır. Aktarım single-link için 3 görüntü ve 1 clock hattı olmak üzere toplamda 4 diferansiyel hat üzerinden gerçekleşir. Dual-link'de ek olarak 3 görüntü hattı daha eklenir. Diferansiyel tür olarak CML kullanılır. Aktarım tek yönlüdür.

DVI arayüzünün temeli VGA'dır. VGA HSync, VSync ve RGB sinyallerinden oluşur. HSync ve VSync sinyalleri görüntü senkronizasyon için kullanılır. RGB sinyalleri üzerinden de görüntü sinyali aktarılır. VGA ile daha ayrıntılı bilgi için daha önce yazdığım FPGA ile VGA Monitör Kontrolü yazısına bakabilirsiniz. DVI arayüzü üretilen HSync, VSync ve RGB sinyallerini birleştirerek dijital bir şekilde monitöre aktarır.

HSync, VSync ve RGB sinyalleri serializer'a gitmeden önce TMDS(Transition-minimized differential signaling) kodlayıcıdan geçer. TMDS algoritması diferansiyel hat üzerindeki elekromanyetik girişimi engeller ve DC değeri dengeler. Bu sayede daha uzun mesafelere görüntü sinyali taşınabilir. TMDS kodlama algoritması aşağıda gösterilmiştir.

DVI arayüzünün blok şeması aşağıda gösterilmiştir.

TMDS kodlayıcıdaki C0 ve C1 girişleri kontrol girişleridir. DVI arayüzünde sadece CH0'ın kontrol girişleri kullanılır. Bunlar HSync ve VSync dir. Diğer TMDS kodlayıcıların kontrol girişleri gelecek için rezerve edilmiştir(HDMI'da bu kontrol girişleri ses aktarımı için kullanılmıştır). DE(Data Enable) girişlerine aktif görüntü alanında '1', blanking alanında '0' değerini gönderilir. DVI arayüzünde HSync ve VSync polariteleri her zaman pozitiftir.

FPGA Üzerinde DVI Kontrolcüsü Tasarımı

TMSD Kodlayıcı

VHDL kodu:

-------------------------- TMDS_Encoder.vhd ---------------------------
--                           Bertan Taşkın
--                             7.6.2017
--                           Verisyon 1.0
-- 
-- TMDS kodlayıcı. DVI ve HDMI arayüzleri için elektromanyerik girişimleri
-- engelleyerek daha uzun mesafelere aktarımı sağlar.
--
--
-- Versiyon Notları:
--
-- Versiyon 1.0 (27.6.2017): İlk sürüm.
--


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

entity TMDS_Encoder is	
	port(Clk, Enable : in std_logic;               --Clock ve Enable Girişleri
		D : in std_logic_vector(7 downto 0);       --Data Girişi
		DE, C0, C1 : in std_logic;                 --Data Enable ve Kontrol Girişleri
		q_out : out std_logic_vector(9 downto 0)); --Kodlanmış Data Çıkışı
end TMDS_Encoder;

architecture Behavioral of TMDS_Encoder is

	--Data vektöründeki '1' lerin sayısını bulan fonksiyon
	function N1(Data : std_logic_vector) return integer is
	variable X : integer := 0;
	begin
	
		a : for i in 0 to Data'length - 1 loop
			if Data(i) = '1' then
				X := X + 1;
			end if;
		end loop;
		
		return X;
	end N1;
	
	--Data vektöründeki '0' ların sayısını bulan fonksiyon
	function N0(Data : std_logic_vector) return integer is
	variable X : integer := 0;
	begin
	
		a : for i in 0 to Data'length - 1 loop
			if Data(i) = '0' then
				X := X + 1;
			end if;
		end loop;
		
		return X;
	end N0;
	
	--Std_logic tipini integer'a dönüştüren fonksiyon
	--'0' için 0, '1' için 1
	function StdlogictoInteger(X : std_logic) return integer is
	begin
	
		if X = '1' then
			return 1;
		else
			return 0;
		end if;
		
	end StdlogictoInteger;
	
	signal C : std_logic_vector(1 downto 0);
	signal Cnt : integer;
	
begin

	C(0) <= C0;
	C(1) <= C1;
	
	process(Clk)	
	variable q_m : std_logic_vector(8 downto 0);
	begin

		--TMDS Algoritması
		if N1(D) > 4 or (N1(D) = 4 and D(0) = '0') then
			q_m(0) := D(0);
			q_m(1) := q_m(0) xnor D(1);
			q_m(2) := q_m(1) xnor D(2);
			q_m(3) := q_m(2) xnor D(3);
			q_m(4) := q_m(3) xnor D(4);
			q_m(5) := q_m(4) xnor D(5);
			q_m(6) := q_m(5) xnor D(6);
			q_m(7) := q_m(6) xnor D(7);
			q_m(8) := '0';
		else
			q_m(0) := D(0);
			q_m(1) := q_m(0) xor D(1);
			q_m(2) := q_m(1) xor D(2);
			q_m(3) := q_m(2) xor D(3);
			q_m(4) := q_m(3) xor D(4);
			q_m(5) := q_m(4) xor D(5);
			q_m(6) := q_m(5) xor D(6);
			q_m(7) := q_m(6) xor D(7);
			q_m(8) := '1';
		end if;
	
		if rising_edge(Clk) and Enable = '1' then
			if DE = '0' then
					
				case C is
					when "00" => q_out <= "0010101011";
					when "01" => q_out <= "1101010100";
					when "10" => q_out <= "0010101010";
					when others => q_out <= "1101010101";
				end case;
				
				Cnt <= 0;
				
			else
		
				if Cnt = 0 or (N1(q_m(7 downto 0)) = N0(q_m(7 downto 0))) then
				
					q_out(9) <= not q_m(8);
					q_out(8) <= q_m(8);
					
					if q_m(8) = '1' then
						q_out(7 downto 0) <= q_m(7 downto 0);
					else
						q_out(7 downto 0) <= not q_m(7 downto 0);
					end if;
					
					if q_m(8) = '0' then
						Cnt <= Cnt + N0(q_m(7 downto 0)) - N1(q_m(7 downto 0));
					else
						Cnt <= Cnt + N1(q_m(7 downto 0)) - N0(q_m(7 downto 0));
					end if;
				
				else
				
					if (Cnt > 0 and N1(q_m(7 downto 0)) > N0(q_m(7 downto 0))) or
						(Cnt < 0 and N0(q_m(7 downto 0)) > N1(q_m(7 downto 0))) then
						
						q_out(9) <= '1';
						q_out(8) <= q_m(8);
						q_out(7 downto 0) <= not q_m(7 downto 0);
						
						Cnt <= Cnt + 2 * stdlogictoInteger(q_m(8)) + N0(q_m(7 downto 0)) - N1(q_m(7 downto 0));
						
					else
					
						q_out(9) <= '0';
						q_out(8) <= q_m(8);
						q_out(7 downto 0) <= q_m(7 downto 0);
						
						Cnt <= Cnt - 2 * stdlogictoInteger(not q_m(8)) + N1(q_m(7 downto 0)) - N0(q_m(7 downto 0));
					
					end if;
				
				end if;
					
			end if;
		end if;
		
	end process;

end Behavioral;

RTL Şeması:

Kaynak Kullanımı:

Fmax Değerleri(EP4CE22F17C6, Cyclone IV -6 Speed Grade):

DVI Kontrolcüsü

VHDL kodu:

-------------------------- DVIController.vhd -----------------------------
--                           Bertan Taşkın
--                            17.10.2017
--                           Versiyon 1.0
--
-- DVI kontrolcüsü. Zamanlama parametreleri generic kısmından ayarlanabilir.
-- HSync ve VSync polariteleri pozitif olarak ayarlanmıştır. BufferAddress
-- aktif pikselin ramdeki adresini işaretler. BufferAddress güncellendikten
-- 1 cycle sonra BufferData'dan veriler okunur ve ekranda gösterilir.
-- BufferAddress FeedbackClock ile güncellenir ve FeedbackClock'un yükselen
-- kenarı ile BufferData okunur. Renk derinliği sabit 24 bittir. BufferData
-- aşağıdaki gibi parçalara ayrılabilir:
--
-- BufferData <= (Red & Green & Blue)
--
-- Versiyon Notları:
--
-- Versiyon 1.0 (17.10.2017): İlk sürüm.
--


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

entity DVIController is
	generic(HorizontalVisibleArea : natural := 1024;      --Zamanlama Parametreleri
		HorizontalFrontPorch : natural := 24;
		HorizontalSyncPulse : natural := 136;
		HorizontalBackPorch : natural := 144;
		VerticalVisibleArea : natural := 768;
		VerticalFrontPorch : natural := 3;
		VerticalSyncPulse : natural := 6;
		VerticalBackPorch : natural := 29);
	port(DVIClk, Enable : in std_logic;                    --Clock ve Enable Girişleri
		DVI_Channel0 : out std_logic;                      --DVI Kanal 0 Çıkışı
		DVI_Channel1 : out std_logic;                      --DVI Kanal 1 Çıkışı
		DVI_Channel2 : out std_logic;                      --DVI Kanal 2 Çıkışı
		DVI_Clock : out std_logic;                         --DVI Clock Çıkışı
		FeedbackClock : out std_logic;                     --Geri Besleme Clock Çıkışı
		BufferAddress : out std_logic_vector(31 downto 0); --Buffer Adresi Çıkışı
		BufferData : in std_logic_vector(23 downto 0));	   --Buffer Veri Girişi(RGB)
end DVIController;

architecture Behavioral of DVIController is

--VGA Kontrolcüsü (Versiyon 2.0)
component VGA
	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 component;

--TMDS Kodlayıcı (Versiyon 1.0)
component TMDS_Encoder
	port(Clk, Enable : in std_logic;               --Clock ve Enable Girişleri
		D : in std_logic_vector(7 downto 0);       --8 Bitlik veri girişi
		DE, C0, C1 : in std_logic;                 --DE ve Kontrol Sinyalleri Girişleri
		q_out : out std_logic_vector(9 downto 0)); --Kodlanmış Sinyal Çıkışı
end component;

--Serializer (Versiyon 3.0)
component Serializer
	generic(SerializationFactor : natural := 10;             --Serializer Katsayısı
		NumberofChannel : natural := 1;                      --Kanal Sayısı
		ClockPattern : string := "AutoGenerate";             --Clock Pattern'i
		UserClockPattern : std_logic_vector := "1111100000"; --Kullanıcı Clock Pattern'i
		FeedbackClockSource : string := "ExternalRing";      --Geri Besleme Clock Kaynağı
		FeedbackPipelineLength : natural := 2;               --Geri Besleme Gecikmesi
		FirstBit : string := "LSB");                         --Gönderilecek İlk Bit

	port(Clk, Enable : in std_logic;                                                       --Clock ve Enable Girişleri
		DataIn : in std_logic_vector(SerializationFactor * NumberofChannel - 1 downto 0);  --Veri Girişi
		SerializerData : out std_logic_vector(NumberofChannel - 1 downto 0);               --Serializer Veri Çıkışı
		SerializerClock : out std_logic;                                                   --Serializer Clock Çıkışı
		FeedbackClock : out std_logic);                                                    --Geri Besleme Clock Çıkışı
end component;

	signal Div10Clk : std_logic;
	
	signal Red, Green, Blue : unsigned(7 downto 0);
	
	signal HSync, VSync : std_logic;
	signal DE : std_logic;	
		
	signal q_out0, q_out1, q_out2 : std_logic_vector(9 downto 0);
		
	signal SerOut : std_logic_vector(2 downto 0);
	signal SerClk : std_logic;
	
begin
	
	--VGA sinyal üretici
	--HSync ve VSync polariteleri pozitif
	VGAController : VGA
		generic map(HorizontalVisibleArea => HorizontalVisibleArea,
			HorizontalFrontPorch => HorizontalFrontPorch,
			HorizontalSyncPulse => HorizontalSyncPulse,
			HorizontalBackPorch => HorizontalBackPorch,
			VerticalVisibleArea => VerticalVisibleArea,
			VerticalFrontPorch => VerticalFrontPorch,
			VerticalSyncPulse => VerticalSyncPulse,
			VerticalBackPorch => VerticalBackPorch,
			HorizontalSyncPolarity => '1',
			VerticalSyncPolarity => '1',
			RGBLength => 8)
		port map(PixelClk => Div10Clk,
			Enable => Enable,
			Red => Red,
			Green => Green,
			Blue => Blue,
			HSync => HSync,
			VSync => VSync,
			DE => DE,
			BufferAddress => BufferAddress,
			BufferData => BufferData);
	
	--Kanal 0 TMDS kodlayıcı
	--Mavi, HSync ve VSync
	TMDSEncoder0 : TMDS_Encoder
		port map(Clk => Div10Clk,
			Enable => Enable,
			D => std_logic_vector(Blue),
			DE => DE,
			C0 => HSync,
			C1 => VSync,
			q_out => q_out0);
			
	--Kanal 1 TMDS kodlayıcı
	--Yeşil
	TMDSEncoder1 : TMDS_Encoder
		port map(Clk => Div10Clk,
			Enable => Enable,
			D => std_logic_vector(Green),
			DE => DE,
			C0 => '0',
			C1 => '0',
			q_out => q_out1);
			
	--Kanal 2 TMDS kodlayıcı
	--Kırmızı
	TMDSEncoder2 : TMDS_Encoder
		port map(Clk => Div10Clk,
			Enable => Enable,
			D => std_logic_vector(Red),
			DE => DE,
			C0 => '0',
			C1 => '0',
			q_out => q_out2);
		
	--Serializer
	--Serialization Factor = 10  
	Ser : Serializer
		generic map(SerializationFactor => 10,
			NumberofChannel => 3,
			ClockPattern => "AutoGenerate",
			UserClockPattern => "1111100000",
			FeedbackClockSource => "ExternalRing",
			FeedbackPipelineLength => 2,
			FirstBit => "LSB")
		port map(Clk => DVIClk,
			Enable => Enable,
			DataIn => (q_out2 & q_out1 & q_out0),
			SerializerData => SerOut, 
			SerializerClock => SerClk,
			FeedbackClock => Div10Clk);
		
	--Serializer çıkışlarının modül çıkışlarına aktarılması
	DVI_Channel0 <= SerOut(0);
	DVI_Channel1 <= SerOut(1);
	DVI_Channel2 <= SerOut(2);
		
	DVI_Clock <= SerClk;
	
	--Geri dönüş clock'u
	FeedbackClock <= Div10Clk;

end Behavioral;

RTL Şeması:

Kaynak Kullanımı:

Fmax Değerleri(EP4CE22F17C6, Cyclone IV -6 Speed Grade):

Çalışma Görüntüsü

1024x768@70Hz, Pixel Clock = 750Mhz, Toplam Hız = 2.25Gbps

One thought on “DVI Arayüzü ve FPGA Üzerinde Tasarımı

Bir cevap yazın

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