Artikel ini adalah tentang proyek open source pertama saya "repl" (link ke repositori di bawah). Ide dari proyek ini adalah untuk memungkinkan programmer mikrokontroler untuk men-debug program di mikrokontroler melalui salah satu antarmuka, sementara debugging tidak jauh berbeda dari debugging melalui antarmuka jtag. Itu mungkin untuk menghentikan program, mengatur breakpoint, melihat register, memori, dengan debugging instruktif program.
Hal pertama yang terlintas dalam pikiran adalah membuat aplikasi 2x, salah satu utas bertanggung jawab untuk antarmuka debugging, yang lainnya untuk program pengguna, yang saya lakukan. Beralih di antara utas dilakukan pada timer, setiap utas memiliki tumpukannya sendiri. Saya memutuskan untuk tidak menggunakan banyak alat untuk menulis antarmuka debugging. mereka harus digunakan 2 berbeda, atau saat bekerja dengan heap, terus beralih ke satu utas.
Ide pertama implementasi untuk debugging instruksional adalah untuk mengurangi waktu antara interupsi pengatur waktu secukupnya sehingga hanya 1 instruksi yang dapat dieksekusi. Opsi ini menunjukkan kerja yang ideal pada mikrokontroler Atmega328p, faktanya waktu minimum antar interupsi untuk Atmega adalah 1 jam prosesor, setiap instruksi, berapa pun jumlah siklus jam yang diperlukan untuk pelaksanaannya, akan selalu berakhir jika eksekusinya telah dimulai.
Sayangnya, ketika saya beralih ke stm32, opsi ini tidak berfungsi, karena inti Cortex-M dapat mengganggu pelaksanaan instruksi di tengah, dan kemudian, setelah kembali dari interupsi, mulai menjalankannya lagi. Kemudian saya memutuskan dengan baik, tidak ada masalah, saya hanya akan menambah jumlah siklus jam antara interupsi sampai instruksi dijalankan, kemudian saya menemukan masalah lain, beberapa instruksi dijalankan hanya dengan instruksi yang mengikutinya atau tidak dieksekusi sama sekali, sayangnya masalah ini tidak dapat diselesaikan, jadi saya memutuskan untuk mengubah pendekatan secara radikal.
Saya memutuskan untuk meniru instruksi ini. Sekilas, ide untuk membuat emulator inti Cortex M, dan bahkan yang cocok dengan memori mikrokontroler, terlihat fantastis. Tetapi saya menyadari bahwa saya tidak perlu meniru semua instruksi, tetapi hanya yang terkait dengan penghitung program, jumlahnya tidak begitu banyak. Sisanya saya dapat dengan mudah pindah ke lokasi memori lain dan mengeksekusi di sana, dan sehingga hanya satu instruksi yang dijalankan, tambahkan instruksi lompat "b" setelahnya.
Dan kemudian pergantian breakpoints datang, untuk implementasinya saya memutuskan untuk menggunakan instruksi yang mengimplementasikan while (1); logic. Kami mengganti instruksi, yang terletak di alamat di mana kami ingin meletakkan breakpoint dan menunggu interupsi timer. Saya mengerti bahwa sesuatu seperti instruksi yang akan memberikan pengecualian akan lebih baik, tetapi saya ingin membuat versi universal. Saat dijalankan, kami mengganti instruksi ini kembali. Pilihan yang baik adalah menjalankan program di RAM mikrokontroler, jika tidak, memori flash mikrokontroler tidak akan bertahan lama. Tetapi pada titik ini saya sudah selesai menulis emulator instruksi untuk stm32 dan memutuskan mengapa tidak menulis yang sama untuk Atmega328 dan menulisnya. Sekarang Anda tidak perlu mengganti instruksi kembali; mereka dapat ditiru.
Untuk membuat semua ini berteman dengan runtime, pertama-tama saya ingin menulis klien gdb saya sendiri. Sayangnya, ini mendukung dua antarmuka untuk bekerja dengan ide. Terserah dia untuk memutuskan ide mana yang akan digunakan. Menerapkan keduanya (yang pertama menurut saya cukup sederhana, yang kedua tidak terlalu), ditambah lagi saya harus menggabungkan sumber dengan firmware, yang menurut saya bukan ide yang sangat bagus. Jadi saya memutuskan untuk menulis gdbserver saya sendiri, untungnya hanya ada satu protokol dan itu cukup sederhana.
Antarmuka pertama saya, yang saya putuskan untuk diterapkan, adalah GSM. Sebagai transceiver, saya memutuskan untuk menggunakan SIM800, sebagai server, server dengan dukungan php. Ide utamanya adalah bahwa setelah kedatangan permintaan posting dari mikrokontroler, pertahankan koneksi ke mikrokontroler selama 30 detik dan hubungi database setiap 100 ms, jika data muncul untuk mengirimkannya sebagai respons atas permintaan dan tunggu permintaan berikutnya dari mikrokontroler.
Sambungan pertama klien gdb ke server menunjukkan bahwa ada terlalu banyak permintaan dari klien gdb ke server dengan perintah jeda atau langkah. Oleh karena itu, diputuskan untuk menggabungkan semua permintaan ini menjadi satu permintaan besar untuk mikrokontroler, untuk ini saya memahami logika permintaan ini dan mempelajari cara memprediksinya. Sekarang perintah-perintah ini tidak dijalankan begitu cepat, saya ingin lebih cepat, tetapi dapat ditahan.
Antarmuka berikutnya adalah usb, untuk mikrokontroler Atmega328 saya memutuskan untuk menggunakan perpustakaan V-usb. Untuk bekerja dengan usb, saya menulis ulang logika perintah run. Sekarang mikrokontroler setelah perintah ini tidak memulai program menunggu perintah jeda, itu memulainya selama 1 detik, kemudian perintah jalankan baru dikirim ke sana, dll. Logika ini diperlukan karena Saya menonaktifkan antarmuka saat program sedang berjalan. Untuk menyelamatkan diri dari masalah menulis driver, saya memutuskan untuk menggunakan driver hid standar. Karena fitur komunikasi menyembunyikan laporan fitur, menyembunyikan laporan fitur.
Adapun flashing mikrokontroler, saya memutuskan bahwa ini berlebihan untuk antarmuka usb, jadi untuk firmware pertama Anda masih memerlukan programmer. Tapi untuk interface GSM paling banyak. Biasanya, program terpisah ditulis untuk tujuan ini, tetapi saya memutuskan untuk melakukannya secara berbeda, untuk tempat penulisan program terpisah, saya memutuskan untuk memuat program sepenuhnya ke dalam memori flash mikrokontroler, kemudian setelah pengunduhan selesai, salin program ini ke awal memori. Kemudian saya berpikir mengapa saya harus mengirim seluruh program, saya hanya dapat mengirim perbedaan antara file biner saat ini dan sebelumnya dari firmware.
Untuk meminimalkan perbedaan ini, saya memutuskan untuk mengganti nama bagian array .text, .data, .bss, .contructors untuk bagian dari program pengguna (nama umum berbeda untuk mikrokontroler yang berbeda) dan menempatkannya di memori tepat setelah program utama.
Saya juga harus menulis fungsi saya sendiri untuk menginisialisasi bagian ini. Sekarang, dalam banyak kasus, perubahan program kecil sama dengan perubahan biner kecil yang sama dengan sejumlah kecil data yang ditransfer. Akibatnya, mikrokontroler sering berkedip lebih cepat daripada perintah RUN, STEP, PAUSE.
Dan akhirnya, video kerja:
Stm32 debugging melalui antarmuka usb.
Debugging Stm32 melalui antarmuka gsm.
Debugging Atmega328 melalui antarmuka usb.
Debugging Atmega328 melalui antarmuka gsm.
Repositori Git