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.

verilog_6_1.jpg

verilog_6_3.jpg

Kumandanın içini açtığımızda aşağıdaki manzara ile karşılaşıyoruz:

verilog_6_2.jpg

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.

verilog_6_4.jpg

İğ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.

  1. VSS (8. iğne) toprak,
  2. VDD (16. iğne) +3.3V,
  3. Q8 (3. iğne) çıkış,
  4. Ds (11. iğne) paralel iletişim için yani bizim için toprak,
  5. CLOCK (10. iğne) 3.3V 1.5Mhz saat darbesi girişi,
  6. 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:

  1. Turuncu tel: P/S
  2. Kırmızı tel: CLOCK
  3. Kahverengi tel: VSS
  4. Beyaz tel: VDD
  5. Sarı tel: Q8 (veri çıkışı)

Ayrıca hangi düğmenin hangi iğneye bağlı olduğunu bilmekte fayda var:

verilog_6_5.jpg

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.

  1. `timescale 1ns / 1ps
  2. module v6(SAAT, KUMANDA, LEDLER, CLOCK,PS);
  3. // Girdi-Çıktı Kapıları
  4. input                 SAAT;
  5. input                 KUMANDA;
  6. output     [7:0]     LEDLER;
  7. output                 CLOCK;
  8. output PS;
  9. // Yazmaçlar
  10. reg         [7:0]     ledlerim;
  11. reg                     clockum;
  12. reg psim;
  13. // Kod buraya…
  14. // Yazmaçları çıktı kapılarına bağla
  15. assign LEDLER     = ledlerim;
  16. assign CLOCK     = clockum;
  17. assign PS = psim;
  18. endmodule

Şimdi öncelikle CLOCK çıktısına 1Mhz’lik bir saat darbesi uygulayacak döngüyü oluşturalım.

  1. `timescale 1ns / 1ps
  2. module v6(SAAT, KUMANDA, LEDLER, CLOCK,PS);
  3. // Girdi-Çıktı Kapıları
  4. input                SAAT;
  5. input                 KUMANDA;
  6. output     [7:0]     LEDLER;
  7. output                 CLOCK;
  8. output                PS;
  9. // Yazmaçlar
  10. reg        [7:0]     ledlerim;
  11. reg                    clockum;
  12. reg        [10:0]    sayac1;
  13. reg        [7:0]        sayac2;
  14. reg        [10:0]    sayac3;
  15. reg                    psim;
  16. reg        [7:0]        veri;
  17. // CLOCK oluşturucu
  18. always @ (posedge SAAT) begin        // Her saat darbesinde tetiklen
  19. if(sayac1 == 50) begin            // 50 saat darbesi oldu mu?
  20. clockum    <= ~clockum;        // clockum’u tersle
  21. sayac1    <= 0;                    // sayacı sıfırla
  22. end
  23. else begin
  24. sayac1    <= sayac1 + 1;        // sayacın değerini arttır
  25. clockum    <= clockum;            // clockum değerini korusun
  26. end
  27. end
  28. // Yazmaçları çıktı kapılarına bağla
  29. assign LEDLER    = ledlerim;
  30. assign CLOCK    = clockum;
  31. assign PS        = psim;
  32. 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.

  1. `timescale 1ns / 1ps
  2. module v6(SAAT, KUMANDA, LEDLER, CLOCK,PS);
  3. // Girdi-Çıktı Kapıları
  4. input                SAAT;
  5. input                 KUMANDA;
  6. output     [7:0]     LEDLER;
  7. output                 CLOCK;
  8. output                PS;
  9. // Yazmaçlar
  10. reg        [7:0]     ledlerim;
  11. reg                    clockum;
  12. reg        [10:0]    sayac1;
  13. reg        [7:0]        sayac2;
  14. reg        [10:0]    sayac3;
  15. reg                    psim;
  16. reg        [7:0]        veri;
  17. always @ (posedge SAAT) begin
  18. if(sayac3 == 101) begin
  19. sayac3        <= 0;
  20. psim            <= 0;
  21. if(sayac2 == 0) begin
  22. sayac2    <= sayac2 + 1;
  23. if(KUMANDA) begin
  24. veri[0] <= 0;
  25. end
  26. else begin
  27. veri[0] <= 1;
  28. end
  29. end
  30. else if(sayac2 == 1) begin
  31. sayac2    <= sayac2 + 1;
  32. if(KUMANDA) begin
  33. veri[1] <= 0;
  34. end
  35. else begin
  36. veri[1] <= 1;
  37. end
  38. end
  39. else if(sayac2 == 2) begin
  40. sayac2    <= sayac2 + 1;
  41. if(KUMANDA) begin
  42. veri[2] <= 0;
  43. end
  44. else begin
  45. veri[2] <= 1;
  46. end
  47. end
  48. else if(sayac2 == 3) begin
  49. sayac2    <= sayac2 + 1;
  50. if(KUMANDA) begin
  51. veri[3] <= 0;
  52. end
  53. else begin
  54. veri[3] <= 1;
  55. end
  56. end
  57. else if(sayac2 == 4) begin
  58. sayac2    <= sayac2 + 1;
  59. if(KUMANDA) begin
  60. veri[4] <= 0;
  61. end
  62. else begin
  63. veri[4] <= 1;
  64. end
  65. end
  66. else if(sayac2 == 5) begin
  67. sayac2    <= sayac2 + 1;
  68. if(KUMANDA) begin
  69. veri[5] <= 0;
  70. end
  71. else begin
  72. veri[5] <= 1;
  73. end
  74. end
  75. else if(sayac2 == 6) begin
  76. sayac2    <= sayac2 + 1;
  77. if(KUMANDA) begin
  78. veri[6] <= 0;
  79. end
  80. else begin
  81. veri[6] <= 1;
  82. end
  83. end
  84. else begin
  85. sayac2    <= 0;
  86. ledlerim <= veri;
  87. psim <= 1;
  88. if(KUMANDA) begin
  89. veri[7] <= 0;
  90. end
  91. else begin
  92. veri[7] <= 1;
  93. end
  94. end
  95. end
  96. else begin
  97. psim        <= psim;
  98. sayac3    <= sayac3 + 1;
  99. end
  100. end
  101. // CLOCK oluşturucu
  102. always @ (posedge SAAT) begin        // Her saat darbesinde tetiklen
  103. if(sayac1 == 50) begin            // 50 saat darbesi oldu mu?
  104. clockum    <= ~clockum;        // clockum’u tersle
  105. sayac1    <= 0;                    // sayacı sıfırla
  106. end
  107. else begin
  108. sayac1    <= sayac1 + 1;        // sayacın değerini arttır
  109. clockum    <= clockum;            // clockum değerini korusun
  110. end
  111. end
  112. // Yazmaçları çıktı kapılarına bağla
  113. assign LEDLER    = ledlerim;
  114. assign CLOCK    = clockum;
  115. assign PS        = psim;
  116. 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.

  1. NET “SAAT” LOC = “C9” | IOSTANDARD = LVCMOS33 ;
  2. NET “SAAT” PERIOD = 20.0ns HIGH 40%;
  3. NET “LEDLER<7>” LOC = “F9” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8 ;
  4. NET “LEDLER<6>” LOC = “E9” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8 ;
  5. NET “LEDLER<5>” LOC = “D11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
  6. NET “LEDLER<4>” LOC = “C11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
  7. NET “LEDLER<3>” LOC = “F11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
  8. NET “LEDLER<2>” LOC = “E11” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
  9. NET “LEDLER<1>” LOC = “E12” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
  10. NET “LEDLER<0>” LOC = “F12” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE =8;
  11. NET “CLOCK” LOC = “B4” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ;
  12. NET “PS” LOC = “A4” | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ;
  13. 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.

verilog_6_6.jpg

4- Vidyo:

Vidyo 1

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.