NRF24 losing sync after coming back from sleep

Hi,
Here is my setup:
I am trying to make a RF remote with NRF24 and arduino Pro Mini (8MHz, 3.3V). I have fit a chassis of an old nonworking handheld multimeter with a joystick, NRF and the Pro mini.
I am trying to send the x,y and sw values given by the joytstick over the RF.

As the multimeter worked on AAA batteries, for power saving, I removed the voltage regulator from the Pro mini and directly connected the VCC pin to a series of two AAA cells (3V). Also, I tried to build a logic for putting the remote to sleep. What I did was, put a capacitive touch sensor on the remote such that the person holding the remote will touch the sensor. Initially when the remote is powered on by putting in batteries, it is in wake up state. When someone holds it, it still keeps the state. But after that if the person puts it down then the arduino goes to sleep, also it will put the NRF24 to sleep. and it comes back up as soon as someone holds the remote again.
I modified a sktech that I found on this forum for interfacing the rf module.

Now the problem:
The sleeping and waking up logic is working fine for the arduino, but on the receiver side most of the times the RF communication does not resume, even though on the transmitter side I can see the SCK LED blinking again when I hold the remote up again. I need to power off the transmitter by removing the battery and put it back again, then the receiver starts receiving again.

I suspected that my Transmit side NRF is not coming back up from sleep, so I modified the code to only make the arduino sleep and not the NRF… still the same issue arrises when waking up.

Here is my Transmitter code

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

#define CE_PIN   9
#define CSN_PIN 10


#define SLEEP_PIN 2
#define LEFT_RIGHT A0
#define FORWARD_REVERSE A1
#define BUTTON 3

bool buttonState = false;
const byte slaveAddress[5] = {'R','x','A','A','A'};
RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

struct Data_to_be_sent {
  uint16_t lrValue=128;
  uint16_t frValue=128;
  bool buttonState= false;
};

Data_to_be_sent  data;

void sleep() {

  if (digitalRead(SLEEP_PIN))
  {
    //radio.powerUp();
    delayMicroseconds(5000);
  }
  else
  {
      LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
    //  radio.powerDown();
          delayMicroseconds(5000);
  }
}



void setup() {
    pinMode(SLEEP_PIN,INPUT_PULLUP);
    pinMode(BUTTON,INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(SLEEP_PIN), sleep, CHANGE);
    
    Serial.begin(115200);
    Serial.println("Tx Starting");
    radio.begin();
    radio.setAutoAck(false);
    radio.setDataRate( RF24_250KBPS );
    radio.setPALevel(RF24_PA_LOW);
    radio.setRetries(3,5); // delay, count
    radio.setChannel(110);
    radio.openWritingPipe(slaveAddress);
      radio.printDetails();

}


void loop() {
          data.lrValue = analogRead(LEFT_RIGHT);      
          data.frValue = analogRead(FORWARD_REVERSE);
          data.buttonState = digitalRead(BUTTON);
          radio.write(&data, sizeof(Data_to_be_sent));
          Serial.print("lr Value:  ");
          Serial.println(data.lrValue);
          Serial.print("fr Value:  ");
          Serial.println(data.frValue);     
            Serial.print("Button State:  ");
          Serial.println(data.buttonState);   
      delay(200);

}

And my receiver code:

// NRF remote control - Receiver

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

#define CE_PIN   9
#define CSN_PIN 10



const byte slaveAddress[5] = {'R','x','A','A','A'};
RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

struct Rx_data {
  uint16_t lrValue=512;
  uint16_t frValue=512;
  bool button=0;
};

Rx_data  data;
uint16_t old_lr=0;
uint16_t old_fr=0;

void setup() {
    reset_the_Data();
    Serial.begin(115200);
    Serial.println("Rx Starting");
    radio.begin();
    radio.setAutoAck(false);
    radio.setDataRate( RF24_250KBPS );
    radio.setPALevel(RF24_PA_LOW);
    radio.setRetries(3,5); // delay, count
    radio.setChannel(110);
      radio.openReadingPipe(1,slaveAddress);
       radio.startListening();

}

unsigned long lastRecvTime = 0;

void receive_the_data()
{
  while ( radio.available() ) {
  radio.read(&data, sizeof(Rx_data));
  lastRecvTime = millis(); //Here we receive the data
  Serial.print("lr Value:  ");
Serial.println(data.lrValue);

Serial.print("fr Value:  ");
Serial.println(data.frValue);
Serial.print("fbutton Value:  ");
Serial.println(data.button);

}
}

void reset_the_Data() 
{
  // 'safe' values to use when NO radio input is detected
  data.lrValue =512;
  data.frValue =512;
  data.button=0;
}


void loop() {

if (radio.available()) receive_the_data();

//////////This small if will reset the data if signal is lost for 1 sec.
/////////////////////////////////////////////////////////////////////////
  unsigned long now = millis();
  if ( now - lastRecvTime > 1000 ) {
    // signal lost?
    reset_the_Data();

  } 
}

I hope I could explain the issue clearly. I hope someone can guide me in the right direction

I have never had any need to put an Arduino to sleep so I am not familiar with that business.

It does seem as if your ISR has huge delay()s in it. Timing needs interrupts to be enabled so it could be that you have created an endless loop. An ISR should be designed to complete in as few microseconds as possible. It may be sufficient to use the ISR to set a flag variable that can be acted on in loop() - where delays are technically OK.

...R

I had given the time delay to let RF module wakeup, forgot to remove it when i removed the sleep of rf module. I will remove it and check again.Thanks

Robin2:
It does seem as if your ISR has huge delay()s in it. Timing needs interrupts to be enabled so it could be that you have created an endless loop. An ISR should be designed to complete in as few microseconds as possible. It may be sufficient to use the ISR to set a flag variable that can be acted on in loop() - where delays are technically OK.

