pdf-icon

RFID

M5Dial RFID uses MFRC522 library as the driver, refer to the following API & examples to realize simple display, get more API content can refer to MFRC522 source code.

Example

Scanning UID Example

#include "M5Dial.h"

void setup() {
    auto cfg = M5.config();
    M5Dial.begin(cfg, false, true);
}

void loop() {
    if (M5Dial.Rfid.PICC_IsNewCardPresent() &&
        M5Dial.Rfid.PICC_ReadCardSerial()) {
        M5Dial.Display.clear();

        Serial.print(F("PICC type: "));
        uint8_t piccType = M5Dial.Rfid.PICC_GetType(M5Dial.Rfid.uid.sak);
        Serial.println(M5Dial.Rfid.PICC_GetTypeName(piccType));

        // Check is the PICC of Classic MIFARE type
        if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&
            piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
            piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
            Serial.println(F("Your tag is not of type MIFARE Classic."));
            return;
        }
        for (byte i = 0; i < M5Dial.Rfid.uid.size;
             i++) {  // Output the stored UID data. 
            Serial.printf("%02X ", M5Dial.Rfid.uid.uidByte[i]);
        }
        Serial.println();
    }
}

Read/Write Card Example

#include "M5Dial.h"

MFRC522::MIFARE_Key key;

void setup() {
    auto cfg = M5.config();
    M5Dial.begin(cfg, false, true);
    // Prepare the key (used both as key A and as key B)
    // using FFFFFFFFFFFFh which is the default at chip delivery from the factory
    for (byte i = 0; i < 6; i++) {
        key.keyByte[i] = 0xFF;
    }
}

/**
 * Helper routine to dump a byte array as hex values to Serial.
 */
void dump_byte_array(byte *buffer, byte bufferSize) {
    for (byte i = 0; i < bufferSize; i++) {
        Serial.print(buffer[i] < 0x10 ? " 0" : " ");
        Serial.print(buffer[i], HEX);
    }
}

