Menggunakan Alat Konfigurasi Datapath



Kita harus mengambil langkah kedua dari belakang dalam pengembangan praktis bekerja dengan UDB. Hari ini kita tidak akan mengembangkan menggunakan Editor UDB otomatis, tetapi dalam mode semi-manual menggunakan Datapath Config Tool. Bantuan yang sangat baik dalam menguasai alat ini adalah AN82156 - PSoC 3, PSoC 4, dan PSoC 5LP - Merancang Komponen Pencipta PSoC dengan Datapaths UDB. Sebenarnya, saya mempelajarinya sendiri.

Mungkin, saat membaca terjemahan dokumentasi kami tentang UDB , seseorang mencoba mereproduksi pengetahuan dari sana menjadi praktik dan memperhatikan bahwa tidak semua fungsi yang dijelaskan dalam publikasi tersedia di Editor UDB. Ini disebabkan oleh fakta bahwa pengembang tidak mulai menempatkan beberapa mekanisme yang sangat rumit di Editor UDB. Para penulis AN82156 berpendapat bahwa melalui Editor UDB Anda tidak dapat melakukan hal-hal berikut:

  • mengatur input dan output data paralel;
  • mengatur manajemen FIFO yang dinamis;
  • menerapkan kebalikan dari sinyal jam FIFO;
  • mengimplementasikan fungsi CRC;
  • mengimplementasikan fungsi PRS;
  • menerapkan pilihan transfer masuk;
  • menerapkan migrasi masuk dinamis.

Dari saya sendiri, saya akan menambahkan bahwa saya tidak menemukan cara menerapkan permutasi camilan di Editor UDB.

Jika fungsi-fungsi ini diperlukan dalam proyek, Anda harus membuat kode Verilog Anda sendiri. Saya secara khusus menggunakan kata "buat" daripada "tulis." Mengetahui bahasa pemrograman ini sudah cukup di tingkat membaca. Maksud saya, Anda perlu memahami desain apa yang dibutuhkan untuk apa. Dan untuk dapat menulis dari awal selalu berguna, tetapi keterampilan ini tidak diperlukan untuk apa yang disajikan dalam artikel ini.

Sebagai masalah yang dapat dipecahkan, saya memilih kasing semi sintetis. Secara umum, saya memutuskan untuk menampilkan beberapa data ke port paralel, dan khususnya, dari apa yang ada, teks LCD memiliki port paralel. Saya mengeluarkannya dari printer 3D MZ3D tiga tahun lalu ketika saya memindahkan yang terakhir ke STM32. Oleh karena itu, kasing semi-sintetik: saat ini, indikator tersebut biasanya memiliki input I2C, dan mereka tidak perlu terhubung melalui tumpukan kabel di kehidupan nyata. Namun, LCD modern juga memiliki port paralel, sehingga semua orang dapat menggunakannya untuk mengulangi percobaan.

Pertimbangkan skema alih tampilan yang diambil dari reprap.org (ini tidak mudah, penyedia saya memblokir situs ini, serta sejumlah teknis lainnya, memotivasi dengan fakta bahwa ia hidup pada IP yang sama dengan seseorang diblokir).



Tata letak yang bagus! Pertama, saya tidak perlu berpikir tentang membaca: data dalam LCD hanya dapat ditulis (garis R / W di-ground dan tidak tersedia pada konektor). Kedua, data datang dalam format 4-bit, yang berarti bahwa kita tidak hanya dapat bekerja pada output paralel, tetapi juga memeriksa operasi fungsi permutasi menggigit.

Pembuatan proyek


Jadi, luncurkan PSoC Creator dan pilih File-> New-> Project :



Selanjutnya, saya memilih papan tempat memotong roti saya:



Berikutnya adalah diagram kosong:



Saya akan memanggil proyek LCDTest2 :



Sekarang, seperti sebelumnya, buka tab Komponen :



Dan, setelah memilih proyek, tekan tombol mouse kanan, lalu pilih Tambahkan Komponen .



Dan di sini Anda harus memilih Wisaya Simbol . Beri nama ... Baiklah, katakanlah LCD4bit .



Saya menetapkan port berikut ke simbol:



CLK adalah input jam. Port dengan awalan LCD adalah port LCD standar. lapar - output memberitahu unit DMA bahwa ada ruang kosong di FIFO, ide itu dibahas dalam artikel tentang cara mengendalikan LED RGB . Klik OK untuk mendapatkan karakter.



Sekarang, berdasarkan simbol ini, templat Verilog harus dibuat. Klik tombol kanan mouse di sekitar simbol dan pilih Generate Verilog di menu konteks.



Kami mendapat templat yang ditunjukkan pada gambar di bawah ini (dalam bentuk teks belum masuk akal):



Kami telah membuat modul dan beberapa bagian. Tetapi mereka belum menciptakan Datapath. Untuk menambahkannya, pergi ke pohon proyek, pilih file LCD4bit.v , tekan tombol kanan mouse dan pilih Datapath Config Tool di menu konteks yang muncul:



