None of my debuggers seems to work right

I’m trying to chase down an issue with debuggers failing to connect. I’m using PlatformIO on macOS Mojave in VSCode (PlatformIO, version 3.6.5, IDE extension 1.6.0). My target is an Adafruit Trinket M0, wired up to a Cortex Debug Port (10 pin 1.27mm pitch).

I’ve got the following debuggers in front of me:

  • ST-Link/V2 clone with CMSIS-DAP compatible firmware loaded
  • Atmel-ICE
  • BlackMagic Probe (1bitsquared hardware)
  • J-Link EDU.

The J-Link is the only one that reliably works under all circumstances, and I can’t figure out why. I could just use the J-Link and be done with it, but this is a commercial project and that’d be illegal, so I’d like to get any of the others working reliably.

Here’s an experiment. I’ve run it with the Metro M4 for easy reproducibility - results are basically the same between the Metro M4 vs the M0. And the blackmagic probe isn’t supported for the M4 out of the box, so that result is on my Trinket M0. Each run I start with a fresh vscode launch and a deleted .pioenvs.

Metro M4, USB Power, J-Link EDU

; platformio.ini
[env:adafruit_metro_m4]
platform = atmelsam
board = adafruit_metro_m4
framework = arduino

debug_tool = jlink
upload_protocol = jlink

Default launch.json PIO Debug results in nominal operation, including tbreak main, and breaking on any pre-existing breakpoints.

Metro M4, USB Power, Atmel-ICE

; platformio.ini
[env:adafruit_metro_m4]
platform = atmelsam
board = adafruit_metro_m4
framework = arduino

debug_tool = atmel-ice
upload_protocol = atmel-ice

PIO Debug in this configuration results in nothing happening, but if I go over to the debug console, I see

Info : CMSIS-DAP: Interface ready
Info : clock speed 400 kHz
Info : SWD DPIDR 0x2ba01477
Info : at91samd51j19.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : accepting 'gdb' connection from pipe
Error: Couldn't find part corresponding to DID 60060005
Error: auto_probe failed
Error: Connect failed. Consider setting up a gdb-attach event for the target to prepare target for GDB connect, or use 'gdb_memory_map disable'.
Error: attempted 'gdb' connection rejected
Ignoring packet error, continuing...
warning: unrecognized item "timeout" in "qSupported" response

Metro M4, USB Power, Clone CMSIS-DAP

; platformio.ini
[env:adafruit_metro_m4]
platform = atmelsam
board = adafruit_metro_m4
framework = arduino

debug_tool = atmel-ice
upload_protocol = atmel-ice

Identical result to real Atmel-ICE

Metro M4, BlackMagic Probe

Unsupported out of the box.

Trinket M0 Results

Full disclosure, this is actually a Trinket M0 clone, for what that’s worth. There have been minor BSP modifications in Arduino to reconfigure IO names and whatnot. But it’s the same SAMD21E18, etc.

Trinket M0 clone, USB Power, J-Link EDU

; platformio.ini
[env:trinket_m0_clone]
platform = atmelsam
board = trinket_m0_clone
framework = arduino

debug_tool = jlink
upload_protocol = jlink

Default launch.json PIO Debug results in almost-nominal operation, including tbreak main. Oddly, for whatever reason, this config does NOT break on pre-existing breakpoints in the code. I have to add breakpoints when a debug session is already underway. If it means anything to you, I see the following in the debug console at the end of the start sequence, while the debugger is brokeon on the tbreak main:

PlatformIO: Initialization completed
PlatformIO: Resume the execution to `debug_init_break = tbreak main`
Reading all registers
Starting target CPU...
Cannot execute this command while the target is running.
Cannot execute this command while the target is running.
Reading all registers
Starting target CPU...

If I then remove and re-add the breakpoint in my own code, I see

Debugger requested to halt target...
...Target halted (PC = 0x0000336C)
Reading all registers
Starting target CPU...
Debugger requested to halt target...
...Target halted (PC = 0x00003344)
Reading all registers
Starting target CPU...
Reading all registers

