Integer values not received as sent using NRF24L01 transceivers [solved]

Hello,

Below are some sketches I'm using for wireless sending integer values (with auto ack) from one Uno to another using NRF24L01 tranceivers. I copy/ pasted them from this site: Auto Ack completely fixed – Just Electronics

I'm using the NRF24 library by TMRh20 version 1.2.0 and Arduino (Windows store) version 1.8.1.0.

Similar examples are available (inside the library and on this forum) and have basically the same approach. I tried many of them but with the same strange results: the radio modules seem to be working properly (as verified with library "Gettingstarted" example) but the integer values which I send are most of the time received as a different but close to the original integer value. No matter how often I send the same integer, it will always be received as the wrong but equally wrong value. Even after reapplying power, the results are always the same. Some values are however properly received. Here are some examples:

Integer sent= 1; integer received=1
Integer sent= 2; integer received=3
Integer sent= 3; integer received=3
Integer sent= 4; integer received=6
Integer sent= 5; integer received=7
Integer sent= 6; integer received=7
Integer sent= 7; integer received=7
Integer sent= 8; integer received=12
Integer sent= 9; integer received=13
Integer sent= 10; integer received=15
...
Integer sent= 25; integer received=29
...
Integer sent= 30; integer received=31
Integer sent= 31; integer received=31
...
Integer sent= 115; integer received=123
...
Integer sent= 255; integer received=255

The acknowledge payload values which the receiver sends back is always correct as I tried several different values for rec[1].

Does someone recognize this behavior and explain to me what could be causing this difference between the values? Thank you for your help in advance!

The transmitter code:

#include<SPI.h>
#include<nRF24L01.h>
#include<RF24.h>
int msg[1] = {1};
int rec[1] = {5};
bool stat = true;
RF24 radio(9,10);
const uint64_t pipe[1] = {0xF0F0F0F0E1LL};
  
void setup()
{
  Serial.begin(57600);
  radio.begin();
  delay(100);
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.stopListening();
  radio.openWritingPipe(pipe[0]);
  radio.setRetries(15,15);
 }
void loop()
{
if(stat)
{
    if(radio.write(msg,sizeof(msg)))
    {
      Serial.print( msg[0] );
      Serial.println("...tx success");
      if(radio.isAckPayloadAvailable())
      {
        radio.read(rec,sizeof(int));
        Serial.print("received ack payload is : ");
        Serial.println(rec[0]);
      }
      else
      {
        stat = false; //doing this completely shuts down the transmitter if an ack payload is not received !!
        Serial.println("status has become false so stop here....");
      }
      msg[0]+=3;;
    if(msg[0]>=100)
    {msg[0]=1;}
    }
 }
}

The receiver code:

#include<SPI.h>
#include<nRF24L01.h>
#include<RF24.h>
const uint64_t pipe[1]= {0xF0F0F0F0E1LL};
RF24 radio(9,10);
int rec[1] = {2};
int red;
void setup()
{
  Serial.begin(57600);
  radio.begin();
  delay(100);
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.openReadingPipe(1,pipe[0]);
  radio.startListening();
  radio.setRetries(15,15);
}
void loop()
{
  if ( radio.available() ) {
    radio.writeAckPayload( 1, rec, sizeof(int) );
    radio.read( &red,sizeof(red) );rec[0]+=2;
    Serial.print("integer got is : ");
    Serial.println(red);
}
}

I don't think your sending back to back is very sensibel.

You will block on Serial, you can send faster than print the results.

How about sending one packet per second to test the communication?

If it works as expected, you can speed up again if neccessary.

I see what you mean, but I tried also by commenting out the following lines so only the same value of msg[0] get transmitted over and over:

//msg[0]+=3;
//if(msg[0]>=100)
//{msg[0]=1;}

Then I modified the declaration of msg[1] to {2}, uploaded and tried; to {5}, uploaded and tried; to {30}, uploaded and tried, etc. The results are the same as I posted above:
Integer sent= 2; integer received=3
Integer sent= 5; integer received=7
Integer sent= 30; integer received=31

I think you do not understand the ackpayload process (symptom: no preload in setup, ackpayload used as response)

The reception of a packet returns the payload that was written before the receive happend.

if ( radio.available() ) {
    radio.writeAckPayload( 1, rec, sizeof(int) );
    radio.read( &red,sizeof(red) );rec[0]+=2;
    Serial.print("integer got is : ");
    Serial.println(red);
  }

If a packet was received,
write an int as ackpayload for the next packet,
read the current packet
increment the int for next ackpayload by two,
then print the received value.

You increment the sended int by 3 starting with 1, returning to zero if above 100
you increment the returned int by 2 starting with 2.

