1- Giriş:
Bu yazıda elimdeki bir NES (Nintendo Entertainment System – 1983) kumandayı Spartan 3E Starter Kit’ e bağlayıp kullanacağım. Mesela basılan tuşlara göre Starter Kit üzerinde farklı bir LED yakacağım. Başka herhangi bir kumanda kullanmanız veya kendi kumandanızı tasarlayıp Starter Kit’e bağlamanız da doğal olarak mümkün. Benim elimde hazırda NES kumandası var ve kullanmıyorum. Bu yüzden onu seçtim.
Kumandayı bağlamadan önce kumanda hakkında biraz bilgi edinmek gerekiyor. Mesela veriyi nasıl veriyor, kaç volt ile besleniyor, hangi iğne ne işe yarıyor ve benzeri.
2- Kumandayı İnceleyelim:
Aşağıda kumandanın ve soketinin görüntülerini görebilirsiniz.
Kumandanın içini açtığımızda aşağıdaki manzara ile karşılaşıyoruz:
Görüldüğü gibi düğmelerin dışında 2 adet direnç ve bir tane de entegre (BU4021B) kullanılmış. BU4021B entegresini Google‘da aratınca entegrenin veri sayfasını bulabiliyoruz. Aslında bu beni biraz olsun şaşırttı. Sonuçta eski bir konsolun eski kumandasının içinde kullanılan eski bir entegrenin veri sayfasını çok rahat bir şekilde bulabildim. Bu arada BU4021B 8 bitlik kaydıran bir yazmaçmış.
Veri sayfasını incelediğimizde kumandanın -0.3V ve 18V arası gerilimlerle çalışabildiğini görüyoruz. İğne diyagramına bakarak hangi iğnenin ne olduğunu görebiliyoruz.
İğne diyagramına bakacak olursak CLOCK adlı bir iğne görüyoruz. Akla hemen şu soru geliyor:
Kaç Mhz’lik saat darbesi beslemem ve geriliminin ne olması gerekiyor?
Bunun cevabı için veri sayfasını biraz daha incelemek gerekiyor ve aşağıdaki maksimum değer ile karşılaşıyoruz:
VDD 5V iken maksimum CLOCK frekansı 3Mhz
VDD 10V iken maksimum CLOCK frekansı 6Mhz
VDD 15V iken maksimum CLOCK frekansı 9Mhz
Düz mantık uygulayarak 3.3V’da maksimum frekansın 1.98Mhz olması gerektiğini söyleyebiliriz. Tabii ki bu maksimum frekans değeri, daha düşük bir değer kullanabiliriz. Biz bu aleti 3.3V’da 1Mhz ile çalıştırmayı deneyelim. Elimizde 1Mhz’lik kristal yok demeyin. FPGA’imiz var. Yanıp sönen LEDlerimizi hatırladınız umarım, işte o mantığı 1Mhz lik saat darbesini üretmek için kullanacağız.
Bir diğer ilginç iğne ise P/S iğnesi. P/S iğnesi entegrenin paralel ve seri kipleri arasında geçiş yapmaya yarıyor. Düğmelerden verileri paralel olarak almak için P/S iğnesi mantıksal 1 (bir) durumuna getirilmelidir. Düğme verileri yazmaca aktarıldıktan sonra ise P/S iğnesi mantıksal 0 (sıfır) durumuna getirilerek paralel olarak alınan verinin seri olarak iletilmesi sağlanacaktır.
Ds iğnesi için ise veri sayfasında yazılı olarak bir şey söylenmemiş. Yalnız veri sayfasında entegrenin mantıksal devre karşılığına bakıldığında Ds’in D tipi flip flopların birincisine giriş olduğunu görüyoruz. Bunun üzerine biraz aşağıdaki doğruluk tablolarına göz atarsak Ds’in paralel iletişimde kullanılmadığını, seri iletişimde kullanıldığını görüyoruz. Kumandanın devresini incelediğimizde Ds iğnesi mantıksal 0 (sıfır) durumuna sabitlenmiş olduğunu görüyoruz. Yukarıdaki bilgiler üzerinde biraz düşünülürse aslında bu Ds iğnesinin seri veri girişi için kullanıldığını anlayabiliriz.
Devreyi incelediğimizde Kahverengi kablonun toprak hattına, Beyaz kablonun ise VDD hattına bağlı olduğunu görüyoruz. Ayrıca Turuncu tel P/S girişine, Kırmızı tel CLOCK girişine ve Sarı tel de veri çıkışına bağlıdır.
Düğmelerin çıktıları entegrenin P girişlerine giriyor ve entegrenin çıktıları Q6, Q7 ve Q8 çıkışlarından çıkıyor. Kumandanın devresi incelendiğinde Q6 ve Q7′nin kullanılmadığı görülüyor.
Kumandanın çalışma prensibini çözdüğümüze göre şimdi madde madde entegreyi özetleyelim.
- VSS (8. iğne) toprak,
- VDD (16. iğne) +3.3V,
- Q8 (3. iğne) çıkış,
- Ds (11. iğne) paralel iletişim için yani bizim için toprak,
- CLOCK (10. iğne) 3.3V 1.5Mhz saat darbesi girişi,
- P1, P2, P3, P4, P5, P6, P7 ve P8 (sırasıyla 7., 6., 5., 4., 13., 14., 15. ve 1. iğneler) girişler (bu girişler düğmelere bağlı)
Kumandadan çıkan tellerin anlamlarına bakacak olursak:
- Turuncu tel: P/S
- Kırmızı tel: CLOCK
- Kahverengi tel: VSS
- Beyaz tel: VDD
- Sarı tel: Q8 (veri çıkışı)
Ayrıca hangi düğmenin hangi iğneye bağlı olduğunu bilmekte fayda var:
3- Kumanda Denetleyicimizi Tasarlayalım:
Evet kumandamızı inceledikten sonra kumanda denetleyicimizi Verilog ile tasarlamaya geçebiliriz. Öncelikle temiz bir proje oluşturalım. Ardından da SAAT ve KUMANDA girişleri ile CLOCK, PS ve LEDLER çıkışlarını tanımlayalım. Burada SAAT, KUMANDA, PS ve CLOCK 1 bit, LEDLER ise 8 bittir. Ayrıca çıkışlar için ilgili yazmaçları da tanımlayalım.
Bu işlemleri yaptığımızda aşağıdakine benzer bir verilog dosyası elde edeceğiz.
- `timescale 1ns / 1ps
- module v6(SAAT, KUMANDA, LEDLER, CLOCK,PS);
- // Girdi-Çıktı Kapıları
- input SAAT;
- input KUMANDA;
- output [7:0] LEDLER;
- output CLOCK;
- output PS;
- // Yazmaçlar
- reg [7:0] ledlerim;
- reg clockum;
- reg psim;
- // Kod buraya…
- // Yazmaçları çıktı kapılarına bağla
- assign LEDLER = ledlerim;
- assign CLOCK = clockum;
- assign PS = psim;
- endmodule
Şimdi öncelikle CLOCK çıktısına 1Mhz’lik bir saat darbesi uygulayacak döngüyü oluşturalım.
- `timescale 1ns / 1ps
- module v6(SAAT, KUMANDA, LEDLER, CLOCK,PS);
- // Girdi-Çıktı Kapıları
- input SAAT;
- input KUMANDA;
- output [7:0] LEDLER;
- output CLOCK;
- output PS;
- // Yazmaçlar
- reg [7:0] ledlerim;
- reg clockum;
- reg [10:0] sayac1;
- reg [7:0] sayac2;
- reg [10:0] sayac3;
- reg psim;
- reg [7:0] veri;
- // CLOCK oluşturucu
- always @ (posedge SAAT) begin // Her saat darbesinde tetiklen
- if(sayac1 == 50) begin // 50 saat darbesi oldu mu?
- clockum <= ~clockum; // clockum’u tersle
- sayac1 <= 0; // sayacı sıfırla
- end
- else begin
- sayac1 <= sayac1 + 1; // sayacın değerini arttır
- clockum <= clockum; // clockum değerini korusun
- end
- end
- // Yazmaçları çıktı kapılarına bağla
- assign LEDLER = ledlerim;
- assign CLOCK = clockum;
- assign PS = psim;
- endmodule
Şimdi de her CLOCK darbesinde bir kumanda verisini alan kodu yazalım. Veri alırken gecikmeleri de göz önünde bulundurarak biraz daha küçük frekansda verileri alalım. Unutmayın toplamda 8 tane veri alacağız.
- `timescale 1ns / 1ps
- module v6(SAAT, KUMANDA, LEDLER, CLOCK,PS);
- // Girdi-Çıktı Kapıları
- input SAAT;
- input KUMANDA;
- output [7:0] LEDLER;
- output CLOCK;
- output PS;
- // Yazmaçlar
- reg [7:0] ledlerim;
- reg clockum;
- reg [10:0] sayac1;
- reg [7:0] sayac2;
- reg [10:0] sayac3;
- reg psim;
- reg [7:0] veri;
- always @ (posedge SAAT) begin
- if(sayac3 == 101) begin
- sayac3 <= 0;
- psim <= 0;
- if(sayac2 == 0) begin
- sayac2 <= sayac2 + 1;
- if(KUMANDA) begin
- veri[0] <= 0;
- end
- else begin
- veri[0] <= 1;
- end
- end
- else if(sayac2 == 1) begin
- sayac2 <= sayac2 + 1;
- if(KUMANDA) begin
- veri[1] <= 0;
- end
- else begin
- veri[1] <= 1;
- end
- end
- else if(sayac2 == 2) begin
- sayac2 <= sayac2 + 1;
- if(KUMANDA) begin
- veri[2] <= 0;
- end
- else begin
- veri[2] <= 1;
- end
- end
- else if(sayac2 == 3) begin
- sayac2 <= sayac2 + 1;
- if(KUMANDA) begin
- veri[3] <= 0;
- end
- else begin
- veri[3] <= 1;
- end
- end
- else if(sayac2 == 4) begin
- sayac2 <= sayac2 + 1;
- if(KUMANDA) begin
- veri[4] <= 0;
- end
- else begin
- veri[4] <= 1;
- end
- end
- else if(sayac2 == 5) begin
- sayac2 <= sayac2 + 1;
- if(KUMANDA) begin
- veri[5] <= 0;
- end
- else begin
- veri[5] <= 1;
- end
- end
- else if(sayac2 == 6) begin
- sayac2 <= sayac2 + 1;
- if(KUMANDA) begin
- veri[6] <= 0;
- end
- else begin
- veri[6] <= 1;
- end
- end
- else begin
- sayac2 <= 0;
- ledlerim <= veri;
- psim <= 1;
- if(KUMANDA) begin
- veri[7] <= 0;
- end
- else begin
- veri[7] <= 1;
- end
- end
- end
- else begin
- psim <= psim;
- sayac3 <= sayac3 + 1;
- end
- end
- // CLOCK oluşturucu
- always @ (posedge SAAT) begin // Her saat darbesinde tetiklen
- if(sayac1 == 50) begin // 50 saat darbesi oldu mu?
- clockum <= ~clockum; // clockum’u tersle
- sayac1 <= 0; // sayacı sıfırla
- end
- else begin
- sayac1 <= sayac1 + 1; // sayacın değerini arttır
- clockum <= clockum; // clockum değerini korusun
- end
- end
- // Yazmaçları çıktı kapılarına bağla
- assign LEDLER = ledlerim;
- assign CLOCK = clockum;
- assign PS = psim;
- endmodule
Tasarımımızı sentezleyelim. Normalde herhangi bir sorun ile karşılaşmamamız gerekiyor.
Tasarımımız hazır olduğuna göre şimdi de UCF dosyamızı oluşturalım ve ardından da tasarımımızı gerçekleyelim.
- NET “SAAT” LOC = “C9” | IOSTANDARD = LVCMOS33 ;
- NET “SAAT” PERIOD = 20.0ns HIGH 40%;
- NET “LEDLER<7>” LOC = “F9” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8 ;
- NET “LEDLER<6>” LOC = “E9” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8 ;
- NET “LEDLER<5>” LOC = “D11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
- NET “LEDLER<4>” LOC = “C11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
- NET “LEDLER<3>” LOC = “F11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
- NET “LEDLER<2>” LOC = “E11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
- NET “LEDLER<1>” LOC = “E12” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
- NET “LEDLER<0>” LOC = “F12” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
- NET “CLOCK” LOC = “B4” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ;
- NET “PS” LOC = “A4” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ;
- NET “KUMANDA” LOC = “C5” | IOSTANDARD = LVTTL;
LOC değerlerine dikkat edecek olursanız kumandayı J1 bağlantı noktasına bağladığımı göreceksiniz. Başka bir bağlantı noktası da kullanabilirisiniz.
Tasarımımızı gerçekledikten sonra Spartan 3E Starter Kit’e yükleyelim. Kumandamızı da bağlandıktan sonra kumandamızı deneyebiliriz. Aşağıda kurduğum sistemin resmini bulabilirsiniz.
4- Vidyo:
5- Son:
Uygulamamızın sonuna geldik. Sorularınızı ve önerilerinizi lütfen benimle paylaşın. Bu uygulama aslında Oyun Konsolu projemin bir parçası. Gördüğünüz gibi tek başına çok bir şey ifade etmiyor ama diğer bileşenler de hazır olduğunda ortaya bir oyun konsolu çıkacak.