NRF24L01 + W5100 = Fail

OK, I figured I sould get off the 'project guidance' thread since my problem seems more of a programming/interface issue...

I have been trying to make a simple sketch that reads data over the NRF24L01 and then display it in a web browser. For the purposes of sorting out how to do this, I created the sketch below, starting with SurferTim's WebServerST and adding the RF24 library to it.

Both seem to work perfect by themselves, but when run together it's not stable at all. The code runs for a while, for some random number of cycles, and then it quits.

By 'quits' I mean that the NRF24L01 quits returning data -- I get FFFF for everything I try to read from it. At leas 3 times I thought I had it licked and got it to work, but I kept finding it would not provided data from the remote NRF24L01 (which is just sitting there sending 32 bytes of data every 10-20 seconds or so. It's actually hooked up to a PIR sensor so I can wave my hand at it to get something sent to me. That code is essentially the RF24 library's 'ping pair' example with the PIR initiating the pings so I could fire them off on demand. (Pushbuttons are so 20th century, you know)

I've tried switching the NRF24L01 modules, changing the pins it uses for ce/cs, and a different UNO board. Still the problem persists.

So I'm hoping someone might have some recommendations on coding or configuration to truly resolve this. By all reckoning, this should 'just work'. My W5100 boards are of recent vintage and seem to have the inverter-fix incorporated for SS that handles the longstanding 'SPI bug'.

/*
   Web server sketch for IDE v1.0.1 and w5100/w5200
   Posted October 2012 by SurferTim
*/

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

#include <nRF24L01.h>
#include <RF24.h>

RF24     radio(8, 7);
uint64_t pipe = 0xF0F0F0F0E1LL;
uint16_t i = 0;

int data_rate = 0;
int payload_size;

bool tx_ok;
bool tx_fail;
bool rx_ready;
bool good = true;

// this must be unique
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEC };
char payload[32];
// change to your network settings
IPAddress ip( 192,168,0,11 );
IPAddress gateway( 192,168,0,1 );
IPAddress subnet( 255,255,255,0 );

EthernetServer server(80);

void setup()
{
  Serial.begin(9600);
	
  // disable w5100 while setting up SD
  // uncomment next 5 lines if using a microSD card

  //  pinMode(10,OUTPUT);
  //  digitalWrite(10,HIGH);
  // Serial.print("Starting SD..");
  // if(!SD.begin(4)) Serial.println("failed");
  // else Serial.println("ok");

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  digitalWrite(10,HIGH);

  delay(2000);
  server.begin();
  Serial.println("Ready");
		
    radioOn();                
//    radio.printDetails();
}

