Going beyond the Arduino IDE

Whilst great as a quick start, and undeniably providing some useful libraries. The Arduino IDE itself is very limited and it is easy to setup a much better development environment.

The 'Arduino' download includes a gcc based cross compiler for the AVR chips used in Arduinos, and avrdude for programming them. Both these have many more options then the IDE expose.

Whilst Arduino try to hide some of the standard scaffolding, an `.ino` file is actually just a standard CPP program. The IDE simple automatically adds a include for the Arduino libraries, and writes any missing function declensions you provide implementations for. This can easily be done with this Python code I adapted from [ http://inotool.org/ ] (another Command line Arduino system, but not the one I will cover here). I recommend you do this once and change to editing the pure CPP output, but obviously you can automate the conversion on every compile.

import sys import re def main: out = sys.stdout sketch = sys.stdin.read proto = prototypes(sketch) lines = sketch.split('\n') includes, lines = extract_includes(lines) out.write('#include \n') out.write('\n'.join(includes)) out.write('\n') out.write('\n'.join(proto)) out.write('\n') out.write('\n'.join(lines)) def prototypes(src): src = collapse_braces(strip(src)) regex = re.compile("[\\w\\[\\]\\*]+\\s+[&\\[\\]\\*\\w\\s]+\\([&,\\[\\]\\*\\w\\s]*\\)(?=\\s*\\{)") matches = regex.findall(src) return [m + ';' for m in matches] def extract_includes(src_lines): regex = re.compile("^\\s*#include\\s*[<\"](\\S+)[\">]") includes = [] sketch = [] for line in src_lines: match = regex.match(line) if match: includes.append(line) # if the line is #include directive it should be            # commented out in original sketch so that # 1) it would not be included twice             #  2) line numbers will be preserved sketch.append('//' + line) else: sketch.append(line) return includes, sketch def collapse_braces(src): """    Remove the contents of all top-level curly brace pairs {}.     """ result = [] nesting = 0; for c in src: if not nesting: result.append(c) if c == '{': nesting += 1 elif c == '}': nesting -= 1 result.append(c) return ''.join(result) def strip(src): """    Strips comments, pre-processor directives, single- and double-quoted     strings from a string.     """ # single-quoted character p = "('.')" # double-quoted string p += "|(\"(?:[^\"\\\\]|\\\\.)*\")"        # single and multi-line comment     p += "|(//.*?$)|(/\\*[^*]*(?:\\*(?!/)[^*]*)*\\*/)"         # pre-processor directive     p += "|" + "(^\\s*#.*?$)"     regex = re.compile(p, re.MULTILINE)     return regex.sub(' ', src) if __name__ == '__main__':     main
 * 1) ! /usr/bin/env python
 * 2) -*- coding: utf-8; -*-
 * 3) Hacked from Ino http://inotool.org
 * 4) License: MIT

= Flashing =

To communicate with the hardware Arduino always used `avrdude` either via the bootloader (referred to as the 'arduino' programmer) or via an ISP. You need to tell avrdude the programmer you are using and sometimes the port and speed, but once you have done this you can have more flexibility:

If you want to overwrite the boot-loader and save some space:

avrdud -p atmega328p ... -U flash:w:firmware.hex:i

If you want to backup the existing firmware:

avrdud -p atmega328p ... -U flash:r:backup.hex:i

