Jan 01 2013

nRF905 AVR/Arduino Library/Driver

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.

Download from GitHub

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 D2 (4) 2 Carrier detect – High when a signal is detected, for collision avoidance
AM 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, not used by this library
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 this pin must be connected
NOTE: On Arduino Mega change INTERRUPT_NUM to 5 in nRF905_config.h and for Arduino Yun it should be changed to 0.
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

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

Module IC

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).

UPDATE: Use 470R instead of
4k7 and 1k instead of 10k
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.

Library coding tips

  • You can call nRF905_receive() straight after calling nRF905_sendData(), this makes the radio go into receive mode once the payload has finished transmitting.
  • Calling an nRF905_set***() function will put the radio into standby mode (radio must be in standby mode to change registers), if you want it to carry on receiving you must call nRF905_receive() again.

Nitty-gritty radio stuff
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

10 bits
1 or 4 bytes
1 – 32 bytes
0 – 2 bytes

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.

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: This library loads the address bytes in reverse order, keep that in mind if you try to use this library to interface with other radio systems!


1 ping

Skip to comment form

  1. Jasmin

    is this how i will put it in a while loop? i’ve tried it but the arduino does not read sensor data anymore

    1. Zak Kemble

      Yup. You could see if the ping example work as that has the send in a while() loop, if the example doesn’t work then you might have a wiring issue (probably to do with the CD pin).

      1. Jasmin

        it does not work 🙁 however, i checked the CD pin and it is connected to pin2. all the other pins are also connected correctly.

        1. Zak Kemble

          Did you load ping_client on to one Arduino, and ping_server onto another? There’s definitely a wiring issue if pings don’t work, could you post some picture of your setup?

          1. Jasmin

            Yes we did. where can i post the pictures? do you need the picture of the connections?

          2. Zak Kemble

            You can upload to https://imgur.com Yeah, pictures of all the wires connecting the Arduino to the radio module.

  2. Jasmin

    here are the pictures.

  3. Jasmin

    we tried again, it’s not ping time out anymore. but on the other side, it only outputs waiting for ping.

    1. Zak Kemble

      Ah, you’re using a MEGA. Have you changed INTERRUPT_NUM to 5 in nRF905_config.h?

      1. Jasmin

        oh, i’ve changed it before but now that i have checked it, it went back to 1. ugh. now it is working thank you ^_^ but there are many garbage data, how can we eliminate or lessen those?

        1. Zak Kemble

          Hah alright 😛 Can you post a screen shot showing the bad data?

          1. Jasmin

            here’s the screen shot 🙂

          2. Zak Kemble

            What does your latest code look like now? (pastebin)

  4. Jasmin

    here is the print screen of the output from the ping example

  5. Brian

    Hey I’m having trouble getting these two NRF905 modules talking with two Arduino Uno R3 controllers. I have followed your Arduino Uno connections to the letter and I am using the ping_client, ping_server code provided. I have the digital pins directly connected to the NRF905 pins. When I change the interrupt to 0 (as I’ve read in through the comments) in the config file the client prints out:

    Client started
    Ping time: 0ms
    Data from server:

    and the server:

    Server started
    Waiting for ping…

    Nothing happens in the server side after that. I’m guessing the receiver isn’t working? Would you have any suggestions? I’ve been racking my brain all day. I’ve used recommended below connections: Thank you for your help and time!

    * 7 -> CE
    * 8 -> PWR
    * 9 -> TXE
    * 2 -> CD
    * 3 -> DR
    * 10 -> CSN
    * 12 -> SO
    * 11 -> SI
    * 13 -> SCK

    1. Zak Kemble

      Hi Brian, if the ping time is 0 or 1 then there is a problem with the client side, as it already takes around 6ms just for the radio to transmit the packet. What does the debug example print out?

      1. Brian

        Hey Zak,

        Thanks for the reply! Sorry in the client side it does display 6ms afterwards, but the issue is the receiver I believe. It’s just stays at the “waiting for ping….” print. Are there different pin connections for the receiver side? I have both wired exactly the same according to your tutorial.


        1. Zak Kemble

          6ms still means there’s an issue on the client side, it should timeout if it doesn’t get a response from the server. The “Data from server” part should print out “test #” where # is a number that increments if everything is ok. Both sides have the same connections, could you post a picture of the client side connections? Upload to http://imgur.com

  6. Jasmin

    Hello Zak! I would like to ask if it is possible to increase the maximum payload in your program from 32 bytes to 64 bytes? If yes, how can we implement it? Thanks!

    1. Zak Kemble

      No, 32 bytes is the limit as that the maximum payload the nRF905 radio can send.

  7. Jasmin

    Hey 🙂 I have another question. The serial monitor freezes when I send a frame. What can i do to solve this?

    1. Zak Kemble

      What sketch are you running on the Arduino?

      1. Jasmin

        http://pastebin.com/NXamBDG6 here is for the TX
        http://pastebin.com/5hzu6YM1 here is for the RX

        1. Zak Kemble

          You’ve got a lot going on there, I don’t really have time to go though it all. Though, I’d try to avoid using strings as they tend to eat up a lot of RAM, which the Arduino doesn’t have much of. Instead of strings use byte arrays or char arrays and use numeric values or characters to indicate what type of packet it is. [0] could be the packet type (1 = ENQ, 2 = ACK, 3 = EOT …), [1] could be the message length and the rest are the bytes is the message data. You don’t really need CRC as the radio already does all that stuff, and if the received packet is corrupted then it is automatically discarded.

          1. Jasmin

            I’ve tried using bytes but i can’t put it in an if else condition even if i tried to convert the received bytes into string. What can be the solution to this?

          2. Zak Kemble

            You can do conditionals on individual bytes like this:

            if(myArray[0] == 1)
  8. Jasmin

    hey i tried it but it lags what should i do 🙁

    1. Zak Kemble

      I’m not sure what you mean by it lags?

      1. Jasmin

        the serial monitor freezes.

        1. Zak Kemble

          The Arduino is probably crashing or getting stuck in a loop, what’s your latest code like?

          1. Jasmin

            http://pastebin.com/bBXWEaXx – for the rx
            http://pastebin.com/Mmx8PmpM – for the tx

          2. Zak Kemble

            Looks ok to me, although the transmitter will be spamming out packets since it doesn’t have any delays between transmissions. Put more Serial.print debugging messages around the code, so you can see exactly where it gets to.

  9. Jasmin

    ohhh okay i’ll try. hey, i have another question. can i put pins 2 3 7 and 51 52 53 into another input? im also using an lcd tft and the pins collided.

    1. Zak Kemble

      2 and 7 can be moved to any pin.
      3 must be connected to an interrupt pin, unless you’ve disabled interrupts with NRF905_INTERRUPTS 0 then it can be any pin.
      Make sure you update the nRF905_config.h file.
      50, 51 and 52 can’t change as they connect to the SPI bus, unless you modify the library to use software SPI then you can move to any pin.
      53 can be moved to any pin.

      SPI pins (50, 51 and 52) can be shared with multiple SPI devices.

  10. Michael

    Hi Zak,

    Thanks for the blog, it’s been a great help to get communication between two Arduino Unos. I don’t have enough pins on the receiver for other sensors, so am trying to set this up with an Arduino Mega 2560. Like a few other respondents to the blog am having difficulty with the Mega, but I think I am very close. I have follow your instructions and set INTERRUPT_NUM to 5 in nRF905_config.h and changed the pins:
    11 -> 51
    12 -> 50
    13 -> 52

    With the INTERRUPT_NUM set to 1 the debug sketch seemed to work OK – see below.

    Raw: 108 12 68 32 32 229 166 76 254 2 Channel: 108
    Freq: 433200KHz
    Auto retransmit: 0 Low power
    RX: 0
    TX Power: 10dBm
    Band: 433MHz
    TX Address width: 4
    RX Address width: 4
    RX Payload size: 32
    TX Payload size: 32
    RX Address [0]: 229
    RX Address [1]: 166
    RX Address [2]: 76
    RX Address [3]: 254
    RX Address: 4266436325
    CRC Mode: 16bit
    Xtal freq: 16MHz
    Clock out freq: Disabled

    But when I set it to 5 it runs with errors – see below.

    All registers read as 0xFF or 0x00! Is the nRF905 connected correctly?
    Raw: 0 0 0 0 0 0 0 0 0 0

    With INTERRUPT_NUM set to 5 and the Mega set up as the ping server I get communication, but the data appear to sometimes scramble – see below.

    On the server ……..
    Data: £+›¡‰�
    Waiting for ping… Got ping
    Sending reply… Reply sent
    On the client ……..
    Ping time 122ms
    Data from the server: £+›¡‰�

    No communication when I set the Mega up as the client

    I have the wirelessSerialLink and my own sketch working with the two Unos, but neither work with the Mega.

    Any suggestions would be much appreciated?


    1. Zak Kemble

      Hey Michael, odd that the debug sketch doesn’t work with INTERRUPT_NUM 5, since it doesn’t use any interrupt stuff to read the config registers. Everything else seems fine. Since the nRF905 is a 3.3V device and the Arduino uses 5V signalling, how are you doing the level conversion? Is the nRF905 the only thing connected to the Mega?

  11. ksshin

    Thank you, this saved me a lot of trouble.
    I had to rename *.c files into *.cpp to get this working (Xubuntu 16.04 + default Arduino package), but maybe it does not happen on other Arduino IDE installations?

    1. Zak Kemble

      Hey, for Arduino you should use the files from the Arduino folder, which are already .cpp and include example code written for Arduino.

  12. stevestrong

    Hi Zak,

    thank you for this great work.
    I am using your software, actually I rewrote it a bit for my needs, but still works fine.
    I am currently using my module only in receive mode, in 868 MHz range.
    So far so good.

    The only problem I have is the limited Rx range: if the transmitter is closer than 1 meter, all data is received OK.
    But I cannot receive anymore data if i place the transmitter more than 1 m away form the module.

    Could you maybe recommend what can I do in order to improve the Rx performance?

    Thank you in advance.

    1. Zak Kemble

      Hey Steve, nRF905 modules are usually only tuned for 433MHz operation. Using a different frequency band will result in very short range as you’ve found out. I don’t think I’ve came across any modules for 868MHz so you’ll probably have to design the module yourself, the nRF905 datasheet shows what components are needed for each frequency band.

  13. Jean

    Hi there !
    First of all thanks for your work !
    I was able to make this working the client and server examples using an arduino UNO.
    I didn’t use power level conversion and it was still working, is it normal ?

    Then I tried with an arduino mega, changing SO SI and SCK pins as expected.
    I also updated the config.h changing the INTERRUPT_NUM to 5 as requested.
    Everything is compiling great.
    But this time when debugging I have “ing timeout” for the client and “Waiting for ping…” for the server

    Did I miss something ? 🙁

    Jean (France)

    1. Jean

      Hi zak,

      I finally achieved make it working.
      Indeed after having read every comments from the beginning, I found one saying that he solved the same problem as me by uncommenting and modifying these lines :
      #define BIT_EXTERNAL_INT INT5
      #define INT_VECTOR INT5_vect
      #define BIT_EXTERNAL_INT_CTL (_BV(ISC51)|_BV(ISC50))
      Now it’s working even if it’s surprising that I need that knowing that I’ve already changed the INT_NUM to 5.

      Anyway, I would like to ask you a new question :
      I have a TX which send a string every 100ms.
      I have a RX which receive this string and analyse it : I added a TIMEOUT if the RX doesn’t receive anything during 1 second (in order to stop motors running in my specific case).
      To test that I disconnect the TX and it’s working fine (the RX stop).
      But when I connect the TX again, this takes around 5 seconds for the RX to receive again (in the meantime I display “timeout”).
      Does this time to reconnect is normal ? Do you have some advices to imporove that ?

      Thanks for you help

      1. Zak Kemble

        Hey Jean, I’ve just put a fix up on Github for the INTERRUPT_NUM issue, shouldn’t have to use the REG_EXTERNAL_INT stuff anymore. About the slow reconnect, add some Serial.println()s in your code to see where it’s taking its time. It should work straight away since there aren’t any connections being made with the radio modules, they just transmit to everything as fast as they can.

        Without any level conversion you are applying 5V to the IO pins, which are only meant to have 3.3V. This is slowly damaging the chip, and it’ll probably start going weird after a while.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Are you human? *