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.
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.
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
lsusb
and to find the serial number of your device, just use this command.
lsusb -vd 03eb:2141 | grep iSerial
openocd
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.
mkdir ~/share
cd ~/share
unzip ~/Downloads/asf-standalone-archive-3.35.1.54.zip
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.
Building
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
MCUTYPE=__SAMD21G18A__
OBJS=$(BOOTUP) TestCode.o
# Tools
CC=arm-none-eabi-gcc
LD=arm-none-eabi-gcc
AR=arm-none-eabi-ar
AS=arm-none-eabi-as
ELF=TestCode.elf
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 .
CFLAGS+= -D$(MCUTYPE)
$(ELF): $(OBJS)
$(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
# compile and generate dependency info
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
$(CC) -MM $(CFLAGS) $< > $*.d
%.o: %.s
$(AS) $< -o $@
clean:
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.
#include <samd21.h>
void delay(int n)
{
int i;
for (;n >0; n--)
{
for (i=0;i<100;i++)
__asm("nop");
}
}
int main()
{
REG_PORT_DIR0 |= (1<<28);
while(1)
{
REG_PORT_OUT0 &= ~(1<<28);
delay(200);
REG_PORT_OUT0 |= (1<<28);
delay(100);
REG_PORT_OUT0 &= ~(1<<28);
delay(200);
REG_PORT_OUT0 |= (1<<28);
delay(1000);
}
}
So I set the direction of the pin
REG_PORT_DIR0 |= (1<<28);
and toggled it.
REG_PORT_OUT0 &= ~(1<<28);
delay(200);
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.
make
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.
load
monitor reset
Summary
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.