[Request - Answered] nRF24L01+ library

I can try that, but I just loaded the RF24_Network “helloworld_tx” and “helloworld_rx” examples on the two units. Unit 1 was Tx and Unit 2 was Rx and that worked great. Then I swapped the RF modules to reverse their roles and after power cycling the arduinos, it works great as well. Unit 2 Tx’s to Unit 1 Rx’ing and messages are getting through every 2 seconds. I think I saw maybe one out of 100 of the first packets dropped, but that’s it. Think this is good enough to start porting to Spark Core now?

BDub, I really would like to get the nRF24 stuff working since the module are inexpensive and available from so many sources. I have 2 DigiX Arduino Due compatible boards from DigiStump that have the nRF24 module right next to the onboard WiFi module. So testing generic Chinese units with these boards makes sense. I have 10 brand new nRF24 modules that I individually tested that I can use. If we can agree on a good testing sketch, I could do some range and reliability testing with these. With 10 units, it creates a more credible statistic. Any thoughts?

@peekay123 Do you have a link to the specific modules that you have? Are they the same as pictured here?

I think you doing range testing on 10 units would be pretty useful to show how consistent they when it comes to range and reception reliability.

Tried this and they don't look any different than when powering up for the first time.

I tried increasing the delay between transmitting... didn't help.

I tried these two which seems to help:

radio.setRetries(15,15);
radio.setPayloadSize(8);

Just setting radio.setPayloadSize(8); by itself improves the success rate by more than double.

radio.setRetries(15,15); is already at max value for both delay and retries ... lesser values does worsen the situation.

One thing I am wondering is when either unit is in Tx mode, why does it initially say "failed" after sending? what exactly does that mean. It calls this function:
bool ok = radio.write( &time, sizeof(unsigned long) ); in the RF24 Class.

I enabled the debug statement printf("%u%u%u...%d...",tx_ok,tx_fail,ack_payload_available,millis() - sent_at); and added the time that the write took into the output. Seems like whenever things are failing, the max retry is running up against it's limit... not sure what that means.. like why does it retry?

Further reducing payload to 4 doesn't help radio.setPayloadSize(4);

RWB, I bought THESE on eBay. They are based on Nordic’s the reference design.

BDub, I have a sketch that does ping tests with variable payloads. Perhaps that is a good way to test these radios. Thoughts?

Sure, let's see it :smile:

BDub, here it is. This code is part of the RF24 library supplied by DigiStump. The filename is pingpair_dyn.pde.

/*
 Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 */

/**
 * Example using Dynamic Payloads 
 *
 * This is an example of how to use payloads of a varying (dynamic) size. 
 */

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"

//
// Hardware configuration
//

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10

RF24 radio(53,52);

// sets the role of this unit in hardware.  Connect to GND to be the 'pong' receiver
// Leave open to be the 'ping' transmitter
const int role_pin = 7;

//
// Topology
//

// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

//
// Role management
//
// Set up role.  This sketch uses the same software for all the nodes
// in this system.  Doing so greatly simplifies testing.  The hardware itself specifies
// which node it is.
//
// This is done through the role_pin
//

// The various roles supported by this sketch
typedef enum { role_ping_out = 1, role_pong_back } role_e;

// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};

// The role of the current running sketch
role_e role;

//
// Payload
//

const int min_payload_size = 4;
const int max_payload_size = 32;
const int payload_size_increments_by = 2;
int next_payload_size = min_payload_size;

char receive_payload[max_payload_size+1]; // +1 to allow room for a terminating NULL char

void setup(void)
{
  //
  // Role
  //

  // set up the role pin
  pinMode(role_pin, INPUT);
  digitalWrite(role_pin,HIGH);
  delay(20); // Just to get a solid reading on the role pin

  // read the address pin, establish our role
  if ( digitalRead(role_pin) )
    role = role_ping_out;
  else
    role = role_pong_back;

  //
  // Print preamble
  //

  Serial.begin(57600);
  
  p("\n\rRF24/examples/pingpair_dyn/\n\r");
  p("ROLE: %s\n\r",role_friendly_name[role]);

  //
  // Setup and configure rf radio
  //

  radio.begin();

  // enable dynamic payloads
  radio.enableDynamicPayloads();

  // optionally, increase the delay between retries & # of retries
  radio.setRetries(15,15);

  //
  // Open pipes to other nodes for communication
  //

  // This simple sketch opens two pipes for these two nodes to communicate
  // back and forth.
  // Open 'our' pipe for writing
  // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)

  if ( role == role_ping_out )
  {
    radio.openWritingPipe(pipes[0]);
    radio.openReadingPipe(1,pipes[1]);
  }
  else
  {
    radio.openWritingPipe(pipes[1]);
    radio.openReadingPipe(1,pipes[0]);
  }

  //
  // Start listening
  //

  radio.startListening();

  //
  // Dump the configuration of the rf unit for debugging
  //

  radio.printDetails();
}

