NRF24L01+ Failing AckPayload

I am using the NRF24L01+ modules for my project and utilizing the writeAckPayload(); function for fast two-way communcation. The test code that I used was from this link: NRF24L01+ Transceiver Demo

It worked great and I was able to get about 600 messages a second back and forth between the modules. I modified the code for my needs and noticed some issues.

First, when I add more data (increase the size of the packet), the speeds start to slow down significantly. I thought that the NFR24l01+ always sends out a 32 byte message and replaces the non-used bytes with zeros. So would using the full 32 byte message really slow down the transmission if it is sending a 32 byte message either way?

Second, in the documentation it says the the writeAckPayload() function can handle 32 bytes of information. But when I try to add any more than 16 bytes the payload wont send. I do not understand why this is happening. I have posted my receiver code below.

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

#define CE_PIN   12
#define CSN_PIN 8

const byte thisSlaveAddress[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN);

char dataReceived[10]; // this must match dataToSend in the TX
int ackData[2] = {109, -4000}; // the two values to be sent to the master

struct dataStruct {       //this is the NRF data. Max of 32 bytes
  int Xposition;         //int=2 bytes
  int Yposition;         //double=4 bytes
  bool switchOn;         //boolean=1 byte

  int X2position;       
  int Y2position;
  bool switch2On; 
} myData;

struct dataStruct1 {  
  double feedback_1;
  double feedback_2;
  double feedback_3;
  double feedback_4;
//  double feedback_5;
//  double feedback_6;
} myTele; 

unsigned long timer, countTimer, count, interval;

//==============

void setup() {

    Serial.begin(115200);

    radio.begin();
    radio.setChannel(108); //
    radio.setDataRate( RF24_250KBPS );
    //radio.setDataRate( RF24_2MBPS );
    radio.setPALevel(RF24_PA_MAX); //
    
    radio.openReadingPipe(1, thisSlaveAddress);

    radio.enableAckPayload();
    radio.writeAckPayload(1, &myTele, sizeof(myTele)); // pre-load data

    radio.startListening();

    myTele.feedback_1 = 1;
    myTele.feedback_2 = 2;
    myTele.feedback_3 = 3;
    myTele.feedback_4 = 4;
//    myTele.feedback_5 = 5;
//    myTele.feedback_6 = 6;
}

//==========

void loop() {
    timer = micros();
    if ( radio.available() ) {
        count += 1;
        radio.read( &myData, sizeof(myData) );
        
        radio.writeAckPayload(1, &myTele, sizeof(myTele));

        Serial.print("X1: "); Serial.print(myData.Xposition);
        Serial.print("Y1: "); Serial.print(myData.Yposition);
        Serial.print("X2: "); Serial.print(myData.X2position);
        Serial.print("Y2: "); Serial.print(myData.Y2position);
        Serial.println();
    }
    if (countTimer > 1000000) { Serial.print(count); Serial.print("\t"); count = 0; countTimer = 0; }
    interval=micros()-timer;
    countTimer+=interval;
}

Post your corresponding TX program and I will try them myself. But it will be later today at the earliest.

...R

Transmitter Code:

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


#define CE_PIN   7
#define CSN_PIN 8

