2015-04-12

Building Our Program Manually

Last time, we stopped relying on the Arduino IDE for uploading the program to the board. Today, I'm going to show you how we can build the program ourselves. To get started, we first need to translate our blink.ino file into proper C code:

// blink.c

#include <Arduino.h>

int led = 13;

void setup() {
	pinMode(led, OUTPUT);
}

void loop() {
	digitalWrite(led, HIGH);
	delay(200);
	digitalWrite(led, LOW);
	delay(800);
}
			

As you can see, besides including the Arduino header file, nothing has changed[1].

Ok then, how do we turn this C file into something we can upload to the Arduino Due? This question turned out to be surprisingly easy to answer: Just run an Arduino IDE build with verbose output and see what it does. As I found out, the Arduino IDE first compiles the program into an object file. Here's how we can do that:

ARDUINO_IDE=<insert path to Arduino IDE>

arm-none-eabi-g++ \
	-c \
	-nostdlib \
	-Dprintf=iprintf \
	-MMD \
	-mcpu=cortex-m3 \
	-DF_CPU=84000000L \
	-DARDUINO=10700 \
	-DARDUINO_SAM_DUE \
	-DARDUINO_ARCH_SAM \
	-D__SAM3X8E__ \
	-mthumb \
	-DUSB_VID=0x2a03 \
	-DUSB_PID=0x003e \
	-DUSBCON \
	-DUSB_MANUFACTURER="Unknown" \
	-DUSB_PRODUCT="Arduino Due" \
	-I$ARDUINO_IDE/hardware/arduino/sam/system/libsam \
	-I$ARDUINO_IDE/hardware/arduino/sam/system/CMSIS/CMSIS/Include/ \
	-I$ARDUINO_IDE/hardware/arduino/sam/system/CMSIS/Device/ATMEL/ \
	-I$ARDUINO_IDE/hardware/arduino/sam/cores/arduino \
	-I$ARDUINO_IDE/hardware/arduino/sam/variants/arduino_due_x \
	blink.c \
	-o blink.o
			

There are several things to note about this command:

Now we've compiled our program, but that's not all. We still need to build the final executable that has all the Arduino libraries linked into it[3]:

ARDUINO_IDE=<insert path to Arduino IDE>
ARDUINO_TMP=<insert path of the IDE's temporary build directory>

arm-none-eabi-gcc \
	-Wl,--gc-sections \
	-mcpu=cortex-m3 \
	-T$ARDUINO_IDE/hardware/arduino/sam/variants/arduino_due_x/linker_scripts/gcc/flash.ld \
	-L$ARDUINO_TMP \
	-mthumb \
	-Wl,--entry=Reset_Handler \
	-Wl,--start-group \
		$ARDUINO_TMP/syscalls_sam3.c.o \
		blink.o \
		$ARDUINO_TMP/variant.cpp.o \
		$ARDUINO_IDE/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a \
		$ARDUINO_TMP/core.a \
	-Wl,--end-group \
	-lm \
	-o blink.elf
			

This second build command gnerates an executable file (blink.elf) from our object file and several Arduino libraries. Again, there are several things to note here:

Now we have an executable for our program, but we're still not done! The executable we built is in the ELF format. ELF is used on many operating systems, but for a bare-metal ARM board, we need something different:

arm-none-eabi-objcopy -O binary blink.elf blink.bin
			

This final command will convert the binary into the correct format. We can upload this to the Due using the method outlined in the last article:

bossac --write --verify --boot -R blink.bin
			

If everything worked out, the code will be uploaded to the board and you can keep watching the LED blinking to your heart's content. Don't forget that you need to erase the board before the upload (using the ERASE button).

That's it for today. As always, the full code is available on GitHub. See you next time!