NOTE: an updated version of this article is available here
These notes describe how I program a SAMD21E17 breakout board with the Atmel ICE, using the command line on Mac OS X, without Atmel Sudio or any other IDE. I assume that the almost exact same procedure can be applied to linux.
The board I used is a TAU (see http://rabidprototypes.com/product/tau/), but the procedure would be the same for the more popular SAMD21G18 that can be found on the Arduino Zero for example.
The ARM developper tools (arm-none-eabi) need to be installed your system.
OpenOCD
On the Mac, I used brew to install OpenOCD (see https://brew.sh/):
$ brew install openocd
The first step is to set up OpenOCD correctly. For this purpose create a file called openocf.cfg, with the following content:
# Atmel-ICE JTAG/SWD in-circuit debugger. interface cmsis-dap cmsis_dap_vid_pid 0x03eb 0x2141 # Chip info set CHIPNAME at91samd21e17 source [find target/at91samdXX.cfg]
You should change the value at91samd21e17 to match the microcontroller you are using (e.g. at91sam21g18).
If you have several Atmel-ICE debuggers connected to your machine, you need to distinguish them by their serial number in the openocd.cfg file by adding the following line with your own serial number substitued:
cmsis_dap_serial J418000123456
On a MAC, you can find the serial number by searching through the output of the command system_profiler SPUSBDataType
and on linux you would look through the output of lsusb -v
.
You can test you openocd.cfg file by simply typing openocd
. You should get an output similar to this:
$ openocd Open On-Chip Debugger 0.9.0 (2015-11-15-05:39) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : only one transport option; autoselect 'swd' adapter speed: 500 kHz adapter_nsrst_delay: 100 cortex_m reset_config sysresetreq Info : CMSIS-DAP: SWD Supported Info : CMSIS-DAP: JTAG Supported Info : CMSIS-DAP: Interface Initialised (SWD) Info : CMSIS-DAP: FW Version = 01.26.0081 Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1 Info : CMSIS-DAP: Interface ready Info : clock speed 500 kHz in procedure 'init' in procedure 'ocd_bouncer'
Now you can plug the SWD header in the board you want to program (don't forget to power the board!). If you launch OpenOCD again, you should get the following output:
$ openocd Open On-Chip Debugger 0.9.0 (2015-11-15-05:39) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : only one transport option; autoselect 'swd' adapter speed: 500 kHz adapter_nsrst_delay: 100 cortex_m reset_config sysresetreq Info : CMSIS-DAP: SWD Supported Info : CMSIS-DAP: JTAG Supported Info : CMSIS-DAP: Interface Initialised (SWD) Info : CMSIS-DAP: FW Version = 01.26.0081 Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1 Info : CMSIS-DAP: Interface ready Info : clock speed 500 kHz Info : SWD IDCODE 0x0bc11477 Info : at91samd21e17.cpu: hardware has 4 breakpoints, 2 watchpoints
Now, while OpenOCD is still running, we can test that gdb works by typing arm-none-eabi-gdb -iex "target extended-remote localhost:3333":
$ arm-none-eabi-gdb -iex "target extended-remote localhost:3333" GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20151217-cvs Copyright (C) 2015 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-apple-darwin10 --target=arm-none-eabi". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word". Remote debugging using localhost:3333 0x00000168 in ?? () (gdb)
If you got this far, your OpenOCD is complete.
Let's blink an LED
The TAU has an LED on Pin 25, which maps to the GPIO PA27: the 27th io port on port A. We will make it blink to test our setup. If you have another board it might have an LED on a different PIN or none at all, you will need to adapt the code below (e.g. the SAMD21 Xplained pro has a led on PB30).
/* * main.c */ #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<<27); while (1) { REG_PORT_OUT0 &= ~(1<<27); delay(500); REG_PORT_OUT0 |= (1<<27); delay(500); } }
To compile this file, you will need a set of headers provided by Microchip/Atmel. First, download the Atmel Software Framework (ASF) from http://www.atmel.com/tools/avrsoftwareframework.aspx
When uncompressing a the file, you'll get a directory named xdk-asf-3.34.2/
or something similar depending on the version you dowloaded. Let's name ASFROOT the absolute path corresponding to that directory (e.g. ASFROOT="/Users/pannetra/Downloads/xdk-asf-3.34.2").
Go to the directory where you put the openocd.cfg file and perform the following actions:
$ cp -R $ASF_ROOT/sam0/utils/cmsis/samd21/include ./include $ cp -R $ASF_ROOT/thirdparty/CMSIS/Include ./cmsis $ cp $ASF_ROOT/sam0/utils/cmsis/samd21/source/system_samd21.h . $ cp $ASF_ROOT/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c . $ cp $ASF_ROOT/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.h .
Now the following steps will need a small customisation depending on the microcontroller you have. In my case it's a SAMD21E17A:
$ cp $ASF_ROOT/sam0/utils/linker_scripts/samd21/gcc/samd21e17a_flash.ld
If you have a different microcontroller from the SAMD21E17A, you should change the file name samd21e17a_flash.ld to match your microcontroller.
LDSCRIPT = samd21e17a_flash.ld STARTUP = startup_samd21.o system_samd21.o PTYPE=__SAMD21E17A__ OBJS=$(STARTUP) main.o # Tools CC=arm-none-eabi-gcc LD=arm-none-eabi-gcc AR=arm-none-eabi-ar AS=arm-none-eabi-as ELF=$(notdir $(CURDIR)).elf LDFLAGS+= -T$(LDSCRIPT) -mthumb -mcpu=cortex-m0 -Wl,--gc-sections CFLAGS+= -mcpu=cortex-m0 -mthumb -g CFLAGS+= -I ./include -I ./cmsis -I . CFLAGS+= -D$(PTYPE) $(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)
The above Makefile is derived from the great work of Geoffrey Brown on the STM32.
If you have a different microcontroller from the SAMD21E17A, you need to change the following two lines in the Makefile: LDSCRIPT = samd21e17a_flash.ld
and PTYPE=__SAMD21E17A__
, replacing references to the samd21e17a with your own.
Compiling and running the code
First we will check that the code compiles as expected.
$ make arm-none-eabi-gcc -c -mcpu=cortex-m0 -mthumb -g -I ./include -I ./cmsis -I . -D__SAMD21E17A__ startup_samd21.c -o startup_samd21.o arm-none-eabi-gcc -MM -mcpu=cortex-m0 -mthumb -g -I ./include -I ./cmsis -I . -D__SAMD21E17A__ startup_samd21.c > startup_samd21.d arm-none-eabi-gcc -c -mcpu=cortex-m0 -mthumb -g -I ./include -I ./cmsis -I . -D__SAMD21E17A__ system_samd21.c -o system_samd21.o arm-none-eabi-gcc -MM -mcpu=cortex-m0 -mthumb -g -I ./include -I ./cmsis -I . -D__SAMD21E17A__ system_samd21.c > system_samd21.d arm-none-eabi-gcc -c -mcpu=cortex-m0 -mthumb -g -I ./include -I ./cmsis -I . -D__SAMD21E17A__ main.c -o main.o arm-none-eabi-gcc -MM -mcpu=cortex-m0 -mthumb -g -I ./include -I ./cmsis -I . -D__SAMD21E17A__ main.c > main.d arm-none-eabi-gcc -Tsamd21e17a_flash.ld -mthumb -mcpu=cortex-m0 -Wl,--gc-sections -o OPENOCD_TEST.elf startup_samd21.o system_samd21.o main.o
Now, you are ready to run the program. Connect the OpenOCD and power your board. We will use gdb to load the program and run it:
$ make debug arm-none-eabi-gdb -iex "target extended-remote localhost:3333" OPENOCD_TEST.elf GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20151217-cvs Copyright (C) 2015 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-apple-darwin10 --target=arm-none-eabi". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Remote debugging using localhost:3333 0x00000168 in ?? () Reading symbols from OPENOCD_TEST.elf...done. (gdb) load Loading section .text, size 0x488 lma 0x0 Loading section .relocate, size 0x428 lma 0x488 Start address 0x0, load size 2224 Transfer rate: 2 KB/sec, 1112 bytes/write. (gdb) monitor reset (gdb) monitor halt target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x81000000 pc: 0x00000270 msp: 0x20001418 (gdb) c Continuing.
Note the gdb commands (load, monitor reset, monitor halt, c...).
Let the LED blink!
The example above does not include the HAL (Hardware Abstraction Layer), which is yet part of another directory in the ASF. A topic for another post I guess.
Comments
Thanks for the great write up. I got as far as typing arm-none-eabi-gdb. Seems I have to set up a cross compile environment on my Gentoo system to get an arm build of the gdb server.
Justin, over 7 years agoIs your solution open sourced? I am designing a network for my small RV van and would like to use something like your solution, but need much smaller boards? Can I make a smaller version of the board? How would you get compensated?
Mike Roberts, over 7 years agoCoru
pPKZ, 9 months agoCoru
pPKZ))',(),,"., 9 months agoCoru
pPKZ'yBsfGw<'">ohYaXv, 9 months agoCoru
pPKZ, 9 months agoCoru
pPKZ, 9 months agoCoru,,".,...,'
pPKZ, 9 months agoCoru'YSUoeH<'">lBFBWJ
pPKZ, 9 months agoCoru
pPKZ, 9 months agoCoru
pPKZ, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU.'"((,(()), 9 months agogJCR
itsU'oFzdkG<'">fLPHVC, 9 months agogJCR
itsU, 9 months agogJCR
itsU') AND 5560=8432 AND ('OHuS'='OHuS, 9 months agogJCR
itsU') AND 7002=7002 AND ('ZgCB'='ZgCB, 9 months agogJCR
itsU' AND 5299=9335 AND 'sxYC'='sxYC, 9 months agogJCR
itsU' AND 7002=7002 AND 'srXW'='srXW, 9 months agogJCR
itsU) AND 2169=5211 AND (1674 BETWEEN 1674 AND 1674, 9 months agogJCR
itsU) AND 7002=7002 AND (9981 BETWEEN 9981 AND 9981, 9 months agogJCR
itsU AND 1515 BETWEEN 8601 AND 8601, 9 months agogJCR
itsU AND 7002 BETWEEN 7002 AND 7002, 9 months agogJCR
itsU AND 5638 BETWEEN 1083 AND 1083-- YnSk, 9 months agogJCR
itsU AND 7002 BETWEEN 7002 AND 7002-- cZmQ, 9 months agogJCR
(SELECT (CASE WHEN (6121=2482) THEN 0x69747355 ELSE (SELECT 2482 UNION SELECT 5799) END)), 9 months agogJCR
(SELECT (CASE WHEN (6040=6040) THEN 0x69747355 ELSE (SELECT 5069 UNION SELECT 7452) END)), 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR..(.",'(..
itsU, 9 months agogJCR'PMXTIb<'">CEeVRV
itsU, 9 months agogJCR
itsU, 9 months agogJCR') AND 2559=4293 AND ('iUTZ'='iUTZ
itsU, 9 months agogJCR') AND 9200=9200 AND ('PrsA'='PrsA
itsU, 9 months agogJCR' AND 1027=7724 AND 'vFNo'='vFNo
itsU, 9 months agogJCR' AND 9200=9200 AND 'plgG'='plgG
itsU, 9 months agogJCR) AND 1960=8817 AND (9439 BETWEEN 9439 AND 9439
itsU, 9 months agogJCR) AND 9200=9200 AND (2359 BETWEEN 2359 AND 2359
itsU, 9 months agogJCR AND 2795 BETWEEN 7718 AND 7718
itsU, 9 months agogJCR AND 9200 BETWEEN 9200 AND 9200
itsU, 9 months agogJCR AND 2772 BETWEEN 3887 AND 3887-- aCYp
itsU, 9 months agogJCR AND 9200 BETWEEN 9200 AND 9200-- wTeg
itsU, 9 months ago(SELECT (CASE WHEN (6461=5909) THEN 0x674a4352 ELSE (SELECT 5909 UNION SELECT 9661) END))
itsU, 9 months ago(SELECT (CASE WHEN (6851=6851) THEN 0x674a4352 ELSE (SELECT 7073 UNION SELECT 7458) END))
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agogJCR
itsU, 9 months agoLeave a comment