void loop() {
    M5Dial.update();
    if (M5Dial.Rfid.PICC_IsNewCardPresent() && M5Dial.Rfid.PICC_ReadCardSerial()) {
        Serial.print(F("PICC type: "));
        uint8_t piccType = M5Dial.Rfid.PICC_GetType(M5Dial.Rfid.uid.sak);
        Serial.println(M5Dial.Rfid.PICC_GetTypeName(piccType));

        // Check is the PICC of Classic MIFARE type
        if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI && piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
            piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
            Serial.println(F("Your tag is not of type MIFARE Classic."));
            return;
        }
        String uid = "";
        for (byte i = 0; i < M5Dial.Rfid.uid.size; i++) {  // Output the stored UID data.  将存储的UID数据输出
            Serial.printf("%02X ", M5Dial.Rfid.uid.uidByte[i]);
            uid += String(M5Dial.Rfid.uid.uidByte[i], HEX);
        }
        Serial.println();
        // M5Dial.Rfid.PICC_DumpToSerial(&(M5Dial.Rfid.uid));

        // In this sample we use the second sector,
        // that is: sector #1, covering block #4 up to and including block #7
        byte sector      = 1;
        byte blockAddr   = 4;
        byte dataBlock[] = {
            0x01, 0x02, 0x03, 0x04,  //  1,  2,   3,  4,
            0x05, 0x06, 0x07, 0x08,  //  5,  6,   7,  8,
            0x09, 0x0a, 0xff, 0x0b,  //  9, 10, 255, 11,
            0x0c, 0x0d, 0x0e, 0x0f   // 12, 13, 14, 15
        };
        byte trailerBlock = 7;
        MFRC522::StatusCode status;
        byte buffer[18];
        byte size = sizeof(buffer);

        // Authenticate using key A
        Serial.println(F("Authenticating using key A..."));
        status = (MFRC522::StatusCode)M5Dial.Rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key,
                                                                   &(M5Dial.Rfid.uid));
        if (status != MFRC522::STATUS_OK) {
            Serial.print(F("PCD_Authenticate() failed: "));
            Serial.println(M5Dial.Rfid.GetStatusCodeName(status));
            return;
        }

        // Show the whole sector as it currently is
        Serial.println(F("Current data in sector:"));
        M5Dial.Rfid.PICC_DumpMifareClassicSectorToSerial(&(M5Dial.Rfid.uid), &key, sector);
        Serial.println();

        // Read data from the block
        Serial.print(F("Reading data from block "));
        Serial.print(blockAddr);
        Serial.println(F(" ..."));
        status = (MFRC522::StatusCode)M5Dial.Rfid.MIFARE_Read(blockAddr, buffer, &size);
        if (status != MFRC522::STATUS_OK) {
            Serial.print(F("MIFARE_Read() failed: "));
            Serial.println(M5Dial.Rfid.GetStatusCodeName(status));
        }
        Serial.print(F("Data in block "));
        Serial.print(blockAddr);
        Serial.println(F(":"));
        dump_byte_array(buffer, 16);
        Serial.println();
        Serial.println();

        // Authenticate using key B
        Serial.println(F("Authenticating again using key B..."));
        status = (MFRC522::StatusCode)M5Dial.Rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key,
                                                                   &(M5Dial.Rfid.uid));
        if (status != MFRC522::STATUS_OK) {
            Serial.print(F("PCD_Authenticate() failed: "));
            Serial.println(M5Dial.Rfid.GetStatusCodeName(status));
            return;
        }

        // Write data to the block
        Serial.print(F("Writing data into block "));
        Serial.print(blockAddr);
        Serial.println(F(" ..."));
        dump_byte_array(dataBlock, 16);
        Serial.println();
        status = (MFRC522::StatusCode)M5Dial.Rfid.MIFARE_Write(blockAddr, dataBlock, 16);
        if (status != MFRC522::STATUS_OK) {
            Serial.print(F("MIFARE_Write() failed: "));
            Serial.println(M5Dial.Rfid.GetStatusCodeName(status));
        }
        Serial.println();

        // Read data from the block (again, should now be what we have written)
        Serial.print(F("Reading data from block "));
        Serial.print(blockAddr);
        Serial.println(F(" ..."));
        status = (MFRC522::StatusCode)M5Dial.Rfid.MIFARE_Read(blockAddr, buffer, &size);
        if (status != MFRC522::STATUS_OK) {
            Serial.print(F("MIFARE_Read() failed: "));
            Serial.println(M5Dial.Rfid.GetStatusCodeName(status));
        }
        Serial.print(F("Data in block "));
        Serial.print(blockAddr);
        Serial.println(F(":"));
        dump_byte_array(buffer, 16);
        Serial.println();

        // Check that data in block is what we have written
        // by counting the number of bytes that are equal
        Serial.println(F("Checking result..."));
        byte count = 0;
        for (byte i = 0; i < 16; i++) {
            // Compare buffer (= what we've read) with dataBlock (= what we've written)
            if (buffer[i] == dataBlock[i]) count++;
        }
        Serial.print(F("Number of bytes that match = "));
        Serial.println(count);
        if (count == 16) {
            Serial.println(F("Success :-)"));
        } else {
            Serial.println(F("Failure, no match :-("));
            Serial.println(F("  perhaps the write didn't work properly..."));
        }
        Serial.println();

        // Dump the sector data
        Serial.println(F("Current data in sector:"));
        M5Dial.Rfid.PICC_DumpMifareClassicSectorToSerial(&(M5Dial.Rfid.uid), &key, sector);
        Serial.println();

        // Halt PICC
        M5Dial.Rfid.PICC_HaltA();
        // Stop encryption on PCD
        M5Dial.Rfid.PCD_StopCrypto1();
    }
}

  • 读写案例输出, 可以看到扇区1的4号block被成功写入数据。
« PICC type: MIFARE 1KB
C2 34 D4 44 
Authenticating using key A...
Current data in sector:
   1      7   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 
          6   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 
          5   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 
          4   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

Reading data from block 4 ...
Data in block 4:
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Authenticating again using key B...
Writing data into block 4 ...
 01 02 03 04 05 06 07 08 09 0A FF 0B 0C 0D 0E 0F

Reading data from block 4 ...
Data in block 4:
 01 02 03 04 05 06 07 08 09 0A FF 0B 0C 0D 0E 0F
Checking result...
Number of bytes that match = 16
Success :-)

Current data in sector:
   1      7   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 
          6   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 
          5   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 
          4   01 02 03 04  05 06 07 08  09 0A FF 0B  0C 0D 0E 0F  [ 0 0 0 ] 

INIT API

The following is the use of common API instructions, general read and write MIFARE card using the process as follows.

    1. initialize RFID
    1. detect the existence of new cards, get the card uid
    1. select the card through the uid, enter the active state
    1. through the A,B KEY to unlock the corresponding block to be operated
    1. read and write data
    1. control the card to enter the dormant state

Operation return value status code

enum StatusCode {
    STATUS_OK                = 1,    // Success
    STATUS_ERROR            = 2,    // Error in communication
    STATUS_COLLISION        = 3,    // Collission detected
    STATUS_TIMEOUT            = 4,    // Timeout in communication.
    STATUS_NO_ROOM            = 5,    // A buffer is not big enough.
    STATUS_INTERNAL_ERROR    = 6,    // Internal error in the code. Should not happen ;-)
    STATUS_INVALID            = 7,    // Invalid argument.
    STATUS_CRC_WRONG        = 8,    // The CRC_A does not match
    STATUS_MIFARE_NACK        = 9        // A MIFARE PICC responded with NAK.
};

