14.1.1.4. Aygıt yazılımının hata ayıklaması

Donanım üzerinde hata ayıklama, işlemciyi durdurmak, C kaynağında kesme noktaları ayarlamak, tek adım adım ilerlemek ve değişkenleri, belleği, yazmaçları ve çevre birimlerini incelemek anlamına gelir – hepsi VS Code içinden. Bunun için üç şey gerekir: bir hata ayıklama derlemesi (debug build), bir SWD hata ayıklama probu (bir Segger J-Link) ve bir J-Link GDB sunucusuna karşı arm-none-eabi-gdb çalıştıran Cortex-Debug uzantısı.

14.1.1.4.1. Hata ayıklama için derleme

Hedefi her zaman DEBUG=1 ile yeniden derleyin:

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

Bir sürüm (DEBUG=0) imajı -O2 ile derlenir; hata ayıklayıcıda birçok değişken için <optimized out> görürsünüz, satır içine alınmış işlevler çağıranların içinde toplanır ve adım adım ilerleme öngörülemez biçimde sıçrar. DEBUG=1 ise -Og -ggdb3 ile derler; bu, kamera üzerinde hâlâ önyükleme yapabilirken hata ayıklanabilir olmasını sağlar. Hata ayıklayıcıyı yönlendirdiğiniz ELF şudur:

build/<TARGET>/bin/firmware.elf

(Alif AE3 için build/OPENMV_AE3/bin/firmware_M55_HP.elf dosyasında hata ayıklayın – yüksek performanslı çekirdek.)

14.1.1.4.3. VS Code Cortex-Debug kurulumu

Depoda .vscode/launch.json oluşturun. En basit durum – VS Code, J-Link ve derlemenin tümü aynı Linux / macOS makinesinde olduğunda – Cortex-Debug’ın kendisinin bir J-Link GDB sunucusu başlatmasını sağlayan servertype: "jlink" kullanır:

{
  "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"
    }
  ]
}

Kartınıza göre executable ve device değerlerini değiştirin (yukarıdaki tabloya bakın). main işlevine kadar derle-flash’la-ve-çalıştır işlemini yapıp orada durmak için F5 tuşuna basın.

Tüyo

Hata ayıklamayı her başlattığınızda otomatik olarak yeniden derlemek için .vscode/tasks.json dosyasına bir derleme görevi ekleyin ve başlatma yapılandırmasından "preLaunchTask" ile ona referans verin. Örneğin, "build-firmware" adında make -j$(nproc) TARGET=OPENMV4 DEBUG=1 çalıştıran bir görev ile yukarıdaki yapılandırmadaki "preLaunchTask": "build-firmware" birlikte, böylece F5 tek bir adımda yeniden derler, flash’lar ve hata ayıklayıcıyı başlatır.

Uyarı

Cortex-Debug arm-none-eabi-gdb gerektirir. SDK’da ~/openmv-sdk-<version>/gcc/bin konumunda gelir ancak varsayılan olarak PATH üzerinde değildir, bu nedenle hata ayıklama “GDB executable ‘arm-none-eabi-gdb’ was not found” hatasıyla başarısız olur. Bunu ya yukarıda gösterildiği gibi armToolchainPath / gdbPath ayarlayarak ya da PATH ortam değişkeninize ~/openmv-sdk-<version>/gcc/bin ekleyerek düzeltin (printenv PATH o zaman onu listelemelidir).

14.1.1.4.4. Çevre birimi yazmaç görünümü (SVD)

Çözümlenmiş bir çevre birimi yazmaç görünümü (zamanlayıcılar, DMA, kamera arabirimi vb.) ada ve bit alanına göre elde etmek için Cortex-Debug’ı bir CMSIS SVD dosyasına yönlendirin:

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

STM32 ve MIMXRT için SVD’yi ST / NXP CMSIS paketlerinden veya Cortex-Debug SVD kayıt defterinden alın. Alif SVD’leri, aygıt yazılımı deposunda lib/micropython/lib/alif_ensemble-cmsis-dfp/Debug/SVD/ konumunda dahili olarak yer alır (AE3 HP çekirdeği için ..._CM55_HP_View.svd kullanın).

14.1.1.4.6. gdbrunner ile komut satırı hata ayıklaması

