Cannot upload to Adafruit Feather M0 using JLink

I just started using PlatformIO and I have what is hopefully an easy question.

I have an Adafruit Feather M0 (ATSAMD21G18 processor) that I’m attempting to upload via JLink. My test program is the simple LED blink program. It compiles without errors and appears to upload also without errors, however doesn’t run.

This same program uploads and runs correctly on this processor when compiled and uploaded using Atmel Studio (and JLink).

The BOOTPROT fuse in the processor is cleared.

Here’s the test code:

#include <Arduino.h>
void setup()
{
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(0, LOW);
}
void loop()
{
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    delay(1000);
}

The platformio.ini file is:

[env:adafruit_feather_m0]
platform = atmelsam
board = adafruit_feather_m0
framework = arduino
debug_tool = jlink
; SWD interface
upload_protocol = jlink
; JTAG interface
;upload_protocol = jlink-jtag

The .gitignore file is:

.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

And the build and upload log is at the end of this post (I looked for a way to attach a file, but could not find it. If there is a way, please let me know).

Any help would be appreciated, thanks,
Jack

Build/Upload Log:

> Executing task: C:\Users\jtgar\.platformio\penv\Scripts\platformio.exe run --verbose --target upload --environment adafruit_feather_m0 <
Processing adafruit_feather_m0 (platform: atmelsam; board: adafruit_feather_m0; framework: arduino; debug_tool: jlink; upload_protocol: jlink)
----------------------------------------------------------------------------------------------CONFIGURATION: https://docs.platformio.org/page/boards/atmelsam/adafruit_feather_m0.html
PLATFORM: Atmel SAM (6.3.1) > Adafruit Feather M0
HARDWARE: SAMD21G18A 48MHz, 32KB RAM, 256KB Flash
DEBUG: Current (jlink) External (atmel-ice, blackmagic, jlink)
PACKAGES:
 - framework-arduino-samd-adafruit 1.7.2
 - framework-cmsis 2.50400.181126 (5.4.0)
 - framework-cmsis-atmel 1.2.2
 - tool-jlink 1.75001.0 (7.50.1)
 - toolchain-gccarmnoneeabi 1.90301.200702 (9.3.1)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 11 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
MethodWrapper(["checkprogsize"], [".pio\build\adafruit_feather_m0\firmware.elf"])
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [=         ]  10.3% (used 3380 bytes from 32768 bytes)
Flash: [          ]   4.2% (used 10960 bytes from 262144 bytes)
.pio\build\adafruit_feather_m0\firmware.elf  :

section            size        addr
.text             10704        8192
.data               256   536870912
.bss               3124   536871168
.ARM.attributes      40           0
.comment             67           0
.debug_frame        692           0
Total             14883
<lambda>(["upload"], [".pio\build\adafruit_feather_m0\firmware.bin"])
AVAILABLE: atmel-ice, blackmagic, jlink, sam-ba
CURRENT: upload_protocol = jlink
JLink.exe -device ATSAMD21G18 -speed 4000 -if swd -autoconnect 1 -NoGui 1 -CommanderScript "C:\Users\jtgar\~Software\Arduino\PlatformIO\Debug_Feather_Test\.pio\build\adafruit_feather_m0\upload.jlink"
SEGGER J-Link Commander V7.50a (Compiled Jul  8 2021 18:18:11)
DLL version V7.50a, compiled Jul  8 2021 18:16:52


J-Link Command File read successfully.
Processing script file...

J-Link connection not established yet but required for command.
Connecting to J-Link via USB...O.K.
Firmware: J-Link V11 compiled Jun 29 2021 16:12:24
Hardware version: V11.00
S/N: 261005798
License(s): FlashBP, GDB
OEM: SEGGER-EDU
VTref=3.309V
Target connection not established yet but required for command.
Device "ATSAMD21G18" selected.


