Exasperation: W5100 locking up nRf24L01 (solved)

Is there any reason I could not simply copy the SPI.cpp/.h to SPI2.cpp/.h, change the SPI pin assignments and talk with the nrf24L01 via 'SPI2' without sharing the pins the W5100 uses? Does SPI HAVE to be done over pins 10-13 of the Uno? (Yes, I did change the csn for the nRFL2401 to a free pin -- not 10).

Since the SPI code is so small that wouldn't be a big burden I suppose. Worth it if it eliminates the problem.

Hate to do that but I've had no luck making the two share the bus. The nRF24L01 randomly stops talking (returns FFFF for every register) after the webserver handles some number of requests. I actually have to power off the whole UNO to get everything running again.

I built a sketch with the webduino and RF24 pingpair code co-resident, then after having difficulties again with the standard arduino webserver example sketch+pingpair. Both sketches work for anywhere from 5 to 120 requests made from a web browser, then the nRF24L01 locks up. This happens after the browser receives a dozen or so copies of the short HTML block all in one single transmission from the W5100.

I seem to have W5100 shields with the 'inverter fix' that's supposed to correct the so-called SPI bug that first plagued the W5100 implementations. I also have a couple of the ENC28J60 boards to try, hoping they could do better, if it's an actual SPI problem with the W5100. I expect more headaches getting those to function however as they are not so mainstream as the W5100.

SPI is done in hardware so you can't simply use other pins. There are some software SPI implementations that can be used on any digital pins, but they don't use the same API as the standard hardware SPI library which means you can't simply substitute one for the other. I spent several days trying to persuade the RF24 library and nRF24L01+ to work with one of these software implementations, without success.

Hate to do that but I've had no luck making the two share the bus. The nRF24L01 randomly stops talking (returns FFFF for every register) after the webserver handles some number of requests. I actually have to power off the whole UNO to get everything running again.

Have you considered the possibility it may be that server code failing? You could compare that code to this sketch. It works well for me.
http://playground.arduino.cc/Code/WebServerST
And zoomkat has some server code that handles images stored on the SDcard. The SD is also a SPI device, and those work well together. So does my FTP code. It uses the w5100 and SD simultaneously.

I figured that was going to be the case, Peter. Never really knew if the admonitions elsewhere to use the standard pins were because the software was 'wired' up to those or the internals demanded it.

Tim, I'lll give the WebserverST a test run, too. I had assumed the webserver piece was to blame but I already incoporated 2 different variants of webservers with same results. Next I guess I'll switch the hardware around just in case I have a bad board somewhere. I fiddled with the SD briefly already and had no issues with that so the W5100 seemed the culprit.

Days like this make me I wish I had a logic analyzer again. :stuck_out_tongue_closed_eyes:

If you want to do a simple arduino server stress test, load the below web server test code then open the arduino supplied web page with a browser. Click the fast-data on the page and let the repeated uploading run (you can minimize the browser to the tool bar). I got over 500k+ uploads per the counter and the arduino never froze.

// zoomkat's meta refresh data iframe test page 12/24/12
// use http://192.168.1.102:84 in your brouser for main page
// http://192.168.1.102:84/data static data page
// http://192.168.1.102:84/datastart meta refresh data page
// for use with W5100 based ethernet shields
// set the refresh rate to 0 for fastest update
// use STOP for single data updates

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // arduino ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port
unsigned long int x=0; //set refresh counter to 0
String readString; 

//////////////////////

void setup(){
  Serial.begin(9600);
    // disable SD SPI if memory card in the uSD slot
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  server.begin();
  Serial.println("meta refresh data frame test"); // so I can keep track of what is loaded
}

