How to upload arduino bootloader to a custom samd21 usig Jlink mini

Do you only have one custom board? If you've got two then it would be useful to compare their behaviour.

Is the NVMCTRL_REGION_LOCKS fuse value set to 0xFFFFFFF ?

Only made 1 board at the moment , for this batch of prototype i have parts good for 3 boards so i have 2 that are still not made. im going to try to make another onne

I have tried to upload the bootloader for an aduino MKR1000 that i had laying around and everything went fine.

only 0xFFFF not 0xFFFFFFF. it wont let me add 3 more Fs


That's OK, this is due to your microcontroller having reduced memory, therefore less regions to lock or unlock.

@John41234 I had a look at the AVR freaks forum here:

It suggests separately erasing the chip using the "Erase now" button then progamming/verifying the device with the "Erase Flash before programming" box unchecked.


I made another board , it worked this time, i guess something went wrong on the old one.

I still have one problem remaing though, my computer does not detect the board

That's great.

Have you tried double tapping the reset button two times in quick succession?

This should put the microcontroller into bootloader mode and the COM port should become available.

nothing happens windows dont see it, isnt the indicator light supposed light up also?

i have done a continuity check on the data pins of the usb cable and the leg of the samd21 and can confirm that tx and rx are connected.

@MartinL i would like to upload the blink sketch to my board, since the usb does not work as of the moment .

i have already tracked down the .bin that the arduino ide compiles, mine is under


when i upload this on atmel studio using the jlink , If i program it under flash wont the bootloader get replaced?

Hi @John41234

I tested your custom bootloader on my SAMD21 board. My board uses the SAMD21G18A, so it has more memory than your target SAMD21E15B. However, that shouldn't matter, since on both our boards the bootloader will look for the double tap magic number in the last 4 bytes in the first 4K of RAM.

I uploaded the custom bootloader using my Segger J-Link Mini Edu and I can confirm that it works, including double tap reset functionality, which means that it finds the magic number at the correct address in RAM.

I also successfully uploaded a "Blink" sketch over my board's native USB port with its SAMD21 Arduino core code limited to 32K flash and 4K RAM, to simulate your board's memory footprint.

This suggests that whatever's causing your board not to communicate over USB might be hardware related. It could also be a Windows driver issue, but I don't think that's the case, seeing as you microcontroller's bootloader should look to all intents and purposes to the driver like an Arduino Zero.

Yes, if you upload "Blink" via the programmer, it will overwrite the bootloader. In that case, you'll just need to re-program the bootloader again.

If your custom board uses a 32.768kHz external crystal, you can eliminate it as a potential source of any problem, by getting the bootloader to switch to the microcontroller's internal oscillator instead with the use of the CRYSTALLESS flag in the "board_definition_arduino_zero.h" file:

/* Frequency of the board main oscillator */
#define VARIANT_MAINOSC                   (32768ul)
#define CRYSTALLESS                       (1)

Arduino produces a file that implies that i contain the bootloader. Which is good i guess

I do not have a crystal onboard.

@MartinL Im having trouble uploadig my sketch as erase does nnot work anymore, would that matter? will old sketches just get overwritten?

Hmmm, i made another board and it had the same poblem, could there be a problem with my jlink, if so is it possible to create a .bin file that is basically all zeros inside. if so how do i make this? when i try to open a .bin file it does not have an obvious structure just random characters

Did you include the CRYSTALLESS definition in the "board_definition_arduino_zero.h" file?

If the CRYSTALLESS definition isn't defined and your board doesn't have a crystal, the bootloader will stall as it switches from its internal 8MHz oscillator over to its internal 48MHz Digital Frequency Locked Loop driven by the external 32.768kHz crystal, since the DFLL has no signal to lock on to.

If CRYSTALLESS is defined the bootloader will use the microcontroller's internal 32kHz oscillator as a clock source for the DFLL instead, allowing the crystal to be omitted.

Indeed i have added it, here is whats inside my definitions


 * USB device definitions
#define STRING_PRODUCT "Arduino Zero"
#define USB_VID_HIGH   0x23
#define USB_VID_LOW    0x41
#define USB_PID_HIGH   0x00
#define USB_PID_LOW    0x4D

 * If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by
 * quickly tapping two times on the reset button.
 * BOOT_DOUBLE_TAP_ADDRESS must point to a free SRAM cell that must not
 * be touched from the loaded application.
//#define BOOT_DOUBLE_TAP_ADDRESS           (0x20007FFCul)
#define BOOT_DOUBLE_TAP_ADDRESS           (0x20000FFCul)    // 4K RAM - 4 bytes
#define BOOT_DOUBLE_TAP_DATA              (*((volatile uint32_t *) BOOT_DOUBLE_TAP_ADDRESS))

 * If BOOT_LOAD_PIN is defined the bootloader is started if the selected
 * pin is tied LOW.
//#define BOOT_LOAD_PIN                     PIN_PA21 // Pin 7
//#define BOOT_LOAD_PIN                     PIN_PA15 // Pin 5

#define BOOT_USART_MODULE                 SERCOM0
#define BOOT_USART_PAD3                   PINMUX_PA11C_SERCOM0_PAD3
#define BOOT_USART_PAD2                   PINMUX_PA10C_SERCOM0_PAD2
#define BOOT_USART_PAD1                   PINMUX_UNUSED
#define BOOT_USART_PAD0                   PINMUX_UNUSED

