PlatformIO Community

Problems starting debug session with jlink on feather M0

Hello, I have difficulties starting a debug session for the feather M0 board using jLink EDU.
(I think that I didn’t have this problems 3 months ago)
After ‘Start Debugging’ the App is loaded on the board and stops at the normal breakpoint at init();
After hitting F5 the board stops in the routine ‘micros(void)’ (see picture 1). After (repeatedly) hitting F5 the CPU is restarted every time but gets a signal SIGTRAP and always stops
at the same line in the micros() routine (see picture 2). When I now click ‘Restart’ and immediatly after stopping at breakpoint init() hit F5 the program runs and I can debug.
I suspect that after the program is loaded to the board and started it cannot connect fast enough to the serial port.
Does anybody face the same issue and how can it be solved?
Kind regards
RoSchmi

PS: Second picture is missing as I’m not allowed to upload more then one.

Here is the second image

Can you provide more information?

  • What framework are you using? (post the platformio.ini file)
  • What does the call stack look like when the debugger stops? The call stack is display in the debugger view.
  • What board are you using? There are several Feather M0 boards.
  • Can you post the relevant code, in particular the one that includes init()?
1 Like

Thanks @manuelbl for your interest and answer.
My OS is Windows 10
My Board is a Adafruit Feather M0 RFM69 Packet Radio (433 MHz)
My platformio.ini file is:

[env:adafruit_feather_m0]
platform = atmelsam
board = adafruit_feather_m0
framework = arduino
debug_tool = jlink

Here is the content of the debugger window:

Processing adafruit_feather_m0 (platform: atmelsam; board: adafruit_feather_m0; framework: arduino)

Verbose mode can be enabled via -v, --verbose option
CONFIGURATION: https://docs.platformio.org/page/boards/atmelsam/adafruit_feather_m0.html
PLATFORM: Atmel SAM 4.1.0 > Adafruit Feather M0
HARDWARE: SAMD21G18A 48MHz, 32KB RAM, 256KB Flash
DEBUG: Current (jlink) External (atmel-ice, blackmagic, jlink)
PACKAGES:

  • framework-arduino-samd-adafruit 1.5.10
  • framework-cmsis 1.40500.0 (4.5.0)
  • framework-cmsis-atmel 1.2.0
  • toolchain-gccarmnoneeabi 1.70201.0 (7.2.1)
    LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
    LDF Modes: Finder ~ chain, Compatibility ~ soft
    Found 10 compatible libraries
    Scanning dependencies…
    No dependencies
    Building in debug mode
    Checking size .pio\build\adafruit_feather_m0\firmware.elf
    Advanced Memory Usage is available via “PlatformIO Home > Project Inspect”
    RAM: [= ] 9.1% (used 2992 bytes from 32768 bytes)
    Flash: [ ] 4.8% (used 12680 bytes from 262144 bytes)
    ========================= [SUCCESS] Took 3.34 seconds =========================
    SEGGER J-Link GDB Server V6.52 Command Line Version

JLinkARM.dll V6.52 (DLL compiled Sep 27 2019 17:50:11)

Command line: -singlerun -if SWD -select USB -device ATSAMD21G18 -port 2331
-----GDB Server start settings-----
GDBInit file: none
GDB Server Listening port: 2331
SWO raw output listening port: 2332
Terminal I/O port: 2333
Accept remote connection: localhost only
Generate logfile: off
Verify download: off
Init regs on start: off
Silent mode: off
Single run mode: on
Target connection timeout: 0 ms
------J-Link related settings------
J-Link Host interface: USB
J-Link script: none
J-Link settings file: none
------Target related settings------
Target device: ATSAMD21G18
Target interface: SWD
Target interface speed: 4000kHz
Target endian: little