Integer sent= 1; integer received=1
Integer sent= 2; integer received=3
Integer sent= 3; integer received=3
Integer sent= 4; integer received=6
Integer sent= 5; integer received=7
Integer sent= 6; integer received=7
Integer sent= 7; integer received=7
Integer sent= 8; integer received=12
Integer sent= 9; integer received=13
Integer sent= 10; integer received=15
...
Integer sent= 25; integer received=29
...
Integer sent= 30; integer received=31
Integer sent= 31; integer received=31
...
Integer sent= 115; integer received=123
...
Integer sent= 255; integer received=255

can not be produced by the code above.

Please post real output.

This Simple nRF24L01+ Tutorial may be useful.

...R

Thank you Whandall for actually looking into the problem!

I think you do not understand the ackpayload process (symptom: no preload in setup, ackpayload used as response)

As I mentioned, the acknowledge process is working correctly and indeed is always one step behind. Maybe the code (not my creation) is not an example of showing that the process is understood, but I'm aware of it and even need the acknowledge for my future purpose (I don't want to make role changing modules for cross-traffic as the acknowledge payload is very usable if implemented correctly). Let's keep the acknowledge process out of focus for now, just ignore it.

can not be produced by the code above.

Please post real output.

You're absolutely correct. I just made that resume trying to explain the situation as simple as possible and with "results" I wasn't referring to the actual program output over the serial port.

I changed the delay in the tx sketch and added 1 instead of 3 each time to the integer value. I don't know why the creator of the code picked 3, it does not help clearing things up.

Here are both sketches:

tx:

#include<SPI.h>
#include<nRF24L01.h>
#include<RF24.h>
int msg[1] = {1};
int rec[1] = {5};
bool stat = true;
RF24 radio(7,8);
const uint64_t pipe[1] = {0xF0F0F0F0E1LL};
  
void setup()
{
  Serial.begin(57600);
  radio.begin();
  delay(100);
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.stopListening();
  radio.openWritingPipe(pipe[0]);
  radio.setRetries(15,15);
 }
void loop()
{delay(1000);

if(stat)
{
    if(radio.write(msg,sizeof(msg)))
    {
      Serial.print( msg[0] );
      Serial.println("...tx success");
      if(radio.isAckPayloadAvailable())
      {
        radio.read(rec,sizeof(int));
        Serial.print("received ack payload is : ");
        Serial.println(rec[0]);
      }
      else
      {
        stat = false; //doing this completely shuts down the transmitter if an ack payload is not received !!
        Serial.println("status has become false so stop here....");
      }
      msg[0]+=1;
    if(msg[0]>=100)
    {msg[0]=1;}
    }
 }
}

rx:

#include<SPI.h>
#include<nRF24L01.h>
#include<RF24.h>
const uint64_t pipe[1]= {0xF0F0F0F0E1LL};
RF24 radio(7,8);
int rec[1] = {1};
int red;
void setup()
{
  Serial.begin(57600);
  radio.begin();
  delay(500);
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.openReadingPipe(1,pipe[0]);
  radio.startListening();
  radio.setRetries(15,15);
}
void loop()
{
  if ( radio.available() ) {
    radio.writeAckPayload( 1, rec, sizeof(int) );
    radio.read( &red,sizeof(red) );rec[0]+=1;
    Serial.print("integer got is : ");
    Serial.println(red);
}
}

And here are the real results:

tx serial output (everything looking fine here):

1...tx success
                                                                
received ack payload is : 1
                                                   
2...tx success
                                                                
received ack payload is : 2
                                                   
3...tx success
                                                                
received ack payload is : 3
                                                   
4...tx success
                                                                
received ack payload is : 4
                                                   
5...tx success
                                                                
received ack payload is : 5
                                                   
6...tx success
                                                                
received ack payload is : 6
                                                   
7...tx success
                                                                
received ack payload is : 7
                                                   
8...tx success
                                                                
received ack payload is : 8
                                                   
9...tx success
                                                                
received ack payload is : 9
                                                   
10...tx success
                                                               
received ack payload is : 10
                                                  
11...tx success
                                                               
received ack payload is : 11
                                                  
12...tx success
                                                               
received ack payload is : 12
                                                  
13...tx success
                                                               
received ack payload is : 13
                                                  
14...tx success
                                                               
received ack payload is : 14
                                                  
15...tx success
                                                               
received ack payload is : 15
                                                  
16...tx success
                                                               
received ack payload is : 16
                                                  
17...tx success
                                                               
received ack payload is : 17
                                                  
18...tx success
                                                               
received ack payload is : 18
                                                  
19...tx success
                                                               
received ack payload is : 19
                                                  
20...tx success
                                                               
received ack payload is : 20
                                                  
21...tx success
                                                               
received ack payload is : 21
                                                  
22...tx success
                                                               
received ack payload is : 22
                                                  
23...tx success
                                                               
