Terakhir kali, kami mempertimbangkan opsi untuk menghasilkan pulsa untuk motor stepper, sebagian dihapus dari perangkat lunak ke tingkat firmware. Dalam hal kesuksesan penuh, ini menjanjikan tidak adanya kebutuhan untuk memproses interupsi tiba dengan frekuensi hingga 40 KHz. Tetapi opsi itu memiliki sejumlah kelemahan yang jelas. Pertama, akselerasi tidak didukung di sana. Kedua, rincian frekuensi langkah yang diizinkan dalam solusi itu adalah ratusan hertz (misalnya, dimungkinkan untuk menghasilkan frekuensi 40.000 Hz dan 39966 Hz, tetapi tidak mungkin untuk menghasilkan frekuensi dengan besarnya antara dua nilai ini).
Implementasi Akselerasi
Apakah mungkin untuk menghilangkan kerugian yang ditunjukkan dengan menggunakan alat UDB yang sama tanpa menyulitkan sistem? Mari kita perbaiki. Mari kita mulai dengan yang paling sulit - dengan akselerasi. Akselerasi ditambahkan di awal dan akhir jalan. Pertama, jika pulsa frekuensi tinggi diterapkan segera ke motor stepper, itu akan membutuhkan arus yang lebih besar untuk memulai operasi. Arus yang diizinkan tinggi adalah pemanasan dan kebisingan, jadi lebih baik untuk membatasinya. Tapi kemudian mesin bisa melompati langkah di awal. Jadi lebih baik mempercepat mesin dengan lancar. Kedua, jika kepala yang berat berhenti tiba-tiba, maka ia mengalami transien yang terkait dengan inersia. Gelombang terlihat di plastik. Oleh karena itu, lancar diperlukan tidak hanya untuk membubarkan, tetapi juga untuk menghentikan kepala. Secara klasik, grafik kecepatan mesin disajikan dalam bentuk trapesium. Ini adalah bagian dari kode sumber firmware Marlin:

Saya bahkan tidak akan mencoba mencari tahu apakah mungkin untuk mengimplementasikan ini menggunakan UDB. Ini disebabkan oleh fakta bahwa jenis akselerasi lain sekarang sedang populer: bukan trapesium, tetapi S-Curve. Jadwal mereka terlihat seperti ini:

Ini jelas bukan untuk UDB. Menyerah? Tidak semuanya! Saya sudah mencatat bahwa UDB tidak mengimplementasikan antarmuka perangkat keras, tetapi hanya memungkinkan Anda untuk mentransfer sebagian kode dari perangkat lunak ke tingkat firmware. Biarkan profil menghitung prosesor pusat, dan pembentukan pulsa langkah masih melakukan UDB. Prosesor pusat memiliki banyak waktu untuk perhitungan. Tugas menghilangkan interupsi yang sering akan terus diselesaikan dengan cukup elegan, dan tidak ada yang berencana untuk membawa proses sepenuhnya ke level firmware.
Tentu saja, profil perlu disiapkan dalam memori, dan UDB akan mengambil data dari sana menggunakan DMA. Tetapi berapa banyak memori yang dibutuhkan? Satu milimeter membutuhkan 200 langkah. Sekarang dengan penyandian 24-bit, ini adalah 600 byte per 1 mm pergerakan head! Sekali lagi, ingat tentang tidak begitu sering, tetapi masih gangguan konstan untuk mengirimkan semuanya dalam fragmen? Tidak juga! Faktanya adalah bahwa mekanisme DMA PSoC didasarkan pada deskriptor. Setelah menjalankan tugas dari satu deskriptor, pengontrol DMA melanjutkan ke yang berikutnya. Jadi, di sepanjang rantai, Anda dapat menggunakan banyak deskriptor. Kami menggambarkan ini dengan beberapa gambar dari dokumentasi resmi:

