"Sekarang aku akan menunjukkan padamu sebuah potret ... Hmm ... Aku memperingatkanmu bahwa ini adalah potret ... Bagaimanapun, tolong perlakukan dia seperti potret ...Dalam posting ini, kita akan berbicara tentang pengembangan dan debugging program untuk CC1350 MK di lingkungan pengembangan CCS yang direkomendasikan oleh pabrikan. Kelebihan (dan mereka) dan kerugian (dan bagaimana tanpa mereka) dari produk di atas akan terpengaruh. Tidak akan ada tangkapan layar dalam teks untuk menunjukkan (dilingkari) lokasi ikon kompilasi di lingkungan pemrograman terintegrasi atau memilih file dalam direktori. Menyadari kemungkinan mendasar dari artikel dengan gaya yang sama, saya akan mencoba untuk fokus pada masalah konseptual dengan harapan bahwa pembaca saya akan dapat mengetahui detailnya.
Tujuan dari karya ini, di samping untuk berbagi pengalaman yang didapat, adalah upaya untuk membangkitkan kecemburuan yang sehat di antara para produsen MK dalam negeri, yang merupakan pesaing langsung TI ("di negara tempat kami makmur") - tugas ini sejujurnya tidak berterima kasih, tetapi mereka mengatakan bahwa sebuah batu menghilangkan setetes air.
Saya akan segera menekankan bahwa ini hanya tentang Windows 7 (apalagi, hanya) versi 7, meskipun situs web TI memiliki opsi untuk Mac dan Linux, saya belum mencobanya, saya cukup siap untuk percaya bahwa semuanya tidak terlalu keren di sana, tetapi mengapa tentang yang buruk (atau sebaliknya, semuanya bagus di sana, tapi lalu mengapa iri).
Jadi, apa yang diajarkan situs web TI kami - untuk mulai bekerja dengan modul evaluasi, Anda perlu melakukan tiga langkah yang perlu:
- Beli modul evaluasi - selesai.
Catatan tentang margin (PNP): Anda juga harus melakukan ini, karena dalam lingkungan pemrograman yang dimaksud saya pribadi (sayangnya) tidak berhasil menemukan kemampuan untuk meniru perangkat keras untuk debugging, setidaknya di mana saya melihat. - Instal lingkungan pengembangan - unduh, jalankan pemasang, semuanya beres. Kami menghubungkan modul evaluasi ke USB - kayu bakar naik dengan sendirinya dan semuanya bekerja kembali - selesai. Saat Anda mencoba memprogram perangkat, kami menerima pesan tentang perlunya memperbarui firmware, kami setuju dan semuanya kembali. Secara umum, tidak ada yang perlu ditulis jika itu selalu dan di mana-mana ...
- Pergi dan pelajari kursus TI SimpleLink Academy 3.10.01 untuk SimpleLink CC13x0 SDK 3.10 - saran yang aneh, sepertinya mengajari saya - hanya untuk memanjakan, tetapi biarlah, saya membuka tautan yang sesuai dan terpana - berapa banyak hal yang dimasukkan di sini.
Di sini kita melihat materi pelatihan tentang bekerja dengan driver perangkat keras SYS / BIOS dan dengan sistem operasi TI-RTOS dan tentang menggunakan tumpukan jaringan NDK, termasuk USB, dan tentang menggunakan protokol nirkabel dan banyak lagi aspek bekerja dengan perwakilan dari berbagai keluarga MK yang diproduksi oleh perusahaan. Dan semua kekayaan ini disertai dengan contoh-contoh siap pakai, dan jika kita memperhitungkan kehadiran manual pengguna dan deskripsi modul, maka mungkin tidak ada lagi yang diharapkan. Tetapi ada juga utilitas yang memfasilitasi pekerjaan mempersiapkan dan mengkonfigurasi kode program, flashing dan debugging dengan berbagai cara, dan kekayaan ini juga cukup didokumentasikan.
Pnp: jika seseorang cenderung menganggap materi ini sebagai iklan dalam kaitannya dengan perusahaan, produk dan sistem pemrogramannya, maka kemungkinan besar akan benar dan saya benar-benar sangat terkesan dengan volume perangkat lunak yang terdeteksi. Kualitasnya akan dibahas lebih lanjut dan, saya harap, kecurigaan bias akan dihilangkan, saya tidak sepenuhnya dibutakan oleh perasaan dan saya terus melihat dengan sempurna cacat dari objek deskripsi, jadi ini bukan cinta remaja, tetapi perasaan serius seorang spesialis dewasa. Saya takut membayangkan jumlah biaya material yang diperlukan untuk membuat dan memelihara volume perangkat lunak dan dokumentasi untuk itu, tetapi ini jelas tidak dilakukan dalam satu bulan, dan perusahaan mungkin mengerti apa yang dilakukannya.
Oke, sampai kita menunda studi bahan untuk nanti, kita akan memahami segala sesuatu "sepanjang jalan dengan nugget" dan dengan berani membuka CCS. Ini mengimplementasikan konsep ruang kerja, yang diterima dari induknya - Eclipse. Secara pribadi, konsep proyek lebih dekat dengan saya, tetapi tidak ada yang mengganggu kita untuk menjaga satu proyek tetap di ruang angkasa, jadi mari kita beralih.
Tapi kemudian situasinya menjadi sedikit lebih buruk - kami membuka ruang kerja (RP) untuk papan debug kami dan melihat banyak proyek (sebagai aturan, dalam dua versi - untuk RTOS dan untuk "bare iron"). Seperti yang saya katakan sebelumnya, ini bukan kejahatan, tetapi kenyataan bahwa banyak proyek berisi file yang sama dengan modul perangkat lunak yang identik tidak bagus sama sekali. Kode digandakan berkali-kali dan perubahan pendukung menjadi tugas yang sangat sepele. Ya, dengan solusi seperti itu, jauh lebih mudah untuk mentransfer proyek hanya dengan menyalin direktori, tetapi untuk hal-hal seperti itu ada ekspor proyek, dan itu diimplementasikan dengan cukup baik. Tautan ke file di pohon proyek didukung secara memadai, sehingga keputusan untuk memasukkan file itu sendiri dalam contoh yang diberikan tidak dapat dianggap memuaskan.
Kami melanjutkan penelitian kami - kami akan mulai bekerja dengan proyek yang sudah selesai, tetapi tidak berkedip LED, meskipun ada dua dari mereka di papan debug, tetapi bekerja dengan port serial, contoh uartecho siap pakai. Kami membuat RP baru, termasuk proyek yang menarik bagi kami dan ... tidak ada yang datang darinya, jelas dari pesan bahwa perlu untuk menyertakan proyek terkait dalam RP. Tidak begitu jelas mengapa ini dilakukan, tetapi tidak sulit untuk memenuhi persyaratan lingkungan, setelah itu proyek mulai dirakit.
Pnp: pada mesin rumah, saya menggunakan perintah Proyek Impor dan semua inklusi yang diperlukan terjadi sendiri. Di mana tepatnya proyek terkait ditunjukkan, saya tidak tahu, mari kita tinggalkan analisis aspek ini untuk masa depan.
Kami mengkompilasi, mem-flash, dan memulai debugging. Kami menemukan fenomena yang menarik - eksekusi langkah demi langkah tidak cukup ditampilkan ketika mempertimbangkan perpustakaan bekerja dengan port serial - biaya optimasi. Kami mematikan optimisasi dalam pengaturan kompiler (yang tidak ada pengaturannya, apakah benar-benar ada orang yang mengenal mereka dan, terlebih lagi, gunakan semuanya), kumpulkan proyek lagi - dan tidak ada perubahan. Ternyata hanya file-file itu yang dimasukkan yang termasuk dalam pohon proyek, setidaknya dalam bentuk tautan. Kami menambahkan tautan ke sumber pustaka dan setelah membangun kembali semuanya di-debug dengan benar (asalkan kami memiliki opsi untuk menghasilkan informasi debug yang diaktifkan).
Pnp: tapi saya menemukan opsi untuk mengaktifkan pemeriksaan kepatuhan MISRA-C.
Pnp: cara lain adalah dengan menggunakan perintah "Bersihkan ..." dengan rakitan berikutnya, perintah "Bangun Semua" karena alasan tertentu tidak memengaruhi proyek terkait.
Kemudian kami menemukan bahwa tidak semuanya selalu didebug secara normal, kadang-kadang kami menemukan diri kami di area kode mesin yang pembuatnya tidak menemukan sumbernya. Karena lingkungan pemrograman memberi kita semua file yang diperlukan untuk bekerja - hasil preprocessor, kode assembler dan kartu linker (Anda hanya perlu mengingat untuk mengaktifkan opsi yang sesuai), kita beralih ke yang terakhir. Kami menemukan dua area kode program - mulai dari 0x0000. dan mulai dari 0x1000. (Arsitektur 32-bit baik untuk semua orang, tetapi penulisan alamat bukanlah kelebihan mereka). Kami membuka dokumentasi untuk rangkaian mikro dan mengetahui bahwa di dalamnya ada area ROM yang dipetakan secara khusus untuk 0x1000., Dan itu berisi bagian built-in dari perpustakaan. Dikatakan bahwa menggunakan rutinitas darinya meningkatkan kinerja dan mengurangi konsumsi dibandingkan dengan ruang alamat 0x000. Saat kami menguasai MK, kami tidak begitu tertarik pada parameter terakhir, tetapi kenyamanan debugging sangat penting. Anda dapat menonaktifkan penggunaan ROM (tetapi untuk tujuan kami) dengan mengatur opsi NO_ROM ke kompiler, yang kami lakukan dan pasang kembali proyek.
PNP: transisi ke subrutin dalam ROM terlihat sangat lucu - tidak ada transisi panjang dalam sistem perintah, jadi transisi pertama dilakukan dengan kembali ke titik tengah di area alamat rendah (0x0000), dan sudah ada perintah boot PC, yang parameternya tidak dikenali oleh disassembler. Sesuatu yang saya tidak percaya, seolah-olah dengan biaya overhead seperti itu Anda bisa menang dalam kecepatan, meskipun untuk rutinitas lama - mengapa tidak
Ngomong-ngomong, pertanyaan yang menarik adalah bagaimana umumnya dijamin bahwa isi ROM sesuai dengan kode sumber yang disediakan oleh perusahaan. Saya dapat langsung menyarankan mekanisme untuk menanamkan fungsi tambahan (tentu saja, debugging dan layanan) dalam ROM, yang bagi pengguna - programmer MK akan sepenuhnya tidak terlihat. Dan secara pribadi, saya tidak ragu bahwa para pengembang chip juga tahu banyak mekanisme lain yang menerapkan fungsi seperti itu, tetapi kita akan mengakhiri serangan paranoia.
Di sisi lain, saya hanya bisa menyambut penampilan analog dari BIOS, karena dalam jangka panjang ini akan membuat impian pengembang akan portabilitas kode nyata antara keluarga MK yang berbeda dengan satu inti menjadi kenyataan. Kami juga mencatat kekhasan implementasi interaksi dengan modul perangkat lunak "tertanam". Jika dalam upaya awal untuk membuat mekanisme serupa yang diterapkan dalam model TivaC, ada seorang supervisor panggilan yang diakses dengan nomor grup dan jumlah titik masuk ke dalam subprogram, yang menyebabkan overhead yang signifikan, maka di sini resolusi komunikasi berada pada level linker karena nama fungsi ganda dan Langsung lompat jauh ke subrutin dalam ROM dimasukkan. Ini jauh lebih cepat dalam eksekusi, tetapi membutuhkan kompilasi ulang proyek ketika mengubah model penggunaan.
Sekarang setelah kami sepenuhnya siap untuk debugging yang nyaman, kami kembali ke proyek kami dan mulai dengan tenang men-debug program dengan akses ke kode sumber modul (well, itulah yang saya pikir ...), yang akan memungkinkan kami untuk memberikan pendapat tentang kualitas teks-teks ini. Proyek yang diteliti menerapkan cermin dari saluran komunikasi serial dan sangat nyaman untuk tujuan pelatihan. Tentu saja, kami mengambil opsi menggunakan RTOS, saya tidak melihat alasan sedikit pun untuk tidak menggunakannya dalam konfigurasi kami (banyak memori dan memori program).
Segera, kami mencatat bahwa kode sumber disajikan dalam C, seringkali tidak terlalu nyaman, banyak konstruksi bahasa terlihat rumit dibandingkan dengan analog mereka pada plus, tetapi pencipta lebih peduli dengan kompatibilitas kode daripada gula sintaksis. Meskipun mungkin untuk membuat versi C ++ perpustakaan, kompilasi bersyarat telah dikenal sejak lama dan digunakan di mana-mana, tetapi ini memerlukan biaya bahan tambahan. Tentunya, manajemen perusahaan tahu apa yang mereka lakukan, dan komentar saya adalah semacam "analisis licik", tetapi bagi saya tampaknya saya juga memiliki hak atas pendapat saya.
Saya juga tahu pendekatan yang berlawanan, ketika perpustakaan dirancang menggunakan alat C ++ terbaru, dan ketika ditanya apa yang harus dilakukan untuk para pengembang yang menggunakan kompiler yang tidak memenuhi spesifikasi terbaru, jawaban yang sempurna adalah meng-upgrade ke versi baru atau tidak. perpustakaan ini (saya sangat merekomendasikan opsi kedua dalam kasus seperti itu). Pendapat pribadi saya adalah bahwa jika kita benar-benar ingin produk kita digunakan (dan TI jelas menginginkannya, dan tidak membuat perpustakaan berdasarkan prinsip "drop it off me, ini drum baru untukmu"), maka pendekatannya tentu benar.
Kode sumber program terlihat klasik - menginisialisasi lingkungan perangkat keras dan perangkat lunak, membuat tugas dan meluncurkan sheduler dalam modul utama, teks tugas dalam modul kompilasi terpisah. Dalam contoh yang dipertimbangkan, tugasnya persis satu - mainThread, tujuannya tidak sepenuhnya jelas dari namanya, dan juga, yang agak membingungkan saya - nama file yang berisi teks sumber tidak sesuai dengan nama fungsi (uartecho.c - meskipun namanya berbicara di sini) ya Pencarian di lingkungan pemrograman diimplementasikan dengan cara standar (menu konteks atau F3 pada nama entitas) dan tidak ada masalah dengan ini.
Proses pengaturan parameter tugas sebelum memulai cukup banyak diharapkan:
- buat struktur parameter (lokal, tentu saja),
- berikan nilai default,
- mengatur parameter selain standar, dan
- gunakan struktur saat membuat tugas.
Terlepas dari jenis kealamian operasi ini, tidak jelas bagi semua penulis perpustakaan, dan saya melihat berbagai implementasi di mana, misalnya, tidak ada tahap 2, yang mengarah ke perilaku program yang lucu (untuk pengamat luar, bukan untuk programmer). Dalam hal ini, semuanya baik-baik saja, satu-satunya pertanyaan yang muncul adalah mengapa nilai default tidak konstan, mungkin ini adalah warisan dari masa lalu yang terkutuk.
PNP: dalam FREE-RTOS yang terkenal pendekatan yang sedikit berbeda diambil dengan parameter tugas yang ditunjukkan secara langsung di tubuh panggilan API dari fungsi pembuatan tugas. Pro dan kontra dari pendekatan ini adalah sebagai berikut:
- + memungkinkan Anda untuk tidak secara eksplisit menentukan parameter yang cocok dengan nilai default, + tidak perlu mengingat urutan parameter, -lebih verbose, -biaya memori lebih besar, -Anda perlu mengetahui parameter default, -membuat objek perantara bernama
- - Membutuhkan menentukan semua parameter, -membutuhkan mengingat urutan parameter, + lebih kompak, + membutuhkan lebih sedikit memori, + tidak memerlukan bernama objek antara.
Ada metode ketiga, yang dianjurkan oleh penulis postingan ini (dengan gaya TURBO), yang memiliki perangkat sendiri - + memungkinkan Anda untuk tidak secara eksplisit menentukan parameter yang sesuai dengan standar, + tidak perlu mengingat urutan parameter, -multi-verbal, -biaya memori lebih besar, -Anda perlu mengetahui parameter default, + bekerja dengan gaya lambda, + membuat kesalahan standar sulit untuk diimplementasikan, -lihat beberapa standar aneh karena banyak kurung kanan.
Nah, ada pilihan keempat lain, tanpa kekurangan, tetapi membutuhkan C ++ tidak lebih rendah dari 14 - kita menjilat bibir kita dan melewatinya.
Kami mulai debugging, menjalankan program dan membuka salah satu dari dua port serial yang disediakan oleh papan debugging di jendela terminal yang disediakan oleh lingkungan pemrograman. Yang mana dari dua port (satu adalah debugging, mungkin yang kedua adalah pengguna, Anda dapat melihat nomor mereka di sistem) yang sulit untuk diketahui sebelumnya, kadang-kadang yang termuda, kadang-kadang senior, setidaknya itu tidak berubah ketika Anda menyambungkan kembali papan, sehingga Anda dapat menuliskannya di papan tulis. Nah, satu lagi ketidaknyamanan - terminal terbuka tidak disimpan dengan proyek dan tidak dikembalikan ketika Anda membuka sesi debugging, meskipun mereka tidak menutup ketika Anda keluar. Kami memeriksa operasi program dan segera menemukan satu kekurangan lagi - terminal tidak dapat dikonfigurasi, misalnya, pada dasarnya bekerja dalam gaya Unix dengan penutup / r, saya telah kehilangan sentuhan dengan minimalis seperti itu, meskipun tidak ada yang mengganggu kami dengan menggunakan program terminal eksternal.
Pnp: Kami mencatat satu lagi fitur debugging, yah, ini berlaku untuk lingkungan pengembangan mana pun - ketika kami berganti tugas dengan sheduler, kami kehilangan fokus fokus, breakpoints akan membantu kami menyelesaikan masalah ini.
Untuk memulai, pertimbangkan proses pembuatan instance dari port serial - semuanya tampak standar di sini, struktur digunakan, bidang yang ditugaskan parameter yang diperlukan dari objek. Perhatikan bahwa pada pro kami memiliki kesempatan, benar-benar tidak ada dalam C, untuk sepenuhnya menyembunyikan semua inisialisasi "di bawah tenda", tetapi saya telah menyuarakan kemungkinan argumen yang mendukung solusi kedua. Ada fungsi untuk menginisialisasi struktur tuning, dan ini bagus (paradoks kedengarannya, fungsi ini tampaknya tidak wajib bagi penulis dari beberapa perpustakaan). Pada titik ini dalam cerita, bulan madu berakhir dan kehidupan biasa
(suami) dimulai.
Penelitian yang cermat terhadap sumber-sumber menunjukkan bahwa tidak semuanya baik. Apa masalahnya - fungsi inisialisasi menyalin nilai-nilai default dari objek yang terletak di wilayah konstan ke dalam struktur kontrol kami, dan ini luar biasa, tetapi untuk beberapa alasan:
- objek bersifat global, meskipun hanya digunakan oleh satu-satunya fungsi untuk menginisialisasi parameter (pada satu waktu praktik yang sama membuat Toyota membayar jumlah yang layak) - well, menambahkan arahan statis itu mudah;
- objek kontrol bernama, di C tidak ada solusi yang indah untuk masalah ini, atau lebih tepatnya, ada solusi dengan salinan anonim dan saya memberikannya dalam posting yang lama, tetapi banyak tanda kurung kanan tidak memungkinkan untuk memanggil opsi ini benar-benar indah, ditambah juga ada solusi keindahan yang luar biasa, tapi apa untuk memimpikan mimpi pipa;
- semua bidang objek jelas redundan dalam kedalaman bit, bahkan bidang bit (enumerasi dari dua nilai yang mungkin) disimpan dalam kata-kata 32-bit;
- konstanta mode enumerated didefinisikan dalam bentuk mendefinisikan, yang membuatnya tidak mungkin untuk memeriksa pada tahap kompilasi dan diperlukan dalam waktu berjalan;
- mengulangi bagian dari loop tak terbatas di tempat yang berbeda dari kemungkinan kegagalan, akan jauh lebih tepat untuk membuat satu (dalam hal ini kosong) handler;
- Nah, semua operasi untuk mengatur dan memulai tugas dapat (dan harus) disembunyikan dalam satu fungsi atau bahkan makro.
Tetapi inisialisasi buffer penerimaan dilakukan dengan baik - kami menggunakan memori yang sudah dipesan sebelumnya, tidak ada manipulasi tumpukan, rantai panggilan agak rumit, tetapi semuanya dapat dibaca.
Pnp: di jendela debug, di depan mata kita, tumpukan panggilan, semuanya dilakukan sebagaimana mestinya dan nyenyak - menghormati dan menghormati. Satu-satunya hal yang agak mengejutkan adalah upaya untuk menyembunyikan jendela ini mengarah ke akhir sesi debugging.
Nah, dan satu lagi keputusan yang agak tak terduga - mengatur jumlah objek yang mungkin dalam enumerasi, untuk port serial dan untuk papan debug ini sama dengan 1, dengan gaya
typedef enum CC1310_LAUNCHXL_UARTName { CC1310_LAUNCHXL_UART0 = 0, CC1310_LAUNCHXL_UARTCOUNT } CC1310_LAUNCHXL_UARTName;
Solusi semacam itu adalah standar untuk transfer nyata, tetapi untuk deskripsi objek perangkat keras - dan saya tidak tahu bahwa ini mungkin, meskipun itu berfungsi untuk diri saya sendiri. Kami telah menyelesaikan inisialisasi besi, mari kita lanjutkan.
Dalam tugas yang sedang berjalan, kami mengamati loop infinite klasik di mana data dari port serial dibaca oleh fungsi
UART_read(uart, &input, 1);
dan segera dikirim kembali dengan fungsi
UART_write(uart, &input, 1);
. Mari kita masuk ke yang pertama dan melihat upaya untuk membaca karakter dari buffer terima
return (handle->fxnTablePtr->readPollingFxn(handle, buffer, size))
(bagaimana saya membenci hal-hal seperti itu, tetapi dalam C itu hanya mustahil jika tidak), kita masuk lebih dalam dan menemukan diri kita di UARTCC26XX_read, dan dari sana kita masuk ke implementasi buffer cincin - fungsi
RingBuf_get(&object->ringBuffer, &readIn)
. Di sini, kehidupan biasa memasuki fase akut.
Saya tidak ingin mengatakan bahwa saya tidak suka modul khusus ini (file ringbuf.c), itu ditulis dengan sangat buruk dan secara pribadi saya akan mengusir tempat perusahaan yang sangat dihormati dari penulis bagian ini dengan rasa malu (Anda masih dapat mengambil saya di tempat mereka, tetapi saya takut bahwa tingkat gaji kolega India kami tidak akan cocok untukku), tapi aku mungkin tidak tahu apa. Awasi tangan Anda:
1) re-roll pointer baca / tulis dilaksanakan melalui sisa divisi
object->tail = (object->tail + 1) % object->length;
dan tidak ada optimisasi kompilator saat melakukan operasi ini, seperti overlay bit mask, karena panjang buffer tidak konstan. Ya, di MK ini ada operasi divisi perangkat keras dan ini cukup cepat (saya menulis tentang itu), tapi tetap saja tidak pernah membutuhkan 2 siklus clock, seperti dalam implementasi yang benar dengan re-roll yang jujur (dan saya juga menulis tentang ini),
Pnp: Saya baru-baru ini melihat deskripsi arsitektur M7 baru dalam implementasi dan saya tidak ingat siapa pun, jadi untuk beberapa alasan, membagi 32 dengan 32 mulai dilakukan dalam 2-12 siklus, bukan 2-7. Entah ini kesalahan terjemahan, atau ... Saya bahkan tidak tahu harus berpikir apa.
2) Selain itu, fragmen kode ini diulangi di lebih dari satu tempat - makro dan inline untuk pengecut, aturan ctrl + C dan ctrl + V, prinsip KERING melewati hutan,
3) penghitung yang benar-benar redundan dari tempat-tempat penyangga diisi diimplementasikan, yang mencakup kelemahan berikut,
4) bagian penting dalam membaca dan menulis. Yah, saya masih bisa percaya bahwa penulis modul ini tidak membaca posting saya di Habré (walaupun perilaku ini tidak dapat diterima untuk para profesional di bidang firmware), tetapi mereka harus terbiasa dengan Mustang Book, di sana masalah ini diperiksa secara rinci,
5) seperti ceri pada kue, indikator ukuran buffer maksimum telah diperkenalkan, apalagi, dengan nama yang sangat tidak jelas dan deskripsi yang sama sekali tidak ada (yang terakhir berlaku umumnya untuk seluruh modul). Saya tidak mengecualikan bahwa opsi ini mungkin berguna untuk debugging, tetapi mengapa menyeretnya ke rilis - apakah kita memiliki siklus prosesor sama sekali dengan RAM?
6) pada saat yang sama, pemrosesan buffer overflow benar-benar tidak ada (ada sinyal balik -1 tentang situasi ini) - bahkan di Arduino, kami akan mengesampingkan kualitas pemrosesan ini, tetapi ketidakhadirannya bahkan lebih buruk. Atau apakah penulis diilhami oleh fakta terkenal bahwa asumsi apa pun yang benar mengenai set yang relatif kosong, termasuk fakta bahwa itu tidak kosong?
Secara umum, komentar saya sepenuhnya konsisten dengan baris pertama demotivator pada topik ulasan kode "10 baris kode - 10 komentar."
By the way, kedua dari kekurangan yang dicatat membuat kita berpikir tentang hal-hal yang lebih global - tetapi bagaimana kita bahkan menerapkan kelas dasar untuk dapat melakukan modifikasi yang mendalam. Untuk membuat semua bidang aman adalah ide yang meragukan (meskipun mungkin satu-satunya yang tepat), memasukkan panggilan fungsi ramah ke ahli waris sangat mirip dengan tongkat penyangga. Jika dalam kasus khusus ini ada jawaban sederhana untuk pertanyaan memperkenalkan indikator kepenuhan buffer - kelas yang dihasilkan dengan penulisan dan pembacaan yang tumpang tindih dan penghitung tambahan, kemudian menerapkan bacaan tanpa memajukan buffer (seperti dalam kasus ini) atau mengganti karakter yang ditempatkan terakhir (saya melihat seperti implementasi buffer ring) Anda tidak dapat melakukannya tanpa akses ke data internal kelas induk.
Pada saat yang sama, tidak ada keluhan tentang implementasi pembacaan yang sebenarnya dari antarmuka serial - input menghalangi, dengan tidak adanya jumlah karakter yang cukup dalam buffer penerima, semaphore dikokang dan kontrol ditransfer ke sheduler - semuanya dilaksanakan secara akurat dan benar. Secara pribadi, saya tidak begitu suka mengendalikan peralatan dalam prosedur tujuan umum, tetapi ini mengurangi prosedur bersarang dan mengurangi indeks kompleksitas siklomatik, tidak peduli apa artinya.
Mari kita perhatikan transmisi data yang diterima ke saluran serial, karena saat membuat objek itu hanya disediakan satu buffer cincin - penerima. Memang, buffer internal perangkat keras digunakan untuk mengirimkan karakter, dan ketika diisi, menunggu kesiapan dimasukkan (setidaknya dalam mode operasi pemblokiran). Saya tidak bisa menahan diri, agar tidak mengkritik gaya fungsi yang sesuai: 1) karena suatu alasan, objek memiliki pointer yang digeneralisasikan, yang di dalam fungsinya secara konstan berubah menjadi pointer ke karakter.
*(unsigned char *)object->writeBuf);
2) logika kerja benar-benar buram dan sedikit bingung. Tetapi semua ini tidak begitu penting, karena tetap disembunyikan dari pengguna dan "tidak mempengaruhi kecepatan maksimum."
Dalam proses penelitian, kami menemukan satu fitur lagi - kami tidak melihat kode sumber dari beberapa fungsi internal dalam mode debug - ini disebabkan oleh perubahan nama untuk opsi kompilasi yang berbeda (ROM / NO_ROM). Ganti file sumber yang diperlukan (C: \ Jenkins \ jobs \ FWGroup-DriverLib \ workspace \ modules \ output \ cc13xx_cha_2_0_ext \ driverlib \ bin \ ccs /./../../../ driverlib / uart.c--) Saya tidak berhasil (tapi saya tidak berusaha sangat keras), walaupun saya menemukan sumbernya (tentu saja, dalam file di file uart.c, terima kasih, kapten), untungnya, fragmen ini sederhana dan mudah untuk mengidentifikasi kode assembler dengan kode sumber di C (terutama jika Anda tahu fitur-fitur dari tim ITxxx). Saya tidak tahu bagaimana menyelesaikan masalah ini untuk perpustakaan dengan fungsi yang kompleks, kami akan berpikir ketika dibutuhkan.
Dan akhirnya, sebuah pernyataan kecil - Saya siap untuk percaya bahwa perangkat keras dari implementasi saluran serial untuk model CC13x0 bertepatan dengan model CC26x0, dan menduplikasi konten file yang disebut UARTCC26XX.c --- tidak dapat disebut solusi yang tepat, tetapi membuat file definisi menengah dengan penyertaan Saya akan menyambut file sumber, mengesampingkan fungsi dan komentar yang sesuai, karena ini akan membuat program lebih dimengerti, dan ini harus selalu diterima, vout.
Jadi, test case berfungsi, kami belajar banyak tentang struktur internal perpustakaan standar, mencatat kekuatan mereka dan sisi yang tidak begitu baik, dalam kesimpulan ulasan kami akan mencoba menemukan jawaban untuk pertanyaan yang biasanya dipedulikan oleh programmer dalam dilema "OS or not OS" - konteks waktu pengalihan. Ada dua cara yang mungkin di sini: 1) pertimbangan kode sumber lebih merupakan cara teoretis, memerlukan tingkat pencelupan dalam subjek yang belum siap saya tunjukkan, dan 2) percobaan praktis. Tentu saja, metode kedua, tidak seperti yang pertama, tidak memberikan hasil yang benar-benar benar, tetapi "kebenaran selalu konkret" dan data yang diperoleh dapat dianggap memadai jika pengukurannya diatur dengan benar.
Untuk mulai dengan, untuk memperkirakan waktu switching, kita perlu belajar bagaimana mengevaluasi waktu eksekusi keseluruhan dari berbagai fragmen program. Dalam arsitektur ini, ada modul debugging, yang bagiannya adalah penghitung sistem. Informasi tentang modul ini cukup mudah diakses, tetapi iblis, seperti biasa, bersembunyi di detailnya. Pertama, mari kita coba mengkonfigurasi mode yang diperlukan dengan pegangan secara langsung melalui akses ke register. Kami dengan cepat menemukan blok register CPU_DWT dan di dalamnya kami menemukan penghitung CYCCNT itu sendiri dan register kontrol untuknya CTRL dengan bit CYCCNTENA. Tentu saja, atau, seperti yang mereka katakan, tentu saja, tidak ada yang terjadi dan situs web ARM memiliki jawaban untuk pertanyaan mengapa - perlu untuk mengaktifkan modul debugging dengan bit TRCENA dalam register DEMCR. Tetapi register terakhir tidak begitu sederhana - di blok DWT itu tidak ada, di blok lain itu malas untuk mencari - mereka cukup panjang, tapi saya tidak menemukan pencarian dengan nama di jendela register (tetapi akan menyenangkan untuk memilikinya). Kita masuk ke jendela memori, masukkan alamat register (diketahui dari tanggal) (omong-omong, untuk beberapa alasan format heksadesimal dari alamat tidak default, Anda perlu menambahkan awalan 0x dengan pena) dan, tiba-tiba, kita melihat sel memori bernama dengan nama CPU_CSC_DEMCR. Sangat lucu, untuk sedikitnya, mengapa perusahaan mengganti nama register dibandingkan dengan nama yang diusulkan oleh pemberi lisensi arsitektur, mungkin itu perlu. Dan tepatnya, di blok register CPU_CSC kami menemukan register kami, atur bit yang diinginkan di dalamnya, kembali ke konter, aktifkan, dan semuanya bekerja.
Pnp: masih ada pencarian dengan nama, itu disebut (secara alami) oleh kombinasi Ctrl-F, itu hanya ada di menu konteks, tetapi dalam yang biasa dibatalkan, saya minta maaf kepada para pengembang.
Segera saya perhatikan kelemahan lain dari jendela memori - pencetakan konten terputus dengan menunjukkan sel bernama, yang membuat output robek dan ara tidak tersegmentasi menjadi 16 (8.32.64, gantikan kata-kata yang diperlukan). Selain itu, format output berubah ketika jendela diubah ukurannya. Mungkin semua ini dapat dikonfigurasi sesuai kebutuhan pengguna, tetapi, berdasarkan pengalaman saya sendiri (dan apa lagi yang harus saya lanjutkan dari), saya menyatakan bahwa pengaturan format output dari jendela melihat memori tidak berlaku untuk solusi yang jelas secara intuitif. Saya sepenuhnya mendukung mengaktifkan fitur yang nyaman seperti menampilkan area memori bernama di jendela tampilan, jika tidak banyak pengguna tidak akan pernah mengetahuinya, tetapi perhatian juga harus diberikan kepada mereka yang secara sadar ingin menonaktifkannya.
Omong-omong, saya tidak akan sepenuhnya meninggalkan kemungkinan membuat makro (atau skrip) untuk bekerja dengan lingkungan, karena saya harus melakukan pengaturan register ini (untuk mengaktifkan pengukuran waktu) setiap kali setelah mengatur ulang MK, karena saya mempertimbangkan koreksi kode dengan memasukkan manipulasi register untuk keperluan debugging tidak terlalu benar. Tetapi, walaupun saya tidak pernah menemukan makro, bekerja dengan register dapat sangat disederhanakan karena fakta bahwa register individu (yang diperlukan) dapat dimasukkan dalam jendela ekspresi, dan dengan demikian secara signifikan memfasilitasi dan mempercepat pekerjaan dengan mereka.
Untuk menekankan bahwa perasaan insinyur terhadap keluarga MK belum mendingin (jika tidak saya memarahi berbagai aspek lingkungan pengembangan), saya perhatikan bahwa penghitung berfungsi dengan baik - saya tidak dapat menemukan siklus tambahan dalam mode debug mana pun, tetapi sebelum ini terjadi menjadi, setidaknya dalam seri MK, yang dikembangkan oleh LuminaryMicro.
Jadi, kami menguraikan rencana percobaan untuk menentukan waktu pengalihan konteks - membuat tugas kedua yang akan menambah penghitung internal tertentu (dalam loop tak terbatas), memulai MC untuk waktu tertentu, menemukan hubungan antara penghitung sistem dan penghitung tugas. Selanjutnya, mulai MK untuk waktu yang sama (tidak harus persis sama) dan masukkan 10 karakter dengan kecepatan kira-kira sekali per detik. Dapat diharapkan bahwa ini akan menghasilkan 10 peralihan ke tugas gema dan 10 beralih kembali ke tugas penghitung. Ya, sakelar konteks ini akan dilakukan tidak sesuai dengan penghitung waktu sheduler, tetapi menurut acara, tetapi ini tidak akan memengaruhi total waktu eksekusi dari fungsi yang diselidiki, jadi kami mulai mengimplementasikan rencana, membuat tugas penghitung, dan memulainya.
Di sini kita menemukan satu fitur RTOS, setidaknya dalam konfigurasi standar - itu tidak berkerumun "nyata": jika tugas prioritas selalu siap untuk dieksekusi (dan tugas counter adalah itu) dan tidak memberikan kontrol ke sheduler (tidak mengharapkan sinyal, tidak tertidur, tidak diblokir oleh flag, dll.) maka tidak satu pun tugas dengan prioritas lebih rendah akan dieksekusi dari kata sama sekali. Ini bukan Linux, di mana berbagai metode digunakan untuk menjamin bahwa setiap orang mendapatkan kuantum, "sehingga tidak ada yang tersinggung." Perilaku ini diharapkan, banyak RTOS ringan berperilaku seperti ini, tetapi masalahnya lebih dalam, karena manajemen tidak menerima tugas dengan prioritas yang sama dengan yang selalu disiapkan. Itulah sebabnya dalam contoh ini, saya menempatkan tugas gema, yang ditahan, prioritas lebih tinggi daripada tugas konter yang selalu siap, jika tidak maka yang terakhir akan menangkap semua sumber daya prosesor tepat waktu.
Kami memulai percobaan, bagian pertama (hanya menunggu waktu eksekusi) memberikan data pada rasio penghitung 406181 / 58015 = 7 - itu sangat diharapkan. Bagian kedua (dengan 10 karakter berturut-turut selama ~ 10 detik) memberikan hasil 351234k-50167k * 7 = 63k / 20 = 3160 siklus, digit terakhir adalah waktu yang terkait dengan prosedur switching konteks dalam siklus MK. Secara pribadi, nilai ini menurut saya agak lebih besar dari yang diharapkan, kami terus melakukan riset, tampaknya masih ada beberapa tindakan yang merusak statistik.
PNP: kesalahan umum dari seorang eksperimen adalah tidak mengevaluasi hasil yang diharapkan sebelumnya dan percaya pada sampah yang diterima (hai untuk 737 pengembang).
Jelas ("ya, cukup jelas") bahwa hasilnya, selain pengalihan konteks aktual, juga berisi waktu yang diperlukan untuk melakukan operasi membaca karakter dari buffer dan mengeluarkannya ke port serial. Yang kurang jelas adalah bahwa ia juga memiliki waktu untuk memproses interupsi ketika diterima dan menempatkan karakter dalam buffer yang diterima). Bagaimana kita dapat memisahkan kucing dari daging - untuk ini kita memiliki trik yang rumit - kita menghentikan program, memasukkan 10 karakter dan memulainya. Kita dapat mengharapkan (kita harus melihat sumbernya) bahwa interupsi pada penerimaan hanya akan terjadi 1 kali dan segera semua karakter akan dikirim dari buffer terima ke ring satu, yang berarti kita akan melihat lebih sedikit overhead. Juga mudah untuk menentukan waktu pengiriman ke port serial - kami akan menampilkan setiap karakter kedua dan menyelesaikan 2 persamaan linear yang dihasilkan dengan 2 yang tidak diketahui. Dan itu mungkin dan bahkan lebih sederhana - untuk tidak menyimpulkan apa pun, yang saya lakukan.
Dan berikut ini adalah hasil manipulasi yang rumit: kami membuat input oleh paket dan kutu yang hilang menjadi lebih kecil - 2282, matikan output dan biaya turun menjadi 1.222 kutu - lebih baik, meskipun saya berharap untuk 300 kutu.
Tetapi dengan waktu membaca, tidak ada yang seperti ini dapat muncul dengan itu, itu diskalakan pada saat yang sama dengan konteks yang diinginkan mengubah waktu. Satu-satunya hal yang dapat saya tawarkan adalah mematikan timer internal di awal memasukkan karakter yang diterima dan menyalakannya lagi sebelum memasukkan menunggu untuk yang berikutnya. Kemudian dua penghitung akan bekerja secara serempak (dengan pengecualian beralih) dan dapat dengan mudah ditentukan. Namun pendekatan semacam itu membutuhkan implementasi yang mendalam dari program sistem dalam teks, dan masih komponen penanganan interupsi akan tetap ada. Oleh karena itu, saya mengusulkan untuk membatasi diri pada data yang telah diperoleh, yang memungkinkan kami untuk dengan tegas menyatakan bahwa waktu pengalihan tugas dalam TI-RTOS yang dipertimbangkan tidak melebihi siklus 1222 jam, yang untuk frekuensi clock yang diberikan adalah 30 mikrodetik.
PNP: ngomong-ngomong, banyak - saya menghitung siklus pada 100: 30 untuk menyelamatkan konteks, 40 untuk menentukan tugas yang sudah selesai dan 30 untuk memulihkan konteks, tetapi kami mendapatkan urutan lebih besar. Meskipun pengoptimalan telah dimatikan sekarang, hidupkan –o2 dan lihat hasilnya: itu tidak banyak berubah - itu telah menjadi 2894 bukannya 3160.
Ada ide lain - jika OS mendukung switching tugas peer-to-peer, maka Anda dapat menjalankan dua tugas dengan penghitung, secara ajaib mendapatkan data tentang jumlah sakelar dalam beberapa saat dan menghitung hilangnya penghitung sistem, tetapi karena kekhasan sheduler, tentang apa yang saya sudah dikatakan, pendekatan ini tidak akan mengarah pada kesuksesan. Meskipun opsi lain dimungkinkan - untuk melakukan ping-pong antara dua tugas peer-to-peer (atau bahkan peer-to-peer) melalui semaphore, mudah untuk menghitung jumlah switch konteks di sini - Anda harus mencobanya, tetapi itu akan menjadi besok.
Survei tradisional pada akhir posting kali ini akan dikhususkan untuk tidak pada tingkat presentasi (jelas bagi setiap pembaca yang tidak memihak bahwa ia melampaui segala pujian dan melebihi harapan apa pun), tetapi untuk topik posting berikutnya.