RF24 module and MFRC522 RFID reader : SPI bus contention ?

I have a small code to read a RFID tag and send the tag data alone to another unit via nRF24L01 module. The setup works as expected but with a problem ... the radio.write(const void *buf, uint8_t len) function never returns TRUE even though it does send the RFID tag info to the receiver. COnsequently i am not able to reset the RFID tag information - if this Bool returns true, then i read the AckPayload and using the information in it can reset the RFID tag. Also I use this to light up a RF_OK led

I notice that the function returns TRUE if i remove the MFRC522 from circuit and the RF-OK led remains lit as long as the communication is alive.

( I am making sure that the RFID functionality is blocked when RF24 comm is active. But that does not help )

So what else could be the issue ??

#include <SPI.h>
#include <RF24.h>
#include <nRF24L01.h>
#include <MFRC522.h>
/****************** User Config ***************************/
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7,8 */
RF24 radio(7, 8);
/**********************************************************/
/* RFID interface configuration apart from SPI bus */
#define RfidRst    9                                           // RFID reset pin
#define RfidSel    10                                          // RFID select pin
/*********************************************************/
byte rf_Address[6] = {"3_PTX"} ;                               // Radio pipe refernce of this RFIDReader,
MFRC522 mfrc522(RfidSel, RfidRst);                             // Instantiate the reader MFRC522
byte RFID_Data[4];                                             // Data to Rx unit
bool resetRFID;                                                // Reset data frrom Rx
unsigned long prevMillisA;
unsigned long intervalA = 500;
unsigned long rfStatusTimeOut;
byte rfidTxCount ;
bool blockMfrc522;

byte RF_OK_Out   = 3;
byte RFID_OK_Out = 4;

void setup() {
  Serial.begin(9600);
  Serial.println(F("*** STARTING TRANSMITTER *** "));
  SPI.begin();
  mfrc522.PCD_Init();                                          // Initialize the  MFRC522 reader

  // Setup and configure radio
  radio.begin();
  radio.setChannel(108);                                       // Above most Wifi Channels
  radio.setDataRate( RF24_250KBPS );
  radio.setRetries(5, 10);                                     // Delay, count
  radio.enableAckPayload();                                    // Allow optional ack payloads
  radio.enableDynamicPayloads();                               // Ack payloads are dynamic payload

  pinMode(RF_OK_Out, OUTPUT);
  pinMode(RFID_OK_Out, OUTPUT);
}

void loop(void)
{
  if ( !blockMfrc522) getRFID();                               // Read the RFID tag... when not transmitting

  if (RFID_Data[0] == 0 && RFID_Data[1] == 0 && RFID_Data[2] == 0 && RFID_Data[3] == 0 )
  {
    digitalWrite(RFID_OK_Out, LOW);                            // Handle the RFID led..
  }
  else
  {
    digitalWrite(RFID_OK_Out, HIGH);
  }
  //******************************************************
  if ( millis() - prevMillisA > intervalA )
  {
    prevMillisA = millis();
    blockMfrc522 = true;
    send_rfid();                                             // Transmitt the last read RFID
    blockMfrc522 = false;
  }
  //******************************************************
  if ( millis() - rfStatusTimeOut > 2000)                      // Update RF24 comm status
  {
    digitalWrite( RF_OK_Out, LOW);
  }
  else
  {
    digitalWrite( RF_OK_Out, HIGH);
  }
}

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

