Thursday, September 5, 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.
ATtiny-x5

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.


ATtiny-x4
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.

7 comments:

  1. Hi, whanted to thank you for that post! Would you mind posting the pin connections to ATtiny85/84? I've tryed guessing from the code but something is not working for me. Same code works on Mega328.

    Thanks again!

    ReplyDelete
    Replies
    1. Good idea. I've added some explanation of the SPI mappings and connecting to a radio. Hope it helps!

      Delete
  2. Hello. Before anything, thank you for the sharing of your work.
    I would like to know one thing, since you went to Jee Labs for some inspiration and base work, did you consider having encryption in your fork of the RF24, with xxtea like Jee Labs has on is, for the RF he uses?
    Thank you.

    ReplyDelete
    Replies
    1. I hadn't noticed that feature, it's interesting! It might even be possible to add it in the ATtiny's remaining space. Not sure if it would leave much room for the actual sketch though!

      To be clear though: all I did with RF24 was blindly reduce its footprint for ATtiny. I didn't think about changing it in any other way. It would probably be better to ask Maniacbug to add it to his upstream codebase? (More room on the ATmega anyway.)

      Delete
  3. Hi Steve..

    I'm the blogger for http://arduino-for-beginners.blogspot.com/ and I'm glad to find your blog...

    I had made these attiny84 PCB and was trying to get the RF24 to compile on the attiny84... luckily I found your SPI forks for attiny from a mentioned on the Arduino forum...

    I'm able to upload the codes to the attiny84 but my Arduino as a hub codes was not receiving anything from the attiny84/nRF ...

    Without all those print_details statements, how do I know if the radio is working ?? How do you do the debugging ?

    My Tiny nRF PCBs :
    http://farm4.staticflickr.com/3758/12700701585_491d93ff84.jpg

    ReplyDelete
    Replies
    1. Hi Stanley,
      As far as I can remember now (it's been about a year since the original investigation) I had a pretty hard time getting it all working initially.

      I ended up with two ATmegas running Maniacbug's code (with prints) trying to talk to each other (and failing) until I put decoupling capacitors across the radios' power pins. Once this was working, I kept one ATmega and moved the other to ATtiny.

      Hope this helps,
      Steve

      BTW your RF24 code for Raspberry Pi was very useful to me later on: thanks!

      Delete