3

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.

3
  • 2
    This sounds much more like a hardware/software debug problem than something specific to IoT. I'm not sure it's really suitable to any SE site as is though. Commented May 4, 2018 at 16:07
  • 1
    Nevermind, the problem is solved. It was a timing issue. Commented May 5, 2018 at 0:29
  • 1
    @VinayDivakar Feel free to post your solution below as an answer so that you can mark this as resolved and potentially help future visitors with a similar problem.
    – Aurora0001
    Commented May 5, 2018 at 8:12

1 Answer 1

6

After a while of debugging and going through the code, I got to know that the problem was happening due to the Audio beeps on detection/reading a new card within the void TestNFC_ReadTag (void) function which was causing some intermediate delay between the time the UUID was read and the subsequent call to the read/write page API. So to write to or read from the NTAGs user memory, it is always necessary to issue the INDATAEXCHANGE command and invoke the read/write page immediately after the tag is read. So, I made some slight changes to the void TestNFC_ReadTag (void) function to meet this requirement and it works. The below is the changes I made:

/* Made these as static global variables */
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)



// 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;
    static flag = 0;

    /************************************ Everytime Try Reading a Card ***********************************/
    // Check for a good card read
    success = PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength, 1000);
    
    if (success) {

        if(flag == 0){
           testPN532WritePage();
           flag = 1;
        }
        else{
           testPN532ReadPage();
           flag = 0;
     }

        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 Invalid card read then short light flash no beep
    else {
        LIGHT_ON();
        _delay_ms(10);
        LIGHT_OFF();
    }
}

void TestNFCInterrupt_ReadTag (void){

    /* Read the tag and write/read to NTAG213 user memory */
    TestNFC_ReadTag();

    /* Needs to restart the scan to detect the NTAG passively */
    PN532_StartScan();
}

I hope this helps!

Not the answer you're looking for? Browse other questions tagged or ask your own question.