Gömülü bir hedefe karşı bir GDB oturumunu elle kurmak beş adımlı bir danstır: J-Link / ST-Link GDB sunucusunu bir pencerede doğru cihaz, bağlantı noktası ve arabirim bayraklarıyla başlatın; Waiting for GDB connection yazdırmasını bekleyin; ikinci bir pencerede arm-none-eabi-gdb çalıştırın; target remote localhost:<port> yazın; gdb’yi ELF’e yönlendirin. gdb oturumu sona erdiğinde sunucu penceresini kapatmayı unutmayın. gdbrunner, tüm bunları tek bir ön plan komutunda toplayan küçük bir CLI’dir. OpenMV SDK’sının Python ortamında gelir, bu nedenle kurulacak bir şey yoktur; her zamanki giriş noktası aygıt yazılımı deposunun make debug hedefidir:

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

Bu, gdbrunner’ı kartın yapılandırmasındaki hata ayıklayıcı argümanlarıyla – J-Link cihaz adı ve gerektiğinde ST-Link harici flash yükleyici – ve SDK’nın arm-none-eabi-gdb aracı zaten PATH üzerindeyken çalıştırır. Varsayılan arka uç J-Link’tir; make DEBUGGER=STLINK debug ise bunun yerine bir ST-Link probuyla çalışır.

