Arduino without the arduino environment (a minute guide)

The only way to learn a new programming language is by writing programs in it. The first program to write is the same for all languages:

Print the words
hello, world

This is the big hurdle; to leap over it you have to be able to create the program text somewhere, compile it successfully, load it, run it, and find out where the output went. With these mechanical details mastered, everything else is comparatively easy.

–Kernighan & Ritchie, 1978

This quote is annoyingly true in the world of microcontrollers. “Hello, world” is considered to be flashing an LED, and it’s more a case of learning the microcontroller rather than a language, though there’s often not that much different, due to the idiosyncrasies of microcontrollers.

This time, I’m diving in to Atmel, via Arduino. Today I came to the conclusion that I needed some reasonably precise timing on some I/O lines. So, I went off to Maplin to see what they had and perhaps not very surprisingly they had a selection of Arduinos (they no longer stock PICKIT in store), so I picked one up. The device consists of an Atmega328p MCU, another Atmega acting as a USB-serial device, a USB port, some bootloader software and some headers including in circuit programming ones.

Essentially the Arduino is everything you need to do to get started with microcontrollers (except the USB cable), a standard breakout layout and an easy to use programming environment. The Arduino environment is not suitable for me today. This is not a criticism, but the trade of simplicity for flexibility means it deals with all the interrupts and timers and good control over them is precisely what I need.

Without the nice environment, the main problem is figuring out the correct magic incantations to go from some C code to a blinking LED. It of course also took me far longer than it ought to have done to figure out, which is why I’m writing about it here.

Here’s the C++ program (test.cc) which I want to run. Note that avr-gcc comes with some nice utilities like time delays, and the Arduino UNO (and most other arduinos) have an LED wired up to what is labelled as pin 13 on the board which corresponds to B5 for the UNO.

#include <avr/io.h>
#include <util/delay.h>
int main()
{
    // DDRB  Data Direction Register for port B
    // 1 corresponds to output. 0 for input.
    // _BV is Bit Value, i.e. BV(x) is 1<<x
    DDRB |= _BV(DDB5); 

    while(1) 
    {
	PORTB^=_BV(PB5);
        _delay_ms(100);
    }
}

And here are the magic incantations in the form of a Makefile:

#This is the form of names cross compilers usually have
CXX=avr-g++
CC=avr-gcc
LD=avr-g++

#atmega328p is used on the Arduino Uno
#It needs to be specified in several places so it's in the 
#Makefile, not the source code.
MCU=atmega328p

#serial port for programmer
#Find this by typing "dmesg" after plugging in the cable
PORT=/dev/ttyACM0

#Specify the CPU frequency in Hz
#Required for the delay() function in the C source.
F_CPU=16000000UL

#Specify optimizations:t's more common to optimize for size
#not speed (-Os) due to limited flash. We need to tell the compiler
#what the MCU is (of course), and F_CPU needs to be #defined before
#the util header is included.
FLAGS=-Os -mmcu=$(MCU) -DF_CPU=$(F_CPU)

#Set these flags so they're picked up by the implicit C and C++ 
#compiler rules.
CXXFLAGS=$(FLAGS)
CFLAGS=$(FLAGS)


OBJECTS=test.o

#Bog standard linker line
test:$(OBJECTS)
	$(LD) -o $@ $<


# Programmers expect HEX files not ELF files.
# Copy the text and data sections to make a hex file.
# .text is the machine code. .data is all the static data
# I don't believe we need anything else
%.hex: %
	avr-objcopy -j .text -j .data -O ihex $< $@

clean:
	rm -f *.o *.hex test

# "make upload" target to program the MCU
# -p specify MCU
# -c progrmmer type.
# -e erase
# -U actions which are flash memory write test.hex
# -P perial port
upload:test.hex
	avrdude -p $(MCU) -c arduino -e -U flash:w:test.hex  -P $(PORT)

And that’s it. It was as simple as I expected/hoped. Other than a bit of Make guff and some verbosification to make it a bit more managable and obvious, there’s 4 lines of active code, one of which is a completely standard linker instruction. How many LOC per day would that make it? 🙂

I’d like to thank Micah Carrick and Sudar Muthu for their guides/tools which is where I got most of the information from in the end.

Advertisements