Qwiic RFID wrong readings after 20 reads

Hi,

I have the following test sketch running on a Micromod Single Board + ESP32 + Qwiic.

No other components are connected, power is over USB.

The purpose of the setup is to just detect the presence of a device, like:

  • reading “00000” = no device is present (myRfid.getTag() returns 000000 when no tag was detected)
  • reading “number wrong” = device (tag) is present but the wrong one (in my example, 5809122368250)
  • reading “number correct” = device (tag) is present and the right one (in my example, 580912131888)

After exactly 20 readings (with the 21st) this happens (this is repeatable):

  1. the readings gets wrong (it reads 59102000232 instead of 580912131888)
  2. myRfid.clearTags() seems to not be executed any more as myRfid.getTag() delivers the same result again and again, even when there is no tag present any more
  3. with every additional reading, the read number changes (increases)
  4. if I continue reading tags, eventually a crash happens (i2c.master: I2C hardware NACK detected))
  5. this happens no matter if I change NFC tags or use the same over and over again

I found that in the SparkFun_Qwiic_Rfid.h file there is #define MAX_TAG_STORAGE 20 I assume this means that 20 read tags are stored and are cleared with clearTags(), so that I do not get the last read tag when calling myRfid.getTag() but get the 000000 mentioned above.

What I have tried:

  • Changing MAX_TAG_STORAGE to e.g. 1 does not solve the issue.
  • removing calling myRfid.getTag() when a tag was detected does not solve the issue

The issue persists even when I reboot the board once it starts to read wrong. The only thing that helps resetting the Reader is with power cycle.

I wonder if I am using the library functions wrong (I based my program on the example), do something unallowed (const char* String compare..) or if I hit a bug in the library?

//repeat reading tag 21 times
//after 20 reads, tag starts to show 59102000232 (instead of 580912131888)
//it does not reset/clear the read then but goes up to 60102000232
//then with every subsequent read the number changes a bit: 62102000232
//next read: 63102000232
//next read: 64102000232
//eventually this becomes: 92102000232
//after that, there is a crash (E (199983) i2c.master: I2C hardware NACK detected)

#define LOGENABLED
#ifdef LOGENABLED
  #define LOG_PRINT(x) Log(x)
#else
  #define LOG_PRINT(x)
#endif

#include <Wire.h>
#include "SparkFun_Qwiic_Rfid.h"
#define RFID_ADDR 0x13 // Default I2C address
Qwiic_Rfid myRfid(RFID_ADDR);
String tagRead = "0000000000000000"; //length 16
const char* tagEmpty = "000000";
const char* tagRequired = "580912131888"; 
const char* textNoTag = "TAG_0";
const char* textTrueTag = "TAG_1";  
const char* textFalseTag = "TAG_2"; 

bool nfcDetected;
unsigned long nfcUpdateLast = 0;
unsigned long nfcUpdateInterval = 500;
int reading = 0;

void setup()
{
  Serial.begin(115200);
  while(!Serial) delay(10);

  Wire.begin();

  if(!myRfid.begin())
  {
    while(1);
  }
  myRfid.clearTags();
}

void loop()
{
    if (millis() - nfcUpdateLast >= nfcUpdateInterval)
  {
    nfcUpdateLast = millis();
    LoopNFC();
  }
}

void LoopNFC()
{
  //Reset values before the next reading
  if (nfcDetected == 1)
  {
    myRfid.clearTags();
    nfcDetected = 0;
    tagRead = tagEmpty;
  }

  //Read tag
  tagRead = myRfid.getTag();
  LOG_PRINT(tagRead);

  if (tagRead.equals(tagEmpty))
  {
    LOG_PRINT(textNoTag);
  }  
  else
  {
    reading++;
    nfcDetected = 1;
  }

  if (nfcDetected == 1)
  {
    if (tagRead.equals(tagRequired))
    {
      LOG_PRINT(textTrueTag);
    }
    else
    {
      LOG_PRINT(textFalseTag);
    }

    //clear all discovered tags after everything is done this loop, otherwise myRfid delivers wrong results
    //myRfid.clearTags();
    Serial.println(reading);
  }
}

void Log(String pText)
{
#ifdef LOGENABLED
  Serial.println(pText);
#endif
}

Given that you need to power cycle, made me look at the RFID reader. The firmware can be found on SparkFun_Qwiic_RFID_ID-XXLA/Firmware/ATtiny85_Firmware/Qwiic_RFID_IDXXLA/Qwiic_RFID_IDXXLA.ino at master · sparkfun/SparkFun_Qwiic_RFID_ID-XXLA · GitHub.

The firmware has a FIFO with 20 entries and 2 pointers: newestTag and oldestTag. The newestTAG is the “write pointer” and oldestTag is the “read-pointer”. They turnaround to zero when exceeding the 20 entries. Apart from some small errors, it looks to me it should work.

BUT that firmware-source is 4 years old, where it seems to be new firmware binary uploaded 2 years ago. Not sure where the source is of that.

Do you know if there is someone at Sparkfun that could be asked that?

@TS-Russel do you know where the latest source of the Qwiic RFID can be found ?

I’ve sent a ping, it looks like they might be out until tomorrow but hang tight! :smiley:

Thanks @TS-Russell for forwarding the issue.

While we wait for a reply, I wonder about this:

Line 103 in the main loop there is
delay(11);//Necessary to not overwhelm the ID-XXLA module baud rate.

From everything I read about the I2C bus and hardware errors, mostly someone mentions that it is a very bad idea to use delay (basically pausing the loop) together with I2C as a kind of “slow down”. Or am I mixing up something here and this delay is not causing problems?

1 Like

It seems I am not the only one who stumbles upon this issue, these postings are likely about the same problem:

I have taken some time to simulate the FIFO and the 2 pointers: NewestTag OldestTag as defined in the sketch :SparkFun_Qwiic_RFID_ID-XXLA/Firmware/ATtiny85_Firmware/Qwiic_RFID_IDXXLA/Qwiic_RFID_IDXXLA.ino at master · sparkfun/SparkFun_Qwiic_RFID_ID-XXLA · GitHub

It fails..
The problem related to the moment the pointers return to zero !

MAX_TAG_STORAGE is defined as 20 and thus positions 0 - 19.

The FIFO is defined as:

struct {
  byte tagID[6]; //The Uniqe identifier of the RFID tag, converted from ASCII to HEX will be six bytes in size.
  unsigned long tagTime; //When was the RFID tag sensed?
} tagEvent[MAX_TAG_STORAGE];

The turnaround pointer check is done AFTER the a new tag has been added:
if( newestTag++ == MAX_TAG_STORAGE ) newestTag = 0;

As newestTag is increment AFTER the compare it can contain position 20 to store the next TAG. This is beyond the FIFO size and a such will overwrite memory that is used for other variables. The result is undefined.. but not good…

Changing the turn around check to BEFORE doing the check, solves the issue
if( ++newestTag == MAX_TAG_STORAGE ) newestTag = 0;

btw the same should be done for OldestTag :
if (++oldestTag == MAX_TAG_STORAGE) oldestTag = 0;

Attached the sketch I used to simulate.
RFID_QWIIC_FIFO.txt (3.2 KB)

2 Likes

Hi @paulvha

great you figured that out! I am very thankful for your support :slight_smile:

Do I understand that right, that this is a problem in the firmware of the Reader which could only be fixed by a FW update?

This means flash the Attiny using an Arduino; which is complicated but doable as @micropuller suggests in this posting: Qwiic RFID keeps sending tag identifier, even if there is no tag present when quickly changing tags - #16 by micropuller