gdbrunner doğrudan da çağrılabilir (SDK dışında, 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

İlk konumsal argüman sunucu arka ucunu seçer (jlink, stlink, qemu); geri kalanlar, OpenMV kameraları için çalışan varsayılanlarla birlikte o arka uca iletilir. gdbrunner --help her arka uca özel tam bayrak listesini gösterir; her arka ucun argüman tablosu JSON tabanlıdır (src/gdbrunner/backends.json), bu nedenle yeni bir sunucu eklemek kod değişikliği yerine bir yapılandırma düzenlemesidir.

gdbrunner’ın komut satırı çalışmaları için yaptıkları:

  • Tek işlem, temiz yaşam döngüsü. Sunucu başlar, bağlantı noktası açıldığında gdb bağlanır, gdb çıktığında sunucu temiz biçimde sonlandırılır. Oturumdan sağ kalan başıboş bir JLinkGDBServer yok, yönetilecek iki terminal yok.

  • STM32CubeProgrammer otomatik keşfi. stlink arka ucu, STM32CubeProgrammer araçları için her zamanki kurulum konumlarını (~/STM32CubeProgrammer/, /opt/st/, STM32CubeIDE eklenti ağacı) arar, böylece uzun --cube-prog yolunun her seferinde yazılması gerekmez. SDK, ~/openmv-sdk-<version>/stcubeprog/bin konumunda kendi kopyasını paketler – sistemde kurulu bir kopya yoksa --cube-prog öğesini buraya yönlendirin.

  • Proje başına gdbinit dikkate alınır. Geçerli dizindeki bir .gdbinit dosyası -ix ile yüklenir – kullanıcı genelindeki ~/.gdbinit dosyasını geçersiz kılarak – böylece proje başına gdb betikleme (pretty-printer’lar, karta özgü makrolar, kesme noktası kümeleri) çalışma dizininde bulunarak devreye girer. make debug depo kökünden çalışır, bu nedenle oradaki bir .gdbinit geçerli olur.

  • Kuru çalıştırma. --dryrun sunucu komutunu çalıştırmadan yazdırır; çağrıyı bir sarmalayıcı betiğe uyarlamak, bir IDE başlatıcı yapılandırmasına kopyalamak veya yalnızca gdbrunner’ın hangi argümanları oluşturduğunu kontrol etmek için yararlıdır.

  • Sunucu çıktısı görünür. --show-output sunucunun stdout / stderr çıktısını görünür tutar. Varsayılan bunu bastırır (böylece gdb’nin arabirimi temiz kalır); hatalı davranan şeyin sunucunun kendisi olduğu durumlarda bayrağı açın.

  • QEMU arka ucu. qemu-system-arm hiçbir kart takılı olmadan bir aygıt yazılımı derlemesinde hata ayıklar. MPS2_AN500 hedefi, kart yapılandırmasında bu arka ucu seçer, böylece make TARGET=MPS2_AN500 DEBUG=1 debug QEMU’nun mps2-an500 makinesi için derleme yapar ve platformdan bağımsız kodda – kameraya özgü çevre birimlerine dokunmayan her şey – adım adım ilerler; uçuş halindeyken. (qemu-system-arm bir host kurulumudur, SDK’nın parçası değildir.)

Kesme noktası kenarlıkları ve bir çevre birimi yazmaç görünümüyle kaynak düzeyinde adım adım ilerlemek için yukarıdaki VS Code Cortex-Debug kurulumu daha iyi bir araçtır; gdbrunner ise komut satırında yaşayan her şey için doğru olandır.

14.1.1.4.7. Hata ayıklayıcının kullanımı

Bir oturum çalışmaya başladığında (işlemci main işlevinde durdurulmuş halde):

  • Kesme noktaları – bir C satırının yanındaki kenarlığa tıklayın veya Debug Console’da break <file>:<line> / break <function> yazın. Cortex-M çekirdeklerinde az sayıda donanımsal kesme noktası karşılaştırıcısı bulunur (genellikle M7 / H7 üzerinde 6–8, M55 üzerinde 8). Flash’taki kod üzerinde bunu aşmak sessizce başarısız olur – etkin kesme noktası sayısını mütevazı tutun.

  • Adım adım ilerlemeF10 üzerinden geç (next), F11 içine gir (step), Shift+F11 dışarı çık (finish), F5 devam et. Komut düzeyinde adım adım ilerleme Debug Console’da stepi / nexti ile yapılır.

  • Değişkenler / izleme / çağrı yığınıVariables ve Call Stack bölmeleri yerel değişkenleri ve geri izlemeyi gösterir; Watch öğesine ifadeler ekleyin. Değerini görmek için kaynaktaki bir değişkenin üzerine gelin. <optimized out> gösteren her şey, bir DEBUG=1 derlemesinde olmadığınız anlamına gelir.

  • İzleme noktaları (veri kesme noktaları)watch <expr> bir değişkene yazıldığında durur, rwatch okumada, awatch ise her ikisinde de durur. Cortex-M DWT birimi ~4 donanımsal izleme noktasını destekler – bir değişkeni kimin bozduğunu yakalamak için paha biçilmezdir.

  • Yazmaçlar ve çevre birimleriCortex Registers görünümü çekirdek yazmaçlarını gösterir; svdFile ayarlandığında Peripherals görünümü her çevre birimi yazmacını ve bit alanını çözümler (DMA, zamanlayıcılar, kamera / CSI arabirimi, XSPI vb.) – bir sürücünün neden hatalı davrandığını görmenin en hızlı yolu.

  • Bellek – çerçeve arabelleklerini, DMA arabelleklerini ve yapıları doğrudan incelemek için Cortex-Debug bellek görüntüleyicisini veya gdb x/ komutunu kullanın.

  • Durdurma olmadan printf (SWO/RTT) – zamanlamaya duyarlı sorunlar için Segger RTT veya SWO, hedef çalışırken neredeyse sıfır ek yüklü printf sağlar. DEBUG_PRINTF=1 ile derleyin ve Cortex-Debug’ın rttConfig (RTT) veya swoConfig (SWO, çekirdek saatine ihtiyaç duyar) yapılandırmasını ekleyin. Bir kesme noktasının gözlemlemeye çalıştığınız zamanlamayı değiştireceği durumlarda doğru araç budur.

  • Bağlantıyı kesme – bir launch oturumunda Stop hedefi durdurur; bir attach oturumunda Disconnect kamerayı çalışır halde bırakır. Daha sonra normal çalışmasına döndürmek için kameranın gücünü kapatıp açın.

14.1.1.4.8. Hata ayıklama tuzakları

  • Optimize edilerek çıkarılmış değişkenler. Her şey <optimized out> gösteriyor – DEBUG=0 ile derlediniz. DEBUG=1 ile yeniden derleyin.

  • “GDB executable not found” – SDK gcc/bin PATH üzerinde değil; armToolchainPath / gdbPath ayarlayın.

  • “Cannot connect” / yanlış bellek haritası – yanlış veya eksik device adı; tablodaki tam dizeyi kullanın.

  • Kesme noktalarına sessizce ulaşılmıyor – flash’ta yer alan kod üzerinde çok fazla donanımsal kesme noktası var; bunları azaltın.

  • Kaynak yolları eşleşmiyor (Docker ile derlenmiş ELF) – Docker build-firmware-dev hedefiyle derleyin (kapsayıcının içinde ve dışında aynı mutlak yol) veya gdb set substitute-path ayarlayın.