void loop(){
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
         if (readString.length() < 100) {
          readString += c; 
         } 
        //check if HTTP request has ended
        if (c == '\n') {

          //check get atring received
          Serial.println(readString);

          //output HTML data header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();

          //generate data page
          if(readString.indexOf("data") >0) {  //checks for "data" page
            x=x+1; //page upload counter
            client.print("<HTML><HEAD>");
            //meta-refresh page every 1 seconds if "datastart" page
            if(readString.indexOf("datastart") >0) client.print("<meta http-equiv='refresh' content='1'>"); 
            if(readString.indexOf("datafast") >0) client.print("<meta http-equiv='refresh' content='0'>"); 
            client.print("<title>Zoomkat's meta-refresh test</title></head><BODY>
");
            client.print("page refresh number ");
            client.print(x); //current refresh count
            client.print("

");
              //output the value of each analog input pin
             for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
             client.print("analog input ");
             client.print(analogChannel);
             client.print(" is ");
             client.print(analogRead(analogChannel));
             client.print("
");
             }
            client.print("</BODY></HTML>");
           }
          //generate main page with iframe
          else
          {
            client.print("<HTML><HEAD><TITLE>Zoomkat's frame refresh test</TITLE></HEAD>");
            client.print("Zoomkat's Arduino frame meta refresh test 2/20/13");
            client.print("

Arduino analog input data frame:
");
            client.print("&nbsp;&nbsp;<a href='http://192.168.1.102:84/datastart' target='DataBox' title=''yy''>META-REFRESH</a>");
            client.print("&nbsp;&nbsp;&nbsp;&nbsp;<a href='http://192.168.1.102:84/data' target='DataBox' title=''xx''>SINGLE-STOP</a>");
            client.print("&nbsp;&nbsp;&nbsp;&nbsp;<a href='http://192.168.1.102:84/datafast' target='DataBox' title=''zz''>FAST-DATA</a>
");
            client.print("<iframe src='http://192.168.1.102:84/data' width='350' height='250' name='DataBox'>");
            client.print("</iframe>
</HTML>");
          }
          delay(1);
          //stopping client
          client.stop();
          //clearing string for next read
          readString="";
        }
      }
    }
  }
}

I plugged the WebserverST example into a sketch with the pingpair code and it seems rock-solid. Not a single misfire/lockup of the SPI bus after several hours of banging on it. As they say, 3rd times a charm, it seems. Over the weekend I will sit down with the code and see if I can figure out why the other two don't play well.

This appears to have gotten me past a significant roadblock in my project. Thanks to all for the guidance!

I think I have found the source of my problem.

The RF24 library has quite a few 'print' statements in it for debugging, etc. It defines its own PSTR to accomplish those printouts. There is some difficulty with using them when other SPI devices are in use. On the surface, it sounds absurd to make such a claim, but by using just the data acquisition methods of the RF24 class, all seems well.

Based on my limited c++ expertise, it seems the RF24 library defines PSTR and some other statements that ought to be the equivalent of the F() function from the Wire library which SurferTim's code example -- however, it directly conflicts with what RF24 does. I was not able to comprehend these mechanisms for using ProgMem well enough to 'fix' RF24 so it also used F().

Regardless, my test sketch hums along nicely without calling the RF24 printDetails() (which I had been using as a way to tell when it 'locks up'). Persumably as long as I steer clear of using any of the RF24 'print' statements, my code will work fine.

For future reference, this is the code I have been running for hours now without any (apparent) problems:

/*
   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;

bool tx_ok;
bool tx_fail;
bool rx_ready;

// 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");
		
		radio.begin();
		
		// optionally, increase the delay between retries & # of retries
		radio.setRetries(15,15);
		
		// optionally, reduce the payload size.  seems to
		// improve reliability

		radio.setPayloadSize(32);
		
		//
		// Open pipe to other node for communication
		//
		
		radio.openReadingPipe(1,pipe);
		
		//
		// Start listening
		//
		
		radio.startListening();
                
                radio.printDetails();
                Serial.println("Radio ready");}

void loop()
{
  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("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("setInterval(function(){document.forms[0].submit()},1000);");
          client.print("function show_alert() {alert(\"This is an alert\");}");
          client.print("</script></head");


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

          client.print("<form method=GET onSubmit=\"show_alert()\">T: <input type=text name=t value=\""); client.print(data_rate); 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");
  }
  
  if (millis() % 5000 == 0) {
//    radio.printDetails();

    radio.whatHappened(tx_ok, tx_fail, rx_ready);
    Serial.print("Data Rate ============================== ");
    Serial.println( data_rate = radio.getPALevel());
    Serial.print(tx_ok);
    Serial.print(", ");
    Serial.print(tx_fail);
    Serial.print(", ");
    Serial.println(rx_ready);
    
    Serial.println(++i);
  }}

(Whoops, initially didn't paste my test sketch, just the WebserverST code I started from. Fixed. It's all there now.)

I had problems with the client.write function (actually any write function call) and the F() macro working together. It will generate a IDE compiler error something like "can't convert char* to __FlashStringHelper*". I don't know how the compiler might handle that if the call is in a library.

I do not get the same error with client.print() tho.

Drat! Not solved. I should probably not keep dredging this up on the Guidance thread as I have transitioned into a 'networking' issue. So I started a discussion over there to pick where I left off here.

http://arduino.cc/forum/index.php/topic,159084.0.html