@ vicatcu jawabannya cukup komprehensif. Satu hal tambahan yang perlu diperhatikan adalah bahwa CPU dapat mengalami kondisi tunggu (siklus CPU terhenti) saat mengakses I / O, termasuk memori program dan data.
Misalnya, kami menggunakan DSP TI F28335; beberapa area RAM adalah keadaan 0-tunggu untuk program dan memori data, jadi ketika Anda mengeksekusi kode dalam RAM, itu berjalan pada 1 siklus per instruksi (kecuali untuk instruksi yang membutuhkan lebih dari 1 siklus). Ketika Anda mengeksekusi kode dari memori FLASH (EEPROM bawaan, lebih atau kurang), namun, itu tidak dapat berjalan pada 150MHz penuh dan beberapa kali lebih lambat.
Sehubungan dengan kode interupsi berkecepatan tinggi, Anda harus mempelajari sejumlah hal.
Pertama, menjadi sangat akrab dengan kompiler Anda. Jika kompiler melakukan pekerjaan dengan baik, seharusnya tidak lebih lambat dari perakitan kode tangan untuk kebanyakan hal. (di mana "yang jauh lebih lambat": faktor 2 akan baik-baik saja bagi saya; faktor 10 akan tidak dapat diterima) Anda perlu belajar bagaimana (dan kapan) menggunakan bendera optimisasi kompiler, dan setiap kali sesekali Anda harus melihat di keluaran kompiler untuk melihat bagaimana hasilnya.
Beberapa hal lain yang dapat Anda lakukan pada kompiler untuk mempercepat kode:
gunakan fungsi sebaris (tidak ingat apakah C mendukung ini atau jika hanya C ++ - ism), baik untuk fungsi kecil maupun untuk fungsi yang akan dieksekusi hanya sekali atau dua kali. Kelemahannya adalah fungsi inline sulit untuk di-debug, terutama jika optimisasi kompiler dihidupkan. Tetapi mereka menyelamatkan Anda urutan panggilan / kembali tidak perlu, terutama jika abstraksi "fungsi" adalah untuk tujuan desain konseptual daripada implementasi kode.
Lihatlah manual kompiler Anda untuk melihat apakah ia memiliki fungsi intrinsik - ini adalah fungsi bawaan yang bergantung pada kompiler yang memetakan langsung ke instruksi perakitan prosesor; beberapa prosesor memiliki instruksi perakitan yang melakukan hal-hal berguna seperti min / max / bit mundur dan Anda dapat menghemat waktu melakukannya.
Jika Anda melakukan perhitungan numerik, pastikan Anda tidak memanggil fungsi perpustakaan matematika secara tidak perlu. Kami memiliki satu kasus di mana kode itu seperti y = (y+1) % 4
untuk penghitung yang memiliki periode 4, mengharapkan kompiler untuk mengimplementasikan modulo 4 sebagai bitwise-AND. Sebaliknya itu disebut perpustakaan matematika. Jadi kami diganti dengan y = (y+1) & 3
untuk melakukan apa yang kami inginkan.
Biasakan diri dengan halaman hack bit-twiddling . Saya jamin Anda akan menggunakan paling tidak salah satunya.
Anda juga harus menggunakan periferal timer CPU Anda untuk mengukur waktu eksekusi kode - kebanyakan dari mereka memiliki timer / penghitung yang dapat diatur untuk dijalankan pada frekuensi clock CPU. Tangkap salinan penghitung di awal dan akhir kode kritis Anda, dan Anda dapat melihat berapa lama. Jika Anda tidak bisa melakukan itu, alternatif lain adalah menurunkan pin output di awal kode Anda, dan menaikkannya di akhir, dan lihat output ini pada osiloskop untuk menentukan waktu pelaksanaannya. Ada pengorbanan untuk setiap pendekatan: penghitung waktu internal / counter lebih fleksibel (Anda dapat mengatur waktu beberapa hal) tetapi lebih sulit untuk mendapatkan informasi, sedangkan pengaturan / kliring pin output segera terlihat pada ruang lingkup dan Anda dapat menangkap statistik, tetapi sulit untuk membedakan banyak acara.
Akhirnya, ada keterampilan yang sangat penting yang datang dengan pengalaman - baik umum dan dengan kombinasi prosesor / kompiler tertentu: mengetahui kapan dan kapan tidak mengoptimalkan . Secara umum jawabannya adalah jangan optimalkan. Kutipan Donald Knuth sering diposting di StackOverflow (biasanya hanya bagian terakhir):
Kita harus melupakan efisiensi kecil, katakanlah sekitar 97% dari waktu: optimasi prematur adalah akar dari semua kejahatan
Tetapi Anda berada dalam situasi di mana Anda tahu harus melakukan semacam optimasi, jadi inilah saatnya untuk menggigit peluru dan mengoptimalkan (atau mendapatkan prosesor yang lebih cepat, atau keduanya). Apakah TIDAK menulis seluruh ISR Anda dalam perakitan. Itu hampir merupakan bencana yang dijamin - jika Anda melakukannya, dalam beberapa bulan atau bahkan beberapa minggu Anda akan melupakan bagian dari apa yang Anda lakukan dan mengapa, dan kode ini cenderung sangat rapuh dan sulit untuk diubah. Namun, ada kemungkinan bagian-bagian kode Anda yang merupakan kandidat yang baik untuk perakitan.
Tanda-tanda bahwa bagian-bagian kode Anda sangat cocok untuk pengkodean perakitan:
- fungsi yang terkandung dengan baik, rutinitas kecil yang terdefinisi dengan baik tidak akan berubah
- fungsi yang dapat memanfaatkan instruksi perakitan khusus (min / maks / shift kanan / dll)
- fungsi yang dipanggil berkali-kali (memberi Anda pengganda: jika Anda menyimpan 0,5 usec pada setiap panggilan, dan dipanggil 10 kali, itu menghemat 5 usec yang penting dalam kasus Anda)
Pelajari konvensi pemanggilan fungsi kompiler Anda (mis. Di mana ia menempatkan argumen dalam register, dan register mana yang disimpan / dipulihkan) sehingga Anda dapat menulis rutinitas perakitan yang dapat dipanggil-C.
Dalam proyek saya saat ini, kami memiliki basis kode yang cukup besar dengan kode kritis yang harus dijalankan dalam interupsi 10kHz (100usec - sound familiar?) Dan tidak ada banyak fungsi yang ditulis dalam perakitan. Yang ada, adalah hal-hal seperti perhitungan CRC, antrian perangkat lunak, ADC gain / kompensasi kompensasi.
Semoga berhasil!