Make ATSAMD21J15A work with Arduino

Hello friends! As you can guess for the title, I've made a custom board with this chip and I've tried everything to make run a blink on this chip with no success. Following I write some key points:

  • I have my own boards definition for Arduino, so I'm familiar with variants, boards.txt, and so on. I also have compiled UF2 bootloaders for each board.
  • I have experienced same problems with ATSAMD51J18A, so it must be software related issue with "no previously arduino supported" chips.
  • This same custom boards works fine with ATSAMD51J20A, so it's not the board itself.
  • I've modified CMSIS-Atmel to include D21J15A. The chip was indeed already there, but not added in the "include" list, so no huge modification or scratch coding.
  • The debugger says me that the chip is running "cortex debug handler" what it seems to be a place to go when the stack overflows or something like this, so this is maybe a clue.
  • I use JLINK Mini for program and debug.
  • I don't want to run a bootloader, just the program .bin itself placed on 0X0 memory. But anyway I also tried with it but no results. With D51J20A I just loaded the program on 0x0 and just for the first time after loading I had to connect debugging for make it run.

This is my board.txt definition of the board:

# -----------------------------------
# Remote IO (SAMD21)
# -----------------------------------
remote_io_d21.name=Remote IO (SAMD21)

# VID/PID for Bootloader, Arduino
remote_io_d21.vid.0=0x010A
remote_io_d21.pid.0=0x0001

# Upload
remote_io_d21.upload.tool=bossac18
remote_io_d21.upload.protocol=sam-ba
remote_io_d21.upload.maximum_size=32768
remote_io_d21.upload.maximum_data_size=4096
remote_io_d21.upload.offset=0x0000
remote_io_d21.upload.use_1200bps_touch=true
remote_io_d21.upload.wait_for_upload_port=true
remote_io_d21.upload.native_usb=true

# Build
remote_io_d21.build.mcu=cortex-m0plus
remote_io_d21.build.chip=SAMD21J15A
remote_io_d21.build.f_cpu=48000000L
remote_io_d21.build.usb_product="Remote IO (SAMD21)"
remote_io_d21.build.usb_manufacturer="Navarro Systems"
remote_io_d21.build.board=RID21_BOARD
remote_io_d21.build.core=arduino
remote_io_d21.build.extra_flags=-D__SAMD21J15A__ -DARM_MATH_CM0PLUS {build.usb_flags}
remote_io_d21.build.ldscript=linker_scripts/gcc/flash_without_bootloader.ld
remote_io_d21.build.openocdscript=scripts/openocd/daplink_samd21.cfg
remote_io_d21.build.variant=remote_io_d21
remote_io_d21.build.variant_system_lib=
remote_io_d21.build.vid=0x010A
remote_io_d21.build.pid=0x0001
remote_io_d21.bootloader.tool=jlink
remote_io_d21.bootloader.file=remote_io_d21/bootloader-remote_io_d21.bin

# Menu: Board Version
remote_io_d21.menu.board_version.1_0=V2.1
remote_io_d21.menu.board_version.1_0=V2.0
remote_io_d21.menu.board_version.1_0=V1.0

# Menu: Optimization
remote_io_d21.menu.opt.small=Small (-Os) (standard)
remote_io_d21.menu.opt.small.build.flags.optimize=-Os
remote_io_d21.menu.opt.fast=Fast (-O2)
remote_io_d21.menu.opt.fast.build.flags.optimize=-O2
remote_io_d21.menu.opt.faster=Faster (-O3)
remote_io_d21.menu.opt.faster.build.flags.optimize=-O3
remote_io_d21.menu.opt.fastest=Fastest (-Ofast)
remote_io_d21.menu.opt.fastest.build.flags.optimize=-Ofast
remote_io_d21.menu.opt.dragons=Here be dragons (-Ofast -funroll-loops)
remote_io_d21.menu.opt.dragons.build.flags.optimize=-Ofast -funroll-loops

# Menu: USB Stack
remote_io_d21.menu.usbstack.arduino=Arduino
remote_io_d21.menu.usbstack.tinyusb=TinyUSB
remote_io_d21.menu.usbstack.tinyusb.build.flags.usbstack=-DUSE_TINYUSB

# Menu: Debug
remote_io_d21.menu.debug.off=Off
remote_io_d21.menu.debug.on=On
remote_io_d21.menu.debug.on.build.flags.debug=-g

This is my linker script of the board:

/*
  Copyright (c) 2014-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
*/

/* Linker script to configure memory regions.
 * Need modifying for a specific board.
 *   FLASH.ORIGIN: starting address of flash
 *   FLASH.LENGTH: length of flash
 *   RAM.ORIGIN: starting address of RAM bank 0
 *   RAM.LENGTH: length of RAM bank 0
 */
MEMORY
{
  FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00008000
  RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00001000
}

/* Linker script to place sections and symbol values. Should be used together
 * with other linker script that defines memory regions FLASH and RAM.
 * It references following symbols, which must be defined in code:
 *   Reset_Handler : Entry of reset handler
 *
 * It defines following symbols, which code can use without definition:
 *   __exidx_start
 *   __exidx_end
 *   __copy_table_start__
 *   __copy_table_end__
 *   __zero_table_start__
 *   __zero_table_end__
 *   __etext
 *   __data_start__
 *   __preinit_array_start
 *   __preinit_array_end
 *   __init_array_start
 *   __init_array_end
 *   __fini_array_start
 *   __fini_array_end
 *   __data_end__
 *   __bss_start__
 *   __bss_end__
 *   __end__
 *   end
 *   __HeapLimit
 *   __StackLimit
 *   __StackTop
 *   __stack
 *   __ram_end__
 */