Connecting to target via SWD
InitTarget() start
InitTarget()
InitTarget() end
Found SW-DP with ID 0x0BC11477
DPIDR: 0x0BC11477
Scanning AP map to find all available APs
AP[1]: Stopped AP scan as end of AP map has been reached
AP[0]: AHB-AP (IDR: 0x04770031)
Iterating through AP map to find AHB-AP to use
AP[0]: Core found
AP[0]: AHB-AP ROM base: 0x41003000
CPUID register: 0x410CC601. Implementer code: 0x41 (ARM)
Found Cortex-M0 r0p1, Little endian.
FPUnit: 4 code (BP) slots and 0 literal slots
CoreSight components:
ROMTbl[0] @ 41003000
ROMTbl[0][0]: E00FF000, CID: B105100D, PID: 000BB4C0 ROM Table
ROMTbl[1] @ E00FF000
ROMTbl[1][0]: E000E000, CID: B105E00D, PID: 000BB008 SCS
ROMTbl[1][1]: E0001000, CID: B105E00D, PID: 000BB00A DWT
ROMTbl[1][2]: E0002000, CID: B105E00D, PID: 000BB00B FPB
ROMTbl[0][1]: 41006000, CID: B105900D, PID: 001BB932 MTB-M0+
Cortex-M0 identified.
PC = 000021C8, CycleCnt = 00000000
R0 = 20000120, R1 = E000E010, R2 = 00000001, R3 = 00000000
R4 = E000ED00, R5 = 00000000, R6 = 00007EFC, R7 = 00000000
R8 = F6DDFFBF, R9 = 3DF7F946, R10= 7FF3FDF7, R11= FA7FE8B8
R12= 20000120
SP(R13)= 20007FB0, MSP= 20007FB0, PSP= FFBBCDF4, R14(LR) = 0000222D
XPSR = 41000000: APSR = nZcvq, EPSR = 01000000, IPSR = 000 (NoException)
CFBP = 00000000, CONTROL = 00, FAULTMASK = 00, BASEPRI = 00, PRIMASK = 00
FPU regs: FPU not enabled / not implemented on connected CPU.

Downloading file [.pio\build\adafruit_feather_m0\firmware.bin]...
Comparing flash   [100%] Done.
J-Link: Flash download: Bank 0 @ 0x00000000: Skipped. Contents already match
O.K.

Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
ResetTarget() start
ResetTarget() end


Script processing completed.

================================ [SUCCESS] Took 3.29 seconds ================================

Terminal will be reused by tasks, press any key to close it.

The compilation process is still using the linker script meant for the case where a bootlaoder is present, as you can see in

Can also be seen in the output

The address of .text is 0x2000, which is not 0x0 (start of flash), but offset by the size of the bootloader.

The bootloader may have been overwritten by JLink because it clears the flash before uploading, or something else was uploaded to it. (You can reflash the bootloader via the Arduino IDE anytime.)

Try and use the other linkerscript, flash_without_bootloader.ld. You do that by adding

; change arduino linker script
board_build.arduino.ldscript = flash_without_bootloader.ld

to the platformio.ini.

Hi Maximilian,

Thanks for the reply. I was able to make a bit of progress, but I’ll have to dig into it a bit further before I get to where I want to be. Is there any documentation other than the help files that explains this in more depth?

Anyway, I mostly wanted to thank you for your reply; you’ve given me a starting point and I’ll post another question if I have anything specific.

Thanks,

Jack

There is one question that I meant to ask, but forgot to add to my last post.
In the original log file that I included in my original post was the line shat showed the start of flash:

Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [=         ]  10.3% (used 3380 bytes from 32768 bytes)
Flash: [          ]   4.2% (used 10960 bytes from 262144 bytes)
.pio\build\adafruit_feather_m0\firmware.elf  :
section            size        addr
.text             10704        8192  <--------

I’ve never seen that line since, and don’t know what I did, or did not do, to cause that be included or excluded. That section of the build log now looks like:

Checking size .pio\build\adafruit_feather_m0\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [=         ]  10.3% (used 3380 bytes from 32768 bytes)
Flash: [          ]   4.2% (used 10960 bytes from 262144 bytes)
Building .pio\build\adafruit_feather_m0\firmware.bin
Configuring upload protocol...
AVAILABLE: atmel-ice, blackmagic, jlink, sam-ba
CURRENT: upload_protocol = jlink

How do I cause that to be included?

Thanks again,

Jack

The sections of the .elf file are only shown in a verbose build (project tasks → Advanced → Verbose Build).

