Thursday, 5 September 2013

RF24 with ATtiny84

An ATtiny84 and nrf24l01+ transceiver
The nrf24l01+ is an amazing little wireless transceiver which is (a) incredibly cheap (how about 10 for €8?) (b) can be put into an extremely low-power mode under software when not transmitting and (c) is controlled over SPI (available on Arduino). Furthermore Arduino has support for them via the Mirf library. Unfortunately this library isn't super-easy to use (although I've seen worse).

Luckily for us, someone called Maniacbug has produced an excellent pair of libraries (RF24 and RF24Network) which simplify use of these devices considerably, and in a manner consistent with the Arduino way. The latter library makes building meshed wireless networks very easy indeed. (If you're thinking XBee at a twentieth-the-cost, you're way ahead of me.) An RF24Network article describes the design and implementation of an impressively low-cost, whole-building, wireless sensor network scalable to thousands of sensors.

While reading about this sensor network, a question arose: why was it restricted to ATmegas? Surely an ATtiny would be equally up to the job? It turns out that I wasn't the first to think about this. One source of problems was the ambiguous nature of the SPI interface on ATtiny chips.

Although these chips have pins named after SPI functions (SCK, MISO, MOSI) they are primarily for programming the chip over SPI, not for use in the SPI master role, to control other devices. However USI (for Universal Serial Interface), which can be used to implement SPI, is provided. In principle, therefore, it should be possible to talk to an nrf24l01 radio from an ATtiny, and it turns out by forking the Mirf library, it has been done.

While USI-SPI is demonstrated only for ATtiny85, mutatis mutandis it is pretty easy to make work on an ATtiny84 as well. (Blindly mapping pins by name works pretty well.) A bigger problem is that RF24 relies on the built-in Arduino SPI library, which only works on ATmegas. This library could be a poster-child for the library-dependency problem --- i.e., how to replace an underlying dependency of a library cleanly. In short, with the current Arduino library handling semantics, it's impossible: only one approach works and that's to edit it. (One small consolation is that it's not necessary to edit it in place, the IDE will search ~/sketchbook/libraries before its built-in libraries.)

My cross-platform SPI library is here, (credit is due to Nick Gammon, SPI85 and JeeLib's RF12 driver). It supports ATtiny-x4 and -x5 as well as ATmegas.

The SPI library uses the pins marked DI/DO/USCK in each of the ATtiny pinouts linked here. (Note that DI/DO are not the same as MISO and MOSI!) For the ATtiny84, SS is mapped to PA7 (pin 6), while on the '85 it's mapped to PB3 (pin 2).

Armed with this library, and the ATtiny development environment described yesterday, it was a simple matter to compile the helloworld_tx example from RF24Network. And, while it compiled fine, it failed to link because the resulting binary was too large for the ATtiny84's 8kB code space. An inspection of the library code revealed extensive use of printf_P, which eats up a lot of flash space on an ATtiny. A quick hack with the C preprocessor and the code size was down to 5700 bytes, leaving a couple of kB for user sketches.

When connecting a radio, DO connects to MOSI, DI to MISO and USCK to SCK. CE and CSN can be set to anything reasonable (check cores/tiny/pins_arduino.c for the Arduino pin mappings).

Here are my forked RF24 and RF24Network libraries.

Wednesday, 4 September 2013

ATtiny84 Development Board

 This little board was inspired by a series of articles at JeeLabs describing how to program a JNµ from Arduino-1.5. (I tweaked a couple of values in its boards.txt but otherwise it's as described there.)

Background: since the ATtiny has no bootloader support, it can't be programmed with an FTDI cable but requires an ISP (e.g., an Arduino running the ArduinoISP example) to upload sketches to it over SPI, via avrdude (as seen below). The latest version of the Arduino IDE now supports this from within the IDE itself.
Programming it.
However I chose to add an FTDI connector because the authors of the arduino-tiny core had cunningly added a transmit-only serial emulation (on pin PB0 on the ATtiny84). (While a SoftwareSerial library which can also receive data exists, it's not yet supported on IDE 1.5.2. However I added future support for it anyway by wiring the receive line to PB1.)

Board layout
But wait, there's more! This fine article points out an alternative to ArduinoISP, which can also act as a serial relay: TinyISP. It provides two ways of doing this: by relaying SoftwareSerial and a (more robust) alternative called Knock-Bang. Each of these methods uses the SPI lines so no extra connector is required. This allows programming an ATtiny in almost the same way as an Arduino --- except you need an Arduino to act as a serial port for it!