NFR24 Ack payload issues

Hey everyone! I have a question regarding the nrf24 transceiver module. I am trying to setup a two way communication system using ACK payloads between two modules. The Primary TX reads an anlaog value from pin 7 and transmits it to the primary receiver. The primary receiver then also reads the analog value from pin 7 and transmits it’s value back to the transmitter. I have tried using th e library’s examples, but they are quite complicated and have a lot of code which I don’t need for my purpose. Only problem is that The values aren’t sending or being received properly. It would be great if someone could see if it is obvious what I am doing wrong. Thanks!

Primary Transmitter code

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

RF24 radio(7,8);
struct package
{
 int remotePotSlider = 0;
 int boardBatVoltage = 0;
};

byte adresses[][6] ={"0"};

typedef struct package Package;
Package data;





void setup() {
  Serial.begin(115200);
  radio.begin();
  radio.setRetries(15, 15);
  radio.setChannel(115);
  radio.setPALevel(RF24_PA_LOW);
  radio.setDataRate(RF24_250KBPS);
  radio.enableAckPayload();           
  radio.enableDynamicPayloads(); 
  radio.openWritingPipe(adresses[1]);
  radio.openReadingPipe(1,adresses[0]);
  
  delay(1000);

}

void loop() {
  data.remotePotSlider = analogRead(7);
  delay(20);

  
  if(radio.write(&data, sizeof(data)))
  {
      Serial.println("  transmitted successfully");
      
      if(!radio.available()){                             // If nothing in the buffer, we got an ack but it is blank
          Serial.println("Got blank response");
        }
        
      else{      
            while(radio.available() ){                      // If an ack with payload was received
                radio.read(&data, sizeof(data));  
                Serial.print("Ack payload is: ");
                Serial.print(data.boardBatVoltage);
                }
        }
  }
  else {
    Serial.println("Failed Sending");
  }
        
  delay(50);
        
        
 }

Primary Receiver code

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

RF24 radio(7,8);
struct package
{
 int remotePotSlider = 0;
 int boardBatVoltage = 0;
};

byte adresses[][6] ={"0"};

typedef struct package Package;
Package data;





void setup() {
  Serial.begin(15200);
  radio.begin();
  radio.setRetries(15, 15);
  radio.setChannel(115);
  radio.setPALevel(RF24_PA_LOW);
  radio.setDataRate(RF24_250KBPS);
  radio.enableAckPayload();           
  radio.enableDynamicPayloads(); 
  radio.openWritingPipe(adresses[0]);
  radio.openReadingPipe(1,adresses[1]);
  radio.startListening();
  delay(1000);

}

void loop() {
  data.boardBatVoltage = analogRead(7);
  delay(20);
  
  while( radio.available()){              
      radio.read(&data,sizeof(data));                              
      Serial.println("Received potslider:");
      Serial.print(data.remotePotSlider);
      radio.writeAckPayload(1,&data,sizeof(data));  
      
   }
  
  delay(50);
  
}

You define one 'warned against' address (0x0000000030, not enough bit changes),
but you use some garbage address for the communication (out of array bounds).

You do not preload the first ack payload.

startListening followed by a delay(1000) is contraproductive and guaranteed to overrun the receiver if any sender is active.

You overwrite boardBatVoltage with the received packet before uploading it.

Just a first glance...

The pair of programs in this link work using ackPayload.

...R

Whandall:
You define one 'warned against' address (0x0000000030, not enough bit changes),
but you use some garbage address for the communication (out of array bounds).

You do not preload the first ack payload.

startListening followed by a delay(1000) is contraproductive and guaranteed to overrun the receiver if any sender is active.

You overwrite boardBatVoltage with the received packet before uploading it.

Just a first glance...

Ok thanks for the help. So to preload the first ack payload would I put something like "radio.writeAckPayload(1,&data,sizeof(data));" in the setup part of the primary receiver code? Also, what would be a better address to use instead of "0x0000000030"?

You have to do it before a packet comes in, so setup would be a good place (where the delay was?).

Just give the addresses some more bit changes like 0x3259657830, 0x3259657831, or "1Node", "2Node".

Remember that the common prefixes are in different places in hex or ASCII,
but that only matters if you use pipes 2 to 5 (they have to share the same prefix with pipe 1).

Whandall:
You have to do it before a packet comes in, so setup would be a good place (where the delay was?).

Just give the addresses some more bit changes like 0x3259657830, 0x3259657831, or “1Node”, “2Node”.

Remember that the common prefixes are in different places in hex or ASCII,
but that only matters if you use pipes 2 to 5 (they have to share the same prefix with pipe 1).

Ok cool. So I made some changes following your advice, and it seems to work as intended! :slight_smile:

Tx

#include <SPI.h>
#include "RF24.h";
RF24 radio(7,8);

struct package
{
 int TxSlider = 0;
 int RxVoltage = 0;
};

//byte adresses[][6] ={"0"};
const uint64_t pipe[1] = {0x3259657830};

