Bagaimana cara saya menggunakan pengendali interupsi yang sama secara efisien untuk setiap port periferal (identik)?

(Mudah-mudahan) versi sederhana dari masalah saya:

Katakanlah saya menggunakan setiap port GPIO di MCU korteks M-4 saya untuk melakukan hal yang persis sama, seperti membaca port pada perubahan level pin. Saya telah menyederhanakan kode saya sehingga menjadi port-agnostik, tetapi saya mengalami masalah dengan solusi yang bagus untuk menggunakan kembali fungsi pengendali interupsi yang sama.

  1. Apakah ada cara agar saya dapat menggunakan fungsi pengendali interupsi yang sama sambil memiliki metode untuk menemukan port mana yang memicu interupsi? Idealnya beberapa O(1)/tidak ditingkatkan tergantung pada berapa banyak port yang dimiliki papan.
  2. Haruskah saya memiliki penangan berbeda untuk setiap port yang memanggil fungsi yang sama yang menggunakan parameter port? (Yang terbaik yang bisa saya pikirkan sejauh ini)

Jadi seperti:

void worker (uint32_t gpio_id) {
    *work goes here*
}

void GPIOA_IRQ_Handler(void) { worker(GPIOA_id); }
void GPIOB_IRQ_Handler(void) { worker(GPIOB_id); }
void GPIOC_IRQ_Handler(void) { worker(GPIOC_id); }
...

Masalah saya yang sebenarnya:

Saya belajar dan mengutak-atik FreeRTOS dan membuat driver sederhana untuk debug/stdio UART, beberapa tombol yang ada di dev. papan, seterusnya. Sejauh ini saya telah membuat driver untuk periferal/port tertentu.

Sekarang saya ingin membuat driver I2C tanpa mengetahui antarmuka mana yang akan saya gunakan (ada 10 port I2C di mcu saya), dan berpotensi mengizinkan kode driver digunakan pada beberapa port secara bersamaan. Saya tahu semua port yang digunakan pada waktu kompilasi.

Saya punya ide yang cukup bagus tentang cara membuat driver menjadi port-agnostic, kecuali saya sedang memikirkan cara yang bagus untuk menemukan port mana yang memicu interupsi menggunakan fungsi handler tunggal. (selain menelusuri status interupsi setiap port karena itu O(n)).

Seperti saya katakan, hal terbaik yang saya temukan adalah tidak memiliki satu penangan dan sebagai gantinya memiliki penangan berbeda pada tabel vektor yang semuanya memanggil fungsi pekerja yang sama di dalamnya dan meneruskan parameter port. Metode ini mengacaukan kode driver, namun merupakan O(1) (kecuali jika Anda mempertimbangkan kompleksitas kode).

  1. Apakah saya melakukan semua ini salah dan harus membuatnya tetap bodoh dan mengimplementasikan driver sesuai dengan port/kasus penggunaan yang sebenarnya saya perlukan dengan cara yang paling sederhana? (bahkan tidak punya rencana untuk menggunakan beberapa bus I2C, meskipun itu akan menarik untuk diterapkan)

Terima kasih sebelumnya, semoga postingannya tidak terlalu ambigu atau panjang (saya rasa agak panjang maaf).