/* Master clock frequency */
#define CPU_FREQUENCY                     (48000000ul)
#define VARIANT_MCK                       CPU_FREQUENCY

/* Frequency of the board main oscillator */
#define VARIANT_MAINOSC                   (32768ul)
#define CRYSTALLESS                       (1)

/* Calibration values for DFLL48 pll */
#define NVM_SW_CALIB_DFLL48M_FINE_VAL     (64)

 * LEDs definitions
#define BOARD_LED_PORT                    (0)
#define BOARD_LED_PIN                     (15)

//#define BOARD_LEDRX_PORT                  (1)
//#define BOARD_LEDRX_PIN                   (3)

//#define BOARD_LEDTX_PORT                  (0)
//#define BOARD_LEDTX_PIN                   (27)


So i have tried programming a sketch that is compiled by the ide

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  REG_PORT_DIRSET0 = 0xFFFFFFFF; // Direction set to OUTPUT PA00-PA32

// the loop function runs over and over again forever
void loop() {
  delay(1000);                       // wait for a second
  delay(1000);                       // wait for a second

its supposed to turn all gpio pin high and low, im thinking that if for some rea
son there is a burnt pin or an improper soldered pin, it cant be all of them,

And indeed none of the GPIOs are toggleing none of the 32GPIOs

I think there something wrong , i did compare the hex files of the one uploaded and the one read from the mcU and they are the same but take a look, notice the slider on the "document.hex" (the one read from the mcu) there are some code before the first line while the file uploaded(blink.ino.hex) there are no lines before the first one

having not able to eras the mCu makes things a bit tricky

Im really being cursed by integration hell

Hi @John41234

Getting the bootloader working is just the first phase.

If you're also using the Arduino Zero core code, (the core code is separate from the bootloader), then your sketch will stall (for the same reason as the bootloader), because by default the Arduino Zero operates with an external crystal.

Crystalless operation can be specified by setting the -DCRYSTALLESS compilation flag in the core code's "boards.txt" file. However, it's more complex than that, since you'll also need to change your compilation target flag to a SAMD21E15A or SAMD21E15B as well. This will certainly cause compilation errors, since the default Arduino SAMD21 core code won't support this device.

The quickest way forward is to continue to use the Arduino Zero bootloader, then choose a crystalless Arduino compatible board in the IDE, whose size more closely matches yours, such as the SAMD21ExxA, before uploading a sketch.

By the way, you'll also need to evaluate the board's core code files called: "variant.h" and "variant.cpp", to make sure that the Arduino analog and digital pins match your custom board, prior to uploading the sketch.

Its been 5 days now its not been solved so i guess its time to give up and have to switch to the same actual chip the zero uses ‎ATSAMD21G18A, there is stock, i have to change the board also to match the chips package.

Thank you very much fo spending time with me for the last few days.

Can you share some things to avoid? like what pins best not use on the ‎ATSAMD21G18A, i only need 32 GPIOs and the ‎ATSAMD21G18A has plenty. I will also be not using arduino core when coding, technically i will be using them so that i can use 3rd party libraries but i will be using some macros to substitute them with register manipulationns as arduino add so much overhead

Hi @John41234

The key lesson I learnt from designing Arduino based custom boards, is that the further your board diverges from the Arduino design upon which it's based, the more work you have to do in terms creating the support environment around it.

I'd suggest first deciding upon the need or goal that custom board is trying fulfill, then look for a Arduino based board that can meet this requirement, in terms of microcontroller speed, memory, IO, etc... Take time to look at the board's schematic diagram and the microcontroller's datasheet, especially for any board design considerations.

If your custom board closely matches the one on which it's based, it's possible to simply use that board's bootloader and core code without any modification. This way you'll also benefit from any core code updates from the company manufacturing and supporting it.

If not then you have to start modifying an existing bootloader, then fork the core code and create a new entry for your board in the Arduino IDE. A while back I created a guide to create a new board entry in the Arduino IDE, it's a bit out-of-date, but gives you an idea of what it entails:

If you manage to get your SAMD21E based custom board's bootloader going, a good board to select in the Arduino IDE would be something like the Adafruit Trinket M0 or Adafruit Qt Py.

I won't bore you with the sorry saga, but if it's any consolation my first custom boards took a lot longer than 5 days to get working.

You have the JLINK programmer, you have broken out the SWD pins, there is really no need for the Arduino bootloader. You can just program in the Arduino IDE, and upload the compiled code using Atmel Studio...

1 Like

Hello everyone.
With the help of Microchip Studio 7, I tried to set up copy protection for SAMD21G18. Checking this protection, I erased the controller's memory and not because everything was erased, including the fuses. After that, I could no longer write to the controller's memory. Reading showed that in the controller's memory all cells are set to FF and I could not change it.
I saw that many owners of the SAMD21G18 controller got into a similar situation. I used the fuse readings that were available but I didn't get the desired success.
Fortunately, I had several identical modules on this controller. I read the values ​​of fuses from the working device and manually, using Microchip Studio 7, entered these values ​​into the memory of the non-working controller. Everything returned to working order.
Conclusion: On different breadboards, the controllers themselves and the functional connection may differ. If you accidentally lost the fuse values, only the values ​​from a similar board will help you.

1 Like

Hi @John41234

There's a possible way forward. The reason why your SAMD21E15B doesn't work is because the version of Bossa that Arduino use isn't compatible with your microcontroller.

A further discussion for the SAMD21E17D is continued here:

Although the memory footprint for your microcontroller is different, in principle the steps are the same.