@@ -33,10 +33,11 @@ The hardware: J-Link over SWD
3333
3434Connect a Segger J-Link to the camera's **SWD ** pins (SWDIO, SWCLK, GND,
3535and target VCC for reference; the camera is powered over USB as usual).
36- A J-Link EDU / Base / Pro all work. The SWD pads / header location
37- differs per camera -- check that board's pinout diagram and schematic in
38- the OpenMV hardware documentation for which pins to wire (some boards
39- expose SWD on the I/O header, others on dedicated test pads). Install
36+ A J-Link EDU / Base / Pro all work. Where the debug pins surface
37+ differs per camera -- many boards have a dedicated JTAG/SWD connector,
38+ others expose SWD on the I/O header or on test pads -- so check that
39+ board's pinout diagram and schematic in the OpenMV hardware
40+ documentation for which pins to wire. Install
4041the **J-Link Software and Documentation Pack ** from `segger.com
4142<https://www.segger.com/downloads/jlink/> `__ on the machine the probe is
4243physically plugged into. Keep it reasonably current -- older J-Link
@@ -52,12 +53,15 @@ right flash loader and memory map:
5253 * - Camera (``TARGET ``)
5354 - MCU
5455 - J-Link ``device ``
55- * - ``OPENMV4 `` / `` OPENMV4P `` / `` OPENMVPT ``
56- - STM32H743
57- - ``STM32H743VI ``
56+ * - ``OPENMV2 ``
57+ - STM32F427
58+ - ``STM32F427VG ``
5859 * - ``OPENMV3 ``
5960 - STM32F765
6061 - ``STM32F765VI ``
62+ * - ``OPENMV4 `` / ``OPENMV4P `` / ``OPENMVPT ``
63+ - STM32H743
64+ - ``STM32H743VI ``
6165 * - ``OPENMV_N6 ``
6266 - STM32N657
6367 - ``STM32N657L0 ``
@@ -71,15 +75,6 @@ right flash loader and memory map:
7175 - STM32H747
7276 - ``STM32H747XI ``
7377
74- .. note ::
75-
76- The STM32N6, MIMXRT1062, and Alif AE3 boot from **external ** flash. A
77- J-Link *flash-load * of those needs the correct external loader,
78- which is less straightforward; it is usually easier to **attach ** to
79- the already-running firmware (``"request": "attach" `` below) than to
80- have the debugger program flash. The STM32H7 cameras (H7 / H7 Plus /
81- Pure Thermal) have internal flash and ``launch `` works directly.
82-
8378VS Code Cortex-Debug setup
8479--------------------------
8580
@@ -150,28 +145,25 @@ the ``..._CM55_HP_View.svd`` for the AE3 HP core).
150145Windows: the WSL ↔ Windows J-Link bridge
151146----------------------------------------
152147
153- WSL 2 cannot see the J-Link's USB device directly, so the split is: the
154- **J-Link GDB server runs on Windows ** (where the probe is plugged in)
155- and ** VS Code + gdb run in WSL ** and connect to it over TCP.
148+ WSL 2 cannot see the J-Link's USB device directly, so the split is:
149+ **Windows serves the probe ** (where it is plugged in) and ** VS Code +
150+ gdb run in WSL ** and reach it over TCP.
156151
157152#. **On Windows **, install the Segger J-Link pack and plug the J-Link
158153 into a Windows USB port.
159154
160- #. **On Windows **, start the J-Link GDB server, using your board's
161- device name from the table above::
162-
163- "C:\Program Files\SEGGER\JLink\JLinkGDBServerCL.exe" -select USB -device STM32H743VI -endian little -if SWD -speed 4000 -port 2331
164-
165- Allow it through the Windows firewall when prompted (inbound TCP
166- 2331). The server window **displays the IP address ** it is listening
167- on -- note it.
155+ #. **On Windows **, start the **J-Link Remote Server ** (it ships with
156+ the J-Link pack): launch it with the J-Link attached and click
157+ **OK **. Allow it through the Windows firewall when prompted. The
158+ window shows the **IP address ** it is serving the probe on -- note
159+ it.
168160
169161#. **In WSL **, build ``DEBUG=1 `` and make sure ``arm-none-eabi-gdb `` is
170162 reachable (set ``armToolchainPath `` as above).
171163
172- #. **In WSL VS Code **, use a `` launch.json `` that connects to the
173- already-running server instead of starting one. Either keep
174- `` servertype: "jlink" `` and add ``serverpath `` + ``ipAddress ``::
164+ #. **In WSL VS Code **, keep `` servertype: "jlink" `` -- the GDB server
165+ runs in WSL and reaches the probe through the Remote Server -- and
166+ add ``serverpath `` + ``ipAddress ``::
175167
176168 {
177169 "name": "OpenMV J-Link (Windows host)",
@@ -188,39 +180,8 @@ and **VS Code + gdb run in WSL** and connect to it over TCP.
188180 "armToolchainPath": "${env:HOME}/openmv-sdk-1.6.0/gcc/bin"
189181 }
190182
191- Set ``ipAddress `` to whatever the Windows J-Link server window
192- shows. Or use the cleaner ``external `` form, which starts no server
193- and just points gdb at the bridge::
194-
195- {
196- "name": "OpenMV J-Link (external)",
197- "type": "cortex-debug",
198- "request": "attach",
199- "cwd": "${workspaceFolder}",
200- "executable": "${workspaceFolder}/build/OPENMV4/bin/firmware.elf",
201- "servertype": "external",
202- "gdbTarget": "host.docker.internal:2331",
203- "armToolchainPath": "${env:HOME}/openmv-sdk-1.6.0/gcc/bin",
204- "gdbPath": "${env:HOME}/openmv-sdk-1.6.0/gcc/bin/arm-none-eabi-gdb"
205- }
206-
207- Point the config at the Windows host (see below) on the port the
208- server uses (``2331 `` by default). Windows Firewall must allow
209- inbound TCP on that port for ``JLinkGDBServerCL.exe ``.
210-
211- Reaching the Windows host from WSL depends on the WSL networking mode:
212-
213- * **NAT mode (the default). ** The Windows host is the WSL virtual
214- network's gateway. Get its address in WSL with ``ip route show
215- default `` and use that as the ``ipAddress `` / ``gdbTarget `` host; the
216- LAN IP the J-Link server window prints also works if both ends share
217- a network. ``host.docker.internal `` resolves to the Windows host
218- **only if Docker Desktop's WSL integration is installed ** -- do not
219- rely on it otherwise.
220- * **Mirrored mode ** (``networkingMode=mirrored `` in
221- ``%UserProfile%\.wslconfig `` on recent Windows builds). WSL shares
222- the Windows network stack, so the J-Link server is reachable as plain
223- ``localhost `` and no IP discovery is needed.
183+ Set ``ipAddress `` to the address the Remote Server window shows.
184+ That is the whole bridge.
224185
225186.. tip ::
226187
@@ -246,28 +207,38 @@ Reaching the Windows host from WSL depends on the WSL networking mode:
246207
247208 Use ``"request": "attach" `` to debug the firmware *as it is already
248209 running * without resetting or reflashing it -- ideal for catching a
249- hang in the field, and the reliable choice for the external-flash
250- boards (N6 / RT1062 / AE3). Use ``"request": "launch" `` to reset,
251- flash the ELF, and start fresh at ``runToEntryPoint ``.
210+ hang in the field. Use ``"request": "launch" `` to reset, flash the
211+ ELF, and start fresh at ``runToEntryPoint ``.
252212
253213Command-line debugging with gdbrunner
254214-------------------------------------
255215
256216Setting up a GDB session against an embedded target by hand is a
257- five-step dance: start the J-Link / ST-Link / OpenOCD GDB server in
217+ five-step dance: start the J-Link / ST-Link GDB server in
258218one window with the right device, port, and interface flags; wait
259219for it to print *Waiting for GDB connection *; run
260220``arm-none-eabi-gdb `` in a second window; type ``target remote
261221localhost:<port> ``; point gdb at the ELF. When the gdb session ends,
262222remember to kill the server window. `gdbrunner
263223<https://github.com/openmv/gdbrunner> `__ is a small CLI that collapses
264- all of that into one foreground command::
224+ all of that into one foreground command. It ships in the OpenMV SDK's
225+ Python environment, so there is nothing to install; the usual entry
226+ point is the firmware repository's ``make debug `` target::
227+
228+ make -j$(nproc) TARGET=<TARGET> DEBUG=1 debug
229+
230+ This runs gdbrunner with the debugger arguments from the board's
231+ configuration -- the J-Link device name and, where needed, the
232+ ST-Link external flash loader -- with the SDK's ``arm-none-eabi-gdb ``
233+ already on ``PATH ``. The default backend is J-Link; ``make
234+ DEBUGGER=STLINK debug `` works with an ST-Link probe instead.
265235
266- pip install gdbrunner
236+ gdbrunner can also be invoked directly (outside the SDK, ``pip
237+ install gdbrunner ``)::
267238
268239 gdbrunner jlink --device STM32H743VI build/OPENMV4/bin/firmware.elf
269240 gdbrunner stlink build/OPENMV4/bin/firmware.elf
270- gdbrunner qemu --machine mps2-an500 build/OPENMV4 /bin/firmware.elf
241+ gdbrunner qemu --machine mps2-an500 build/MPS2_AN500 /bin/firmware.elf
271242
272243The first positional argument picks the server backend (``jlink ``,
273244``stlink ``, ``qemu ``); the rest are forwarded to that backend, with
@@ -276,15 +247,6 @@ the full per-backend flag list; each backend's argument table is
276247JSON-driven (``src/gdbrunner/backends.json ``), so adding a new server
277248is a config edit rather than code.
278249
279- The firmware repository's ``make debug `` target is a thin wrapper
280- around gdbrunner that fills in the current ``TARGET ``'s J-Link
281- arguments automatically::
282-
283- make -j$(nproc) TARGET=<TARGET> DEBUG=1 debug
284-
285- This is the fastest way to drop into command-line gdb on whichever
286- board ``TARGET `` selects.
287-
288250What gdbrunner does for command-line work:
289251
290252* **One process, clean lifecycle. ** Server starts, gdb attaches when
@@ -293,14 +255,17 @@ What gdbrunner does for command-line work:
293255 to manage.
294256* **STM32CubeProgrammer auto-discovery. ** The ``stlink `` backend
295257 searches the usual install locations (``~/STM32CubeProgrammer/ ``,
296- ``/opt/st/ ``, the STM32CubeIDE plugin tree) for
297- ``ST-LINK_gdbserver ``, so the long ``--cube-prog `` path doesn't
298- have to be typed every time.
258+ ``/opt/st/ ``, the STM32CubeIDE plugin tree) for the
259+ STM32CubeProgrammer tools, so the long ``--cube-prog `` path doesn't
260+ have to be typed every time. The SDK bundles its own copy at
261+ ``~/openmv-sdk-<version>/stcubeprog/bin `` -- point ``--cube-prog ``
262+ there if no system install exists.
299263* **Per-project gdbinit honoured. ** A ``.gdbinit `` in the current
300264 directory is loaded with ``-ix `` -- overriding the user-wide
301265 ``~/.gdbinit `` -- so per-project gdb scripting (pretty-printers,
302266 board-specific macros, breakpoint sets) drops in by being present
303- in the working directory.
267+ in the working directory. ``make debug `` runs from the repository
268+ root, so a ``.gdbinit `` there applies.
304269* **Dry run. ** ``--dryrun `` prints the server command without
305270 running it, useful for adapting the invocation to a wrapper
306271 script, copying it into an IDE launcher config, or just checking
@@ -309,10 +274,13 @@ What gdbrunner does for command-line work:
309274 stdout / stderr visible. The default suppresses it (so gdb's UI
310275 stays clean); flip the flag when the server itself is what's
311276 misbehaving.
312- * **QEMU backend. ** ``qemu-system-arm `` running ``mps2-an500 `` /
313- ``mps3-an547 `` debugs the same ELF without a board plugged in --
314- code paths that don't touch cam-specific peripherals are
315- steppable on a flight.
277+ * **QEMU backend. ** ``qemu-system-arm `` debugs a firmware build with
278+ no board plugged in. The ``MPS2_AN500 `` target selects this backend
279+ in its board configuration, so ``make TARGET=MPS2_AN500 DEBUG=1
280+ debug `` builds for QEMU's ``mps2-an500 `` machine and steps the
281+ platform-independent code -- everything that doesn't touch
282+ cam-specific peripherals -- on a flight. (``qemu-system-arm `` is a
283+ host install, not part of the SDK.)
316284
317285For source-level stepping with breakpoint gutters and a peripheral
318286register view, the VS Code Cortex-Debug setup above is the better
@@ -361,33 +329,10 @@ Once a session is running (the processor halted at ``main``):
361329 This is the right tool when a breakpoint would change the timing you
362330 are trying to observe.
363331
364- * **Disconnecting ** -- *Stop * on a ``launch `` / ``jlink `` session halts
365- the target; *Disconnect * on an ``attach `` / ``external `` session
366- leaves the camera running. Power-cycle the camera to return it to
367- normal operation afterwards.
368-
369- OpenOCD alternative (ST-Link)
370- -----------------------------
371-
372- If you have an ST-Link instead of a J-Link, the STM32 cameras can be
373- debugged with OpenOCD. The firmware repository ships OpenOCD configs
374- under ``lib/micropython/ports/stm32/boards/ ``:
375-
376- .. list-table ::
377- :header-rows: 1
378- :widths: 38 62
379-
380- * - OpenOCD config
381- - Cameras
382- * - ``openocd_stm32h7_dual_bank.cfg ``
383- - STM32H7 -- OpenMV Cam H7, H7 Plus, Pure Thermal; Arduino
384- Portenta H7, Giga, Nicla Vision
385- * - ``openocd_stm32f7.cfg ``
386- - STM32F7 -- OpenMV Cam M7
387-
388- Use ``servertype: "openocd" `` with ``configFiles `` pointing at the
389- appropriate ``.cfg ``. There are no in-repo OpenOCD configs for the N6,
390- RT1062, or AE3 -- use J-Link for those.
332+ * **Disconnecting ** -- *Stop * on a ``launch `` session halts the
333+ target; *Disconnect * on an ``attach `` session leaves the camera
334+ running. Power-cycle the camera to return it to normal operation
335+ afterwards.
391336
392337Debugging pitfalls
393338------------------
@@ -400,9 +345,6 @@ Debugging pitfalls
400345 ``device `` name; use the exact string from the table.
401346* **Breakpoints silently not hit ** -- too many hardware breakpoints on
402347 flash-resident code; reduce them.
403- * **N6 / RT1062 / AE3 won't flash from the debugger ** -- they boot
404- from external flash; use ``"request": "attach" `` against running
405- firmware instead of ``launch ``.
406348* **Source paths don't match (Docker-built ELF) ** -- build with the
407349 Docker ``build-firmware-dev `` target (same absolute path inside and
408350 outside the container) or set gdb ``set substitute-path ``.
0 commit comments