nrf24+ slow after wake up

Hi !

I'm facing a strange issue with Sparkfun nrf24+ modules.

When I wake up the system from sleep the RF module is working very very slowly to send data, on data received it operate at normal speed.

It works well with 2$ Chinese module.....

This is how I setup the RF module :

void setupRF24() {
 delay(1000);
 radio.begin();
 radio.setDataRate(RF24_250KBPS);
 radio.setPALevel(RF24_PA_MAX);
 radio.setChannel(125);
 radio.openReadingPipe(1, thisButtonAddress);
 radio.enableAckPayload();
 radio.setRetries(5, 15); // delay, count
 radio.startListening();
 radio.openWritingPipe(masterAddress);
}

To save the maximum power I turn off the power pin while sleeping :

void sleepNow() {  // here we put the arduino to sleep   

 digitalWrite(RF_POWER_PIN, LOW); // turn off RF module
 led.state = LED_OFF; //Set LED to OFF state

 attachInterrupt(2, wakeUpNow, CHANGE); // use interrupt

 power_timer0_disable();
 power_timer1_disable();
 power_spi_disable();

 set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here

 sleep_enable();          // enables the sleep bit in the mcucr register
 sleep_mode();            // here the device is actually put to sleep!!
 // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
 sleep_disable();         // first thing after waking from sleep:
 // disable sleep...
 detachInterrupt(2);      // disables interrupt 
}

then, on wake up code I turn on power pin back on and call the RF setup code again :

if (wakeUP) {
 lastActionMillis = millis();

 digitalWrite(RF_POWER_PIN, HIGH); // turn off RF module
 setupRF24();

 led.state = LED_BLINK;
 led.blinkCount = 3;

 wakeUP = false;
 }

I've also tried not to fully turn off the module but to just use radio.powerDown(); and radio.powerUp(); sadly it behave the same.

What's even stranger is that it's not reproducible, it doesn't happen every time.
Sometimes I can put the device to sleep 20 times and it works well, I reset the device, put it in sleep once and it become slow, then it stay slow even if I put it again in sleep.

I've tried to change the Lib and tried another module it behave the same.

Any idea what's wrong ?


Thanks for your support solving this issue

I use this lib: http://tmrh20.github.io/RF24/

The board is an Adafruit ItsyBitsy 32u4 8Mhz

No difference if I power the module from battery or USB, 3.3V or 5V

Alkerion:
It works well with 2$ Chinese module.....

I have only ever used the cheap modules.

What is different about the Sparkfun modules? Have you asked Sparkfun for an explanation?

What exactly does this mean "is working very very slowly to send data". I can't envisage an nRF24 being able to send data at anything other than the speed specified by setDataRate()

...R
Simple nRF24L01+ Tutorial

The SF module doesn't have the same pin out, their modules are in my case very practical as the pin out is 95% in line with the Itsybitsy pin out, so no wiring required.

They also have an embed voltage regulator.

The Chinese modules works perfect with my code, but their pin out in two rows is just a nightmare to fix on the circuit.

By slow I mean that the transmission speed is slow, the delay between the button is pressed on module A and the reception on Module B is huge.

What I've remarked it that after >12s the SF module Tx is not working anymore, and he change the transmission speed.

Start the module
Mashed !
speed: 2
Acknowledge but no data
Mashed !
speed:2
Acknowledge but no data
Mashed !
speed:2
Acknowledge but no data

Wait >12s

Mashed !
speed:2
Tx failed
Mashed !
speed:1
Tx failed

If I use higher voltage 4V instead of 3.6V and add a 47uF cap it solve the issue of the module not working after 12s.

