14.1.1.4. Men-debug firmware

Debugging pada hardware berarti menghentikan prosesor, menetapkan breakpoint dalam source C, melakukan single-stepping, dan memeriksa variabel, memori, register, dan periferal -- dari dalam VS Code. Ini membutuhkan tiga hal: sebuah debug build, sebuah SWD debug probe (Segger J-Link), dan ekstensi Cortex-Debug yang menjalankan arm-none-eabi-gdb terhadap J-Link GDB server.

14.1.1.4.1. Build untuk debugging

Selalu build ulang target dengan DEBUG=1

make -j$(nproc) TARGET=<TARGET> DEBUG=1

Citra rilis (DEBUG=0) dikompilasi dengan -O2; di debugger Anda akan melihat <optimized out> untuk banyak variabel, fungsi-fungsi yang di-inline menyatu ke pemanggilnya, dan stepping melompat-lompat secara tidak terduga. DEBUG=1 di-build dengan -Og -ggdb3, yang dapat di-debug namun tetap bisa booting pada kamera. ELF yang Anda arahkan ke debugger adalah:

build/<TARGET>/bin/firmware.elf

(Untuk Alif AE3, debug build/OPENMV_AE3/bin/firmware_M55_HP.elf -- core berkinerja tinggi.)

14.1.1.4.3. Pengaturan VS Code Cortex-Debug

Buat .vscode/launch.json di repositori. Kasus paling sederhana -- VS Code, J-Link, dan build semuanya berada pada mesin Linux / macOS yang sama -- menggunakan servertype: "jlink", yang membuat Cortex-Debug memulai J-Link GDB server sendiri:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "OpenMV J-Link",
      "type": "cortex-debug",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "executable": "${workspaceFolder}/build/OPENMV4/bin/firmware.elf",
      "servertype": "jlink",
      "device": "STM32H743VI",
      "interface": "swd",
      "runToEntryPoint": "main",
      "armToolchainPath": "${env:HOME}/openmv-sdk-1.6.0/gcc/bin",
      "gdbPath": "${env:HOME}/openmv-sdk-1.6.0/gcc/bin/arm-none-eabi-gdb"
    }
  ]
}

Ubah executable dan device untuk board Anda (lihat tabel di atas). Tekan F5 untuk build-flash-and-run ke main dan berhenti di sana.

Tip

Untuk melakukan build ulang otomatis setiap kali Anda memulai debugging, tambahkan build task ke .vscode/tasks.json dan referensikan dari launch config dengan "preLaunchTask". Misalnya sebuah task yang menjalankan make -j$(nproc) TARGET=OPENMV4 DEBUG=1, bernama "build-firmware", ditambah "preLaunchTask": "build-firmware" dalam konfigurasi di atas, sehingga F5 melakukan build ulang, flashing, dan memulai debugger dalam satu langkah.

Peringatan

Cortex-Debug membutuhkan arm-none-eabi-gdb. Ia disertakan dalam SDK di ~/openmv-sdk-<version>/gcc/bin tetapi tidak berada di PATH secara default, sehingga debugging gagal dengan "GDB executable 'arm-none-eabi-gdb' was not found". Perbaiki dengan mengatur armToolchainPath / gdbPath seperti ditunjukkan di atas, atau dengan menambahkan ~/openmv-sdk-<version>/gcc/bin ke PATH Anda (printenv PATH kemudian harus menampilkannya).

14.1.1.4.4. Tampilan register periferal (SVD)

Arahkan Cortex-Debug ke file CMSIS SVD untuk mendapatkan tampilan register periferal yang telah diterjemahkan (timer, DMA, antarmuka kamera, dll.) berdasarkan nama dan bitfield:

"svdFile": "/path/to/STM32H743.svd"

Untuk STM32 dan MIMXRT, dapatkan SVD dari paket CMSIS ST / NXP atau registri SVD Cortex-Debug. SVD Alif disertakan dalam repositori firmware di lib/micropython/lib/alif_ensemble-cmsis-dfp/Debug/SVD/ (gunakan ..._CM55_HP_View.svd untuk core HP AE3).

