[solved] problem with reading from multiple MFRC522

Hi Community!

I've got a problem with reliable reading from multiple (4) MFRC522-RFID-readers.
The idea is to make an "RFID-puzzle", where you have to place 4 correct tags on the matching reader to solve it.

My setup is essentially like this:

The differences are in the SS-pins (you will find it in the sketch) and it is all connected to an Arduino Nano.

// SPI-DECLARATION
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN         10
#define SS_1_PIN        4
#define SS_2_PIN        5
#define SS_3_PIN        6
#define SS_4_PIN        7
#define NR_OF_READERS   4
byte ssPins[] = {SS_1_PIN, SS_2_PIN, SS_3_PIN, SS_4_PIN};
MFRC522 mfrc522[NR_OF_READERS];       // Create MFRC522 instance.
uint8_t reader;
byte uidreadarray[4][7];              // arrays for read UIDs
byte uidwinarray[4][7];               // arrays for comparing read UID (set by Eeprom)
boolean tagpresent[4];                // arrays for placed tag on readers
bool newtagispresent;                 // true, if a new tag is placed
//MFRC522::MIFARE_Key key;

// IO-DECLARATION
#define Button A0

// global variables
bool gamewon;

// EEPROM-DECLARATION
#include <EEPROM.h>


void setup() {

  Serial.begin(9600);

  pinMode(Button, INPUT_PULLUP);

  EEPROMreadUID();    // set uidwinarray

  while (!Serial);    // Do nothing if no serial port is opened

  SPI.begin();        // Init SPI bus

  checkReaders();

}


void loop() {
  gamewon = false;
  while (gamewon == false) {
    newtagispresent = false;
    for (reader = 0; reader < NR_OF_READERS; reader++) {        // check all readers for a new tag
      delay(1);
      if (mfrc522[reader].PICC_IsNewCardPresent()) {
        newtagispresent = true;
      }
    }
    if (newtagispresent == true) {                              // new tag detected
      readTags();                                               // read UID from all tags
      checkWinUID();                                            // compare with correct UIDs
      if (gamewon == false) {
        Serial.println("Try again...");                         // uid combination not correct, show it!
      }
    }
  }
  Serial.println("Game won!");                                  // uid combination is correct, show it!
  while (digitalRead(Button) == HIGH) {
    delay(1);
  }
}


void readTags() {
  byte atqa[4][2];                                              // for identification of tag-type
  byte atqaLen = sizeof(atqa[0]);
  checkReaders();                                               // check the readers first
  for (reader = 0; reader < NR_OF_READERS; reader++) {
    Serial.print(F("Reader :"));
    Serial.print(reader);
    Serial.print("\t");
    delay(1);
    //mfrc522[reader].PICC_RequestA(atqa[reader], &atqaLen);     // buggy
    mfrc522[reader].PICC_WakeupA(atqa[reader], &atqaLen);
    if (atqa[reader][0] == 0x04 && atqa[reader][1] == 0) {
      Serial.println("Mifare Classic");
      //read and store UID
      mfrc522[reader].PICC_Select(&(mfrc522[reader].uid), 0);
      for (int n = 0; n < 4; n++) {                                        // mfrc522[reader].uid.size
        uidreadarray[reader][n] = mfrc522[reader].uid.uidByte[n];          // fill uidreadarray
      }
      uidreadarray[reader][4] = 0;                                         // fill the last 3 blocks with 0 (Classic)
      uidreadarray[reader][5] = 0;
      uidreadarray[reader][6] = 0;
      tagpresent[reader] = true;
    }
    else if (atqa[reader][0] == 0x44 && atqa[reader][1] == 0) {
      Serial.println("Mifare Ultralight");
      //read and store UID
      mfrc522[reader].PICC_Select(&(mfrc522[reader].uid), 0);
      for (int n = 0; n < 7; n++) {                                        // mfrc522[reader].uid.size
        uidreadarray[reader][n] = mfrc522[reader].uid.uidByte[n];          // fill uidreadarray
      }
      atqa[reader][0] = 0;
      tagpresent[reader] = true;
    }
    else {
      Serial.println("no valid tag present!");          // no Mifare Classic or Ultralight
      atqa[reader][0] = 0;
      tagpresent[reader] = false;
      for (int n = 0; n < 7; n++) {                     // empty array for this reader
        uidreadarray[reader][n] = 0;
      }
    }
    mfrc522[reader].PICC_HaltA();
    mfrc522[reader].PCD_StopCrypto1();
  }
  Serial.println();
  outputUID();
}


