Problem with PN532 reader

I'm trying to get the PN532 NFC and RFID reader working with an ESP32. Currently I'm able to init the PN532 from the ESP32 but I can't read any tags.

There's a lot of counterfeit PN532's in the world but I don't think mine is one since I bought it from elechouse.com, a very reputable vendor (product link).

I'm using the reader in I2C mode, and set the jumper to I2C on the reader. I'm connected to the I2C pins of a Espressif ESP32-Wrover dev board (D21 and D22). Communication is successful since the ESP32 is able to read the firmware version off the reader. But it can't read any cards or RFID fobs.

I used this code as a starting point. Pasting below:


// Define the interface type
#if 0
#include <SPI.h>
#include <PN532_SPI.h>
#include "PN532.h"
PN532_SPI pn532spi(SPI, 10);
PN532 nfc(pn532spi);

#elif 0
#include <PN532_HSU.h>
#include <PN532.h>
PN532_HSU pn532hsu(Serial1);
PN532 nfc(pn532hsu);

#else
#include <Wire.h>
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>

PN532_I2C pn532i2c(Wire);
PN532 nfc(pn532i2c);
#endif


// added
//#define SDA 21
//#define SDL 22


volatile bool connected = false;

void setup(void)
{
  Serial.begin(115200);
  Serial.println("*** Testing Module PN532 NFC RFID ***");
  //Wire.begin(SDA, SDL);  // added

  delay(2000);

}

void loop(void)
{
  boolean success;
  // Buffer to store the UID
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
  // UID size (4 or 7 bytes depending on card type)
  uint8_t uidLength;

  while (!connected) {
    connected = connect();
  }

  // Wait for an ISO14443A type cards (Mifare, etc.).  When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);

  // If the card is detected, print the UID
  if (success)
  {
    Serial.println("Card Detected");
    Serial.print("Size of UID: "); Serial.print(uidLength, DEC);
    Serial.println(" bytes");
    Serial.print("UID: ");
    for (uint8_t i = 0; i < uidLength; i++)
    {
      Serial.print(" 0x"); Serial.print(uid[i], HEX);
    }
    Serial.println("");
    Serial.println("");
    
    delay(1000);
    connected = connect();
  }
  else
  {
    // PN532 probably timed out waiting for a card
    // Serial.println("Timed out waiting for a card");
  }
}

bool connect() {
  
  nfc.begin();

  // Connected, show version
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata)
  {
    Serial.println("PN53x card not found!");
    return false;
  }

  //port
  Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
  Serial.print("Firmware version: "); Serial.print((versiondata >> 16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);

  // Set the max number of retry attempts to read from a card
  // This prevents us from waiting forever for a card, which is
  // the default behaviour of the PN532.
  nfc.setPassiveActivationRetries(0xFF);

  // configure board to read RFID tags
  nfc.SAMConfig();

  Serial.println("Waiting for card (ISO14443A Mifare)...");
  Serial.println("");

  return true;
}

The output is:

20:25:21.867 -> *** Testing Module PN532 NFC RFID ***
20:25:29.532 -> Found chip PN532
20:25:29.532 -> Firmware version: 1.6
20:25:29.532 -> Waiting for card (ISO14443A Mifare)...
20:25:29.532 -> 

But it won't read any tags or fobs. I get the same behavior using the examples script from the Github repo, which is essentially the same as the code above.

I don't imagine anyone has any ideas?

Progress: the reader works when connected to an Arduino Mega in HSU mode, using [this script] (Interfacing PN532 NFC RFID Module with Arduino - Electropeak) (pasted below).

But I can't get that or any samples to run on my ESP32, it just crashes in a loop.

    /*
  PN532-NFC-RFID-Module-Library
  modified on 18 Nov 2020
  by Amir Mohammad Shojaee @ Electropeak
  Home

  based on www.electroschematics.com Arduino Examples
*/

#include <SoftwareSerial.h>

#include <PN532_SWHSU.h>

