RF22
RF22 library for Arduino

This is the Arduino RF22 library. It provides an object-oriented interface for sending and receiving data messages with Hope-RF RF22B based radio modules, and compatible chips and modules, including the RFM22B transceiver module such as this bare module: http://www.sparkfun.com/products/10153 and this shield: http://www.sparkfun.com/products/11018

RF22 also supports some of the features of ZigBee and XBee, (such as mesh routing and automatic route discovery), but with a much less complicated system and less expensive radios.

The Hope-RF (http://www.hoperf.com) RFM22B (http://www.hoperf.com/rf_fsk/fsk/RFM22B.htm) is a low-cost ISM transceiver module. It supports FSK, GFSK, OOK over a wide range of frequencies and programmable data rates. Manual can be found at https://www.sparkfun.com/datasheets/Wireless/General/RFM22.PDF

This library provides functions for sending and receiving messages of up to 255 octets on any frequency supported by the RF22B, in a range of predefined data rates and frequency deviations. Frequency can be set with 312Hz precision to any frequency from 240.0MHz to 960.0MHz.

Up to 3 RF22B modules can be connected to an Arduino, permitting the construction of translators and frequency changers, etc.

This library provides classes for

The following modulation types are suppported with a range of modem configurations for common data rates and frequency deviations:

Support for other RF22B features such as on-chip temperature measurement, analog-digital converter, transmitter power control etc is also provided.

The latest version of this documentation can be downloaded from http://www.airspayce.com/mikem/arduino/RF22

Example Arduino programs are included to show the main modes of use.

The version of the package that this documentation refers to can be downloaded from http://www.airspayce.com/mikem/arduino/RF22/RF22-1.39.zip You can find the latest version at http://www.airspayce.com/mikem/arduino/RF22

You can also find online help and disussion at http://groups.google.com/group/rf22-arduino Please use that group for all questions and discussions on this topic. Do not contact the author directly, unless it is to discuss commercial licensing. Before asking a question or reporting a bug, please read http://www.catb.org/esr/faqs/smart-questions.html

Tested on Arduino Diecimila and Mega with arduino-0021 on OpenSuSE 11.1 and avr-libc-1.6.1-1.15, cross-avr-binutils-2.19-9.1, cross-avr-gcc-4.1.3_20080612-26.5. With HopeRF RFM22 modules that appear to have RF22B chips on board:

Packet Format

All messages sent and received by this RF22 library must conform to this packet format:

For technical reasons, the message format is not compatible with the 'HopeRF Radio Transceiver Message Library for Arduino' http://www.airspayce.com/mikem/arduino/HopeRF from the same author. Nor is it compatible with 'Virtual Wire' http://www.airspayce.com/mikem/arduino/VirtualWire.pdf also from the same author.

Connecting RFM-22 to Arduino

If you have the Sparkfun RFM22 Shield (https://www.sparkfun.com/products/11018) the connections described below are done for you on the shield, no changes required, just add headers and plug it in to an Arduino (but not and Arduino Mega, see below)

The physical connection between the RF22B and the Arduino require 3.3V, the 3 x SPI pins (SCK, SDI, SDO), a Slave Select pin and an interrupt pin. Note also that on the RFF22B, it is required to control the TX_ANT and X_ANT pins of the RFM22 in order to enable the antenna connection. The RF22 library is configured so that GPIO0 and GPIO1 outputs can control TX_ANT and RX_ANT input pins automatically. You must connect GPIO0 to TX_ANT and GPIO1 to RX_ANT for this automatic antenna switching to occur.

If you are using the Sparkfun RF22 shield, it will work with any 5V arduino without modification. Connect the RFM-22 module to most Arduino's like this (Caution, Arduino Mega has different pins for SPI, see below):

* Arduino RFM-22B
* GND----------GND-\ (ground in)
* SDN-/ (shutdown in)
* 3V3----------VCC (3.3V in)
* interrupt 0 pin D2-----------NIRQ (interrupt request out)
* SS pin D10----------NSEL (chip select in)
* SCK pin D13----------SCK (SPI clock in)
* MOSI pin D11----------SDI (SPI Data in)
* MISO pin D12----------SDO (SPI data out)
* /--GPIO0 (GPIO0 out to control transmitter antenna TX_ANT
* \--TX_ANT (TX antenna control in)
* /--GPIO1 (GPIO1 out to control receiver antenna RX_ANT
* \--RX_ANT (RX antenna control in)
*

For an Arduino Mega:

* Mega RFM-22B
* GND----------GND-\ (ground in)
* SDN-/ (shutdown in)
* 3V3----------VCC (3.3V in)
* interrupt 0 pin D2-----------NIRQ (interrupt request out)
* SS pin D53----------NSEL (chip select in)
* SCK pin D52----------SCK (SPI clock in)
* MOSI pin D51----------SDI (SPI Data in)
* MISO pin D50----------SDO (SPI data out)
* /--GPIO0 (GPIO0 out to control transmitter antenna TX_ANT
* \--TX_ANT (TX antenna control in)
* /--GPIO1 (GPIO1 out to control receiver antenna RX_ANT
* \--RX_ANT (RX antenna control in)
*

For Chipkit Uno32. Caution: you must also ensure jumper JP4 on the Uno32 is set to RD4

* Arduino RFM-22B
* GND----------GND-\ (ground in)
* SDN-/ (shutdown in)
* 3V3----------VCC (3.3V in)
* interrupt 0 pin D38----------NIRQ (interrupt request out)
* SS pin D10----------NSEL (chip select in)
* SCK pin D13----------SCK (SPI clock in)
* MOSI pin D11----------SDI (SPI Data in)
* MISO pin D12----------SDO (SPI data out)
* /--GPIO0 (GPIO0 out to control transmitter antenna TX_ANT
* \--TX_ANT (TX antenna control in)
* /--GPIO1 (GPIO1 out to control receiver antenna RX_ANT
* \--RX_ANT (RX antenna control in)
*

and you can then use the default constructor RF22(). You can override the default settings for the SS pin and the interrupt in the RF22 constructor if you wish to connect the slave select SS to other than the normal one for your Arduino (D10 for Diecimila, Uno etc and D53 for Mega) or the interrupt request to other than pin D2 (Caution, different processors have different constraints as to the pins available for interrupts).

It is possible to have 2 radios connected to one Arduino, provided each radio has its own SS and interrupt line (SCK, SDI and SDO are common to both radios)

Caution: on some Arduinos such as the Mega 2560, if you set the slave select pin to be other than the usual SS pin (D53 on Mega 2560), you may need to set the usual SS pin to be an output to force the Arduino into SPI master mode.

Caution: Power supply requirements of the RF22 module may be relevant in some circumstances: RF22 modules are capable of pulling 80mA+ at full power, where Arduino's 3.3V line can give 50mA. You may need to make provision for alternate power supply for the RF22, especially if you wish to use full transmit power, and/or you have other shields demanding power. Inadequate power for the RF22 is reported to cause symptoms such as:

Caution: some RF22 breakout boards (such as the HAB-RFM22B-BOA HAB-RFM22B-BO) reportedly have the TX_ANT and RX_ANT pre-connected to GPIO0 and GPIO1 round the wrong way. You can work with this if you edit RF22.cpp and change the code that does spiWrite(RF22_REG_0B_GPIO_CONFIGURATION0, 0x12). See the comments there

Caution: If you are using a bare RF22 module without IO level shifters, you may have difficulty connecting to a 5V arduino. The RF22 module is 3.3V and its IO pins are 3.3V not 5V. Some Arduinos (Diecimila and Uno) seem to work OK with this, and some (Mega) do not always work reliably. Your Mileage May Vary. For best result, use level shifters, or use a RF22 shield or board with level shifters built in, such as the Sparkfun RFM22 shield http://www.sparkfun.com/products/11018. You could also use a 3.3V IO Arduino such as a Pro. It is recognised that it is difficult to connect the Sparkfun RFM22 shield to a Mega, since the SPI pins on the Mega are different to other Arduinos, But it is possible, by bending the SPI pins (D10, D11, D12, D13) on the shield out of the way before plugging it in to the Mega and jumpering the shield pins to the Mega like this:

* RF22 Shield Mega
* D10 D53
* D13 D52
* D11 D51
* D12 D50
*
Interrupts

The RF22 library uses interrupts to react to events in the RF22 module, such as the reception of a new packet, or the completion of transmission of a packet. The RF22 library interrupt service routine reads status from and writes data to the the RF22 module via the SPI interface. It is very important therefore, that if you are using the RF22 library with another SPI based deviced, that you disable interrupts while you transfer data to and from that other device. Use cli() to disable interrupts and sei() to reenable them.

SPI Interface

The RF22 module uses the SPI bus to communicate with the Arduino. Arduino IDE includes a hardware SPI class to communicate with SPI devices using the SPI facilities built into the Atmel chips, over the standard designated SPI pins MOSI, MISO, SCK, which are usually on Arduino pins 11, 12 and 13 respectively (or 51, 50, 52 on a Mega).

By default, the RF22 library uses the Hardware SPI interface to communicate with the RF22 module. However, if your RF22 SPI is connected to the Arduino through non-standard pins, and the standard Hardware SPI interface will not work for you, you can instead use a bit-banged Software SPI, which can be configured to work on any Arduino digital IO pins. A sample Software SPI class contributed by Chris Lapa is included in the RF22 library, and example sketches showing how to use it are in rf22_client_softwarespi and rf22_server_softwarespi. Thanks Chris!

The advantages of the Software SPI interface are that it can be used on any Arduino pins, not just the usual dedicated hardware pins. The disadvantage is that it is slightly slower then hardware.

Memory

The RF22 library requires non-trivial amounts of memory. The sample programs above all compile to about 9 to 14kbytes each, which will fit in the flash proram memory of most Arduinos. However, the RAM requirements are more critical. Most sample programs above will run on Duemilanova, but not on Diecimila. Even on Duemilanova, the RAM requirements are very close to the available memory of 2kbytes. Therefore, you should be vary sparing with RAM use in programs that use the RF22 library on Duemilanova.

The sample RF22Router and RF22Mesh programs compile to about 14kbytes, and require more RAM than the others. They will not run on Duemilanova or Diecimila, but will run on Arduino Mega.

It is often hard to accurately identify when you are hitting RAM limits on Arduino. The symptoms can include:

With an Arduino Mega, with 8 kbytes of SRAM, there is much more RAM headroom for your own elaborate programs. This library is reported to work with Arduino Pro Mini, but that has not been tested by me.

The Arduino UNO is now known to work with RF22.

Automatic Frequency Control (AFC)

The RF22M modules use an inexpensive crystal to control the frequency synthesizer, and therfore you can expect the transmitter and receiver frequencies to be subject to the usual inaccuracies of such crystals. The RF22 contains an AFC circuit to compensate for differences in transmitter and receiver frequencies. It does this by altering the receiver frequency during reception by up to the pull-in frequency range. This RF22 library enables the AFC and by default sets the pull-in frequency range to 0.05MHz, which should be sufficient to handle most situations. However, if you observe unexplained packet losses or failure to operate correctly all the time it may be because your modules have a wider frequency difference, and you may need to set the afcPullInRange to a differentvalue, using setFrequency();

Performance

Some simple speed performance tests have been conducted. In general packet transmission rate will be limited by the modulation scheme. Also, if your code does any slow operations like Serial printing it will also limit performance. We disabled any printing in the tests below. We tested with RF22::GFSK_Rb125Fd125, which is probably the fastest scheme available. We tested with a 13 octet message length, over a very short distance of 10cm.

Transmission (no reply) tests with modulation RF22::GFSK_Rb125Fd125 and a 13 octet message show about 330 messages per second transmitted.

Transmit-and-wait-for-a-reply tests with modulation RF22::GFSK_Rb125Fd125 and a 13 octet message (send and receive) show about 160 round trips per second.

Installation

Install in the usual way: unzip the distribution zip file to the libraries sub-folder of your sketchbook.

This software is Copyright (C) 2011 Mike McCauley. Use is subject to license conditions. The main licensing options available are GPL V2 or Commercial:

Open Source Licensing GPL V2

This is the appropriate option if you want to share the source code of your application with everyone you distribute it to, and you also want to give them the right to share who uses it. If you wish to use this software under Open Source Licensing, you must contribute all your source code to the open source community in accordance with the GPL Version 2 when your application is distributed. See http://www.gnu.org/copyleft/gpl.html

Commercial Licensing

This is the appropriate option if you are creating proprietary applications and you are not prepared to distribute and share the source code of your application. Contact info@.nosp@m.airs.nosp@m.payce.nosp@m..com for details.

Revision History
Version
1.0 Initial release
1.1 Added rf22_snoop and rf22_specan examples
1.2 Changed default modulation to FSK_Rb2_4Fd36 Some internal reorganisation. Added RF22Router and RF22Mesh classes plus sample programs to support multi-hop and automatic route discovery.
1.3 Removed some unnecessary debug messages. Added virtual doArp and isPhysicalAddress functions to RF22Mesh to support other physical address interpretation schemes (IPV4/IPV6?)
1.4 RF22Router and RF22Mesh were inadvertently left out of the distro.
1.5 Improvements contributed by Peter Mousley: Modem config table is now in flash rather than SRAM, saving 400 bytes of SRAM. Allow a user-defined buffer size. Thanks Peter.
1.6 Fixed some minor typos on doc and clarified that this code is for the RF22B. Fixed errors in the definition of the power output constants which were incorrectly set to the values for the RF22. Reported by Fred Slamen. If you were using a previous version of RF22, you probably were not getting the output power you thought.
1.7 Added code to initialise GPIO0 and GPIO1 so they can automatically control the TX_ANT and RX_ANT antenna switching inputs. You must connect GPIO0 to TX_ANT and GPIO1 to RX_ANT for this automatic antenna switching to occur. Updated doc to reflect this new connection requirement
1.8 Changed the name of RF22_ENLBD in RF22_REG_06_INTERRUPT_ENABLE2 to RF22_ENLBDI because it collided with a define of the same name in RF22_REG_07_OPERATING_MODE. RF22_REG_05_INTERRUPT_ENABLE1 enable mask incorrectly used RF22_IFFERROR instead of RF22_ENFFERR. Reported by Steffan Woltjer.
1.9 Fixed typos in RF22_REG_21_CLOCk*. Reported by Steffan Woltjer.
1.10 Fixed a problem where a IFFERR during transmission could cause an infinite loop and a hang. Reported by Raymond Gilbert.
1.11 Fixed an innocuous typo in RF22::handleInterrupt. Reported by Zhentao.
1.12 Improvements to RF22::init from Guy Molinari to improve compatibility with some Arduinos. Now reported to be working with official Mega 2560 and Uno. Updated so compiles on Arduino 1.0.
1.13 Announce google support group
1.14 Added definitions for bits and masks in RF22_REG_1D_AFC_LOOP_GEARSHIFT_OVERRIDE and RF22_REG_1E_AFC_TIMING_CONTROL
1.15 Small alterations to initialisation code so that SS pin is not set to output: may cause interference with other devices connected to the Arduino. Testing with Uno: OK.
1.16 Fixed a problem that prevented building with arduino 0021
1.17 Added optional AFC pull-in frequency range argument to setFrequency(). Default AFC pull-in range set to 0.05MHz
1.18 Changed default value for slave slect pin in constructor to be SS, ie the normal one for the compiled Arduino (D10 for Diecimila, Uno etc and D53 for Mega). This is because some Arduinos such as Mega 2560 reportedly use the type of the SS pin to determine whether to run in slave or master mode. Therfore it is preferred that the slave select pin actually be the normal SS pin.
1.19 Added new mode() function. Fixed a potential race condition in RF22Datagram::recvfrom which might cause corrupt from, to, id or flags under extreme circumstances. Improvements to interrupt hygeine by adding cli()_/sei() around all RF22 register acceses. Found that 0 length transmit packets confuses the RF22, so they are now forbidden. Added IPGateway example, which routes UDP messages from an internet connection using an Ethernet Shield and sends them to a radio whose ID is based on the UDP port. Replies are sent back to the originating UDP address and port.
1.20 _mode is now volatile. RF22::send() now waits until any previous transmission is complete before sending. RF22::waitPacketSent() now waits for the RF22 to not be in _mode == RF22_MODE_TX _txPacketSent member is now redundant and removed. Improvements to interrupt handling and blocking. Now use ATOMIC_BLOCK(ATOMIC_RESTORESTATE) to prevent reenabling interrupts too soon. Thanks to Roland Mieslinger for this suggestion. Added some performance measurements to documentation.
1.21 Fixed a case where a receiver buffer overflow could occur. Reported by Joe Tuttle.
1.22 Added documentation after testing with Sparkfun RFM22 Shield DEV-11018. Fixed incorrect link to register calculator excel file, reported by Joey Morin.
1.23 Added support for alternative SPI interfaces, with default implementation for the standard Arduino hardware SPI interface. Contributed by Joanna Rutkowska.
1.24 Fixed a problem that could cause corrupted receive messages if a transmit interrupted a partial receive (as was common with eg ReliableDatagram with poor reception. Also fixed possible receive buffer overrun.
1.25 More rigorous use of const, additional register defines (RF22_CRCHDRS RF22_VARPKLEN) and two methods (setPreambleLength() and setSyncWords())made public. Patch provided by Matthijs Kooijman.
1.26 Added Cautions about RF22 IO voltages , level shifters and Mega. Include Doxygen documentation in distribution.
1.27 Updated author and distribution location details to airspayce.com Added example demodulated data from an actual RF22 transmission assembled by this RF22 library
1.28 Fixed a problem that prevented packets of more than 59 octets being sent properly. This problem was introduced in a recent update.
1.29 Improvements to waitAvailableTimeout to make it robust on millis() rollover. Contributed by Mats Byggmastar.
1.30 More improvements to timeouts to be robust on millis() rollover. Contributed by Mats Byggmastar.
1.31 Added new function bool waitPacketSent(uint16_t timeout) requested by Benoit Joassart
1.32 Can now specify interrupt number 2 in constructor.
1.33 Now also compiles for Chipkit Uno32 under mpide-0023. Beta testing only. Operational reports and testing are welcome.
1.34 Added rf22_serial_modem example which implements a transparent serial-radio-serial connection.
1.35 Added setCRCPolynomial() to permit alternative CRC polynomials to be used for comptibility with other radio hardware. Fixed a case where noise or certain types of runt packets could cause the RX fifo to get confused, losing the start point of the next message. Added missing define for RF22_SKIP2PH option for register 30. Added new modem config FSK_Rb_512Fd2_5 for POCSAG for Kristoff Bonne.
1.36 Added new modem config FSK_Rb_512Fd4_5 for POCSAG for Kristoff Bonne.
1.37 Added SoftwareSPI.h, which is bit-banged software SPI interface class contributed by by Chris Lapa. Also examples sketches rf22_client_softwarespi.ino and rf22_server_softwarespi.ino showing how to use it.
1.38 Chris Lapa corrected some minor errors in SoftwareSPI.h. Thanks Chris.
1.39 rf22_serial_modem.ino was accidentally omitted
Author
Mike McCauley (mikem.nosp@m.@air.nosp@m.spayc.nosp@m.e.co.nosp@m.m) DO NOT CONTACT THE AUTHOR DIRECTLY. USE THE LISTS