Daha önceki yazımda ML506 üzerinde çalıştığımı belirtmiştim. Bu yazımda yine bu geliştirme kartı üzerinde bulunan 16×2 LCD ekranı sürmeyi göstereceğim. Hmm sanırım çok resmi bir yazı girişi oldu. Neyse efendim yazımıza geri dönelim. Ne diyorduk , 16×2 lcd diyorduk. ML50x serisindeki kartların çoğunda bu lcd var. Bildiğimiz karakter tabanlı bir lcd. Benim kartta bulunanın markası ise “Tianma TM162VBA6”. Daha önce bu tarz lcd ekranları mikrodenetleyici ile sürenleriniz varsa zaten konuya aşinalar. Ama kısa bir hatırlatma yaparsak bu lcd ekran 8 bit veri yoluna sahip, 3 adet te yönetim sinyali içeren oldukça basit bir ekran. 8bit ya da 4bit şeklinde iletişim kurulabiliyor.
Ekranla ilgili dosyalar ise 5KS0066U ve TM162Vdc . İlk dosyada ekrandaki yönetici yonga ile ilgili bilgiler bulabilirsiniz. İkinci dosya ise üretici firmanın hazırlamış olduğu kullanım klavuzu. Gerçi bu ekranların neredeyse hepsi birbirinin aynı olduğu için muhtemelen başka firmaların bilgileri de aynıdır. Şimdi tasarımla ilgili bir kaç bilgi vereyim:
- 100 Mhz saat işareti kullanıldı (USER_CLK=100 MHz)
- Ekranın kullanım talimatları incelenerek zamanlamalar ona göre ayarlandı.
- İlk açılış gecikmesi olarak 40ms’lik bir süre kullanıldı (init_d>30ms)
- Kullanım talimatlarını incelerseniz çoğu komutun ortalama 40 µs içinde tamamlandığını göreceksiniz. Bazı komutlar ise 1.53 ms içinde tamamlanıyor.
- Ben ortalama her komut için 50 µs lik bir süre seçtim.
- Yine kullanım talimatlarında bulunan zamanlama bilgilerine göre yönetim ve bilgi işaretlerinin ortalama tamamlanma süresi 500 ns civarında ki bu Tablo 1’de ve Çizelge 1’de görülebilir.
- İletişim biçimi olarak ekran, ML506 deney kartına 4bit iletişim tipinde bağlanmış. Komutlar 8bit uzunluğunda olduğuna göre her komutun gönderilmesi ancak iki aşamada tamamlanabiliyor. Önce yüksek değerlilikli 4bit(upper 4bit), sonra da düşük değerlilikli (lower 4bit) gönderiliyor.
- Ekranın çalışmaya hazır hale getirilmesi ise şöyle gerçekleştiriliyor:
- İlk açılış için 30 ms’den fazla bekle
- “Function Set” ayarını yap. 39 µs’den fazla bekle.
- “Display On/OFF” ayarını yap. Aynı zamanda imleç seçeneklerini de içerir. 39 µs’den fazla bekle.
- “Display Clear” ayarını yap. 1.53 ms’den fazla bekle.
- “Entry Mode Set” ayarını yap. 39 µs’den fazla bekle.
- “Write Data to RAM“, karakter bas. 43 µs’den fazla bekle.
- Ekranın desteklediği diğer seçenekler için yazıda paylaştığım kulanım yönergesini inceleyebilirsiniz.
Yukarıdaki bilgilerden sonra bir de kodun çalıştığını gösteren resimlerini ekleyelim. Cep telefonunun kamerası ile çekildiği için çok şahane sayılmaz ama yine de anlaşılır durumda.
Ve son olarak da VHDL kodu. Zamanlamalar 100 MHz işarete göre hesaplanmıştır.
----------------------------------------------------------------------------------
-- Company: www.muuzoo.gen.tr
-- Engineer: Mehmet Muzaffer KOSTEN
--
-- Create Date: 02:27:34 01/07/2010
-- Design Name: 2x16 LCD Ekran Calismasi
-- Module Name: lcd_216_kabuk - Behavioral
-- Project Name:
-- Target Devices: ML506 Gelistirme Karti
-- Tool versions: ISE 11.3
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity lcd_216_kabuk is
generic(
init_d : integer := 4000000; --40 ms gecikme
com_dl : integer := 200000; --2 ms gecikme
com_ds : integer := 5000); --50 us gecikme
port(
USER_CLK : in std_logic;
LCD_FPGA_DB : inout unsigned(3 downto 0);
LCD_FPGA_E : out std_logic;
LCD_FPGA_RS : out std_logic;
LCD_FPGA_RW : out std_logic);
end lcd_216_kabuk;
architecture Behavioral of lcd_216_kabuk is
type tip_mesaj is array (0 to 12) of unsigned(7 downto 0);
constant mesaj : tip_mesaj :=((X"6D"),(X"75"),(X"75"),(X"7a"),(X"6f"),
(X"6f"),(X"2e"),(X"67"),(X"65"),(X"6e"),
(X"2e"),(X"74"),(X"72"));
signal lcd : unsigned(6 downto 0):="1111111";
begin
LCD_FPGA_DB <= lcd(3 downto 0);
LCD_FPGA_E <= lcd(6);
LCD_FPGA_RS <= lcd(5);
LCD_FPGA_RW <= lcd(4);
process(USER_CLK)
variable adim : integer range 0 to 23 := 0;
variable sayac : integer range 0 to 4194303 := 0;
variable i : integer range 0 to 12 := 0;
begin
if(rising_edge(USER_CLK)) then
sayac:=sayac+1;
case adim is
---------------Acilis Gecikmesi, 40 ms -----------------------------
when 0 => if (sayac=init_d) then
sayac := 0;
adim := 1;
end if;
---------------Acilis Ayarlari, 2x16 biciminde calis----------------
when 1 => lcd <= "1000010";
if (sayac=com_ds/20) then
sayac := 0;
adim := 2;
end if;
when 2 => lcd <= "0000010";
if (sayac=com_ds/20) then
adim := 3;
end if;
when 3 => lcd <= "1000010";
if (sayac=com_ds/10) then
adim := 4;
end if;
when 4 => lcd <= "0000010";
if (sayac=3*com_ds/20) then
adim := 5;
end if;
when 5 => lcd <= "1001000";
if (sayac=com_ds/5) then
adim := 6;
end if;
when 6 => lcd <= "0000010";
if (sayac=com_ds) then
adim := 7;
sayac := 0;
end if;
---------------Ekrani Acma, Imlec ayarlari, Yanip/sonme---------------
when 7 => lcd <= "1000000";
if (sayac=com_ds/20) then
adim := 8;
end if;
when 8 => lcd <= "0000000";
if (sayac=com_ds/10) then
adim := 9;
end if;
when 9 => lcd <= "1001111";
if (sayac=3*com_ds/20) then
adim := 10;
end if;
when 10 => lcd <= "0001111";
if (sayac=com_ds) then
adim := 11;
sayac := 0;
end if;
---------------Ekrani Temizle, Baslangic Adresine Git-----------------
when 11 => lcd <= "1000000";
if (sayac=com_dl/800) then
adim := 12;
end if;
when 12 => lcd <= "0000000";
if (sayac=com_ds/400) then
adim := 13;
end if;
when 13 => lcd <= "1000001";
if (sayac=3*com_dl/800) then
adim := 14;
end if;
when 14 => lcd <= "0000001";
if (sayac=com_dl) then
adim := 15;
sayac := 0;
end if;
---------------Adresleme Ayarlari Adres Arttirici---------------------
when 15 => lcd <= "1000000";
if (sayac=com_ds/20) then
adim := 16;
end if;
when 16 => lcd <= "0000000";
if (sayac=com_ds/10) then
adim := 17;
end if;
when 17 => lcd <= "1000110";
if (sayac=3*com_ds/20) then
adim := 18;
end if;
when 18 => lcd <= "0000110";
if (sayac=com_ds) then
adim := 19;
sayac := 0;
end if;
---------------Ekrana Karakter Basma slemi--------------------------
when 19 => lcd <= "110"&mesaj(i)(7 downto 4);
if (sayac=com_ds/20) then
adim := 20;
end if;
when 20 => lcd <= "010"&mesaj(i)(7 downto 4);
if (sayac=com_ds/10) then
adim := 21;
end if;
when 21 => lcd <= "110"&mesaj(i)(3 downto 0);
if (sayac=3*com_ds/20) then
adim := 22;
end if;
when 22 => lcd <= "010"&mesaj(i)(3 downto 0);
if (sayac=com_ds) then
adim := 23;
end if;
when 23 => if (i<12) then
i:=i+1;
adim := 19;
else
adim := 23;
end if;
end case;
end if;
end process;
end Behavioral;
Bence bu tür işleri FPGA’in içine gömülebilecek mikroişlemcilerle yapmak en iyisi.
Zaten yer oldukça fazla olduğundan bir sorun teşkil edeceğini de sanmam. Böylelikle paralel çalışmanın nimetlerinden de faydalanmış oluruz.
Xilinx için Picoblaze hoş bence 😉
Aslına bakarsanız haklısınız biraz zorlama bir çalışma 🙂 .Bu tarz işlemler için mikroişlemci kullanmak en mantıklısı. Bu çalışma aslında bir arkadaşın sorusu üzerine yapıldı. Ve yine bir arkadaşın çalışmasında hata ayıklama işlemi için kullanıldı.