void checkWinUID() {                                    // Check if readUID is winUID
  byte wincount = 0;
  byte checksum = 0;
  for (reader = 0; reader < NR_OF_READERS; reader++) {
    for (int n = 0; n < 7; n++) {
      if (uidreadarray[reader][n] == uidwinarray[reader][n]) {
        wincount++;
      }
      checksum++;
    }
  }
  if (wincount == checksum) {
    gamewon = true;
  }
}

void EEPROMreadUID() {
  // read UID from Eeprom and set uidwinarray
  Serial.println("Reading UIDs from Eeprom!");
  for (reader = 0; reader < NR_OF_READERS; reader++) {
    Serial.print("Reader: ");
    Serial.print(reader);
    Serial.print("\tADDR/VALUE:\t");
    for (int n = 0; n < 7; n++) {
      byte addresstoread = (reader * 10) + n + 1;         // dynamic Eeprom-address
      Serial.print(addresstoread);
      Serial.print("/");
      uidwinarray[reader][n] = EEPROM.read(addresstoread);
      Serial.print(uidwinarray[reader][n]);
      Serial.print("\t");
    }
    Serial.println();
  }
}

void outputUID() {
  Serial.println("showing read UID-arrays...");
  for (reader = 0; reader < NR_OF_READERS; reader++) {
    Serial.print ("Reader: ");
    Serial.print (reader);
    Serial.print ("\tUID:\t");
    for (int n = 0; n < 7; n++) {
      Serial.print (uidreadarray[reader][n]);
      Serial.print ("\t");
    }
    Serial.println();
  }
  Serial.println();
}


void checkReaders() {
  boolean allworking = true;
  Serial.println();
  Serial.println("Checking all Readers!");
  for (reader = 0; reader < NR_OF_READERS; reader++) {
    delay(1);
    mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN);        // Init each MFRC522 tag
    byte verbyte = mfrc522[reader].PCD_ReadRegister(mfrc522[reader].VersionReg);
    Serial.print(F("Reader "));
    Serial.print(reader);
    Serial.print(F(": "));
    mfrc522[reader].PCD_DumpVersionToSerial();
    if (verbyte != 0x92) {
      allworking = false;
    }
  }
  if (allworking == false) {
    Serial.println("There is a Problem!");
  }
  else {
    Serial.println("Readers are working");
  }
  Serial.println();
}

The good news first..: it does work... mostly.

My Problem is, when I play around with the tags over the readers, i.E. swapping them quickly, the readings might get "stuck".
From then on all of the readers are unable to read the UID. They continuously give the info "new tag present" as long as there is a tag on the reader, but are already failing to identify the tag type.
When this problem occurs, the only way to solve it, is to reset the Nano and then everything is well again...
The SPI-connection seems to be fine (I succesfully check the chip-version of all readers before reading the tags).

Actually this is my first project that involves SPI-communication and I don't know, how to "reset" the readers without resetting the Nano.
Does the SPI have a buffer, which might get corrupted by my handling of the tags and could be flushed after every reading?
Maybe my function of reading the tags is not what it should be like, but understanding all the functions that the library provides is a tough process.. :sweat_smile:

I had trouble getting reliable reads on just one card.
You could try a reset

  // Set the resetPowerDownPin as digital output, 
  pinMode(_rst, OUTPUT);

  if (digitalRead(_rst) == LOW) { //The RFID chip is in power down mode.
    digitalWrite(_rst, HIGH);   // Exit power down mode. This triggers a hard reset.
    // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let us be generous: 50ms.
    delay(50);
  } else { // Perform a soft reset
    PCD_Reset();
  }

I also turn the antenna off between reads and turn it on to read.
and my read starts with

  bool present = PICC_IsNewCardPresent();
  bool readCard = PICC_ReadCardSerial();
  if (!present || !readCard) {
    stop(); // turn antenna off and in my case stop the SPI
    clearPreviousUid(); // allow retry here??
    return STATUS_CARD_NOT_FOUND;
  }

I would suggest you post a schematic, as wired, not a frizzy thing that shows all the power, ground, and decoupling capacitors. It appears you are having a glitch in your power source. Those MFRC522-RFID-readers can draw 26mA each. Consider leaving the antenna(s??) on. Swapping quickly indicates an increase in the power load.

drmpf:
You could try a reset