...R

I removed the delay, and it seems like it is working now, i will check for longer durations and check the performance. Thank you very much

EDIT: I just noticed a very silly thing in my code, I was trying to power off the radio after I had given command to my processor to go to sleep.
I corrected that and along with removing the delay change... it works fine now.

Thanks for the update

…R

Hi again,

So, I tested my RF remote for a few days, and what I have noticed is that, if it is kept unused for a day or two, when I pick it up again, whatever it sends is still received on the other side.

But when I leave it for longer duration and then try to use it again, it is unable to talk to the receiver. The atmega turns on, its SPI clock led starts blinking as it sends data to the RF module, but no data is received on the other side.

The data starts up again only when I restart the remote by taking out the batteries.

Now, I could have added a power ON OFF button so that I do not need to take out batteries to restart the RF remote, but the whole purpose of exploring this sleep feature was that I was trying to make it work for long durations with need to manually switch it OFF and ON.

This is the code for the transmitter, although I feel now it is about some sleep related detail of the controller or the NRF24 that I don’t know about.
If someone can point me in the right direction I would be very thankful.

// NRF remote control - the master or the transmitter
#include <RF24_config.h>
#include <printf.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include "LowPower.h"

#define CE_PIN   9
#define CSN_PIN 10


#define SLEEP_PIN 2
#define LEFT_RIGHT A0
#define FORWARD_REVERSE A1
#define BUTTON 3

bool buttonState = false;
const byte slaveAddress[5] = {'R','x','A','A','A'};
RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

struct Data_to_be_sent {
 uint16_t lrValue=512;
 uint16_t frValue=512;
 bool buttonState= false;
};

Data_to_be_sent  data;
//
void sleep() {

 if (digitalRead(SLEEP_PIN))
 {
   radio.powerUp();
 }
 else
 {
     radio.powerDown();
     LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
     
 }
}



void setup() {
   pinMode(SLEEP_PIN,INPUT_PULLUP);
   pinMode(BUTTON,INPUT_PULLUP);
   attachInterrupt(digitalPinToInterrupt(SLEEP_PIN), sleep, CHANGE);
   
   Serial.begin(115200);
   Serial.println("Tx Starting");
   radio.begin();
   radio.setAutoAck(1);
   radio.setDataRate( RF24_250KBPS );
   radio.setPALevel(RF24_PA_HIGH);
//    radio.setRetries(3,1); // delay, count
   radio.setChannel(110);
   radio.openWritingPipe(slaveAddress);
     radio.printDetails();

}


void loop() {
         data.lrValue = analogRead(LEFT_RIGHT);      
         data.frValue = analogRead(FORWARD_REVERSE);
         data.buttonState = digitalRead(BUTTON);
         radio.write(&data, sizeof(Data_to_be_sent));
         Serial.print("lr Value:  ");
         Serial.println(data.lrValue);
         Serial.print("fr Value:  ");
         Serial.println(data.frValue);     
           Serial.print("Button State:  ");
         Serial.println(data.buttonState);   
     delay(200);

}

Referring to Reply #5 ...

You are exploring territory that I know nothing about. Sorry.

A couple of things comes to mind ...

The nRF24 has a system where the Tx cycles through the numbers 0 to 4 with each transmission (but not with repeats) so that the Rx can tell if a received message is a repeat - which it then ignores. This has caught me out a few times (admittedly in very different circumstances) where I was sequentially sending messages to 4 receivers and if the data was the same it meant that the nRF24's "telltale" value was the same when the second round of messages arrived so the RX thought it was a repeat and ignored it. The solution is to make sure the data is a little different each time.

Maybe the internal buffers in the Tx or in the Rx nRF24 are full and would need to be cleared.

...R

Hi,
Thanks alot for the reply.

I do not think it would be the case here because my receiver is turned OFF normally. I connect power to it only when I use it. and the Tx is coming back frm sleep so I would expect its buffers are already empty.

Lets see if I can dig into the documentations and my hardware to see if I am doing something stupid (again?).

Thanks again for the reply and your guide for NRF24. I just noticed it yesterday that guide was written by you. It is great!

mohitsingh2806:
I do not think it would be the case here because my receiver is turned OFF normally. I connect power to it only when I use it. and the Tx is coming back frm sleep so I would expect its buffers are already empty.

I'm a bit confused.

Are you saying that you de-power the complete Arduino + nRF24 receiver when your Arduino + nRF24 transmitter is put to sleep?

I have been assuming the receiver is running all the time and it is only the Tx that goes to sleep.

It would do no harm to flush the Tx buffers.

...R

Robin2:
Are you saying that you de-power the complete Arduino + nRF24 receiver when your Arduino + nRF24 transmitter is put to sleep?

I have been assuming the receiver is running all the time and it is only the Tx that goes to sleep.

Yes, the Arduino+ RF Transmitter is put in sleep when not in use and the Arduino+RF receiver is powered off. I am sorry I was not clear about this.
My reason was that I wanted to mimic functionality of a normal remote control that we use for TV or similar instruments where we don't switch the remote control off manually.
But the device on the receiver end may be switched off. It may be a toy car or some other device.
Also, for shorter durations of Transmitter remote being in sleep, when I power off the receiver and then power it ON again it works.. It doesn't work only when the transmitter has been in sleep for too long. So I feel it may not be related to the receiver.

Robin2:
It would do no harm to flush the Tx buffers.

I will try that and get back after testing for a few days. Thanks

EDIT: Just an update that after flushing the Tx buffers before going to sleep and reinitializing the radio after it comes back from sleep, it is working fine.