setPayloadSize for nRF24L01 library

Hi all,

I’m trying to use a nRF24L01 transmitter to send over 2bits of data.

Some more details see the last comment to this instructable (by cts_casemod).

the code provided works fine with 1 or 2 bits, but anything over that doesn’t work.

I’m using the provided libraries.

This is my code:

Transmitter:

********************************************************************************

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

int transmitterId = 0;

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
// Contacts from the radio to connect NRF24L01 -> Arduino

//SCK -> 13
//MISO -> 12
//MOSI -> 11
//CSN -> 10
//CE -> 9

RF24 radio(9, 10);

// Transmitter address
const uint64_t pipe = 0xE8E8F0F0E1LL;

//button connected to these pins

int buttonPin1 = 7;

void setup(void) {

// CHANGE THIS PER EACH TRANSMITTER, from 0 to 255
transmitterId = 64;

pinMode(buttonPin1, INPUT_PULLUP);
radio.begin();

// the following statements improve transmission range
radio.setPayloadSize(2); // setting the payload size to the needed value
radio.setDataRate(RF24_250KBPS); // reducing bandwidth

radio.openWritingPipe(pipe); // set the transmitter address

}

void loop(void) {

//until button 1 (buttonPin1) pressed send the package (id) to receiver Arduino
if (digitalRead(buttonPin1) == HIGH) {

// some implementations automatically shut down the radio after a transmission: this ensures the radio is powered up before sending data
radio.powerUp();

// read and write expect a reference to the payload (& symbol)
// second argument is the packet length in bytes (sizeof(int) == 2)
radio.write(&transmitterId, 1);
//delay(100);
}
}

Receiver:

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

int senderId;

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
//Contacts from the radio to connect NRF24L01 pinamnam -> Arduino

//SCK -> 13
//MISO -> 12
//MOSI -> 11
//CSN -> 10
//CE -> 9

RF24 radio(9, 10);

// this is not the channel address, but the transmitter address
const uint64_t pipe = 0xE8E8F0F0E1LL;

// Output LED
int LEDpin = 3;

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

radio.begin();

// the following statements improve transmission range
radio.setPayloadSize(2); // setting the payload size to the needed value
radio.setDataRate(RF24_250KBPS); // reducing bandwidth

radio.openReadingPipe(1, pipe); // Open one of the 6 pipes for reception

radio.startListening(); // begin to listen

// Enable all the LED pins as output
pinMode(LEDpin, OUTPUT);
digitalWrite(LEDpin, LOW); // this is unnecessary but good practice nonetheless

}

void loop(void) {

// Turns off all the LEDs
digitalWrite(LEDpin, LOW);

if (radio.available()) {

// this while is here to throw away all the packets but the last one
bool done = false;
while (!done) {

// read and write expect a reference to the payload (& symbol)
// second argument is the packet length in bytes (sizeof(int) == 2)
done = radio.read(&senderId, 1);
}

//Light up the correct LED for 50ms
if (senderId == 64)
{
digitalWrite(LEDpin, HIGH);
Serial.print("LED ");
Serial.print(senderId);
Serial.print(" On , ");
}
Serial.print("Received = ");
Serial.println(senderId);
delay(500);
}
}

Everything works fine if I set the field:

radio.setPayloadSize(2);

to either 1 or 2 bits, however, if i try 3 or more bits nothing works.

The library documentation suggests 32 bit transmission should be possible, I’m unsure if the overhead bits could be causing this value to be exceeded, but even if they do, surely 3 bit transmission should be possible? Any suggestions?

It's not bits, it's bytes.

I've used 2, 6, 8, 16 and 24 byte payloads with no problems as long as both the transmitter and receiver are set to use the same payload size.

Pete

Oh, and there’s one other thing. You have to make sure that having set the payload size to 2 in both receiver and transmitter:

radio.setPayloadSize(2);

which you did correctly, you must also write

radio.write(&transmitterId, 1);

and read

done = radio.read(&senderId, 1);

2 bytes, which you don’t.

Pete

// read and write expect a reference to the payload (& symbol)
radio.write(&transmitterId, 1);

The & is the address-of-operator, it is not a reference that is passed, it is a pointer.

Thanks guys. I'm not sure I understood whats being said here.

Any code examples?

El_supremo: The transmitter is not sending anything whenever setPayloadSize() is set > 2. The code just hangs when it gets to the main loop, with no SPI communication. Having a mismatch on the sender/receiver would truncate the data.

May God be with you all.

Having a mismatch on the sender/receiver would truncate the data.

Not in my experience. When you set a payload size, the receiver must send packets of exactly that size, and the receiver must ask for exactly that size. Try it.

Pete

The pair of demo programs in this link may be helpful.

You seem to have defined transmitterId as an int (which is 2 bytes long) but you are only sending one byte with

radio.write(&transmitterId, 1);

I prefer to create an array for the data - eg transmitterId[1] = 64; because then you can use