if (digitalRead(_rst) == LOW) { //The RFID chip is in power down mode.

digitalWrite(_rst, HIGH);  // Exit power down mode. This triggers a hard reset.
    // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let us be generous: 50ms.
    delay(50);
  } else { // Perform a soft reset
    PCD_Reset();
  }

this sounds, what I might be looking for..

I've tried to include the pcd_reset into the readTags()-void after an unsuccesfully read of a tag. But I was still able to reproduce the error.. :confused:
Maybe I did it the wrong way? When should I check for a (reset_pin == low) or turn the antennas off/on, when I am cycling through all readers? Why does a reset on the arduino have the desired effect on the readers, what pcd_reset doesn't?

void readTags() {
  checkReaders();                                                         // check the readers first
  for (reader = 0; reader < NR_OF_READERS; reader++) {
    Serial.print(F("Reader :"));
    Serial.print(reader);
    Serial.print("\t");
    delay(5);
    //mfrc522[reader].PICC_RequestA(atqa[reader], &atqaLen);      // which one to use?
    mfrc522[reader].PICC_WakeupA(atqa[reader], &atqaLen);       // which one to use?
    // WHEN STUCK, READING OF ATQA ONLY RESULTS IN 0
    if (atqa[reader][0] == 0x04 && atqa[reader][1] == 0) {
      Serial.println("Mifare Classic");
      //read and store UID
      mfrc522[reader].PICC_Select(&(mfrc522[reader].uid), 0);
      for (int n = 0; n < 4; n++) {                                        // mfrc522[reader].uid.size
        uidreadarray[reader][n] = mfrc522[reader].uid.uidByte[n];          // fill uidreadarray
      }
      uidreadarray[reader][4] = 0;                                         // fill the last 3 blocks with 0 (Classic)
      uidreadarray[reader][5] = 0;
      uidreadarray[reader][6] = 0;
      atqa[reader][0] = 0;
      tagpresent[reader] = true;
    }
    else if (atqa[reader][0] == 0x44 && atqa[reader][1] == 0) {
      Serial.println("Mifare Ultralight");
      //read and store UID
      mfrc522[reader].PICC_Select(&(mfrc522[reader].uid), 0);
      for (int n = 0; n < 7; n++) {                                        // mfrc522[reader].uid.size
        uidreadarray[reader][n] = mfrc522[reader].uid.uidByte[n];          // fill uidreadarray
      }
      atqa[reader][0] = 0;
      tagpresent[reader] = true;
    }
    else {
      Serial.print  ("no valid tag present!\t");          // no Mifare Classic or Ultralight
      Serial.print  ("atqa[0]="); 
      Serial.print  (atqa[reader][0]);
      Serial.print  ("\atqa[1]="); 
      Serial.println(atqa[reader][1]);         
      atqa[reader][0] = 0;
      tagpresent[reader] = false;
      for (int n = 0; n < 7; n++) {                     // empty array for this reader
        uidreadarray[reader][n] = 0;
      }
      mfrc522[reader].PCD_Reset();
      delay(50);
      mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN);        // Init each MFRC522 reader
      delay(50);
    }
    mfrc522[reader].PICC_HaltA();
    mfrc522[reader].PCD_StopCrypto1();  
  }
  Serial.println();
  outputUID();
}

@gilshultz: I'll try to post a schematic of my individual setup asap. But it wouldn't look much different: 5V and 3.3V come from external linear voltage regulators (with 1.5A each), there is (yet) no electric lock attached and since there are some capacitors near the regulators, I didn't feel the need for additional coupling capacitors. But I'm sure, that I am wrong there, too... Should I add one to every reader?

by looking for solutions I stumbled upon many other people seeming to have the same problem with the tag-reader. Haven't found a solution that worked for me..

Then I've found this post: "Pylon" suggested

You should set the size variable before each call of MIFARE_Read() as the method returns the read bytes in this variable. So if you read less then the expected bytes once you'll never see more in the future

..sadly he couldn't elaborate that hint because OP had his own workaround for his problem. But I would like to know, if somebody can make use of this..?

And speaking of the workaround: a new command (for me) was brought up there: PCD.SoftPowerDown() and .SoftPowerUp() .. never saw it before... will try it :slight_smile: edit: with no success

I do the reset in the init() method for my reader, but you may need to do it each time.
My code uses PICC_WakeupA as it seems to handle halt as well as idle cards

