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

Cara membuat efek LED pernapasan menggunakan gelombang sinus yang disimpan di blok RAM

Saya perhatikan bahwa banyak gadget yang saya beli beberapa tahun terakhir telah beralih dari kedipan LED ke pernapasan led. Sebagian besar alat elektronik berisi LED status yang perilakunya memberikan indikasi tentang apa yang terjadi di dalam perangkat.

Sikat gigi elektrik saya berkedip LED ketika saatnya untuk mengisi ulang, dan ponsel saya menggunakan LED untuk menarik perhatian saya untuk berbagai alasan. Tapi LED tidak berkedip seperti dulu. Ini lebih seperti efek denyut analog dengan intensitas bervariasi terus menerus.

Animasi Gif di bawah ini menunjukkan mouse Logitech saya menggunakan efek ini untuk menunjukkan bahwa itu sedang mengisi daya baterai. Saya menyebut efek ini LED pernapasan karena pola intensitas cahaya memiliki kecepatan dan percepatan yang mirip dengan siklus pernapasan manusia. Terlihat sangat alami karena siklus iluminasi mengikuti pola gelombang sinus.

Artikel ini merupakan kelanjutan dari posting blog minggu lalu tentang modulasi lebar-pulsa (PWM). Hari ini, kita akan menggunakan modul PWM, penghitung gigi gergaji, dan modul reset yang telah kita buat pada tutorial sebelumnya. Klik link di bawah untuk membaca artikel tentang PWM!

Cara membuat pengontrol PWM di VHDL

Menyimpan nilai gelombang sinus dalam blok RAM

Meskipun dimungkinkan untuk menghasilkan gelombang sinus menggunakan pemrosesan sinyal digital (DSP) primitif di FPGA, cara yang lebih mudah adalah menyimpan titik sampel dalam blok RAM. Alih-alih menghitung nilai selama run-time, kami menghitung serangkaian nilai sinus selama sintesis dan membuat memori hanya-baca (ROM) untuk menyimpannya.

Perhatikan contoh minimal di bawah ini, yang menunjukkan cara menyimpan gelombang sinus penuh dalam ROM 3x3 bit. Baik input alamat dan output data memiliki lebar tiga bit, artinya keduanya dapat mewakili nilai integer pada rentang dari 0 hingga 7. Kita dapat menyimpan delapan nilai sinus dalam ROM, dan resolusi data juga 0 hingga 7. .

Fungsi sinus trigonometri menghasilkan angka pada rentang [-1, 1] untuk input sudut apa pun, x . Juga, siklus berulang ketika x 2π. Oleh karena itu, cukup untuk menyimpan hanya nilai sinus dari nol dan hingga, tetapi tidak termasuk 2π. Nilai sinus untuk 2π sama dengan sinus untuk nol. Ilustrasi di atas menunjukkan konsep ini. Kami menyimpan nilai sinus dari nol hingga \frac{7\pi}{4}, yang merupakan langkah spasi terakhir sebelum lingkaran 2π penuh.

Logika digital tidak dapat mewakili nilai nyata, seperti nilai sudut atau sinus, dengan presisi tak terbatas. Itulah yang terjadi di sistem komputer mana pun. Bahkan saat menggunakan angka floating-point presisi ganda, itu hanya perkiraan. Begitulah cara kerja bilangan biner, dan ROM sinus kita tidak berbeda.

Untuk mendapatkan hasil maksimal dari bit data yang tersedia, kami menambahkan offset dan skala ke nilai sinus saat kami menghitung konten ROM. Nilai sinus terendah yang mungkin dari -1 dipetakan ke nilai data 0, sedangkan nilai sinus tertinggi yang mungkin dari 1 diterjemahkan menjadi 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 menerjemahkan 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 sudut universal untuk konverter nilai sinus. 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 bilangan bulat tidak bertanda sudah cukup baik. Dan seperti yang akan kita lihat di bagian berikutnya, itulah yang kita butuhkan untuk contoh proyek LED berdenyut.

Modul ROM sinus

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

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

