#include <M5Unified.h>
#include <MFRC522_I2C.h>
MFRC522_I2C mfrc522(0x28, -1); // 0x28: I2C address of Unit RFID / RFID2; -1: reset pin (not connected)
void setup() {
M5.begin();
Serial.begin(115200);
mfrc522.PCD_Init();
}
void loop() {
M5.update();
// PICC: Proximity Integrated Circuit Card
if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
M5.Display.clear();
uint8_t piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
Serial.print(F("PICC type: "));
Serial.println(mfrc522.PICC_GetTypeName(piccType));
// Check if the tag / card is of type MIFARE Classic
if (piccType != MFRC522_I2C::PICC_TYPE_MIFARE_MINI
&& piccType != MFRC522_I2C::PICC_TYPE_MIFARE_1K
&& piccType != MFRC522_I2C::PICC_TYPE_MIFARE_4K) {
Serial.println(F("This tag / card is not of type MIFARE Classic.\n"));
delay(500);
return;
}
// Output the stored UID data
for (byte i = 0; i < mfrc522.uid.size; i++) {
Serial.printf("%02X ", mfrc522.uid.uidByte[i]);
}
Serial.println("\n");
delay(500);
}
}
#include <M5Unified.h>
#include <MFRC522_I2C.h>
MFRC522_I2C mfrc522(0x28, -1); // 0x28: I2C address of Unit RFID / RFID2; -1: reset pin (not connected)
MFRC522_I2C::MIFARE_Key key;
void setup() {
M5.begin();
Serial.begin(115200);
mfrc522.PCD_Init();
// Prepare the key (used both as key A and as key B) with 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.printf("%02X ", buffer[i]);
}
}
void loop() {
M5.update();
// PICC: Proximity Integrated Circuit Card
if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
M5.Display.clear();
uint8_t piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
Serial.print(F("PICC type: "));
Serial.println(mfrc522.PICC_GetTypeName(piccType));
// Check if the tag / card is of type MIFARE Classic
if (piccType != MFRC522_I2C::PICC_TYPE_MIFARE_MINI
&& piccType != MFRC522_I2C::PICC_TYPE_MIFARE_1K
&& piccType != MFRC522_I2C::PICC_TYPE_MIFARE_4K) {
Serial.println(F("This tag / card is not of type MIFARE Classic.\n"));
delay(500);
return;
}
// Output the stored UID data
String uid = "";
for (byte i = 0; i < mfrc522.uid.size; i++) {
Serial.printf("%02X ", mfrc522.uid.uidByte[i]);
uid += String(mfrc522.uid.uidByte[i], HEX);
}
Serial.println("\n");
// mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
// Serial.println("\n");
// In this example, we use the second sector (sector #1) including blocks #4, #5, #6, #7
byte sector = 1;
byte blockAddr = 4;
byte trailerBlock = 7;
byte dataBlock[] = {
0x01, 0x02, 0x03, 0x04, // 1, 2, 3, 4,
0x05, 0x06, 0x07, 0x08, // 5, 6, 7, 8,
0x09, 0x0a, 0x0b, 0x0c, // 9, 10, 11, 12,
0x0d, 0x0e, 0x0f, 0xff // 13, 14, 15, 255
};
MFRC522_I2C::StatusCode status;
byte buffer[18];
byte size = sizeof(buffer);
// Authenticate using key A
Serial.println(F("Authenticating using key A..."));
status = (MFRC522_I2C::StatusCode)mfrc522.PCD_Authenticate(MFRC522_I2C::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522_I2C::STATUS_OK) {
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
// Show the whole sector as it currently is
Serial.println(F("Current data in sector: "));
mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.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_I2C::StatusCode)mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522_I2C::STATUS_OK) {
Serial.print(F("MIFARE_Read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.print(F("Data in block #"));
Serial.print(blockAddr);
Serial.println(F(": "));
dump_byte_array(buffer, 16);
Serial.println("\n");
// Authenticate using key B
Serial.println(F("Authenticating again using key B..."));
status = (MFRC522_I2C::StatusCode)mfrc522.PCD_Authenticate(MFRC522_I2C::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522_I2C::STATUS_OK) {
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(mfrc522.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_I2C::StatusCode)mfrc522.MIFARE_Write(blockAddr, dataBlock, 16);
if (status != MFRC522_I2C::STATUS_OK) {
Serial.print(F("MIFARE_Write() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.println("");
// Read data from the block again, now it should be what we have written
Serial.print(F("Reading data from block #"));
Serial.print(blockAddr);
Serial.println(F(" ..."));
status = (MFRC522_I2C::StatusCode)mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522_I2C::STATUS_OK) {
Serial.print(F("MIFARE_Read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.print(F("Data in block #"));
Serial.print(blockAddr);
Serial.println(F(": "));
dump_byte_array(buffer, 16);
Serial.println("\n");
// Check if the 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: "));
mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
Serial.println("");
// Halt PICC
mfrc522.PICC_HaltA();
// Stop encryption on PCD
mfrc522.PCD_StopCrypto1();
Serial.println("====================");
}
}
This program reads the data from Block 4 in Sector 1 after completing Key A authentication, and then modifies the data of Block 4 in Sector 1 after completing Key B authentication. During this process, the tag / card must remain close to Unit RFID2. The program output is as follows:
Below are usage notes for the common APIs. A typical flow for reading / writing a MIFARE card is:
Operation return status codes
enum StatusCode {
STATUS_OK = 1, // Success
STATUS_ERROR = 2, // Error in communication
STATUS_COLLISION = 3, // Collision detected
STATUS_TIMEOUT = 4, // Timeout in communication
STATUS_NO_ROOM = 5, // The 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 // The MIFARE PICC responded with NAK
};
Function Prototype:
MFRC522_I2C(byte chipAddress, byte resetPowerDownPin);
Description:
Input parameters:
Return value:
Function prototype:
void PCD_Init();
Function Description:
Input Parameters:
Return Value:
Function Prototype:
bool PICC_IsNewCardPresent();
Description:
IDLE
state. Cards in the HALT
state will be ignored.Input Parameters:
Return Value:
Function Prototype:
bool PICC_ReadCardSerial();
Description:
Uid uid;
. Before performing the read operation, you must call PICC_IsNewCardPresent()
, PICC_RequestA()
, or PICC_WakeupA()
to ensure a card is detected.for (byte i = 0; i < mfrc522.uid.size; i++) {
Serial.printf("%02X ", mfrc522.uid.uidByte[i]);
}
Input Parameters:
Return Value:
Function Prototype:
uint8_t PICC_RequestA(uint8_t *bufferATQA, uint8_t *bufferSize);
Description:
Input Parameters:
Return Value:
Function Prototype:
uint8_t PICC_WakeupA(uint8_t *bufferATQA, uint8_t *bufferSize);
Description:
Input Parameters:
Return Value:
Function Prototype:
uint8_t PICC_Select(Uid *uid, uint8_t validBits = 0);
Description:
Input Parameters:
Return Value:
Function Prototype:
uint8_t PICC_HaltA();
Description:
Input Parameters:
Return Value:
Function Prototype:
uint8_t PCD_Authenticate(uint8_t command, uint8_t blockAddr, MIFARE_Key *key, Uid *uid);
Description:
PCD_StopCrypto1()
; otherwise, new communication cannot be started.Input Parameters:
FFFFFFFFFFFF
Return Value:
Function Prototype:
void PCD_StopCrypto1();
Description:
PCD_StopCrypto1()
; otherwise, new communication cannot be started.Input Parameters:
Return Value:
Function Prototype:
uint8_t MIFARE_Read(uint8_t blockAddr, uint8_t *buffer, uint8_t *bufferSize);
Description:
Input Parameters:
Return Value:
Function Prototype:
uint8_t MIFARE_Write(uint8_t blockAddr, uint8_t *buffer, uint8_t bufferSize);
Description:
Input Parameters:
Return Value: