1
0
Fork 0
mirror of https://github.com/iNavFlight/inav.git synced 2025-07-13 11:29:56 +03:00

[DOC] Document hardware debugging procedure with stlink, openocd and gdb

This commit is contained in:
Alberto García Hierro 2019-11-04 16:19:09 +00:00
parent 27ae5a3ef9
commit 48b921be0e
6 changed files with 156 additions and 81 deletions

View file

@ -1,106 +1,160 @@
# Hardware debugging
# Hardware Debugging
The code can be compiled with debugging information, you can then upload a debug version to a board via a JLink/St-Link debug adapter and step through the code in your IDE.
Hardware debugging allows debugging the firmware with GDB, including most of its
features that you can find while debugging software for a computer like setting
breakpoins or printing variables or stepping through the code.
More information about the necessary hardware and setting up the eclipse IDE can be found [here](Hardware Debugging in Eclipse.md)
Additionally, firmware can also be flashed directly either from the IDE or from GDB,
significanly reducing the time required for the compile/flash/test cycle.
A guide for visual studio can be found here:
http://visualgdb.com/tutorials/arm/st-link/
## Required Hardware
This video is also helpful in understanding the proces:
https://www.youtube.com/watch?v=kjvqySyNw20
Although more complex and expensive solutions exists, an STLink V2 clone will let you
use all the features of hardware debugging. They can be purchased on any of the typical
Chinese sites.
## Hardware
[ST Link V2 Clone](https://inavflight.com/shop/s/bg/1177014)
[Original ST Link V2](https://inavflight.com/shop/s/bg/1099119)
Various debugging hardware solutions exist, the Segger J-Link clones are cheap and are known to work on Windows.
Additionally, most nucleo boards from ST come with a brekable part that contains an
STLink V2.1 or V3. These can also be used to debug an FC, but can be more difficult to
source.
### J-Link devices
To connect it a flight controller, you need to locate the SWDIO and SWCLK pins from the
MCU. These correspond to PA13 (SWDIO) and PA14 (SWCLK). Be aware that not all manufacturers
break out these pins, but a lot of them put them in small pads available somewhere.
Connect SWDIO, SWCLK and GND from the FC to pins with the FC
Segger make excellent debuggers and debug software.
TODO: Add pictures of several FCs with SWDIO and SWCLK highlighted.
The Segger J-Link GDB server can be obtained from here.
## Required software
http://www.segger.com/jlink-software.html
Besides an ARM toolchain, [OpenOCD](http://openocd.org) is required. Note that at the
time of this writing, OpenOCD hasn't had a release in almost 3 years, so you might
need to look for unofficial releases or compile from source.
#### Segger J-Link EDU EDU version, for hobbyists and educational use.
[stlink](https://github.com/texane/stlink), while not strictly required, can be handy
for quickly testing the SWD connection or flashing or erasing. To avoid ambiguities
between the hardware and the software, the former will be referred as `ST Link` while
we'll use `stlink` for the latter.
![Segger J-Link EDU](assets/hardware/j-link-edu.jpg)
Please, follow the installation instructions for your operating system.
https://www.segger.com/j-link-edu.html
### Windows
#### USB-MiniJTAG J-Link JTAG/SWD Debugger/Emulator
Install the Windows Subsystem for Linux, then follow the Linux instructions.
http://www.hotmcu.com/usbminijtag-jlink-jtagswd-debuggeremula%E2%80%8Btor-p-29.html?cPath=3_25&zenid=fdefvpnod186umrhsek225dc10
### macOS
![THAOYU USB-MiniJTAG](assets/hardware/THAOYU-USB-MiniJTAG.jpg)
Install [Homebrew](https://brew.sh) (a package manager) first.
##### ARM-JTAG-20-10 adapter
To install OpenOCD type `brew install open-ocd --HEAD` in a terminal. Note the `--HEAD`
command line switch.
https://www.olimex.com/Products/ARM/JTAG/ARM-JTAG-20-10/
http://uk.farnell.com/jsp/search/productdetail.jsp?sku=2144328
For stlink, use `brew install stlink`.
![OLIMEX ARM JTAG ADAPTER](assets/hardware/OLIMEX-ARM-JTAG-ADAPTER-2144328-40.jpg)
### Linux
#### CJMCU-STM32 Singlechip Development Board Jlink Downloader Jlink ARM Programmer
Install [Homebrew for Linux](https://docs.brew.sh/Homebrew-on-Linux), since versions
provided by your distro's package manager might be out of date. Homebrew can cohexist
with your existing package manager without any problems.
![CJMCU-STM32 Jlink ARM Programmer Front](assets/hardware/cjmcu-jlink-front.jpg)
Then, follow the same instructions for installing OpenOCD and stlink for macOS.
![CJMCU-STM32 Jlink ARM Programmer Back](assets/hardware/cjmcu-jlink-back.jpg)
## Hardware setup
http://www.goodluckbuy.com/cjmcu-stm32-singlechip-development-board-jlink-downloader-jlink-arm-programmer.html
Connect SWDIO and SWCLK from the FC to pins with the same label on the ST Link. You must
also connect one of the GND from FC to any of the GND pins to the ST Link. Note the
following caveats:
- There are several ST Link clone types with different pinouts. Pay attention to the pin
labels.
- In some ST Link clones, some GND pins are actually floating and not connected to
- anything. Use a multimeter to check the GND pins and use any of the valid ones.
- Even if you're powering everything from the same computer, make sure to directly connect
the grounds from the FC to the ST Link. Some FC/stlink combinations have a 0.1-0.2V
difference between their grounds and if you don't connect them, stlink won't work.
### STLink V2 devices
The FC can be powered by any power source that it supports (battery, USB, etc...), just
make sure to not connect power from the ST Link (the pins labelled as 3.3V and 5V) to the
FC if something else is powering it.
STLink V2 devices can be used too, via OpenOCD.
Once you're wired everything, test the connections with a DMM before applying power. Then
power both the FC and the stlink (the order doesn't matter) and run `st-info --probe`
You should see something like:
#### CEPark STLink V2
![CEPark STLink V2](assets/hardware/cepark-stlink-v2-front.jpg)
http://www.goodluckbuy.com/cepark-stlink-st-link-v2-emulator-programmer-stm8-stm32-downloader.html
```
Found 1 stlink programmers
serial: 0d0d09002a12354d314b4e00
openocd: "\x0d\x0d\x09\x00\x2a\x12\x35\x4d\x31\x4b\x4e\x00"
flash: 524288 (pagesize: 16384)
sram: 131072
chipid: 0x0431
descr: F4 device (low power) - stm32f411re
```
## Compilation options
use `DEBUG=GDB` make argument.
INAV is compiled with debug symbols by default, since they're only stored in the locally
generated `.elf` file and they never use flash space in the target. However, some
optimizations like inlining and LTO might rearrange some sections of the code enough
to interfere with debugging. All compile time optimizations can be disabled by
using `DEBUG=GDB` when calling `make`.
You may find that if you compile all the files with debug information on that the program is too big to fit on the target device. If this happens you have some options:
You may find that if you compile all the files without optimizations the program might
too big to fit on the target device. In that case, one of the possible solutions is
compiling all files with optimization (`make clean`, `make ...`) first, then re-save
or `touch` the files you want to be able to step though and then run `make DEBUG=GDB`.
This will then re-compile the files you're interested in debugging with debugging symbols and you will get a smaller binary file which should then fit on the device.
* Compile all files without debug information (`make clean`, `make ...`), then re-save or `touch` the files you want to be able to step though and then run `make DEBUG=GDB`. This will then re-compile the files you're interested in debugging with debugging symbols and you will get a smaller binary file which should then fit on the device.
* You could use a development board such as an EUSTM32F103RB, development boards often have more flash rom.
## Debugging
## OSX
To run a debug session, you will need two terminal windows. One will run OpenOCD, while
the other one will run gdb.
### Install OpenOCD via Brew
Although not strictly required, it is recommended to set the target you're working on
in `make/local.mk` (create it if it doesn't exist), by adding a line like e.g.
`TARGET ?= SOME_VALID_TARGET`. This way you won't need to specify the target name in
all commands.
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
From one of the terminals, type `make openocd-run`. This will start OpenOCD and connect
to the MCU. Leave OpenOCD running in this terminal.
brew install openocd
From another terminal, type `make gdb-openocd`. This will compile the `.elf` binary for
the current target and start `gdb`. From there you will usually want to execute the gdb
`load` command first, which will flash the binary to the target. Once it finishes, start
running it by executing the `continue` command.
### GDB debug server
For conveniency, you can invoke `make gdb-openocd` with the environment variable `$LOAD`
set to a non-empty string (e.g. `LOAD=1 make gdb-openocd`), which will run the `load`
command and flash the target as soon as gdb connects to it.
#### J-Link
From there on, you can use any gdb commands like `b` for setting breakpoints, `p` for
printing, etc... Check a gdb tutorial for more details if you're not already familiar
with it.
##### Windows
### Rebuilding and reflashing
Run the Launch the J-Link GDB Server program and configure using UI.
To rebuild, flash and rerun the binary after doing any modifications, recompile it
with `make`, then press `control+c` to interrupt gdb. Halt the target by entering the
gdb command `monitor reset halt` and then type `load` to flash it. gdb will notice the
binary has changed and re-read the debug symbols. Then you can restart the firmware with
`continue`. This way, you can very quickly flash, upload and test since neither OpenOCD
nor gdb need to be restarted.
#### OpenOCD
### ST Link versions
##### Windows
STM32F103 targets
"C:\Program Files (x86)\UTILS\openocd-0.8.0\bin-x64\openocd-x64-0.8.0.exe" -f interface/stlink-v2.cfg -f target/stm32f1x_stlink.cfg
STM32F30x targets
"C:\Program Files (x86)\UTILS\openocd-0.8.0\bin-x64\openocd-x64-0.8.0.exe" -f scripts\board\stm32f3discovery.cfg
##### OSX/Linux
STM32F30x targets
openocd -f /usr/share/openocd/scripts/board/stm32vldiscovery.cfg
By default, the Makefiles will assume an ST Link v2, which is the version found in the
popular and cheap clones. However, other versions are also supported. Just set the
`STLINK` environment variable (either via command line or either via `local.mk`) to
`1` or `2` or `2.1`, according to your hardware.
### Semihosting
Semihosting is an ARM feature that allows printing messages via the SWD connection.
The logging framework inside INAV can output its messages via semihosting. To enable
it, make sure you've deleted all generated files (e.g. `make clean`) and set the
environment variable `$SEMIHOSTING` to a non-empty string, either via command line
or via `local.mk`. Once you start the target, log messages will appear on the openocd
terminal. Note that even with semihosting enabled, logging has be explicitely enabled
via settings.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View file

@ -1,7 +1,8 @@
GDB ?= $(ARM_SDK_PREFIX)gdb
GDB_OPENOCD_REMOTE ?= localhost:3333
GDB_REMOTE ?= localhost:3333
GDB_OPENOCD_INIT_CMDS ?= -ex "monitor reset halt"
GDB_OPENOCD_INIT_CMDS ?=
GDB_OPENOCD_INIT_CMDS += -ex "monitor reset halt"
ifneq ($(LOAD),)
GDB_OPENOCD_INIT_CMDS += -ex load
endif
@ -10,6 +11,4 @@ GDB_OPENOCD_INIT_CMDS += -ex "monitor arm semihosting enable"
endif
gdb-openocd: $(TARGET_ELF)
(nc -z $(subst :, ,$(GDB_OPENOCD_REMOTE)) 2> /dev/null && \
$(GDB) $< -ex "target remote $(GDB_OPENOCD_REMOTE)" $(GDB_OPENOCD_INIT_CMDS)) || \
$(GDB) $< -ex "target remote | $(OPENOCD_CMDLINE) -c \"gdb_port pipe;\"" $(GDB_OPENOCD_INIT_CMDS)
$(GDB) $< -ex "target remote $(GDB_REMOTE)" $(GDB_OPENOCD_INIT_CMDS)

View file

@ -1,27 +1,49 @@
.PHONY: openocd
.PHONY: .FORCE openocd-cfg $(OPENOCD_CFG) openocd-run openocd-flash
OPENOCD_CMD ?= openocd
OPENOCD_INTERFACE ?= stlink-v2
OPENOCD_CFG ?= $(TARGET_OBJ_DIR)/openocd.cfg
CLEAN_ARTIFACTS += $(OPENOCD_CFG)
OPENOCD_CMD ?= openocd
ifeq ($(TARGET_MCU),STM32F1)
OPENOCD_TARGET ?= stm32f1x
else ifeq ($(TARGET_MCU),STM32F3)
OPENOCD_TARGET ?= stm32f3x
else ifeq ($(TARGET_MCU),STM32F4)
OPENOCD_TARGET ?= stm32f4x
else ifeq ($(TARGET_MCU),STM32F7)
OPENOCD_TARGET ?= stm32f7x
STLINK ?= 2
ifeq ($(OPENOCD_INTERFACE),)
ifeq ($(STLINK),1)
OPENOCD_INTERFACE := stlink-v1
else ifeq ($(STLINK),2)
OPENOCD_INTERFACE := stlink-v2
else ifeq ($(STLINK),2.1)
OPENOCD_INTERFACE := stlink-v2-1
else
$(error Uknown ST Link version $(STLINK))
endif
endif
ifeq ($(OPENOCD_TARGET),)
ifeq ($(TARGET_MCU_GROUP),STM32F3)
OPENOCD_TARGET := stm32f3x
else ifeq ($(TARGET_MCU_GROUP),STM32F4)
OPENOCD_TARGET := stm32f4x
else ifeq ($(TARGET_MCU_GROUP),STM32F7)
OPENOCD_TARGET := stm32f7x
endif
endif
ifeq ($(OPENOCD_TARGET),)
$(warning Unknown OPENOCD_TARGET)
endif
OPENOCD_CMDLINE := $(OPENOCD_CMD) -f interface/$(OPENOCD_INTERFACE).cfg -f target/$(OPENOCD_TARGET).cfg
OPENOCD_CMDLINE := $(OPENOCD_CMD) -f $(OPENOCD_CFG)
openocd-run:
openocd-cfg: $(OPENOCD_CFG)
$(OPENOCD_CFG): .FORCE
$(V1) mkdir -p $(dir $@)
$(V1) echo "source [find interface/$(OPENOCD_INTERFACE).cfg]" > $@
$(V1) echo "source [find target/$(OPENOCD_TARGET).cfg]" >> $@
openocd-run: $(OPENOCD_CFG)
$(OPENOCD_CMDLINE)
openocd-flash: $(TARGET_ELF)
openocd-flash: $(TARGET_ELF) $(OPENOCD_CFG)
(echo "halt; program $(realpath $<) verify reset" | nc -4 localhost 4444 2>/dev/null) || \
$(OPENOCD_CMDLINE) -c "program $< verify reset exit"