14.1.1.4. Налагодження мікропрограми¶
Налагодження на реальному обладнанні означає зупинку процесора, встановлення точок зупину у C-коді, покрокове виконання та перевірку змінних, пам’яті, регістрів і периферійних пристроїв – безпосередньо з VS Code. Для цього потрібні три речі: збірка для налагодження, SWD-пробник (Segger J-Link) та розширення Cortex-Debug, яке керує arm-none-eabi-gdb через J-Link GDB-сервер.
14.1.1.4.1. Збірка для налагодження¶
Завжди перебудовуйте ціль із DEBUG=1
make -j$(nproc) TARGET=<TARGET> DEBUG=1
Реліз (DEBUG=0) компілюється з -O2; у відладчику ви побачите <optimized out> для багатьох змінних, вбудовані функції зливаються з викликаючими, а покрокове виконання перестрибує непередбачувано. DEBUG=1 будується з -Og -ggdb3, що придатне для налагодження і водночас завантажується на камері. ELF-файл, на який слід вказати відладчику:
build/<TARGET>/bin/firmware.elf
(Для Alif AE3 налагоджуйте build/OPENMV_AE3/bin/firmware_M55_HP.elf – ядро з високою продуктивністю.)
14.1.1.4.2. Апаратна частина: J-Link через SWD¶
Підключіть Segger J-Link до SWD-виводів камери (SWDIO, SWCLK, GND та VCC цілі для зворотного зв’язку; камера живиться через USB як зазвичай). Підійдуть J-Link EDU / Base / Pro. Розташування виводів для налагодження різниться залежно від камери – на багатьох платах є окремий роз’єм JTAG/SWD, на інших SWD виведено на роз’єм введення/виведення або тестові контакти – тому зверніться до схеми виводів і принципової схеми відповідної плати в апаратній документації OpenMV. Встановіть J-Link Software and Documentation Pack з segger.com на машину, до якої фізично підключено пробник. Підтримуйте його актуальним – старіші версії J-Link не знатимуть нових назв пристроїв (STM32N6, MIMXRT, Alif).
Кожному MCU потрібна точна назва пристрою J-Link, щоб пробник завантажив правильний flash-завантажувач і карту пам’яті:
Камера ( |
MCU |
J-Link |
|---|---|---|
|
STM32F427 |
|
|
STM32F765 |
|
|
STM32H743 |
|
|
STM32N657 |
|
|
MIMXRT1062 |
|
|
Alif Ensemble (M55-HP) |
|
|
STM32H747 |
|
14.1.1.4.3. Налаштування Cortex-Debug у VS Code¶
Створіть .vscode/launch.json у репозиторії. Найпростіший випадок – VS Code, J-Link і збірка розташовані на одній машині Linux/macOS – використовує servertype: "jlink", і тоді Cortex-Debug сам запускає J-Link GDB-сервер:
{
"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"
}
]
}
Змініть executable та device відповідно до вашої плати (дивіться таблицю вище). Натисніть F5, щоб зібрати, прошити та запустити до main зі зупинкою там.
Порада
Щоб автоматично перебудовувати проєкт при кожному запуску налагодження, додайте задачу до .vscode/tasks.json і посилайтесь на неї у конфігурації запуску через "preLaunchTask". Наприклад, задача, що виконує make -j$(nproc) TARGET=OPENMV4 DEBUG=1 з назвою "build-firmware", плюс "preLaunchTask": "build-firmware" у конфігурації вище – і F5 перебудує, прошиє та запустить відладчик за один крок.
Попередження
Cortex-Debug потребує arm-none-eabi-gdb. Він поставляється з SDK у ~/openmv-sdk-<version>/gcc/bin, але за замовчуванням не додається до PATH, тому налагодження завершується помилкою «GDB executable „arm-none-eabi-gdb“ was not found». Виправте це, вказавши armToolchainPath / gdbPath як показано вище, або додавши ~/openmv-sdk-<version>/gcc/bin до вашого PATH (printenv PATH повинен показати його).
14.1.1.4.4. Перегляд регістрів периферії (SVD)¶
Вкажіть Cortex-Debug шлях до CMSIS-файлу SVD, щоб отримати декодований перегляд регістрів периферії (таймери, DMA, інтерфейс камери тощо) за назвою та бітовим полем:
"svdFile": "/path/to/STM32H743.svd"
Для STM32 і MIMXRT отримайте SVD з пакетів CMSIS від ST/NXP або з реєстру SVD Cortex-Debug. SVD-файли для Alif зберігаються у репозиторії мікропрограми в lib/micropython/lib/alif_ensemble-cmsis-dfp/Debug/SVD/ (використовуйте ..._CM55_HP_View.svd для ядра AE3 HP).
14.1.1.4.5. Windows: міст WSL ↔ Windows J-Link¶
WSL 2 не може напряму бачити USB-пристрій J-Link, тому схема така: Windows обслуговує пробник (куди він підключений), а VS Code та gdb працюють у WSL і звертаються до нього через TCP.
На Windows: встановіть пакет Segger J-Link і підключіть J-Link до USB-порту Windows.
На Windows: запустіть J-Link Remote Server (поставляється з пакетом J-Link): запустіть його з підключеним J-Link і натисніть OK. Дозвольте йому доступ через брандмауер Windows, коли з’явиться запит. У вікні відображається IP-адреса, через яку він надає доступ до пробника – запишіть її.
У WSL: зберіть із
DEBUG=1і переконайтеся, щоarm-none-eabi-gdbдоступний (встановітьarmToolchainPathяк описано вище).У VS Code у WSL: залиште
servertype: "jlink"– GDB-сервер працює у WSL і дістається до пробника через Remote Server – і додайтеserverpath+ipAddress{ "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" }
Встановіть
ipAddressрівним адресі, яку показує вікно Remote Server. Це весь міст.
Порада
Альтернатива мосту GDB-сервера: usbipd-win. Замість запуску сервера на Windows можна підключити USB-пристрій J-Link безпосередньо до WSL за допомогою usbipd-win. З PowerShell від імені адміністратора:
winget install usbipd
usbipd list
usbipd bind --busid <busid>
usbipd attach --wsl --busid <busid>
(<busid> – це ідентифікатор шини J-Link зі списку usbipd list.) Пробник з’являється всередині WSL, і ви використовуєте звичайну однотипну конфігурацію servertype: "jlink" з Налаштування Cortex-Debug у VS Code без IP-адреси та окремого сервера Windows. Міст через GDB-сервер потребує менше налаштувань для разового використання; usbipd-win зручніший для регулярної розробки.
Порада
Використовуйте "request": "attach", щоб налагоджувати мікропрограму у процесі її роботи без скидання або перепрошивання – ідеально для виявлення зависань у польових умовах. Використовуйте "request": "launch", щоб скинути, прошити ELF і почати заново з runToEntryPoint.
14.1.1.4.6. Налагодження з командного рядка за допомогою gdbrunner¶
Ручне налаштування GDB-сесії для вбудованої цілі – це п’ять кроків: запустити J-Link/ST-Link GDB-сервер в одному вікні з правильними параметрами пристрою, порту та інтерфейсу; дочекатися повідомлення Waiting for GDB connection; запустити arm-none-eabi-gdb у другому вікні; ввести target remote localhost:<port>; вказати gdb на ELF. Після завершення сесії gdb не забути закрити серверне вікно. gdbrunner – невелика CLI-утиліта, яка замінює все це однією командою переднього плану. Вона входить до складу Python-середовища SDK OpenMV, тому нічого не потрібно встановлювати; звичайна точка входу – ціль make debug у репозиторії мікропрограми:
make -j$(nproc) TARGET=<TARGET> DEBUG=1 debug
Це запускає gdbrunner із аргументами відладчика з конфігурації плати – назвою пристрою J-Link і, де потрібно, завантажувачем зовнішньої flash-пам’яті ST-Link – а arm-none-eabi-gdb зі SDK вже додано до PATH. Типовим бекендом є J-Link; make DEBUGGER=STLINK debug працює з пробником ST-Link.
gdbrunner також можна запускати безпосередньо (поза 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
Перший позиційний аргумент обирає серверний бекенд (jlink, stlink, qemu); решта передаються бекенду з налаштуваннями за замовчуванням, що підходять для камер OpenMV. gdbrunner --help виводить повний список прапорів для кожного бекенду; таблиця аргументів кожного бекенду описана у JSON (src/gdbrunner/backends.json), тому додавання нового сервера – це зміна конфігурації, а не коду.
Що gdbrunner робить для роботи з командного рядка:
Один процес, чистий життєвий цикл. Сервер запускається, gdb приєднується, коли порт відкрито, сервер коректно завершується, коли gdb виходить. Жодних залишкових процесів
JLinkGDBServerпісля сесії, жодних двох терміналів для управління.Автовизначення STM32CubeProgrammer. Бекенд
stlinkшукає інструменти STM32CubeProgrammer у стандартних місцях встановлення (~/STM32CubeProgrammer/,/opt/st/, дерево плагінів STM32CubeIDE), тому довгий шлях--cube-progне потрібно вводити щоразу. SDK містить власну копію у~/openmv-sdk-<version>/stcubeprog/bin– вказуйте--cube-progтуди, якщо системне встановлення відсутнє.Дотримання gdbinit на рівні проєкту. Файл
.gdbinitу поточному каталозі завантажується з-ix– перекриваючи загальний~/.gdbinit– тому скрипти gdb для конкретного проєкту (pretty-printer’и, макроси для плати, набори точок зупину) застосовуються просто своєю наявністю в робочому каталозі.make debugзапускається з кореня репозиторію, тому.gdbinitтам і застосовується.Пробний запуск.
--dryrunвиводить команду сервера без її виконання – корисно для адаптації виклику до обгорткового скрипта, копіювання його в конфігурацію запускача IDE або просто для перевірки аргументів, які складає gdbrunner.Вихід сервера видимий.
--show-outputзберігає stdout/stderr сервера у відкритому вигляді. За замовчуванням він придушується (щоб інтерфейс gdb залишався чистим); перемикайте прапор, коли неправильно поводиться сам сервер.Бекенд QEMU.
qemu-system-armналагоджує збірку мікропрограми без підключеної плати. ЦільMPS2_AN500обирає цей бекенд у конфігурації плати, томуmake TARGET=MPS2_AN500 DEBUG=1 debugзбирає для машини QEMUmps2-an500і дозволяє покроково виконувати платформонезалежний код – все, що не торкається специфічних периферійних пристроїв камери – без реального обладнання. (qemu-system-armвстановлюється на хості, не входить до SDK.)
Для покрокового виконання з точками зупину та переглядом регістрів периферії налаштування Cortex-Debug у VS Code описане вище є кращим інструментом; gdbrunner підходить для всього, що виконується з командного рядка.
14.1.1.4.7. Використання відладчика¶
Після запуску сесії (процесор зупинено на main):
Точки зупину – клацніть поле ліворуч від рядка C-коду або у консолі налагодження введіть
break <file>:<line>/break <function>. Ядра Cortex-M мають обмежену кількість апаратних компараторів точок зупину (зазвичай 6–8 на M7/H7, 8 на M55). Перевищення їх кількості на коді у flash мовчки ігнорується – тримайте кількість активних точок зупину помірною.Покрокове виконання – F10 крок через (
next), F11 крок у (step), Shift+F11 крок назовні (finish), F5 продовжити. Покрокове виконання на рівні інструкцій –stepi/nextiу консолі налагодження.Змінні / watch / стек викликів – панелі Variables і Call Stack показують локальні змінні та стек; додавайте вирази до Watch. Наведіть курсор на змінну у коді, щоб побачити її значення. Якщо відображається
<optimized out>, значить збірка виконана безDEBUG=1.Точки спостереження (data breakpoints) –
watch <expr>зупиняє при записі змінної,rwatch– при читанні,awatch– при будь-якому доступі. Блок DWT Cortex-M підтримує ~4 апаратні точки спостереження – незамінні для визначення того, хто пошкодив змінну.Регістри та периферія – вигляд Cortex Registers показує регістри ядра; якщо встановлено
svdFile, вигляд Peripherals декодує кожен регістр і бітове поле периферії (DMA, таймери, інтерфейс камери/CSI, XSPI тощо) – найшвидший спосіб зрозуміти, чому драйвер не працює.Пам’ять – використовуйте переглядач пам’яті Cortex-Debug або команду gdb
x/, щоб безпосередньо оглядати кадрові буфери, DMA-буфери та структури.printf без зупинки (SWO/RTT) – для чутливих до часу проблем Segger RTT або SWO забезпечує
printfз мінімальними накладними витратами під час роботи цілі. Зберіть ізDEBUG_PRINTF=1і додайтеrttConfig(RTT) абоswoConfig(SWO, потребує тактової частоти ядра) у Cortex-Debug. Це правильний інструмент, коли точка зупину змінювала б затримку, яку ви намагаєтеся спостерігати.Відключення – Stop у сесії
launchзупиняє ціль; Disconnect у сесіїattachзалишає камеру працювати. Щоб повернути камеру до нормальної роботи, відключіть і повторно підключіть живлення.
14.1.1.4.8. Типові пастки при налагодженні¶
Оптимізовані змінні. Усе показує
<optimized out>– ви збирали зDEBUG=0. Перебудуйте зDEBUG=1.«GDB executable not found» –
gcc/binзі SDK не додано доPATH; встановітьarmToolchainPath/gdbPath.«Cannot connect» / неправильна карта пам’яті – неправильна або відсутня назва
device; використовуйте точний рядок із таблиці.Точки зупину мовчки не спрацьовують – занадто багато апаратних точок зупину на коді у flash; зменшіть їх кількість.
Шляхи до джерел не збігаються (ELF, зібраний у Docker) – зберіть із ціллю Docker
build-firmware-dev(той самий абсолютний шлях всередині та поза контейнером) або встановіть у gdbset substitute-path.