begin

Syntax:

void begin();

Description:

  • Initialize RFID

It can be initialized by setting the parameter enableRFID to true when calling M5Dial.begin.

M5Dial.begin(m5::M5Unified::config_t cfg, bool enableEncoder,bool enableRFID)

Parameters:

  • null

Return:

  • null

PICC_IsNewCardPresent

Syntax:

bool PICC_IsNewCardPresent();

Description:

  • Scans for the presence of cards that have not been detected and are in the IDLE state, cards in the HALT state are ignored.

Parameters:

  • null

Return:

  • bool:
    • true:New card scanned.
    • false:No new cards scanned

PICC_ReadCardSerial

Syntax:

bool PICC_ReadCardSerial();

Description:

  • The operation reads the card UID, the UID after successful reading can be read in class member Uid uid;. Before read operation, PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() should be executed to make sure the card is read.
for (byte i = 0; i < M5Dial.Rfid.uid.size;
     i++) {  // Output the stored UID data. 
    Serial.printf("%02X ", M5Dial.Rfid.uid.uidByte[i]);
}

Parameters:

  • null

Return:

  • bool:
    • true:Read successfully
    • false:Failed to read

PICC_RequestA

Syntax:

uint8_t PICC_RequestA(uint8_t *bufferATQA, uint8_t *bufferSize);

Description:

  • Scanning detects cards of Type A standard within reading range

Parameters:

  • uint8_t *bufferATQA:
    • Storage Request Response ATQA (Answer to request) 的buffer
  • uint8_t *bufferSize:
    • buffer Size(>2byte).

Return:

  • uint8_t:
    • StatusCode

PICC_WakeupA

Syntax:

uint8_t PICC_WakeupA(uint8_t *bufferATQA, uint8_t *bufferSize);

Description:

  • Wake up range of Type A compliant cards

Parameters:

  • uint8_t *bufferATQA:
    • Storage Request Response ATQA (Answer to request) 的buffer
  • uint8_t *bufferSize:
    • buffer Size(>2byte).

Return:

  • uint8_t:
    • StatusCode

PICC_Select

Syntax:

uint8_t PICC_Select(Uid *uid, uint8_t validBits = 0);

Description:

  • Select a card by uid to enter active state

Parameters:

  • Uid *uid:
    • Pointer to the card uid structure obtained through scanning
  • uint8_t validBits:
    • Valid bits in the last uint8_t, 0 means 8 valid bits.

Return:

  • uint8_t:
    • StatusCode

PICC_HaltA

Syntax:

uint8_t PICC_HaltA();

Description:

  • Select the current card to enter the hibernation state

Parameters:

  • null

Return:

  • uint8_t:
    • StatusCode

MIFARE API

PCD_Authenticate

Syntax:

uint8_t PCD_Authenticate(uint8_t command, uint8_t blockAddr, MIFARE_Key *key, Uid *uid);

Description:

  • For MIFARE authentication, before calling this function, you need to select the card to make it active. Call PCD_StopCrypto1() after the authenticated PICC communication is finished, otherwise a new communication cannot be started.

Parameters:

  • uint8_t command:
    • PICC_CMD_MF_AUTH_KEY_A
    • PICC_CMD_MF_AUTH_KEY_B
  • uint8_t blockAddr:
    • Block Address
  • MIFARE_Key *key:
    • By default, A,B keys are FFFFFFFFFFFFFFF.
  • Uid *uid

Return:

  • uint8_t:
    • StatusCode

PCD_StopCrypto1

Syntax:

void PCD_StopCrypto1();

Description:

  • Exit the authentication state of the PCD. PCD_StopCrypto1() must be called after the authenticated PICC communication is finished, otherwise a new communication cannot be started.

Parameters:

  • null

Return:

  • null

MIFARE_Read

Syntax:

uint8_t MIFARE_Read(uint8_t blockAddr, uint8_t *buffer, uint8_t *bufferSize);

Description:

  • Write data to the specified block addr

Parameters:

  • uint8_t blockAddr:
    • Block address in the actual card sector
  • uint8_t *buffer:
    • Pointer to the buffer that receives the data
  • uint8_t *bufferSize:
    • Length of buffer to receive data (>=18byte)

Return:

  • uint8_t:
    • StatusCode

MIFARE_Write

Syntax:

uint8_t MIFARE_Write(uint8_t blockAddr, uint8_t *buffer, uint8_t bufferSize);

Description:

  • Write data to the specified block addr

Parameters:

  • uint8_t blockAddr:
    • Block address in the actual card sector
  • uint8_t *buffer:
    • data pointer
  • uint8_t *bufferSize:
    • data length(16byte)

Return:

  • uint8_t:
    • StatusCode
On This Page