Arduino Playground is read-only starting December 31st, 2018. For more info please look at this Forum Post

Introduction

This page is for those that want to develop software for the Arduino ATmega168-based microcontrollers but don't want to use the Arduino IDE. The reasons for not wanting to use the IDE can range from simply disliking the IDE to feeling the need to be able to write code that ports more easily to different kinds of Atmel-based microcontrollers.

Toolchains

FreeBSD

Let's start with the tools you're going to need in FreeBSD (successfully tested with FreeBSD 8.2-RELEASE). All of this software is available in /usr/ports. Please use portinstall -R -P <package> (requires /usr/ports/ports-mgmt/portupgrade).

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

If you're using an Arduino Uno or newer Arduino hardware that uses an on-board ATMel 8U2 controller to handle the USB-to-serial interface, you'll need to build and load the uarduno kernel module by building and installing the comms/uarduno port or the uarduno package.

After installing the uarduno port, you can manually load the driver with kldload uarduno.ko or automatically load it on startup, add

    uarduno_load="YES"

to your /boot/loader.conf file.

For older Arduino hardware you're going to need the FTDI driver (uftdi.ko). To load it, run the following as root: kldload uftdi.

Then detach your Arduino if it's attached and reattach it to your PC's USB host. You should see /dev/cuaUX and /dev/ttyUX appear, where X is some number representing the device's location. If you don't know which number is your board's location, run usbdevs -v.

OpenBSD

Note: See the OpenBSD CLI page for instructions specifically geared towards developing Arduino projects on OpenBSD, utilizing the Arduino programming language extensions, with more up-to-date information and instructions. (The following information will be left for the respective authors to clean up, update, etc.)

OpenBSD can also be used for CLI development with arduino. As of writing(4.6-CURRENT), no modifications to a base system are required, apart from getting the following packages.It is advised to use "pkg_add -i <packagename>" to get packages.

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

With this you can follow the rest of the example, without additional modification.

Note, however, that the avr-gcc currently(4.6-CURRENT) is still 4.2.2, which means it will not work with atmega328 devices. To work around this, just don't install avr-gcc, and build a newer version from source into /usr/local/avr. Also, avrdude config files must be updated.

Building and Uploading

Let's start with a piece of code that is easy to test: the "Hello, world!" blinking LED example! This will put us on common ground when building and deploying the software so you can be sure if it worked or not. Please copy the following code into "blink.c".

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


int main (void)
{
  /* set PORTB for output*/
  DDRB = 0xFF;

  while (1)
    {
      /* set PORTB.6 high */
      PORTB = 0x20;

      _delay_ms(1000);

      /* set PORTB.6 low */
      PORTB = 0x00;

      _delay_ms(1000);
    }

  return 1;
}

Now, going to the directory containing blink.c, run the following commands (explanations later):

    avr-gcc -DF_CPU=16000000UL \
        -mmcu=atmega168 -o blink.out blink.c # ignore the warning for now
    avr-objcopy -O ihex -R .eeprom blink.out blink.hex
    sudo avrdude -V -F -c stk500v1 -p m168 -b 19200 -P /dev/cuaU0 -U flash:w:blink.hex

You should now see the little LED blinking fairly rapidly.

Line-by-Line

  1.     avr-gcc -DF_CPU=16000000UL \
            -mmcu=atmega168 -o blink.out blink.c # ignore the warning for now
    
    This tells GCC to compile blink.c into blink.out, setting up the code so it knows it'll be running on a 16 MHz ATmega168. This is for timing purposes and must be set correctly. We also tell GCC that the MCU is an ATmega168. Without this, it will not map I/O pins and other hardware correctly when it outputs assembly.

  2.     avr-objcopy -O ihex -R .eeprom blink.out blink.hex
    
    This copies information from the ELF binary, blink.out, to blink.hex. The eeprom section is copied, which contains the part of the binary that needs to execute on the ATmega168.

  3.     sudo avrdude -V -F -c stk500v1 -p m168 -b 19200 -P /dev/cuaU0 -U flash:w:blink.hex
    
    This final line uploads blink.hex into the ATmega168's flash memory via your USB link to the Arduino. The ATmega168's bootloader follows the stk500v1 protocol for getting information from a serial line into its flash memory, and it expects data to be sent to it at 19,200 baud. NOTE: You must have root privileges for this to work (this is what "sudo" provides).

Notes

In general, you can use avr-gcc to build your code for various kinds of Atmel-based MCUs. Consult the avr-gcc documentation for a list of the various architectures available for "-mmcu", and be sure to pass the appropriate frequency (Hz) to "-DF_CPU=".

Example Makefile

The following GNUmakefile could prove useful to those wanting a simple template they can use to start larger projects. Tweak as necessary.

CC=avr-gcc
CFLAGS=-Wall -Os -DF_CPU=$(F_CPU) -mmcu=$(MCU)
MCU=atmega168
F_CPU=16000000UL

OBJCOPY=avr-objcopy
BIN_FORMAT=ihex

PORT=/dev/cuaU0
BAUD=19200
PROTOCOL=stk500v1
PART=$(MCU)
AVRDUDE=avrdude -F -V

RM=rm -f

.PHONY: all
all: blink.hex

blink.hex: blink.elf

blink.elf: blink.s

blink.s: blink.c

.PHONY: clean
clean:
	$(RM) blink.elf blink.hex blink.s

.PHONY: upload
upload: blink.hex
	$(AVRDUDE) -c $(PROTOCOL) -p $(PART) -P $(PORT) -b $(BAUD) -U flash:w:$<

%.elf: %.s ; $(CC) $(CFLAGS) -s -o $@ $<

%.s: %.c ; $(CC) $(CFLAGS) -S -o $@ $<

%.hex: %.elf ; $(OBJCOPY) -O $(BIN_FORMAT) -R .eeprom $< $@