nRF24L01 - Network problem.

I have a strange “Network Discovery” problem.

Context:

Libray: RF24 by TMRh0
Arduino: Nano model
Problem:  slave nodes don't always respond
Hardware: working, the pingpair_dyn example run 
Setup:
    radio.setPALevel(RF24_PA_MAX);
    radio.setDataRate(RF24_1MBPS);
    radio.setChannel(0x66);
    radio.setRetries(10, 10);
    radio.setAutoAck(true);

Status:

Node Agent - v0.1.0
Node Id: 0x7 - 7

DynamicPayloads: DISABLE
STATUS		 = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1	 = 0xa4a3a2a107 0xc2c2c2c2c2
RX_ADDR_P2-5	 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR		 = 0xa4a3a2a159
RX_PW_P0-6	 = 0x20 0x00 0x00 0x00 0x00 0x00
EN_AA		 = 0x3f
EN_RXADDR	 = 0x03
RF_CH		 = 0x66
RF_SETUP	 = 0x07
CONFIG		 = 0x0f
DYNPD/FEATURE	 = 0x00 0x00
Data Rate	 = 1MBPS
Model		 = nRF24L01+
CRC Length	 = 16 bits
PA Power	 = PA_MAX

My network have 3 node:

Node 1 with id 0x07 == 7    & address RX_ADDR_P0 == 0xa4a3a2a107
Node 2 with id 0x37 == 55	& address RX_ADDR_P0 == 0xa4a3a2a137
Node 3 with id 0x47 == 66	& address RX_ADDR_P0 == 0xa4a3a2a147

Only Pipe 0 is used.

Node 2 & 3 are always are listening, they never transmit, send only automatic ACK.

Node 1, on user prompt via button, run a discovery sending a simply payload (5 bytes)

for (i=from; i<to; i++) {
    address[0] = i;
    radio.openWritingPipe(address);
    result = radio.write(&TxFrame, TxLen);
    if (result) {
        Serial.print("Node ");
        Serial.print(i);
        Serial.println(" - LIVE");
        count++;
    }
}

Node 1 always receives ACK from the others 2 nodes when discovery range is [50, 80]

Discovery From node: 50 - To node: 80
Node 55 - LIVE
Node 66 - LIVE
Nodes found: 2

Node 2 & 3 on serial terminal correctly show:

RxFrame len: 5
RX frame: 0x6162636400

Now, I have a problem with smaller discovery range as [50, 70].

Node 1 still receives ACK

Discovery From node: 50 - To node: 70
Node 55 - LIVE
Node 66 - LIVE
Nodes found: 2

BUT, now, Node 2 & 3 on serial terminal do not display anything !!!
This is the problem :frowning:

Source code attached.

nodeAgent.ino (3.4 KB)

Are you satisfied that all of the nRF24s work properly on a one-to-one basis without the Network library?

If not, I would check that first.

...R

Hi robin2,
i don’t use RF24 network library but only RF24 base library.

My code is much simple.

a) Node 1 write a paylod with ACK
b) Node2’s nRF24 receive payload and send automatic ACK
c) Node 1 receive ACK => TX is ok
d) Node2 read payload and print it on serial

This is all ok, but when i run discovery on range [50, 70] the slave node return ACK to Node-1 but don’t print payload on screen.

There is no performance problem.

I did a simple test

  1. Set serial rate to 115.200 bps
  2. Node 1 send 50.000 write to Node 2 & Node 3
  3. Node 2 & 3 send ACK and print to serial only ‘1’ char (for fast answer)
TxLen = 5;

for (i=0; i<50000; i++) {
    address[0] = 0x37;
    radio.openWritingPipe(address);
    result = radio.write(&TxFrame, TxLen);
    if (result) x37Live++;
    else x37Dead++;
        
    address[0] = 0x42;
    radio.openWritingPipe(address);
    result = radio.write(&TxFrame, TxLen);
    if (result) x42Live++;
    else x42Dead++;
}
while (radio.available()) {							
    len = 5;
    radio.read(&RxFrame, len);
    Serial.print('1'); 	
}

None TX is failure !!!

Test Start
Test End
Node x37 - LIVE: 50000
Node x37 - DEAD: 0

Node x42 - LIVE: 50000
Node x42 - DEAD: 0
Elapsed time: 256780 ms

snico_one:
Hi robin2,
i don't use RF24 network library but only RF24 base library.

That is even more confusing. Your title clearly says Network Problem.

If you are not trying to use the Network library then I suggest you try the examples in this Simple nRF24L01+ Tutorial.

Wireless problems can be very difficult to debug so get the wireless part working on its own before you start adding any other features.

