adafruit / Adafruit-PN532

Arduino library for SPI and I2C access to the PN532 RFID/Near Field Communication chip
Other
426 stars 266 forks source link

Receiving Response instead of ACK #85

Closed joshwapohlmann closed 1 year ago

joshwapohlmann commented 3 years ago

Using ESP32 dev kit, Platformio, library version 1.2.2

During initialization I receive the following sequence instead of an ACK

0x0 0x3F 0xDF 0xFF 0xE9 0xAF

The code executed so far is

Adafruit_PN532 nfc(PN532_SS);
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();

With build_flags = -DPN532DEBUG the serial monitor shows

Sending : 0x0, 0x0, 0xFF, 0x2, 0xFE, 0xD4, 0x2, 0x2A, 0x0, 
Sending : 0x0, 0x0, 0xFF, 0x2, 0xFE, 0xD4, 0x2, 0x2A, 0x0, 
No ACK:  0x0 0x3F 0xDF 0xFF 0xE9 0xAF
No ACK frame received!

I checked the PN532 user manual. Normally, whatever state it is in, it should abort ANY prior command when receiving a new command (page 38). This is clearly the case (i also checked with a logic analyzer) when retrieving the firmware version.

After this, the code correctly waits for the IC to be ready

// Wait for chip to say its ready!
  if (!waitready(timeout)) {
    return false;
  }

where it reads the status register until it is RDY.

After this, bool Adafruit_PN532::readack() is called. In the manual on page 45 the procedure is explained.

The code follow this exactly

if (spi_dev) {
    uint8_t cmd = PN532_SPI_DATAREAD;
    spi_dev->write_then_read(&cmd, 1, ackbuff, 6);
  }

According to the manual, even in case of a syntax error, it will respond with an ACK. This means, the received data is the response to a prior command. Therefore an ACK was missed. It is unclear how and where it happens.

joshwapohlmann commented 3 years ago

So, I commited this issue because I just found the solution. The manual states there are 2 ways to abort an operation (and to get back to a clean state).

  1. One is seen above, where simply a new command is send.
  2. The other one is to send an ACK from host to the PN532.

This solved my issue AND another issue I had reading out an NTAG213. How? I simply added a sendAck() function and execute it manually:

  1. once after nfc.init()
  2. and right before reading data with nfc.ntag2xx_ReadPage(...);

For completeness, here the code snippet I added to the library

/**************************************************************************/
/*!
    @brief  Sends an ACK to the PN532 causing it to abort the current operation and wait for a new command
*/
/**************************************************************************/
bool Adafruit_PN532::sendAck() {
  uint8_t cmd = PN532_SPI_DATAWRITE;
  spi_dev->write(pn532ack, 6, &cmd, 1);
  return true;
}

A pull request will follow

solhuebner commented 3 years ago

@joshwapohlmann thanks for providing this solution :) I would like to add it to my fork but if you would submit the mentioned PR I could use that and give you credit that way :)

solhuebner commented 3 years ago

I added it to play around with it but if I use it before nfc.ntag2xx_ReadPage(...); my PN532 hangs. Maybe you need to provide more details?

joshwapohlmann commented 3 years ago

Next time I play with it I will make some tests and also check in my exact changes I'm using right now.

caternuson commented 1 year ago

Closing. Looks resolved.