Program an Atmel SAM without an IDE. // Tutorial

I’ve been asked this question a couple times. How do you program an Atmel SAM MCU without a boot loader or the Arduino IDE?

In this video I’ll show you how to do this using Linux and an Atmel In-Circuit Debugger.

The Atmel SAM MCU

The Atmel SAM MCUs are a step up from the old AVR series. Atmel provide a range of them targeted towards different applications. Besides running an ARM core they also have multiplexed serial comms, called SERCOM, allowing you to assign functions to different pins. They’re a pretty neat chip.However, if you’ve ever designed a board yourself, like this one I designed for a customer, the MCU won’t of course contain any bootloader, which is a requirement if you want to use an IDE like Arduino or Eclipse.With this method you can choose to burn a bootloader and then use one of those IDEs, or just keep using this method to develop your code.

Install OpenOCD

You will of course need the Atmel ICE which allows you to program a variety of MCUs and connects to your PC via USB. You can pick these up for around US$60 if you don’t want the snazzy case. Or you can use a Raspberry Pi. In a later video I’ll show you how to use a Pi instead.First of all you’re going to need OpenOCD version 0.10. The reason is that this version now supports a lot of the Atmel SAM MCUs.Depending on your Linux distribution and release you’re running you may or may not have the latest version of OpenOCD. I tend to use Debian which only has version 0.9.0, since I’m running the latest stable release.To upgrade, I could use a Debian feature called “apt pinning” to select the more recent version, but sometimes it’s easier just to download the deb files and install manually. There was only one upgraded dependency that I needed to download which was libjim. So I just installed that along with the updated version of OpenOCD.

sudo dpkg -i libjim0.77_0.77-2_amd64.deb openocd_0.10.0-1+b1_amd64.deb

Once you have the correct version of OpenOCD you’ll need to install a couple more packages, which is called a cross-compiler as it targets a different processor that runs on the build machine.

sudo apt-get install binutils-arm-none-eabi gcc-arm-none-eabi gdb-arm-none-eabi libstdc++-arm-none-eabi-newlib libnewlib-arm-none-eabi

Once you have all that installed, create a directory with the name of your choice. I called it TestCode.

mkdir ~/TestCodecd ~/TestCode

Then change into that directory and create a file called openocd.cfg wit hthe following contents:

# Atmel-ICE JTAG/SWD in-circuit debugger.
interface cmsis-dap
cmsis_dap_vid_pid 0x03eb 0x2141
cmsis_dap_serial SerialNumber

# Chip info
set CHIPNAME at91samd21g18
source [find target/at91samdXX.cfg]

This file has several keys parts to it.

  • interface – Defines the type of in-circuit debugger you are using.
  • cmsis_dap_vid_pid – Refers to the USB device that you’re using.
  • cmsis_dap_serial – Atmel IDE serial number. Both are important and I’ll show you how to get those in a minute.
  • The next two lines are the type of SAM MCU you are using.

It’s important that you use the right definitions here. In my case; I’m using the SAMD21G18.

To find out your Atmel ICE USB device, just run


and to find the serial number of your device, just use this command.

lsusb -vd 03eb:2141 | grep iSerial

Then head back to your openocd.cfg file and update and save. You should now be able to run the openocd command and see this response.


Powering up your board and plugging it in to the debugger should make the green LED light up.

OpenOCD will see the device connected and then just sit there. This means that it’s now listening on port 3333 and waiting for a connection.

Install ASF

Next you will need the Atmel Software Framework. This is a fairly large package that you’ll need to download and install. You’ll actually end up only using a couple of kB of this half a gig package, but you’ll need to fetch it all.Once downloaded, unzip to somewhere on your filesystem. I unzipped it under the share directory under my home directory.

mkdir ~/share
cd ~/share
unzip ~/Downloads/

Once unzipped head back to your source code directory.
Create a sub-directory called xdk-asf and cd into it.

cd ~/TestCode
mkdir xdk-asf
cd xdk-asf

You will need to create a bunch of symbolic links back to the ASF directory. Make sure you are using the correct MCU as things will break if you don’t.