14.1.1.4.6. Debugging command-line dengan gdbrunner

Menyiapkan sesi GDB terhadap target tertanam secara manual adalah proses lima langkah: mulai J-Link / ST-Link GDB server di satu jendela dengan flag perangkat, port, dan antarmuka yang tepat; tunggu hingga mencetak Waiting for GDB connection; jalankan arm-none-eabi-gdb di jendela kedua; ketik target remote localhost:<port>; arahkan gdb ke ELF. Ketika sesi gdb berakhir, ingat untuk mematikan jendela server. gdbrunner adalah CLI kecil yang menggabungkan semua itu menjadi satu perintah foreground. Ia disertakan dalam lingkungan Python SDK OpenMV, jadi tidak ada yang perlu dipasang; titik masuk biasanya adalah target make debug repositori firmware:

make -j$(nproc) TARGET=<TARGET> DEBUG=1 debug

Ini menjalankan gdbrunner dengan argumen debugger dari konfigurasi board -- nama perangkat J-Link dan, bila diperlukan, flash loader eksternal ST-Link -- dengan arm-none-eabi-gdb SDK sudah ada di PATH. Backend default adalah J-Link; make DEBUGGER=STLINK debug bekerja dengan probe ST-Link.

gdbrunner juga dapat dipanggil langsung (di luar SDK, pip install gdbrunner):

gdbrunner jlink --device STM32H743VI build/OPENMV4/bin/firmware.elf
gdbrunner stlink build/OPENMV4/bin/firmware.elf
gdbrunner qemu --machine mps2-an500 build/MPS2_AN500/bin/firmware.elf

Argumen posisional pertama memilih backend server (jlink, stlink, qemu); sisanya diteruskan ke backend tersebut, dengan default yang berfungsi untuk kamera OpenMV. gdbrunner --help mencantumkan daftar flag per-backend lengkap; tabel argumen setiap backend didorong oleh JSON (src/gdbrunner/backends.json), sehingga menambahkan server baru adalah pengeditan konfigurasi bukan kode.

Yang dilakukan gdbrunner untuk pekerjaan command-line:

  • Satu proses, lifecycle bersih. Server dimulai, gdb terhubung saat port terbuka, server dihentikan dengan bersih saat gdb keluar. Tidak ada JLinkGDBServer yatim yang bertahan setelah sesi, tidak ada dua terminal yang perlu dikelola.

  • Penemuan otomatis STM32CubeProgrammer. Backend stlink mencari lokasi instalasi yang umum (~/STM32CubeProgrammer/, /opt/st/, pohon plugin STM32CubeIDE) untuk alat STM32CubeProgrammer, sehingga path --cube-prog yang panjang tidak perlu diketik setiap saat. SDK menyertakan salinannya sendiri di ~/openmv-sdk-<version>/stcubeprog/bin -- arahkan --cube-prog ke sana jika tidak ada instalasi sistem.

  • gdbinit per-proyek dihormati. Sebuah .gdbinit di direktori saat ini dimuat dengan -ix -- mengesampingkan ~/.gdbinit yang berlaku untuk seluruh pengguna -- sehingga skrip gdb per-proyek (pretty-printer, makro spesifik board, set breakpoint) aktif dengan hanya menempatkannya di direktori kerja. make debug dijalankan dari root repositori, sehingga .gdbinit di sana berlaku.

  • Dry run. --dryrun mencetak perintah server tanpa menjalankannya, berguna untuk menyesuaikan pemanggilan ke skrip wrapper, menyalinnya ke konfigurasi launcher IDE, atau hanya memeriksa argumen apa yang disusun oleh gdbrunner.

  • Output server terlihat. --show-output membuat stdout / stderr server tetap terlihat. Default menekannya (agar UI gdb tetap bersih); balik flag saat server itulah yang bermasalah.

  • Backend QEMU. qemu-system-arm men-debug build firmware tanpa board yang terhubung. Target MPS2_AN500 memilih backend ini dalam konfigurasi boardnya, sehingga make TARGET=MPS2_AN500 DEBUG=1 debug di-build untuk mesin QEMU mps2-an500 dan menelusuri kode yang independen dari platform -- semua yang tidak menyentuh periferal spesifik kamera -- dalam simulasi. (qemu-system-arm adalah instalasi host, bukan bagian dari SDK.)