Sebuah jendela terbuka di hadapan kami, yang untuk saat ini saya hanya akan menampilkan sebagian:



Tolong cintai dan nikmatilah, editor Datapath. Ini berisi semua bit yang dijelaskan dalam terjemahan dokumentasi hak milik. Tetapi ada begitu banyak bagian ini sehingga pada hari-hari awal saya memandangnya, tetapi takut untuk melakukan apa pun. Lihat, lihat dan pergi. Dan hanya setelah beberapa waktu, setelah terbiasa, ia mulai mencoba melakukan sesuatu. Sebenarnya, itu sebabnya saya hanya membawa sebagian jendela. Mengapa menakuti semua orang sebelumnya? Sementara itu, kita hanya perlu membuat Datapath, jadi kita pilih item menu Edit-> Datapath Baru :



Opsi mana yang harus dipilih dalam dialog yang muncul?



Pertanyaannya sedikit lebih serius daripada kelihatannya. Izinkan saya menyoroti paragraf berikutnya sehingga tidak ada yang tertangkap (saya menangkap diri saya sendiri, dan kemudian saya melihat pertanyaan di jaringan dari yang saya dapatkan, dan tidak ada yang benar-benar menjawabnya, dan jawabannya ada di AN82156 , Anda hanya perlu membacanya secara diagonal, seperti yang tertulis di sana. frasa singkat yang tidak mencolok).
Jika Anda berencana untuk bekerja dengan data paralel, Anda harus memilih opsi CY_PSOC3_DP. Tidak ada opsi lain yang akan berisi port untuk menghubungkan data paralel.
Jadi Biarkan instance disebut LCD_DP:



Klik OK dan tutup Alat Konfigurasi Datapath untuk saat ini , setuju untuk menyimpan hasilnya. Kami akan kembali ke sini nanti.

Kode Verilog kami telah diperluas. Sekarang memiliki Datapath. Permulaannya benar-benar tidak dapat dibaca. Itu tidak menakutkan, itu dikonfigurasikan oleh Datapath Config Tool .



