Use PN532 NFC reader with interrupt

Hello,
I would like to read a card with PN532 NFC card reader via interrupt , because my Arduino does a lot of other things. I use this NFC module: (https://www.elechouse.com/elechouse/index.php?main_page=product_info&cPath=90_93&products_id=2271) with an Arduino Mega. Basically the NFC module has an IRQ pin which is HIGH (if you set SAM with 14 01 14 01 as you can read that at page 89), and I get the answer 15. If a card is presented, then the IRQ goes to LOW, but in my case the IRQ voltage never changes , it's always approx. 3,2V. I supply the NFC board with a different power supply line which has approx. 5V, I connected the GND of the power supply line with arduino's GND. If I disconnect the IRQ and the pin 2 between the arduino and the NFC module, then I get and iterrupt, and after that the interrupt always triggered (obviously the interrupt function is triggered, because I use FALLING interrupt condition), after that my interrupt function is always called, and it's like the function is called from void loop() . Here is my code: https://pastebin.com/gYuQ0kfQ To tell the truth, I do not really know what could cause the problem. Maybe PN532 IRQ voltage is for 3,3V logic level ? Because Arduino has 5V logic level. May I use logic level converter for IRQ pin?

Here is my updated code:

#include "emulatetag.h"
#include "NdefMessage.h"
#include <avr/wdt.h>

#include <SPI.h>
#include <PN532_SPI.h>
#include "PN532.h"
//MEGA
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
PN532_SPI pn532spi(SPI, 53);
//UNO
#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
PN532_SPI pn532spi(SPI, 10);
#endif


#define PN532IRQPIN (2)
volatile boolean cState = false;
PN532 nfc(pn532spi);
void cardreading();

void setup() {
  // put your setup code here, to run once:
  //pinMode(PN532IRQPIN, INPUT);
  //analogWrite(PN532IRQPIN, HIGH);
  Serial.begin(115200);
  Serial.println("\nHello!");
  nfc.begin();
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  // Got ok 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);
  
  nfc.SAMConfig();
  //pinMode(PN532IRQPIN, INPUT_PULLUP);
  //nfc.setPassiveActivationRetries(0x00);
  Serial.println(cState);
  attachInterrupt(digitalPinToInterrupt(PN532IRQPIN), cardreading, FALLING);
  //attachInterrupt(0, cardreading, FALLING);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(cState)
  {
    Serial.println("Interrupted");
    

    uint8_t 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)
    // 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)
    //nfc.inListPassiveTarget();
    success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
    
    if (success)
    {
      // Display some basic information about the card
      Serial.println("Found an ISO14443A card");
      Serial.print("  UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
      Serial.print("  UID Value: ");
      nfc.PrintHex(uid, uidLength);
    }
    cState = false;
    
    Serial.print("OUT: ");
    Serial.println(cState);
  }
  
}
void cardreading()
{
  
  cState = true;
  
}

I would put money on that.

Well, at present when I open the port I get an interrupt, I do not know why?! After that I never get anymore... and I use logic level converter.

What exactly do you mean by that?

Is this still true?
If so what happens when you disconnect your interrupt line from your Arduino?

The falling condition is the correct one to use.

It is loop function not void loop().
The interrupt function will be called from what ever code the program is in when the interrupt occurs. If it spends most of its time in the loop function it will look like it is called from there.

I meant open the Serial Monitor in Arduino IDE

So, yesterday I played with it a little bit. I got an interrupt, when I set the nfc.SAMconfig(); in the void setup() After that one card reading is "available", but after that I never get interrupt. I only get interrupt, when I disconnect the interrupt connection from Arduino.

The falling condition is the correct one to use.

Finally, I connected a logic level shifter, and after that my IRQ output is around 5V when no card presented, but I still do not get interrupt. I guess I have to configure the PN532 in read-tag mode. At present I do not really know how to do that properly, because I tried, but nothing happened.
https://forums.adafruit.com/viewtopic.php?f=31&t=40185&p=530924&hilit=pn532+interrupt#p530924

Finally, I found out the solution, therefore I wrote it down for those people who get into trouble with it.

Here is the library that works with interrupts: Seed Studio PN532 Arduino Library

After the interruption, you have to call nfc.startPassiveTargetIDDetection(PN532_MIFARE_ISO14443A); which sets again the PN532 reader in detection mode non blocking, so interrupts must be enabled
@param cardBaudRate: Baud rate of the card (you can find the cardBaudRates here-->

baud rate and the modulation type to be used during the initialization:

  • 0x00 : 106 kbps type A (ISO/IEC14443 Type A),
  • 0x01 : 212 kbps (FeliCa polling),
  • 0x02 : 424 kbps (FeliCa polling),
  • 0x03 : 106 kbps type B (ISO/IEC14443-3B),
  • 0x04 : 106 kbps Innovision Jewel tag.)

The PN532_MIFARE_ISO14443A means 0x00

bool PN532::startPassiveTargetIDDetection(uint8_t cardbaudrate) {
    pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
    pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later)
    pn532_packetbuffer[2] = cardbaudrate;

    if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
        return 0x0;  // command failed
    }
}

! You do not have to use logic level shifter, it works with 5V because you only detect voltage FALLING of the IRQ pin.
The basic voltage between the IRQ and the separated 5V line is about 3,1V. If a card is presented then the voltage goes down to 2,7V.
I only tested it with SPI. It works with electhouse's and Adafruit's PN532 breakout shield too.

#include <PN532_SPI.h>
#include <PN532.h>
//MEGA
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
PN532_SPI pn532spi(SPI, 53);
//UNO
#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
PN532_SPI pn532spi(SPI, 10);
#endif

#define PN532IRQPIN (2)

volatile boolean cState = false;

PN532 nfc(pn532spi);

void cardreading();

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("\nHello!");
  nfc.begin();
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  // Got ok 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);
  
  Serial.println(cState);
  attachInterrupt(digitalPinToInterrupt(PN532IRQPIN), cardreading, FALLING);
  //It generates interrupt, I do not really know why?!
  nfc.SAMConfig();
}

void loop() {
  // put your main code here, to run repeatedly:
  if(cState)
  {
    
    Serial.println("Interrupted");
    

    uint8_t 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)
    // 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, &uidLength);
    
    if (success)
    {
      // Display some basic information about the card
      Serial.println("Found an ISO14443A card");
      Serial.print("  UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
      Serial.print("  UID Value: ");
      nfc.PrintHex(uid, uidLength);
      
    }
    //This must be called or IRQ won't work!
    nfc.startPassiveTargetIDDetection(PN532_MIFARE_ISO14443A);
    cState = false;
    Serial.print("OUT: ");
    Serial.println(cState);
  }
  
}
void cardreading()
{
  
  cState = true;
  
}

Total and utter rubbish. You seem to be happy wallowing in your ignorance. You have a poor grip of the way electricity works.

So what post was that then? Was it the original post #1? The post the rules specifically ask you not to change? Goes with the rest of your attitude as far as I can see.
Anyway welcome to my ignore list.

I do not really know why you are prejudiced about me. If you do not know me, then do not say unrelevant things about me... I have just proof that you do not have to use logic level shifter for that. Futhermore, I wrote down the solution. I feel that you are so arrogant, because I have mentioned that you haven’t checked my code, where the problem occured…

It’s in the original post with my pastebin link, I did not edit that part.

Btw, I do not want to respond all of your comments. The problem was solved, and I posted the solution for other people. You can manage your list of ignored people, but I would rather deal with some professional things.

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