14.1.1.4. Otklanjanje pogrešaka u ugrađenom programu (firmware)

Otklanjanje pogrešaka na sklopovlju znači zaustavljanje procesora, postavljanje točaka prekida u C izvornom kodu, izvođenje korak po korak te pregledavanje varijabli, memorije, registara i periferije – sve iz unutrašnjosti VS Code-a. Za to su potrebne tri stvari: debug build, SWD debug sonda (Segger J-Link) i ekstenzija Cortex-Debug koja upravlja programom arm-none-eabi-gdb spojenim na J-Link GDB poslužitelj.

14.1.1.4.1. Izgradnja za otklanjanje pogrešaka

Ciljni program uvijek ponovno izgradite s DEBUG=1

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

Release (DEBUG=0) slika prevodi se s -O2; u debuggeru ćete za mnoge varijable vidjeti <optimized out>, ugrađene (inline) funkcije stapaju se sa svojim pozivateljima, a izvođenje korak po korak nepredvidivo skače. DEBUG=1 gradi s -Og -ggdb3, što je pogodno za otklanjanje pogrešaka uz zadržanu mogućnost pokretanja na kameri. ELF na koji usmjeravate debugger je:

build/<TARGET>/bin/firmware.elf

(Za Alif AE3 otklanjajte pogreške u build/OPENMV_AE3/bin/firmware_M55_HP.elf – visokoučinkovita jezgra.)

14.1.1.4.3. Postavljanje VS Code Cortex-Debug

Stvorite .vscode/launch.json u repozitoriju. Najjednostavniji slučaj – VS Code, J-Link i build svi su na istom Linux / macOS računalu – koristi servertype: "jlink", čime Cortex-Debug sam pokreće J-Link GDB poslužitelj:

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

Promijenite executable i device prema svojoj pločici (vidi tablicu iznad). Pritisnite F5 za izgradnju, flashanje i pokretanje do main te zaustavljanje na tom mjestu.

Savjet

Za automatsku ponovnu izgradnju svaki put kad pokrenete otklanjanje pogrešaka, dodajte zadatak izgradnje u .vscode/tasks.json i referencirajte ga iz konfiguracije pokretanja pomoću "preLaunchTask". Na primjer zadatak koji izvodi make -j$(nproc) TARGET=OPENMV4 DEBUG=1, nazvan "build-firmware", te "preLaunchTask": "build-firmware" u gornjoj konfiguraciji, tako da F5 u jednom koraku ponovno izgradi, flasha i pokrene debugger.

Upozorenje

Cortex-Debug treba arm-none-eabi-gdb. Isporučuje se u SDK-u na lokaciji ~/openmv-sdk-<version>/gcc/bin, ali nije prema zadanim postavkama na PATH, pa otklanjanje pogrešaka ne uspijeva s porukom „GDB executable ‘arm-none-eabi-gdb’ was not found”. Riješite to bilo postavljanjem armToolchainPath / gdbPath kao što je prikazano iznad, bilo dodavanjem ~/openmv-sdk-<version>/gcc/bin u svoj PATH (printenv PATH bi ga tada trebao prikazati).

14.1.1.4.4. Pregled registara periferije (SVD)

Usmjerite Cortex-Debug na CMSIS SVD datoteku kako biste dobili dekodirani pregled registara periferije (mjerači vremena, DMA, sučelje kamere itd.) po nazivu i bitnom polju:

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

Za STM32 i MIMXRT nabavite SVD iz ST / NXP CMSIS paketa ili iz Cortex-Debug SVD registra. Alif SVD-ovi uključeni su u repozitorij ugrađenog programa na lib/micropython/lib/alif_ensemble-cmsis-dfp/Debug/SVD/ (koristite ..._CM55_HP_View.svd za AE3 HP jezgru).

14.1.1.4.6. Otklanjanje pogrešaka iz naredbenog retka pomoću gdbrunner