Connecting to J-Link…
Reading symbols from c:\Users\Roland\source\PlatformIO\Proj\Feather_M0_Debug_Test_01.pio\build\adafruit_feather_m0\firmware.elf…
done.
J-Link is connected.
PlatformIO Unified Debugger -> http://bit.ly/pio-debug
PlatformIO: debug_tool = jlink
PlatformIO: Initializing remote target…
Firmware: J-Link ARM V8 compiled Nov 28 2014 13:44:46
Hardware: V8.00
S/N: 268003384
OEM: SEGGER-EDU
Feature(s): FlashBP, GDB
Checking target voltage…
Target voltage: 3.24 V
Listening on TCP/IP port 2331
Connecting to target…
Connected to target
Waiting for GDB connection…
Connected to 127.0.0.1
Reading all registers
Read 4 bytes @ address 0x00003770 (Data = 0x4290D1EE)
Received monitor command: clrbp
Received monitor command: speed auto
Select auto target interface speed (2000 kHz)
Received monitor command: reset
Resetting target
Received monitor command: halt
Halting target CPU…
…Target halted (PC = 0x000005E8)
Downloading 12424 bytes @ address 0x00002000
Downloading 92 bytes @ address 0x00005088
Downloading 256 bytes @ address 0x000050E4
0x00003770 in micros () at C:\Users\Roland.platformio\packages\framework-arduino-samd-adafruit\cores\arduino\delay.c:57
57 } while ((pend != pend2) || (count != count2) || (ticks < ticks2));
Select auto target interface speed (2000 kHz)
Resetting target
Loading section .text, size 0x3088 lma 0x2000
Loading section .ramfunc, size 0x5c lma 0x5088
Loading section .data, size 0x100 lma 0x50e4
Start address 0x36a8, load size 12772
Writing register (PC = 0x 36a8)
Read 4 bytes @ address 0x000036A8 (Data = 0x4A12B510)
Reading 64 bytes @ address 0x00003800
Read 2 bytes @ address 0x00003812 (Data = 0xF000)
Transfer rate: 4157 KB/sec, 4257 bytes/write.
Temporary breakpoint 1 at 0x3812: file C:\Users\Roland.platformio\packages\framework-arduino-samd-adafruit\cores\arduino\main.cpp, line 35.
PlatformIO: Initialization completed
PlatformIO: Resume the execution to debug_init_break = tbreak main
PlatformIO: More configuration options -> http://bit.ly/pio-debug

Temporary breakpoint 1, main () at C:\Users\Roland.platformio\packages\framework-arduino-samd-adafruit\cores\arduino\main.cpp:35
35 init();
Setting breakpoint @ address 0x00003812, Size = 2, BPHandle = 0x0001
Starting target CPU…
…Breakpoint reached @ address 0x00003812
Reading all registers
Removing breakpoint @ address 0x00003812, Size = 2
Read 4 bytes @ address 0x00003812 (Data = 0xF8EDF000)
Starting target CPU…
Reading all registers
Read 4 bytes @ address 0x000005E4 (Data = 0xE7FEBE01)
Read 2 bytes @ address 0x000005E4 (Data = 0xBE01)

Program
received signal SIGTRAP, Trace/breakpoint trap.
0x000005e4 in ?? ()
Read 4 bytes @ address 0x20007FCC (Data = 0x41000000)
Reading 64 bytes @ address 0x20007FC0
Read 4 bytes @ address 0x00003792 (Data = 0x00C81841)
Read 4 bytes @ address 0x000037DE (Data = 0x4B031B40)
Read 4 bytes @ address 0x00003824 (Data = 0x00204C09)
Reading 64 bytes @ address 0x20007F80

Here is my sample code:

#include <Arduino.h>
#define LED           13  // onboard blinky
volatile int dummy;

void setup() {
dummy = 1;
while (!Serial); // wait until serial console is open, remove if not tethered to computer
Serial.begin(115200);
Serial.println("Hello");
pinMode(LED, OUTPUT);
for (int i = 0; i < 5; i++)
{
digitalWrite(LED, HIGH);
delay(500);
digitalWrite(LED, LOW);
delay(500);
}
}

void loop() {
dummy++;
Serial.println("\r\nSerial is opened (Loop)\r\n");
delay(1000);
dummy--;
}

The first (intrinsic) stop at init() is in C:\Users\Roland.platformio\packages\framework-arduino-samd-adafruit\cores\arduino\main.cpp

/*
Copyright (c) 2015 Arduino LLC.  All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#define ARDUINO_MAIN
#include "Arduino.h"

// Weak empty variant initialization function.
// May be redefined by variant files.
void initVariant() __attribute__((weak));
void initVariant() { }

// Initialize C library
extern "C" void __libc_init_array(void);

/*
 * \brief Main entry point of Arduino application
 */