You can also change fuses to reconfigure how the AVR works. [ http://www.engbedded.com/fusecalc ] makes finding the right settings easy. For instance disable the brown out detector:

avrdude -p atmega328p ... -U efuse:w:0xff:m

= CLI =

My preferred build environment is a old-fashioned Makefile from the command line. This lets you see exactly what is happening and also change exactly what you want. Whilst the learning curve is undeniably steeper, this is actually a lot less to learn and overall it is much easier.

For Arduino's I recommend [ https://github.com/sudar/Arduino-Makefile.git ]. This dose the same magic as the IDE when it comes to including the right libraries. Then simply create a Makefile with a few settings:

ARDUINO_DIR   = ../arduino-1.0.5 BOARD_TAG     = atmega328 include Arduino-Makefile/arduino-mk/Arduino.mk

You can then compile and upload with `make upload`. You will notice that recompiles are already much quicker then in the IDE.

Debugging
IMO the most important thing missing from the IDE is a debugger. Simply add `DEBUG = 1` to your Makefile to get a full debug symbols then you have two options:

Hardware Emulator
You can buy a hardware emulator. I use the cheep [ http://uk.rs-online.com/web/p/processor-microcontroller-development-kits/6962566/ ] but it has a few design faults: don't under volt its USB supply or touch it whilst operating! This is great as you can debug real hardware (using just the reset pin), with hardware breakpoints and most of what you need.

First build and flash your AVR, then you then need to enable the DebugWire on the AVR:

avrdude -p atmega328p -c dragon_isp -b 57600 -P usb -U hfuse:w:0x9a:m

Then install and run:

avarice -g -w -P atmega328p :1234

Then create a .gdbinit to connect on startup:

target remote localhost:1234 set can-use-hw-watchpoints 0

(The second line is just because the auto-detect failed for me)·

Software Simulator
Download and build:

git clone https://git.gitorious.org/simavr/simavr.git

This includes a `examples/board_simduino` that compiles into `obj-x86_64-pc-linux-gnu/simduino.elf` which simulates the 328 runs the Arduino bootloader and creates a virtual serial port in /tmp/simavr-uart0. This meas you can then flash it with firmware like a normal Arduino but also debug it via TCP port 1234. This emulator can run much faster then the hardware and supports full watches etc. giving you much more flexibility.

I have had some multithreading issues with `simduino.elf` UART, perversely the easiest work around seems to be to actually attach a debugger to it. i.e. launch (then r to actually run):

gdb obj-x86_64-pc-linux-gnu/simduino.elf

Create the .gdbinit

target remote localhost:1234

The sim-avr source also includes some other common parts like LCD screens so you can emulate a complete board with a few changes to the code.

Debugging
Then debug:

avr-gdb ${PATH_TO_YOUR_ELF}

= Eclipse =

For people who prefer GUIs then Eclipse is very powerful. You will soon laugh at the Arduino IDE's code completion and syntax highlighting. It is particularly useful when debugging, but a bit of a pain to configure.

There are dedicated Arduino plug-ins but they require specific versions of the IDE and Eclipse, it is easier to use the generic AVR plugin.

Setup
First install the CDT (C Development Tools) or download that version of Eclipse. Then add a new update site: http://avr-eclipse.sourceforge.net/updatesite and install the plugin it provides.

In `Window->Preferences->AVR->Paths` you need to set:

AVR-GCC = ${ARDUINO}\hardware\tools\avr\bin AVR Header Files = ${ARDUINO}\hardware\tools\avr\avr\include

Where ${ARDUINO} is the full path of your Arduino IDE install.

Then create a Arduino Library called 'ArduinoCore' you can use in all your other programs: `New->C++ Project->AVR Cross Target Static Library->Empty Project` set the right chips (ATmega328P 16000000Hz). Add the include paths under `Properties->C/C++ Build->Settings->AVR Compiler->Directories` and `Properties->C/C++ Build->Settings->AVR C++ Compiler->Directories`

${ARDUINO}\hardware\arduino\cores\arduino ${ARDUINO}\hardware\arduino\variants\standard

Then import all the files except main.cpp from:

${ARDUINO}\hardware\arduino\cores\arduino

And build.

Use
You can then create `AVR Cross Target Application` projects with the same chip and include settings. You then need to `Properties->C/C++ Build->Settings->AVR C++ Linker->Libraries` and add 'ArduinoCore' as a library and the workspace path to the other library project's output to the path.

You can also setup avrdude to use 'arduino' or your ISP then just click the 'AVR' icon on the tool bar.

This way we get to write our own main routine, which if you want normal Arduino behaviour is:

int main(void) { init; setup; while(true) { loop; } }

Debugging
I find the default Eclipse 'debugging' output doesn't have all the info. So change `Properties->C/C++ Build->Settings->AVR Compiler->Debugging` and `Properties->C/C++ Build->Settings->AVR C++->Debugging` to -g3 and stabs+.

Then create a `C/C++ Remote Application' debug configuration changing the Debugger to 'avr-gdb' and the remote port to 1234.