void send_rfid()
{
  radio.openWritingPipe(rf_Address);                                 // Open the writing pipe with own reference
  bool rfTxStatus = (radio.write(&RFID_Data, sizeof(RFID_Data)));     // Send the RFID info
  if (rfTxStatus)          // PROBLEM : THIS BOOL NEVER RETRUNS TRUE
  {
    if ( radio.isAckPayloadAvailable() )                              // Sent. Now read the Ack Pay load from Rx module..
    {
      radio.read(&resetRFID, sizeof(resetRFID));                      // If ackPayLoad is True , reset RFID data
    }
    if (resetRFID)
    {
      RFID_Data[0] = 0;
      RFID_Data[1] = 0;
      RFID_Data[2] = 0;
      RFID_Data[3] = 0;
    }
    rfStatusTimeOut = millis();                                     // Hold the RF_OK LED 
  }
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  // FUNCTION TO READ RFID TAG AND CONVERT IT TO A 8 BYTE DATA

  int getRFID() 
  {
    // Look for new cards
    if ( ! mfrc522.PICC_IsNewCardPresent()) {
      return;
    }
    // Select one of the cards
    if ( ! mfrc522.PICC_ReadCardSerial()) {
      return;
    }
    for (int i = 0; i < mfrc522.uid.size; i++) {
      RFID_Data[i] = mfrc522.uid.uidByte[i];
    }
    char scannedRFID[10];
    sprintf ( scannedRFID, "%02X%02X%02X%02X", RFID_Data[0], RFID_Data[1], RFID_Data[2], RFID_Data[3]);
    Serial.println(scannedRFID);
    
    mfrc522.PICC_HaltA();
    return 1;
  }

What's the length of the wires to the nrf24 and to the mfrc522?

A little history: I found your post because I also have an RF/RFID combination project, and it initially wasn't working. The project is intended to be used by someone other than me, so I thought I'd be clever and wire it up so that the nrf24 module and the mfrc522 module could be connected via rj45 connectors running a patch cord between the arduino board and a mini board with the RF or RFID modules.

I initially had the nrf24 connected by itself and ran some testing. I found that I couldn't connect a patch cord longer than about 8 inches. If I did, the code would hang and not get past my network.update() line (see the Network_Ping example in the RF24Network library) at the beginning of the loop block.

Ok. Fine. I'll use a shorter RF patch cord.

Separately, I made sure my RFID code worked by commenting out all of the radio code. It worked well with a longer patch cord ~5 ft.

As soon as I connect up both modules with all code uncommented, the RF code would hang again. Unplugging the RFID patch cord got it working again.

So, I soldered up a temporary board using a protoboard and put a female header pin close to the Arduino into which I could directly plug in the nrf24 module. Same thing for the RFID.

Success! Shorter connections helped.

Then, to test, I left the nrf24 module connected into the header and used the 8 in patch cord to extend the RFID.

That also worked.

However, when I went to the 5 ft. patch cord, no luck.

To verify my findings, I wanted to test your code to see if the same thing would work with different code. I didn't have an example of the RX code you were using, but searching for ackPayLoad examples, I found the blog at shantamraj.wordpress.com. I had to modify your code to work with my pinouts and to work with his data. I also modified his data a little to receive the RFID_Data you were sending.

Using these code modifications, I got your code to work with his. I found the same cord length issues I was having: the 8 in. cord and the direct connection worked fine, and the 5 ft. cord didn't. Too bad for me. I'll just have to make it work.

However, the modified code is below. This code works for me with 2 Arduino nanos and their respective nrf24 hardware. I've tried to comment the beginning of the lines where I modified your code. I may have missed some.

Your code (TX side):

#include <SPI.h>
#include <RF24.h>
#include <nRF24L01.h>
#include <MFRC522.h>
/****************** User Config ***************************/
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7,8 */
/*changed per my setup*/    //RF24 radio(7, 8);
/*changed per my setup*/    RF24 radio(9, 10);
/**********************************************************/
/* RFID interface configuration apart from SPI bus */
/*changed per my setup*/    //#define RfidRst    9                                           // RFID reset pin
/*changed per my setup*/    //#define RfidSel    10                                          // RFID select pin
/*changed per my setup*/    #define RfidRst    15                                           // RFID reset pin
/*changed per my setup*/    #define RfidSel    14                                          // RFID select pin
/*********************************************************/
/*changed to work with RX from URL*/   //byte rf_Address[6] = { "3_PTX" };                               // Radio pipe refernce of this RFIDReader,
/*changed to work with RX from URL*/   const uint64_t pipe[1] = { 0xF0F0F0F0E1LL };
MFRC522 mfrc522(RfidSel, RfidRst);                             // Instantiate the reader MFRC522
byte RFID_Data[4];                                             // Data to Rx unit
/*changed to work with RX from URL*/   //bool resetRFID;                                                // Reset data frrom Rx
/*changed to work with RX from URL*/   int resetRFID;
unsigned long prevMillisA;
unsigned long intervalA = 500;
unsigned long rfStatusTimeOut;
byte rfidTxCount;
bool blockMfrc522;

byte RF_OK_Out = 3;
byte RFID_OK_Out = 4;

void setup() {
	Serial.begin(9600);
	Serial.println(F("*** STARTING TRANSMITTER *** "));
	SPI.begin();
	mfrc522.PCD_Init();                                          // Initialize the  MFRC522 reader

																 // Setup and configure radio
	radio.begin();
	radio.setChannel(108);                                       // Above most Wifi Channels
	radio.setDataRate(RF24_250KBPS);
	radio.setRetries(5, 10);                                     // Delay, count
	radio.enableAckPayload();                                    // Allow optional ack payloads
	radio.enableDynamicPayloads();                               // Ack payloads are dynamic payload

	pinMode(RF_OK_Out, OUTPUT);
	pinMode(RFID_OK_Out, OUTPUT);
}

void loop(void)
{
	if (!blockMfrc522) getRFID();                               // Read the RFID tag... when not transmitting

	if (RFID_Data[0] == 0 && RFID_Data[1] == 0 && RFID_Data[2] == 0 && RFID_Data[3] == 0)
	{
		digitalWrite(RFID_OK_Out, LOW);                            // Handle the RFID led..
	}
	else
	{
		digitalWrite(RFID_OK_Out, HIGH);
	}
	//******************************************************
	//if (millis() - prevMillisA > intervalA)
	if (blockMfrc522)
	{
		prevMillisA = millis();
		//blockMfrc522 = true;
		send_rfid();                                             // Transmitt the last read RFID
		blockMfrc522 = false;
	}
	//******************************************************
	if (millis() - rfStatusTimeOut > 2000)                      // Update RF24 comm status
	{
		digitalWrite(RF_OK_Out, LOW);
	}
	else
	{
		digitalWrite(RF_OK_Out, HIGH);
	}
}

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

void send_rfid()
{
/*changed to work with RX from URL*/   	//radio.openWritingPipe(rf_Address);                                 // Open the writing pipe with own reference
/*changed to work with RX from URL*/   	radio.openWritingPipe(pipe[0]);
	bool rfTxStatus = (radio.write(&RFID_Data, sizeof(RFID_Data)));     // Send the RFID info
	if (rfTxStatus)          // PROBLEM : THIS BOOL NEVER RETRUNS TRUE
	{
		if (radio.isAckPayloadAvailable())                              // Sent. Now read the Ack Pay load from Rx module..
		{
			radio.read(&resetRFID, sizeof(resetRFID));                      // If ackPayLoad is True , reset RFID data
		}
		/*changed to work with RX from URL*/   		//if (resetRFID)
		/*changed to work with RX from URL*/   		if (resetRFID == 2)
		{
			RFID_Data[0] = 0;
			RFID_Data[1] = 0;
			RFID_Data[2] = 0;
			RFID_Data[3] = 0;
/*added to verify data cleared*/   			Serial.println("data reset");
		}
		rfStatusTimeOut = millis();                                     // Hold the RF_OK LED 
	}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// FUNCTION TO READ RFID TAG AND CONVERT IT TO A 8 BYTE DATA

int getRFID()
{
	// Look for new cards
	if (!mfrc522.PICC_IsNewCardPresent()) {
		return;
	}
	// Select one of the cards
	if (!mfrc522.PICC_ReadCardSerial()) {
		return;
	}
	for (int i = 0; i < mfrc522.uid.size; i++) {
		RFID_Data[i] = mfrc522.uid.uidByte[i];
	}
	blockMfrc522 = true;
	char scannedRFID[10];
	sprintf(scannedRFID, "%02X%02X%02X%02X", RFID_Data[0], RFID_Data[1], RFID_Data[2], RFID_Data[3]);
	Serial.println(scannedRFID);

	mfrc522.PICC_HaltA();
	return 1;
}

Receiver code (based on URL above):

#include<SPI.h>
#include<nRF24L01.h>
#include<RF24.h>
const uint64_t pipe[1] = {0xF0F0F0F0E1LL};
RF24 radio(8, 9);
int rec[1] = {2};
byte RFID_Data[4];
void setup()
{
  Serial.begin(115200);
  radio.begin();
  delay(100);
  radio.setChannel(108);
  radio.setDataRate(RF24_250KBPS);
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.openReadingPipe(1, pipe[0]);
  radio.startListening();
  radio.setRetries(15, 15);
}
void loop()
{
  if ( radio.available() ) {
    radio.writeAckPayload( 1, rec, sizeof(int) );
    radio.read( &RFID_Data, sizeof(RFID_Data) );
    Serial.print("Data got is: ");
    char scannedRFID[10];
    sprintf(scannedRFID, "%02X%02X%02X%02X", RFID_Data[0], RFID_Data[1], RFID_Data[2], RFID_Data[3]);
    Serial.println(scannedRFID);
  }
}

Hope this helps.

@ClueKent

Thanks for your response and time spent to unravel the issue. Well in my case the RF 24 module sits on the PCB next to the ProMini and the RFID tag gets connected via a 3 inch long ribbon cable.

Anyway its now working and out of two reasons not sure which fixed it .. First : The data type of the AckPayload ... the Tx was expecting a Bool and the Rx was sending a byte.

Next the sending portion of the code was modified as below. Now the code works reliably.

void send_rfid()
{  
  bool rfTxStatus = false ; 
  radio.openWritingPipe(rf_Address[1]);                  
  (radio.write(&rfidTagInfo, sizeof(rfidTagInfo)));     // Send the RFID info

  while ( radio.available() )
  {
    radio.read( &resetRFID, sizeof(resetRFID));
    rfTxStatus = true; 
  }

  if ( rfTxStatus == true) rfStatusTimeOut = millis();
  Serial.println( rfTxStatus); 

 }

SO looks like the problem got solved in a specific case only. In another version where the Master is in Tx mode and requests data from the RFID reader unit in Tx mode the set up just does not work as long as the RFID reader is in connected - just unplug it and the RF link immediately becomes OK but to no avail as there is no RFID data to send !!

3.3V power supplies / different RFID readers / different RF24 modules ....all behave consistently and refuse to work together.

SO it ultimately looks like if I have a RFID reader and RF24 on the same SPI bus, the RF24 has to be only a Tx unit as otherwise it has to be listening always and we have a issue.

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

/****************** User Config ***************************/
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins CE, CSN */
RF24 radio(7, 8);
/**********************************************************/
/* RFID interface configuration apart from SPI bus */
#define RfidRst    9                                           // RFID reset pin
#define RfidSel    10                                         // RFID select pin
/*********************************************************/
const uint64_t   deviceID = 0xE8E8F0F0E2LL;

MFRC522 mfrc522(RfidSel, RfidRst);                           // Instantiate the reader MFRC522
struct rfid2main
{
  byte rfidTag[4];                                           // Data to Main
  bool newTag;
} rfidTagInfo;
byte resetRFID = 0;                                          // Data from Main

unsigned long rfStatusTimeOut = millis();
byte RF_OK_Out   = 3;

//$$$$$$$$$$$$$$$$$$$$$$$$$$$$
void setup() {

  Serial.begin(9600);
  Serial.println(F("*** STARTING TRANSMITTER *** "));

  SPI.begin();

  mfrc522.PCD_Init();                                      // Initialize the  MFRC522 reader

  radio.begin();                                           // Setup and configure radio
  radio.setChannel(108);
  radio.setDataRate( RF24_250KBPS );                       // Minimum drop out with this setting
  radio.openReadingPipe(1, deviceID);
  radio.enableAckPayload();
  radio.writeAckPayload(1, &rfidTagInfo, sizeof(rfidTagInfo));
  radio.startListening();
  pinMode(RF_OK_Out, OUTPUT);
}

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

void loop(void)
{
  getRFID();                                              // Read the RFID tag...
  respondToMain();                                        // RF comm with Main..

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

  if ( millis() - rfStatusTimeOut > 2000)                 // Handle the RF status LED.. but works only when the RFID interface is removed !!
  {
    digitalWrite( RF_OK_Out, LOW);
  }
  else
  {
    digitalWrite( RF_OK_Out, HIGH);
  }

}

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

// F U N C T I O N S

void respondToMain()                  // Function to send the RFID tag data when Master requests...
{
  if ( radio.available())
  {
    radio.read( &resetRFID, sizeof(resetRFID));                      // READ FROM MASTER.. this is just a token from master requesting data

    radio.writeAckPayload(1, &rfidTagInfo, sizeof(rfidTagInfo));     // SEND rfid tag data to master

    rfStatusTimeOut = millis();
  }
}

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

// FUNCTION TO READ RFID TAG AND CONVERT IT TO A BYTE ARRAY

int getRFID() {
  // Look for new cards
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return 0;
  }
  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    return 0;
  }
  for (int i = 0; i < mfrc522.uid.size; i++) {
    rfidTagInfo.rfidTag[i] = mfrc522.uid.uidByte[i];
  }
  char scannedRFID[10];
  sprintf ( scannedRFID, "%02X%02X%02X%02X", rfidTagInfo.rfidTag[0], rfidTagInfo.rfidTag[1], rfidTagInfo.rfidTag[2], rfidTagInfo.rfidTag[3]);
  Serial.println(scannedRFID);
  mfrc522.PICC_HaltA();
  return 1;
}

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