int main( void )
{
init();

__libc_init_array();

initVariant();

delay(1);

#if defined(USE_TINYUSB)
Adafruit_TinyUSB_Core_init();
#elif defined(USBCON)
USBDevice.init();
USBDevice.attach();
#endif

setup();

for (;;)
{
  loop();
yield(); // yield run usb background task

if (serialEventRun) serialEventRun();
}

return 0;
}

#if defined(USE_TINYUSB)

// run TinyUSB background task when yield()
extern  "C" void yield(void)
{
tud_task();
tud_cdc_write_flush();
}

#endif

Thanks for the information. That gives the full context.

I remember having run into this problem as well. The serial port is a virtual port (USB CDC) and implemented in software only. If the program is stopped at the wrong time, your computer thinks that the USB device (your Feather board) is not communicating and ignores it. And the boards waits for the computer to contact it, which never happens. At least that’s what it looks like.

If I remember correctly, you have to prevent the debugger from stopping too early. The best approach is probably to disable the temporary break point that is set on main. In platformio.ini, add:

debug_init_break =

Set a breakpoint wherever the debugger should stop instead. If I’m not mistaken, it needs to be after Serial.begin(...) to ensure the serial port is correctly set up and the computer is communicating with the device.

Thanks for your answer. Unfortunately it didn’t solve the problem.

With this platformio.ini

[env:adafruit_feather_m0]
platform = atmelsam
board = adafruit_feather_m0
framework = arduino
debug_tool = jlink
debug_init_break =

The program makes a first stop in the Reset_Handler (see picture), after hitting F5 in the micros() routine as before.

With this platformio.ini

[env:adafruit_feather_m0]
platform = atmelsam
board = adafruit_feather_m0
framework = arduino
debug_tool = jlink
debug_init_break = break main.cpp:11

The program makes a first stop in the micros() routine.

I can now live with the way to click ‘Restart’ (Ctrl+Shift+F5) after the first stop but that’s not the way it should be.
Resethandler_Halt

I just read your tutorial:

I saw that the boards you used have a Reset pin besides SWD and SWCLCK. My feather M0 board has only SWD and SWCLCK Can this be the reason why it is not working “out of the box”?

According to the PlatformIO documentation, debug_init_break = should disable the initial break point. I’ll have to do some tests why it isn’t working.

The reset pin won’t make a difference. Unless I can connect a fully configured cable, I don’t usually connect the reset pin as it isn’t really needed. The chip can also be reset by SWD and JTAG commands.

My understanding is that the SAMD21 and/or Adafruit Arduino board support is part of the problem. They could change the USB code such that it triggers a USB reenumeration during initialization. That would get rid of most of the problems when running the board with a debugger.

1 Like

I was able to resolve this issue by upgrading the bootloader of my Feather M0 to v2.0.0. I suspect the cause of this issue the old bootloader immediately hard faulting on first reset with the debugger enabled, causing a breakpoint and confusing GDB, though I’d have to do more investigation to be sure.