received ack payload is : 23

rx serial output:

integer got is : 1
                                                            
integer got is : 3
                                                            
integer got is : 3
                                                            
integer got is : 6
                                                            
integer got is : 7
                                                            
integer got is : 7
                                                            
integer got is : 7
                                                            
integer got is : 12
                                                           
integer got is : 13
                                                           
integer got is : 15
                                                           
integer got is : 15
                                                           
integer got is : 14
                                                           
integer got is : 15
                                                           
integer got is : 15
                                                           
integer got is : 15
                                                           
integer got is : 24
                                                           
integer got is : 25
                                                           
integer got is : 27
                                                           
integer got is : 27
                                                           
integer got is : 30
                                                           
integer got is : 31
                                                           
integer got is : 31
                                                           
integer got is : 31

I expect the received integers to increase with 1 each time a radio.available event happens at the rx side, but they do not. What am I doing wrong or not understanding correctly here?

The first sent packet should not get an ack-payload (because you still do not preload it),
try to power down the module between tests, to see that effect.

The way you have written it, the transmitter should stall after the first send with
Serial.println("status has become false so stop here....");.

Drop the delays after radio.begin, that's voodoo.

You are not using pin 10 as SS, so you should set it to output. (SPI documentation).

Why are you still not preloading the ackpayload for the first received packet?

After all: you are seeing really strange results.

I tried a slightly modified version adapted to my hardware settings here on a nano (sender) and mega (receiver).

It just works as expected.

RX

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

const uint64_t pipe[1] = {0xF0F0F0F0E1LL};

RF24 radio(8, 7);

int rec = 1;
int red;

void setup()
{
  Serial.begin(250000);
  radio.begin();
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.openReadingPipe(1, pipe[0]);
  radio.setRetries(15, 15);
  radio.startListening();
  loadPayload();
}

void loop() {
  if (radio.available() ) {
    loadPayload();
    radio.read( &red, sizeof(red) );
    Serial.print(F("integer got is : "));
    Serial.println(red);
  }
}

void loadPayload() {
  Serial.print(F("integer loaded : "));
  Serial.println(rec);
  radio.writeAckPayload( 1, &rec, sizeof(int) );
  rec++;
}

TX

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

const uint64_t pipe[1] = {0xF0F0F0F0E1LL};

int msg = 1;
int rec = 1;
bool stat = true;

RF24 radio(9, 10);

void setup()
{
  Serial.begin(250000);
  radio.begin();
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.stopListening();
  radio.openWritingPipe(pipe[0]);
  radio.setRetries(15, 15);
}

void loop() {
  if (stat) {
    if (radio.write(&msg, sizeof(msg)))  {
      Serial.print(msg);
      Serial.println(F("...tx success"));
      if (radio.isAckPayloadAvailable()) {
        radio.read(&rec, sizeof(rec));
        Serial.print(F("received ack payload is : "));
        Serial.println(rec);
      } else {
        stat = false;
        Serial.println(F("status has become false so stop here...."));
      }
      if (++msg >= 100) {
        msg = 1;
      }
    } else {
      Serial.println(F("...tx failed"));
    }
    delay(1000);
  }
}

RX-log

integer loaded : 1
integer loaded : 2
integer got is : 13
integer loaded : 3
integer got is : 14
integer loaded : 4
integer got is : 15
integer loaded : 5
integer got is : 16
integer loaded : 6
integer got is : 17
integer loaded : 7
integer got is : 18
integer loaded : 8
integer got is : 19
integer loaded : 9
integer got is : 20
integer loaded : 10
integer got is : 21
integer loaded : 11
integer got is : 22
integer loaded : 12
integer got is : 23

TX-log

...tx failed
13...tx success
received ack payload is : 1
14...tx success
received ack payload is : 2
15...tx success
received ack payload is : 3
16...tx success
received ack payload is : 4
17...tx success
received ack payload is : 5
18...tx success
received ack payload is : 6
19...tx success
received ack payload is : 7
20...tx success
received ack payload is : 8
21...tx success
received ack payload is : 9
22...tx success
received ack payload is : 10
23...tx success
received ack payload is : 11
24...tx success
received ack payload is : 12
25...tx success
received ack payload is : 13
26...tx success
received ack payload is : 14
27...tx success
received ack payload is : 15
28...tx success
re

Thank you very much Whandall for your input and suggestions!

Setting pin D10 to output was something I assumed was taken care of by the SPI library in case SPI was included in the sketch so I forgot to do so while using other pins. I switched to all proprietary SPI pins for connecting the radio. It makes more sense anyway to use the hardware SPI pins instead of assigning alternative pins in software.

All is working perfectly and very stable now using your sketches!

Thanks again!

You could add a [Solved] to the title of the thread.

Glad to hear it works now.