Xilinx ML506 İpuçları – 1

Bir süredir Xilinx ML506 ile cebelleşiyordum. Aslında bu “bir süre” kavramı oldukça uzun olmakla birlikte her zaman aynı yoğunlukta dikkatimi verdiğim söylenemez. Her neyse. Bu naçizane deney kartımız ML506 namı diğer “ömür törpüsü”  oldukça çok donanım içeren tabiri caizsse, ufacık tefecik içi dolu turşucuk kıvamında bir kart. Üzerinde yok yok. Ayrıntılarını öğrenmek isteyenler BURAYA bakabilirler. Neyse gelelim sadece. Bu kart üzerinde ekran sürmek için kullanılan Chrontel üretimi CH7301C serisi bir ekran sürücü var. Kendileri aslen bir “DVI Transmitter”. Bu arkadaşı iki temel durumda kullanmak mümkün:

  • DVI
  • VGA

DVI mevzusuna şimdilik girmiyorum, şu an önemli olan VGA biçimindeki kullanım. Altera’nın DE2-70’ne kıyasla biraz daha zorlayan bir sürücü yongası bu CH7301C. En önemli fark şu; bu yonganın siz gerekli tüm bağlantıları yaptığında çalışacağnı zannetmeyin. Zira bu mereti kullanmak için ilk olarak bir “hazırlık” aşamasından geçmek gerekiyor. İki adımda özetlersek :

  • Yongayı etkinleştir: Bu adımda I2C yöntemi ile yongayla haberleşip belli başlı komutlar vermemiz gerekiyor.
  • Bilgiyi Gönder: Bu adımda ise şöyle bir güzelliğimiz var; her renk kanalı için ayrı veri girişi yok. Tek girişimiz 12 bitlik bir veri hattı. Buraya gönderilecek veriler belirli şartları sağlamak zorunda. Bu şartlar da bir önceki adımda verilen komutlara göre değişiklik gösterebilir.Bu yüzden CH7301’e ait kullanım klavuzunu yalayıp yutmanız en iyi çözüm.

1. Tasarım Aşamasında Dikkat Edilecekler

  • CH7301C’yi inceldeğinizde iki adet clk girişine sahip olduğunu göreceksiniz. Bu yonga öntanımlı ayarlarda iki clk (saat çifti) girişi ile çalışıyor ama i2c üzerinden göndereceğiniz komutlar ile tek clk girişi ile de çalışabilir. Buradaki önemli nokta normalde çift clk ile 25 MHZ ‘de çalışacaksanız, tek clk kullandığınızda hızınızı 2’ye katlamalısınız yani bu durumda 50 MHZ olmalı ve yongaya renk bilgilerini bu hıza göre göndermelisiniz.
  • Tek clk kullanımında hızınızı ikiye katlasanızda ekran yönetim işaretleri için (hsync,vsync) temel hızınız yine (çözünürlüğe bağlı olarak) normal hızınızdır.
  • I2C ile haberleşirken , yonga ile haberleşmeniz bittiğinde mutlaka I2C hattını (hem bilgi ,hemde saat) ‘1’ konumuna çekin.
  • İşinizin kolaylaşmasını isterseniz anahtar kelimeler DCM ve ODDR. Bunları bir inceleyin. Ne için kullanacağınızı anlarsınız.

2. I2C (IIC) ile Haberleşme Safhası

  • Bu adımda lütfen ama lütfen kullanım klavuzunu ve uygulama notlarını yalayıp yutmuş olun.
  • Benim örnek çalışmamda hedeflediğim amaç VGA biçimnde 640×480 @60Hz çözünürlükte ekran sürmekti. Bu yüzden vereceğim bilgiler bu ayarlara göredir. Belirttiğim çözünürlükte çalışmak için:

Register Adresi

Bilgi

Amaç

1CH

0x00

Çift clk kullan @ 25.125 MHZ

21H

1FH

0X09

0x80

RGB bypass mode

RGB Biçim bilgisi(IDF Mod= 0)

48H

0x19(Test Mode)

0x18(normal)

0x19 olursa ekranda renkli çubuklar görünecektir. Yongayı denemek için kullanılabilir. Diğer durumda verdiğiniz bilgi işlenir.

49H

0x00

Yongayı etkinleştir (Power On)

I2C ile haberleşme de hazır yazılmış I2C kodları bulmak mümkün. Opencore sitesinde ,yanlış hatırlamıyorsam 3-4 tane kod pakedi mevcut. Kolay bir şey isterseniz aşağıdaki kodları uygun şekilde değiştirerek kullanabilirsiniz. Şimdiden söyleyeyim hazır kod istemeyin. Size yolu gösterdim, gerisi size ait.

GÜNCELLEME : Kullandığım eklentiden dolayı aşağıdaki kodda bazı yerler yanlış çıkmış.

--------------------------------------------------------------------------------
-- File:        i2c.vhd
-- Description: Simple I2C controller.
-- History:     Felix Bertram, 2002jan11, Created.
--------------------------------------------------------------------------------
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity ValI2C is
	port (
		-- clocks & reset
		clk24: in  std_logic;
		reset: in  std_logic;
		-- dynamic data from external units (token wrd)
		val:   in  std_logic_vector(7 downto 0); -- value
		idx:   out std_logic_vector(7 downto 0); -- index
		-- i2c bus
		sda:   out std_logic;
		scl:   out std_logic
		);
