Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Industrial programming >> VHDL

Membuat Efek LED Bernapas dengan Gelombang Sinus dari Block RAM

Saya telah memperhatikan bahwa banyak perangkat yang saya beli selama beberapa tahun terakhir telah beralih dari LED berkedip ke LED bernapas. Sebagian besar gaya elektronik mengandung LED status yang perilakunya memberikan indikasi tentang apa yang terjadi di dalam perangkat.

Sikat gigi listrik saya berkedip LED saat saatnya untuk diisi ulang, dan ponsel saya menggunakan LED untuk memanggil perhatian saya untuk berbagai alasan. Tapi LED tidak berkedip seperti dulu. Ini lebih seperti efek pulsa analog dengan intensitas yang terus bervariasi.

Animasi GIF di bawah ini menunjukkan mouse Logitech saya menggunakan efek ini untuk menunjukkan bahwa baterai sedang diisi. Saya menyebut efek ini breathing LED karena pola intensitas cahaya mirip dalam kecepatan dan percepatan dengan siklus pernapasan manusia. Ini terlihat sangat alami karena siklus pencahayaan mengikuti pola gelombang sinus.

Membuat Efek LED Bernapas dengan Gelombang Sinus dari Block RAM

Artikel ini adalah lanjutan dari posting blog minggu lalu tentang modulasi lebar pulsa (PWM). Hari ini, kita akan menggunakan modul PWM, counter gigi gergaji, dan modul reset yang kita buat dalam tutorial sebelumnya. Klik tautan di bawah ini untuk membaca artikel tentang PWM!

Cara membuat pengontrol PWM dalam VHDL

Menyimpan Nilai Gelombang Sinus di Block RAM

Sementara mungkin untuk menghasilkan gelombang sinus menggunakan primitif pemrosesan sinyal digital (DSP) di FPGA, cara yang lebih sederhana adalah menyimpan titik sampel di block RAM. Alih-alih menghitung nilai selama run-time, kita menghitung serangkaian nilai sinus selama sintesis dan membuat memori hanya baca (ROM) untuk menyimpannya.

Pertimbangkan contoh minimal di bawah ini, yang menunjukkan cara menyimpan gelombang sinus penuh di ROM 3×3 bit. Kedua input alamat dan output data adalah tiga bit lebar, artinya mereka dapat mewakili nilai integer dalam rentang 0 hingga 7. Kita dapat menyimpan delapan nilai sinus di ROM, dan resolusi data juga 0 hingga 7.

Membuat Efek LED Bernapas dengan Gelombang Sinus dari Block RAM

Fungsi sinus trigonometrik menghasilkan angka dalam rentang [-1, 1] untuk masukan sudut x apa pun. Juga, siklusnya berulang ketika x ≥ 2π. Oleh karena itu, cukup untuk menyimpan nilai sinus dari nol hingga, tidak termasuk, 2π. Nilai sinus untuk 2π sama dengan sinus untuk nol. Ilustrasi di atas menunjukkan konsep ini. Kita menyimpan nilai sinus dari nol hingga \frac{7\pi}{4}, yang adalah langkah yang sama rata terakhir sebelum lingkaran penuh 2π.

Logika digital tidak dapat mewakili nilai nyata, seperti sudut atau nilai sinus, dengan presisi tak terbatas. Itu adalah kasus dalam sistem komputer apa pun. Bahkan saat menggunakan bilangan floating-point presisi ganda, itu hanyalah perkiraan. Itulah cara kerja bilangan biner, dan ROM sinus kami tidak berbeda.

Untuk mendapatkan yang terbaik dari bit data yang tersedia, kita menambahkan offset dan skala ke nilai sinus saat kita menghitung konten ROM. Nilai sinus terendah -1 dipetakan ke nilai data 0, sementara nilai sinus tertinggi 1 diterjemahkan ke 2^{\mathit{data\_bits}-1}, seperti yang ditunjukkan oleh rumus di bawah ini.

\mathit{data} = \mathit{Round}\left(\frac{(1 + \sin \mathit{addr}) * (2^\mathit{data\_bits} - 1)}{2}\right)

Untuk menterjemahkan alamat ROM menjadi sudut, x, kita dapat menggunakan rumus berikut:

x = \frac{\mathit{addr} * 2\pi}{2^\mathit{addr\_bits}}