Untuk stepping level source dengan gutter breakpoint dan tampilan register periferal, pengaturan VS Code Cortex-Debug di atas adalah alat yang lebih baik; gdbrunner adalah alat yang tepat untuk semua yang berada di command line.

14.1.1.4.7. Menggunakan debugger

Setelah sesi berjalan (prosesor berhenti di main):

  • Breakpoint -- klik gutter di sebelah baris C, atau di Debug Console break <file>:<line> / break <function>. Core Cortex-M memiliki sejumlah kecil hardware breakpoint comparator (biasanya 6--8 pada M7 / H7, 8 pada M55). Melebihi itu pada kode di flash akan gagal secara diam-diam -- jaga agar jumlah breakpoint aktif tetap terbatas.

  • Stepping -- F10 step over (next), F11 step into (step), Shift+F11 step out (finish), F5 lanjutkan. Stepping tingkat instruksi adalah stepi / nexti di Debug Console.

  • Variabel / watch / call stack -- panel Variables dan Call Stack menampilkan variabel lokal dan backtrace; tambahkan ekspresi ke Watch. Arahkan kursor ke variabel di source untuk melihat nilainya. Apa pun yang menampilkan <optimized out> berarti Anda tidak menggunakan build DEBUG=1.

  • Watchpoint (data breakpoint) -- watch <expr> berhenti saat variabel ditulis, rwatch saat dibaca, awatch untuk keduanya. Unit DWT Cortex-M mendukung ~4 hardware watchpoint -- sangat berharga untuk menangkap siapa yang merusak variabel.

  • Register dan periferal -- tampilan Cortex Registers menampilkan register inti; dengan svdFile diatur, tampilan Peripherals mendekode setiap register periferal dan bitfield (DMA, timer, antarmuka kamera / CSI, XSPI, dll.) -- cara tercepat untuk melihat mengapa driver bermasalah.

  • Memori -- gunakan penampil memori Cortex-Debug atau x/ gdb untuk memeriksa buffer bingkai, buffer DMA, dan struktur secara langsung.

  • printf tanpa menghentikan (SWO/RTT) -- untuk masalah yang sensitif terhadap waktu, Segger RTT atau SWO memberikan printf dengan overhead hampir nol saat target berjalan. Build dengan DEBUG_PRINTF=1 dan tambahkan rttConfig (RTT) atau swoConfig (SWO, membutuhkan clock inti) dari Cortex-Debug. Ini adalah alat yang tepat ketika breakpoint akan mengubah timing yang sedang Anda amati.

  • Memutuskan koneksi -- Stop pada sesi launch menghentikan target; Disconnect pada sesi attach membiarkan kamera tetap berjalan. Matikan dan hidupkan kembali kamera untuk mengembalikannya ke operasi normal setelahnya.

14.1.1.4.8. Jebakan dalam debugging

  • Variabel ter-optimasi-keluar. Semuanya menampilkan <optimized out> -- Anda membangun dengan DEBUG=0. Build ulang dengan DEBUG=1.

  • "GDB executable not found" -- SDK gcc/bin tidak ada di PATH; atur armToolchainPath / gdbPath.

  • "Cannot connect" / peta memori salah -- nama device salah atau tidak ada; gunakan string yang tepat dari tabel.

  • Breakpoint diam-diam tidak terpicu -- terlalu banyak hardware breakpoint pada kode yang berada di flash; kurangi jumlahnya.

  • Path source tidak cocok (ELF yang di-build dengan Docker) -- build dengan target Docker build-firmware-dev (path absolut yang sama di dalam dan di luar container) atau atur gdb set substitute-path.