end ValI2C;
 
--------------------------------------------------------------------------------
architecture bhv of ValI2C is
	------------------------------------
	-- basic structure
	--     note: data field is used for constants or value-indices
	type i2cE is (start, stop, const, wrd);
	type i2cT is record
		tag:  i2cE;
		data: std_logic_vector(7 downto 0);
	end record;
 
	------------------------------------
	-- Crystal CS43L43 control sequence
	--     i2c start condition
	--         i2c address= 001000, R/nW= 0
	--             memory address pointer
	--             volume data
	--     i2c stop condition
	type seqT is array(0 to 9) of i2cT;
	constant seq: seqT:= (
	(start, x"00"),
	(const, "0010000" & '0'),
	(const, x"04"),  -- 04h Channel A Digital Volume Control
	(wrd,   x"00"),
	(stop,  x"00"),
	--
	(start, x"00"),
	(const, "0010000" & '0'),
	(const, x"05"),  -- 05h Channel B Digital Volume Control
	(wrd,   x"00"),
	(stop,  x"00")
	);
 
	------------------------------------
	-- clock divider and sequencing
	signal   idxSeq:         integer range seqT'low to seqT'high;
	signal   idxBit:         unsigned(3 downto 0);
	signal   idxCyc:         unsigned(1 downto 0);
	signal   clkdiv:         unsigned(8 downto 0);
	signal   clkp1a, clkp1b: std_logic;
	signal   clken:          std_logic;
	------------------------------------
	-- transmit data
	signal   txd:      std_logic_vector(8 downto 0);
	constant txdstart: std_logic_vector(8 downto 0):= "111000000"; -- I2C start pattern
	constant txdstop:  std_logic_vector(8 downto 0):= "000000111"; -- I2C stop  pattern
begin
 
	-- ic2 clock divider, approx 100kHz
	process(clk24, reset)
	begin
		if reset= '1' then
			clkdiv<= (others=> '0');
			clkp1b<= '0';
		elsif rising_edge(clk24) then
			clkdiv<= clkdiv + 1;
			clkp1b<= clkp1a;
		end if;
	end process;
	clkp1a<= clkdiv(clkdiv'left);
	clken <= clkp1a and not clkp1b;
 
	----------------------------------------------------------------------------
	-- create i2c timing
	----------------------------------------------------------------------------
 
	-- i2c clock cycle counter: 4 cycles per bit
	--           |___ _______________ ________
	--     sda   |___X_______________X________
	--           |        _______         ____
	--     scl   |_______/       \_______/
	--           |
	--     phase | 0 / 1 / 2 / 3 / 0 / 1 / 2 / ...
	process(clk24, reset)
	begin
		if reset= '1' then
			idxCyc<= "00";
		elsif rising_edge(clk24) then
			if clken= '1' then
				if idxCyc/= "11" then idxCyc<= idxCyc + 1;
				else                  idxCyc<= "00"; end if;
			end if;
		end if;
	end process;
 
	-- i2c bit counter: 9 bits per token (8 data + 1 ack)
	process(clk24, reset)
	begin
		if reset= '1' then
			idxBit<= x"8";
		elsif rising_edge(clk24) then
			if clken= '1' and idxCyc= 3 then
				if idxBit/= x"8" then idxBit<= idxBit + 1;
				else                  idxBit<= x"0"; end if;
			end if;
		end if;
	end process;
 
	-- i2c sequence counter: see seqT definition
	process(clk24, reset)
	begin
		if reset= '1' then
			idxSeq<= seqT'high;
		elsif rising_edge(clk24) then
			if clken= '1' and idxCyc= 3 and idxBit= 8 then
				if idxSeq/= seqT'high then idxSeq<= idxSeq + 1;
				else                       idxSeq<= 0; end if;
			end if;
		end if;
	end process;
 
	----------------------------------------------------------------------------
	-- create i2c clock and data
	----------------------------------------------------------------------------
 
	-- create data address
	idx<= seq(idxSeq).data;
 
	-- select byte to transfer, send out bits msb first
	process(clk24, reset)
	begin
		if reset= '1' then
			txd<= (others=> '1');
		elsif rising_edge(clk24) then
			if clken= '1' and idxCyc= 0 then
				if idxBit= 0 then
					case seq(idxSeq).tag is
						when start => txd<= txdstart; 						when stop  => txd<= txdstop; 						when const => txd<= seq(idxSeq).data &amp; '1'; -- const + ack 						when wrd   => txd<= val &amp; '1';              -- value + ack
					end case;
				else
					txd<= txd(7 downto 0) &amp; '-';
				end if;
			end if;
		end if;
	end process;
	sda<= txd(8);
 
	-- select clock to transfer, send out clock
	process(clk24, reset)
	begin
		if reset= '1' then
			scl<= '1'; 		elsif rising_edge(clk24) then 			if clken= '1' then 				case seq(idxSeq).tag is 					when const | wrd=> scl<= idxCyc(0) xor idxCyc(1); 					when start=>       scl<= not(idxBit(3) or idxBit(2)); 					when stop=>        scl<= idxBit(3) or idxBit(2);
				end case;
			end if;
		end if;
	end process;
 
end bhv;

Bir Cevap Yazın

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