Dan kita akan menentukan akhir dari deskripsi Datapath. Situs kami terlihat seperti ini
(dari titik ini masuk akal untuk membawa semuanya dalam bentuk teks).
)) LCD_DP( /* input */ .reset(1'b0), /* input */ .clk(1'b0), /* input [02:00] */ .cs_addr(3'b0), /* input */ .route_si(1'b0), /* input */ .route_ci(1'b0), /* input */ .f0_load(1'b0), /* input */ .f1_load(1'b0), /* input */ .d0_load(1'b0), /* input */ .d1_load(1'b0), /* output */ .ce0(), /* output */ .cl0(), /* output */ .z0(), /* output */ .ff0(), /* output */ .ce1(), /* output */ .cl1(), /* output */ .z1(), /* output */ .ff1(), /* output */ .ov_msb(), /* output */ .co_msb(), /* output */ .cmsb(), /* output */ .so(), /* output */ .f0_bus_stat(), /* output */ .f0_blk_stat(), /* output */ .f1_bus_stat(), /* output */ .f1_blk_stat(), /* input */ .ci(1'b0), // Carry in from previous stage /* output */ .co(), // Carry out to next stage /* input */ .sir(1'b0), // Shift in from right side /* output */ .sor(), // Shift out to right side /* input */ .sil(1'b0), // Shift in from left side /* output */ .sol(), // Shift out to left side /* input */ .msbi(1'b0), // MSB chain in /* output */ .msbo(), // MSB chain out /* input [01:00] */ .cei(2'b0), // Compare equal in from prev stage /* output [01:00] */ .ceo(), // Compare equal out to next stage /* input [01:00] */ .cli(2'b0), // Compare less than in from prv stage /* output [01:00] */ .clo(), // Compare less than out to next stage /* input [01:00] */ .zi(2'b0), // Zero detect in from previous stage /* output [01:00] */ .zo(), // Zero detect out to next stage /* input [01:00] */ .fi(2'b0), // 0xFF detect in from previous stage /* output [01:00] */ .fo(), // 0xFF detect out to next stage /* input [01:00] */ .capi(2'b0), // Software capture from previous stage /* output [01:00] */ .capo(), // Software capture to next stage /* input */ .cfbi(1'b0), // CRC Feedback in from previous stage /* output */ .cfbo(), // CRC Feedback out to next stage /* input [07:00] */ .pi(8'b0), // Parallel data port /* output [07:00] */ .po() // Parallel data port ); 


Menakutkan Sekarang kita akan mencari tahu apa itu - itu akan berhenti menakutkan. Sebenarnya, ada tiga kelompok berbeda dalam teks ini. Mari kita ingat terjemahan dokumentasinya. Seperti apa datapath dalam gambar? Saya akan segera mencatat pada gambar tempat kelompok "1", "2" dan "3" berada.



Sebenarnya, kelompok port pertama dalam kode Verilog adalah input. Bandingkan nama-nama pada output multiplexer input ("1" pada gambar) dan nama-nama sinyal dalam kode.

Sekarang semua input nol. Kami harus menghubungkan input jam dan kami dapat meneruskan hingga enam jalur input, seperti yang dilakukan di Editor UDB. Input-input ini adalah:

  /* input */ .reset(1'b0), /* input */ .clk(1'b0), /* input [02:00] */ .cs_addr(3'b0), /* input */ .route_si(1'b0), /* input */ .route_ci(1'b0), /* input */ .f0_load(1'b0), /* input */ .f1_load(1'b0), /* input */ .d0_load(1'b0), /* input */ .d1_load(1'b0), 

Kelompok kedua adalah pintu keluar. Nama-nama dalam kode juga bertepatan dengan nama-nama input dari multiplexer output "2":

  /* output */ .ce0(), /* output */ .cl0(), /* output */ .z0(), /* output */ .ff0(), /* output */ .ce1(), /* output */ .cl1(), /* output */ .z1(), /* output */ .ff1(), /* output */ .ov_msb(), /* output */ .co_msb(), /* output */ .cmsb(), /* output */ .so(), /* output */ .f0_bus_stat(), /* output */ .f0_blk_stat(), /* output */ .f1_bus_stat(), /* output */ .f1_blk_stat(), 

Hanya spesies Datapath yang diberikan memiliki kelompok ketiga (yang lain tidak memiliki, oleh karena itu, tidak ada data paralel). Ini adalah sinyal internal Datapath yang melaluinya Anda dapat secara independen menyatukan atau melakukan tindakan bermanfaat lainnya. Nama-nama dalam kode juga bertepatan dengan nama-nama sinyal internal yang tersebar dalam gambar. Kami melalui salah satu dari mereka (yang terakhir dalam daftar, namanya po ) akan menampilkan data paralel langsung ke kaki chip.

  /* input */ .ci(1'b0), // Carry in from previous stage /* output */ .co(), // Carry out to next stage /* input */ .sir(1'b0), // Shift in from right side /* output */ .sor(), // Shift out to right side /* input */ .sil(1'b0), // Shift in from left side /* output */ .sol(), // Shift out to left side /* input */ .msbi(1'b0), // MSB chain in /* output */ .msbo(), // MSB chain out /* input [01:00] */ .cei(2'b0), // Compare equal in from prev stage /* output [01:00] */ .ceo(), // Compare equal out to next stage /* input [01:00] */ .cli(2'b0), // Compare less than in from prv stage /* output [01:00] */ .clo(), // Compare less than out to next stage /* input [01:00] */ .zi(2'b0), // Zero detect in from previous stage /* output [01:00] */ .zo(), // Zero detect out to next stage /* input [01:00] */ .fi(2'b0), // 0xFF detect in from previous stage /* output [01:00] */ .fo(), // 0xFF detect out to next stage /* input [01:00] */ .capi(2'b0), // Software capture from previous stage /* output [01:00] */ .capo(), // Software capture to next stage /* input */ .cfbi(1'b0), // CRC Feedback in from previous stage /* output */ .cfbo(), // CRC Feedback out to next stage /* input [07:00] */ .pi(8'b0), // Parallel data port /* output [07:00] */ .po() // Parallel data port ); 

Jadi Saat kita bekerja, kita harus menghubungkan beberapa input dan output ini ke entitas kita sendiri, dan sisanya - biarkan saja dalam bentuk di mana kita membuatnya.

Menggunakan Editor UDB sebagai referensi


Dan sekarang kita memiliki blank, kita tahu di mana dan apa yang harus kita tulis. Masih memahami apa yang akan kita masukkan di sana. Kebetulan saya menggunakan bahasa Verilog tidak setiap hari, jadi secara umum saya mengingat semuanya, dan menulis dari awal bagi saya selalu merupakan situasi yang penuh tekanan. Ketika proyek sudah berjalan, itu semua diingat, tetapi jika setelah beberapa bulan tidak aktif saya memulai sesuatu dari awal, tentu saja, saya tidak lagi ingat rincian sintaks dari bahasa khusus ini. Oleh karena itu, saya sarankan meminta lingkungan pengembangan untuk membantu kami.

Editor UDB untuk swa-monitor membangun kode Verilog. Kami mengambil keuntungan dari fakta bahwa komponen yang tidak terlibat dalam sirkuit utama tidak dikompilasi, sehingga kami dapat membuat komponen tambahan di Editor UDB, dan itu tidak akan masuk ke dalam kode output. Kami akan menggambar otomat di sana, kami akan melakukan penyesuaian kasar input dan output Datapath, dan kemudian cukup mentransfer teks yang dihasilkan secara otomatis ke modul Verilog kami dan memodifikasi semuanya secara kreatif. Ini jauh lebih sederhana daripada mengingat detail sintaksis Verilog dan menulis semuanya dari awal (walaupun siapa pun yang menggunakan Verilog terus-menerus, tentu saja, akan lebih mudah untuk menulis dari awal: penyelesaian kreatif, seperti yang akan kita lihat segera, sederhana, tetapi membutuhkan waktu).

Jadi, kami mulai membuat komponen tambahan. Dengan gerakan tangan yang biasa kami tambahkan elemen baru ke proyek:



Ini akan menjadi dokumen UDB, sebut saja UDBhelper :



Sudah waktunya untuk memikirkan mesin, yang akan kita tempatkan pada lembar yang dibuat. Untuk melakukan ini, kita perlu mempertimbangkan diagram waktu apa yang harus kita bentuk dengannya:





Jadi Pertama, Anda perlu mengatur sinyal RS (karena R / W disolder ke nol pada perangkat keras). Selanjutnya, tunggu tAS, lalu naikkan sinyal E dan atur data (pengaturan data berkenaan dengan tepi positif E tidak terbatas). Data harus berada di bus tidak kurang dari tDSW, setelah itu sinyal E harus dijatuhkan. Data harus tetap di bus setidaknya untuk tDHW, dan RS untuk setidaknya tAH.

RS adalah perintah atau flag data. Jika RS nol, maka perintah ditulis, jika itu satu, data ditulis.

Saya sarankan mengirim perintah melalui FIFO0 , dan data melalui FIFO1 . Dalam kerangka tugas saat ini, ini tidak bertentangan dengan apa pun. Maka mesin keadaan terbatas yang saya usulkan akan memiliki bentuk berikut:



Dalam kondisi Idle , mesin masih tidak memiliki data FIFO. Jika data muncul di FIFO0 , ia pergi ke LoadF0 , di mana di masa depan ia akan menerima data dari FIFO0 ke A0.

Ketika perintah sedang dikirim, data tidak boleh dikirim. Oleh karena itu, kondisi untuk menerima data akan lebih rendah dalam prioritas daripada kondisi untuk menerima perintah.



Data diterima dalam A1 di negara LoadF1 (dari FIFO1 mereka hanya bisa pergi untuk mendaftar A1 dan tidak bisa mendaftar A0), dan kemudian mereka disalin dari A1 ke A0 di negara A1toA0 .

Apa pun cara kita menuju titik konvergensi panah, kita memiliki data dalam A0. Mereka sudah output ke port paralel. Kami memiringkan E (dalam keadaan E_UP1 ), menjatuhkan E (dalam keadaan E_DOWN1 ). Selanjutnya, kita akan memiliki status untuk swapping nibbles ( SWAP ), setelah itu E naik lagi ( E_UP2 ). Tentang ini, saya telah kehabisan delapan negara yang dapat dikodekan dalam tiga bit. Dan kita ingat bahwa konfigurasi dinamis Datapath RAM hanya memiliki tiga input alamat. Beberapa trik bisa diterapkan, tetapi artikelnya sudah besar. Oleh karena itu, hanya kedua kalinya kami akan menjatuhkan E dalam kondisi Idle . Maka delapan negara bagian sudah cukup bagi kita.

Kami juga menempatkan Datapath pada lembar dan menetapkan input dan output dengan cara yang akrab di artikel sebelumnya. Berikut inputnya:



Berikut ini hasilnya:



Tidak ada yang baru, semuanya sudah dijelaskan dalam artikel siklus sebelumnya. Jadi, kita punya tempat kosong, atas dasar itu kita bisa melakukan sesuatu sendiri. Benar, untuk memastikan semuanya berjalan, kita perlu membawa sistem kita ke tingkat atas proyek, jika tidak, tidak ada kesalahan akan ditemukan. Dan dalam percobaan awal tanpa kesalahan tidak akan berhasil. Karena itu, kami akan membuat satu tindakan tambahan lagi.

Deskripsi tentang bagaimana sirkuit dibuat melampaui deskripsi bekerja dengan UDB. Saya hanya akan menunjukkan kepada Anda sirkuit mana yang saya dapatkan. Hanya ada satu unit DMA: saat mengirim perintah ke LCD, perlu untuk menahan jeda besar, sehingga masih lebih mudah untuk melakukan ini secara terprogram. Untuk aplikasi lain, Anda cukup meletakkan blok DMA kedua dengan analogi menggunakan sinyal lapar0 .



Untuk secara akurat memenuhi kerangka waktu, saya memilih frekuensi clock yang sama dengan satu megahertz. Akan mungkin untuk mengambil frekuensi dan lebih tinggi, tetapi data ditransmisikan melalui kabel panjang dalam kondisi gangguan tinggi, sehingga lebih baik meluangkan waktu untuk mengatur data sebelum dan sesudah gerbang dengan margin. Jika seseorang akan mengulangi percobaan saya di papan tempat memotong roti yang sama - jangan gunakan port P3.2: kapasitor disolder ke kaki ini di papan. Saya membunuh selama setengah jam, sampai saya menemukan mengapa saya tidak membentuk impuls E, yang pertama kali saya hubungkan di sana. Saya melemparkannya ke P3.1 - semuanya langsung bekerja. Bus data saya pergi ke P3.7-P3.4, RS pergi ke P3.3, jadi E awalnya pergi ke P3.2 ...

Baik di sini. Sekarang, jika Anda mencoba mengkompilasi proyek, kami mendapatkan kesalahan yang dapat diprediksi sepenuhnya



Jadi sistem mencoba mengumpulkan sesuatu. Tapi dia masih belum mengumpulkan apa pun. Kami melanjutkan untuk menyalin kode. Untuk melakukan ini, di Editor UDB, beralih ke tab Verilog (tab ini terletak di bawah jendela dengan lembar Editor UDB):



Apa yang akrab di sana? Di bagian paling akhir teks adalah badan otomat. Mari kita mulai migrasi dari sana.

Juga tempatkan di bawah Datapath:
 /* ==================== State Machine: SM ==================== */ always @ (posedge clock) begin : Idle_state_logic case(SM) Idle : begin if (( !F0empty ) == 1'b1) begin SM <= LoadF0 ; end else if (( !F1empty ) == 1'b1) begin SM <= LoadF1 ; end end LoadF0 : begin if (( 1'b1 ) == 1'b1) begin SM <= E_Up1 ; end end E_Up1 : begin if (( 1'b1 ) == 1'b1) begin SM <= E_Down1 ; end end E_Down1 : begin if (( 1'b1 ) == 1'b1) begin SM <= SWAP ; end end SWAP : begin if (( 1'b1 ) == 1'b1) begin SM <= E_UP2 ; end end E_UP2 : begin if (( 1'b1 ) == 1'b1) begin SM <= Idle ; end end LoadF1 : begin if (( 1'b1 ) == 1'b1) begin SM <= A1toA0 ; end end A1toA0 : begin if (( 1'b1 ) == 1'b1) begin SM <= E_Up1 ; end end default : begin SM <= Idle; end endcase end 


Ada deklarasi di bagian atas untuk kode ini (nama untuk negara, rantai untuk Datapath, register yang mengkode keadaan otomat). Kami mentransfernya ke yang sesuai
bagian dari kode kami:
 /* ==================== Wire and Register Declarations ==================== */ localparam [2:0] Idle = 3'b000; localparam [2:0] LoadF0 = 3'b001; localparam [2:0] LoadF1 = 3'b010; localparam [2:0] E_Up1 = 3'b100; localparam [2:0] A1toA0 = 3'b011; localparam [2:0] E_Down1 = 3'b101; localparam [2:0] SWAP = 3'b110; localparam [2:0] E_UP2 = 3'b111; wire hungry0; wire F0empty; wire hungry1; wire F1empty; wire Datapath_1_d0_load; wire Datapath_1_d1_load; wire Datapath_1_f0_load; wire Datapath_1_f1_load; wire Datapath_1_route_si; wire Datapath_1_route_ci; wire [2:0] Datapath_1_select; reg [2:0] SM; 


Baik, dan

situs pengikatan sinyal dapat ditransfer:
 /* ==================== Assignment of Combinatorial Variables ==================== */ assign Datapath_1_d0_load = (1'b0); assign Datapath_1_d1_load = (1'b0); assign Datapath_1_f0_load = (1'b0); assign Datapath_1_f1_load = (1'b0); assign Datapath_1_route_si = (1'b0); assign Datapath_1_route_ci = (1'b0); assign Datapath_1_select[0] = (SM[0]); assign Datapath_1_select[1] = (SM[1]); assign Datapath_1_select[2] = (SM[2]); 


Sudah waktunya untuk menyambungkan Datapath. Kode yang diangkut dari Editor UDB baik untuk pengeditan mesin, tetapi tidak terlalu baik untuk pengeditan manual. Di sana, rantai dibuat yang terhubung ke input Datapath di satu ujung dan ke konstanta di sisi lain. Tetapi dalam kode yang dibuat oleh Alat Konfigurasi Datapath (yang melakukan segalanya untuk pekerjaan manual), semua input sudah langsung terhubung ke konstanta nol. Jadi saya akan menghubungkan hanya garis-garis yang bukan konstanta, tetapi saya akan memotong semua yang terkait dengan penerusan konstanta dari teks yang ditransfer. Koneksi berubah menjadi seperti ini (warnanya menyoroti tempat-tempat yang saya sunting sehubungan dengan yang secara otomatis dibuat di Alat Konfigurasi Datapath):



Teks yang sama:
 )) LCD_DP( /* input */ .reset(1'b0), /* input */ .clk(clk), /* input [02:00] */ .cs_addr(SM), /* input */ .route_si(1'b0), /* input */ .route_ci(1'b0), /* input */ .f0_load(1'b0), /* input */ .f1_load(1'b0), /* input */ .d0_load(1'b0), /* input */ .d1_load(1'b0), /* output */ .ce0(), /* output */ .cl0(), /* output */ .z0(), /* output */ .ff0(), /* output */ .ce1(), /* output */ .cl1(), /* output */ .z1(), /* output */ .ff1(), /* output */ .ov_msb(), /* output */ .co_msb(), /* output */ .cmsb(), /* output */ .so(), /* output */ .f0_bus_stat(hungry0), /* output */ .f0_blk_stat(F0empty), /* output */ .f1_bus_stat(hungry1), /* output */ .f1_blk_stat(F1empty), 


Data paralel sedikit lebih rumit. Datapath memiliki port delapan-bit, dan hanya empat di antaranya yang perlu dibawa keluar. Oleh karena itu, kami memulai sirkuit bantu dan menghubungkan hanya setengahnya ke output:

 wire [7:0] tempBus; assign LCD_D = tempBus[7:4]; 

Dan hubungkan seperti ini:



Teks yang sama:
  /* input [07:00] */ .pi(8'b0), // Parallel data port /* output [07:00] */ .po( tempBus) // Parallel data port ); 


Kami mencoba merakit (Shift + F6 atau melalui item menu Build-> Generate Application ). Kami mendapatkan kesalahan:



Kami memiliki port lapar0 dan lapar1 (muncul saat membuat komponen), serta rantai dengan nama yang sama (muncul saat menyeret dari sampel). Hapus saja rantai ini (meninggalkan port). Dan di suatu tempat sinyal jam bocor, dan kami memiliki sirkuit ini disebut CLK .

Setelah menghapus semua sirkuit yang tidak perlu (yang awalnya melemparkan nol konstanta ke input Datapath, serta lapar0 dan lapar1 ), kami mendapatkan kode berikut untuk awal file kami:

 // Your code goes here /* ==================== Wire and Register Declarations ==================== */ localparam [2:0] Idle = 3'b000; localparam [2:0] LoadF0 = 3'b001; localparam [2:0] LoadF1 = 3'b010; localparam [2:0] E_Up1 = 3'b100; localparam [2:0] A1toA0 = 3'b011; localparam [2:0] E_Down1 = 3'b101; localparam [2:0] SWAP = 3'b110; localparam [2:0] E_UP2 = 3'b111; wire F0empty; wire F1empty; reg [2:0] SM; /* ==================== Assignment of Combinatorial Variables ==================== */ wire [7:0] tempBus; assign LCD_D = tempBus[7:4]; 

Dan ketika mengganti jam dengan clk di tubuh mesin, pada saat yang sama saya akan membuang semua baris yang bagus untuk pembuatan otomatis, tetapi dengan pengeditan manual hanya membuat kebingungan (semua perbandingan yang memberikan hasil tanpa syarat BENAR dan sebagainya). Secara khusus, dalam contoh di bawah ini, Anda dapat mencoret sekitar setengah dari garis (dan beberapa mulai / akhir adalah opsional, kadang-kadang akan diperlukan, karena kami akan menambahkan tindakan, saya menyoroti mereka):



Setelah menyisir sesuai dengan prinsip di atas (dan mengganti jam dengan clk ), tubuh seperti itu tetap ada

(menjadi lebih pendek, yang berarti lebih mudah dibaca):
 always @ (posedge clk) begin : Idle_state_logic case(SM) Idle : begin if (( !F0empty ) == 1'b1) begin SM <= LoadF0 ; end else if (( !F1empty ) == 1'b1) begin SM <= LoadF1 ; end end LoadF0 : begin SM <= E_Up1 ; end E_Up1 : begin SM <= E_Down1 ; end E_Down1 : begin SM <= SWAP ; end SWAP : begin SM <= E_UP2 ; end E_UP2 : begin SM <= Idle ; end LoadF1 : begin SM <= A1toA0 ; end A1toA0 : begin SM <= E_Up1 ; end default : begin SM <= Idle; end endcase end 


Sekarang, selama kompilasi, kita diberitahu bahwa sirkuit LCD_E dan LCD_RS tidak terhubung.

Sebenarnya ini benar:



Waktunya telah tiba untuk menambahkan tindakan ke mesin negara. Kami akan mengganti deklarasi port yang terkait dengan rantai tidak terhubung dengan reg , karena kami akan menuliskannya di badan mesin (ini adalah sintaks dari bahasa Verilog, jika kami menulis, data harus klik, untuk ini kami memerlukan pemicu, dan diberikan oleh reg kata kunci):


Teks yang sama:
 module LCD4bit ( output hungry0, output hungry1, output [3:0] LCD_D, output reg LCD_E, output reg LCD_RS, input clk ); 


Dan isi mesin dengan tindakan. Saya sudah mengatakan logika di atas ketika saya sedang mempertimbangkan grafik transisi automaton, jadi saya hanya akan menunjukkan hasilnya:


Teks yang sama:
 always @ (posedge clk) begin : Idle_state_logic case(SM) Idle : begin LCD_E <= 0; if (( !F0empty ) == 1'b1) begin SM <= LoadF0 ; LCD_RS <= 0; end else if (( !F1empty ) == 1'b1) begin SM <= LoadF1 ; LCD_RS <= 1; end end LoadF0 : begin SM <= E_Up1 ; end E_Up1 : begin SM <= E_Down1 ; LCD_E <= 1'b1; end E_Down1 : begin SM <= SWAP ; LCD_E <= 1'b0; end SWAP : begin SM <= E_UP2 ; end E_UP2 : begin SM <= Idle ; LCD_E <= 1; end LoadF1 : begin SM <= A1toA0 ; end A1toA0 : begin SM <= E_Up1 ; end default : begin SM <= Idle; end endcase end 


Mulai saat ini, proyek mulai berkumpul. Tapi dia belum akan bekerja. Sejauh ini saya terkenal mengatakan: "Dalam keadaan ini, kami akan memuat register dari FIFO", "Dalam hal ini, A1 akan disalin ke A0", "Nibbles akan diatur ulang dalam hal ini". Secara umum, saya banyak berbicara, tetapi sejauh ini belum ada tindakan. Waktunya telah tiba untuk memenuhi mereka. Kami melihat bagaimana negara dikodekan:

 localparam [2:0] Idle = 3'b000; localparam [2:0] LoadF0 = 3'b001; localparam [2:0] LoadF1 = 3'b010; localparam [2:0] E_Up1 = 3'b100; localparam [2:0] A1toA0 = 3'b011; localparam [2:0] E_Down1 = 3'b101; localparam [2:0] SWAP = 3'b110; localparam [2:0] E_UP2 = 3'b111; 

Buka kembali Alat Konfigurasi Datapath :



Dan mulai mengedit garis CFGRAM . Saat mengedit, Anda harus mengingat skema Datapath, yaitu:



Bingkai merah pada gambar di bawah ini (dan panah pada gambar di atas) Saya menyoroti area yang diperbaiki (dan jalur data) untuk keadaan LoadF0 (kode 001, yaitu, Reg1 ). Saya juga memasukkan komentar secara manual. Isi F0 harus masuk ke A0.



Dengan bingkai dan panah hijau, saya menandai pengaturan dan jalur untuk status LoadF1 (kode 010 - Reg2 ).

Dengan bingkai dan panah biru, saya menandai pengaturan dan jalur untuk status A1toA0 (kode 011 - Reg3 ).

Bingkai dan panah ungu saya menandai pengaturan dan jalur untuk keadaan SWAP (kode 110 - Reg6 ).

Akhirnya, panah oranye menunjukkan jalur data paralel. Dan tidak ada tindakan yang diambil untuk mereka. Mereka selalu keluar dari SRCA . Kami hampir selalu memiliki A0 dipilih sebagai SRCA : data keluar dari A0. Jadi, untuk mengarahkan ulang data input, kami harus melakukan banyak tindakan tambahan, tetapi kami tidak menerima data apa pun, jadi di sini kami tidak memerlukan tindakan ini, dan semua orang akan menemukan daftar mereka di AN82156 . Kami juga tidak perlu mengedit pengaturan Datapath statis, jadi tutup Alat Konfigurasi Datapath .

Itu saja. Perangkat keras yang dikonsep selesai. Mulai mengembangkan kode C. Untuk melakukan ini, buka tab Sumber dan edit file main.c.



Inisialisasi LCD reguler dan output karakter "ABC" terlihat seperti ini (saya ingatkan Anda bahwa perintahnya masuk ke FIFO0 , dokumentasi perlu memasukkan jeda antar tim, dan data masuk ke FIFO1 , saya tidak menemukan apa pun tentang jeda di antara data):

  volatile uint8_t* pFIFO0 = (uint8_t*) LCD4bit_1_LCD_DP__F0_REG; volatile uint8_t* pFIFO1 = (uint8_t*) LCD4bit_1_LCD_DP__F1_REG; pFIFO0[0] = 0x33; CyDelay (5); pFIFO0[0] = 0x33; CyDelay (100); pFIFO0[0] = 0x33; CyDelay (5); pFIFO0[0] = 0x20; CyDelay (5); pFIFO0[0] = 0x0C; //   CyDelay (50); pFIFO0[0] = 0x01; //   CyDelay (50); pFIFO1[0] = 'A'; pFIFO1[0] = 'B'; pFIFO1[0] = 'C'; 

Apa itu Mengapa hanya ada karakter pertama di layar?



Dan jika Anda menambahkan penundaan antara output data - semuanya baik-baik saja:



Osiloskop tidak memiliki saluran yang cukup untuk pekerjaan seperti itu. Kami memeriksa pekerjaan pada penganalisis logis. Proses perekaman data adalah sebagai berikut.



Semua data ada di tempat (tiga pasang paket). Waktu untuk pemasangan dan pengambilan data dialokasikan dalam volume yang cukup. Secara umum, dari sudut pandang diagram waktu - semuanya dilakukan dengan benar. Masalah ilmiah terpecahkan, diagram waktu yang diinginkan terbentuk. Ini rekayasa - tidak. Alasannya adalah lambatnya prosesor yang dipasang di LCD. Di antara byte, tambahkan penundaan.

Kami akan membentuk penundaan menggunakan penghitung tujuh-bit, pada saat yang sama kami akan melatih untuk menambahkannya ke sistem seperti itu. Mari kita berada dalam keadaan Idle tidak kurang dari waktu tertentu, dan penghitung tujuh-bit akan mengukur waktu ini untuk kita. Dan lagi, kita tidak akan menulis, tetapi membuat kode. Oleh karena itu, sekali lagi kita pergi ke komponen tambahan Editor UDB dan menambahkan penghitung ke lembar kerja, mengatur parameternya sebagai berikut:



Penghitung ini akan selalu berfungsi ( Enable diatur ke 1). Tapi itu akan memuat ketika mesin berada dalam keadaan E_UP2 (setelah itu kita segera jatuh ke keadaan menganggur ). Baris Count7_1_tc akan dinaikkan menjadi 1 saat penghitung dihitung menjadi nol, yang akan kami buat kondisi tambahan untuk keluar dari kondisi Idle . Angka tersebut juga mengandung nilai periode, tetapi kami tidak akan menemukannya dalam kode Verilog. Itu harus dimasukkan ke dalam kode C. Tetapi pertama-tama, kami mentransfer kode Verilog yang dibuat secara otomatis dengan beralih ke tab Verilog. Pertama-tama, penghitung harus terhubung (kita melihat kode ini di awal file dan memindahkannya ke awal juga):

 `define CY_BLK_DIR "$CYPRESS_DIR\..\psoc\content\CyComponentLibrary\CyComponentLibrary.cylib\Count7_v1_0" `include "$CYPRESS_DIR\..\psoc\content\CyComponentLibrary\CyComponentLibrary.cylib\Count7_v1_0\Count7_v1_0.v" 

Bagaimana penyempurnaan garis dan konstanta yang kreatif dilakukan telah dijelaskan, jadi saya hanya akan menunjukkan hasilnya. Inilah rantai dan tugas yang ditambahkan sebagai hasilnya (sisanya mengatur konstanta, jadi saya membuangnya):

 wire Count7_1_load; wire Count7_1_tc; assign Count7_1_load = (SM==E_UP2); 

Dan di sini adalah penghitung itu sendiri, ditempatkan di akhir file. Semua konstanta ditugaskan ke port secara langsung dalam deklarasi ini:

  Count7_v1_0 Count7_1 ( .en(1'b1), .load(Count7_1_load), .clock(clk), .reset(1'b0), .cnt(), .tc(Count7_1_tc)); defparam Count7_1.EnableSignal = 1; defparam Count7_1.LoadSignal = 1; 

Agar penghitung ini berfungsi, kami secara otomatis menambahkan kondisi tambahan untuk keluar dari status Idle :


Teks yang sama:
  case(SM) Idle : begin LCD_E <= 0; if (( !F0empty ) == 1'b1) begin SM <= LoadF0 ; LCD_RS <= 0; end else if (( !F1empty &Count7_1_tc ) == 1'b1) begin SM <= LoadF1 ; LCD_RS <= 1; end end 


API untuk penghitung yang ditambahkan dengan cara ini tidak dibuat, jadi kami menambahkan dua garis ajaib ke fungsi utama , yang saya bentuk dalam gambar dan rupa dari apa yang saya lihat di API dari proyek sebelumnya (baris pertama menetapkan nilai yang dimuat dari akun, Beban yang sama, yang kedua memulai penghitung):

  *((uint8_t*)LCD4bit_1_Count7_1_Counter7__PERIOD_REG) = 0x20; *((uint8_t*)LCD4bit_1_Count7_1_Counter7__CONTROL_AUX_CTL_REG) |= 0x20; // Start 

Alat analisis menunjukkan bahwa dalam kasus yang dimodifikasi, penundaannya jelas:



LCD juga memiliki ketiga karakter.

Tetapi keluaran karakter terprogram dalam kehidupan nyata tidak dapat diterima. Dengan menambahkannya ke FIFO akan meluap. Tunggu hingga FIFO kosong - ini berarti membuat penundaan besar untuk inti prosesor. 72 , 7-8 1 . DMA. Β« Β». UDB, FIFO DMA. DMA, , .

:
  static const char line[] = "This is a line"; /* Defines for DMA_D */ #define DMA_D_BYTES_PER_BURST 1 #define DMA_D_REQUEST_PER_BURST 1 /* Variable declarations for DMA_D */ /* Move these variable declarations to the top of the function */ uint8 DMA_D_Chan; uint8 DMA_D_TD[1]; /* DMA Configuration for DMA_D */ DMA_D_Chan = DMA_D_DmaInitialize(DMA_D_BYTES_PER_BURST, DMA_D_REQUEST_PER_BURST, HI16(line), HI16(LCD4bit_1_LCD_DP__F1_REG)); DMA_D_TD[0] = CyDmaTdAllocate(); CyDmaTdSetConfiguration(DMA_D_TD[0], sizeof(line)-1, CY_DMA_DISABLE_TD, CY_DMA_TD_INC_SRC_ADR); CyDmaTdSetAddress(DMA_D_TD[0], LO16((uint32)line), LO16((uint32)LCD4bit_1_LCD_DP__F1_REG)); CyDmaChSetInitialTd(DMA_D_Chan, DMA_D_TD[0]); CyDmaChEnable(DMA_D_Chan, 1); 


:



Kesimpulan


, , UDB β€” Datapath Config Tool. , UDB Editor, UDB, , UDB Editor. , , , UDB Editor.

.

Source: https://habr.com/ru/post/id442572/


All Articles