void loop(void)
{
  //
  // Ping out role.  Repeatedly send the current time
  //

  if (role == role_ping_out)
  {
    // The payload will always be the same, what will change is how much of it we send.
    static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012";

    // First, stop listening so we can talk.
    radio.stopListening();

    // Take the time, and send it.  This will block until complete
    p("Now sending length %i...",next_payload_size);
    radio.write( send_payload, next_payload_size );

    // Now, continue listening
    radio.startListening();

    // Wait here until we get a response, or timeout
    unsigned long started_waiting_at = millis();
    bool timeout = false;
    while ( ! radio.available() && ! timeout )
      if (millis() - started_waiting_at > 500 )
        timeout = true;

    // Describe the results
    if ( timeout )
    {
      p("Failed, response timed out.\n\r");
    }
    else
    {
      // Grab the response, compare, and send to debugging spew
      uint8_t len = radio.getDynamicPayloadSize();
      radio.read( receive_payload, len );

      // Put a zero at the end for easy printing
      receive_payload[len] = 0;

      // Spew it
      p("Got response size=%i value=%s\n\r",len,receive_payload);
    }
    
    // Update size for next time.
    next_payload_size += payload_size_increments_by;
    if ( next_payload_size > max_payload_size )
      next_payload_size = min_payload_size;

    // Try again 1s later
    delay(1000);
  }

  //
  // Pong back role.  Receive each packet, dump it out, and send it back
  //

  if ( role == role_pong_back )
  {
    // if there is data ready
    if ( radio.available() )
    {
      // Dump the payloads until we've gotten everything
      uint8_t len;
      bool done = false;
      while (!done)
      {
        // Fetch the payload, and see if this was the last one.
	len = radio.getDynamicPayloadSize();
	done = radio.read( receive_payload, len );

	// Put a zero at the end for easy printing
	receive_payload[len] = 0;

	// Spew it
	p("Got payload size=%i value=%s\n\r",len,receive_payload);
      }

      // First, stop listening so we can talk
      radio.stopListening();

      // Send the final one back.
      radio.write( receive_payload, len );
      p("Sent response.\n\r");

      // Now, resume listening so we catch the next packets.
      radio.startListening();
    }
  }
}

I started with your code, and they basically changed a few things that made it a pain to get working... had to scrap it when I realized it was just the RF24/examples/pingpair_dyn/ example. I hardcoded the Tx and Rx function instead of reading the digital input. It seems to be randomly flaky... Lower payloads work better, but even those fail and sometimes long ones work.

I also tried to figure out why the Helloworld_Tx RF24_Network example works very well... and one of the only things I see different is they use Channel 90 instead of the default 76 that the pingpair examples use. Tried to set Helloworld_TX to channel 76, and it works just as good as on channel 90, so that's not it.

Will continue to look at RF24_Network stuff and see why it works better.

BDub, I will run some demos on the Digix I have and let you know what I see.

Sounds good.

FYI: I reduced the number of pipes that the RF24_Network Class opens from 6 down to 1 to keep things equal… and the RF24_Network example still works great. Still digging.

@BDub what Was the payload size when your were experiencing failures? I’m going to try with a 18bytes payload right now to check my configuration.

Really any payload with the RF24 Class makes it fail at some point… it’s pretty random. However the RF24_Network Class examples are pretty reliable.

Okydoky, I ran the nRF24 variable payload ping sketch on two Digix boards, the “receiver” connected to a PC w/putty running and the other powered by a LiPo so I could move it around easily. The receiver was in my workshop in the basement. I placed the “sender” around the basement, up to the ground and second floors until I lost packet traffic (lots of running back and forth!). Bottom line is that I had good traffic within a line-of-sight distance of 30-40 feet at best. Within those distances, the link worked well. Beyond that, it depended mostly on architectural obstructions (wall, beams, etc.). I suspect in open-air, the range would go up substantially.

Bottom line is that the eBay specials I bought (10 modules for $10) worked reliably. I did not tune the nRF24 parameters which could have extended the interior range. I would be glad to run any “tuned” test code for further testing, if someone can suggest it. :smile:

Nice to hear @peekay123. I was also doing more testing last night, and now the RF24_Network examples weren’t talking at all, but the RF24 examples were (but still sketchy with the acknowledgement to my Unit 1 that doesn’t Rx well).

Regardless I did testing from one end of my house, all the way into the garage and inside my car… and Unit 2 was still receiving packets at a 10Hz rate. I’d say I was at least 50 feet away. Depending on how I oriented the antenna, I could find spots where it nulled out.

I ordered 4 more boards off ebay last night to see if I could get a more reliable unit that my Unit 1.

I did read some comments that suggested the communication pins were not 5V tolerant like most of the specs claim, and that switching to 3.3V I/O made their issues go away. I still haven’t tried that, but definitely will if these new boards still have issues.

Regardless I’ll start porting the RF24 library to Spark Core now :wink:

BDub, they pins are NOT 5V tolerant. I blew 2 modules that way! :frowning:

This is kind of what I was going off of… but obviously we have to check some things:

BDub, my modules did not read the specs it seems! Thanks for the info.

If you apply 5V to the VDD pin, it will smoke though! …

These will probably work great with the 3.3V Spark Core :slight_smile:

That must be what I did! I tested my modules with a DigiX due-compatible board which runs at 3.3V so yup, they will work quite well with the Spark. :smile:

I confirm the modules are 5V tolerant on all the communication pins, but they require a 3.3V on the voltage source. I’ve tested them for short periods at 3.7V: they didn’t blow up, but I wouldn’t go for that long term.