How to use an nrf24l01 (rf24) with an Arduino Ethernet Shield

rf24Ethernet
I have been working on a project that requires the use of both a wiznet-type w5100 Ethernet shield like this and an nrf24l01 radio at the same time.  The problem I ran into was that both of these peripherals use the SPI protocol, and I could not get them both working simultaneously (the Ethernet shield has it’s pins hardwired to the hardware SPI, of course).  After doing some reading on the SPI protocol, I found out that there seems to be some kind of issue that, according to the freetronics website, causes the w5100 chip to maintain control of the SPI bus even when another device has been selected.

After much searching, and much experimenting, I finally found a workaround that seems to be working reliably for me.  The solution was to use ‘software’ or ‘bit-banged’ SPI.  This allows the Ethernet shield to happily commandeer the hardware SPI pins, while the nrf24l01 (or any other peripheral, I suppose) to operate on a separate, emulated SPI bus.

The credit for this goes to a user on the Arduino forums, nicoverduin, who suggested using some software SPI libraries already available and modifying maniacbug’s nrf24 library to use the software spi interface.

Here is the step by step:

1.)  Download the modified maniacbug library and softSPI libraries here.
2.) Copy the libraries to your Arduino libraries folder.
3.) Configure your Arduino/Ethernet-shield/nrf24l01 like this (you can also modify the pin configuration if needed.  Instructions are in the readme file on the linked github repository):

 

Connect to the soft-spi designated pins
Connect to the soft-spi designated pins

 

If you would like to download the fritzing file, here you go:
rf24-softSPI_plusEthernetShield

4.) Add the library references to your code or use example code provided below.

This sketch is a companion sketch to the nrf24l01_send_string sketch I posted previously.

Once you have completed the above steps, you can upload your sketch to the Arduino and you should be able to browse to the IP of your Arduino with Ethernet shield and you will see a web page that tells you the last message received over the nrf24l01.

There is one major caveat to all of this, however.  I have found that sometimes when I am working with the softSPI version of the nrf24 library and then I switch back to the regular/hardware version (e.g. when I work on the sending device, which in this case has no ethernet shield, after I upload a sketch to the one with the ethernet shield), the hardware-based SPI nrf24l01 breaks.  This seems to be happening because the Arduino IDE is holding on to the softSPI version of the rf24 library.  I am just speculating on that, but it kind of makes sense since the internal naming is identical between the libraries.

The fix for this problem is simple, if a bit inconvenient.  I have been removing my modified version of the rf24 library from the Arduino libraries folder before working with the hardware-SPI version.  I am sure there is a smarter way of fixing this, and if someone could point it out to me, I would be glad to post the solution here.