/**
   Transmits a Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.
   Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design.

   @return STATUS_OK on success, STATUS_??? otherwise.
*/

I suggest you try just one reader first and get that running reliably and then add another one.
Keep them separated so that the antenna/cards do not interfere.
Another 'gross' option is to power cycle the readers, by using another output pin to drive a FET switch in the Reader power line.

Thank you all for being interested in my problem and giving me advice! :slight_smile:

The problem seems to be solved! 8)

What would you do, if you fail again and again? I've decided to start all over and abandon this abomination of my sketch.. Back to the basic examples and see, where the problems begin. Reading of the tags works like a charm. In my efforts to detect the removal of a tag I noticed, that the use of **PICC_RequestA(..); ** or PICC_WakeupA(..) was the part that got me into trouble, because after once mis-reading a tag they always resulted in 0.

The readers still detected flawlessly the presence of a new card and were able to read the uid (if I would have just used PICC_ReadCardSerial()), but I couldn't see that..
In order to be able to detect the presence of a tag I initialise every reader before usage, so it will detect and read the tag or else... no tag :wink:

#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN         10
#define SS_1_PIN        4
#define SS_2_PIN        5
#define SS_3_PIN        6
#define SS_4_PIN        7
#define NR_OF_READERS   4
byte ssPins[] = {SS_1_PIN, SS_2_PIN, SS_3_PIN, SS_4_PIN};
MFRC522 mfrc522[NR_OF_READERS];                     // Create MFRC522 instance.
uint8_t reader;

void setup() {
  Serial.begin(9600);
  while (!Serial);    // Do nothing if no serial port is opened
  SPI.begin();        // Init SPI bus
  checkReaders();     // Init the readers
}


void loop() {
  for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) {
    mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN);     // Init each MFRC522 reader
    delay(1);                                              // necessary delay to detect mifare ultralight
    // Look for new cards
    if (mfrc522[reader].PICC_IsNewCardPresent() && mfrc522[reader].PICC_ReadCardSerial()) {
      Serial.print(F("Reader "));
      Serial.print(reader);
      // Show some details of the PICC (that is: the tag/card)
      Serial.print(F(": Card UID:"));
      dump_byte_array(mfrc522[reader].uid.uidByte, mfrc522[reader].uid.size);
      Serial.print("\tPICC type: ");
      MFRC522::PICC_Type piccType = mfrc522[reader].PICC_GetType(mfrc522[reader].uid.sak);
      Serial.println(mfrc522[reader].PICC_GetTypeName(piccType));
    } //if (mfrc522[reader].PICC_IsNewC
    else {
      // no new card found and read
      Serial.println("no valid tag present!");
    }
    // Halt PICC
    mfrc522[reader].PICC_HaltA();
    // Stop encryption on PCD
    mfrc522[reader].PCD_StopCrypto1();
  } //for(uint8_t reader
}


void dump_byte_array(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
}

void checkReaders() {
  boolean allworking = true;
  Serial.println();
  Serial.println("Checking all Readers!");
  for (reader = 0; reader < NR_OF_READERS; reader++) {
    delay(1);
    mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN);        // Init each MFRC522 reader
    byte verbyte = mfrc522[reader].PCD_ReadRegister(mfrc522[reader].VersionReg);
    Serial.print(F("Reader "));
    Serial.print(reader);
    Serial.print(F(": "));
    mfrc522[reader].PCD_DumpVersionToSerial();
    if (verbyte != 0x92) {
      allworking = false;
    }
    mfrc522[reader].PICC_HaltA();
    mfrc522[reader].PCD_StopCrypto1();
  }
  if (allworking == false) {
    Serial.println("There is a Problem!");
  }
  else {
    Serial.println("Readers are working");
  }
  Serial.println();
}

I guess, from now on, it shouldn't be too hard for me to build the rest of the sketch around this vital part. And if it works, I will mark this post as solved. :smiley:

1 Like

PICC_IsNewCardPresent() does a PICC_RequestA for you.
I think the PCD_Init() is what is fixing your problems.
In my situation, detecting presents/absents of a card is the main job.

  restart();
 bool present = PICC_IsNewCardPresent();
  bool readCard = PICC_ReadCardSerial();
  if (!present || !readCard) {
    stop();
    clearPreviousUid(); // allow retry here??
    return STATUS_CARD_NOT_FOUND;
  }

Seems to do it for me.
stop() turns the antenna off, and restart() turns it on again (plus some SPI cs stuff)

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.