Game of Life-Based Lighting – Hackster.io

Latar Belakang

Beberapa minggu yang lalu saya menunjukkan proyek yang saya buat untuk memantau suhu di kamar tidur anak saya. Seperti banyak balita dia terpesona oleh lampu dan pola lampu.

Ini membuat saya berpikir bagaimana saya bisa menciptakan efek cahaya yang menarik untuk kamar tidurnya berdasarkan sains dan teknologi.

Setelah sedikit pertimbangan, saya memutuskan untuk mengimplementasikan Game of Life yang dibuat oleh Conway pada tahun 1970. The Game of Life adalah Cellular Automaton zero player game di mana pemain menyaksikan evolusi selama beberapa generasi.

Berdasarkan grid dua dimensi, setiap sel dalam grid hidup, mati atau mereproduksi berdasarkan aturan berikut.

  • Setiap sel hidup dengan kurang dari dua tetangga hidup mati, bereplikasi di bawah populasi.
  • Setiap sel hidup dengan dua atau tiga tetangga hidup hidup ke generasi berikutnya.
  • Setiap sel hidup dengan lebih dari tiga tetangga hidup mati, mereplikasi overpopulasi.
  • Setiap sel mati dengan tepat tiga tetangga hidup menjadi sel hidup, mereplikasi reproduksi. [19659010] Untuk menampilkan Game of Life, itu evolusi saya memutuskan untuk menggunakan sejumlah NeoPixel 8 oleh 8 panel. Ini memungkinkan saya untuk membuat array 256 piksel di mana saya dapat menampilkan permainan kehidupan hingga 16 juta warna.

    Negara-Negara Awal

    Keadaan awal dari mana Game of Life berjalan dapat berupa apa saja meskipun ada beberapa pengelompokan pengaturan awal. Ini termasuk

    • Osilator – Kembali ke pola aslinya setelah sejumlah evolusi.
    • Statis atau Still Life – Ini adalah pola yang tidak berevolusi dari satu generasi ke generasi berikutnya.
    • Space Ships – Ini bergerak melintasi grid, ada banyak kelas kapal ruang angkasa dari glider sederhana ke knighthip yang baru ditemukan (The first new primary spaceship find in 48 Years)

    Jika Anda membaca ke dalam Game of Life Anda akan menemukan keadaan awal dapat Turing lengkap. Itu mereka dapat mereplikasi mesin AND, OR, NOT dan bahkan mesin negara yang terbatas. Melihat ke dalam Game of Life dapat menjadi sangat adiktif dengan sangat cepat.

    NeoPixels

    NeoPixels secara digital mengendalikan tiga LED warna yang dapat menampilkan hingga 16 juta warna berkat ada format 24 bit Red Green Blue.

    Setiap warna keluaran NeoPixels ditentukan oleh sebuah kata serial 24 bit. Apa yang benar-benar keren tentang NeoPixels adalah mereka dapat diubah menjadi daisy bersama. Jika NeoPixel mulai menerima kata serial lain dalam 50 mikrodetik maka akan dihasilkan kata yang diterima sebelumnya ke NeoPixel berikutnya sesuai.

    Karena NeoPixels hanya menyediakan input dan output serial tanpa jam. Mereka menggunakan gelombang self-clocking, non-return-to-zero (NRZ) yang unik untuk menentukan nilai bit,

    Informasi waktu untuk menggerakkan NeoPixel ditunjukkan di bawah ini.

    Arsitektur

    Sementara contoh yang saya buat hanya akan menggunakan larik 256, saya ingin desain untuk skala sedemikian rupa sehingga dapat menerapkan tampilan yang jauh lebih besar jika diinginkan.

    Karena itu, pendekatan yang saya putuskan adalah yang berikut

    • The NeoPixel Array akan digerakkan oleh komponen perangkat keras
    • Algoritma evolusi akan dieksekusi dalam PS, itu tidak penting saat kita ingin evolusi akan terlihat pada layar.
    • Antara PS dan PL akan menggunakan BRAM besar, ke BRAM ini akan ditempatkan jumlah piksel dalam array dan setiap nilai piksel Ini kemudian akan dibaca oleh komponen perangkat keras.

    Desain RTL

    Hal pertama yang perlu kita lakukan dalam desain adalah membuat dan mensimulasikan blok RTL yang dapat menggerakkan NeoPixel.

    Modul ini dirancang untuk clock dari Jam 20 MHz, dan merupakan mesin keadaan sederhana yang membaca nilai piksel dari BRAM dan mengeluarkannya ke NeoPixel.

     LIBRARY IEEE;
     USE ieee.std_logic_1164.ALL;
     USE ieee.numeric_std.ALL;
     ENTITY neo_pixel IS PORT (
     CLK: IN std_logic;
     dout: KELUAR std_logic;
     rstb: OUT STD_LOGIC;
     enb: OUT STD_LOGIC;
     web: OUT STD_LOGIC_VECTOR (3 DOWNTO 0);
     addrb: OUT STD_LOGIC_VECTOR (31 DOWNTO 0);
     dinb: OUT STD_LOGIC_VECTOR (31 DOWNTO 0);
     doutb: IN STD_LOGIC_VECTOR (31 DOWNTO 0)
    );
     END ENTITY;
     ARSITEKTUR rtl DARI neo_pixel IS
     TYPE FSM IS (idle, wait1, led, count, reset, addr_out, wait2, grab, wait_done, done_addr);
     KONSTAN dilakukan: std_logic_vector (25 DOWNTO 0): = "00000000000000000000000001"; - menunjukkan ketika shift reg kosong
     CONSTANT nol: std_logic_vector (24 DOWNTO 0): = "1111111000000000000000000"; --waveform untuk bit nol
     KONSTAN satu: std_logic_vector (24 DOWNTO 0): = "1111111111111100000000000"; --waveform untuk satu bit
     CONSTANT numb_pixels: integer: = 24; - Jumlah bit dalam satu piksel
     reset_duration KONSTAN: integer: = 1000; - nomor cclocks di periode reset
     SIGNAL shift_reg: std_logic_vector (24 DOWNTO 0): = (OTHERS => '0'); - reg pergeseran berisi gelombang keluaran pixel
     SIGNAL shift_dne: std_logic_vector (25 DOWNTO 0): = (OTHERS => '0'); - shift reg untuk mengatur waktu reg reg output untuk beban berikutnya
     SIGNAL current_state: fsm: = idle; --fsm untuk mengontrol output beign piksel
     SIGNAL prev_state: fsm: = idle; --pernyataan sebelumnya
     SIGNAL load_shr: std_logic: = '0'; - Mengisi shr dengan pixel berikutnya
     SIGNAL pix_cnt: integer RANGE 0 TO 31: = 0; - menghitung posisi dalam pixel ke op
     SIGNAL rst_cnt: integer RANGE 0 TO 1023: = 0; - menghitung jumlah jam dalam periode reset 50 us @ 20 MHz
     SIGNAL led_numb: integer RANGE 0 TO 1023; - Jumlah LED dalam string
     SIGNAL ram_addr: integer RANGE 0 TO 1023: = 0; --Masukkan untuk membaca dari RAM
     SIGNAL led_cnt: integer RANGE 0 TO 1023; - Hitungan led itu telah ditangani
     SIGNAL pixel: std_logic_vector (23 DOWNTO 0); --menyebabkan nilai led menjadi output
     BEGIN
     web <= (OTHERS => '0');
     rstb <= '0';
     dinb <= (OTHERS => '0');
     pixel_cntrl: PROCESS (clk)
     BEGIN
     IF rising_edge (CLK) MAKA
     load_shr <= '0';
     enb <= '0';
     KASUS current_state IS
     WHEN idle =>
     current_state <= menunggu1;
     rst_cnt <= 0;
     addrb <= std_logic_vector (to_unsigned (ram_addr, 32));
     enb <= '1';
     SAAT menunggu1 =>
     current_state <= led;
     WHEN led =>
     led_numb <= to_integer (unsigned (doutb));
     IF to_integer (unsigned (doutb)) = 0 THEN
     current_state <= idle;
     ELSE
     current_state <= addr_out;
     ram_addr <= ram_addr +4;
     AKHIR JIKA;
     WHEN count =>
     JIKA pix_cnt = (numb_pixels-1) MAKA
     IF led_cnt = (led_numb-1) THEN
     current_state <= reset;
     pix_cnt <= 0;
     ram_addr <= 0;
     ELSE
     ram_addr <= ram_addr + 4;
     current_state <= done_addr;
     led_cnt <= led_cnt + 1;
     AKHIR JIKA;
     ELSE
     current_state <= wait_done;
     AKHIR JIKA;
     WHEN done_addr =>
     IF (shift_dne (shift_dne'high-1) = '1') MAKA
     current_state <= addr_out;
     AKHIR JIKA;
     SAAT wait_done =>
     IF (shift_dne (shift_dne'high-1) = '1') MAKA
     load_shr <= '1';
     pix_cnt <= pix_cnt + 1;
     current_state <= hitungan;
     AKHIR JIKA;
     KETIKA addr_out =>
     addrb <= std_logic_vector (to_unsigned (ram_addr, 32));
     enb <= '1';
     current_state <= wait2;
     SAAT menunggu2 =>
     current_state <= ambil;
     prev_state <= wait2;
     WHEN grab =>
     pixel <= doutb (doutb'high-8 DOWNTO doutb'low);
     load_shr <= '1';
     current_state <= wait_done;
     pix_cnt <= 0;
     SAAT reset =>
     pix_cnt <= 0;
     led_cnt <= 0;
     IF rst_cnt = (reset_duration-1) THEN
     current_state <= idle;
     ram_addr <= 0;
     ELSE
     rst_cnt <= rst_cnt + 1;
     AKHIR JIKA;
     KASUS AKHIR;
     AKHIR JIKA;
     PROSES AKHIR;
     shr_op: PROCESS (clk)
     BEGIN
     IF rising_edge (clk) THEN
     JIKA load_shr = '1' THEN
     shift_dne <= selesai;
     IF pixel ((numb_pixels-1) -pix_cnt) = '1' MAKA
     shift_reg <= satu;
     ELSE
     shift_reg <= nol;
     AKHIR JIKA;
     ELSE
     shift_reg <= shift_reg (shift_reg'high-1 DOWNTO shift_reg'low) & '0';
     shift_dne <= shift_dne (shift_dne'high-1 DOWNTO shift_reg'low) & '0';
     AKHIR JIKA;
     AKHIR JIKA;
     PROSES AKHIR;
     dout <= shift_reg (shift_reg'high);
     ARSITEKTUR AKHIR;
    

    Ketika waktu diuji pada perangkat keras dengan osiloskop, waktu output untuk satu dan nol adalah seperti yang ditunjukkan di bawah

    Desain Perangkat Keras

    Setelah file RTL dibuat, langkah berikutnya adalah menggunakannya di desain, untuk mana kami menggunakan Vivado. Dalam Vivado kita dapat menambahkan elemen-elemen berikut

    • Zynq Processing System – Mengonfigurasi lengan A9
    • AXI Bram Control – Memungkinkan A9 untuk membaca dan menulis BRAM
    • Blok Memori – Menyimpan nilai-nilai NeoPixel
    • AXI Smart Connect – Menyediakan Koneksi AXI yang diperlukan
    • Reset Block – Mengontrol ulang untuk sistem

    Desain perangkat keras akan menargetkan papan pengembangan MiniZed dari Avnet. Ini berisi perangkat Zynq 7007 inti tunggal.

    Untuk menghubungkan NeoPixel ke MiniZed, desain menggunakan Pmod1 dan Pmod CON1 untuk menghubungkan input dan ground serial. Karena NeoPixels dapat memiliki konsumsi daya yang signifikan, catu daya eksternal digunakan untuk menyalakan array piksel.

    Setiap LED individu dalam NeoPixel membutuhkan arus maksimum 20mA. Ada tiga LED di setiap NeoPixel, maka setiap piksel RGB membutuhkan 60mA.

    Karena kami memiliki kekuatan hingga 256 NeoPixels yang didukung, kami harus memiliki catu daya yang cukup besar. Dengan semua tampilan LED hanya menampilkan satu warna, kami akan membutuhkan solusi catu daya yang mampu menyediakan 5,12 Amps sementara jika kami ingin menggunakan beberapa LED, kami harus dapat menyediakan hingga 15,36 Amps (yang cukup besar)

    Desain Perangkat Lunak

    Desain perangkat lunak adalah modular dan bekerja pada kisi-kisi yang didefinisikan yang dapat kita tambahkan di negara-negara awal. misalnya Glider atau Exploder.

    Yang saya pikirkan adalah kita dapat memilih pola melalui port serial (akhirnya nirkabel dan Linux tetapi saya perlu memperbarui MiniZed BSP yang akan kita lakukan dalam proyek segera)

    Arsitektur ini didasarkan pada hal berikut functions

    • next_generation () – Ini menciptakan evolusi berikutnya dari game
    • update () – Pembaruan evolusi berikutnya ke dalam generasi yang ditampilkan saat ini
    • load_ram () – Ini memuat generasi saat ini ke layar NeoPixel. [19659010] Untuk memastikan kita dapat mengamati pembaruan untuk setiap generasi, saya menghitung waktu desain untuk menghasilkan evolusi baru sekitar setiap 2,5 detik

      Kode untuk menentukan generasi berikutnya berfungsi dalam dua untuk loop satu untuk setiap dimensi array. Sementara di dalam loop dalam, dua loop lainnya digunakan untuk menentukan jumlah piksel yang hidup di dekat piksel yang sedang diperiksa.

      Semua ini dilakukan dalam fungsi generasi berikutnya, hidup bit mati diwakili oleh bit tunggal dalam array 2D.

       membatalkan next_generation ()
       {
       untuk (int l = 1; l  {
       untuk (int m = 1; m  {
       int alive = 0;
       untuk (int i = -1; i <= 1; i ++) {
       untuk (int j = -1; j <= 1; j ++) {
       hidup + = ada [l + i][m + j];
      }
      }
       hidup - = ada [l][m];
       if ((sekarang [l][m] == 1) &&
       (hidup <2))
       masa depan [l][m] = 0;
       else if ((present [l][m] == 1) &&
       (hidup> 3))
       masa depan [l][m] = 0;
       else if ((present [l][m] == 0) &&
       (hidup == 3))
       masa depan [l][m] = 1;
       lagi
       masa depan [l][m] = ada [l][m];
      }
      }
      }
      

      Ini adalah fungsi BRAM beban yang memberikan warna pada piksel di NeoPixel Array.

       membatalkan load_ram ()
       {
       int ram_addr = 0x4;
       int read_out = 0;
       u32 keluar;
       ram_addr = 0x4;
       read_out = 0;
       untuk (int l = 0; l  {
       untuk (int m = 0; m  {
       jika ((l <8) && (m <8))
       {
       if (present [l][m] == 1) {
       keluar = 0x00000f;
       ram_addr = ((l * 8) + m) * 4) +4;
       XBram_WriteReg (XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR, ram_addr, out); // present [l][m]);
      }
       lagi {
       keluar = 0x000f00;
       ram_addr = ((l * 8) + m) * 4) +4;
       XBram_WriteReg (XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR, ram_addr, keluar);
      }
      }
       jika ((l < 8)&& (m > 7))
       {
       if (present [l][m] == 1) {
       keluar = 0x00000f;
       ram_addr = ((256) + ((l * 8) + (m-8)) * 4) +4;
       XBram_WriteReg (XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR, ram_addr, out); // present [l][m]);
      }
       lagi {
       keluar = 0x000f00;
       ram_addr = ((256) + ((l * 8) + (m-8)) * 4) +4;
       XBram_WriteReg (XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR, ram_addr, keluar);
      }
      }
       jika ((l> 7) && (m> 7))
       {
       if (present [l][m] == 1) {
       keluar = 0x00000f;
       ram_addr = ((256) + ((l * 8) + (m-8)) * 4) +4;
       XBram_WriteReg (XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR, ram_addr, out); // present [l][m]);
      }
       lagi {
       keluar = 0x000f00;
       ram_addr = ((256) + ((l * 8) + (m-8)) * 4) +4;
       XBram_WriteReg (XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR, ram_addr, keluar);
      }
      }
       jika ((l> 7) && (m <8))
       {
       if (present [l][m] == 1) {
       keluar = 0x00000f;
       ram_addr = ((512) + ((l * 8) + (m)) * 4) +4;
       XBram_WriteReg (XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR, ram_addr, out); // present [l][m]);
      }
       lagi
       keluar = 0x000f00;
       ram_addr = ((512) + ((l * 8) + (m)) * 4) +4;
       XBram_WriteReg (XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR, ram_addr, keluar);
      }
      }
      }
       // aktifkan data
       XBram_WriteReg (XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR, 0, (u32) numb_pixels);
      }
      

      Membangun perangkat keras

      Desainnya memiliki panel piksel neo yang terintegrasi, memberi kita total 256 piksel untuk menciptakan permainan kehidupan kita. Setiap array NeoPixel memiliki koneksi Data In dan Data Out, ini memungkinkan kita untuk menghubungkan daisy array NeoPixel bersama.

      Menguji

      Setelah keempat panel dihubungkan bersama-sama, langkah selanjutnya adalah memastikan arsitektur daya cukup. Untuk pengujian, saya menggunakan catu daya bangku yang mampu menyediakan arus yang dibutuhkan untuk memberi daya pada rongga NeoPixel sementara MiniZed ditenagai oleh konektor USB. Untuk memastikan sinyal data diterima dengan benar, referensi ground terhubung antara Pmod CON1 dan bangku PSU.

      Kalibrasi

      Setelah empat panel dibangun Saya ingin dapat memeriksa bahwa pemetaan saya ke setiap NeoPixels dalam perangkat lunak sudah benar. Untuk melakukan ini di grid awal, saya mengatur empat sudut luar untuk menyala, bersama dengan empat LED tengah. Pada saat yang sama setiap panel memiliki Blinker menjalankannya.

      Ketika saya menyatukan ini semua saya merekam video di bawah ini

      Glider

      Glider bergerak melintasi NeoPixel Array

      Oscillator

      Memasang [19659003] Untuk memasang empat array NeoPixel di grid, saya akan menggunakan printer 3D untuk membuat frame sederhana yang akan menahan empat Neo Pixel Arrays. Namun pertama saya harus membeli printer!

      Pekerjaan Lebih Lanjut – Kontrol MiniZed melalui Wifi untuk keadaan awal

      Anda dapat menemukan file yang terkait dengan proyek ini di sini:

      https://github.com/ATaylorCEngFIET/Hackster [19659003] Lihat proyek sebelumnya di sini.

      Lebih lanjut tentang Xilinx menggunakan pengembangan mingguan FPGA di MicroZed Chronicles.

Leave a Reply

Your email address will not be published. Required fields are marked *