const byte slaveAddress[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataToSend[10] = "Message 0";
char txNum = '0';
int ackData[2] = {-1, -1}; // to hold the two values coming from the slave

unsigned long timer, countTimer, count, interval;

bool rslt;

struct dataStruct {
  int Xposition;    
  int Yposition;   
  bool switchOn; 

  int X2position;       
  int Y2position;
  bool switch2On; 
} myData;

struct dataStruct1 {  
  double feedback_1;
  double feedback_2;
  double feedback_3;
  double feedback_4;
  double feedback_5;
  double feedback_6;
} myTele; 

//////////////////first joystick///////////////////////////////////
#define JOYSTICK_X   A3
#define JOYSTICK_Y   A2
#define JOYSTICK_SW  4  
//////////////////second joystick//////////////////////////////////
#define JOYSTICK2_X   A1
#define JOYSTICK2_Y   A0
#define JOYSTICK2_SW  5
///////////////////////////////////////////////////////////////////

//===============

void setup() {

    Serial.begin(115200);

    radio.begin();
    radio.setChannel(108); //
    radio.setDataRate( RF24_250KBPS );
    //radio.setDataRate( RF24_2MBPS );
    radio.setPALevel(RF24_PA_MAX); //

    radio.enableAckPayload();

    radio.setRetries(3,5); // delay, count
    radio.openWritingPipe(slaveAddress);
}

//=============

void loop() {
    timer = micros();
    myData.Xposition = analogRead(JOYSTICK_X);
    myData.Yposition = analogRead(JOYSTICK_Y);
    myData.X2position = analogRead(JOYSTICK2_X);
    myData.Y2position = analogRead(JOYSTICK2_Y);

    rslt = radio.write( &myData, sizeof(myData));

    if (rslt) {
        if ( radio.isAckPayloadAvailable() ) {
            radio.read(&myTele, sizeof(myTele));
            count += 1;
            Serial.print("Feedback 1: "); Serial.print(myTele.feedback_1); Serial.print("\t");
            Serial.print("Feedback 2: "); Serial.print(myTele.feedback_2); Serial.print("\t");
            Serial.print("Feedback 3: "); Serial.print(myTele.feedback_3); Serial.print("\t");
            Serial.print("Feedback 4: "); Serial.print(myTele.feedback_4); Serial.print("\t");
            Serial.println();
        }
    }
        else { Serial.println("  Tx failed"); }

    if (countTimer > 1000000) { Serial.print(count); Serial.print("\t"); count = 0; countTimer = 0; }
    interval=micros()-timer;
    countTimer+=interval;
}

//================

I see you are a person of few words :slight_smile:

I won't get a chance to look at this until tomorrow. I will bookmark this Thread so I can find it.

...R

mschindl:
First, when I add more data (increase the size of the packet), the speeds start to slow down significantly. I thought that the NFR24l01+ always sends out a 32 byte message and replaces the non-used bytes with zeros. So would using the full 32 byte message really slow down the transmission if it is sending a 32 byte message either way?

That is the case if you don't change the configuration.
By using AckPayloads you have implicitly enabled DynamicPayloads, so bigger packets (both ways) take longer.

mschindl:
I am using the NRF24L01+ modules for my project and utilizing the writeAckPayload(); function for fast Second, in the documentation it says the the writeAckPayload() function can handle 32 bytes of information. But when I try to add any more than 16 bytes the payload wont send. I do not understand why this is happening.

You configured the retry timeout too short.

    radio.setDataRate( RF24_250KBPS );
    radio.enableAckPayload();
    radio.setRetries(3,5); // delay, count

So the retry kills your AckPayload by collision.

There is information about the lowest possible values for delay
with respect to transmission speed and AckPayload length, I don't know that by heart.

If ACK packet payload is activated, ACK packets have dynamic payload lengths and the Dynamic Pay-load Length feature should be enabled for pipe 0 on the PTX and PRX. This is to ensure that they receive the ACK packets with payloads. If the payload in ACK is more than 15 byte in 2Mbps mode the ARD must be 500μS or more, and if the payload is more than 5byte in 1Mbps mode the ARD must be 500μS or more

The ARD defines the time from the end of a transmitted packet to a retransmit starts on the PTX side. ARD is set in SETUP_RETR register in steps of 250μs.
A retransmit is made if no ACK packet is received by the PTX.
There is a restriction for the length of ARD when using ACK packets with payload.
The ARD time must never be shorter than the sum of the startup time and the time on-air for the ACK packet.
For 1Mbps data rate and 5 byte address; 5 byte is maximum ACK packet payload length for ARD=250μs (reset value).
For 2Mbps data rate and 5 byte address; 15 byte is maximum ACK packet payload length for RD=250μs (reset value).
ARD=500μs will be long enough for any payload length.

So your setting (750) should work if you would set it in all stations,
same holds true for enableDynamicPayloads and enableAckPayload.

Is my ARD not equal to 1000us when set to 3? 0=250us, 1=500us, 2=750us, and 3=1000us?

I am also in 250KBPS mode, but as you have shown me from the datasheet, 500us should be long enough for any ACK packet.

You configured the retry timeout too short.

You are correct. Once I changed the delay from 3 to 5 I get an acknowledgement.

I have noticed something strange about these NRF's though. For these tests I have been using the standard modules, but I have also bought the PA+LNA kind as well. When I switch in the transmitter NRF for an upgraded one, everything works fine as it should. When I switch out the receiver NRF for the upgraded one, it stops working unless I put the setting to 2MPBS or have it set to 250KBPS and touch the antenna with my finger.

What is going on here? Are their consequences to using the PA+LNA version of the module?

The high power modules don't work well when too close, specifically when using

 radio.setPALevel(RF24_PA_MAX);

You could try lower settings.

Added:

Have a look at this Signal problems with long-range Nordic nRF24L01+PA+LNA 2.4GHz RF module.

This could be interesting too Fixing your cheap nrf24l01+ pa/lna module

Great to see someone else sorting out the problem :slight_smile:

...R

The symptom was pretty obvious.

I like helping people that already have some experience with the NRFs,
I' absolutely tired of explaining the pipe system over and over.

[OT]

Recently I played around with the tiny NRF24L01+ module variants,
today I ran the PA LNA version (with onboard ceramic antenna) for the first time.
It was a little hard to find the pinout (which is different from the pinout of the non-PA modules).

[/OT]

Thanks for all the help! Lowering the power level at close range did give me stable data. I do have one last question though. Is it possible with the NRF's to detect when the module is "far" or "close" and switch the PA level based on the distance.

I did a little math and I do not think using the differences in delay would work out. At the speed of light, a transmission would take only 3.33 nanoseconds to reach the NRF from 1 meter away. From 100 meters away it would take 333 nanoseconds. I do not believe the Arduino is nearly fast enough to measure the differences in these delays. Among the other issues presented with this method.

So is there another way to do it? Is it possible for the NRF to judge how powerful the incoming transmission is and change its power level accordingly?

One could send packets and measure the ratio of fails under different settings.
You have no access to any reception strength values AFAIK.

But basically I have no answer to your question.