Tentu saja, metode ini tidak memberi Anda konverter sudut ke nilai sinus universal. Jika itu yang Anda inginkan, Anda harus menggunakan logika tambahan atau primitif DSP untuk menskalakan input alamat dan output data. Tetapi untuk banyak aplikasi, gelombang sinus yang direpresentasikan sebagai integer tanpa tanda sudah cukup. Dan seperti yang akan kita lihat di bagian selanjutnya, itu adalah tepat apa yang kita butuhkan untuk proyek LED bernapas kami.

Modul Sine ROM

Modul Sine ROM yang disajikan dalam artikel ini akan menyimpulkan block RAM pada sebagian besar arsitektur FPGA. Pertimbangkan untuk mencocokkan lebar dan kedalaman generic dengan primitif memori target FPGA Anda. Itu akan memberi Anda utilizasi sumber daya terbaik. Anda selalu dapat merujuk ke proyek Lattice contoh jika Anda tidak yakin cara menggunakan Sine ROM untuk proyek FPGA nyata.

Tinggalkan email Anda dalam formulir di bawah ini untuk mengunduh file VHDL dan proyek ModelSim / iCEcube2!

Entitas

Kode di bawah ini menunjukkan entitas modul Sine ROM. Ini memiliki dua input generic yang memungkinkan Anda menentukan lebar dan kedalaman block RAM yang disimpulkan. Saya menggunakan spesifikasi rentang pada konstanta untuk mencegah overflow integer yang tidak disengajakan. Lebih lanjut tentang itu nanti dalam artikel ini.

 entity sine_rom is generic ( addr_bits : integer range 1 to 30; data_bits : integer range 1 to 31 ); port ( clk : in std_logic; addr : in unsigned(addr_bits - 1 downto 0); data : out unsigned(data_bits - 1 downto 0) ); end sine_rom; 

Deklarasi port memiliki input clock, tetapi tidak ada reset karena primitif RAM tidak dapat memiliki reset. Input addr adalah tempat kita menetapkan nilai sudut yang diskala (x), dan output data adalah tempat nilai sinus yang diskala akan muncul.

Deklarasi Tipe

Di bagian atas wilayah deklaratif file VHDL, kita mendeklarasikan tipe dan subtype untuk objek penyimpanan ROM kita. Subtype addr_range adalah rentang integer sama dengan jumlah slot di RAM kita, dan rom_type menggambarkan array 2D yang akan menyimpan semua nilai sinus.

 subtype addr_range is integer range 0 to 2**addr_bits - 1; type rom_type is array (addr_range) of unsigned(data_bits - 1 downto 0); 

Namun, kita tidak akan mendeklarasikan sinyal penyimpanan saat ini. Pertama, kita perlu mendefinisikan fungsi yang akan menghasilkan nilai sinus, yang dapat kita gunakan untuk mengubah RAM menjadi ROM. Kita harus mendeklarasikannya di atas deklarasi sinyal sehingga kita dapat menggunakan fungsi untuk menetapkan nilai awal ke sinyal penyimpanan ROM.

Perhatikan bahwa kita menggunakan generic addr_bits sebagai dasar untuk mendefinisikan addr_range. Itulah sebabnya saya harus menentukan nilai maksimum 30 untuk addr_bits. Karena untuk nilai yang lebih besar, perhitungan 2**addr_bits - 1 akan overflow. Integer VHDL adalah 32-bit, meskipun itu akan berubah dengan VHDL-2019, yang menggunakan integer 64-bit. Tetapi untuk saat ini, kita harus hidup dengan keterbatasan ini saat menggunakan integer dalam VHDL sampai alat mulai mendukung VHDL-2019.

Fungsi untuk Menghasilkan Nilai Sinus

Kode di bawah ini menunjukkan fungsi init_rom yang menghasilkan nilai sinus. Fungsi ini mengembalikan objek rom_type, itulah sebabnya kita harus mendeklarasikan tipe terlebih dahulu, kemudian fungsi, dan akhirnya konstanta ROM. Mereka bergantung satu sama lain dalam urutan yang tepat itu.

 function init_rom return rom_type is variable rom_v : rom_type; variable angle : real; variable sin_scaled : real; begin for i in addr_range loop angle := real(i) * ((2.0 * MATH_PI) / 2.0**addr_bits); sin_scaled := (1.0 + sin(angle)) * (2.0**data_bits - 1.0) / 2.0; rom_v(i) := to_unsigned(integer(round(sin_scaled)), data_bits); end loop; return rom_v; end init_rom; 

Fungsi ini menggunakan beberapa variabel kenyamanan, termasuk rom_v, salinan lokal dari array yang kita isi dengan nilai sinus. Di dalam subprogram, kita menggunakan loop for untuk melintasi rentang alamat, dan untuk setiap slot ROM, kita menghitung nilai sinus menggunakan rumus yang saya sebutkan sebelumnya. Dan di akhir, kita mengembalikan variabel rom_v yang pada titik ini berisi semua sampel sinus.