Sebenarnya, mekanisme ini juga dapat digunakan dengan membangun rantai tiga deskriptor:
Tidak. | Penjelasan |
---|
1 | Dari memori ke FIFO dengan penambahan alamat. Mengindikasikan bagian dengan profil percepatan. |
2 | Dari memori ke FIFO tanpa penambahan alamat. Mengirim semua waktu ke kata yang sama dalam memori untuk kecepatan konstan. |
3 | Dari memori ke FIFO dengan penambahan alamat. Mengindikasikan bagian dengan profil pengereman.
|
Ternyata jalur utama dijelaskan pada langkah 2, dan di sana kata yang sama digunakan secara fisik, yang menetapkan kecepatan konstan. Konsumsi memori tidak besar. Pada kenyataannya, deskriptor kedua dapat secara fisik diwakili oleh dua atau tiga deskriptor. Ini disebabkan oleh fakta bahwa panjang pemompaan maksimum, menurut TRM, bisa 64 kilobyte (amandemen akan lebih rendah). Artinya, 32.767 kata. Bahwa pada 200 langkah per milimeter akan sesuai dengan jalur 163 milimeter. Anda mungkin harus membuat segmen dua atau tiga bagian, tergantung pada jarak maksimum yang dapat ditempuh mesin pada satu waktu.
Namun demikian, untuk menghemat memori (dan biaya blok UDB), saya mengusulkan untuk meninggalkan blok DatapPath 24-bit, beralih ke yang 16-bit lebih ekonomis.
Jadi Proposal pertama untuk revisi.
Array disiapkan dalam memori yang mengkodekan durasi langkah-langkah. Selanjutnya, informasi ini pergi ke UDB menggunakan DMA. Bagian bujursangkar dikodekan oleh array dari satu elemen, blok DMA tidak meningkatkan alamat, memilih elemen yang sama sepanjang waktu. Bagian akselerasi, bujursangkar, dan pengereman terhubung dengan sarana yang tersedia di pengontrol DMA.Rune midrange yang bagus
Sekarang kita akan mempertimbangkan bagaimana mengatasi masalah granularity frekuensi. Tentu saja, tidak mungkin untuk mengaturnya dengan tepat. Tetapi, pada kenyataannya, "firmware" asli juga tidak bisa melakukan ini. Sebagai gantinya, mereka menggunakan algoritma Bresenham. Penundaan satu ukuran ditambahkan ke beberapa langkah. Akibatnya, frekuensi rata-rata menjadi menengah, antara nilai yang lebih kecil dan lebih besar. Dengan menyesuaikan rasio periode reguler dan jangka panjang, Anda dapat dengan lancar mengubah frekuensi rata-rata. Jika kecepatan kita sekarang ditetapkan bukan melalui register data, tetapi ditransmisikan melalui FIFO, dan jumlah pulsa umumnya ditetapkan melalui jumlah kata yang dikirimkan melalui DMA, kedua register data di UDB dibebaskan. Selain itu, salah satu baterai, yang menghitung jumlah pulsa, juga dirilis. Di sini kita akan membangun PWM tertentu pada mereka.
Biasanya, ALU membandingkan dan menetapkan register dengan indeks yang sama. Ketika satu register memiliki indeks 0 dan yang lainnya memiliki 1, tidak setiap versi operasi dapat diimplementasikan. Tapi saya berhasil mengumpulkan solitaire dari register di mana PWM dapat dilakukan. Ternyata seperti yang ditunjukkan pada gambar.

Ketika kondisi A0 <D1 terpenuhi, kami akan menambahkan detak ekstra pada panjang pulsa yang diberikan. Ketika kondisinya tidak terpenuhi, kita tidak akan.
Kuda bulat dalam kondisi normal
Jadi, kami mulai memodifikasi blok yang dikembangkan untuk UDB, dengan mempertimbangkan arsitektur baru. Ganti kedalaman bit Datapath:

Kami akan membutuhkan lebih banyak keluar dari Datapath daripada terakhir kali.

Mengklik dua kali pada mereka, kami melihat detailnya:

Ada lebih banyak digit untuk variabel
State , jangan lupa untuk menghubungkan yang lebih lama !!! Di versi lama, ada konstanta 0.

Grafik transisi automaton yang saya dapatkan seperti ini:

Kami dalam kondisi
Idle saat FIFO1 kosong. By the way, bekerja dengan FIFO1 dan bukan FIFO0 adalah hasil dari pembentukan solitaire. Register A0 digunakan untuk mengimplementasikan PWM, sehingga lebar pulsa ditentukan oleh register A1. Dan saya dapat mengunduhnya hanya dari FIFO1 (mungkin ada metode rahasia lainnya, tetapi mereka tidak diketahui oleh saya). Oleh karena itu, DMA mengunggah data dengan tepat ke FIFO1, dan justru keadaan
"Tidak kosong" untuk FIFO1 yang keluar dari keadaan
menganggur .
ALU dalam status
IDLE membatalkan register A0:

Ini diperlukan agar pada awal operasi PWM, selalu mulai bekerja dari awal.
Namun data masuk ke FIFO. Mesin masuk ke status
LoadData :

