diff --git a/MFRC522.cpp b/MFRC522.cpp index 3e8d084..770a6f2 100644 --- a/MFRC522.cpp +++ b/MFRC522.cpp @@ -18,18 +18,8 @@ MFRC522::MFRC522( byte chipSelectPin, ///< Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low) byte resetPowerDownPin ///< Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) ) { - // Set the chipSelectPin as digital output, do not select the slave yet _chipSelectPin = chipSelectPin; - pinMode(_chipSelectPin, OUTPUT); - digitalWrite(_chipSelectPin, HIGH); - - // Set the resetPowerDownPin as digital output, do not reset or power down. _resetPowerDownPin = resetPowerDownPin; - pinMode(_resetPowerDownPin, OUTPUT); - digitalWrite(_resetPowerDownPin, LOW); - - // Set SPI bus to work with MFRC522 chip. - setSPIConfig(); } // End constructor /** @@ -100,7 +90,7 @@ void MFRC522::PCD_ReadRegister( byte reg, ///< The register to read from. One o if (count == 0) { return; } - //Serial.print("Reading "); Serial.print(count); Serial.println(" bytes from register."); + //Serial.print(F("Reading ")); Serial.print(count); Serial.println(F(" bytes from register.")); byte address = 0x80 | (reg & 0x7E); // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. byte index = 0; // Index in values array. digitalWrite(_chipSelectPin, LOW); // Select slave @@ -194,6 +184,16 @@ byte MFRC522::PCD_CalculateCRC( byte *data, ///< In: Pointer to the data to tra * Initializes the MFRC522 chip. */ void MFRC522::PCD_Init() { + // Set the chipSelectPin as digital output, do not select the slave yet + pinMode(_chipSelectPin, OUTPUT); + digitalWrite(_chipSelectPin, HIGH); + + // Set the resetPowerDownPin as digital output, do not reset or power down. + pinMode(_resetPowerDownPin, OUTPUT); + + // Set SPI bus to work with MFRC522 chip. + setSPIConfig(); + if (digitalRead(_resetPowerDownPin) == LOW) { //The MFRC522 chip is in power down mode. digitalWrite(_resetPowerDownPin, HIGH); // Exit power down mode. This triggers a hard reset. // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74�s. Let us be generous: 50ms. @@ -285,9 +285,9 @@ bool MFRC522::PCD_PerformSelfTest() { // 2. Clear the internal buffer by writing 25 bytes of 00h byte ZEROES[25] = {0x00}; - PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // flush the FIFO buffer - PCD_WriteRegister(FIFODataReg, 25, ZEROES); // write 25 bytes of 00h to FIFO - PCD_WriteRegister(CommandReg, PCD_Mem); // transfer to internal buffer + PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // flush the FIFO buffer + PCD_WriteRegister(FIFODataReg, 25, ZEROES); // write 25 bytes of 00h to FIFO + PCD_WriteRegister(CommandReg, PCD_Mem); // transfer to internal buffer // 3. Enable self-test PCD_WriteRegister(AutoTestReg, 0x09); @@ -323,6 +323,12 @@ bool MFRC522::PCD_PerformSelfTest() { // Pick the appropriate reference values const byte *reference; switch (version) { + case 0x88: // Fudan Semiconductor FM17522 clone + reference = FM17522_firmware_reference; + break; + case 0x90: // Version 0.0 + reference = MFRC522_firmware_referenceV0_0; + break; case 0x91: // Version 1.0 reference = MFRC522_firmware_referenceV1_0; break; @@ -545,7 +551,7 @@ byte MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally outp byte count; byte index; byte uidIndex; // The first index in uid->uidByte[] that is used in the current Cascade Level. - char currentLevelKnownBits; // The number of known UID bits in the current Cascade Level. + int8_t currentLevelKnownBits; // The number of known UID bits in the current Cascade Level. byte buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 byte standard frame + 2 bytes CRC_A byte bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO. byte rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received. @@ -641,7 +647,7 @@ byte MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally outp while (!selectDone) { // Find out how many bits and bytes to send and receive. if (currentLevelKnownBits >= 32) { // All UID bits in this Cascade Level are known. This is a SELECT. - //Serial.print("SELECT: currentLevelKnownBits="); Serial.println(currentLevelKnownBits, DEC); + //Serial.print(F("SELECT: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); buffer[1] = 0x70; // NVB - Number of Valid Bits: Seven whole bytes // Calculate BCC - Block Check Character buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; @@ -657,7 +663,7 @@ byte MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally outp responseLength = 3; } else { // This is an ANTICOLLISION. - //Serial.print("ANTICOLLISION: currentLevelKnownBits="); Serial.println(currentLevelKnownBits, DEC); + //Serial.print(F("ANTICOLLISION: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); txLastBits = currentLevelKnownBits % 8; count = currentLevelKnownBits / 8; // Number of whole bytes in the UID part. index = 2 + count; // Number of whole bytes: SEL + NVB + UIDs @@ -1141,6 +1147,7 @@ byte MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointer to the data t /** * Returns a __FlashStringHelper pointer to a status code name. * + * @return const __FlashStringHelper * */ const __FlashStringHelper *MFRC522::GetStatusCodeName(byte code ///< One of the StatusCode enums. ) { @@ -1194,6 +1201,7 @@ byte MFRC522::PICC_GetType(byte sak ///< The SAK byte returned from PICC_Select /** * Returns a __FlashStringHelper pointer to the PICC type name. * + * @return const __FlashStringHelper * */ const __FlashStringHelper *MFRC522::PICC_GetTypeName(byte piccType ///< One of the PICC_Type enums. ) { @@ -1224,7 +1232,10 @@ void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned fro // UID Serial.print(F("Card UID:")); for (byte i = 0; i < uid->size; i++) { - Serial.print(uid->uidByte[i] < 0x10 ? " 0" : " "); + if(uid->uidByte[i] < 0x10) + Serial.print(F(" 0")); + else + Serial.print(F(" ")); Serial.print(uid->uidByte[i], HEX); } Serial.println(); @@ -1299,7 +1310,7 @@ void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid str // Dump sectors, highest address first. if (no_of_sectors) { Serial.println(F("Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits")); - for (char i = no_of_sectors - 1; i >= 0; i--) { + for (int8_t i = no_of_sectors - 1; i >= 0; i--) { PICC_DumpMifareClassicSectorToSerial(uid, key, i); } } @@ -1354,11 +1365,14 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U byte buffer[18]; byte blockAddr; isSectorTrailer = true; - for (char blockOffset = no_of_blocks - 1; blockOffset >= 0; blockOffset--) { + for (int8_t blockOffset = no_of_blocks - 1; blockOffset >= 0; blockOffset--) { blockAddr = firstBlock + blockOffset; // Sector number - only on first line if (isSectorTrailer) { - Serial.print(sector < 10 ? " " : " "); // Pad with spaces + if(sector < 10) + Serial.print(F(" ")); // Pad with spaces + else + Serial.print(F(" ")); // Pad with spaces Serial.print(sector); Serial.print(F(" ")); } @@ -1366,7 +1380,14 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U Serial.print(F(" ")); } // Block number - Serial.print(blockAddr < 10 ? " " : (blockAddr < 100 ? " " : " ")); // Pad with spaces + if(blockAddr < 10) + Serial.print(F(" ")); // Pad with spaces + else { + if(blockAddr < 100) + Serial.print(F(" ")); // Pad with spaces + else + Serial.print(F(" ")); // Pad with spaces + } Serial.print(blockAddr); Serial.print(F(" ")); // Establish encrypted communications before reading the first block @@ -1388,7 +1409,10 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U } // Dump data for (byte index = 0; index < 16; index++) { - Serial.print(buffer[index] < 0x10 ? " 0" : " "); + if(buffer[index] < 0x10) + Serial.print(F(" 0")); + else + Serial.print(F(" ")); Serial.print(buffer[index], HEX); if ((index % 4) == 3) { Serial.print(F(" ")); @@ -1423,8 +1447,8 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U if (firstInGroup) { // Print access bits Serial.print(F(" [ ")); - Serial.print((g[group] >> 2) & 1, DEC); Serial.print(" "); - Serial.print((g[group] >> 1) & 1, DEC); Serial.print(" "); + Serial.print((g[group] >> 2) & 1, DEC); Serial.print(F(" ")); + Serial.print((g[group] >> 1) & 1, DEC); Serial.print(F(" ")); Serial.print((g[group] >> 0) & 1, DEC); Serial.print(F(" ] ")); if (invertedError) { @@ -1466,12 +1490,18 @@ void MFRC522::PICC_DumpMifareUltralightToSerial() { // Dump data for (byte offset = 0; offset < 4; offset++) { i = page + offset; - Serial.print(i < 10 ? " " : " "); // Pad with spaces + if(i < 10) + Serial.print(F(" ")); // Pad with spaces + else + Serial.print(F(" ")); // Pad with spaces Serial.print(i); Serial.print(F(" ")); for (byte index = 0; index < 4; index++) { i = 4 * offset + index; - Serial.print(buffer[i] < 0x10 ? " 0" : " "); + if(buffer[i] < 0x10) + Serial.print(F(" 0")); + else + Serial.print(F(" ")); Serial.print(buffer[i], HEX); } Serial.println(); @@ -1695,6 +1725,7 @@ bool MFRC522::MIFARE_UnbrickUidSector(bool logErrors) { } return false; } + return true; } ///////////////////////////////////////////////////////////////////////////////////// diff --git a/MFRC522.h b/MFRC522.h index c249f85..8a07bf1 100644 --- a/MFRC522.h +++ b/MFRC522.h @@ -58,13 +58,13 @@ * MIFARE Ultralight (MF0ICU1): * Has 16 pages of 4 bytes = 64 bytes. * Pages 0 + 1 is used for the 7-byte UID. - * Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) + * Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. * Pages 4-15 are read/write unless blocked by the lock bytes in page 2. * MIFARE Ultralight C (MF0ICU2): - * Has 48 pages of 4 bytes = 64 bytes. + * Has 48 pages of 4 bytes = 192 bytes. * Pages 0 + 1 is used for the 7-byte UID. - * Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) + * Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. * Pages 4-39 are read/write unless blocked by the lock bytes in page 2. * Page 40 Lock bytes @@ -79,8 +79,23 @@ #include // Firmware data for self-test -// Reference values based on firmware version; taken from 16.1.1 in spec. -// Version 1.0 +// Reference values based on firmware version +// Hint: if needed, you can remove unused self-test data to save flash memory +// +// Version 0.0 (0x90) +// Philips Semiconductors; Preliminary Specification Revision 2.0 - 01 August 2005; 16.1 Sefttest +const byte MFRC522_firmware_referenceV0_0[] PROGMEM = { + 0x00, 0x87, 0x98, 0x0f, 0x49, 0xFF, 0x07, 0x19, + 0xBF, 0x22, 0x30, 0x49, 0x59, 0x63, 0xAD, 0xCA, + 0x7F, 0xE3, 0x4E, 0x03, 0x5C, 0x4E, 0x49, 0x50, + 0x47, 0x9A, 0x37, 0x61, 0xE7, 0xE2, 0xC6, 0x2E, + 0x75, 0x5A, 0xED, 0x04, 0x3D, 0x02, 0x4B, 0x78, + 0x32, 0xFF, 0x58, 0x3B, 0x7C, 0xE9, 0x00, 0x94, + 0xB4, 0x4A, 0x59, 0x5B, 0xFD, 0xC9, 0x29, 0xDF, + 0x35, 0x96, 0x98, 0x9E, 0x4F, 0x30, 0x32, 0x8D +}; +// Version 1.0 (0x91) +// NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 Self test const byte MFRC522_firmware_referenceV1_0[] PROGMEM = { 0x00, 0xC6, 0x37, 0xD5, 0x32, 0xB7, 0x57, 0x5C, 0xC2, 0xD8, 0x7C, 0x4D, 0xD9, 0x70, 0xC7, 0x73, @@ -91,7 +106,8 @@ const byte MFRC522_firmware_referenceV1_0[] PROGMEM = { 0x1F, 0xA7, 0xF3, 0x53, 0x14, 0xDE, 0x7E, 0x02, 0xD9, 0x0F, 0xB5, 0x5E, 0x25, 0x1D, 0x29, 0x79 }; -// Version 2.0 +// Version 2.0 (0x92) +// NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 Self test const byte MFRC522_firmware_referenceV2_0[] PROGMEM = { 0x00, 0xEB, 0x66, 0xBA, 0x57, 0xBF, 0x23, 0x95, 0xD0, 0xE3, 0x0D, 0x3D, 0x27, 0x89, 0x5C, 0xDE, @@ -102,6 +118,18 @@ const byte MFRC522_firmware_referenceV2_0[] PROGMEM = { 0x86, 0x96, 0x83, 0x38, 0xCF, 0x9D, 0x5B, 0x6D, 0xDC, 0x15, 0xBA, 0x3E, 0x7D, 0x95, 0x3B, 0x2F }; +// Clone +// Fudan Semiconductor FM17522 (0x88) +const byte FM17522_firmware_reference[] PROGMEM = { + 0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18, + 0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B, + 0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7, + 0xC3, 0x97, 0xAE, 0x77, 0xF4, 0x37, 0xD7, 0x9B, + 0x7C, 0xF5, 0x3C, 0x11, 0x8F, 0x15, 0xC3, 0xD7, + 0xC1, 0x5B, 0x00, 0x2A, 0xD0, 0x75, 0xDE, 0x9E, + 0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB, + 0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62 +}; class MFRC522 { public: @@ -218,8 +246,8 @@ public: PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision. PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1 - PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 1 - PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 1 + PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2 + PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3 PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT. // The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9) // Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. diff --git a/README.rst b/README.rst index a210eae..3aa6397 100644 --- a/README.rst +++ b/README.rst @@ -28,11 +28,11 @@ The following table shows the typical pin layout used: +-----------+----------+-------------+---------+---------+---------------+-----------+--------+ | SPI SS | SDA [3]_ | 10 [2]_ | 53 [2]_ | D10 | 10 | 10 | 10 | +-----------+----------+-------------+---------+---------+---------------+-----------+--------+ -| SPI MOSI | MOSI | 11 / ICSP-4 | 52 | D11 | ICSP-4 | 16 | 11 | +| SPI MOSI | MOSI | 11 / ICSP-4 | 51 | D11 | ICSP-4 | 16 | 11 | +-----------+----------+-------------+---------+---------+---------------+-----------+--------+ -| SPI MISO | MISO | 12 / ICSP-1 | 51 | D12 | ICSP-1 | 14 | 12 | +| SPI MISO | MISO | 12 / ICSP-1 | 50 | D12 | ICSP-1 | 14 | 12 | +-----------+----------+-------------+---------+---------+---------------+-----------+--------+ -| SPI SCK | SCK | 13 / ICSP-3 | 50 | D13 | ICSP-3 | 15 | 13 | +| SPI SCK | SCK | 13 / ICSP-3 | 52 | D13 | ICSP-3 | 15 | 13 | +-----------+----------+-------------+---------+---------+---------------+-----------+--------+ .. [1] Configurable, typically defined as RST_PIN in sketch/program. @@ -82,14 +82,55 @@ Protocols 2. The reader and the tags communicate using a 13.56 MHz electromagnetic field. -* The protocol is defined in ISO/IEC 14443-3:2011 Part 3. +* The protocol is defined in ISO/IEC 14443-3:2011 Part 3 Type A. * Details are found in chapter 6 *"Type A – Initialization and anticollision"*. - + * See http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf for a free version of the final draft (which might be outdated in some areas). + + * The reader do not support ISO/IEC 14443-3 Type B. +Troubleshooting +------- + +* **I don't get input from reader** or **WARNING: Communication failure, is the MFRC522 properly connected?** + + #. Check your connection, see `Pin Layout`_ . + #. Check voltage. Most breakouts work with 3.3V. + #. The SPI only works with 3.3V, most breakouts seems 5V tollerant, but try a level shifter. + + +* **Sometimes I get timeouts** or **tag/card sometimes not work.** + + #. Try other site of the antenna. + #. Try to decrease distance between MFRC522. + #. Increase antenna gain per firmware: ``mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);`` + #. Use better power supply. + #. Hardware corrupted, most products are from china and sometimes the quality is really low. Contact your seller. + + +* **My tag/card doesn't work.** + + #. Distance between antenna and token too huge (>1cm). + #. You got wrong PICC. Is it really 13.56MGhz? Is it really a Mifare Type A? + #. NFC tokens are not supported. Some may work. + #. Animal marker are not supported. They use other frequency. + #. Hardware corrupted, most products are from china and sometimes the quality is really low. Contact your seller. + +* **My mobile phone doesn't recognize the MFRC522** or **my MFRC522 can't read data from other MFRC522** + + #. Card simmulation is not supported. + #. Communication with mobile phones is not supported. + #. Peer to peer communication is not supported. + +* **I need more features.** + + #. If software: code it and make a pull request. + #. If hardware: buy a more expensive like PN532 (supports NFC and many more, but costs about $15) + + License ------- This is free and unencumbered software released into the public domain. diff --git a/examples/rfid_write_personal_data/rfid_write_personal_data.ino b/examples/rfid_write_personal_data/rfid_write_personal_data.ino index 21721a6..dda943a 100644 --- a/examples/rfid_write_personal_data/rfid_write_personal_data.ino +++ b/examples/rfid_write_personal_data/rfid_write_personal_data.ino @@ -64,7 +64,7 @@ void loop() { // Ask personal data: Family name Serial.println(F("Type Family name, ending with #")); len=Serial.readBytesUntil('#', (char *) buffer, 30) ; // read family name from serial - for (byte i = len; i < 30; i++) buffer[i] = '\s'; // pad with spaces + for (byte i = len; i < 30; i++) buffer[i] = ' '; // pad with spaces block = 1; //Serial.println(F("Authenticating using key A...")); @@ -106,7 +106,7 @@ void loop() { // Ask personal data: First name Serial.println(F("Type First name, ending with #")); len=Serial.readBytesUntil('#', (char *) buffer, 20) ; // read first name from serial - for (byte i = len; i < 20; i++) buffer[i] = '\s'; // pad with spaces + for (byte i = len; i < 20; i++) buffer[i] = ' '; // pad with spaces block = 4; //Serial.println(F("Authenticating using key A...")); diff --git a/library.json b/library.json index 96917e1..94e8453 100644 --- a/library.json +++ b/library.json @@ -9,5 +9,5 @@ }, "exclude": "doc", "frameworks": "arduino", - "platforms": "atmelavr" + "platforms": ["atmelavr", "ststm32"] } diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..d223ed8 --- /dev/null +++ b/library.properties @@ -0,0 +1,10 @@ +name=MFRC522 +#date as version - no leading zero +version=2015.9.4 +author=GithubCommunity +maintainer=miguelbalboa +sentence=Arduino RFID Library for MFRC522 (SPI) +paragraph=Read/Write a RFID Card or Tag using the ISO/IEC 14443A/MIFARE interface. +category=Communication +url=https://github.com/miguelbalboa/rfid +architectures=avr,STM32F1