The examples are as simple as I could make them and they have worked for other Forum members. If you get stuck it will be easier to help with code that I am familiar with. Start by getting the first example to work

...R

Robin2 thanks for the answers and your time.

I have already read and studied your excellent tutorial.

All your example (Ack, Payload, Master,. ..) run on my hardware without problem.

"Wireless problems can be very difficult to debug so get the wireless part working on its own before you start adding any other features."

Very fair, it are very difficult to solve.

My problem is similar to other user:

TX node always receiver ACK from RX node but (sometimes) it does not really receive data: radio.available() is false.

When the RX node is power-off, TX node don't receiver ACK correctly, therefore the ack functionality works well.

Therefore I believe the problem is limited to the function radio.available()

Do you know previous cases of this malfunction?

Can you please post the simplest possible pair of programs that demonstrates the problem and I will try to get time to test them myself.

...R

Robin2:
Can you please post the simplest possible pair of programs that demonstrates the problem and I will try to get time to test them myself.

...R

snico_one already posted the one and only program he has running on all three nodes and it is pretty short.

@snico_one: if you get the node id from EEPROM you can the same sketch without changes on all nodes.

Whandall:
snico_one already posted the one and only program he has running on all three nodes and it is pretty short.

I had assumed the one program was only one side of the conversation.

I’m a bear with a small brain so it seems to me easier to have different programs rather than one program trying to adopt different roles at the correct times.

…R

Robin2, I attach another version, very small.

The code is the same for any node: 7, 55 and 66.

Node 7 è TX, node 55 & 66 are RX.

All node open RX_ADDR_P1 with private address.

Ack is enable.

Nodes RX print “RX Frame” string only for fast send to terminal serial (19.200 bps)

See image Test_F40_T90.jpg for Test OK and Test_F50_T70 for test KO.

I forgot.

Discovery start (for node 7) is active on button (pull-up) on D2 pin.
Button is present on board Node 7 only …

nodeAgent.ino (3.09 KB)

Whandall:
@snico_one: if you get the node id from EEPROM you can the same sketch without changes on all nodes.

Yes, EEPROM is best.

The attach code is only small part of program, the code is minimal for debug.

I already use eeprom for stored node Id, network configuration and other.

At the first run the code verify configuration-id byte in eeprom for validate the configuration and run configuration network menu for invalid node-id.

Images from Reply #8 so we don't have to download them. See this Simple Image Guide

For short progams it is much easier for us if you just include the code in your Reply. See How to use the Forum

...R

As you can see the images are impossible to read. Please don't post pictures of text, just copy and paste the text.

The output does not look like the Arduino IDE - what is producing it?

I don't have any more time now. I will try to look at the program tomorrow.

...R

Robin2:
Images from Reply #8 so we don’t have to download them. See this Simple Image Guide

For short progams it is much easier for us if you just include the code in your Reply. See How to use the Forum

…R

OK

I’ve had a chance to look at the code in Reply #8. This is it

// ----------------------------------------------
// NodeAgent
// ----------------------------------------------

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

// push button for start manual discovery, pull-up, active LOW
#define		PIN_MENU    2							

RF24 radio(7, 8);

byte RxFrame[26];
byte TxFrame[] = "abcdefghijklmnopqrstuvwyxz";						// prefix TX buffer

const byte addNode0[5] = {0x07, 0xA1, 0xA2, 0xA3, 0xA4 };			// address for 0x07 node
const byte addNode1[5] = {0x37, 0xA1, 0xA2, 0xA3, 0xA4 };			// address for 0x37 node
const byte addNode2[5] = {0x42, 0xA1, 0xA2, 0xA3, 0xA4 };			// address for 0x42 node


// 0x07 Node todo Discovery
// 0x37 Node always in Listening
// 0x42 Node always in Listening
byte nodeId = 0x07;      						// SET THIS VARIABLE FOR NODE 0x07, 0x37, 0x42

void NetDiscovery(void);

// ---------------------------------------------
// SETUP ROUTINE
// ---------------------------------------------
void setup() {

	pinMode(PIN_MENU, INPUT_PULLUP);        		
    printf_begin();
	Serial.begin(19200);

	// Display node ID
  	Serial.print("Node Id: 0x");
  	Serial.print(nodeId, HEX);
  	Serial.print(" - ");
  	Serial.println(nodeId);
    Serial.println(); 	

	// Active Radio	
  	radio.begin();
  	radio.setPALevel(RF24_PA_MAX);
    radio.setDataRate(RF24_1MBPS);
	radio.setChannel(0x66);
    radio.setRetries(10, 10);
	radio.setAutoAck(true);

	// ALL nodes to open PIPE 1 on private address
	switch (nodeId) {
		case 0x07:
	  		radio.openReadingPipe(1, addNode0);				
	  		break;
		case 0x37:
	  		radio.openReadingPipe(1, addNode1);				
	  		break;
		case 0x42:
	  		radio.openReadingPipe(1, addNode2);				
	  		break;
	  		
  	} 
  	
  	// ALL note at start are in Listing
    radio.startListening();
 
  	radio.printDetails();
    Serial.println(); 	
}