void loop()
{
    radio.whatHappened(tx_ok, tx_fail, rx_ready);
    payload_size = radio.getDynamicPayloadSize();
    
    EthernetClient client = server.available();
  if(client && good) {
    
//    radioOff();
    
    boolean currentLineIsBlank = true;
    boolean currentLineIsGet = true;
    int tCount = 0;
    char tBuf[64];
    int r,t;
    char *pch;

    Serial.print("Client request: ");

    while (client.connected()) {
      while(client.available()) {
        char c = client.read();

        if(currentLineIsGet && tCount < 63)
        {
          tBuf[tCount] = c;
          tCount++;
          tBuf[tCount] = 0;          
        }

        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response
          Serial.println(tBuf);
          Serial.print("POST data: ");
          while(client.available()) Serial.write(client.read());
          Serial.println();

          pch = strtok(tBuf,"?");

          while(pch != NULL)
          {
            if(strncmp(pch,"t=",2) == 0)
            {
              t = atoi(pch+2);
              Serial.print("t=");
              Serial.println(t,DEC);            
            }

            if(strncmp(pch,"r=",2) == 0)
            {
              r = atoi(pch+2);
              Serial.print("r=");              
              Serial.println(r,DEC);
            }


            pch = strtok(NULL,"& ");
          }
          Serial.println("Sending response");
          client.print("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<html>");

          client.print("<head><script type=\"text/javascript\">");
          client.print("var timer = setInterval(function(){if (document.forms[0].t.value != '32') clearInterval(timer); else document.forms[0].submit()},3000);");
          client.print("function show_alert() {return;alert(\"This is an alert\");}");
          client.print("</script></head");


          client.print("<body><H1>TEST</H1>");
// Send back the payload_size and millis(), just so we can see that the page has reloaded.
          client.print("<form method=GET onSubmit=\"show_alert()\">T: <input type=text name=t value=\""); client.print(payload_size); client.print("\">
");
          client.print("R: <input type=text name=r value=\""); client.print(millis()); client.print("\">
<input type=submit></form>");

          data_rate = 0;  // Clear it so we know if radio contines to set it
          
          client.print("</body></html>\r\n\r\n");
          client.stop();
        }
        else if (c == '\n') {
          currentLineIsBlank = true;
          currentLineIsGet = false;
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    Serial.println("done");
//    radioOn();
    if (payload_size > 32) good = false;
  }
  
  if (good && millis() % 5000 == 0) {
//    radio.printDetails();

    radio.whatHappened(tx_ok, tx_fail, rx_ready);
    payload_size = 0;
    payload_size = radio.getDynamicPayloadSize();
    Serial.println("Data Values Read ============================== ");  // Try to read something to see if we get it or the radio has stopped talking

    Serial.print(tx_ok);
    Serial.print(", ");
    Serial.print(tx_fail);
    Serial.print(", ");
    Serial.println(rx_ready);
    Serial.print("Payload Size: ");
    Serial.println(payload_size);
    
    Serial.println(++i);
  }
}
void radioOff() {
  radio.stopListening();
//  radio.powerDown();
  Serial.println("Radio is off");
}

void radioOn() {
  
  radio.begin();
  radio.setRetries(1,1);
  radio.setPayloadSize(32);
  radio.openReadingPipe(1,pipe);
  radio.startListening();
  Serial.println("Radio ready");
}

Which Arduino are you running the code on?

Why are you including SD.h, when you never actually open a file? You are wasting precious memory doing that.

I'd guess that if you researched FreeMemory, you'd find that you have very little (possibly even a negative amount).

JohnHoward:
I've tried switching the NRF24L01 modules, changing the pins it uses for ce/cs, and a different UNO board. Still the problem persists.

#include <SPI.h>

#include <Ethernet.h>
#include <SD.h>

#include <nRF24L01.h>
#include <RF24.h>

While I am looking at much the same thing, you are a few steps ahead of me so I can't offer any real help but the above includes surprise me. I wouldn't have thought a Uno was up to the job and, as I understand it works and then fails, it may simply be that you are running short of memory. I am looking at a Uno for the transmitter but all the real work is at the receiver, with a Mega.

That code above is not the latest modification to my web server code. The F() macro is missing in your code. That will cost you a bunch of SRAM, and possibly crash your code. Take a look at the server code now.
http://playground.arduino.cc/Code/WebServerST

As I indicated, it's an UNO (real article, not a Chinese clone)

I included the SD to see if having a different SPI device sharing the bus would have the same issue. The problem predates including SD library.

I had to remove the F(), knowing full well the implication, but for some reason the RF24 library's PSTR() causes compile errors with respect to F() and complains the 'constness' of the strings.

I think it has to be a deficiency with the NRF24L01, as running the SD seems fine for serving up a simple file from it over the webserver.

I just bought one of those cheap USBee logic analyzers and when it arrives I hope to actually see what's happening with the radio

I included the SD to see if having a different SPI device sharing the bus would have the same issue. The problem predates including SD library.

Do you have a SD card in the ethernet shield slot? If so, remove it to test the other devices first.

I had to remove the F(), knowing full well the implication, but for some reason the RF24 library's PSTR() causes compile errors with respect to F() and complains the 'constness' of the strings.

I found the same problem with the ethernet shield and client.write(). It would not take a string with the F() macro. I changed the client.write() to client.print() and the compiler problem disappeared. I don't know if that will apply to the RF24.

I reconstructed my test sketch, using the WebServerST code from your link, Tim (says it's for arduino 1.0.1 and is dated Oct 2012). Still unable to compile. On a whim, I downloaded 1.5.2 of the GUI and found that it does compile. The culprit seems to have been @ line 38 of WString.h:

It changed from

#define F(string_literal) (reinterpret_cast< __FlashStringHelper *>(PSTR(string_literal)))

to

#define F(string_literal) (reinterpret_cast<[color=red]const[/color] __FlashStringHelper *>(PSTR(string_literal)))

I had been using 1.0.1 of the GUI.

FreeMemory reports 855 bytes available when I run my test code (I get 755 in my 'real' code which is more complex than this). Still the NRF24L01 still quits talking. Sample output suddenly started to return 'all ones' (notice how the RF24 functions whatHappened() and getDynamicPayloadSize():

Client request: GET /?t=&r= HTTP/1.1

POST data: 
t=0
r=0
Sending response
freeMemory()=877
done
Data Values Read ============================== 
0, 0, 0
Payload Size: 32
220
Client request: GET /?t=&r= HTTP/1.1

POST data: 
t=0
r=0
Sending response
freeMemory()=877
done
Data Values Read ============================== 
0, 0, 0
Payload Size: 32
221
Client request: GET /?t=&r= HTTP/1.1

POST data: 
t=0
r=0
Sending response
freeMemory()=877
done
Data Values Read ============================== 
0, 0, 0
Payload Size: 32
222
Client request: GET /?t=&r= HTTP/1.1

POST data: 
t=0
r=0
Sending response
freeMemory()=877
done
Data Values Read ============================== 
1, 1, 1
Payload Size: 255
223

Updated test sketch:

/*
   Web server sketch for IDE v1.0.1 and w5100/w5200
   Posted October 2012 by SurferTim
*/

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

#include <nRF24L01.h>
#include <RF24.h>

#include "MemoryFree.h"

RF24     radio(7,6);  // ce, csn
uint64_t pipe = 0xF0F0F0F0E1LL;
uint16_t i = 0;

int data_rate = 0;
int payload_size;

bool tx_ok;
bool tx_fail;
bool rx_ready;
bool good = true;

// this must be unique
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEC };

// change to your network settings
IPAddress ip( 192,168,0,11 );
IPAddress gateway( 192,168,2,1 );
IPAddress subnet( 255,255,255,0 );

EthernetServer server(80);

void setup()
{
  Serial.begin(9600);

  // disable w5100 while setting up SD
  // uncomment next 5 lines if using a microSD card

  //  pinMode(10,OUTPUT);
  //  digitalWrite(10,HIGH);
  // Serial.print(F("Starting SD.."));
  // if(!SD.begin(4)) Serial.println(F("failed"));
  // else Serial.println(F("ok"));

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  digitalWrite(10,HIGH);

  delay(2000);
  server.begin();
  Serial.println(F("Ready"));
  
  radioOn();                
  //    radio.printDetails();
  
}

void loop()
{
  radio.whatHappened(tx_ok, tx_fail, rx_ready);
  payload_size = radio.getDynamicPayloadSize();

  EthernetClient client = server.available();
  if(client) {
    boolean currentLineIsBlank = true;
    boolean currentLineIsGet = true;
    int tCount = 0;
    char tBuf[64];
    int r,t;
    char *pch;

    Serial.print(F("Client request: "));

    // this controls the timeout
    int loopCount = 0;

    while (client.connected()) {
      while(client.available()) {
        // if packet, reset loopCount
        loopCount = 0;
        char c = client.read();

        if(currentLineIsGet && tCount < 63)
        {
          tBuf[tCount] = c;
          tCount++;
          tBuf[tCount] = 0;          
        }

        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response
          Serial.println(tBuf);
          Serial.print(F("POST data: "));
          while(client.available()) Serial.write(client.read());
          Serial.println();

          pch = strtok(tBuf,"?");

          while(pch != NULL)
          {
            if(strncmp(pch,"t=",2) == 0)
            {
              t = atoi(pch+2);
              Serial.print("t=");
              Serial.println(t,DEC);            
            }

            if(strncmp(pch,"r=",2) == 0)
            {
              r = atoi(pch+2);
              Serial.print("r=");              
              Serial.println(r,DEC);
            }


            pch = strtok(NULL,"& ");
          }
          Serial.println(F("Sending response"));
          client.print(F("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<html>"));

          client.print(F("<head><script type=\"text/javascript\">"));
          client.print(F("function show_alert() {return;alert(\"This is an alert\");}"));
          client.print(F("</script></head"));


          client.print(F("<body><H1>TEST</H1>"));

          client.print(F("<form method=GET onSubmit=\"show_alert()\">T: <input type=text name=t>
"));
          client.print(F("R: <input type=text name=r>
<input type=submit></form>"));


          client.print(F("</body></html>\r\n\r\n"));
          client.stop();
    Serial.print(F("freeMemory()="));
    Serial.println(freeMemory());
        }
        else if (c == '\n') {
          currentLineIsBlank = true;
          currentLineIsGet = false;
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }

      loopCount++;

      // if 10000ms has passed since last packet
      if(loopCount > 10000) {
        // close connection
        client.stop();
        Serial.println("\r\nTimeout");
      }

      // delay 1ms for timeout timing
      delay(1);
    }
    Serial.println(F("done"));

    radio.whatHappened(tx_ok, tx_fail, rx_ready);
    //    payload_size = 0;
    payload_size = radio.getDynamicPayloadSize();
    Serial.println(F("Data Values Read ============================== "));  // Try to read something to see if we get it or the radio has stopped talking

    Serial.print(tx_ok);
    Serial.print(F(", "));
    Serial.print(tx_fail);
    Serial.print(F(", "));
    Serial.println(rx_ready);
    Serial.print(F("Payload Size: "));
    Serial.println(payload_size);

    Serial.println(++i);
  }
}

void radioOn() {

  radio.begin();
  radio.setRetries(15,15);
  radio.setPayloadSize(32);
  radio.openReadingPipe(1,pipe);
  radio.startListening();
  Serial.println("Radio ready");
}

That sketch was originally designed for IDE v1.0.1, but there have been several modifications since then. The most important was the F() macro, but that was not implemented until I was using v1.0.3. I am testing now with IDE v1.0.4. I download the code from the playground and compile it when I do major mods to it.

I just added a new modification and tested the posted code a couple days ago. After a bit of testing with PuTTy, I found a flaw in the section of code that reads the client request. If the connection breaks and the server does not receive a blank line, the code locks up in that while client.connected() loop. Now it has a timeout just like the client sketch.

Had to go on hiatus for a little while... I'm back.

I have an Uno working fine now (thousands of cycles over the past several days with no lock ups) with the same code/configuration as I started out with. I went to a Mega2560 base and that also worked, but I really wanted the Uno form factor. So on a lark I ordered up a couple of SainSmart's 'black' uno boards they have been offering recently on eBay and calling 'new improved'. For some reason they work fine in my application. I can not explain why. They DO use a different variant of the ATMega chip, but as far as I can tell from perusing the datasheets that's merely packaging, nothing new inside. The only 'new improved' features appear to be a switchable 3.3/5V supply and 2 more analog pins.

Odd that TWO true-blue Uno's caused me to experience the identical problem but not the SainSmart's. I assume the things are wired up the same, other than the ATMega chip difference. The 5 volt rail measures the same on both so evidently not a power supply issue.