so it’s almost as if the debugger script for the SAMD21E18 doesn’t add custom breakpoints right off? I don’t really know how debuggers work under the hood - I just know the behavior is unexpected.

Trinket M0 clone, USB Power, Atmel-ICE

; platformio.ini
[env:trinket_m0_clone]
platform = atmelsam
board = trinket_m0_clone
framework = arduino

debug_tool = atmel-ice
upload_protocol = atmel-ice

This actually worked as expected when I ran it just now, for the first time today (maybe something to do with restarting VSCode, which I hadn’t been doing before?) It still didn’t respect pre-existing source breakpoints (just the initial tbreak main).
The second time I ran it, after deleting .pioenvs again, restarting Code, and re-plugging my board and debugger (so, power cycle target AND probe):

Info : clock speed 400 kHz
Error: SWD connect failed
in procedure 'init' 
in procedure 'ocd_bouncer'
.pioinit:10: Error in sourced command file:
Remote connection closed

Trinket M0 clone, USB Power, Clone CMSIS-DAP

(Same platformio.ini as above)
Identical behavior to official atmel-ice.

Trinket M0 Clone, USB Power, BlackMagic Probe

; platformio.ini
[env:trinket_m0_clone]
platform = atmelsam
board = trinket_m0_clone
framework = arduino
debug_tool = blackmagic
upload_protocol = blackmagic
debug_port = /dev/cu.usbmodemC3E9D5EB1

Fails with the below:

Reading symbols from /Users/alexw/Documents/PlatformIO/Projects/ECMBlink/.pioenvs/mira_ecm_0-2-0/firmware.elf...
done.
PlatformIO Unified Debugger > http://bit.ly/pio-debug
PlatformIO: Initializing remote target...
Target voltage: 3.3V
SW-DP scan failed!
.pioinit:18: Error in sourced command file:
Attaching to Remote target failed

If I power-cycle the target and try again,

Reading symbols from /Users/alexw/Documents/PlatformIO/Projects/ECMBlink/.pioenvs/mira_ecm_0-2-0/firmware.elf...
done.
PlatformIO Unified Debugger > http://bit.ly/pio-debug
PlatformIO: Initializing remote target...
Target voltage: 3.3V
SW-DP scan failed!
.pioinit:18: Error in sourced command file:
Attaching to Remote target failed

If I manually reset-button the target right before clicking debug,

Reading symbols from /Users/alexw/Documents/PlatformIO/Projects/ECMBlink/.pioenvs/mira_ecm_0-2-0/firmware.elf...
done.
PlatformIO Unified Debugger > http://bit.ly/pio-debug
PlatformIO: Initializing remote target...
Target voltage: 3.3V
Available Targets:
No. Att Driver
 1      Atmel SAMD21E18A (rev D)
Temporary breakpoint 1 at 0x337a: file /Users/alexw/.platformio/packages/framework-arduinosam/cores/adafruit/main.cpp, line 35.
Loading section .text, size 0x3740 lma 0x2000
Loading section .ramfunc, size 0x50 lma 0x5740
Loading section .data, size 0x104 lma 0x5790
Start address 0x32b8, load size 14484
Transfer rate: 17 KB/sec, 852 bytes/write.
PlatformIO: Initialization completed
PlatformIO: Resume the execution to `debug_init_break = tbreak main`
Note: automatically using hardware breakpoints for read-only addresses.

but then nothing happens after that.

Notably, manually resetting the target with the button before debug doesn’t seem to have any impact on behavior for the two atmel-ice cases.

What’s going on here and how do I get sub-car-payment debuggers to work?

1 Like

Thank you so much for the great explanation! Please file an issue here Issues · platformio/platform-atmelsam · GitHub and put a reference to this topic.

Will do once I’m back at a computer!

I came across a tiny little mention on a tiny little line of an Adafruit guide that, on one of their boards, attaching a debugger can be tricky because the reset timing needs to be just so, and so they recommend a j-link because it always gets it right. So I’ll look into that as possibly related.

But, I think that issue applies because that board has IO attached to the SWD lines, and therefore once the bootloader starts, the SAMD won’t detect a debugger. Which isn’t relevant for my board.

1 Like