But it still sometime (that's not reproducible 100%) went slow after wake up.....

Alkerion:
The SF module doesn't have the same pin out, their modules are in my case very practical as the pin out is 95% in line with the Itsybitsy pin out, so no wiring required.

They also have an embed voltage regulator.

When I asked what was different I was not referring to the pin layout - that won't affect anything.

You need to check with Sparkfun as to what is the minimum voltage that is acceptable for the embedded voltage regulator - it is probably intended for 5v.

...R

Regarding the voltage SF say it's ok between 3.3V and 7V

https://learn.sparkfun.com/tutorials/nrf24l01-transceiver-hookup-guide#hardware-overview

At 3.6V the settings aren't keep and the module crash.
Only at 4V with cap I can avoid settings change after a few sec.

I've already asked SF about this issue but I still haven't received any answer...

I'm new to the wireless stuff, and in fact Arduinos, too, but where are you getting the 3.6V from, and where are you getting the 4V from? Your 3.6V is measured by what? If the nrf runs at 3,3V, and the onboard voltage regulator is out of tolerance, your 3.6V may not be sufficient. Try a couple of fresh AA batteries in series. My cheap chinese nrfs work fine on that, with a 10uF electrolytic cap near its supply pins. I've not noticed any delays. A bigger cap, would most likely take longer to get working, since on initial switch on, it would act more or less as a short circuit, until charged up. afaik, the nrf transmit takes a significant current pulse. A weak 3.6V couldl be inadequate, as you've found out.

Thanks both for your help.

@Raymw, I think you're right, power voltage and quality seems to be much more important on the SF module than the Chinese version.

I measured again the voltage and it's closer to 3.3V than 3.6V.

Until now I've used A3 pin as power output for the RF module (I set the pin to low on sleep to save max power), but no I use the Vhi pin that deliver 4V even when powered by Li battery, and powerDown() and powerUp() functions.

I'll try with a 10uF cap to see if it still works, I've a delay of 1000 on setup(), the cap should have enough time to load.

Now if the crash after 12s is "solved" (SF module is supposed to work at 3.3V without cap but crash at 4V....), I still have the issue that sometimes happens on wake up.

Any suggestion how to identify the issue as there is no more USB serial after sleep ?

And it's only the sending which is slow, data receiving if performing well.

RF values when everything works as expected :

STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1 = 0x3030565253 0x32304e5442
RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR = 0x3030565253
RX_PW_P0-6 = 0x20 0x20 0x00 0x00 0x00 0x00
EN_AA = 0x3f
EN_RXADDR = 0x02
RF_CH = 0x7d
RF_SETUP = 0x27
CONFIG = 0x0f
DYNPD/FEATURE = 0x03 0x06
Data Rate = 250KBPS
Model = nRF24L01+
CRC Length = 16 bits
PA Power = PA_MAX

Here is a video showing how the system behave :

The datasheet for the voltage regulator says "very low dropout voltage (typically 17 mV at light loads and 165 mV at 150 mA),". I would expect the nRF24 to be at the upper end of that range when it is transmitting.

It is an adjustable voltage regulator so it would be interesting to know what the output voltage is when the input is (say) 5v - i.e. well above the dropout range.

If its output voltage is set to 3.3v than I would expect the minimum input voltage to be about 3.5v. And the output voltage would be within the spec for the nRF24 all the way up to 3.6v.

...R

I’ve tried my code on a ProMicro 16Mhz → Same behavior

So the issue is not linked to the ItsyBitsy.

I’ve doubled checked with the Chinese RF module, and I’ve to admit that it is also slower, not as much, but still slower.

If I press very quickly on the button after the wake up the speed is OK, it’s only after a little time that the system is slow.

At the end I think there is something wrong with my wake up logic.

Here is the whole code, perhaps someone will find my mistake :

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <ctype.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <Bounce2.h>
#include <LowPower.h>

#define BUTTON_PIN 0
#define LED_PIN 1
#define CE_PIN A4
#define CSN_PIN A5
#define LOW_POWER_MODE_PIN 8

#define BLINK_INTERVAL 1000  
#define SLEEP_DELAY 480000

//LED states
#define LED_OFF 0
#define LED_ON 1
#define LED_BLINK 2

//LED blink speed
#define LED_SLOW 1000

//LED Brightness
#define LED_MAX_BRIGHTNESS 255
#define LED_MED_BRIGHTNESS 150
#define LED_MIN_BRIGHTNESS 50

//**************************************************************************************

float version = 2.06;

//**************************************************************************************


//RF24
const uint8_t masterAddress[6] = "SRV00";
uint8_t thisButtonAddress[6];

const uint8_t DIPSwitchPins[] = { 7, 9, 10, 11 };

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

volatile int ledState = LOW;

volatile bool do_blinkLed = false;

volatile bool wakeUP = false;

//volatile bool turnedON = true;

long previousMillis = 0;

long lastActionMillis = 0;

Bounce debouncer = Bounce();

int RcvCnt = 0;

int buttonNumber = 0;

//Struct for LED
struct LED {
	byte state;
	int blinkSpeed;
	int blinkCount;
	int brightness;
	unsigned long lastStateChange;
};

//Struct for data to send
typedef struct {
	uint8_t rnd;
	uint8_t type;
	uint8_t msg;
}
A_t;

//Struct for data received
typedef struct {
	uint8_t rnd;
	uint8_t type;
	uint8_t msg;
}
B_t;

A_t Data_Sent;
B_t Data_Received;

struct LED led = { LED_BLINK, LED_FAST, 3, 0, 0 };

//****************************************

void setup() {

	Serial.begin(9600);

	pinMode(LED_PIN, OUTPUT); //Led pin

	pinMode(13, OUTPUT);// onboard LED
	digitalWrite(13, LOW);

	pinMode(LOW_POWER_MODE_PIN, INPUT_PULLUP); //Low power mode pin

	getButtonNr();

	delay(500);

	radio.begin();

	delay(500);// Give RF module some time to run.

	setupRF24();

	debouncer.attach(BUTTON_PIN, INPUT_PULLUP);
	debouncer.interval(5); // interval in ms

	// No power save if Button is pressed or if Jumper is present
	if (digitalRead(BUTTON_PIN) ? 1 : 0 || digitalRead(LOW_POWER_MODE_PIN) ? 0 : 1) {
		digitalWrite(13, HIGH);//turn ON on board led to indicate that we are well connected to USB
	}
	else {
		//save power
		ADCSRA = 0;
		power_adc_disable();
		power_twi_disable();
		power_usart0_disable();
		power_usart1_disable();
		power_timer2_disable();
		power_timer3_disable();
		// disable the USB
		USBCON |= _BV(FRZCLK);  //freeze USB clock
		PLLCSR &= ~_BV(PLLE);   // turn off USB PLL
		USBCON &= ~_BV(USBE);   // disable USB
		power_usb_disable();
	}
}

//****************************************

void loop() {

	if (wakeUP) {

		radio.powerUp();

		delay(500);

		pinMode(BUTTON_PIN, INPUT_PULLUP);

		led.state = LED_BLINK;
		led.blinkCount = 3;

		wakeUP = false;

		lastActionMillis = millis();

	}

	do {

		LED();

		debouncer.update();		// Update the Bounce instance

		// Wait for button being pressed
		if (debouncer.read() == HIGH) {
			if (millis() - lastActionMillis > 200) {
				if (led.state == LED_OFF || !LED_BLINK) {
					sendToMaster(buttonNumber);
				}
			}

			lastActionMillis = millis();
		}

		//Go to sleep if no actions for some times
		if (millis() - lastActionMillis > SLEEP_DELAY) {
			sleepNow();	//Time to go to  sleep to save some power, wake up when button pressed
		}

	} while (!radio.available());

	radio.read(&Data_Received, sizeof(Data_Received));

	int order = Data_Received.msg;

	switch (Data_Received.msg) {

	case 0://test

		break;

	case 10://Make the led blinking
		led.state = LED_BLINK;
		led.blinkCount = 65000;
		led.brightness = 0;
		break;

	case 11://Turn light on
		led.state = LED_ON;
		break;

	case 12://Turn light off
		led.state = LED_OFF;
		break;

	case 55://Force to go to sleep
		sleepNow();
		break;

	case 66://Reset button
		led.state = LED_OFF;
		led.blinkCount = 0;
		break;
		break;

	case 99://Answer Hello I'm alive
		break;

	}

	lastActionMillis = millis();

}

//****************************************

void setupRF24() {
	radio.setDataRate(RF24_250KBPS);
	radio.setPALevel(RF24_PA_MAX);
	radio.setChannel(125);
	radio.openReadingPipe(1, thisButtonAddress);
	radio.enableAckPayload();
	radio.setRetries(5, 15); // delay, count
	radio.startListening();
	radio.openWritingPipe(masterAddress);
}
//****************************************

void sendToMaster(int cmd) {

	if (Data_Sent.rnd == 0) {
		srandom(random() ^ ((uint32_t)analogRead(4) << 22) ^ micros());
		Data_Sent.rnd = random(0, 5000);
	}
	else {
		Data_Sent.rnd++;
	}

	Data_Sent.msg = cmd;

	radio.stopListening();

	delay(10);

	radio.write(&Data_Sent, sizeof(Data_Sent));

	radio.startListening();
	
}

//****************************************

void blinkLED() {
	unsigned long currentMillis = millis();

	if (currentMillis - previousMillis > BLINK_INTERVAL) {

		// save the last time you blinked the LED

		previousMillis = currentMillis;

		// set the LED with the ledState of the variable:
		digitalWrite(LED_PIN, ledState);

		ledState = !ledState;
	}
}


//****************************************

void blinkLED(int d) {
	digitalWrite(LED_PIN, HIGH);
	delay(d);
	digitalWrite(LED_PIN, LOW);
}

//****************************************

void blinkLED(int d, int t) {
	for (int i = 0; i < t; i++) {
		blinkLED(d);
		delay(d);
	}
}

//****************************************

//Read the button number from the DIP switch
void getButtonNr() {

	for (int i = 0; i < sizeof(DIPSwitchPins); ++i) {
		// Setup pin
		pinMode(DIPSwitchPins[i], INPUT_PULLUP);

		uint8_t curState = digitalRead(DIPSwitchPins[i]) ? 0 : 1;
		buttonNumber += (curState << i);
	}

	snprintf(thisButtonAddress, 6, "BTN%02d", buttonNumber);
}

//****************************************

void LED() {

	unsigned long date = millis();
	int valeurPWM;

	switch (led.state) {

	case LED_OFF:
		analogWrite(LED_PIN, 0);
		break;

	case LED_ON:
		analogWrite(LED_PIN, LED_MAX_BRIGHTNESS);
		break;

	case LED_BLINK:
		if (date - led.lastStateChange >= led.blinkSpeed) {
			led.lastStateChange = date;

			switch (led.brightness) {
			case 0:
				led.brightness = 250;
				break;
			case 250:
				led.brightness = 0;
				led.blinkCount--;
				break;
			}
			analogWrite(LED_PIN, led.brightness);

			if (led.blinkCount == 0)
				led.state = LED_OFF;
		}

		break;

	}
}

//****************************************

void wakeUpNow() {
	power_timer0_enable();
	power_timer1_enable();
	power_spi_enable();
	wakeUP = true;
}

//****************************************

void sleepNow() {  

	radio.powerDown();

	blinkLED(300, 2);

	led.state = LED_OFF;

	attachInterrupt(2, wakeUpNow, CHANGE);

	power_timer0_disable();
	power_timer1_disable();
	power_spi_disable();

	set_sleep_mode(SLEEP_MODE_PWR_DOWN);

	sleep_enable();


	sleep_mode();

	sleep_disable();
							
	detachInterrupt(2);

}

Thanks

Alkerion:
Here is the whole code, perhaps someone will find my mistake :

All the real wake up code seems to be in some library. Have you studied the library code?

Have you considered writing a short program that does radio.powerDown() waits for 10 seconds and does a powerUp() and sends a message - no library other than for the nRF24.

If the problem shows up in that I would suspect an nRF24 problem. If not I would looking for the problem somewhere else. For example, when your system goes to sleep does it cut off power to the nRF24? If it does, when is it restored?

...R

I've not looked at the library.

As long as I don't go to sleep there is no Tx speed issues.

as a dirty workaround I've implemented a software reset function with a watchdog, I call this function on wake up.

This way there is no more RF speed issues.

void software_Reboot() {
	wdt_enable(WDTO_15MS);

	while (1) 	{ }
}

But I hope that I'll be able to find an explanation and a real solution to fix this issue.