Monday 11 May 2015

Interrupted

Interrupted is a new approach to developing low-power, low-latency Arduino sketches, which was motivated by two observations:
  • That the default mode of programming for Arduino is busy-waiting, and
  • The runtime support for power management provided by avr-libc is basic, being charitable to it.
Taken together, these two points mean that Arduino sketches aren't easily battery-powered, while the second results in a cargo-cult of code copying. Lastly, timed sleep in Arduino is provided by delay(), which itself is busy-waiting. This increases latency, the response time to external events such as button-presses.

And so to an example; the sketch below manages a very simple hardware configuration composed of an ATtiny85, an LED and a button: the button turns the LED on and a timer turns it off again. (You could imagine such a sketch driving a Useless Machine.)

In the main loop, the CPU sleeps in select(), waking up when an event occurs on one of the devices it manages. Three events are possible here:
  • An external interrupt which occurs when the button drives pin PB2 low,
  • A pin-change when the LED on PB0 is turned on or off,
  • When the watchdog timer fires, one second after the LED comes on.
The value returned from select() indicates which event has woken it up, allowing the concise construction of state-machines. If more than one event source is ready, the one added earlier in setup() is returned, implementing a crude form of priority.

The sleep-mode entered by select() is the maximum which makes sense for the devices currently active. In this little example, SLEEP_MODE_PWR_DOWN will be chosen because external and watchdog interrupts still work in this mode.

Much credit is due to Nick Gammon, for the great work contained in his Interrupts and Power Saving Techniques for Microprocessors forum-pages.

Very similar techniques were employed in the runtimes of the Conic and Regis environments developed at Imperial College (as well as the select system call, of course).

The library has been ported to ATtiny84, ATtiny85 and ATMega328 processors and is, as always, at GitHub. Its code footprint varies, depending on the functionality required by individual sketches, but the little example above comes in at 2.5kB.

Work remains to be done on this library including porting it to Energia (i.e., the msp430 family), porting existing sketches to use it and completing the repertoire of supported devices (e.g., SPI handling).