14.1.1.4. A firmware hibakeresése¶
A hardveres hibakeresés azt jelenti, hogy megállítjuk a processzort, töréspontokat helyezünk el a C forráskódban, lépésenként haladunk, valamint változókat, memóriát, regisztereket és perifériákat vizsgálunk – mindezt a VS Code-on belül. Ehhez három dolog szükséges: egy debug build, egy SWD debug szonda (egy Segger J-Link) és a Cortex-Debug bővítmény, amely az arm-none-eabi-gdb eszközt vezérli egy J-Link GDB szerverrel szemben.
14.1.1.4.1. Build hibakereséshez¶
Mindig fordítsd újra a célt a DEBUG=1 kapcsolóval:
make -j$(nproc) TARGET=<TARGET> DEBUG=1
A release (DEBUG=0) image -O2 optimalizálással fordul; a hibakeresőben sok változónál <optimized out> jelenik meg, az inline függvények beolvadnak a hívóikba, a lépkedés pedig kiszámíthatatlanul ugrál. A DEBUG=1 -Og -ggdb3 beállítással fordít, ami hibakereshető, miközben még elindul a kamerán. Az ELF, amelyre a hibakeresőt irányítod, a következő:
build/<TARGET>/bin/firmware.elf
(Az Alif AE3 esetén a build/OPENMV_AE3/bin/firmware_M55_HP.elf fájlt kell hibakeresni – a nagy teljesítményű mag.)
14.1.1.4.2. A hardver: J-Link SWD-n keresztül¶
Csatlakoztass egy Segger J-Link szondát a kamera SWD lábaihoz (SWDIO, SWCLK, GND, és referenciaként a cél VCC; a kamera szokás szerint USB-ről kap tápot). Egy J-Link EDU / Base / Pro mind működik. Az, hogy a debug lábak hol bukkannak elő, kameránként eltér – sok panelen dedikált JTAG/SWD csatlakozó van, mások az I/O fejlécen vagy tesztpontokon teszik elérhetővé az SWD-t – ezért nézd meg az adott panel lábkiosztási diagramját és kapcsolási rajzát az OpenMV hardverdokumentációban, hogy mely lábakat kell bekötni. Telepítsd a J-Link Software and Documentation Pack csomagot a segger.com oldalról arra a gépre, amelyhez a szonda fizikailag csatlakozik. Tartsd ésszerűen naprakészen – a régebbi J-Link szoftver nem ismeri az újabb eszköznevek (STM32N6, MIMXRT, Alif).
Minden MCU-nak szüksége van a pontos J-Link eszköznevére, hogy a szonda betöltse a megfelelő flash betöltőt és memóriatérképet:
Kamera ( |
MCU |
J-Link |
|---|---|---|
|
STM32F427 |
|
|
STM32F765 |
|
|
STM32H743 |
|
|
STM32N657 |
|
|
MIMXRT1062 |
|
|
Alif Ensemble (M55-HP) |
|
|
STM32H747 |
|
14.1.1.4.3. VS Code Cortex-Debug beállítása¶
Hozz létre egy .vscode/launch.json fájlt a repository-ban. A legegyszerűbb eset – a VS Code, a J-Link és a build mind ugyanazon a Linux / macOS gépen van – a servertype: "jlink" beállítást használja, amely arra készteti a Cortex-Debug-ot, hogy maga indítson el egy J-Link GDB szervert:
{
"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"
}
]
}
Módosítsd az executable és device értékét a paneledhez (lásd a fenti táblázatot). Nyomd meg az F5 billentyűt a build-flash-és-futtatáshoz a main pontig, és ott állj meg.
Javaslat
Ahhoz, hogy minden hibakeresés indításakor automatikusan újraépüljön, adj hozzá egy build feladatot a .vscode/tasks.json fájlhoz, és hivatkozz rá a launch konfigurációból a "preLaunchTask" kulccsal. Például egy feladat, amely a make -j$(nproc) TARGET=OPENMV4 DEBUG=1 parancsot futtatja, "build-firmware" néven, plusz a "preLaunchTask": "build-firmware" a fenti konfigurációban, így az F5 egyetlen lépésben újraépít, flashel és elindítja a hibakeresőt.
Figyelem
A Cortex-Debug-nak szüksége van az arm-none-eabi-gdb eszközre. Ez az SDK-ban a ~/openmv-sdk-<version>/gcc/bin helyen érkezik, de alapértelmezetten nincs a PATH változón, ezért a hibakeresés a „GDB executable «arm-none-eabi-gdb» was not found” hibával hiúsul meg. Javítsd ki vagy az armToolchainPath / gdbPath fent bemutatott beállításával, vagy a ~/openmv-sdk-<version>/gcc/bin hozzáadásával a PATH változóhoz (a printenv PATH ekkor felsorolja).
14.1.1.4.4. Periféria-regiszter nézet (SVD)¶
Irányítsd a Cortex-Debug-ot egy CMSIS SVD fájlra, hogy dekódolt periféria-regiszter nézetet kapj (időzítők, DMA, a kamerainterfész stb.) név és bitmező szerint:
"svdFile": "/path/to/STM32H743.svd"
Az STM32 és MIMXRT esetén az SVD-t az ST / NXP CMSIS csomagokból vagy a Cortex-Debug SVD regisztertől szerezd be. Az Alif SVD-k a firmware repository-ban vannak elhelyezve a lib/micropython/lib/alif_ensemble-cmsis-dfp/Debug/SVD/ helyen (használd a ..._CM55_HP_View.svd fájlt az AE3 HP magjához).
14.1.1.4.5. Windows: a WSL ↔ Windows J-Link híd¶
A WSL 2 nem látja közvetlenül a J-Link USB eszközét, ezért a felosztás a következő: a Windows szolgáltatja a szondát (ahova az be van dugva), a VS Code + gdb pedig a WSL-ben fut, és TCP-n keresztül éri el azt.
Windowson telepítsd a Segger J-Link csomagot, és dugd be a J-Link szondát egy Windows USB portba.
Windowson indítsd el a J-Link Remote Server-t (a J-Link csomaggal érkezik): indítsd el a csatlakoztatott J-Link szondával, és kattints az OK gombra. Engedélyezd át a Windows tűzfalon, amikor kéri. Az ablak megjeleníti az IP-címet, amelyen a szondát szolgáltatja – jegyezd fel.
A WSL-ben építs
DEBUG=1beállítással, és győződj meg róla, hogy azarm-none-eabi-gdbelérhető (állítsd be azarmToolchainPathértékét a fentiek szerint).A WSL VS Code-ban tartsd meg a
servertype: "jlink"beállítást – a GDB szerver a WSL-ben fut, és a Remote Serveren keresztül éri el a szondát – és add hozzá aserverpath+ipAddressértékeket:{ "name": "OpenMV J-Link (Windows host)", "type": "cortex-debug", "request": "launch", "cwd": "${workspaceFolder}", "executable": "${workspaceFolder}/build/OPENMV4/bin/firmware.elf", "servertype": "jlink", "serverpath": "/opt/SEGGER/JLink/JLinkGDBServer", "ipAddress": "192.168.x.x", "device": "STM32H743VI", "interface": "swd", "runToEntryPoint": "main", "armToolchainPath": "${env:HOME}/openmv-sdk-1.6.0/gcc/bin" }
Állítsd az
ipAddressértékét arra a címre, amelyet a Remote Server ablaka mutat. Ez az egész híd.
Javaslat
Alternatíva a GDB-szerver hídhoz: usbipd-win. Ahelyett, hogy szervert futtatnál Windowson, a J-Link USB eszközét közvetlenül a WSL-be csatolhatod a usbipd-win segítségével. Egy rendszergazdai PowerShellből:
winget install usbipd
usbipd list
usbipd bind --busid <busid>
usbipd attach --wsl --busid <busid>
(A <busid> a J-Link busz-azonosítója a usbipd list parancsból.) A szonda ekkor a WSL-en belül jelenik meg, és a VS Code Cortex-Debug setup szakaszból az egyszerű azonos gépes servertype: "jlink" konfigurációt használod, IP-cím és külön Windows szerver nélkül. A GDB-szerver híd kevesebb beállítást igényel alkalmi használathoz; a usbipd-win kényelmesebb a rendszeres fejlesztéshez.
Javaslat
Használd a "request": "attach" beállítást a firmware hibakereséséhez futás közben, visszaállítás vagy újraflashelés nélkül – ideális egy terepen jelentkező lefagyás elkapásához. Használd a "request": "launch" beállítást a visszaállításhoz, az ELF flasheléséhez és a tiszta indításhoz a runToEntryPoint pontnál.
14.1.1.4.6. Parancssori hibakeresés a gdbrunner segítségével¶
Egy beágyazott céllal szembeni GDB munkamenet kézi felállítása ötlépéses tánc: indítsd el a J-Link / ST-Link GDB szervert az egyik ablakban a megfelelő eszközzel, porttal és interfész kapcsolókkal; várd meg, amíg kiírja a Waiting for GDB connection üzenetet; futtasd az arm-none-eabi-gdb eszközt egy második ablakban; írd be a target remote localhost:<port> parancsot; irányítsd a gdb-t az ELF-re. Amikor a gdb munkamenet véget ér, ne feledd leállítani a szerver ablakát. A gdbrunner egy kis CLI, amely mindezt egyetlen előtér-parancsba sűríti. Az OpenMV SDK Python környezetében érkezik, így nincs mit telepíteni; a szokásos belépési pont a firmware repository make debug célja:
make -j$(nproc) TARGET=<TARGET> DEBUG=1 debug
Ez a gdbrunner-t a panel konfigurációjából származó hibakereső argumentumokkal futtatja – a J-Link eszköznévvel és, ahol szükséges, az ST-Link külső flash betöltővel – úgy, hogy az SDK arm-none-eabi-gdb eszköze már a PATH változón van. Az alapértelmezett backend a J-Link; a make DEBUGGER=STLINK debug helyette egy ST-Link szondával működik.
A gdbrunner közvetlenül is meghívható (az SDK-n kívül, 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
Az első pozicionális argumentum választja ki a szerver backendet (jlink, stlink, qemu); a többit továbbítja az adott backendhez, olyan alapértelmezésekkel, amelyek működnek az OpenMV kamerákkal. A gdbrunner --help felsorolja a teljes, backendenkénti kapcsolólistát; az egyes backendek argumentumtáblázata JSON-vezérelt (src/gdbrunner/backends.json), így egy új szerver hozzáadása inkább konfigurációs szerkesztés, mint kódolás.
Mit tesz a gdbrunner a parancssori munkához:
Egy folyamat, tiszta életciklus. A szerver elindul, a gdb csatlakozik, amikor a port megnyílik, a szerver pedig tisztán leáll, amikor a gdb kilép. Nincs árva
JLinkGDBServer, amely túléli a munkamenetet, nincs két kezelendő terminál.STM32CubeProgrammer automatikus felismerés. Az
stlinkbackend a szokásos telepítési helyeken (~/STM32CubeProgrammer/,/opt/st/, az STM32CubeIDE plugin fa) keresi az STM32CubeProgrammer eszközöket, így a hosszú--cube-progútvonalat nem kell minden alkalommal beírni. Az SDK saját másolatot is tartalmaz a~/openmv-sdk-<version>/stcubeprog/binhelyen – ide irányítsd a--cube-progértékét, ha nincs rendszerszintű telepítés.Projektenkénti gdbinit figyelembe vétele. Az aktuális könyvtárban lévő
.gdbinitbetöltődik a-ixkapcsolóval – felülírva a felhasználói szintű~/.gdbinitfájlt – így a projektenkénti gdb szkriptelés (pretty-printerek, panelspecifikus makrók, töréspont-halmazok) egyszerűen a munkakönyvtárban való jelenlétével illeszkedik be. Amake debuga repository gyökeréből fut, így az ott lévő.gdbinitérvényesül.Próbafutás. A
--dryrunkiírja a szerver parancsot anélkül, hogy futtatná, ami hasznos a meghívás wrapper szkripthez igazításához, IDE indító konfigurációba másolásához, vagy egyszerűen annak ellenőrzéséhez, milyen argumentumokat állít össze a gdbrunner.Látható szerverkimenet. A
--show-outputláthatóan tartja a szerver stdout / stderr kimenetét. Az alapértelmezés elnyomja azt (hogy a gdb felülete tiszta maradjon); fordítsd meg a kapcsolót, amikor maga a szerver az, ami hibásan működik.QEMU backend. A
qemu-system-armegy firmware buildet hibakeres anélkül, hogy bármilyen panel be lenne dugva. AzMPS2_AN500cél a panel konfigurációjában ezt a backendet választja, így amake TARGET=MPS2_AN500 DEBUG=1 debuga QEMUmps2-an500gépéhez épít, és lépteti a platformfüggetlen kódot – mindent, ami nem érinti a kameraspecifikus perifériákat – röptében. (Aqemu-system-armegy gazdagépes telepítés, nem része az SDK-nak.)
Forrás szintű lépkedéshez töréspont-jelzőkkel és periféria-regiszter nézettel a fenti VS Code Cortex-Debug beállítás a jobb eszköz; a gdbrunner a megfelelő mindenhez, ami a parancssorban él.
14.1.1.4.7. A hibakereső használata¶
Amint egy munkamenet fut (a processzor a main pontnál megállítva):
Töréspontok – kattints a jelzősávra egy C sor mellett, vagy a Debug Console-ban
break <file>:<line>/break <function>. A Cortex-M magoknak kis számú hardveres töréspont-komparátoruk van (jellemzően 6–8 az M7 / H7 esetén, 8 az M55 esetén). Ennek túllépése flash-ben lévő kódon csendben meghiúsul – tartsd az aktív töréspontok számát szerényen.Lépkedés – F10 átlépés (
next), F11 belépés (step), Shift+F11 kilépés (finish), F5 folytatás. Az utasítás szintű lépkedés astepi/nextia Debug Console-ban.Változók / figyelés / hívási verem – a Variables és Call Stack panelek a lokális változókat és a visszanyomon követést mutatják; adj hozzá kifejezéseket a Watch panelhez. Vidd a kurzort egy változó fölé a forrásban az értékének megtekintéséhez. Bármi, ami
<optimized out>értéket mutat, azt jelenti, hogy nemDEBUG=1buildet használsz.Figyelőpontok (adat-töréspontok) – a
watch <expr>megáll, amikor egy változóba írnak, azrwatcholvasáskor, azawatchpedig bármelyik esetén. A Cortex-M DWT egység ~4 hardveres figyelőpontot támogat – felbecsülhetetlen annak elkapásához, ki rontott el egy változót.Regiszterek és perifériák – a Cortex Registers nézet a magregisztereket mutatja; az
svdFilebeállításával a Peripherals nézet dekódol minden periféria-regisztert és bitmezőt (DMA, időzítők, a kamera / CSI interfész, XSPI stb.) – a leggyorsabb módja annak, hogy lássuk, miért működik hibásan egy driver.Memória – használd a Cortex-Debug memórianézegetőt vagy a gdb
x/parancsát a képkocka-pufferek, DMA pufferek és struktúrák közvetlen vizsgálatához.printf megállítás nélkül (SWO/RTT) – időzítésérzékeny problémáknál a Segger RTT vagy SWO szinte nulla többletterheléssel ad
printflehetőséget, miközben a cél fut. Építs aDEBUG_PRINTF=1kapcsolóval, és add hozzá a Cortex-DebugrttConfig(RTT) vagyswoConfig(SWO, amihez a magórajel szükséges) beállítását. Ez a megfelelő eszköz, amikor egy töréspont megváltoztatná az időzítést, amelyet megfigyelni próbálsz.Lecsatlakozás – a Stop egy
launchmunkameneten megállítja a célt; a Disconnect egyattachmunkameneten futni hagyja a kamerát. Indítsd újra a kamerát a táp ki-be kapcsolásával, hogy utána visszatérjen a normál működéshez.
14.1.1.4.8. Hibakeresési buktatók¶
Optimalizálással eltávolított változók. Minden
<optimized out>értéket mutat –DEBUG=0beállítással építettél. Építsd újraDEBUG=1beállítással.„GDB executable not found” – az SDK
gcc/binnincs aPATHváltozón; állítsd be azarmToolchainPath/gdbPathértékét.„Cannot connect” / rossz memóriatérkép – rossz vagy hiányzó
devicenév; használd a táblázatban szereplő pontos szöveget.A töréspontok csendben nem érvényesülnek – túl sok hardveres töréspont a flash-rezidens kódon; csökkentsd a számukat.
A forrásútvonalak nem egyeznek (Docker-ban épített ELF) – építs a Docker
build-firmware-devcéllal (ugyanaz az abszolút útvonal a konténeren belül és kívül) vagy állítsd be a gdbset substitute-pathértékét.