Why not arduino?

AVR atmega chips are pretty nice. What if you're feeling a bit handicaped by arduino simplicity? What if you want to do something more advanced?

Program arduino board without using arduino IDE and language (who likes this setup, loop anyway?).

Programming boards in C in Vim is much more fun it also much more low level and you'll learn much more if you try to implement your own libraries to talk with your compontents than just using already build libraries from the net which are often of rather poor quality.

If something doesn't work, it will be just your fault, not anyone else's.

Of course, this approach doesn't scale well, but learning and side projects aren't for scaling, but for trying out new things, gathering insight, and creating cool stuff.

Setup

I will assume that you have an arduino board with loaded bootloader and that you know how arduino GPIO maps to GPIO on atmega board.

Further examples will be on atmega32u4 chip.

create a directory for a project

$ cd Projects
$ mkdir atmega32u4_tutorial && cd atmega32u4_tutorial

Hello world for atmega

write a atmega hello world program like this or like below:

#include <avr/io.h>
#include <util/delay.h>

// define what pins the LEDs are connected to.
#define LED PD6

int main(void) {
  // initialize the direction of PORTD #6 to be an output
  DDRD |= (1 << LED);


  while (1) {
    // wait
    _delay_ms(200);
    // change value of LED pin
    PORTD ^= (1 << LED);
  }
}

Dependencies

Make sure that you have all dependencies installed to compile and flash your code.

On Linux it is necessary to install the packages required manually, however the effort involved is no that much different. Go to your Package Manager and install the following;

  • gcc-avr
  • binutils-avr
  • gdb-avr
  • avr-libc
  • avrdude

on ubuntu:

# apt-get install gcc-avr binutils-avr gdb-avr avr-libc avrdude

Let's build it!

Now, as we have already written our hello world code and installed all needed dependencies, it would be nice to compile it.

It's usually done with make command. If you haven't heard about make before, grab a make tutorial.

In short, you have to write a Makefile, which is just an ordinary file with specifications of make commands, if you have well written Makefile, building your code is as simple as typying make into a terminal.

Here is an example of a makefile:

###############################################################################
# Makefile for the project atmega32u4_tutorial
###############################################################################

## General Flags
PROJECT = atmega32u4_tutorial
MCU = atmega32u4
TARGET = atmega32u4_tutorial.elf
CC = avr-gcc

## Options common to compile, link and assembly rules
COMMON = -mmcu=$(MCU)

## Compile options common for all C compilation units.
CFLAGS = $(COMMON)
CFLAGS += -Wall -gdwarf-2 -O0 -D F_CPU=16000000
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d 

## Assembly specific flags
ASMFLAGS = $(COMMON)
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2

## Linker flags
LDFLAGS = $(COMMON)
LDFLAGS += 


## Intel Hex file production flags
HEX_FLASH_FLAGS = -R .eeprom

HEX_EEPROM_FLAGS = -j .eeprom
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0


## Objects that must be built in order to link
OBJECTS = main.o

## Objects explicitly added by the user
LINKONLYOBJECTS = 

## Build
all: $(TARGET) atmega32u4_tutorial.hex atmega32u4_tutorial.eep size

## Compile

main.o: ../main.c
    $(CC) $(INCLUDES) $(CFLAGS) -c  $<

##Link
$(TARGET): $(OBJECTS)
     $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)

%.hex: $(TARGET)
    avr-objcopy -O ihex $(HEX_FLASH_FLAGS)  $< $@

%.eep: $(TARGET)
    avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@

%.lss: $(TARGET)
    avr-objdump -h -S $< > $@

size: ${TARGET}
    @echo
    @avr-size -C --mcu=${MCU} ${TARGET}

## Clean target
.PHONY: clean
clean:
    -rm -rf $(OBJECTS) atmega32u4_tutorial.elf dep/* \
atmega32u4_tutorial.hex atmega32u4_tutorial.eep

## Other dependencies
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)

This Makefile offers two commands:

  • make (will compile everything)
  • make clean (will purge all compiled files)

Uploading our code

Ok, but what do we do with this compiled C code? It won't run on our precious computer...

Connect your arduino board with atmega32u4 to your computer. It good to know which linux device it's using.

You can look for it in /dev/ or run dmesg | tail and look for a message about new USB device.

To upload compiled code to your board, we will use avrdude. It was one of dependencies you installed before.

avrdude has lots of options and to make my life easier I wrote a simple script for uploading. Let's call it 'upload.sh':

#!/bin/bash
/usr/share/arduino/hardware/tools/avrdude \
-C/usr/share/arduino/hardware/tools/avrdude.conf \
-v -v -v -v -patmega32u4 -cavr109 -P/dev/ttyACM0 \
-b57600 -D -Uflash:w:atmega32u4_tutorial.hex:i

When you give it good permissions you can run it to upload compiled code to your board. Code assumes that your arduino device on linux is called /dev/ttyACM0, if it's called differently you have to change your script.

$ chmod u+x upload.sh
$ ./upload.sh

If everything works fine, you should see lots of numbers on you screen (uploaded bytecode) and your atmega32u4 board should start blinking!

Congratulations!

If you learning from tweaking some example projects, take a look at, my github repository of simmilar but a bit more advanced project robocar.