nRF905 Radio Library for AVR and Arduino

The nRF905 is a radio transceiver IC similar to the well known nRF24L01, but operates at 433/898/915MHz instead of 2.4GHz, has a much longer range and a few extra IO pins. However the nRF905 data rate is only 50Kbps compared to nRF24L01’s 2Mbps.

This library offers quite a bit of flexibility: Optional use of interrupts, 2 of the connections to the module are optional since their states can also be accessed by the ICs status register, and supports basic collision avoidance.

NOTE: v3.0.0 of the library was released on 12th September 2017, the default CD pin has changed and the AM pin is now used by the library.

Download from GitHub
Documentation

nRF905 ATmega48/88/168/328 Arduino Uno Description
VCC 3.3V 3.3V Power (3.3V)
CE D7 (13) 7 Standby – High = TX/RX mode, Low = standby
TXE B1 (15) 9 TX or RX mode – High = TX, Low = RX
PWR B0 (14) 8 Power up – High = on, Low = off
CD D4 (6) 4 Carrier detect – High when a signal is detected, for collision avoidance
AM D2 (4) 2 Address Match – High when receiving a packet that has the same address as the one set for this device, optional since state is stored in register, if interrupts are used (default) then this pin must be connected
DR D3 (5) 3 Data Ready – High when finished transmitting/High when new data received, optional since state is stored in register, if interrupts are used (default) then this pin must be connected
SO B4 (18) 12 SPI MISO (Mega pin 50)
SI B3 (17) 11 SPI MOSI (Mega pin 51)
SCK B5 (19) 13 SPI SCK (Mega pin 52)
CSN B2 (16) 10 SPI SS
GND GND GND Ground

Some of the module pin names differ from the IC pin names in the datasheet:

Module IC
CE TRX_EN
TXE TX_EN

The nRF905 is not 5V compatible, so some level conversions will need to be done with the Arduino outputs, a simple voltage divider or resistor and zener diode will do the trick, only TXE, CE, PWR, SI, SCK and CSN pins need level conversion (not CD, AM, DR and SO).

Divider
UPDATE: Use 470R instead of
4k7 and 1k instead of 10k
Zener
UPDATE: Use 470R instead of 4k7
res_div zener

The nRF905 has 511 channels ranging 422.4MHz – 473.5MHz in 100KHz steps on the 433MHz band and 844.8MHz – 947MHz in 200KHz steps on the 868/915MHz band (remember to check which frequencies are legal in your country!), but each channel overlaps adjacent channels so there is only a total of 170 usable channels at once.

Searching for nRF905, PTR8000 and PTR8000+ should yield some results for modules on Ebay and DealExtreme, you should be able to get 2 for around £10.

Callbacks
Since v3.0.0 this library uses callbacks which are ran when events occur. If the option to use interrupts is enabled then the callbacks will run from the interrupt routine so be sure that any global variables you use in them are declared ‘volatile’, just as you would when dealing with normal ISRs. These events will wake the microcontroller if it is sleeping.

Event Callback Notes
New packet incoming NRF905_CB_ADDRMATCH
Valid packet received NRF905_CB_RXCOMPLETE
Invalid packet received NRF905_CB_RXINVALID
Packet transmission complete NRF905_CB_TXCOMPLETE This only works if the nextMode is NRF905_NEXTMODE_STANDBY when calling nRF905_TX()



Nitty-gritty radio stuff
The actual air data rate of nRF905 is 100Kbps, but the data is Manchester encoded which halves it to 50Kbps. The modulation is GFSK with ±50KHz deviation. The radio also adds a few extra bits of data to the address and payload; a preamble and CRC.


Transmitted packet

Preamble
10 bits
Address
1 or 4 bytes
Payload
1 – 32 bytes
CRC
0 – 2 bytes

The address is also used as the syncword and should have as many level shifts as possible. 10100110 01100101 00011010 11011010 (2791643866) would be a good address to use, but 00000000 00000000 00000000 0010000 (32) would not be.

The CRC is used to detect errors in the received data. Having a CRC doesn’t eliminate all bad packets, there is always a small chance of a bad packet passing the CRC. Using larger CRCs helps to reduce that chance.
When the CRC is set to 16 bit the radio uses the CRC16-CCITT-FALSE (0xFFFF) algorithm. I’m not sure what it uses for 8 bit CRCs.

Transmission time
The sizes of the address, payload and CRC can be adjusted for a balance between throughput and latency.


Example configurations

Address Payload CRC = Throughput (bps) Latency (ms)
4 32 2 = 36940 6.93
1 4 1 = 17680 1.81
1 1 0 = 6838 1.17


Throughput is how much useful data can be sent (the payload part), assuming no delays for setting the payload.
Latency is how long it takes for the transmission to complete.
Switching from standby mode to receive or transmit mode takes a maximum of 650us and switching between receive and transmit modes takes a maximum of 550us.

Transmission time can be worked out with:


t = tstartup + tpreamble + ((Naddress + Npayload + NCRC) / BR)

tstartup is the time to switch mode as stated above (650us / 550us).
tpreamble is 200us for the 10 bit preamble.
Naddress, Npayload and NCRC are the address, payload and CRC sizes in bits.
BR is the bit rate which is 50,000.

For config 1, switching from standby to transmit:


t = 0.00065 + 0.0002 + ((32 + 256 + 16) / 50000)
t = 0.00693 seconds (6.93ms)

A note to developers: Before v3.0.0 this library would load the address bytes in reverse order, keep that in mind if you’re using an old version of the library to interface with other radio systems!

586 comments

3 pings