ln -s $HOME/share/xdk-asf-3.35.1/thirdparty/CMSIS/Include cmsis
ln -s $HOME/share/xdk-asf-3.35.1/sam0/utils/cmsis/samd21/include .
ln -s $HOME/share/xdk-asf-3.35.1/sam0/utils/linker_scripts/samd21/gcc/samd21g18a_flash.ld .
ln -s $HOME/share/xdk-asf-3.35.1/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c .
ln -s $HOME/share/xdk-asf-3.35.1/sam0/utils/cmsis/samd21/source/system_samd21.c .
ln -s $HOME/share/xdk-asf-3.35.1/sam0/utils/cmsis/samd21/source/system_samd21.h .

So, after all that it should look a bit like this.


Now you’ll need to create a file called Makefile back in the TestCode directory.

cd ~/TestCode
vi Makefile

You will need to add the content below to this file:

LDSCRIPT = xdk-asf/samd21g18a_flash.ld
BOOTUP = xdk-asf/startup_samd21.o xdk-asf/system_samd21.o

OBJS=$(BOOTUP) TestCode.o

# Tools


LDFLAGS+= -T$(LDSCRIPT) -mthumb -mcpu=cortex-m0 -Wl,--gc-sections
CFLAGS+= -mcpu=cortex-m0 -mthumb -g
CFLAGS+= -I xdk-asf -I xdk-asf/include -I xdk-asf/cmsis -I .

$(ELF):         $(OBJS)
    $(LD) $(LDFLAGS) -o [email protected] $(OBJS) $(LDLIBS)

# compile and generate dependency info
%.o:    %.c
    $(CC) -c $(CFLAGS) $< -o [email protected]
    $(CC) -MM $(CFLAGS) $< > $*.d

%.o:    %.s
    $(AS) $< -o [email protected]

    rm -f $(OBJS) $(OBJS:.o=.d) $(ELF) startup_stm32f* $(CLEANOTHER)

debug:  $(ELF)
    arm-none-eabi-gdb -iex "target extended-remote localhost:3333" $(ELF)

# pull in dependencies
-include        $(OBJS:.o=.d)

There are three important parts that you’ll need to update in this file:

  • LDSCRIPT – needs to point to the correct MCU LD file that you are using.
  • BOOTUP – files which need to match the ones you symlinked in.
  • MCUTYPE – needs to be correct as well.

This Makefile will build the TestCode.c file and generate a file called TestCode.elf and upload the firmware to the MCU using the GDB cross-compiler which connects to the OpenOCD backend listening on port 3333.

Next you’ll want to start coding up. I created a simple LED flasher, because there’s nothing better than seeing an LED flash. Depending on what board you are using things might change a little.For the board I designed I had an LED connected up to GPIO PA28.

#include <samd21.h>

void delay(int n)
    int i;

    for (;n >0; n--)
        for (i=0;i<100;i++)

int main()
    REG_PORT_DIR0 |= (1<<28);

        REG_PORT_OUT0 &= ~(1<<28);
        REG_PORT_OUT0 |= (1<<28);
        REG_PORT_OUT0 &= ~(1<<28);
        REG_PORT_OUT0 |= (1<<28);

So I set the direction of the pin

REG_PORT_DIR0 |= (1<<28);

and toggled it.

REG_PORT_OUT0 &= ~(1<<28);
REG_PORT_OUT0 |= (1<<28);

I also defined a delay function to provide a pseudo mS delay. Since I haven’t performed any other initialization, the SAMD21 will default to using it’s internal 8MHz PLL, so this gives me an almost accurate mS delay.Once you have your C file created, just run make to build it.


If you want to burn the firmware and run it, then type:

make debug

GDB will connect to OpenOCD on port 3333 which you left running in another shell.

You did leave it running didn’t you?

You should see OpenOCD responding like this.You can now burn the firmware by typing:


And run by typing:

monitor reset

and there you go!


So there you have it! It’s pretty simple to get started with SAM MCUs and really the same method can be used for the old AVRs. You just have to make sure that you update the correct MCU details in the various files.

In a later video I’ll show you how to do the same thing using a humble Pi.

If you like this YouTube channel please subscribe by clicking the in-video button, or the little red “Subscribe” button in your browser or app. You can also get updates by subscribing to me on Facebook, Twitter, Google+, Pinterest, and also Tumblr.