ORBTrace for debugging using pyOCD

We’ve already covered getting started with debugging using openocd, but what if your preferred debugger interface is pyocd?

Even if you’re not intending using OpenOCD for debug connection, it’s probably work taking a quick browse through that article because we’re not going to cover all the same material here. Once you’ve done that, come back here and we’ll carry on with pyOCD, a powerful and feature complete alternative to openocd, provided you’re using a chip it supports.

All the opening the box, powering up and simple testing stuff from the OpenOCD article apply just as much to this one, so go follow those bits from there, then we’ll pick up at the Lets Connect step….

Quick check

PyOCD can quickly list what probes you’ve got, that it can connect to. That’s a nice first check;

>pyocd list
  #   Probe              Unique ID         
-------------------------------------------
  0   Orbcode Orbtrace   36FC6192A2189006  

Lets connect…

In the Orbmule repository you will find the Simple demo. This is the basic application we will use for testing. It has been developed using the STM32F427VI muleboard, but it’s deliberately written to be as generic as possible and it doesn’t use anything that is CPU specific (indeed, even the startup and linker files are the generic ones you’ll find in the gdb distribution). For the worst case, to target for other M4 processors you should only need to change the memory configuration in system/linker.ld, and possibly some paths at the head of the Makefile depending on where you’ve got your compiler suite installed. Incidentally, if you’ve not got a compiler suite, head over to Arm to fix that problem sharpish.

Let’s start by building the application;

 >make
 Compiling src/main.c
 Compiling src/itm_messages.c
 Assembling system/startup_ARMCM4.S
   text       data     bss     dec     hex filename
   1500       1080   10068   12648    3168 ofiles/simple.elf
>

Your exact numbers may vary depending on compiler versions, but the important thing is that you’ve now got an output file in ofiles/simple.elf. You’ll also have mapfiles and other things in there too, but hopefully you won’t be needing those. We’ll use pyOCD to handle the connection for us, so as a first step let’s connect to our target, which, in this specific case, is a STM32F429VI (assuming you’re using the mule board);

>pyocd gdb -t stm32f429xI
0000857:INFO:board:Target type is stm32f429xi
0000888:INFO:dap:DP IDR = 0x2ba01477 (v1 rev2)
0000920:INFO:ap:AHB-AP#0 IDR = 0x24770011 (AHB-AP var1 rev2)
0000939:INFO:rom_table:AHB-AP#0 Class 0x1 ROM table #0 @ 0xe00ff000 (designer=020 part=411)
0000946:INFO:rom_table:[0]<e000e000:SCS-M4 class=14 designer=43b part=00c>
0000950:INFO:rom_table:[1]<e0001000:DWT class=14 designer=43b part=002>
0000953:INFO:rom_table:[2]<e0002000:FPB class=14 designer=43b part=003>
0000956:INFO:rom_table:[3]<e0000000:ITM class=14 designer=43b part=001>
0000961:INFO:rom_table:[4]<e0040000:TPIU-M4 class=9 designer=43b part=9a1 devtype=11 archid=0000 devid=ca1:0:0>
0000965:INFO:rom_table:[5]<e0041000:ETM-M4 class=9 designer=43b part=925 devtype=13 archid=0000 devid=0:0:0>
0000971:INFO:cortex_m:CPU core #0 is Cortex-M4 r0p1
0000984:INFO:cortex_m:FPU present: FPv4-SP-D16-M
0000994:INFO:dwt:4 hardware watchpoints
0000998:INFO:fpb:6 hardware breakpoints, 4 literal comparators
0001124:INFO:server:Semihost server started on port 4444 (core 0)
0001145:INFO:gdbserver:GDB server started on port 3333 (core 0)

pyOCD only supports SWD, so that’s what it will connect with. ORBTrace is pretty shifty, so you can speed it up from the default of 1MHz with something like -f50m ..that’s an upper limit and there’s a law of diminishing returns in play. In general, keep it to 10MHz or below for most reliable connectivity (you did notice it’s just a thin ribbon cable, didn’t you?), but be aware that you’ve got headroom if you need it.

As previously, let’s create a minimal .gdbinit to support it and load the application;