Dalam keadaan ini, ALU memuat kata berikutnya dari FIFO ke register A1. Sepanjang jalan, agar tidak membuat keadaan yang tidak perlu, nilai counter A0, yang digunakan untuk bekerja dengan PWM, meningkat:

Jika penghitung A0 belum mencapai nilai D0 (yaitu, kondisi A0 <D0 dipicu, memiringkan bendera NoNeedReloadA0), kami pergi ke keadaan
Satu . Kalau tidak, negara adalah
ClearA0 .
Dalam keadaan
ClearA0, ALU hanya nol nilai A0, memulai siklus PWM baru:

setelah itu mesin juga masuk ke
Satu keadaan, hanya satu ketukan kemudian.
Salah satu yang kami kenal dari versi lama mesin. ALU di dalamnya tidak melakukan fungsi apa pun.
Jadi - dalam kondisi ini, sebuah unit dihasilkan pada output
Out_Step (di sini optimizer bekerja lebih baik ketika unit diproduksi oleh kondisi, ini terdeteksi secara empiris).

Kita berada dalam keadaan ini sampai penghitung tujuh-bit yang sudah kita ketahui diatur ulang ke nol. Tetapi jika sebelumnya kita keluar dari keadaan ini di sepanjang satu jalan, sekarang bisa ada dua jalan: langsung dan tertunda.

Kami akan masuk ke kondisi ExtraTick jika flag
AddCycle diset , yang ditugaskan untuk memenuhi kondisi A0 <D1. Dalam kondisi ini, ALU tidak melakukan tindakan yang menguntungkan. Hanya saja siklusnya membutuhkan 1 ketukan lebih lama. Lebih lanjut, semua jalur bertemu dalam kondisi
Delay .
Kondisi ini mengukur durasi denyut nadi. Daftar A1 (dimuat saat masih dalam kondisi
Muat ) dikurangi hingga mencapai nol.

Selanjutnya, tergantung pada apakah ada data tambahan di FIFO atau tidak, mesin akan pergi ke batch berikutnya untuk
memuat atau ke
Idle . Mari kita lihat ini bukan pada gambar (ada panah panjang, semuanya akan kecil), tetapi dalam bentuk tabel, klik dua kali pada status
Delay :

Sekarang keluar dari UDB. Saya mengonversi tanda sedang dalam kondisi
Idle ke perbandingan asinkron (dalam versi sebelumnya ada pemicu yang dipasang dan diatur ulang di berbagai negara), karena untuk itu pengoptimal menunjukkan hasil terbaik. Ditambah lagi, bendera
Hungry ditambahkan, memberi sinyal ke unit DMA bahwa ia siap menerima data. Itu berakhir pada bendera
"FIFO1 tidak ramai" . Karena tidak ramai, DMA dapat memuat kata data lain di sana.

Pada bagian otomatis - itu saja.
Tambahkan blok DMA ke diagram proyek utama. Untuk saat ini, saya mulai mengganggu bendera terminasi DMA, tetapi bukan fakta bahwa ini benar. Ketika proses akses langsung ke memori selesai, Anda dapat memulai proses baru terkait dengan segmen yang sama, tetapi Anda tidak dapat mulai mengisi informasi tentang segmen baru. FIFO masih memiliki tiga hingga empat elemen. Pada saat ini, masih tidak mungkin untuk memprogram ulang register D0 dan D1 dari blok berdasarkan UDB, mereka masih diperlukan untuk operasi. Oleh karena itu, ada kemungkinan bahwa interupsi berdasarkan output
Out_Idle akan ditambahkan
nanti . Tetapi dapur itu tidak lagi berhubungan dengan pemrograman blok UDB, jadi kami hanya akan menyebutkannya secara sepintas.

