nRF24 - One RX and three TX modules

Robin2:
I'll think some more about this.

May I ask why the Mega is not the "central" unit with the handheld unit another slave - like this

  1. Then the Mega will be the main unit. It will send LCD data to Remote. It will query the other two slaves when it wants their data. Sounds good.

  2. But for that the Remote and two slaves must be in listening mode. I am afraid this will consume more power. No problem for Remote as it has a large 2000mAh cell. But the other two slaves are tiny ones with a 800mAh cell.

  3. Of course this setup also means that the main sends and get data to slaves directly without being routed.

Will think and come back based on your response to above..

thanks

Mogaraghu:
2. But for that the Remote and two slaves must be in listening mode. I am afraid this will consume more power. No problem for Remote as it has a large 2000mAh cell. But the other two slaves are tiny ones with a 800mAh cell.

The slaves don't have to be listening. The Mega (master) must be listening all most of the time. The remote could poll the Mega regularly to get an update for its data - that way it does not have to be listening all the time if you don't want that.

if the slaves are each deciding when to transmit you will need to design your system so that it can deal with the inevitable data collisions, and also design it so as to minimize the likelihood of a collision. I think that requires short messages at long intervals with few if any automatic retries. If the slave does not get an ack immediately it should wait several millisecs before retrying. You could arrange for the wait intervals to be different for each slave so they were unlikely to retry at the same instant. If you then have a fixed interval between TX messages a single collision and its retry should position subsequent messages at a point where they are unlikely to collide next time around. Of course it is a bit harder to avoid collisions if each slave needs a different Tx interval. But some thought should guide you to the most suitable intervals.

...R

Ok elaborating on what you suggested. ( All communication by Call Response method only )

The RFID Slave 04 is the easiest. Its a RFID tag scanner ... I can power it up only when required. The Mega master is needing the tag info... so it says so on the display and listens on the RFID's address. The RFID slave sends the RFID data and once the Mega has read it, it closes the RFID slave pipe.

Similarly the Slave 03 is a pulse reader. But not as easy as the RFID Slave. This pulse reader needs Plan value ( 6 bytes ) and a Reset Boolean. So it sends whatever pulse count is there on it and the Mega in turn sends the Reset Boolean. The Slave 03 resets its count and starts counting. Once a match happens it Sends the actual count and the Match Boolean. The Mega decides what to do with that and then closes that pipe. Of course the count progression also has to be updated atleast once a second.

When both above pipes are closed I open the Remote pipe. That I guess I will leave as is now since the Mega LCD data is nicely replicated on it.

What this means I keep only one pipe open at any instant and I am sure that will work for sure.

Does it make sense as above ??

I do wish you would put the entire concept of pipes out of your mind. They are just causing endless confusion.

Stick to thinking about sending messages. Think of it as a group of friends doing a cooperative job and shouting messages to each other when needed. If two of them talk at the same time nobody can make sense of the message - they just hear noise. While the friends are cooperative, pretend they are each behind a screen that allows them to hear the others, but not to get any visual clues.

The first requirement is to devise a scheme for the flow and management of the data. That does not require any computer programming knowledge.

Leave the programming details for a later stage.

...R

No issues. Unfortunately to explain all that I think will need too much writing ( and bore you ) and so when doing it briefly looks like there is a confusion. The concept of pipes and addresses are clear. ( The confusion initially starts when comparing with a IP address in which you send the data to the receiver address. In RF24 you post the data with your own address and tell the receiver to look for this address )

As we are discussing this back and forth some concepts are evolving. But before that just look at the Power Consumption chart - I think I have been unnecessarily concerned about higher power consumption in Rx mode. It does not seem to be so - its just marginally higher by about 3-4 mA when compared to the full power Tx mode. And once the job is done and they are waiting in Standby the consumption drops to uA levels. I hope my understanding is clear.
Rf24_Pwr.PNG

This gives lots of freedom to design. The Mega master can now sequentially call up each slave, send / request for data - maybe even once every 100ms. And if the Slave is off grid when it has no new data the master times out and moves on. Let me come back with a concrete structure on this line.

Mogaraghu:
In RF24 you post the data with your own address and tell the receiver to look for this address

No.

Each receiver can listen to up to 6 (functional) addresses, there is nothing like a MAC address.
For each functional address at most one receiver may acknowledge.

Whandall:
No.

Each receiver can listen to up to 6 (functional) addresses, there is nothing like a MAC address.
For each functional address at most one receiver may acknowledge.

Of course there is no MAC here !!

Lets say that in this context Tom is the Transmitter and Rex is the receiver.