Konversi integer pada baris terakhir di dalam loop for adalah alasan mengapa saya harus membatasi generic data_bits ke 31 bit. Ini akan overflow untuk panjang bit yang lebih besar.

 constant rom : rom_type := init_rom; 

Di bawah definisi fungsi init_rom, kita melanjutkan untuk mendeklarasikan objek rom sebagai konstanta. ROM hanyalah RAM yang tidak pernah Anda tulis ke dalamnya, jadi itu sangat baik. Dan sekarang saatnya untuk menggunakan fungsi kita. Kita memanggil init_rom untuk menghasilkan nilai awal, seperti yang ditunjukkan dalam kode di atas.

Proses ROM

Logika satu-satunya dalam file Sine ROM adalah proses yang cukup sederhana yang tercantum di bawah ini. Ini menggambarkan block RAM dengan satu port baca.

 ROM_PROC : process(clk) begin if rising_edge(clk) then data <= rom(to_integer(addr)); end if; end process; 

Modul Top

Desain ini adalah lanjutan dari proyek PWM yang saya sajikan dalam posting blog saya sebelumnya. Ini memiliki modul reset, modul pembangkit PWM, dan modul counter siklus clock bebas berjalan (sawtooth counter). Lihat artikel minggu lalu untuk melihat bagaimana modul-modul ini bekerja.

Diagram di bawah ini menunjukkan koneksi antara submodul dalam modul top.

Membuat Efek LED Bernapas dengan Gelombang Sinus dari Block RAM

Kode di bawah ini menunjukkan wilayah deklaratif file VHDL top. Dalam desain PWM minggu lalu, objek duty_cycle adalah alias untuk MSB dari counter cnt. Tapi itu tidak akan bekerja sekarang karena output dari Sine ROM akan mengontrol siklus kerja, jadi saya telah menggantinya dengan sinyal aktual. Selain itu, saya telah membuat alias baru dengan nama addr yang merupakan MSB dari counter. Kita akan menggunakannya sebagai input alamat untuk ROM.

 signal rst : std_logic; signal cnt : unsigned(cnt_bits - 1 downto 0); signal pwm_out : std_logic; signal duty_cycle : unsigned(pwm_bits - 1 downto 0); -- Gunakan MSB counter untuk input alamat Sine ROM alias addr is cnt(cnt'high downto cnt'length - pwm_bits); 

Anda dapat melihat cara membuat instance Sine ROM baru kita di modul top dalam daftar di bawah ini. Kami mengatur lebar dan kedalaman RAM untuk mengikuti panjang counter internal modul PWM. Output data dari ROM mengontrol input duty_cycle ke modul PWM. Nilai pada sinyal duty_cycle akan menggambarkan pola gelombang sinus ketika kita membaca slot RAM satu demi lain.

 SINE_ROM : entity work.sine_rom(rtl) generic map ( data_bits => pwm_bits, addr_bits => pwm_bits ) port map ( clk => clk, addr => addr, data => duty_cycle ); 

Mensimulasikan Sine ROM

Gambar di bawah ini menunjukkan gelombang simulasi modul top di ModelSim. Saya telah mengubah presentasi sinyal unsigned duty_cycle ke format analog sehingga kita dapat mengamati gelombang sinus.

Membuat Efek LED Bernapas dengan Gelombang Sinus dari Block RAM

Itu adalah output top-level led_5 yang membawa sinyal PWM, yang mengontrol LED eksternal. Kita dapat melihat bahwa output berubah cepat ketika siklus kerja naik atau turun. Tetapi ketika siklus kerja di puncak gelombang sinus, led_5 adalah '1' yang stabil. Khi gelombang di dasar lereng, output tetap sejenak pada '0'.

Ingin mencobanya di komputer rumah Anda? Masukkan alamat email Anda dalam formulir di bawah ini untuk menerima file VHDL dan proyek ModelSim dan iCEcube2!

Mengimplementasikan LED bernapas di FPGA

Saya menggunakan perangkat lunak Lattice iCEcube2 untuk mengimplementasikan desain pada papan FPGA iCEstick. Gunakan formulir di atas untuk mengunduh proyek dan mencobanya di papan Anda jika Anda memiliki iCEstick!