Entitas

Kode di bawah ini menunjukkan entitas modul ROM sinus. Ini berisi dua input umum yang memungkinkan Anda menentukan lebar dan kedalaman blok RAM yang disimpulkan. Saya menggunakan penentu rentang pada konstanta untuk mencegah luapan bilangan bulat yang tidak disengaja. Lebih lanjut tentang itu nanti di 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 RAM primitif tidak dapat direset. addr input adalah tempat kami menetapkan sudut skala (x ) nilai, dan data output adalah tempat nilai sinus yang diskalakan akan muncul.

Ketik deklarasi

Di bagian atas wilayah deklaratif file VHDL, kami mendeklarasikan tipe dan subtipe untuk objek penyimpanan ROM kami. addr_range subtipe adalah rentang bilangan bulat yang sama dengan jumlah slot di RAM kita, dan rom_type menjelaskan larik 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, kami belum akan mendeklarasikan sinyal penyimpanan. 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 tersebut untuk menetapkan nilai awal ke sinyal penyimpanan ROM.

Perhatikan bahwa kami menggunakan addr_bits generik sebagai dasar untuk mendefinisikan addr_range . Itulah alasan mengapa saya harus menentukan nilai maksimal 30 untuk addr_bits . Karena untuk nilai yang lebih besar, 2**addr_bits - 1 perhitungan akan meluap. Bilangan bulat VHDL panjangnya 32-bit, meskipun itu akan berubah dengan VHDL-2019, yang menggunakan bilangan bulat 64-bit. Namun untuk saat ini, kita harus hidup dengan batasan ini saat menggunakan bilangan bulat di VHDL hingga alat mulai mendukung VHDL-2019.

Fungsi untuk menghasilkan nilai sinus

Kode di bawah ini menunjukkan init_rom fungsi yang menghasilkan nilai sinus. Ini mengembalikan rom_type objek, itulah sebabnya kita harus mendeklarasikan tipenya terlebih dahulu, lalu fungsinya, dan terakhir, konstanta ROM. Mereka bergantung satu sama lain dalam urutan yang tepat.

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, kami menggunakan for-loop untuk mengulangi rentang alamat, dan untuk setiap slot ROM, kami menghitung nilai sinus menggunakan rumus yang saya jelaskan sebelumnya. Dan pada akhirnya, kami mengembalikan rom_v variabel yang sekarang berisi semua sampel sinus.

Konversi integer pada baris terakhir di for-loop adalah alasan mengapa saya harus membatasi data_bits generik untuk 31 bit. Ini akan meluap untuk panjang bit yang lebih besar.

constant rom : rom_type := init_rom;

Di bawah init_rom definisi fungsi, kita lanjutkan untuk mendeklarasikan rom objek sebagai konstanta. ROM hanyalah RAM yang tidak pernah Anda gunakan untuk menulis, jadi itu baik-baik saja. Dan sekarang saatnya menggunakan fungsi kita. Kami memanggil init_rom untuk menghasilkan nilai awal, seperti yang ditunjukkan pada kode di atas.

Proses ROM

Satu-satunya logika dalam file ROM sinus adalah proses yang agak sederhana yang tercantum di bawah ini. Ini menggambarkan RAM blok dengan port baca tunggal.

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

Modul teratas

Desain ini merupakan kelanjutan dari proyek PWM yang saya sajikan di posting blog saya sebelumnya. Ini memiliki modul reset, modul generator PWM, dan modul penghitung siklus jam (penghitung gigi gergaji) yang berjalan bebas. Lihat artikel minggu lalu untuk melihat cara kerja modul ini.

Diagram di bawah menunjukkan hubungan antar submodul di modul atas.

Kode di bawah ini menunjukkan wilayah deklaratif dari file VHDL teratas. Dalam desain PWM minggu lalu, duty_cycle objek adalah alias untuk MSB dari cnt menangkal. Tapi itu tidak akan berhasil sekarang karena output dari ROM sinus akan mengontrol siklus kerja, jadi saya menggantinya dengan sinyal yang sebenarnya. Selain itu, saya telah membuat alias baru dengan nama addr itu adalah MSB penghitung. Kami 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);