person EmbeddedManuel    schedule 03.07.2020    source sumber
comment
Anda dapat memiliki penangan untuk masing-masing penangan, penangan tersebut menetapkan register untuk menunjukkan interupsi mana yang kemudian dicabangkan ke penangan umum yang kemudian dapat menggunakan register itu atau petunjuk apa pun. Ya jelas Anda dapat mengatur penangan yang sama untuk setiap/setiap interupsi jika diinginkan.   -  person old_timer    schedule 03.07.2020
comment
Apa masalahmu sebenarnya di sini? Konsumsi flash? Seberapa besar pawang Anda?   -  person old_timer    schedule 03.07.2020
comment
Masalah saya pada dasarnya adalah bagaimana menghindari duplikasi kode dengan menggunakan fungsi penangan yang sama untuk beberapa interupsi, tetapi juga memiliki metode kompleksitas konstan untuk menemukan perangkat sumber interupsi. Saya juga tidak yakin apakah ada cara untuk mencapainya, yang mungkin menghasilkan postingan/pertanyaan yang membingungkan.   -  person EmbeddedManuel    schedule 03.07.2020
comment
Handlernya tidak terlalu besar. Untuk masalah saya yang sebenarnya tentang driver I2C, itu hanya akan menjadi standar pengiriman/penerimaan byte berikutnya jika ada; bangun tugas ketika tidak ada lagi byte untuk diproses, yang bisa lebih sederhana jika saya menggunakan operasi DMA, tapi saya tidak ingin membahasnya lebih dalam sekarang.   -  person EmbeddedManuel    schedule 03.07.2020
comment
Jika Anda dapat memfaktorkan parameter individual apa pun, pilih solusi 2 dari posting Anda. Namun, Anda perlu menulis semua baris *handler() { ...} ini, karena baris tersebut memberikan argumen spesifik dan biasanya memasang vektor. Menggunakan trik perakitan yang cerdik akan membuat sumbernya sulit dipelihara. -- Saya akan mulai dengan 2 penangan, masing-masing diimplementasikan dalam penangan yang diluncurkan sendiri. Selanjutnya saya akan mengembangkan algoritma akhir, DMA atau apa pun. Hanya kemudian saya akan menyelidiki di mana perbedaannya, dan mempertimbangkan refactoring dalam arti KERING.   -  person the busybee    schedule 03.07.2020
comment
@EmbeddedManuel DMA sendiri mungkin sulit untuk disiapkan, tetapi dapat menghasilkan kode yang lebih cepat dan lebih mudah dibaca secara keseluruhan. Terutama ketika berhadapan dengan bus serial seperti I2C atau UART, memiliki pemicu interupsi per byte yang diterima cukup menyakitkan (walaupun cara lama dalam melakukan sesuatu).   -  person Lundin    schedule 03.07.2020
comment
@thebusybee Ya itulah yang akan saya lakukan. Posting ini benar-benar lebih merupakan jaminan bahwa saya melakukan segala sesuatunya dengan benar daripada apa pun, yang berguna karena ini adalah proyek solo ke wilayah yang kurang lebih baru. Terima kasih untuk umpan baliknya!   -  person EmbeddedManuel    schedule 06.07.2020
comment
@Lundin Saya sepenuhnya setuju! Saya pasti ingin mengimplementasikan DMA, khususnya karena saya mengimplementasikan ini untuk FreeRTOS. Satu-satunya alasan sebenarnya saya ragu untuk melakukannya adalah karena untuk board saya (tiva seri C) Anda hanya dapat mengaktifkan DMA untuk slave atau master di I2C, jadi penerapannya memerlukan kerja ekstra untuk memeriksa & mengaturnya. dengan aman. Pasti ada dalam tugas saya haha   -  person EmbeddedManuel    schedule 06.07.2020


Jawaban (1)


  1. Apakah ada cara agar saya dapat menggunakan fungsi pengendali interupsi yang sama sambil memiliki metode untuk menemukan port mana yang memicu interupsi?

Hanya jika interupsi yang berbeda dihapus dengan cara yang sama dan aplikasi Anda tidak peduli pin mana yang memicu interupsi tersebut. Kasus penggunaan yang sangat tidak mungkin.

  1. Haruskah saya memiliki penangan berbeda untuk setiap port yang memanggil fungsi yang sama yang menggunakan parameter port?

Ya, itulah yang biasanya aku lakukan. Anda harus meneruskan parameter dari ISR ​​ke fungsi, yang unik untuk interupsi tertentu. Penting: perhatikan bahwa fungsinya harus inline static! ISR yang cepat jauh lebih penting daripada menghemat sedikit flash dengan menggunakan kembali fungsi yang sama. Jadi dalam kode mesin Anda akan memiliki 4 ISR berbeda dengan fungsi pekerja yang ada di dalamnya. (Mungkin ingin menonaktifkan inlining dalam debug build.)

Apakah saya melakukan semua ini dengan salah dan harus membuatnya tetap bodoh

Sepertinya Anda melakukannya dengan benar. Driver yang ditulis dengan benar harus mampu menangani beberapa perangkat keras dengan kode yang sama. Meskipun demikian, pemrogram C cenderung terobsesi untuk menghindari pengulangan kode. KISS seringkali jauh lebih masuk akal daripada menghindari pengulangan kode. Menghindari pengulangan tentu saja bagus, tapi bukan prioritas utama Anda di sini.

Prioritas dalam hal ini adalah yang terpenting terlebih dahulu:

  1. Interupsi secepat dan setipis mungkin.
  2. Kode yang dapat dibaca.
  3. Ukuran lampu kilat yang digunakan.
  4. Menghindari pengulangan kode.
person Lundin    schedule 03.07.2020
comment
Terima kasih, Anda menjawab semua keraguan saya, terutama pada pertanyaan terakhir. Sayangnya ini adalah akun baru, saya tidak dapat melakukan upvote. +1 sekalipun - person EmbeddedManuel; 06.07.2020