// ---------------------------------------------
// LOOP ROUTINE
// ---------------------------------------------
void loop() {

	// For ALL node in listing
	while (radio.available()) {							
    	radio.read(&RxFrame, 5);					// Prefix size len
        Serial.println("RxFrame");
    }
	
	// Only node 0x07 goto in TX 
	if (nodeId == 0x07) {
		if (digitalRead(PIN_MENU) == LOW) {			// Check activation Discovery
	  		radio.stopListening(); 									
			NetDiscovery();
	    	radio.startListening();
		}
	}
}


// ---------------------------------------------
// DISCOVERY ROUTINE
// ---------------------------------------------
void NetDiscovery() {
bool result;
byte address[5];
byte from;
byte to;
byte i;

	address[1] = 0xA1;
	address[2] = 0xA2;
	address[3] = 0xA3;
	address[4] = 0xA4;

// OK	from=40  & to=90   
// KO 	from=50  & to=70

	from = 50;
	to = 70;

    Serial.print("Discovery From: ");
    Serial.print(from);
    Serial.print(" - To: ");
    Serial.println(to);
    

   	for (i=from; i<to; i++) {
	    address[0] = i;									// complete TX address
   		radio.openWritingPipe(address);
		result = radio.write(&TxFrame, 5);				// Prefix len size to 5
	    if (result) {
        	Serial.print("Node ");
        	Serial.print(i);
        	Serial.println(" - LIVE");
    	}
	}

    Serial.println("Discovery END");
    Serial.println();

}

It seems to me horribly complex. For example, why are the addresses at top of the program different from the addresses in the NetDiscovery() function.

And why have you big long Rx and TxFrames when you don’t use the length. Until you get things working keep everything as simple as possible.

Try adding a delay (maybe delay(2000) to start with so that things happen at a pace that a human can observe) in the FOR loop in the NetDiscovery() function.

And start with only one node (i.e. a pair of nRF24s).

…R

Robin2:
For example, why are the addresses at top of the program different from the addresses in the NetDiscovery() function.

They are not.

At the top are the three used full addresses, in the function the address is constructed/enumerated.
I would have used a getAddress(byte select) function that returns a pointer to a static constructed address...

@snico_one are you shure that there are no other nodes around that could use the same addresses?

You could switch to a different channel to test for such a collision.

On the first screenshot the configuration of the left hand node shows that you did not power cycle
the module between configuration changes (pipe 0 -> pipe 1).
Remember that the NRF keeps its register content regardless of any AVR resets,
only a power cycle brings it back to the reset state that the library is expecting on begin.

Whandall:
I would have used a getAddress(byte select) function that returns a pointer to a static constructed address...

That was the sort of thing I had in mind - referring to the same address variable would make the code a lot easier to follow.

...R

Hi Robin2 & Whandall

The code previously attached is not the real code of the project; it was created to reproduce the problem I have in the real code.

The final project is a home network of sensors (NodeAgent with Arduino Nano) coordinates from a node Manager (now it is another Ardunio Nano, tomorrow will be a Raspberry PI).

To extend the range of action between Manager and Agent, each Agent has a simple router function.

Therefore an Agent can be the node router of another Agent.

In Figure Node A3 is the “router node” for the nodes A1 & A2, and so on.

Each node has its own identifier (1 byte) and share the “network address” (4 byte) with the other nodes.

The node’s identifier plus the “network address” form the “node address”.

Each node is listening on its own address through the pipe 1.

The node when it receives a message verifies who the recipient is, if it is not the recipient, it forwards the message to his node router.

The messages are always between Agent <–> Manager, never between Agent <–> Agent.

The FOR cycle is used by each node in the initial phase to discover the existence of any nearby nodes and then determine the router node.

The problem is inside FOR cycle but RX side, RX-NRF24 send ACK but don’t set the availability of the payload.

Nothing in Reply #17 convinces me to change what I said in Reply #13.

When you run into a problem make the exploration code as simple and obvious as possible.

...R

Robin2:
When you run into a problem make the exploration code as simple and obvious as possible.

…R

I totally agree with you. This was always my intent.