Ručno postavljanje GDB sesije prema ugrađenom ciljnom uređaju peterostruki je ples: pokrenite J-Link / ST-Link GDB poslužitelj u jednom prozoru s ispravnim uređajem, portom i zastavicama sučelja; pričekajte da ispiše Waiting for GDB connection; pokrenite arm-none-eabi-gdb u drugom prozoru; upišite target remote localhost:<port>; usmjerite gdb na ELF. Kada gdb sesija završi, ne zaboravite ugasiti prozor poslužitelja. gdbrunner je mali CLI koji sve to sažima u jednu naredbu u prednjem planu. Isporučuje se u Python okruženju OpenMV SDK-a, pa nema ništa za instalirati; uobičajena ulazna točka je cilj make debug repozitorija ugrađenog programa:

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

Ovo pokreće gdbrunner s argumentima debuggera iz konfiguracije pločice – J-Link nazivom uređaja i, gdje je potrebno, ST-Link vanjskim flash loaderom – uz SDK-ov arm-none-eabi-gdb koji je već na PATH. Zadana pozadina je J-Link; make DEBUGGER=STLINK debug umjesto toga radi s ST-Link sondom.

gdbrunner se može pozvati i izravno (izvan SDK-a, 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

Prvi pozicijski argument bira pozadinu poslužitelja (jlink, stlink, qemu); ostatak se prosljeđuje toj pozadini, sa zadanim vrijednostima koje rade za OpenMV kamere. gdbrunner --help ispisuje cijeli popis zastavica po pozadini; tablica argumenata svake pozadine vođena je JSON-om (src/gdbrunner/backends.json), pa je dodavanje novog poslužitelja izmjena konfiguracije, a ne koda.

Što gdbrunner radi za rad iz naredbenog retka:

  • Jedan proces, čist životni ciklus. Poslužitelj se pokreće, gdb se pričvršćuje kada je port otvoren, a poslužitelj se uredno gasi kada gdb izađe. Nema zaostalog JLinkGDBServer koji preživljava sesiju, nema dva terminala za upravljanje.

  • STM32CubeProgrammer automatsko otkrivanje. Pozadina stlink pretražuje uobičajene lokacije instalacije (~/STM32CubeProgrammer/, /opt/st/, stablo dodataka STM32CubeIDE) za STM32CubeProgrammer alate, tako da se duga putanja --cube-prog ne mora upisivati svaki put. SDK uključuje vlastitu kopiju na ~/openmv-sdk-<version>/stcubeprog/bin – usmjerite --cube-prog tamo ako nema instalacije na sustavu.

  • Poštivanje gdbinit-a po projektu. .gdbinit u trenutnom direktoriju učitava se s -ix – nadjačavajući korisnički ~/.gdbinit – tako da se gdb skriptiranje po projektu (pretty-printeri, makroi specifični za pločicu, skupovi točaka prekida) uključuje samim svojim postojanjem u radnom direktoriju. make debug izvodi se iz korijena repozitorija, pa se primjenjuje .gdbinit tamo.

  • Suho pokretanje. --dryrun ispisuje naredbu poslužitelja bez pokretanja, korisno za prilagodbu poziva omotač skripti, kopiranje u konfiguraciju IDE pokretača ili jednostavno provjeru koje argumente gdbrunner sastavlja.

  • Vidljiv izlaz poslužitelja. --show-output zadržava stdout / stderr poslužitelja vidljivim. Zadana postavka ga potiskuje (kako bi gdb-ovo sučelje ostalo čisto); preokrenite zastavicu kada se sam poslužitelj loše ponaša.

  • QEMU pozadina. qemu-system-arm otklanja pogreške u izgrađenom ugrađenom programu bez priključene pločice. Cilj MPS2_AN500 bira ovu pozadinu u svojoj konfiguraciji pločice, pa make TARGET=MPS2_AN500 DEBUG=1 debug gradi za QEMU-ov stroj mps2-an500 i prolazi kroz kod neovisan o platformi – sve što ne dotiče periferiju specifičnu za kameru – u letu. (qemu-system-arm je instalacija na hostu, nije dio SDK-a.)

Za izvođenje korak po korak na razini izvornog koda s prikazom točaka prekida na rubu i pregledom registara periferije, gornje VS Code Cortex-Debug postavljanje bolji je alat; gdbrunner je pravi za sve što živi u naredbenom retku.

14.1.1.4.7. Korištenje debuggera

Kada sesija radi (procesor zaustavljen na main):

  • Točke prekida – kliknite rub uz C redak ili u Debug Console upišite break <file>:<line> / break <function>. Cortex-M jezgre imaju malen broj hardverskih komparatora točaka prekida (obično 6–8 na M7 / H7, 8 na M55). Premašivanje tog broja na kodu u flash memoriji tiho ne uspijeva – održavajte broj aktivnih točaka prekida umjerenim.

  • Izvođenje korak po korakF10 korak preko (next), F11 korak u (step), Shift+F11 korak van (finish), F5 nastavi. Izvođenje na razini instrukcija je stepi / nexti u Debug Console.

  • Varijable / watch / poziv stog – okna Variables i Call Stack prikazuju lokalne varijable i trag poziva; dodajte izraze u Watch. Zadržite pokazivač iznad varijable u izvornom kodu da vidite njezinu vrijednost. Sve što prikazuje <optimized out> znači da niste na DEBUG=1 buildu.

  • Watchpointi (podatkovne točke prekida)watch <expr> zaustavlja kada se u varijablu piše, rwatch pri čitanju, awatch pri oboje. Cortex-M DWT jedinica podržava ~4 hardverska watchpointa – neprocjenjivo za hvatanje tko je oštetio varijablu.

  • Registri i periferija – pregled Cortex Registers prikazuje registre jezgre; uz postavljen svdFile, pregled Peripherals dekodira svaki registar periferije i bitno polje (DMA, mjerači vremena, sučelje kamere / CSI, XSPI itd.) – najbrži način da vidite zašto se upravljački program loše ponaša.

  • Memorija – koristite Cortex-Debug preglednik memorije ili gdb x/ za izravan pregled međuspremnika slika, DMA međuspremnika i struktura.

  • printf bez zaustavljanja (SWO/RTT) – za probleme osjetljive na vremenske odnose, Segger RTT ili SWO daje printf s gotovo nultim opterećenjem dok ciljni uređaj radi. Izgradite s DEBUG_PRINTF=1 i dodajte Cortex-Debug-ov rttConfig (RTT) ili swoConfig (SWO, treba takt jezgre). Ovo je pravi alat kada bi točka prekida promijenila vremenske odnose koje pokušavate promatrati.

  • OdspajanjeStop na launch sesiji zaustavlja ciljni uređaj; Disconnect na attach sesiji ostavlja kameru u radu. Nakon toga ponovno uključite napajanje kamere da je vratite u normalan rad.

14.1.1.4.8. Zamke pri otklanjanju pogrešaka

  • Optimizacijom uklonjene varijable. Sve prikazuje <optimized out> – izgradili ste DEBUG=0. Ponovno izgradite s DEBUG=1.

  • „GDB executable not found” – SDK-ov gcc/bin nije na PATH; postavite armToolchainPath / gdbPath.

  • „Cannot connect” / pogrešna memorijska mapa – pogrešan ili nedostajeći device naziv; koristite točan niz iz tablice.

  • Točke prekida tiho se ne pogađaju – previše hardverskih točaka prekida na kodu koji se nalazi u flash memoriji; smanjite ih.

  • Putanje izvornog koda se ne podudaraju (ELF izgrađen Dockerom) – gradite s Docker ciljem build-firmware-dev (ista apsolutna putanja unutar i izvan kontejnera) ili postavite gdb set substitute-path.