Kami saat ini menggunakan Mikrokontroler PIC32 32-bit. Ini berfungsi dengan baik untuk kebutuhan kita, tetapi kami juga mengeksplorasi mikrokontroler lain yang dapat menyesuaikan kami dengan lebih baik + kami memiliki proyek lain yang kami pilih MCU. Untuk tujuan itu kami telah memilih mikrokontroler SAM DA berbasis ARM yang sama 32-bit tetapi berbasis ARM (lebih populer daripada PIC32 - bijaksana industri).
Sekarang untuk PIC32 kita menggunakan MPLAB tetapi untuk ARM cortex-M0, kita akan menggunakan Atmel Studio. Kami akan menggunakan bahasa-C di kedua platform. Hal yang menjadi perhatian saya adalah, kami akan menggunakan dua mikrokontroler 32 bit (dari perusahaan yang sama) tetapi memiliki arsitektur yang berbeda. Ini akan mengharuskan kita mempelajari dua perangkat yang berbeda dan akan meningkatkan "kurva belajar" + waktu pengiriman kami. Tetapi di sisi lain, saya juga berpikir karena kita akan menggunakan bahasa-C dalam kedua kasus tersebut, kurva pembelajaran untuk ARM seharusnya tidak terlalu terdengar dan perlu untuk mengeksplorasi prosesor itu juga.
Pertanyaan utama saya adalah, seberapa besar perbedaan arsitektur ketika kita memprogram dalam Bahasa-C karena menyediakan abstraksi internal mikrokontroler. Dan apa perbedaan utama dalam MPLAP dan Atmel Studio , mengingat pemrograman bahasa-C.
sumber
Jawaban:
Ini topik yang cukup banyak pendapat. Saya bisa berbicara sendiri (AVR, ARM, MSP430).
Perbedaan 1 (paling signifikan) ada di periferal. Masing-masing MCU memiliki UART, SPI, timer dll. - hanya daftar nama dan bit berbeda. Sebagian besar waktu itu adalah masalah utama yang harus saya tangani saat memindahkan kode di antara chip. Solusi: tulis driver Anda dengan API umum, sehingga aplikasi Anda bisa dibawa-bawa.
Perbedaan 2 adalah arsitektur memori. Jika Anda ingin menempatkan konstanta dalam flash pada AVR Anda harus menggunakan atribut khusus dan fungsi khusus untuk membacanya. Di dunia ARM Anda hanya melakukan dereferensi pointer karena ada ruang alamat tunggal (saya tidak tahu bagaimana PIC kecil menanganinya, tetapi akan menganggap bahwa mereka lebih dekat ke AVR).
Perbedaan 3 adalah deklarasi dan penanganan interupsi.
avr-gcc
memilikiISR()
makro. ARM hanya memiliki nama fungsi (seperti someUART_Handler () - jika Anda menggunakan header CMSIS dan kode startup). Vektor interupsi ARM dapat ditempatkan di mana saja (termasuk RAM) dan dimodifikasi saat runtime (sangat berguna jika Anda memiliki misalnya dua protokol UART berbeda yang dapat diaktifkan). AVR hanya memiliki opsi untuk menggunakan vektor baik di "flash utama" atau "bagian bootloader" (jadi jika Anda ingin menangani interupsi secara berbeda, Anda harus menggunakanif
pernyataan).Perbedaan 4 - mode tidur dan kontrol daya. Jika Anda membutuhkan konsumsi daya terendah, maka Anda harus meningkatkan semua fitur MCU. Ini dapat sangat berbeda antara MCU - beberapa memiliki mode hemat daya yang lebih kasar, beberapa dapat mengaktifkan / menonaktifkan periferal individu. Beberapa MCU memiliki regulator yang dapat diatur sehingga Anda dapat menjalankannya dengan tegangan lebih rendah pada kecepatan yang lebih rendah dll. Saya tidak melihat cara mudah untuk mencapai efisiensi yang sama pada MCU (katakanlah) dengan 3 mode daya global dan lainnya dengan 7 mode daya dan kontrol jam periferal individu.
Satu-satunya hal terpenting ketika merawat portabilitas adalah dengan membagi kode Anda dengan jelas menjadi bagian-bagian yang bergantung pada perangkat keras (driver) dan perangkat keras (aplikasi) yang independen. Anda dapat mengembangkan dan menguji yang terakhir pada PC biasa dengan driver tiruan (mis. Konsol alih-alih UART). Ini menyelamatkan saya berkali-kali karena 90% dari kode aplikasi selesai sebelum perangkat keras prototipe keluar dari oven reflow :)
Menurut pendapat saya hal yang baik tentang ARM adalah "monokultur" - ketersediaan banyak kompiler (gcc, Keil, IAR ... untuk beberapa nama), banyak IDE yang didukung secara gratis dan resmi (setidaknya untuk NXP, STM32, Silicon Labs, Nordik), banyak alat debug (SEGGER - terutama Ozon, ULINK, OpenOCD ...) dan banyak vendor chip (Saya bahkan tidak akan mulai memberi nama). PIC32 sebagian besar terbatas pada Microchip (tetapi itu hanya masalah jika Anda tidak suka alat mereka.
Ketika datang ke kode C. Itu 99% sama,
if
pernyataan sama, loop bekerja dengan cara yang sama. Namun Anda harus peduli tentang ukuran kata asli. Misalnyafor
loop pada AVR tercepat jika Anda gunakanuint8_t
untuk penghitung, sedangkan pada ARMuint32_t
adalah tipe tercepat (atauint32_t
). ARM harus memeriksa 8-bit overflow setiap kali jika Anda menggunakan tipe yang lebih kecil.Memilih MCU dan / atau vendor pada umumnya sebagian besar tentang politik dan logistik (kecuali jika Anda memiliki kendala teknik yang sangat jelas, misalnya: MSP430 atau Vorago yang menggunakan temperatur tinggi). Bahkan jika aplikasi dapat berjalan pada apa saja dan hanya 5% dari kode (driver) harus dikembangkan dan didukung selama masa pakai produk - itu masih merupakan biaya tambahan bagi perusahaan. Semua tempat saya bekerja memiliki vendor favorit dan MCU (seperti "pilih Kinetis yang Anda inginkan kecuali ada alasan yang sangat baik untuk memilih sesuatu yang berbeda"). Ini juga membantu jika Anda memiliki orang lain untuk meminta bantuan, jadi sebagai manajer saya akan menghindari memiliki departemen pengembangan 5 orang di mana setiap orang menggunakan chip yang sama sekali berbeda.
sumber
Saya telah menggunakan beberapa MCU dari empat produsen yang berbeda. Pekerjaan utama setiap waktu sekali lagi adalah membiasakan diri dengan peripheral.
Misalnya UART itu sendiri tidak terlalu rumit dan saya menemukan port driver saya dengan mudah. Tetapi terakhir kali saya butuh hampir satu hari untuk mendapatkan jam, pin I / O mengganggu, mengaktifkan dll diselesaikan.
GPIO bisa sangat kompleks. Bit-set, bit-clear, bit-toggle, Fungsi khusus mengaktifkan / menonaktifkan, tri-state. Selanjutnya Anda mendapatkan interupsi: ujung-ujung, naik, turun, level-rendah, level-tinggi, kliring sendiri atau tidak.
Lalu ada I2C, SPI, PWM, Timers dan dua lusin lebih jenis periferal masing-masing dengan jam mereka sendiri memungkinkan dan setiap kali register berbeda dengan bit baru. Untuk semua itu, dibutuhkan berjam-jam membaca lembar data cara mengatur bit mana dalam keadaan apa.
Pabrikan terakhir memiliki banyak contoh kode yang saya temukan tidak dapat digunakan. Segalanya disarikan. Tetapi ketika saya menelusurinya, kodenya menembus enam! tingkat panggilan fungsi untuk mengatur bit GPIO. Bagus jika Anda memiliki prosesor 3GHz tetapi tidak pada MCU 48MHz. Kode saya pada akhirnya adalah satu baris:
Saya telah mencoba menggunakan lebih banyak driver generik tetapi saya menyerah. Pada MCU Anda selalu berjuang dengan siklus ruang dan jam. Saya menemukan bahwa lapisan abstraksi adalah yang pertama keluar jendela jika Anda menghasilkan bentuk gelombang tertentu dalam rutinitas interupsi yang disebut 10KHz.
Jadi sekarang saya memiliki semuanya berfungsi dan saya berencana untuk TIDAK beralih lagi kecuali untuk alasan yang sangat, sangat bagus.
Semua hal di atas harus diamortisasi atas berapa banyak produk yang Anda jual dan apa yang Anda simpan. Jual sejuta: hemat 0,10 untuk beralih ke jenis yang berbeda berarti Anda dapat menghabiskan 100.000 untuk jam kerja perangkat lunak. Jual 1000 yang Anda miliki hanya 100 untuk dibelanjakan.
sumber
OUTPUT_HI(n)
yang akan menghasilkan kode yang setara denganGPIOD->bssr |= 0x400;
jikan
konstanta seperti 0x6A, tetapi panggil subrutin sederhana jikan
ada tidak konstan. Yang telah dikatakan, sebagian besar API vendor yang saya lihat berkisar antara biasa-biasa saja dan mengerikan.Ini lebih merupakan pendapat / komentar daripada jawaban.
Anda tidak ingin dan tidak seharusnya pemrograman dalam C. C ++, bila digunakan dengan cara yang benar , jauh lebih unggul. (OK, saya harus akui, ketika digunakan dengan cara yang salah itu jauh lebih buruk daripada C.) Yang membatasi Anda untuk chip yang memiliki kompiler C ++ (modern), yang kira-kira semuanya didukung oleh GCC, termasuk AVR (dengan beberapa keterbatasan, filo menyebutkan masalah ruang alamat yang tidak seragam), tetapi mengecualikan hampir semua PIC (PIC32 dapat didukung, tapi saya belum melihat port yang layak).
Ketika Anda memprogram algoritma dalam C / C ++ perbedaan antara pilihan yang Anda sebutkan kecil (kecuali bahwa chip 8 atau 16 bit akan sangat dirugikan ketika Anda melakukan banyak aritmatika bit 16, 32 atau lebih tinggi). Ketika Anda membutuhkan ons kinerja terakhir, Anda mungkin perlu menggunakan assembler (baik kode Anda sendiri atau yang disediakan oleh vendor atau pihak ketiga). Dalam hal ini Anda mungkin ingin mempertimbangkan kembali chip yang Anda pilih.
Ketika Anda membuat kode ke perangkat keras Anda dapat menggunakan beberapa lapisan abstraksi (sering disediakan oleh pabrikan) atau menulis sendiri (berdasarkan lembar data dan / atau kode contoh). IME abstraksi C yang ada (mbed, cmsis, ...) sering berfungsi (hampir) benar, tetapi gagal dalam kinerja (periksa old old bart sekitar 6 lapisan tipuan untuk operasi set pin), kegunaan dan portabilitas. Mereka ingin mengekspos semua fungsionalitas chip tertentu kepada Anda, yang dalam hampir semua kasus Anda tidak perlu dan lebih suka tidak peduli, dan itu mengunci kode Anda ke vendor tertentu (dan mungkin chip tertentu).
Inilah yang C ++ dapat melakukan jauh lebih baik: ketika dilakukan dengan benar, set pin dapat melewati 6 atau lebih lapisan abstraksi (karena itu membuat antarmuka yang lebih baik (portabel!) Dan kode lebih pendek mungkin), namun menyediakan antarmuka yang independen terhadap target untuk kasus sederhana , dan masih menghasilkan kode mesin yang sama seperti yang Anda tulis di assembler .
Cuplikan gaya pengkodean yang saya gunakan, yang bisa membuat Anda bersemangat atau berpaling dengan ngeri:
Pada kenyataannya ada beberapa lapisan abstraksi lagi. Namun penggunaan akhir led, katakanlah untuk menyalakannya, tidak menunjukkan kompleksitas atau rincian target (untuk arduin uno atau pil biru ST32 kode akan identik).
Kompiler tidak terintimidasi oleh semua lapisan itu, dan karena tidak ada fungsi virtual yang terlibat, pengoptimal melihat semuanya (beberapa detail, dihilangkan, seperti mengaktifkan jam periferal):
Begitulah cara saya akan menulisnya di assembler - JIKA saya menyadari bahwa register PIO dapat digunakan dengan offset dari basis umum. Dalam hal ini saya mungkin akan, tetapi kompiler jauh lebih baik dalam mengoptimalkan hal-hal seperti itu daripada saya.
Jadi sejauh yang saya punya jawaban, itu adalah: menulis lapisan abstraksi untuk perangkat keras Anda, tetapi lakukan di C ++ modern (konsep, template) sehingga tidak membahayakan kinerja Anda. Dengan itu, Anda dapat beralih dengan mudah ke chip lain. Anda bahkan dapat mulai mengembangkan beberapa chip acak yang telah Anda letakkan, familiair dengan, memiliki alat debugging yang baik untuk, dll. Dan menunda pilihan terakhir sampai nanti (ketika Anda memiliki lebih banyak info tentang memori yang diperlukan, kecepatan CPU dll).
IMO salah satu kesalahan dari pengembangan yang disematkan adalah memilih chip terlebih dahulu (ini adalah pertanyaan yang sering ditanyakan di forum ini: chip mana yang harus saya pilih untuk .... Jawaban terbaik umumnya: tidak masalah.)
(sunting - respons terhadap "Jadi, kinerja bijak, C atau C ++ akan berada pada level yang sama?")
Untuk konstruksi yang sama, C dan C ++ adalah sama. C ++ memiliki lebih banyak konstruksi untuk abstraksi (hanya beberapa: kelas, templat, constexpr) yang dapat, seperti alat apa pun, digunakan untuk yang baik atau yang buruk. Untuk membuat diskusi lebih menarik: tidak semua orang setuju apa yang baik atau buruk ...
sumber
Jika saya memahaminya dengan benar, Anda ingin tahu fitur spesifik arsitektur apa dari platform "pop up" di lingkungan bahasa C Anda, membuatnya lebih sulit untuk menulis kode portabel yang dapat dirawat di kedua platform.
C sudah cukup fleksibel karena merupakan "perakit portabel". Semua platform yang Anda pilih memiliki GCC / kompiler komersial yang tersedia yang memiliki dukungan untuk standar bahasa C89 dan C99, yang berarti Anda dapat menjalankan kode yang sama di semua platform.
Ada beberapa pertimbangan:
Beberapa platform / kompiler dapat menyembunyikan "batasan" ini lebih baik daripada yang lain. Misalnya pada AVR Anda perlu menggunakan makro tertentu untuk membaca data ROM. Pada PIC24 / dsPIC ada juga instuksi tblrd khusus yang tersedia. Namun di samping itu beberapa bagian juga memiliki fitur "visibilitas ruang program" (PSVPAG) tersedia yang memungkinkan untuk memetakan halaman FLASH ke dalam RAM, membuat pengalamatan data langsung tersedia tanpa tblrd. Kompiler dapat melakukan ini dengan cukup efektif.
ARM dan MIPS adalah Von Neumann, sehingga memiliki wilayah memori untuk ROM, RAM dan periferal yang dikemas ke dalam 1 bus. Anda tidak akan melihat perbedaan antara membaca data dari RAM atau "ROM".
Di sisi lain PIC24 memungkinkan operasi ALU untuk membaca & menulis data secara langsung melalui pengalamatan tidak langsung (bahkan dengan modifikasi pointer ..). Ini memiliki beberapa karakteristik dari arsitektur seperti CISC, sehingga 1 instruksi dapat melakukan lebih banyak pekerjaan. Desain ini dapat menyebabkan core CPU yang lebih kompleks, jam yang lebih rendah, konsumsi daya yang lebih tinggi, dll. Untungnya bagi Anda bagian tersebut sudah dirancang. ;-)
Perbedaan-perbedaan ini dapat berarti bahwa PIC24 dapat "lebih punchy" dengan operasi I / O dibandingkan dengan chip ARM atau MIPS yang serupa. Namun, Anda mungkin mendapatkan bagian clocker ARM / MIPS yang jauh lebih tinggi untuk kendala harga / paket / desain yang sama. Saya kira untuk istilah praktis, saya pikir banyak "mempelajari platform" semakin memahami apa yang bisa dan tidak bisa dilakukan arsitektur, seberapa cepat beberapa set operasi, dll.
Perbedaan-perbedaan ini dapat dienkapsulasi oleh driver perangkat, tetapi pada akhirnya firmware yang tertanam memiliki tingkat tinggi dari penggabungan dengan perangkat keras, sehingga pekerjaan kustom terkadang tidak dapat dihindari.
Juga, jika Anda meninggalkan ekosistem Microchip / Atmel sebelumnya, Anda mungkin menemukan bahwa bagian-bagian ARM memerlukan lebih banyak pengaturan untuk menjalankannya. Maksud saya dalam hal; mengaktifkan jam ke periferal, kemudian mengkonfigurasi periferal dan "mengaktifkan" mereka, mengatur NVIC secara terpisah, dll. Ini hanya bagian dari kurva pembelajaran. Setelah Anda ingat untuk melakukan semua hal ini, dalam urutan yang benar, menulis driver perangkat untuk semua mikrokontroler ini akan terasa sangat mirip di beberapa titik.
sumber
Iya dan tidak. Dari perspektif programmer Anda idealnya menyembunyikan detail set instruksi. Tapi itu sampai batas tertentu sudah tidak relevan periferal yang merupakan inti dari penulisan program ini bukan bagian dari set instruksi. Sekarang pada saat yang sama Anda tidak dapat hanya membandingkan 4096Byte bagian flash di set instruksi tersebut, terutama jika menggunakan C, jumlah konsumsi flash / memori sangat ditentukan oleh set instruksi dan kompiler, beberapa seharusnya tidak pernah melihat kompiler (batuk PIC batuk) karena berapa banyak limbah sumber daya tersebut dikonsumsi dengan menyusun. Lain-lain konsumsi flash adalah overhead yang lebih kecil. Kinerja juga merupakan masalah ketika menggunakan bahasa tingkat tinggi dan masalah kinerja dalam aplikasi MCU, sehingga dapat membuat perbedaan antara menghabiskan $ 3 per papan untuk MCU atau $ 1.
Jika ini tentang membuat pemrograman lebih mudah (dengan biaya keseluruhan produk) Anda harus dapat mengunduh paket pengembang untuk MCU sehingga arsitektur set instruksi adalah sesuatu yang tidak pernah Anda lihat, jadi jika itu adalah perhatian utama Anda, itu bukan masalah. Ini masih membutuhkan uang Anda sejauh biaya produk untuk menggunakan perpustakaan ini, tetapi, waktu untuk memasarkan mungkin lebih pendek, saya menemukan perpustakaan membutuhkan lebih banyak waktu / pekerjaan untuk digunakan vs berbicara langsung dengan periferal.
Intinya set instruksi adalah yang paling sedikit dari kekhawatiran Anda, beralih ke masalah nyata.
sumber