ENTRY(Reset_Handler)

SECTIONS
{
	.text :
	{
		__text_start__ = .;

		KEEP(*(.isr_vector))
		*(.text*)

		KEEP(*(.init))
		KEEP(*(.fini))

		/* .ctors */
		*crtbegin.o(.ctors)
		*crtbegin?.o(.ctors)
		*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
		*(SORT(.ctors.*))
		*(.ctors)

		/* .dtors */
 		*crtbegin.o(.dtors)
 		*crtbegin?.o(.dtors)
 		*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
 		*(SORT(.dtors.*))
 		*(.dtors)

		*(.rodata*)

		KEEP(*(.eh_frame*))
	} > FLASH

	.ARM.extab :
	{
		*(.ARM.extab* .gnu.linkonce.armextab.*)
	} > FLASH

	__exidx_start = .;
	.ARM.exidx :
	{
		*(.ARM.exidx* .gnu.linkonce.armexidx.*)
	} > FLASH
	__exidx_end = .;

	/* To copy multiple ROM to RAM sections,
	 * uncomment .copy.table section and,
	 * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */
	/*
	.copy.table :
	{
		. = ALIGN(4);
		__copy_table_start__ = .;
		LONG (__etext)
		LONG (__data_start__)
		LONG (__data_end__ - __data_start__)
		LONG (__etext2)
		LONG (__data2_start__)
		LONG (__data2_end__ - __data2_start__)
		__copy_table_end__ = .;
	} > FLASH
	*/

	/* To clear multiple BSS sections,
	 * uncomment .zero.table section and,
	 * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */
	/*
	.zero.table :
	{
		. = ALIGN(4);
		__zero_table_start__ = .;
		LONG (__bss_start__)
		LONG (__bss_end__ - __bss_start__)
		LONG (__bss2_start__)
		LONG (__bss2_end__ - __bss2_start__)
		__zero_table_end__ = .;
	} > FLASH
	*/

	__etext = .;

	.data : AT (__etext)
	{
		__data_start__ = .;
		*(vtable)
		*(.data*)

		. = ALIGN(4);
		/* preinit data */
		PROVIDE_HIDDEN (__preinit_array_start = .);
		KEEP(*(.preinit_array))
		PROVIDE_HIDDEN (__preinit_array_end = .);

		. = ALIGN(4);
		/* init data */
		PROVIDE_HIDDEN (__init_array_start = .);
		KEEP(*(SORT(.init_array.*)))
		KEEP(*(.init_array))
		PROVIDE_HIDDEN (__init_array_end = .);


		. = ALIGN(4);
		/* finit data */
		PROVIDE_HIDDEN (__fini_array_start = .);
		KEEP(*(SORT(.fini_array.*)))
		KEEP(*(.fini_array))
		PROVIDE_HIDDEN (__fini_array_end = .);

		KEEP(*(.jcr*))
		. = ALIGN(16);
		/* All data end */
		__data_end__ = .;

	} > RAM

	.bss :
	{
		. = ALIGN(4);
		__bss_start__ = .;
		*(.bss*)
		*(COMMON)
		. = ALIGN(4);
		__bss_end__ = .;
	} > RAM

	.heap (COPY):
	{
		__end__ = .;
		PROVIDE(end = .);
		*(.heap*)
		__HeapLimit = .;
	} > RAM

	/* .stack_dummy section doesn't contains any symbols. It is only
	 * used for linker to calculate size of stack sections, and assign
	 * values to stack symbols later */
	.stack_dummy (COPY):
	{
		*(.stack*)
	} > RAM

	/* Set stack top to end of RAM, and stack limit move down by
	 * size of stack_dummy section */
	__StackTop = ORIGIN(RAM) + LENGTH(RAM) ;
	__StackLimit = __StackTop - SIZEOF(.stack_dummy);
	PROVIDE(__stack = __StackTop);

	__ram_end__ = ORIGIN(RAM) + LENGTH(RAM) -1 ;

	/* Check if data + heap + stack exceeds RAM limit */
	ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
}

The rest of the code is the same that ATSAMD21G18 on Adafruit boards.

I've already read the following post with no results for me:
How to write programs for a custom SAMD21 board using Arduino IDE
ATSAMD21G17D processor programming?
@MartinL posts have been a great help, buy anyway I couldn't make it run... :confused:

Thanks in advance for everyone that could help!

That doesn't look right for code to be loaded via a bootloader.
The ORIGIN would have to be located beyond the end of the bootloader, like in this adafruit linker script:

MEMORY
{
  FLASH (rx) : ORIGIN = 0x00000000+0x2000, LENGTH = 0x00040000-0x2000 /* First 8KB used by bootloader */
  RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
}

Hello West, thanks for answering. No no, I don't want to use a bootloader, just the bare .bin.
I posted the "without bootloader" linker script.