Mogaraghu:
SO it ultimately looks like if I have a RFID reader and RF24 on the same SPI bus, the RF24 has to be only a Tx unit as otherwise it has to be listening always and we have a issue.

That does not make any sense.

When you have more than one device on the SPI bus your program must manage which device is selected before you try to communicate on the bus. In the case of the nRF24 that is with the CSN pin. It is probably the RfidSel pin for the RFID reader. At any one time no more than one of them should be selected - I think that means HIGH, but you should check.

I see no code in your program to change the value on those pins

The nRF24 will listen and receive a message even if CSN is not selected

...R

Yes... it does not make sense and hence I made a blanket statement !!

I am using libraries for both the RF24 module and as well for the RFID module and once I create an instance of the required objects then why would I manipulate the Chip select for the individual modules ? Reason why there is no code for it.

Aren't the libraries supposed to release the SPI bus once they are done with it ? Actually what I have seen is that even if I completely comment out all references pertaining to the RFID reader the RF24 still does not work.

It works ONLY when I physically disconnect the RFID reader. So to me this looks like a HW issue ... and I was wanting to know if anyone else had such a problem.

( In a earlier case a similar thing happened with a Chinese SD card reader - it was not releasing the SPI bus and hence did not allow RF24 to work .. I posted the issue and prompt came a response to work around the issue [or] switch over to a SparkFun module. All well after that )

Mogaraghu:
then why would I manipulate the Chip select for the individual modules

Perhaps because you want it to work?

...R