16 thoughts on “How to use an nrf24l01 (rf24) with an Arduino Ethernet Shield”

  1. Quick question: maniacbug has a “sensor-network” on his blog. I am struggling with compiling it on the latest beta version running on Mac OS.
    Have you ever tried to use the network-library to implement more than 5 senders?

  2. Hi Shane,
    really appreciated this guide. I got my two nrf’s working together with your previous guide on making them communicate, but I can not seem to get them working when I add an ethernet shield (W1500) to the sender. Here is my code http://paste.ubuntu.com/7811292/ can you see anything wrong?

  3. Hi. I am trying to control my house lights in three different ways same time. One by building diy remotecontrol with nrf24l01 sendind different chars to the receiving end ( master arduino) to control light state .

    Second way is control lights via internet browser writing very easy html lines in master arduino code. And using get_ function to turn lights on and off and also writing the light state on those hmtl sites.

    Third way is just simple lightswitch on the wall like normally. This uses basic digitalRead function.

    I am still building remotecontol circuit. First I tried rf433 mhz transmitter but range trough wall was really poor so I have to select this nrf24l01 chip.

    Thanks for sharing solution to this problem! Founding this page saves lots of time and head ake. Thanks! I really preciate!

  4. hi
    I’ve made the following installation:
    Arduino MEGA , Ethernet shield (W5100) with SDcard , NRF24L01 and some sensors.
    int SDchipSelect = 4; // CS : 4
    int SDCardSelect = 53; // SS : 10 on other; 53 on the Mega !! conflict with radio !!
    // nRF24L01(+) radio attached for MEGA SPI: MOSI 51 (6), MISO 50 (7), SCK 52 (5), CSN 49 (4)
    RF24 radio(48,49); // CE = 48 (3), CSN = 49 (4)
    on the MEGA I’ve soldered a 47micro to the 3.3V pins and on the NRF I’ve put a 6.3micro tantal directly on the upper side at pin1,2

  5. hello guys .

    actually i have a problem and i hope that you could help me
    i want send a char from labview to arduino ethernet shield then to send it through the nrf24l01 to the other arduino uno to turn led on , i do every thing as u say ,i change the library and i connect in the same way as mention .
    it dos not take the two order :S
    take the first and stay in .

    that’s my transmit code :

    #include

    #include
    #include
    #include
    #include
    #include
    #include

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    int msg[1];

    RF24 radio(6,7);
    const uint64_t pipe = 0xE8E8F0F0E1LL;

    // Adresses MAC et IP à changer suivant vos besoins
    byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0xF6, 0x27 };
    IPAddress ip(192,168,0, 101);

    // Initialisation de la librairie ethernet
    // et création d’un objet “Server” qui va accepter
    // les connexions extérieures à l’adresse IP defini plus
    // haut et sur le port indiqué (ici 8000)
    EthernetServer server(8000);

    void setup()
    {Serial.begin(9600);
    radio.begin();
    radio.openWritingPipe(pipe);
    Ethernet.begin(mac, ip);
    pinMode(4,OUTPUT);
    }

    void loop()
    {
    // Attente des connexions et création d’un objet client s’il y a lieu
    EthernetClient client = server.available();
    if (client) { // Un client existe
    while (client.connected()) { // il est connecté
    if (client.available()) { // et il a envoyé des caractères
    char c = client.read();

    if (c== ‘1’)
    {
    digitalWrite(4, LOW);
    msg[0] = 1;
    radio.write(msg,1);}

    if (c== ‘2’)
    {
    digitalWrite(4, HIGH);
    msg[0] = 2;
    radio.write(msg,1);}

    else{ radio.write(msg,1);}

    }}}}
    ————————————————————————-
    end here the receive code :

    #include

    #include
    #include
    #include
    #include
    #include
    #include

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    int msg[1];
    RF24 radio(6,7);
    const uint64_t pipe = 0xE8E8F0F0E1LL;

    void setup(void)
    {
    Serial.begin(9600);
    radio.begin();
    radio.openReadingPipe(1,pipe);
    radio.startListening();

    pinMode(3,OUTPUT);
    pinMode(4,OUTPUT);
    }

    void loop(void)
    {
    if (radio.available())
    {
    bool done = false;
    while (!done)
    {
    done = radio.read(msg,1);
    if (msg[0] == 1)
    {
    delay(100);
    digitalWrite(3, HIGH);

    }
    if (msg[0] == 2)
    {
    delay(100);
    digitalWrite(3, LOW);
    digitalWrite(4, HIGH);

    }
    else{
    Serial.println(“No radio available”);
    }
    }
    }
    }
    ——————————————————-
    the labview work fine , the problem in my code :(

    please i need your help

  6. excuse me, but i dont know why the library do not appear in my post :S
    anyway its the same of the example code above ..

  7. Hi, i tried your codes for ethernet shield for a long time. But its not work, on the net page just appear “The last message we got was:” . there is no “hello there”. what am i missing?

    —transmitter code—-
    #include
    #include
    #include
    #include

    /*
    This sketch sends a string to a corresponding Arduino
    with nrf24 attached. It appends a specific value
    (2 in this case) to the end to signify the end of the
    message.
    */

    int msg[1];
    RF24 radio(8,9);
    const uint64_t pipe = 0xE8E8F0F0E1LL;
    void setup(void){
    Serial.begin(9600);
    radio.begin();
    radio.openWritingPipe(pipe);}
    void loop(void){
    String theMessage = “Hello there!”;
    int messageSize = theMessage.length();
    for (int i = 0; i < messageSize; i++) {
    int charToSend[1];
    charToSend[0] = theMessage.charAt(i);
    radio.write(charToSend,1);
    }
    //send the 'terminate string' value…
    msg[0] = 2;
    radio.write(msg,sizeof(msg));
    /*delay sending for a short period of time. radio.powerDown()/radio.powerupp
    //with a delay in between have worked well for this purpose(just using delay seems to
    //interrupt the transmission start). However, this method could still be improved
    as I still get the first character 'cut-off' sometimes. I have a 'checksum' function
    on the receiver to verify the message was successfully sent.
    */
    radio.powerDown();
    delay(1000);
    radio.powerUp();
    }

    ——receiver and ethernet code—–

    #include

    #include
    #include
    #include
    #include
    #include
    #include

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    /*
    This sketch receives strings from sending unit via nrf24
    and prints them out via serial. The sketch waits until
    it receives a specific value (2 in this case), then it
    prints the complete message and clears the message buffer.

    The sketch serves the result to a webpage.
    */
    int messageLength = 12; //message checksum, Make sure to
    // change it if your string is a different length

    int msg[1];
    RF24 radio(6,7);
    const uint64_t pipe = 0xE8E8F0F0E1LL;
    String theMessage = “”;
    String latestMessage = “”; //this is used in the html output

    //Ethernet setup…
    byte mac[] = {
    0xDE, 0xAD, 0x00, 0xCC, 0xFE, 0xAA };
    IPAddress ip(–,–,–,230);
    EthernetServer server(80);

    void setup(void){
    Serial.begin(9600);
    radio.begin();
    radio.openReadingPipe(1,pipe);
    radio.startListening();
    Ethernet.begin(mac,ip);
    server.begin();
    Serial.print(“server is at “);
    Serial.println(Ethernet.localIP());
    }
    void loop(void){
    if (radio.available()){
    bool done = false;
    done = radio.read(msg, 1);
    char theChar = msg[0];
    if (msg[0] != 2){
    theMessage.concat(theChar);
    }
    else {

    if (theMessage.length() == messageLength) {
    Serial.println(theMessage);
    latestMessage = theMessage;
    }
    theMessage= “”;
    }
    }
    //BEGINNING OF SERVER CODE
    // listen for incoming clients
    EthernetClient client = server.available();
    if (client) {
    Serial.println(“new client”);
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
    if (client.available()) {
    char c = client.read();
    Serial.write(c);
    // if you’ve gotten to the end of the line (received a newline
    // character) and the line is blank, the http request has ended,
    // so you can send a reply
    if (c == ‘\n’ && currentLineIsBlank) {
    // send a standard http response header
    client.println(“HTTP/1.1 200 OK”);
    client.println(“Content-Type: text/html”);
    client.println(“Connnection: close”);
    client.println();
    client.println(“”);
    client.println(“”);
    client.println(“”);
    client.println(“Arduino Web Page”);
    client.println(“”);
    client.println(“”);
    client.print(“The last message we got was: “);
    client.print(latestMessage);
    client.println(“”);
    client.println(“”);
    client.println(“”);
    break;
    }
    if (c == ‘\n’) {
    // you’re starting a new line
    currentLineIsBlank = true;
    }
    else if (c != ‘\r’) {
    // you’ve gotten a character on the current line
    currentLineIsBlank = false;
    }
    }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println(“client disonnected”);
    }
    //END OF SERVER CODE

    }

  8. Thanks for sharing this code was crucial to run a HTTP server that receives requests through my network and transmits them to a receiver robot, so I can manage my robot over the Internet! Thank you, thank you, thank you!!!

  9. hello shane, many thanks for your sharing!

    Im working on a project on these 2 modules too. And getting into dead end. So pls i need some explanation. Why did you connect those 3 pin 5, 6, 7 of nrf24l01 to analog pin A0, A1, A2? I know that since the ethernet shield use ISCP connection, so we have to move those 3 pins to another place, but which part of the code tell A0, A1, A2?

Leave a Reply to Pedro Cancel 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>