radio.write(transmitterId, sizeof(transmitterId);

I have no idea why C/C++ treats an array-name as an address and does not do the same with individual variables.

...R

el_supremo: Not in my experience. When you set a payload size, the receiver must send packets of exactly that size, and the receiver must ask for exactly that size. Try it.

Pete

Thanks

The test I made was to leave the receiver with a payload of 2 and change the payload to 1 on the sender. On the receiver side only the 8MSB were transmitted.

Robin2: The pair of demo programs in this link may be helpful.

You seem to have defined transmitterId as an int (which is 2 bytes long) but you are only sending one byte with

radio.write(&transmitterId, 1);

Good catch.

Robin2: I prefer to create an array for the data - eg transmitterId[1] = 64; because then you can use

radio.write(transmitterId, sizeof(transmitterId);

I have no idea why C/C++ treats an array-name as an address and does not do the same with individual variables.

...R

That's interesting. Are you suggesting that if I have 32 bits to send to simply initialize an array with the number of bits I want rather than using a number?

amvcs08: Are you suggesting that if I have 32 bits to send to simply initialize an array with the number of bits I want rather than using a number?

I'm reluctant to respond because your comment is confusing.

Do you mean you have 4 bytes (32 bits) or 32 bytes ?

And where do the 32 bits (if they are bits) come from - for example it may be an unsigned long value which would require slightly different code from 4 bytes.

...R

Very interesting topic indeed! So if you have for example an array of say 70 bytes to send at a time, what would be the optimum payload size?

You can't send more than 32 bytes at a time.

Pete

So, if the payload is set to 32 bytes, would the nrf24 chip split the 70 byte packet down to 3 smaller packets 32 byres each?

Robin2: I'm reluctant to respond because your comment is confusing.

Do you mean you have 4 bytes (32 bits) or 32 bytes ?

And where do the 32 bits (if they are bits) come from - for example it may be an unsigned long value which would require slightly different code from 4 bytes.

...R

I have 4 bytes (32 bits) to send. These are actually part of an array with 4 individual bytes, which I combined as a long to be able to send in a single go using the library

I'm starting to think its better to discard the library and just send the data directly to the registers...?

amvcs08: I have 4 bytes (32 bits) to send. These are actually part of an array with 4 individual bytes, which I combined as a long to be able to send in a single go using the library

If they are 4 individual bytes then just store them in an array and send the array

byte myArrray[4];
myArray[0] = valA;
myArray[1] = valB;
// etc
radio.write(myArray, sizeof(myArray));

On the other side, receive the array and allocate its contents.

...R

So, if the payload is set to 32 bytes, would the nrf24 chip split the 70 byte packet down to 3 smaller packets 32 byres each?

As far as I can tell, it won't send any more than 32 bytes at once. For a 70 byte message I would set the payload size to 14 bytes and send the 70 bytes as 5 separate packets.

Pete

It appears that, if I set the payload to a value => 5 on both transmitter and receiver transmission is successful. I’m not quite sure what is the reason behind this.

Robin2:
If they are 4 individual bytes then just store them in an array and send the array

byte myArrray[4];

myArray[0] = valA;
myArray[1] = valB;
// etc
radio.write(myArray, sizeof(myArray));



On the other side, receive the array and allocate its contents.

...R

That didn’t quite work for some reason, but this did:

for ( int i = 0; i < 4; ++i )
(reinterpret_cast<char*>(&transmitterdata))[i] = mybuf[i];

transmitterdata is set as a global unsigned long variable.

One other question regarding this…

it seems whenever I add a delay to the transmitter, it stops acting correctly (delay on the slave works fine).

Any suggestions to improve this? I want to broadcast once every minute or so.

Regards

amvcs08: That didn't quite work for some reason, but this did:

I need to see both programs in their entirety before I can figure out why one works and the other does not.

Regarding the delay() - are you using the ManiacBug version of the RF24 library? Again post the code that illustrates the problem.

...R

These are the code versions I have working.
For some reason if I try to add a delay to the transmitter no data is sent. I tried to add a stop radio command, but it didn’t help. Trying to read the datasheet to see if I get some hints, but if someone knows why this happens it would be great. Basically i want to send data in periodic intervals rather than continuously.

The libraries I’m using are the ones posted on the instructables tutorial posted on the first link and can be downloaded here

The bit suggested to send the 4 bits is commented out on the transmitter code. It sends only the first 16 bits correctly.

Receiver with serial debug:

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
/*
byte 1 - Passcode - 8 bit unique identifier. Used to detect a corrupted transmission/Base ID
byte 2 - Address - Address of the receiver the data is assigned to.
byte 3 - Data (bits 8...15)
byte 4 - Data (bits 0...7)*/

//Initialize  local variables. 
//Create a 4 bit array, as above
byte mybuf[4];

// Create a long variable to store the received data
unsigned long receiverData = 0;

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
// Contacts from the radio to connect NRF24L01 pinamnam -> Arduino

//SCK -> 13
//MISO -> 12
//MOSI -> 11
//CSN -> 10
//CE -> 9

RF24 radio(9, 10);

// this is not the channel address, but the transmitter address
const uint64_t pipe = 0xE8E8F0F0E1LL;

// Output LED
int LEDpin = 3;

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

  radio.begin();

  // the following statements improve transmission range
  radio.setPayloadSize(6); // setting the payload size to the needed value
  radio.setDataRate(RF24_250KBPS); // reducing bandwidth

  radio.openReadingPipe(1, pipe); // Open one of the 6 pipes for reception

  radio.startListening(); // begin to listen

  // Enable all the LED pins as output
  pinMode(LEDpin, OUTPUT);
  digitalWrite(LEDpin, LOW); // this is unnecessary but good practice nonetheless
  //Serial.println("Init OK");
}

void loop(void) {
  //delay(3000);

  if (radio.available()) 
  {
    // this while is here to throw away all the packets but the last one
    bool done = false;
    while (!done) 
    {
      // read and write expect a reference to the payload (& symbol)
      // second argument is the packet length in bytes (sizeof(int) == 2)
      done = radio.read(&receiverData, 4);
    }

    // Now process received data...
    mybuf[0] = (receiverData);
    mybuf[1] = (receiverData >> 8);
    mybuf[2] = (receiverData >> 16);
    mybuf[3] = (receiverData >> 24);
  }


  Serial.println(mybuf[0]);
  Serial.println(mybuf[1]);
  Serial.println(mybuf[2]);
  Serial.println(mybuf[3]);
  //Check for the correct passphrase
  if (mybuf[0] == 84)
  //Serial.println("passphrase ok");
  {
    // Now check for the correct address
    if (mybuf[1] == 56)
    {
      // Serial.println("Address OK");
      // Extract the needed data.
      
      if(mybuf[2] >> 5 & 1)
      {
        // If bit 5 of mybuf[2] is set turn the LED ON
        digitalWrite(LEDpin, HIGH);
        Serial.println("led on");
        Serial.println(mybuf[2]);
      }
      else
      {
        // Turn it OFF
        digitalWrite(LEDpin, LOW);
        Serial.println("led off");
        Serial.println(mybuf[2]);
      }                
    }
  }
  delay(500);
}

Transmitter:

/* nRF24L01 radio - Transmits 4 bytes of data:
 
 byte 1 - Passcode - 8 bit unique identifier. This is used to detect a corrupted transmission
 byte 2 - Address - Address of the receiver.
 byte 3 - Data (bits 7...15)
 byte 4 - Data (bits 0...7)*/

//Initialize  local variables
byte mybuf[4];

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

unsigned long transmitterdata = 0;

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
//Contacts from the radio to connect NRF24L01 pinamnam -> Arduino

//SCK -> 13
//MISO -> 12
//MOSI -> 11
//CSN -> 10
//CE -> 9

RF24 radio(9, 10);

// this is not the channel address, but the transmitter address
const uint64_t pipe = 0xE8E8F0F0E1LL;

//button connected to these pins

int buttonPin1 = 7;
int i = 0;

void setup(void) {

  Serial.begin(9600);
  // Define security passphrase
  mybuf[0] = 84;     
  // Define Transmission address
  mybuf[1] = 56;
  // DATA
  mybuf[2] = 0;
  mybuf[3] = 0;

  // Define Input button for test. Enable Internal Pull up
  pinMode(buttonPin1, INPUT_PULLUP);

  //-------------------------------------------- 
  radio.begin();

  // the following statements improve transmission range
  radio.setPayloadSize(6); // setting the payload size to the needed value
  radio.setDataRate(RF24_250KBPS); // reducing bandwidth to 250Khz

  radio.openWritingPipe(pipe); // set the transmitter address

  //---------------------------------

}

void loop(void) { 


  if (digitalRead(buttonPin1) == HIGH) 

  {
    //Serial.println(buf[0]);
    mybuf[2] |= _BV(5); // Set bit 5
    //Serial.println(mybuf[1], BIN);
    //delay(500);
  }
  else
  {
    mybuf[2] &= ~_BV(5); // Clear bit 5
  }

  // Encode the variables and send them out
  //  transmitterdata = (((mybuf[0] & 0xFF) << 0) | ((mybuf[1] & 0xFF) << 8) | ((mybuf[2] & 0xFF) << 16) | ((mybuf[3] & 0xFF) << 24)); // This didn't work...
  for ( int i = 0; i < 4; ++i )
    (reinterpret_cast<char*>(&transmitterdata))[i] = mybuf[i];


  Serial.println(transmitterdata, BIN);
  // some implementations automatically shut down the radio after a transmission: this
  // ensures the radio is powered up before sending data
  radio.powerUp();

  // read and write expect a reference to the payload (& symbol)
  // second argument is the packet length in bytes (sizeof(int) == 2)
  //radio.write(mybuf, sizeof(4));
  radio.write(&transmitterdata, 4);
  radio.powerDown();

}
// read and write expect a reference to the payload (& symbol)

You have still this in your code... what a shame.