-- Use MSBs of counter for sine ROM address input
alias addr is cnt(cnt'high downto cnt'length - pwm_bits);

Anda dapat melihat cara membuat ROM sinus baru kami di modul teratas dalam daftar di bawah ini. Kami mengatur lebar dan kedalaman RAM untuk mengikuti panjang penghitung internal modul PWM. data output dari ROM mengontrol duty_cycle masukan ke modul PWM. Nilai pada duty_cycle sinyal akan menggambarkan pola gelombang sinus ketika kita membaca slot RAM satu demi satu.

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 ROM gelombang sinus

Gambar di bawah ini menunjukkan bentuk gelombang simulasi modul teratas di ModelSim. Saya telah mengubah presentasi duty_cycle yang tidak ditandatangani sinyal ke format analog sehingga kita dapat mengamati gelombang sinus.

Ini adalah led_5 output tingkat atas yang membawa sinyal PWM, yang mengontrol LED eksternal. Kita dapat melihat bahwa output berubah dengan cepat ketika siklus tugas naik atau turun. Tetapi ketika siklus kerja berada di puncak gelombang sinus, led_5 adalah '1' yang stabil. Saat gelombang berada di bagian bawah lereng, output tetap sebentar di '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!

Menerapkan pernapasan LED pada 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 disertakan dengan iCEcube2. Hal ini menunjukkan bahwa desain menggunakan satu blok RAM primitif. Itu ROM sinus 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 merutekan desain di iCEcube2, Anda akan menemukan .bin file di led_breathing_Implmnt\sbt\outputs\bitmap folder di dalam Lattice_iCEcube2_proj direktori proyek.

Anda dapat menggunakan perangkat lunak Standalone Lattice Diamond Programmer untuk memprogram FPGA, seperti yang ditunjukkan dalam panduan 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 "bernafas" jika Anda memasukkan imajinasi ke dalamnya.

Pemikiran terakhir

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

Alasan pertama yang terlintas dalam 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 bukan hanya itu.

Untuk setiap bit yang Anda gunakan untuk memperpanjang alamat ROM, Anda menggandakan penggunaan RAM. Jika Anda membutuhkan presisi tinggi pada sumbu X, mungkin tidak ada 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 saat Anda meningkatkan presisi Y.

Secara teori, kita hanya perlu menyimpan satu kuadran gelombang sinus. Oleh karena itu, Anda dapat menggunakan seperempat dari penggunaan RAM jika Anda menggunakan mesin finite-state (FSM) untuk mengontrol pembacaan ROM. Itu harus membalikkan kuadran sinus untuk keempat permutasi sumbu X dan Y. Kemudian, Anda dapat membangun gelombang sinus penuh dari kuadran tunggal yang disimpan dalam RAM blok.

Sayangnya, sulit untuk menyatukan keempat segmen dengan lancar. Dua sampel yang sama pada sambungan di bagian atas dan bawah gelombang sinus mendistorsi data dengan membuat titik datar pada gelombang sinus. Memperkenalkan noise mengalahkan tujuan penyimpanan hanya kuadran untuk meningkatkan presisi gelombang sinus.


VHDL

  1. Cara Membuat Template CloudFormation Menggunakan AWS
  2. Cara Membuat UX Tanpa Gesekan
  3. Cara membuat daftar string di VHDL
  4. Cara membuat testbench berbasis Tcl untuk modul kunci kode VHDL
  5. Cara menginisialisasi RAM dari file menggunakan TEXTIO
  6. Cara membuat testbench pemeriksaan mandiri
  7. Cara membuat Daftar Tertaut di VHDL
  8. Cara Membuat Array Objek di Java
  9. Bagaimana Profesional Medis Menggunakan Manufaktur Digital untuk Membuat Model Anatomi Generasi Berikutnya
  10. Cara memanggil Blok Fungsi dari Klien OPC UA menggunakan Model Informasi