Skip to comment form

    • Chris on July 28, 2019 at 7:31 pm
    • Reply

    Hello Zak,
    First of all thank you for this library. Great work!
    The communication of my modules works flawlessly. I have also connected 2 Sevomotors to the Mega (PIN 40 and 42 with separate power supply) which permanently ticks when the communication starts. Do you have any idea why this could be?
    Many thanks and best regards,
    Chris

    1. Hey Chris, thanks! You’ll have to post your code before I can see what’s up! -> https://pastebin.com/

    • Tim on September 27, 2019 at 8:23 pm
    • Reply

    Hi Zak, I’ve built a few of these links running at 4800 baud to handle 30 bytes of data every 250mS running at 433MHz carrier.

    However on one of the links it runs ok for about 20 seconds then hangs no tx or rx activity. This problem can happen at either end and I suspect it may actually be nRf905 module related.

    I’ve tried disabling IRQ and other variants but always the same result.

    Pressing the reset button on the tx Arduino fixes the problem. Maybe there’s an overflow problem somewhere ?

    Any pointers on how to debug ?

    I’ll try slowing down the refresh rate from 250mS to 1S and see what happens

    • Tim on September 27, 2019 at 8:52 pm
    • Reply

    Hi Zak, me again. Just reduced the update rate to 1 second and still the same problem. However looking at the MOSI pin on the nRF905 when the sending end stops transmitting there is not the normal activity on this pin – looks as though some is corruption.
    Then it’ll start up again.

    Time for a beer – will look at this again tomorrow as I’m well down a ‘rabbit hole’ here 🙂

    • Tim on September 28, 2019 at 8:52 pm
    • Reply

    Hi Zak,

    further to my last e mail about a problem I was having – I’ve managed to fix it.
    I’m running the wireless UART example and found that it would hang in the rx loop and not detect incoming traffic unless the device was reset.
    This problem appears with both the Arduino and AVR code on 2 out of 5 links.
    I fixed it by putting a watch timer set to 1 second which gets reset on transmission or reception of data.
    Thus when the rx stops getting traffic the watch dog kicks in and restarts the link.
    Bit of a bodge as I’m not sure how to get to the root cause.
    Before this fix when the rx hung the carrier detect line didn’t work – so suspect it could be the nRf905 losing it settings and needing to be re-initialized ?

    Regards Tim

    1. Hey Tim, the wireless link example isn’t really very reliable, but it shouldn’t cause things to hang. Things will get even more wack if you’ve got 5 modules with the wireless link example all talking to each other, since it’s only meant for 2 modules! I don’t think the modules are loosing their settings, what state are the TXE, DR and CE pins in when it hangs?

        • Tim on September 28, 2019 at 9:53 pm
        • Reply

        Hi Zak,

        thanks for the reply – just to clarify I’m only using them in pairs but have seen this problem on a couple of pairs and the problem moves with a particular unit.
        Each pair is far enough away not to cause mutual interference and operate on a clear frequency in the 70cm 433MHz band for which I’m licensed.
        By wrapping some extra code around yours combined with the watch dog timer it’s now fairly robust.
        I’ll check the TXE, DR and CE lines when it hangs and report back.

        Best regards Tim

    • Tim on September 29, 2019 at 12:58 pm
    • Reply

    Hi Zak,

    when the rx hangs all the lines are as they should be – a bit more testing seems to indicate the rx crash is possibly being caused by something on the tx side.

    Maybe irq collisions between UART and SPI ?

    I’m sending a total of 30 characters including a string terminator and I suspect this might be the root cause as this is the maximum allowed #define MAX_PACKET_SIZE (NRF905_MAX_PAYLOAD – 2).

    Wonder why maxpayload is -2 ?

    As I’m always sending a fixed length message I’m wondering if there’s a better way to assemble the message in the nano ready for the nRF905 to process it ?

    Currently I’m sending the message character by character at 4800 – just for fun I’ll try 9600.

    Regards Tim

    • Tim on September 29, 2019 at 7:42 pm
    • Reply

    Hi Zak,

    still plugging away at this and learning / discovering as I go along. As I suspected sometimes the tx gets corrupted and either sends jibberish or only part of the packet – maybe roughly once out of a 100 packets.
    I see you mention in your code about needing a 700uS delay going from tx to rx to avoid this so I set it to 1mS then 2mS and seems to have helped but not perfect.
    I also tried to remove your ‘ack code’ – seemed pretty obvious how it worked but strangely it shortened the tx data packet.
    Time for another break and reflection !
    I’m thinking it maybe the nRF905 chip – perhaps a counterfeit device ?
    I have another batch of nRF905’s coming so will see if that helps.

    Regards Tim

    • Tim on September 30, 2019 at 7:29 pm
    • Reply

    Ok, I’m 99% certain it’s a dodgy chip problem as my code works fine on 4 out of 5 links and never misses a beat.

    On the plus side it’s caused me to refine the protocol and generally harden the code to cope with drop outs and missed data.

    I’m going to install the next batch of nRF905 modules in sockets for easy test and replace meant !

    Thanks for a great piece of code and listening to my trials and tribulations !

    • saniul on October 2, 2019 at 1:05 am
    • Reply

    Hi Zak,
    I need your help. I need to transmit a constant data through the nrf905 transceiver module at 915mhz band. I have a arduino uno and a nano. can you please tell me how to set up the whole thing and code for transmitting a constant data. I need these for my final year project. Another thing, Can it jam a mobile signal which operates under 915mhz frequency band? I know it’s illegal to make a jammer but I am working on this project which needs to jam a signal, Which I would use with my bomb disposing robot.

    1. lol I’m not going to do your school work for you.

Leave a Reply

Your email address will not be published.

Are you human? *