typedef struct package Package;
Package data;





void setup() {
  Serial.begin(115200);
  radio.begin();
  delay(100);
  radio.setRetries(15, 15);
  radio.setChannel(115);
  radio.setPALevel(RF24_PA_LOW);
  radio.setDataRate(RF24_250KBPS);
  radio.enableAckPayload();           
  radio.enableDynamicPayloads(); 
  radio.openWritingPipe(pipe[0]);
  
  
  

}

void loop() {
  data.TxSlider = analogRead(6);
  delay(20);

  
  if(radio.write(&data.TxSlider, sizeof(data.TxSlider)))
  {
      Serial.println("Transmitted successfully");
      
      if(!radio.available()){                             // If nothing in the buffer, we got an ack but it is blank
          Serial.println("Got blank response");
        }
        
      else{      
            while(radio.available() ){                      // If an ack with payload was received
                radio.read(&data.RxVoltage, sizeof(data.RxVoltage));  
                Serial.print("Ack payload is: ");
                Serial.println(data.RxVoltage);
                }
        }
  }
  else {
    Serial.println("Failed Sending");
  }
        
  delay(500); // for testing to make serial info easier to read
        
        
 }

Rx

#include <SPI.h>
#include "RF24.h";
RF24 radio(7,8);

struct package
{
 int TxSlider = 0;
 int RxVoltage = 0;
};

//byte adresses[][6] ={"0"};
const uint64_t pipe[1] = {0x3259657830};

typedef struct package Package;
Package data;





void setup() {
  Serial.begin(115200);
  radio.begin();
  delay(100);
  radio.setRetries(15, 15);
  radio.setChannel(115);
  radio.setPALevel(RF24_PA_LOW);
  radio.setDataRate(RF24_250KBPS);
  radio.enableAckPayload();           
  radio.enableDynamicPayloads(); 
  radio.openReadingPipe(1,pipe[0]);
  radio.startListening();
  radio.writeAckPayload(1,&data.RxVoltage,sizeof(data.RxVoltage));

}

void loop() {
  data.RxVoltage = analogRead(7);
  delay(20);
  
  while( radio.available()){              
      radio.read(&data.TxSlider,sizeof(data.TxSlider));                              
      Serial.print("Received Txslider:");
      Serial.println(data.TxSlider);
      radio.writeAckPayload(1,&data.RxVoltage,sizeof(data.RxVoltage));  
      
   }
  
  delay(500); // for testing to make serial info easier to read
  
}

So it works now? Or does it only seem to work?

I would not use one structure for tx and rx packets, it feels wrong to me.

There are (voodoo 20 100) delays in your code, why?

If you want to send the information regularly there are other means to accomplish that.

Maybe you should write 0x3259657830LL if you use uint64_t, but uint64_t waste 3 bytes of memory per address, a string none.

Whandall:
So it works now? Or does it only seem to work?

I would not use one structure for tx and rx packets, it feels wrong to me.

There are (voodoo 20 100) delays in your code, why?

If you want to send the information regularly there are other means to accomplish that.

Maybe you should write 0x3259657830LL if you use uint64_t, but uint64_t waste 3 bytes of memory per address, a string none.

Yeah, it fully works. The 100ms delay is after the radio is started becuase I have seen other code do it lol, so I thought it might have some purpose. The other 20ms delay is after the analogRead() and I thought that you were suppose to have a delay after an analogRead(); to let the ADC to settle. Ok, so I have changed the radio.writeAckPayload(1,&data.RxVoltage,sizeof(data.RxVoltage)); to radio.writeAckPayload(1,&"",1);

radio.writeAckPayload(1, &data.RxVoltage, sizeof(data.RxVoltage));
radio.writeAckPayload(1, &"", 1);

The first version is better, what should the second transmit?

The ADC has time to settle while you send, no need for any delays.

Ok got it, no need for the delay after the analogRead(). Sorry, I don't quite understand what you mean by "what should the second transmit?". I thought that when you preload the ack payload it didn't really matter what you loaded which is why I just put a blank string.

Your sender is sending real data, so the payload should contain real data if possible also.

Best would be to have an analogRead in setup, before uploading it as ackPayload. IMHO

I can not explain why &"" like “” produces a pointer to a zero, but I would not use the first variant.

Background check:

void dump(const void* data, byte len) {
  byte* ptr = (byte*)data;
  while (len--) {
    if (*ptr < 16) {
      Serial.write('0');
    }
    Serial.print(*ptr++, HEX);
  }
  Serial.println();
}
void setup() {
  Serial.begin(115200);
  Serial.print(F("&\"\"  "));
  dump(&"", 1);
  Serial.print(F("\"\"   "));
  dump("", 1);
  Serial.print(F("&\"a\" "));
  dump(&"a", 1);
  Serial.print(F("\"a\"  "));
  dump("a", 1);
}
void loop() {}
&""  00
""   00
&"a" 61
"a"  61

Ok thanks for explaining that, yeah adding an analogRead in the setup does make more sense.