Eksperimen perangkat lunak
Karena sekarang semuanya tidak diketahui, kami tidak akan menulis fungsi khusus. Semua cek akan dilakukan "Di dahi." Kemudian, berdasarkan percobaan yang berhasil, fungsi API dapat ditulis. Jadi Kami membuat fungsi
utama () minimal. Ini hanya mengatur sistem dan menjalankan tes yang dipilih.
int main(void) { CyGlobalIntEnable;
Mari kita coba mengirim paket pulsa dengan memanggil fungsi, memeriksa fakta memasukkan pulsa tambahan. Panggilan fungsi itu sederhana:
TestShortSteps();
Tetapi tubuh membutuhkan penjelasan.
Saya akan memberikan seluruh fungsi terlebih dahulu void TestShortSteps() { // , // // , DMA !!! // , !!! StepperController_X_SingleVibrator_WritePeriod (6); // // — CY_SET_REG16(StepperController_X_Datapath_1_D0_PTR, 4); CY_SET_REG16(StepperController_X_Datapath_1_D1_PTR, 2); // . // static const uint16 steps[] = { 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001, 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001 }; // DMA , uint8 channel = DMA_X_DmaInitialize (sizeof(steps[0]),1,HI16(steps),HI16(StepperController_X_Datapath_1_F1_PTR)); CyDmaChRoundRobin (channel,true); // , uint8 td = CyDmaTdAllocate(); // . , . CyDmaTdSetConfiguration(td, sizeof(steps), CY_DMA_DISABLE_TD, TD_INC_SRC_ADR | TD_AUTO_EXEC_NEXT); // CyDmaTdSetAddress(td, LO16((uint32)steps), LO16((uint32)StepperController_X_Datapath_1_F1_PTR)); // CyDmaChSetInitialTd(channel, td); // CyDmaChEnable(channel, 1); }
Sekarang pertimbangkan bagian-bagian pentingnya.
Jika panjang bagian positif dari pulsa sama dengan 92 clock cycle, maka osiloskop tidak akan dapat melihat apakah ada satu siklus masuk di bagian negatif atau tidak. Skalanya tidak akan sama. Hal ini diperlukan untuk membuat bagian positif sesingkat mungkin sehingga total pulsa akan sebanding dalam skala dengan beat yang dimasukkan. Karena itu, saya dengan paksa mengubah periode penghitung yang menetapkan durasi bagian positif dari pulsa:
// , // // , DMA !!! // , !!! StepperController_X_SingleVibrator_WritePeriod (6);
Tapi mengapa enam ukuran keseluruhan? Kenapa tidak tiga? Kenapa tidak dua? Lagi pula, mengapa tidak? Ini adalah kisah sedih. Jika pulsa positif lebih pendek dari 6 siklus, maka sistem tidak berfungsi. Debugging lama pada osiloskop dengan output dari garis uji ke luar menunjukkan bahwa DMA bukanlah hal yang cepat. Jika mesin berjalan kurang dari durasi tertentu, maka pada saat ia
meninggalkan negara
Delay , FIFO paling sering masih kosong. Itu mungkin belum menempatkan satu kata data baru! Dan hanya ketika bagian positif dari pulsa memiliki durasi 6 siklus, FIFO dijamin punya waktu untuk memuat ...
Penyimpangan latensi
Ide perbaikan lain yang ada di kepala saya adalah akselerasi perangkat keras dari fungsi-fungsi tertentu dari kernel RTOS MAX kami. Tapi sayang sekali, semua ide terbaik saya rusak tentang latensi yang sama.
Ada suatu kasus, saya mempelajari pengembangan aplikasi Bare Metal untuk Cyclone V SoC. Tetapi ternyata bekerja dengan register FPGA tunggal (ketika secara bergantian menulis kepada mereka, kemudian membaca dari mereka) mengurangi operasi inti ratusan (!!!) kali. Kamu dengar benar. Ada ratusan. Selain itu, semua ini tidak terdokumentasi dengan baik, tetapi pada awalnya saya merasakan ke dalam, dan kemudian membuktikan dari potongan-potongan frasa dari dokumentasi bahwa latensi bersalah ketika menyampaikan permintaan melalui banyak jembatan. Jika Anda perlu mengusir array besar, juga akan ada latensi, tetapi dalam hal satu kata yang dipompa, itu tidak akan signifikan. Ketika permintaan tunggal (dan akselerasi perangkat keras dari kernel OS menyiratkan hanya mereka), pelambatan berjalan tepat ratusan kali. Akan jauh lebih cepat untuk melakukan semuanya dengan cara yang sepenuhnya terprogram, ketika program bekerja dengan memori utama melalui cache dengan kecepatan panik.
Di PSoC, saya juga punya rencana tertentu. Secara tampilan, Anda dapat dengan luar biasa mencari data dalam array menggunakan DMA dan UDB. Apa yang sebenarnya ada di sana! Karena struktur deskriptor DMA, pengontrol ini dapat melakukan pencarian perangkat keras sepenuhnya dalam daftar tertaut! Tetapi setelah menerima colokan yang dijelaskan di atas, saya menyadari bahwa itu juga terkait dengan latensi. Di sini, latensi ini dijelaskan dengan indah dalam dokumentasi. Baik dalam keluarga TRM dan dalam dokumen terpisah
AN84810 - PSoC 3 dan PSoC 5LP Advanced DMA Topics . Di sana bagian 3.2 dikhususkan untuk ini. Jadi akselerasi perangkat keras berikutnya dibatalkan. Sayang sekali. Tapi, seperti kata Semyon Semyonovich Gorbunkov: "Kami akan mencari."
Eksperimen perangkat lunak yang berkelanjutan
Selanjutnya, saya mengatur parameter algoritma Bresenham:
// // — CY_SET_REG16(StepperController_X_Datapath_1_D0_PTR, 4); CY_SET_REG16(StepperController_X_Datapath_1_D1_PTR, 2);
Nah, kemudian muncul kode biasa yang mentransfer berbagai kata melalui DMA ke FIFO1 dari unit kontrol mesin X.
Hasilnya memerlukan beberapa penjelasan. Ini dia:

Nilai penghitung A0 ditunjukkan dengan warna merah ketika mesin berada dalam kondisi
Satu . Tanda bintang hijau menunjukkan kasus ketika penundaan dimasukkan karena mesin dalam keadaan
ExtraTick . Ada juga bar di mana penundaan itu karena berada dalam keadaan
ClearA0 , mereka ditandai dengan kotak biru.
Seperti yang Anda lihat, ketika Anda pertama kali memasukkan penundaan pertama hilang. Ini disebabkan oleh fakta bahwa A0 diatur ulang ketika sedang dalam kondisi
idle , tetapi meningkat ketika memasuki
LoadData . Oleh karena itu, ke titik analisis (keluar dari negara
One ), sudah sama dengan kesatuan. Akun dimulai dengan dia. Tetapi secara umum, ini tidak akan mempengaruhi frekuensi tengah. Itu hanya perlu diingat. Karena harus diingat bahwa ketika mengatur ulang A0, jam juga akan dimasukkan. Itu harus diperhitungkan ketika menghitung frekuensi rata-rata.
Namun secara umum, jumlah pulsa sudah benar. Durasi mereka juga bisa dipercaya.
Mari kita coba program rantai deskriptor yang lebih nyata,
terdiri dari fase akselerasi, gerak linier dan pengereman. void TestWithPacking(int countOnLinearStage) { // , // . // , DMA !!! // , !!! StepperController_X_SingleVibrator_WritePeriod (6); // // — CY_SET_REG16(StepperController_X_Datapath_1_D0_PTR, 4); CY_SET_REG16(StepperController_X_Datapath_1_D1_PTR, 2); // static const uint16 accelerate[] = {0x0010,0x0008,0x0004}; // static const uint16 deccelerate[] = {0x004,0x0008,0x0010}; // . . static const uint16 steps[] = {0x0001}; // DMA , uint8 channel = DMA_X_DmaInitialize (sizeof(steps[0]),1,HI16(steps),HI16(StepperController_X_Datapath_1_F1_PTR)); CyDmaChRoundRobin (channel,true); // uint8 tdDeccelerate = CyDmaTdAllocate(); CyDmaTdSetConfiguration(tdDeccelerate, sizeof(deccelerate), CY_DMA_DISABLE_TD, TD_INC_SRC_ADR | TD_AUTO_EXEC_NEXT); CyDmaTdSetAddress(tdDeccelerate, LO16((uint32)deccelerate), LO16((uint32)StepperController_X_Datapath_1_F1_PTR)); // uint8 tdSteps = CyDmaTdAllocate(); // !!! // !!! CyDmaTdSetConfiguration(tdSteps, countOnLinearStage, tdDeccelerate, /*TD_INC_SRC_ADR |*/ TD_AUTO_EXEC_NEXT); CyDmaTdSetAddress(tdSteps, LO16((uint32)steps), LO16((uint32)StepperController_X_Datapath_1_F1_PTR)); // // !!! uint8 tdAccelerate = CyDmaTdAllocate(); CyDmaTdSetConfiguration(tdAccelerate, sizeof(accelerate), tdSteps, TD_INC_SRC_ADR | TD_AUTO_EXEC_NEXT); CyDmaTdSetAddress(tdAccelerate, LO16((uint32)accelerate), LO16((uint32)StepperController_X_Datapath_1_F1_PTR)); // CyDmaChSetInitialTd(channel, tdAccelerate); // CyDmaChEnable(channel, 1); }
Pertama, panggilan untuk sepuluh langkah yang sama (dalam DMA, 20 byte benar-benar berjalan):
TestWithPacking (20);
Hasilnya seperti yang diharapkan. Pada awalnya, akselerasi terlihat. Dan jalan keluar ke
IDLE (sinar biru) terjadi dengan penundaan besar dari pulsa terakhir, saat itulah langkah terakhir selesai sepenuhnya, nilainya kira-kira sama dengan nilai yang pertama.

Kuda sungguhan dalam kondisi normal
Saat merenovasi peralatan, saya entah bagaimana terkenal melompat dari lebar pulsa 24-bit ke pekerjaan 16-bit. Tetapi kami menemukan bahwa ini tidak dapat dilakukan: frekuensi pulsa minimum akan terlalu tinggi. Saya melakukannya dengan sengaja. Faktanya adalah bahwa teknik untuk memperluas kapasitas bit dari penghitung 16-bit ternyata sangat rumit sehingga jika saya mulai menggambarkannya bersama-sama dengan mesin utama, itu akan mengalihkan semua perhatian. Karena itu, kami mempertimbangkannya secara terpisah.
Kami memiliki baterai 16-bit. Saya memutuskan untuk menambahkan entitas konter standar tujuh-bit ke bit-bit tinggi. Apakah penghitung tujuh bit ini? Ini adalah desain yang tersedia di setiap blok UDB (blok UDB dasar memiliki lebar bit semua register 8-bit, peningkatan kedalaman bit ditentukan oleh kombinasi blok dalam kelompok). Dari sumber daya yang sama, register
Kontrol / Status dapat diimplementasikan. Sekarang kami memiliki satu penghitung dan bukan pasangan
Kontrol / Status tunggal untuk 16 bit data. Jadi, menambahkan penghitung lain ke sistem, kami tidak akan menunda sumber daya tambahan. Kami hanya mengambil apa yang sudah dialokasikan untuk kami. Itu bagus! Kami membuat byte tinggi penghitung lebar pulsa melalui mekanisme ini dan mendapatkan total lebar penghitung lebar pulsa sama dengan 23 bit.

Pertama saya akan mengatakan apa yang saya pikirkan. Saya pikir setelah keluar dari negara
Delay , saya akan memeriksa penyelesaian penghitungan penghitung tambahan ini. Jika dia belum selesai menghitung, saya akan mengurangi nilainya dan kembali beralih ke negara
Delay . Jika Anda menghitung, logikanya akan tetap sama, tanpa menambahkan siklus tambahan.
Selain itu, dokumentasi untuk penghitung ini mengatakan bahwa saya benar. Secara harfiah dikatakan:
Periode
Menentukan nilai register periode awal. Untuk periode N clock, nilai periode harus ditetapkan ke nilai N-1. Penghitung akan dihitung dari N-1 hingga 0 yang menghasilkan periode siklus N clock. Nilai register periode 0 tidak didukung dan akan menghasilkan output penghitungan terminal yang diadakan pada kondisi tinggi konstan.
Hidup telah menunjukkan bahwa semuanya berbeda. Saya menyimpulkan keadaan garis
hitung terminal pada osiloskop dan menyaksikan nilainya pada nol dimuat dalam
Periode dan selama pemuatan program. Alas dan ah. Tidak ada
keadaan tinggi yang konstan !
Dengan coba-coba, saya berhasil membuat sistem bekerja dengan benar, tetapi agar ini terjadi, setidaknya satu pengurangan dari penghitung harus terjadi! Keadaan baru
"pengurangan" tidak di samping. Itu harus dimasukkan ke jalan yang diperlukan. Itu terletak di depan negara
Delay dan disebut
Next65536 .

ALU dalam kondisi ini tidak melakukan tindakan yang bermanfaat. Sebenarnya, hanya counter baru yang bereaksi terhadap kenyataan berada di negara ini. Ini dia dalam diagram:

Berikut adalah propertinya secara lebih rinci:

Secara umum, dengan mempertimbangkan artikel-artikel sebelumnya, esensi dari counter ini jelas. Hanya
Enable line yang menderita. Sekali lagi, saya tidak sepenuhnya mengerti mengapa itu harus dihidupkan ketika mesin dalam keadaan
LoadData (kemudian penghitung memuat ulang nilai periode). Saya meminjam trik ini dari properti penghitung yang mengontrol LED, diambil dari penulis bahasa Inggris dari unit kontrol untuk LED tersebut. Tanpanya, nilai nol periode tidak berfungsi. Dia bekerja dengannya.
Dalam kode API, kami menambahkan inisialisasi penghitung baru. Sekarang fungsi mulai terlihat seperti ini:
void `$INSTANCE_NAME`_Start() { `$INSTANCE_NAME`_SingleVibrator_Start(); //"One" Generator start `$INSTANCE_NAME`_Plus65536_Start(); }
Mari kita periksa sistem yang baru. Berikut adalah kode fungsi untuk pengujian
(di dalamnya, hanya baris pertama yang berbeda dari yang sudah dikenal): void JustTest(int extra65536s) { // 65536 StepperController_X_Plus65536_WritePeriod((uint8) extra65536s); // // — CY_SET_REG16(StepperController_X_Datapath_1_D0_PTR, 4); CY_SET_REG16(StepperController_X_Datapath_1_D1_PTR, 2); // . // static const uint16 steps[] = { 0x1000,0x1000,0x1000,0x1000 }; // DMA , uint8 channel = DMA_X_DmaInitialize (sizeof(steps[0]),1,HI16(steps),HI16(StepperController_X_Datapath_1_F1_PTR)); CyDmaChRoundRobin (channel,true); // , uint8 td = CyDmaTdAllocate(); // . , . CyDmaTdSetConfiguration(td, sizeof(steps), CY_DMA_DISABLE_TD, TD_INC_SRC_ADR | TD_AUTO_EXEC_NEXT); // CyDmaTdSetAddress(td, LO16((uint32)steps), LO16((uint32)StepperController_X_Datapath_1_F1_PTR)); // CyDmaChSetInitialTd(channel, td); // CyDmaChEnable(channel, 1); }
Kami menyebutnya seperti ini:
JustTest(0);
Pada osiloskop kita melihat yang berikut (sinar kuning - output STEP, nilai biru dari counter counter TC untuk kontrol proses). Durasi pulsa diatur oleh array
langkah . Pada setiap langkah, durasinya adalah 0x1000 tindakan.

Beralih ke pemindaian lain sehingga ada kompatibilitas antara hasil yang berbeda:

Ubah panggilan fungsi menjadi ini:
JustTest(1);
Hasilnya seperti yang diharapkan. Pertama, output TC adalah nol untuk siklus 0x1000, lalu - unit untuk siklus 0x10000 (65536d). Frekuensinya kira-kira sama dengan 700 hertz, kami menemukan di bagian terakhir artikel, jadi semuanya benar.

Baiklah, mari kita coba deuce:
JustTest(2);
Kami mendapatkan:

Benar juga. Output TC dibalik menjadi satu pada siklus clock 65536 terakhir. Sebelumnya, dia nol untuk 0x1000 + 0x10000 siklus.
Tentu saja, dengan pendekatan ini, semua pulsa harus memiliki nilai yang sama dengan penghitung baru. Tidak mungkin untuk membuat satu pulsa dengan byte tertinggi selama akselerasi, katakan 3, lalu 1, lalu 0. Tetapi pada kenyataannya, pada frekuensi rendah (kurang dari tujuh ratus hertz) akselerasi tidak memiliki makna fisik, oleh karena itu masalah ini dapat diabaikan. Pada frekuensi ini, Anda dapat bekerja dengan mesin secara linear.
Terbang di salep
Dokumen TRM untuk keluarga PSoC5LP menyatakan:
Setiap transaksi dapat dari 1 hingga 64 KB
Tetapi dalam AN84810 yang sudah disebutkan ada ungkapan seperti itu:
1. Bagaimana Anda bisa melakukan buffer lebih dari 4095 byte menggunakan DMA?
Jumlah transfer maksimum TD dibatasi hingga 4.095 byte. Jika Anda perlu mentransfer lebih dari 4095 byte menggunakan saluran DMA tunggal, gunakan beberapa TDs dan rantai seperti yang ditunjukkan pada Contoh 5.
Siapa yang benar Jika Anda melakukan percobaan, hasilnya akan cenderung mendukung yang terburuk dari pernyataan tersebut, tetapi perilaku tersebut akan sepenuhnya tidak dapat dipahami. Seluruh kesalahannya adalah pemeriksaan ini di API:

Teks yang sama. cystatus CyDmaTdSetConfiguration(uint8 tdHandle, uint16 transferCount, uint8 nextTd, uint8 configuration) \ { cystatus status = CYRET_BAD_PARAM; if((tdHandle < CY_DMA_NUMBEROF_TDS) && (0u == (0xF000u & transferCount))) { /* Set 12 bits transfer count. */ reg16 *convert = (reg16 *) &CY_DMA_TDMEM_STRUCT_PTR[tdHandle].TD0[0u]; CY_SET_REG16(convert, transferCount); /* Set Next TD pointer. */ CY_DMA_TDMEM_STRUCT_PTR[tdHandle].TD0[2u] = nextTd; /* Configure the TD */ CY_DMA_TDMEM_STRUCT_PTR[tdHandle].TD0[3u] = configuration; status = CYRET_SUCCESS; } return(status); }
Jika transaksi ditentukan lebih dari 4095 byte, pengaturan sebelumnya akan digunakan. Ya, saya tidak berpikir untuk memeriksa kode kesalahan ...
Eksperimen menunjukkan bahwa jika Anda menghapus cek ini, panjang sebenarnya akan terpotong menggunakan mask 0xfff (4096 = 0x1000). Alas dan ah. Semua harapan untuk pekerjaan yang menyenangkan runtuh. Anda tentu saja dapat membuat rantai deskriptor terkait dalam 4K. Tapi, katakanlah, 64K adalah 16 rantai. Tiga mesin aktif (ekstruder akan memiliki langkah lebih sedikit) - 48 rantai. Sebegitu banyak yang harus diisi dalam kasus terburuk, sebelum setiap segmen. Mungkin tepat waktu. Minimal, 127 deskriptor tersedia, jadi pasti akan ada cukup memori.
Anda dapat mengirim data yang hilang sesuai kebutuhan. Gangguan datang bahwa saluran DMA telah menyelesaikan pekerjaan, kami mentransfer segmen lain ke sana. Dalam hal ini, tidak ada perhitungan yang diperlukan, segmen sudah terbentuk, semuanya akan cepat. Dan tidak ada persyaratan kinerja: ketika permintaan interupsi dikeluarkan, akan ada 4 elemen lagi di FIFO yang akan dilayani masing-masing selama beberapa ratus atau bahkan ribuan siklus clock. Yaitu, semuanya nyata. Strategi khusus akan lebih mudah untuk dipilih selama pekerjaan nyata. Tetapi kesalahan dalam dokumentasi (TRM) merusak seluruh suasana hati. Jika ini diketahui sebelumnya, mungkin saya tidak akan memeriksa metodologi.
Kesimpulan
Secara tampilan, alat bantu firmware yang dikembangkan menjadi dapat diterima sehingga pada dasarnya dimungkinkan untuk membuat versi "Firmware", katakanlah, Marlin, yang tidak terus-menerus dalam pengendali interupsi untuk motor stepper. Sejauh yang saya tahu, ini terutama berlaku untuk printer Delta, di mana permintaan untuk sumber daya komputasi cukup tinggi. Mungkin ini akan menghilangkan masuknya yang terjadi di Delta saya di tempat-tempat di mana kepala berhenti. Pada MZ3D di tempat yang sama tidak ada gelombang masuk yang diamati. Benar atau tidak, waktu akan memberi tahu, dan laporan tentang ini perlu diposting di cabang yang sama sekali berbeda.
Sementara itu, kita telah melihat bahwa pada blok UDB, untuk semua kesederhanaannya, sangat mungkin untuk mengimplementasikan coprocessor yang bekerja bersama-sama dengan prosesor utama dan membiarkannya diturunkan. Dan ketika ada banyak unit ini, koprosesor dapat bekerja secara paralel.
Kesalahan dalam dokumentasi untuk pengontrol DMA mengaburkan hasilnya. Meskipun demikian interupsi diperlukan, tetapi tidak pada frekuensi yang sama dan tidak dengan kekritisan waktu yang ada dalam versi aslinya. Jadi suasananya rusak, tetapi penggunaan "coprocessor" berbasis UDB masih memberikan keuntungan yang cukup besar dibandingkan dengan pekerjaan perangkat lunak murni.
Sepanjang jalan, terungkap bahwa DMA bekerja pada kecepatan yang cukup rendah. Sebagai akibatnya, beberapa pengukuran dilakukan baik pada PSoC5LP dan pada STM32. Hasilnya menarik artikel lain. Mungkin suatu hari nanti saya akan melakukannya jika topiknya ternyata menarik.
Sebagai hasil dari percobaan, dua proyek uji diperoleh sekaligus. Yang pertama lebih mudah dipahami. Anda bisa membawanya ke
sini . Yang kedua diwarisi dari yang pertama, tetapi bingung ketika menambahkan penghitung tujuh-bit dan logika yang terkait. Anda bisa membawanya ke
sini . Tentu saja, contoh-contoh ini hanya yang uji. Tidak ada waktu luang untuk menanamkan ke dalam "firmware" nyata. Tetapi dalam kerangka artikel ini, lebih penting untuk berlatih bekerja dengan UDB.