#include <PN532.h>

SoftwareSerial SWSerial( 10, 11 ); // RX, TX

PN532_SWHSU pn532swhsu( SWSerial );

PN532 nfc( pn532swhsu );


void setup(void) {

  Serial.begin(115200);

  Serial.println("Hello Maker!");

  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();

  if (! versiondata) {

    Serial.print("Didn't Find PN53x Module");

    while (1); // Halt

  }

  // Got valid data, print it out!

  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);

  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);

  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);

  // Configure board to read RFID tags

  nfc.SAMConfig();

  Serial.println("Waiting for an ISO14443A Card ...");

}

void loop(void) {

  boolean success;

  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID

  uint8_t uidLength;                       // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);

  if (success) {

    Serial.println("Found A Card!");

    Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");

    Serial.print("UID Value: ");

    for (uint8_t i=0; i < uidLength; i++)

    {

      Serial.print(" 0x");Serial.print(uid[i], HEX);

    }

    Serial.println("");

    // 2 second halt

    delay(2000);

  }

  else

  {

    // PN532 probably timed out waiting for a card

    Serial.println("Timed out! Waiting for a card...");

  }
}

@wrybread, your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with your project.

Your link is short on technical information such as what is its operating voltage? Do you have pull up resistors on the I2X (SCL SDA) lines? If it is 5V I would not expect it to work with the ESP, you would have to use a voltage translator. Use an active translator, not a resistor hack.

Thakns @sterretje.

And @gilshultz, I'm running it on 5v, but no pullup resistors.

The ESP is 3.3V, you need a translator to operate 5V devices properly. The I2C bus is driven by open drain outputs therefore must have some means of pulling the bus high. The design was to use resistors sized to compensate for the capacitance of the bus. Start with 3.3K to the 3.3V bus. If the bus does not operate properly the software does not have a chance.

I'm powering the reader with 5 volts.

That is what the voltage translator was for. Try it it might even work.

Sorry so late on this, I abandoned the ESP32 and was just using an Arduino. But now my project needs wifi so I'm giving the ESP32 anohter try.

When you say "Start with 3.3K to the 3.3V bus", is that simply using a 3.3k resistor on the positive power lead going to the PN532? Or is this a voltage divider type circuit?

These would be for the I2C bus, +3.3 to SCL another to SDA. It doesn't matter where you put the resistor, it needs to pull up the appropriate bus signal. I said start because I do not have a schematic to work from. The bus length and capacitance will dictate the pull up resistor minimum requirement.

why do you have connect() invoked in the main loop ?

calling it in setup() should be enough

get rid of that while() and that delay() from the main loop too

Well here's an interesting twist: I bought what is obviously a counterfeit/clone PN532 off Amazon and it works with the ESP32 right away... Using I2C mode, which is the only mode I tried.

It's this one:

I don't see any difference in range versus the non counterfeit version I bought from elechouse.com (which I got working with an Arduino Uno).

And to restate the issue:

  • when connected to the ESP32, the genuine PN532 will be initted by the ESP32 and the ESP32 can read the PN532's firmware (1.6), but it won't read any tags.

  • in the exact same environment (same ESP32, same wiring) the clone will be initted by the ESP32 and report it's firmware version (1.6) and read tags

  • when I connect the authentic PN532 to an Arduino it will init and read cards just fine.

And interestingly the clone the same quirk as the original where if it's connected when flashing the ESP, the reader doesn't get detected until I cycle power to it.

The clone seems to be stable longterm running from the ESP32, but that remains to be seen.

How can you possibly be sure that you have a "non counterfeit" item? The elechouse web page looks no different than any other hobby distributor's page.

I can't of course, but their reputation as sellers of genuine PN532's around the internet is stellar.

On another note, the reader started acting erratic again, sometimes requiring cycling power to make it init, and other times initting but not reading tags. So for now at least I went back to my old system of connecting the PN532 to an Uno and having it send the tag's UID to the ESP via UART. That method is rock solid.