pengantar
Selamat siang teman! Baru-baru ini di tempat kerja kami mendapat papan Platform Pengembangan Seluler UltraPlus iCE40 baru dari Lattice Semiconductor. Menurut pengembang di situs web resmi iCE40 UltraPlus, MDP adalah papan yang berisi 4 iCE40 UltraPlus FPGA, yang masing-masing mengontrol perangkat periferalnya sendiri. Set tersebut meliputi:
- tampilan seluler dengan resolusi 240x240 dengan antarmuka MIPI DSI;
- sensor gambar dengan resolusi 640x480 (OVM7692);
- mikrofon berdaya rendah sebanyak 4 buah;
- Modul BLE untuk transmisi data nirkabel;
- memori Flash SPI yang dapat diprogram;
- pak berbagai sensor (tekanan, kompas, giroskop dan akselerometer);
- baik, semua jenis tombol dan lampu.
Hal yang paling keren tentang ikan paus ini adalah dengan bantuan paket perangkat lunak khusus, Anda dapat menerapkan jaringan saraf untuk bekerja dengan video dan suara. Dan ini belum lagi fakta bahwa FPGA Lattice berdaya rendah, berukuran kecil, dan cukup murah.
UltraPlus MDP
Sebagai kasus uji, kedipkan LED RGB (D13 dalam diagram, disorot dengan warna merah pada gambar di sebelah kiri) Setelah meninjau dokumentasi, kami menyimpulkan bahwa LED dikendalikan oleh nomor FPGA U3 (disorot dengan warna merah pada gambar di sebelah kanan). Kami juga belajar dari dokumentasi bahwa LED dikontrol oleh modulator PWM bawaan dan driver saat ini.
Kami mencatat informasi ini.
Menyiapkan papan dan menulis program
Ada sekelompok jumper di papan, yang dengannya Anda dapat memilih FPGA, yang harus di-flash untuk bekerja dengan kelompok perangkat periferal yang dipilih. Kami tertarik pada tiga kelompok jumper yang bertanggung jawab untuk menarik catu daya ke LED dan memprogram FPGA yang diinginkan.
Prosedurnya adalah sebagai berikut:
- Atur sakelar SW5 ke posisi ON / OFF
- Dua jumper di J19 secara horizontal
- J26 , 1-2 3-4 ( . , )
- J17, J25, J27 9-10 ( )
Ya, saya mengerti, semuanya membosankan, tetapi tanpa itu tidak akan berhasil.
Juga, untuk menghubungkan generator sinyal clock, perlu untuk mengatur jumper jumper J23 ke posisi 2-3 (penomoran dimulai dari atas).
Sekarang programnya. Untuk membuat file bit untuk firmware iCE40 UltraPlus MDP, Anda memerlukan lingkungan pengembangan Lattice iCE cube 2 ( tautan ke halaman produk ) dan untuk mem- flash papan Programmer and Deployment Tool itu sendiri . Produk ini berlisensi, tetapi setelah registrasi, lisensinya dapat diperoleh di sini www.latticesemi.com/Support/Licensing/DiamondAndiCEcube2SoftwareLicensing/iceCube2
Editor di IDE sangat tidak nyaman, jadi saya menulis di Sublime Text, tetapi untuk masing-masing editornya sendiri.
Berikut adalah skema umum yang memberikan pemahaman tentang apa dan di mana harus dilakukan:
Jadi modulator PWM dan driver saat ini, yang saya sebutkan sebelumnya, telah muncul. Kedua perangkat ini adalah modul internal. Anda perlu menulis perangkat kontrol logika dan mengirim data agar seluruh dapur ini berfungsi dengan baik. Mari kita mulai secara berurutan, mendeskripsikan "kotak hitam":
entity DriverRGB is
port (
-- RGB Led:
LED0 : out std_logic;
LED1 : out std_logic;
LED2 : out std_logic );
end DriverRGB;
Inisialisasi sinkronisasi tidak ada di kotak hitam. Untuk ini, modul internal digunakan, yang dideklarasikan sebagai berikut:
-- Generator clock:
component SB_HFOSC is
generic (
CLKHF_DIV : string := "0b00" );
port (
CLKHFPU : in std_logic;
CLKHFEN : in std_logic;
CLKHF : out std_logic );
end component;
Modul ini dapat menghasilkan sinyal dengan frekuensi 48MHz, 24MHz, 12MHz dan 6MHz. Parameter CLKHF_DIV bertanggung jawab atas faktor pembagian frekuensi (masing-masing "0b00", "0b01", "0b10", "0b11"). CLKHFPU dan CLKHFEN mengaktifkan modul untuk bekerja. CLKHF - sinyal jam.
Selanjutnya, kami mendeklarasikan modulator PWM dan driver saat ini:
-- Embedded PWM IP:
component SB_LEDDA_IP is
port (
LEDDCS : in std_logic;
LEDDCLK : in std_logic;
LEDDDAT7 : in std_logic;
LEDDDAT6 : in std_logic;
LEDDDAT5 : in std_logic;
LEDDDAT4 : in std_logic;
LEDDDAT3 : in std_logic;
LEDDDAT2 : in std_logic;
LEDDDAT1 : in std_logic;
LEDDDAT0 : in std_logic;
LEDDADDR3 : in std_logic;
LEDDADDR2 : in std_logic;
LEDDADDR1 : in std_logic;
LEDDADDR0 : in std_logic;
LEDDDEN : in std_logic;
LEDDEXE : in std_logic;
LEDDRST : in std_logic;
PWMOUT0 : out std_logic;
PWMOUT1 : out std_logic;
PWMOUT2 : out std_logic;
LEDDON : out std_logic );
end component;
-- RGB Driver:
component SB_RGBA_DRV is
generic (
CURRENT_MODE : string := "0b0";
RGB0_CURRENT : string := "0b000000";
RGB1_CURRENT : string := "0b000000";
RGB2_CURRENT : string := "0b000000" );
port (
CURREN : in std_logic;
RGBLEDEN : in std_logic;
RGB0PWM : in std_logic;
RGB1PWM : in std_logic;
RGB2PWM : in std_logic;
RGB0 : out std_logic;
RGB1 : out std_logic;
RGB2 : out std_logic );
end component;
Modulator PWM perlu memberi makan alamat dan data yang bertanggung jawab untuk mode operasi LED dan beberapa sinyal kontrol. Output tersebut kemudian diproses oleh driver arus RGB, yang sudah menyalakan LED.
Driver saat ini memproses data dari modulator PWM dan menyesuaikan nilai arus yang disuplai ke LED. Parameter RGB0_CURRENT, RGB1_CURRENT, RGB2_CURRENT mengatur jumlah arus untuk setiap warna. CURRENT_MODE - mode daya (penuh atau setengah).
Ya keren. Ada alamat, ada data. Nah, apa yang harus dikirim kepada mereka? Secara umum, pengembang Lattice memberikan deskripsi yang agak detail dalam dokumentasinya, tetapi cukup banyak. Saya akan mencoba memampatkan semuanya menjadi beberapa baris deskripsi dan kode untuk kejelasan.
Modulator PWM mengharapkan 9 alamat. Masing-masing bertanggung jawab atas fungsi tertentu agar LED tetap berfungsi. Di bawah ini adalah tabel yang menunjukkan nilai dan nama alamat:
Untuk mengirim data, kami menerapkan mesin negara hingga:
type LED_Driver is (IDLE, LEDDBR, LEDDONR, LEDDOFR, LEDDBCRR, LEDDBCFR, LEDDPWRR, LEDDPWRG, LEDDPWRB, LEDDCR0, DONE);
Langkah pertama adalah menulis data ke register LEDDBR. Ini menyimpan nilai untuk frekuensi clock PWM. Itu dianggap sebagai berikut:
Register Value N = Fsys/64kHz-1
Struktur rekaman data terlihat seperti ini:
Dua bit paling signifikan untuk nilai frekuensi akan ditambahkan saat kita beralih ke register LEDDCR0.
when LEDDBR =>
led_en <= '1';
led_cs <= '1';
led_exe <= '0';
LEDD_ADR <= "1001";
DAT_Bits(7 downto 0) <= "11101101"; -- ( )
PWM_state_next <= LEDDONR;
Register LEDDONR mencatat waktu aktifnya LED. Dokumentasi berisi tabel korespondensi yang kumpulan bitnya termasuk dalam waktu pembakaran LED tertentu.
when LEDDONR =>
led_en <= '1';
led_cs <= '1';
led_exe <= '0';
LEDD_ADR <= "1010";
DAT_Bits(7 downto 0) <= "00010001"; -- (0.5 c)
Register LEDDOFR berisi data berapa lama LED tidak aktif. Nilai yang sama persis seperti di LEDDONR.
when LEDDOFR =>
led_en <= '1';
led_cs <= '1';
led_exe <= '0';
LEDD_ADR <= "1011";
DAT_Bits(7 downto 0) <= "00010001"; -- (0.5 c)
PWM_state_next <= LEDDBCRR;
LEDDBCRR - data tentang durasi soft-on LED.
when LEDDBCRR =>
led_en <= '1';
led_cs <= '1';
led_exe <= '0';
LEDD_ADR <= "0101";
DAT_Bits(7) <= '1'; -- ()
DAT_Bits(6) <= '1'; --
DAT_Bits(5) <= '1'; --
DAT_Bits(4) <= '0'; -- RESERVED
DAT_Bits(3 downto 0) <= "0011"; -- (0.5 )
PWM_state_next <= LEDDBCFR;
LEDDBCRR - data tentang durasi soft off LED.
when LEDDBCFR =>
led_en <= '1';
led_cs <= '1';
led_exe <= '0';
LEDD_ADR <= "0110";
DAT_Bits(7) <= '1'; -- () (disable/enable)
DAT_Bits(6) <= '0'; -- PWM Range Extend
DAT_Bits(5) <= '1'; --
DAT_Bits(4) <= '0'; -- RESERVED
DAT_Bits(3 downto 0) <= "0011"; -- (0.5 )
PWM_state_next <= LEDDPWRR;
Register LEDDPWRR, LEDDPWRG, dan LEDDPWRB menyimpan data masing-masing pada kecerahan LED merah, biru dan hijau. Nilai kecerahan dihitung sebagai persentase dengan rumus berikut:
ADC(%) = PulseWidth/256
Oleh karena itu, nilai kecerahan yang berbeda memberikan campuran warna, sehingga Anda dapat bermain-main dan mencapai cita-cita Anda.
when LEDDPWRR =>
led_en <= '1';
led_cs <= '1';
led_exe <= '0';
LEDD_ADR <= "0001";
DAT_Bits(7 downto 0) <= "00000001"; -- RED Pulse Width
PWM_state_next <= LEDDPWRG;
when LEDDPWRG =>
led_en <= '1';
led_cs <= '1';
led_exe <= '0';
LEDD_ADR <= "0010";
DAT_Bits(7 downto 0) <= "11111111"; -- GREEN Pulse Width
PWM_state_next <= LEDDPWRB;
when LEDDPWRB =>
led_en <= '1';
led_cs <= '1';
led_exe <= '0';
LEDD_ADR <= "0011";
DAT_Bits(7 downto 0) <= "00011111"; -- BLUE Pulse Width
PWM_state_next <= LEDDCR0;
Nah, dalam LEDDCR0 register terakhir, informasi pengaktifan dan dua bit paling signifikan dari frekuensi sinyal clock PWM ditulis:
when LEDDCR0 =>
led_en <= '1';
led_cs <= '1';
led_exe <= '0';
LEDD_ADR <= "1000";
DAT_Bits(7) <= '1'; -- ()
DAT_Bits(6) <= '1'; -- Flick Rate Select Bit (125/250 Hz)
DAT_Bits(5) <= '0'; -- (1/0)
DAT_Bits(4) <= '0'; --
DAT_Bits(3) <= '1'; -- Blinking Sequence Quick Stop Enable Bit
DAT_Bits(2) <= '0'; -- PWM Mode Selection Bit
DAT_Bits(1 downto 0) <= "10"; --
PWM_state_next <= DONE;
Contoh implementasi
RGB
Ungu / Putih
Meringkas
Nah itu saja. Dengan mengubah parameter, Anda dapat mencapai efek pernapasan indah dari LED dengan warna dan kecerahan berbeda dengan mengubah nilai dalam register LEDDPWRR, LEDDPWRG, LEDDPWRB atau nilai saat ini dari driver RGB. Di bawah ini adalah tautan ke kode di GitHub dan semua dokumentasi yang diperlukan.
Di masa mendatang, saya berencana untuk menguji roti lainnya dan, jika memungkinkan, menaruhnya di sini untuk ditinjau.
Panduan Pengguna Papan Evaluasi Kode
Panduan Penggunaan Driver LED iCE40