If you are having this issue, you can upgrade your bootloader by grabbing the latest version from the adafruit SAMD core (https://github.com/adafruit/ArduinoCore-samd/blob/master/bootloaders/featherM0/bootloader-feather_m0-v2.0.0-adafruit.5.elf) and then using the following instructions to flash it: https://learn.adafruit.com/proper-step-debugging-atsamd21-arduino-zero-m0/restoring-bootloader. Note that in newer versions of Atmel studio the BOOTPROT fuse menu was changed to different options, and instead of “7” you will want to select “0 Bytes”.

Thank you @prototypicalpro for your help.
Unfortunately upgrading the bootloader to V2.0.0 didn’t solve the problem on my board.
The program stops at the normal initial breakpoint at init(); After hitting F5 my PC shows the Message box with ‘USB device not recognized’ at the lower right corner of the screen and debugging is not possible.
(This is different to the behavior with the other bootloader where had 'received signal SIGTRAP and the program stopped in the micros() routine). I If I click the ‘Restart’ button (CTRL+SHIFT+F5) after reaching the initial breakpoint at init() and then hit F5 after it stops again at this initial breakpoint I can bebug as expected.
If I add ‘debug_init_break =’ to my platformio.ini as suggested by @mauelbl the program stops at ‘void Reset_Handler(void){’ (see picture above) and my PC gives the same ‘USB device not recognized’ message.

I ran into that issue as well. After a lot of troubleshooting, the only way I was able to get USB Serial working during debug mode was to remove the bootloader from the Feather M0 entirely. I’m entirely lost as to why this would fix the issue, but I am happy to report that debugging seems to work normally now.

To flash your Feather M0 with no bootloader, you will need to use Atmel Studio to set the BOOTPROT fuse to 0 bytes (should be the same process as the instructions I posted earlier). Once the bootloader partition is unprotected, you can use the following custom board JSON to tell PlatformIO to compile for a no-bootloader Feather M0:

{
    "build": {
        "arduino": {
            "ldscript": "flash_without_bootloader.ld"
        },
        "core": "adafruit",
        "cpu": "cortex-m0plus",
        "extra_flags": "-DARDUINO_ARCH_SAMD -DARDUINO_SAMD_ZERO -DARDUINO_SAMD_FEATHER_M0 -DARM_MATH_CM0PLUS -D__SAMD21G18A__",
        "f_cpu": "48000000L",
        "hwids": [
            [
                "0x239A",
                "0x800B"
            ],
            [
                "0x239A",
                "0x000B"
            ],
            [
                "0x239A",
                "0x0015"
            ]
        ],
        "mcu": "samd21g18a",
        "system": "samd",
        "usb_product": "Adafruit Feather M0",
        "variant": "feather_m0",
        "zephyr": {
            "variant": "adafruit_feather_m0_basic_proto"
        }
    },
    "debug": {
        "jlink_device": "ATSAMD21G18",
        "openocd_chipname": "at91samd21g18",
        "openocd_target": "at91samdXX",
        "svd_path": "ATSAMD21G18A.svd"
    },
    "frameworks": [
        "arduino",
        "zephyr"
    ],
    "name": "Adafruit Feather M0",
    "upload": {
        "disable_flushing": true,
        "maximum_ram_size": 32768,
        "maximum_size": 262144,
        "native_usb": true,
        "offset_address": "0x0000",
        "protocol": "sam-ba",
        "protocols": [
            "sam-ba",
            "blackmagic",
            "jlink",
            "atmel-ice"
        ],
        "require_upload_port": true,
        "use_1200bps_touch": true,
        "wait_for_upload_port": true
    },
    "url": "https://www.adafruit.com/product/2772",
    "vendor": "Adafruit"
}

This JSON is the same as the standard Feather M0 board profile, except upload.offset_address and build.arduino.ldscript were changed to place your program where the bootloader would normally be. To use this file, save it as adafruit_feather_m0_no_bootloader.json under a boards directory in your PlatformIO project, then edit your platformio.ini to reference it:

[env:your_env]
...
board = adafruit_feather_m0_no_bootloader
...

PlatformIO will now compile and upload your project assuming that there is no bootloader present. Note that this means PlatformIO will overwrite the bootloader on your Feather M0 upon upload: as a result you will only be able to program your Feather via an external debugger going forward (though you can always put the bootloader back by following the instructions in my previous post).

Once I implemented the fix above, the only other modification I needed to make was to ensure that I didn’t interrupt Serial when it was establishing a connection to the serial monitor:

...
void setup() {
  // Don't put any breakpoints on the following code
  Serial.begin(115200);
  while(!Serial) 
    yield(); // make sure to call `yield()` here, otherwise the device will hang forever
  ... // Now that the connection to the serial monitor is established, we can proceed as usual
}
...

With those two modifications I was able to get debugging and the serial monitor to function normally.

3 Likes

Thanks @prototypicalpro for your work!
Your solution works!!
As the solution is not really self explanatory for a beginner it would be nice if the PlatformIo staff could find an easier solution in future PlatformIO versions.
Debugging with PlatformIO is really a great breakthrough in comparison to the Arduino IDE.
Thanks a lot

1 Like

Run into the same problem with a Feather M0 LoRa. Your solution worked perfectly. Thanks for the in-depth explanations. You saved my day! :+1: :+1: :+1:

1 Like