Rex is listening and will respond to a packet that has address of Tom on it .

Correct ?

Mogaraghu:
Lets say that in this context Tom is the Transmitter and Rex is the receiver.

Rex is listening and will respond to a packet that has address of Tom on it .

Rex could listen to and could acknowledge up to 6 addresses that somebody (even Tom) could use.

Nobody has an address.

Whandall:
Rex could listen to and could acknowledge up to 6 addresses that somebody (even Tom) could use.

Nobody has an address.

I have one of your posts as reference to clarify when in doubt. I was trying to the say that - but maybe in different words.

Mogaraghu:
No issues. Unfortunately to explain all that I think will need too much writing ( and bore you ) and so when doing it briefly looks like there is a confusion. The concept of pipes and addresses are clear.

I give up.

I'm sure I could get this working very quickly if I knew what was required.

...R

Robin2:
I give up.

I'm sure I could get this working very quickly if I knew what was required.

...R

Its OK ... I do understand the situation. My post #19 has all details anyway.

The challenge right now is to use RF24 to fully duplicate the 4L x 20C LCD of the Mega master on to the Remote which in turn has to grab all the data from Pulse Counter units and RFID units and pass it down to the Mega Master. And due to physical locations it has to be like this only. The Operator + Remote + RFID + Pulse counter are at a distance of 20 to 40 M away from the Mega Master.

Anyway I am right now working in methods to reduce the amount of data transfer to duplicate the LCD. Just check for changes and send only the changes retaining the lines that have not changed.

One last attempt. Think about it like this (M = mega, H = handheld, s = slaves)

M is listening
    s1 sends 5 bytes
    M receives 5 bytes
        M displays data
    
    s2 sends 15 bytes
    M receives 15 bytes
        M displays data
    
    H sends 2 bytes (token message just to prompt a reply)
    M receives 2 bytes
M stops listening briefly
    M sends 5 + 15 bytes to H
M is listening
repeat

Very simple

...R

Thanks. That gives some food for thought. The one condition( due to physical location ) that M cannot directly communicate with Slaves 03 and 04 needs to honoured. This is where the Handheld comes in and relays all communication between these two slaves and Mega.

So I am now working on final version based on our discussions. The only issue seems to be the duplication of the LCD display of the Mega master .. its working now but just wondering if it can be improved. I am just reproducing the send and receive segments for this - with the 32byte clamp I am unable to think of anything better...

The send part from Mega master : ( the rfCommWithRemUnit() is called by loop() once every 500mS)

// FUNCTION TO PUSH ALL FOUR LINE LCD DATA TO REMOTE.

void rfCommWithRemUnit()                      // this function sends 80 bytes of data in 4 transmissions
{
  sendLcdInfo( firstLineMsg,  0);                // Each line is a global variable updated dynamically
  sendLcdInfo( secondLineMsg, 1);
  sendLcdInfo( thirdLineMsg,  2);
  sendLcdInfo( fourthLineMsg, 3);
}

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

// FUNCTION TO TRANSMIT ONE LINE OF LCD DISPLAY

void sendLcdInfo ( char lcdMsg[21], byte cursorRow)
{
  strcpy(txDataToRemUnit.lcdMessage, lcdMsg);
  txDataToRemUnit.cursorRow  = cursorRow;
  bool writeResult = (radio.write(&txDataToRemUnit, sizeof(txDataToRemUnit)));  // Send OneLine of LCD..
  if (writeResult)
  {
    if ( radio.isAckPayloadAvailable())
    {
      radio.read( &rxDataFromRemUnit, sizeof(rxDataFromRemUnit));
    
     }
   }
}

And this is the receiving part on the Remote unit to display the copy of Mega message:

if ( radio.available(&pipeRxd)) 
{
    switch (pipeRxd) 
   {
      case 1:                                                                    // MAIN UNIT RF DATA LINK
        radio.read( &dataFromMain, sizeof(dataFromMain)); // Get the Payload from MAIN Tx
        lcd.setCursor(0, dataFromMain.cursorRow);             // Send the message to LCD with Cursor info..
        sprintf(lcdMessage, "%s", dataFromMain.recdMsg);
        lcd.print(lcdMessage);

        // Prepare the ackDataToMain here ...

        radio.writeAckPayload(1, &ackDataToMain, sizeof(ackDataToMain));     
        break;
        
        // Other channels go here...

        default :
        break;
}

Mogaraghu:
Thanks. That gives some food for thought. The one condition( due to physical location ) that M cannot directly communicate with Slaves 03 and 04 needs to honoured. This is where the Handheld comes in and relays all communication between these two slaves and Mega.

Then write a version of my simple steps in the way that is needed BEFORE you think about any code.

...R

Following is the actual requirement. No real time projects are simple anyway. And I am almost there as the first full setup went on line yesterday. Refinements underway to avoid sending LCD data when its same. This saves so much of payload.

Just reproducing in your pseudocode so that its easy to follow the actual requirement...and to keep it simple I have shown only the data transfer and not what each unit does with the data.

M: Mega ; H : Handheld ; PS : Pulse Slave ; RS : RFID Slave

H is listening (always )
M sends LCD Line 1 [ 21 bytes]
M sends LCD Line 2 [ 21 bytes]
M sends LCD Line 3 [ 21 bytes]
M sends LCD Line 4 and Control data for PS and RS [ 27 bytes]
H sends PS and RS data as Ackpayload to M [ 8 bytes] ( dummy if no PS or RS data )
PS sends Pulse data to H [ 4 bytes] ( when pulse available )
H sends control data received from M as ackPayLoad to PS [ 5 bytes]
RS sends RFID data to H [ 4 bytes] ( when user scans RFID tag)
H sends control data received from M as ackPayLoad to RS [ 1 byte]
Loop.

And all three Tx units - M,PS and RS send at 500ms intervals. And in this also PS and RS send only when the process demands. Otherwise these units sleep. Its only the M that constantly updates H with LCD data and here also I am putting in logic to not send a line when data is same as previous.

You are still confusing your requirement with the way to implement it. Write your requirement while pretending you never heard of ackPayload - or any other of the capabilities of the nRF24.

If you look at my example in Reply #33 you will see that I wrote down the receiving as well as the transmitting for each message.

If you do that you will see that you have not considered which of the M messages the H would send the ackPayload in response to. Which is why it is premature to be considering the technical solution. Stay with the requirement until that is all firmed up.

And, I am still of the opinion (expressed in Reply #15) that ackPayload is not appropriate in this project.

...R

Ok for the time being the project needs focus on the main area and this RF stuff is a very small subsystem of it. Have been able to get it going as per the pseudo code I sent yesterday. That's gives time for more changes and optimization if any.

In the meanwhile you wrote ...

And, I am still of the opinion (expressed in Reply #15) that ackPayload is not appropriate in this project.

Why do you say that ? I thought ( and the examples say so ) that Call Response with Dynamic Payloads is a more efficient method than Listen - Get - Stop - Send - GoBack routine ??

Anyway the receiver sends a Acknowledgment and why not use it to send some payload also ?? I do feel its more simple and efficient to do so .. no ? :confused:

Mogaraghu:
Anyway the receiver sends a Acknowledgment and why not use it to send some payload also ?? I do feel its more simple and efficient to do so .. no ? :confused:

Shure, the payload is only an extension of the normal ack-transmission, but there are some drawbacks.

A collison while transmitting the ack-payload looses the payload (acks can be repeated, but the buffer is gone).

You can only use it on three addresses.

It can be hard to have the correct data waiting, you have no access to the internal buffers,
you only know whether zero or three packet are waiting, you can not check which.

You have to refill the ack-data each time you transmit something.

There are no builtin mechanisms in the library to help you with the above.

Whandall:
but there are some drawbacks.

Very nice summary.

It goes to the heart of why I have been trying to get the OP to focus on his requirement before considering the technical solution to implement it.

...R

Thanks to both of you ( @Robin and @ Whandall ) been able to get more clarity and the fine print. And after reading @Whandalls points on the AckPayLoad , it looks loaded with traps.

Now I understand why Robin was dissuading me from start on this.

Putting together all what you said, I have successfully coded a Tx and Rx unit to transact four lines of 21 byte data. Its working well. Now I can extend this to my project, where the Master will call for data from each slave when it requires. And no AckPayLoad used .

The Tx code :

/*
  06 Oct 2017 : RF24 Tx module code to request four lines of data from a slave.  Works well.. ProMini 3.3V
*/

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

/****************** User Config ***************************/
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7, 8 );                                   
/**********************************************************/

byte addresses[][6] = {"1Node", "3Node"} ;           //  Radio pipe address of this node and Rx node
byte rfOkLed = 3, pinSS = 10;

unsigned long rfTimeOut;
char recdMsg[21];


void setup()
{
  Serial.begin(9600);
  Serial.println(F("*** STARTING MASTER TX *** "));

  pinMode(rfOkLed, OUTPUT);
  pinMode(pinSS, OUTPUT);

  // Setup and configure radio
  radio.begin();
  radio.setChannel(108);                              // Above most Wifi Channels
  radio.setDataRate( RF24_250KBPS );
  radio.setPALevel(RF24_PA_MAX);
  
  radio.openWritingPipe(addresses[0]);                // Open a writing pipe on own address...
  radio.openReadingPipe(1, addresses[1]);             // and a reading pipe on Slave address

  digitalWrite(rfOkLed, HIGH);                        // To check LED wiring
  delay(2000);
  digitalWrite(rfOkLed, LOW);

}

//****************************************************
void loop(void)
{
  for ( byte count = 0; count < 4; count++ )
  {
    sendDataToMe(count); 
    delay(10);                                       // Is a delay required at all here ? 
  }
  Serial.println();                                  // Get a gap between set of data..
  delay(1000);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

// FUNCTION TO SEND A DUMMY VALUE TO REQUEST FOR RESPONSE FROM SALVE..

void sendDataToMe (byte count )
{
  //<<<<<<<<<<<<<< SEND DATA >>>>>>>>>>>>>>>>
  
  radio.stopListening();
  byte txPacket = count;
  if (radio.write( &txPacket, sizeof(txPacket)))
  {
    //Serial.println( txPacket);                       // Use for debugging
  }

  //<<<<<<<<<<<<<< GET DATA >>>>>>>>>>>>>>>>>
  
  radio.startListening();
  
  unsigned long started_waiting_at = millis();        // Wait here until we get a response, or timeout (250ms)
  bool timeout = false;
 
  while ( ! radio.available() && ! timeout )
  if (millis() - started_waiting_at > 250 ) timeout = true;

  if ( timeout )                                     // Explain what happened ...
    {
      Serial.println("Failed, response timed out.");
      digitalWrite(rfOkLed, LOW);
    }
  else
    {
      radio.read( &recdMsg, sizeof(recdMsg)) ;
      Serial.print(" Success ! " );
      Serial.println(recdMsg); 
      digitalWrite(rfOkLed, HIGH); 
    }
}

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

The Rx code :

/*

  06 Oct 2017 : Code to send 4 lines of data based on request from a master. Works ok. ( Pro Mini 3.3V)

*/


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

/****************** User Config ***************************/
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7, 8);
/**********************************************************/

byte addresses[][6] = {"1Node", "3Node"} ;           //  Radio pipe address of Tx node and this node
byte rfOkLed = 3, rfErrLed = 6, pinSS = 10;

byte rxData ;                                        // Data being recieved
char message[21] ;                                    // Data being sent back
unsigned long rfTimeOut;


//$$$$$$$$$$$$$$$$$$$$$$$$$$$$
void setup() {
  Serial.begin(9600);
  Serial.println(F("*** STARTING RECIEVER *** "));
  pinMode(pinSS, OUTPUT);
  SPI.begin();
  // Setup and configure radio
  radio.begin();
  radio.setChannel(108);
  radio.setDataRate( RF24_250KBPS );
  radio.setPALevel(RF24_PA_MAX);
  radio.setRetries(5, 10);
  radio.openWritingPipe(addresses[1]);                // Open a writing pipe on own address..
  radio.openReadingPipe(1, addresses[0]);             // and a reading pipe on Tx address
  radio.startListening();

  pinMode(rfOkLed, OUTPUT);
  digitalWrite(rfOkLed, HIGH);
  delay(2000);
  digitalWrite(rfOkLed, LOW);
}

//$$$$$$$$$$$$$$$$$$$$$$$$$$$$

void loop(void)
{
  uint8_t pipe_num;

  radio.startListening();                                // Now, resume listening so we catch the next packets.

  if ( radio.available(&pipe_num) )
  {
    radio.read( &rxData, sizeof(rxData)) ;
    Serial.print ("Got payload from TxUnit.... ");
    Serial.println( rxData);
    switch (rxData)
    {
      case 0:
        strcpy( message, "This is line One" );
        break;

      case 1:
        strcpy( message, "This is line Two" );
        break;

      case 2:
        strcpy( message, "This is line Three" );
        break;

      case 3:
        strcpy( message, "This is line Four" );
        break;

      default:
        break;
    }

    radio.stopListening();                               // First, stop listening so we can Send

    radio.write( &message, sizeof(message));
    rfTimeOut = millis();
  }

  if ( millis() - rfTimeOut > 5000 )                      // Declare the status to user
  {
    digitalWrite(rfOkLed, LOW);
  }
  else
  {
    digitalWrite(rfOkLed, HIGH);
  }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%