!killall pyocd
!~/Develop/orb/orbuculum/ofiles/orbtrace -p vtpwr,3.3 -e vtpwr,on
!pyocd gdb -t stm32f429xI -f10m &
file ofiles/simple.elf
target extended-remote localhost:3333
set mem inaccessible-by-default off
load

Basically, this powers up your target using the VTPwr pins at 3.3V, kills any old pyocd instances that are laying around and starts a new one. It then selects our application file, connects to the pyocd instance that it just started, loads the application into it and then resets the chip ready to start.

Connect your target to ORBTrace using either the 10-pin or 20-pin header (it doesn’t matter which for this example, we’re only using the SWD, SWCLK and Gnd pins anyway…but be careful to use VTRef if you’re on the 10-pin connector as VTPwr isn’t carried over that), run arm-none-eabi-gdb and you should see something like this;

>arm-none-eabi-gdb
GNU gdb (GNU Arm Embedded Toolchain 9-2020-q2-update) 8.3.1.20191211-git
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-none-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
pyocd: no process found
0000902:INFO:board:Target type is stm32f429xi
0000967:INFO:dap:DP IDR = 0x2ba01477 (v1 rev2)
0000977:INFO:ap:AHB-AP#0 IDR = 0x24770011 (AHB-AP var1 rev2)
0000994:INFO:rom_table:AHB-AP#0 Class 0x1 ROM table #0 @ 0xe00ff000 (designer=020 part=411)
0000998:INFO:rom_table:[0]<e000e000:SCS-M4 class=14 designer=43b part=00c>
0001002:INFO:rom_table:[1]<e0001000:DWT class=14 designer=43b part=002>
0001003:INFO:rom_table:[2]<e0002000:FPB class=14 designer=43b part=003>
0001006:INFO:rom_table:[3]<e0000000:ITM class=14 designer=43b part=001>
0001010:INFO:rom_table:[4]<e0040000:TPIU-M4 class=9 designer=43b part=9a1 devtype=11 archid=0000 devid=ca1:0:0>
0001013:INFO:rom_table:[5]<e0041000:ETM-M4 class=9 designer=43b part=925 devtype=13 archid=0000 devid=0:0:0>
0001016:INFO:cortex_m:CPU core #0 is Cortex-M4 r0p1
0001028:INFO:cortex_m:FPU present: FPv4-SP-D16-M
0001035:INFO:dwt:4 hardware watchpoints
0001065:INFO:fpb:6 hardware breakpoints, 4 literal comparators
0001149:INFO:server:Semihost server started on port 4444 (core 0)
0001174:INFO:gdbserver:GDB server started on port 3333 (core 0)
0001353:INFO:gdbserver:Client connected to port 3333!
0xfffffffe in ?? ()
0001373:INFO:gdbserver:Attempting to load argon
0001374:INFO:gdbserver:Attempting to load freertos
0001374:INFO:gdbserver:Attempting to load rtx5
0001374:INFO:gdbserver:Attempting to load threadx
0001374:INFO:gdbserver:Attempting to load zephyr
Resetting target with halt
Successfully halted device on reset
Loading section .text, size 0x5d4 lma 0x8000000
Loading section .ARM.exidx, size 0x8 lma 0x80005d4
Loading section .data, size 0x438 lma 0x80005dc
[====================] 100%
0001853:INFO:loader:Erased 16384 bytes (1 sector), programmed 16384 bytes (4 pages), skipped 0 bytes (0 pages) at 34.15 kB/s
Start address 0x8000298, load size 2580
Transfer rate: 5 KB/sec, 860 bytes/write.
Resetting target with halt
Successfully halted device on reset
(gdb) 

and the LEDs should all magically spring to life, like this;

As with openocd, because you started pyocd and gdb in the same terminal then you’ll get the output blended. PyOCD isn’t too chatty but still you might prefer a separate window, in which case replace the !pyocd… line with something like;

!gnome-terminal --hide-menubar --title "OpenOCD Session" --zoom 0.8 -- pyocd gdb -t stm32f429xI -f10m --persist

Be aware that pyocd takes a few seconds to clean up after itself at the end of a run. That’s not normally a problem, but if you get any ‘can’t connect’ errors it’s probably that you’re trying to re-run the debug interface too quickly…just give it a second or two and try again.

…and that’s it. You’ve loaded your application and you’re good to go. Follow a decent GDB Tutorial to learn more about one of the most powerful debuggers out there.