There are other topics in this forum about JLink + Feather M0 debugging that also come to the conclusion that the bootloader stands in the way (Problems starting debug session with jlink on feather M0 - #11 by prototypicalpro), but to get to the “my code may not execute because the load address is not 0x0 and the bootloader might be gone” can only be gotten to with general knowledge about bootloading, flash layout and knowing that one’s board does have a bootloader. Adafruit has a few pages on this here and here.

This blog post and this blog post are good for explaining memory layout and bootloader basics (which isn’t so important after all other than realizing that the bootloader must go / load address must be fixed to 0). We get the “0x0 is the address at which the MCU first executes code / loads the vector table” from our target microcontroller’s datasheet, aka, Atmel SAMD21G18 in your case, from the vendor. Chapter 9, “Product Mapping” is the relevant one here.

Thanks for the info on the Verbose Build option. I must have stumbled across it earlier, but didn’t realize it.

No, my issue is not with the bootloader on the ATSAMD21G18 processor, I purposely cleared the `BOOTPROT fuse so that I would not have to deal with the bootloader. I’m a retired software engineer and have been using Atmel Studio for quite a while. I’m going to be starting a project that will be using an Adafruit Qt Py, however, for some reason Atmel Studio does not support the QT PY in an Arduino environment whereas PlatformIO does, hence I’m trying to come up to speed on PlatformIO IDE. I’ll want to use the debugger as well and that’s why I’m using a JLink. I’m using the Adafruit Feather as a test because it’s supported on both Atmel Studio and PlatformIO and once I get comfortable with PlatformIO using the Feather, I’ll switch over to the QT PY, at least that’s my plan.

My document question is regarding PlatformIO documentation. I see that it’s based on Visual Studio Code so probably that’s where I have to start looking. I guess I was hoping that PlatformIO was as straight forward as other IDE’s I’ve used and could just start using it without having to do lot of digging into its “innards”.

Again, thank you for your help.

Jack

So if there is no bootloader now and the firmware is at 0x0, have you traced execution to see what line it reaches or where it crashes? Since you’re using upload_protocol = jlink, debugging should work automatically.

All PIO documentation is at https://docs.platformio.org/.

Hello again,
I made some progress but I still have one issue to clear up. I had been attempting to upload a release version of my test using the Check Mark (PlatformIO Build) and Right Arrow (PlatformIO Upload) at the bottom of the screen (ctrl alt b and ctrl alt u). This always failed.

Based on what you said in your last reply that “debugging should work automatically”, I decided to attempt to build and upload a debug version using the Run->Start Debugging menu (I had not tried this previously because I wanted to start with what I thought was the simplest test, which was to upload a release version of my test program).

Uploading a debug version worked correctly. I was able to run my test, step through it, set breakpoints, watches, etc. without any problems.

The remaining issue I have now is how to upload a release version. Is the Check Mark (PlatformIO Build) and Right Arrow (PlatformIO Upload) at the bottom of the screen the correct way to do this? As you can see from the log, it “thinks” it uploading. Also, I do not see the JLink progress dialog (I do see it when uploading a debug version).

Am I missing something in my ini file?

Again, I’m attempting to upload the simple LED blink test to an Adafruit Feather (ATSAMD21G18 processor), via JLink with the BOOTPROT fuse in the processor cleared (no bootloader).

I’ve attached my current platformio.ini and a verbose download log.

And again, thanks for the help you’ve been giving me,

Jack

platformio.ini

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

; change arduino linker script
board_build.arduino.ldscript = flash_without_bootloader.ld

debug_tool = jlink
; SWD interface
upload_protocol = jlink
; JTAG interface
;upload_protocol = jlink-jtag

Verbose upload log
Executing task: C:\Users\jtgar\.platformio\penv\Scripts\platformio.exe run --verbose --target upload --environment adafruit_feather_m0 <

Processing adafruit_feather_m0 (platform: atmelsam; board: adafruit_feather_m0; framework: arduino; board_build.arduino.ldscript: flash_without_bootloader.ld; debug_tool: jlink; upload_protocol: jlink)
    --------------------------------------------------------------------------------------------CONFIGURATION: https://docs.platformio.org/page/boards/atmelsam/adafruit_feather_m0.html
    PLATFORM: Atmel SAM (6.3.1) > Adafruit Feather M0
HARDWARE: SAMD21G18A 48MHz, 32KB RAM, 256KB Flash
DEBUG: Current (jlink) External (atmel-ice, blackmagic, jlink)
PACKAGES:
 - framework-arduino-samd-adafruit 1.7.2
 - framework-cmsis 2.50400.181126 (5.4.0)
 - framework-cmsis-atmel 1.2.2
 - tool-jlink 1.75001.0 (7.50.1)
 - toolchain-gccarmnoneeabi 1.90301.200702 (9.3.1)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 11 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
MethodWrapper(["checkprogsize"], [".pio\build\adafruit_feather_m0\firmware.elf"])
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [=         ]  10.3% (used 3380 bytes from 32768 bytes)
Flash: [          ]   4.2% (used 10956 bytes from 262144 bytes)
.pio\build\adafruit_feather_m0\firmware.elf  :

section            size        addr

.text             10700           0

.data               256   536870912

.bss               3124   536871168

.ARM.attributes      40           0

.comment             67           0

.debug_frame        692           0

Total             14879
<lambda>(["upload"], [".pio\build\adafruit_feather_m0\firmware.bin"])
AVAILABLE: atmel-ice, blackmagic, jlink, sam-ba
CURRENT: upload_protocol = jlink
JLink.exe -device ATSAMD21G18 -speed 4000 -if swd -autoconnect 1 -NoGui 1 -CommanderScript "C:\Users\jtgar\~Software\Arduino\PlatformIO\Debug_Feather_Test2\.pio\build\adafruit_feather_m0\upload.jlink"
SEGGER J-Link Commander V7.50a (Compiled Jul  8 2021 18:18:11)
DLL version V7.50a, compiled Jul  8 2021 18:16:52

J-Link Command File read successfully.
Processing script file...

J-Link connection not established yet but required for command.
Connecting to J-Link via USB...O.K.
Firmware: J-Link V11 compiled Jun 29 2021 16:12:24
Hardware version: V11.00
S/N: 261005798
License(s): FlashBP, GDB
OEM: SEGGER-EDU
VTref=3.296V
Target connection not established yet but required for command.
Device "ATSAMD21G18" selected.


Connecting to target via SWD
InitTarget() start
InitTarget()
InitTarget() end
Found SW-DP with ID 0x0BC11477
DPIDR: 0x0BC11477
Scanning AP map to find all available APs
AP[1]: Stopped AP scan as end of AP map has been reached
AP[0]: AHB-AP (IDR: 0x04770031)
Iterating through AP map to find AHB-AP to use
AP[0]: Core found
AP[0]: AHB-AP ROM base: 0x41003000
CPUID register: 0x410CC601. Implementer code: 0x41 (ARM)
Found Cortex-M0 r0p1, Little endian.
FPUnit: 4 code (BP) slots and 0 literal slots
CoreSight components:
ROMTbl[0] @ 41003000
ROMTbl[0][0]: E00FF000, CID: B105100D, PID: 000BB4C0 ROM Table
ROMTbl[1] @ E00FF000
ROMTbl[1][0]: E000E000, CID: B105E00D, PID: 000BB008 SCS
ROMTbl[1][1]: E0001000, CID: B105E00D, PID: 000BB00A DWT
ROMTbl[1][2]: E0002000, CID: B105E00D, PID: 000BB00B FPB
ROMTbl[0][1]: 41006000, CID: B105900D, PID: 001BB932 MTB-M0+
Cortex-M0 identified.
PC = 00000242, CycleCnt = 00000000
R0 = 00000099, R1 = 00134F0C, R2 = 00000000, R3 = 000003E8
R4 = 0000004D, R5 = 4B6CC744, R6 = 00014070, R7 = FFFFFFFF
R8 = F6DDFFBF, R9 = 39F7F947, R10= 7FF3FDF7, R11= FA3FE8A8
R12= 000003E8
SP(R13)= 20007FD8, MSP= 20007FD8, PSP= DF3BFDF4, R14(LR) = 00000253
XPSR = 81000000: APSR = Nzcvq, EPSR = 01000000, IPSR = 000 (NoException)
CFBP = 00000000, CONTROL = 00, FAULTMASK = 00, BASEPRI = 00, PRIMASK = 00
FPU regs: FPU not enabled / not implemented on connected CPU.

Downloading file [.pio\build\adafruit_feather_m0\firmware.bin]...
Comparing flash   [100%] Done.
Erasing flash     [100%] Done.
Programming flash [100%] Done.
J-Link: Flash download: Bank 0 @ 0x00000000: 1 range affected (4608 bytes)
J-Link: Flash download: Total: 0.107s (Prepare: 0.033s, Compare: 0.014s, Erase: 0.016s, Program & Verify: 0.029s, Restore: 0.014s)
J-Link: Flash download: Program & Verify speed: 154 KiB/s
O.K.

Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
ResetTarget() start
ResetTarget() end

Script processing completed.

=============================== [SUCCESS] Took 3.13 seconds ===============================

Terminal will be reused by tasks, press any key to close it.

If build_type is not explicitly set, “Build” and “Upload” will compile and upload a release-optimized (-Os) version of the firmware to the board. When debugging via the PIO unified debugger (and again no special flags like debug_build_flags set), it will build & upload a debug-optimized build.

So, when you add

build_type = debug

to the platformio.ini and do a normal upload, it works, but with build_type = release the firmware does not work?

So, when you add

build_type = debug

to the platformio.ini and do a normal upload, it works, but with build_type = release the firmware does not work?

No, it does not work either way. Here’s what I did to test:

  • Added the line “build_type = debug” to the platformio.ini file;
    From the icons at the bottom of the screen, I did a PlatformIO: Clean, a PlatformIO: Build, and then a PlatformIO: Upload. The project appeared to upload, but did not run (the LED on the target did not blink). Also, did not see the JLink progress dialog.

  • Added the line “build_type = release” to the platformio.ini file;
    Did a PlatformIO: Clean, a PlatformIO: Build, and then a PlatformIO: Upload The project appeared to upload, but again did not run (the LED on the target did not blink). Again, did not see the JLink progress dialog.

  • Added the line “build_type = debug” to the platformio.ini file;
    Did a PlatformIO: Clean, then from the menu at the top of the screen, did Run->Start Debugging. The project downloaded (the JLink progress dialog was displayed), and after clicking on the Continue icon the project ran (the LED on the target blinked as expected).

  • Added the line “build_type = build” to the platformio.ini file;
    Did a PlatformIO: Clean, then from the menu, did Run->Start Debugging. The project downloaded (the JLink progress dialog was displayed), and after clicking on the Continue icon the project ran (the LED on the target blinked as expected).

One other thing I should mention is that if I first upload debug version (Run->Start Debugging) such that the project runs (LED on the target is blinking), then do an upload of a release version (PlatformIO: Upload) the LED stops blinking. So either the target’s memory is cleared and/or something is uploaded someplace.

Hopefully this helps.

Jack

That’s interesting, because the build_type = debug case + normal upload it should have uploaded the exact same firmware as during Run → Start Debugging.

When you reset the board via the reset button after uploading the build_type = debug firmware normally, does that make any change?

No reset on the target had no effect.

I think that it might possibly have something to do with the way the JLink is called rather than the build because if I first upload a debug version (Run->Start Debugging), the target runs normally (the LED blinks), then if I upload a release version (PlatformIO: Upload - I think you called a normal upload), it stops running (the LED stops blinking). It’s as if the debug version of the code was cleared by the JLink when it attempted to upload the release version.

Also, when uploading the debug version, the JLink progress dialog is displayed showing the upload progress, whereas when uploading the release version, it is not. And when doing a debug upload the green LED on the JLink blinks for a few seconds as the upload takes place. With a release upload, I see the green LED quickly blink off and back on.

Jack

Hold up one freaking second.

The board definition file still has

which is gonna affect regular uploading because it uploads the bin file plus the offset info.

Debugging takes the ELF file and thus the start address from its section info, which is correct at 0x0.

Of course of works in debug mode and not with a regular upload.

Add

board_upload.offset_address = 0x0

to the platformio.ini and retry a normal upload.

Yes, that worked. Thank you very much.

Bottom line, in this case there are two lines that need to be added to the platformio.ini file:

board_build.arduino.ldscript = flash_without_bootloader.ld
board_upload.offset_address = 0x0

Also, tried it with my Adafruit Qt Py, and that uploaded correctly.

Again, thank you very much for looking into this for me.

Jack