I am currently trying to write a few bytes from the PN532 to NTAG213's user-programmable memory and read back those bytes as well. The write and read happens when the PN532 detects the NTAG213 within proximity. I have ported the necessary functions from the Adafruits library here for the ATxmega32A4U. To scan and read an NTAG213 card, I am using the below functions.
// Reads cards, beep and long light flash for good card read, short light flash for no card read, lights mostly on for NFC chip not talking right
void TestNFC_ReadTag (void) {
bool 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)
/************************************ Everytime Try Reading a Card ***********************************/
// Check for a good card read
success = PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength, 1000);
// If card read is good then beep and long flash of main lights
if (success) {
LIGHT_ON();
EventTimerCreate(200,1,TestingLightsOff);
for (int nfcBeep = 0; nfcBeep < 300; nfcBeep++) {
DACB.CH0DATA = 0x700;
_delay_us(200);
DACB.CH0DATA = 0x900;
_delay_us(200);
}
DACB.CH0DATA = 0x800;
_delay_ms(500); // Reduced from 1000ms to 500ms to avoid WDT reset - Vinay
}
// If valid card read then short light flash no beep
else {
LIGHT_ON();
_delay_ms(10);
LIGHT_OFF();
}
}
/**************************************************************************/
/*!
Waits for an ISO14443A target to enter the field
@param cardBaudRate Baud rate of the card
@param uid Pointer to the array that will be populated
with the card's UID (up to 7 bytes)
@param uidLength Pointer to the variable that will hold the
length of the card's UID.
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
bool PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout)
{
// read data packet
if (PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) {
return 0x0;
}
// check some basic stuff
/* ISO14443A card response should be in the following format:
byte Description
------------- ------------------------------------------
b0 Tags Found
b1 Tag Number (only one used in this example)
b2..3 SENS_RES
b4 SEL_RES
b5 NFCID Length
b6..NFCIDLen NFCID
*/
if (pn532_packetbuffer[0] != 1)
return 0;
uint16_t sens_res = pn532_packetbuffer[2];
sens_res <<= 8;
sens_res |= pn532_packetbuffer[3];
DMSG("ATQA: 0x"); DMSG_HEX(sens_res);
DMSG("SAK: 0x"); DMSG_HEX(pn532_packetbuffer[4]);
DMSG("\r\n");
/* Card appears to be Mifare Classic */
*uidLength = pn532_packetbuffer[5];
for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) {
uid[i] = pn532_packetbuffer[6 + i];
}
return 1;
}
/**************************************************************************/
/*!
@brief Starts the scan
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532_StartScan(void)
{
uint8_t pn532_packetbuffer[2];
uint8_t ret = 0;
pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
pn532_packetbuffer[1] = 1;
pn532_packetbuffer[2] = PN532_MIFARE_ISO14443A;
/* Disable the interrupt */
PORTA.INT1MASK &= ~(1<<PIN7_bp);
/* Send scan command and read acknowledgments */
if (PN532_writeCommand(pn532_packetbuffer, 3, NULL, 0))
ret = 0x0; // command failed
else
ret = 0x01;
/* Enable the interrupt */
PORTA.INT1MASK |= PIN7_bm;
return(ret);
}
To write to and read from the NTAG213's memory. I use the below functions.
/**************************************************************************/
/*!
Tries to write an entire 4-bytes data buffer at the specified page
address.
@param page The page number to write into. (0x04..0x27).
@param buffer The byte array that contains the data to write.
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t PN532_writePage (uint8_t page, uint8_t *buffer)
{
if ((page < NTAG_PAGE_START_ADDRESS) || (page > NTAG_PAGE_END_ADDRESS)) {
DMSG("Page value out of range\n");
return 0;
}
/* Prepare the first command */
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Card number */
pn532_packetbuffer[1] = 1;
pn532_packetbuffer[2] = NTAG_CMD_WRITE_USER_EEPROM; /* NTAG213 Write cmd = 0xA2 */
pn532_packetbuffer[3] = page; /* page Number (0x04..0x27) */
memcpy (pn532_packetbuffer + 4, buffer, 4); /* Data Payload */
/* Send command to write to NTAG 213 EEPROM */
if (PN532_writeCommand(pn532_packetbuffer, 8, NULL, 0))
return 0;
/* Read the response packet */
if(PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), 100) < 0)
return 0;
return 1;
}
/**************************************************************************/
/*!
Tries to read an entire 4-bytes page at the specified address.
@param page The page number ((0x04..0x27 in most cases)
@param buffer Pointer to the byte array that will hold the
retrieved data (if any)
*/
/**************************************************************************/
uint8_t PN532_readPage (uint8_t page, uint8_t *buffer)
{
if ((page < NTAG_PAGE_START_ADDRESS) || (page > NTAG_PAGE_END_ADDRESS)) {
DMSG("Page value out of range\n");
return 0;
}
/* Prepare the command */
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
pn532_packetbuffer[1] = 1; /* Card number */
pn532_packetbuffer[2] = NTAG_CMD_READ_USER_EEPROM; /* NTAG Read command = 0x30 */
pn532_packetbuffer[3] = page; /* page Number (0x04..0x27) */
/* Send the command */
if (PN532_writeCommand(pn532_packetbuffer, 4, NULL, 0))
return 0;
/* Read the response packet */
//if(PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), 100))
if(PN532_readResponse(pn532_packetbuffer, 20, 100) < 0)
return 0;
#ifdef PN532_PGREAD_DBG
printf("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\r\n",
pn532_packetbuffer[0], pn532_packetbuffer[1], pn532_packetbuffer[2], pn532_packetbuffer[3],
pn532_packetbuffer[4], pn532_packetbuffer[5], pn532_packetbuffer[6], pn532_packetbuffer[7],
pn532_packetbuffer[8], pn532_packetbuffer[9], pn532_packetbuffer[10], pn532_packetbuffer[11],
pn532_packetbuffer[12], pn532_packetbuffer[13], pn532_packetbuffer[14], pn532_packetbuffer[15],
pn532_packetbuffer[16], pn532_packetbuffer[17], pn532_packetbuffer[18]);
#endif
/* If the status isn't 0x00 we probably have an error */
if (pn532_packetbuffer[0] == 0x00) {
/* Copy the 4 data bytes to the output buffer */
/* Block content starts at byte 1 of a valid response */
/* Note that the command actually reads 16 bytes or 4 */
/* pages at a time ... we simply discard the last 12 */
/* bytes */
memcpy (buffer, pn532_packetbuffer + 1, 4);
}
else {
return 0;
}
// Return OK signal
return 1;
}
I was performing some tests and came across some issues when tried to read from the NTAG.
The below test code works meaning: The PN532 is able to read the card as well as write and read back the user data from the NTAG.
void TestNFCInterrupt_ReadTag (void){
static uint8_t flag = 0;
/* Test code. Always perform read or write prior to getting the uuid */
if(flag == 0){
testPN532WritePage();
flag = 1;
}
else{
testPN532ReadPage();
flag = 0;
}
/* Needs to restart the scan to detect the NTAG passively */
PN532_StartScan();
TestNFC_ReadTag();
PN532_StartScan();
}
But surprisingly, for the below code, the card is detected, the write works, but when next the read happens after the card is detected, I get a status error response as 0x27 which indicates that the command is not acceptable due to the current context of the PN532, this can be seen on page 68 of the PN532 user manual.
void TestNFCInterrupt_ReadTag (void){
static uint8_t flag = 0;
TestNFC_ReadTag();
/* Test code. Always perform read or write prior to getting the uuid */
if(flag == 0){
testPN532WritePage();
flag = 1;
}
else{
testPN532ReadPage();
flag = 0;
}
/* Needs to restart the scan to detect the NTAG passively */
PN532_StartScan();
}
Also, here is the NTAG213 manual. Apologies for the exhaustive post, but taught the above information is necessary to seek help. I'd appreciate if anyone could take some time to check the code or suggest anything.