Daftar di bawah ini menunjukkan penggunaan sumber daya, seperti yang dilaporkan oleh perangkat lunak Synplify Pro yang hadir dengan iCEcube2. Ini menunjukkan bahwa desain menggunakan satu primitif block RAM. Itulah Sine ROM kami.

 Resource Usage Report for led_breathing Mapping to part: ice40hx1ktq144 Cell usage: GND 4 uses SB_CARRY 31 uses SB_DFF 5 uses SB_DFFSR 39 uses SB_GB 1 use SB_RAM256x16 1 use VCC 4 uses SB_LUT4 65 uses I/O ports: 7 I/O primitives: 7 SB_GB_IO 1 use SB_IO 6 uses I/O Register bits: 0 Register bits not including I/Os: 44 (3%) RAM/ROM usage summary Block Rams : 1 of 16 (6%) Total load per clock: led_breathing|clk: 1 @S |Mapping Summary: Total LUTs: 65 (5%) 

Setelah merute desain di iCEcube2, Anda akan menemukan file .bin di folder led_breathing_Implmnt\sbt\outputs\bitmap di dalam direktori proyek Lattice_iCEcube2_proj.

Anda dapat menggunakan perangkat lunak Lattice Diamond Programmer Standalone untuk memprogram FPGA, seperti yang ditunjukkan dalam manual pengguna iCEstick. Itulah yang saya lakukan, dan animasi GIF di bawah ini menunjukkan hasilnya. Intensitas cahaya LED berosilasi dengan pola gelombang sinus. Ini terlihat sangat alami, dan LED tampak “bernapas” jika Anda membutuhkan imajinasi sedikit.

Membuat Efek LED Bernapas dengan Gelombang Sinus dari Block RAM

Pikiran Akhir

Menggunakan block RAM untuk menyimpan nilai sinus yang telah dihitung sebelumnya cukup sederhana. Tetapi ada beberapa keterbatasan yang membuat metode ini hanya cocok untuk gelombang sinus dengan resolusi X dan Y yang terbatas.

Alasan pertama yang datang ke pikiran adalah batas 32-bit untuk nilai integer yang saya bahas sebelumnya. Saya yakin Anda dapat mengatasi masalah ini dengan menghitung nilai sinus dengan lebih cerdas, tetapi itu belum semua.

Untuk setiap bit yang Anda tambahkan ke alamat ROM, Anda menggandakan penggunaan RAM. Jika Anda membutuhkan presisi tinggi pada sumbu X, mungkin tidak cukup RAM, bahkan pada FPGA yang lebih besar.

Jika jumlah bit yang digunakan untuk nilai sinus sumbu Y melebihi kedalaman RAM asli, alat sintesis akan menggunakan RAM atau LUT tambahan untuk mengimplementasikan ROM. Ini akan menghabiskan lebih banyak anggaran sumber daya Anda seiring dengan peningkatan presisi Y.

Secara teori, kita hanya perlu menyimpan satu kuadran gelombang sinus. Oleh karena itu, Anda dapat menghemat sepertiga penggunaan RAM jika Anda menggunakan mesin keadaan terhingga (FSM) untuk mengontrol pembacaan ROM. Ini akan harus membalikkan kuadran sinus untuk semua empat permutasi sumbu X dan Y. Kemudian, Anda dapat membangun gelombang sinus penuh dari satu kuadran yang disimpan di block RAM.

Sayangnya, sulit untuk membuat semua empat segmen bergabung dengan lancar. Dua sampel yang sama pada persimpangan di puncak dan dasar gelombang sinus mengganggu data dengan menciptakan titik datar pada gelombang sinus. Memasukkan noise mengalahkan tujuan menyimpan hanya kuadran untuk meningkatkan presisi gelombang sinus.


VHDL

  1. Buat Template AWS CloudFormation Pertama Anda – Panduan Praktis
  2. Menciptakan Pengalaman Pengguna Tanpa Hambatan: Panduan Desain UX
  3. Membuat Daftar String dalam VHDL: Praktik Terbaik & Contoh
  4. Membuat Testbench yang Diakibatkan Tcl untuk Modul Kode-Kunci VHDL
  5. Menginisialisasi Block RAM FPGA dari Berkas Teks dengan Pustaka TEXTIO VHDL
  6. Cara Membuat Testbench Self-Checking di VHDL – Panduan Praktis
  7. Implementasi Linked List Dinamis di VHDL dengan Tipe Terlindung dan Pointer Akses
  8. Membuat Array Objek di Java: Panduan Langkah demi Langkah
  9. Revolusi Manufaktur Digital dalam Pemodelan Anatomi di Medis Modern
  10. Memanggil Blok Fungsi PLC melalui Klien OPC UA: Panduan Praktis