[MFRC522] Speed-up detecting cards + make error recovery more stable

This commit is contained in:
TD-er
2025-06-25 00:54:32 +02:00
parent d6d7f139bc
commit a6aca34f4e
8 changed files with 141 additions and 35 deletions
+26 -19
View File
@@ -291,7 +291,7 @@ void MFRC522::PCD_AntennaOff() {
/**
* Get the current MFRC522 Receiver Gain (RxGain[2:0]) value.
* See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf
* See 9.3.3.6 / table 98 in https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf
* NOTE: Return value scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits.
*
* @return Value of the RxGain, scrubbed to the 3 bits used.
@@ -302,7 +302,7 @@ uint8_t MFRC522::PCD_GetAntennaGain() {
/**
* Set the MFRC522 Receiver Gain (RxGain) to value specified by given mask.
* See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf
* See 9.3.3.6 / table 98 in https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf
* NOTE: Given mask is scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits.
*/
void MFRC522::PCD_SetAntennaGain(uint8_t mask) {
@@ -314,7 +314,7 @@ void MFRC522::PCD_SetAntennaGain(uint8_t mask) {
/**
* Performs a self-test of the MFRC522
* See 16.1.1 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf
* See 16.1.1 in https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf
*
* @return Whether or not the test passed. Or false if no firmware reference is available.
*/
@@ -368,21 +368,28 @@ bool MFRC522::PCD_PerformSelfTest() {
// Pick the appropriate reference values
const uint8_t *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;
case 0x92: // Version 2.0
reference = MFRC522_firmware_referenceV2_0;
break;
default: // Unknown version
return false; // abort test
switch(version) {
// Fudan Semiconductor clone:
case 0xb2: // FM17522
reference = FM17522_firmware_referenceB2;
break;
case 0x88: // FM17522
reference = FM17522_firmware_reference88;
break;
case 0x89: // FM17522E
reference = FM17522E_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;
case 0x92: // Version 2.0
reference = MFRC522_firmware_referenceV2_0;
break;
default: // Unknown version
return false; // abort test
}
// Verify that the results match up to our expectations
@@ -868,7 +875,7 @@ MFRC522::StatusCode MFRC522::PICC_HaltA() {
/**
* Executes the MFRC522 MFAuthent command.
* This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card.
* The authentication is described in the MFRC522 datasheet section 10.3.1.9 and http://www.nxp.com/documents/data_sheet/MF1S503x.pdf section 10.1.
* The authentication is described in the MFRC522 datasheet section 10.3.1.9 and https://www.nxp.com/docs/en/data-sheet/MF1S503x.pdf section 10.1.
* For use with MIFARE Classic PICCs.
* The PICC must be selected - ie in state ACTIVE(*) - before calling this function.
* Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start.
+25 -3
View File
@@ -64,7 +64,7 @@ const uint8_t MFRC522_firmware_referenceV2_0[] PROGMEM = {
};
// Clone
// Fudan Semiconductor FM17522 (0x88)
const uint8_t FM17522_firmware_reference[] PROGMEM = {
const uint8_t FM17522_firmware_reference88[] 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,
@@ -74,6 +74,28 @@ const uint8_t FM17522_firmware_reference[] PROGMEM = {
0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB,
0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62
};
// Another "FM17522" ic form Aliexpress
const uint8_t FM17522_firmware_referenceB2[] PROGMEM = {
0x00, 0xeb, 0x44, 0x85, 0xfa, 0x9a, 0x78, 0x01,
0x74, 0xe5, 0x1c, 0x7a, 0x0a, 0xa0, 0x71, 0xe1,
0xf3, 0xfa, 0x96, 0x6d, 0x28, 0xa1, 0x34, 0x46,
0x3a, 0x1c, 0x32, 0x96, 0xb9, 0xe6, 0x44, 0x87,
0x0a, 0x45, 0x98, 0xa9, 0x36, 0x60, 0x89, 0x0f,
0x06, 0x9b, 0x7b, 0x17, 0xb3, 0x0c, 0x1a, 0x6c,
0x1a, 0xae, 0x2c, 0xac, 0x0e, 0x6f, 0x2e, 0x02,
0x2b, 0xcb, 0x8a, 0xb2, 0x45, 0xdd, 0x7e, 0x3c
};
// Fudan Semiconductor FM17522E (0x89)
const uint8_t FM17522E_firmware_reference[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x00, 0x04, 0xcc, 0xc8, 0x00,
0x10, 0x04, 0x00, 0xc0, 0x00, 0x90, 0x00, 0x20,
0x00, 0x00, 0x23, 0x00, 0x38, 0x06, 0x01, 0x33,
0x98, 0xf3, 0x80, 0x06, 0xc0, 0xf9, 0x80, 0x08,
0x27, 0x04, 0x23, 0x82, 0x21, 0x12, 0xf9, 0xc7
};
class MFRC522 {
public:
@@ -173,7 +195,7 @@ public:
};
// MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain factor (on the PCD).
// Described in 9.3.3.6 / table 98 of the datasheet at http://www.nxp.com/documents/data_sheet/MFRC522.pdf
// Described in 9.3.3.6 / table 98 of the datasheet at https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf
enum PCD_RxGain : uint8_t {
RxGain_18dB = 0x00 << 4, // 000b - 18 dB, minimum
RxGain_23dB = 0x01 << 4, // 001b - 23 dB
@@ -210,7 +232,7 @@ public:
PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register.
PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register.
PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block.
// The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
// The commands used for MIFARE Ultralight (from https://www.nxp.com/docs/en/data-sheet/MF0ICU1.pdf, Section 8.6)
// The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight.
PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 uint8_t page to the PICC.
};
+1 -1
View File
@@ -195,7 +195,7 @@ lib_extra_dirs =
; ESP_IDF 5.5.0
[core_esp32_IDF5_5_0__3_2_0_LittleFS]
platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3722/framework-arduinoespressif32-all-release_v5.5-eefeb2bb.zip
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3725/framework-arduinoespressif32-all-release_v5.5-eefeb2bb.zip
;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/3627/framework-arduinoespressif32-all-release_v5.5-5d572003.zip
build_flags = -DESP32_STAGE
-DESP_IDF_VERSION_MAJOR=5
+1 -1
View File
@@ -101,7 +101,7 @@ board_build.filesystem = littlefs
lib_ignore = ${esp32_always.lib_ignore}
ESP32_ping
ESP32 BLE Arduino
${core_esp32_IDF5_4_1__3_2_0_LittleFS.lib_ignore}
${esp32_base_idf5.lib_ignore}
[esp32_IRExt_LittleFS_ETH]
+5 -5
View File
@@ -1,16 +1,16 @@
[esp32s3_common_LittleFS]
extends = esp32_base_idf5
extends = esp32_base_idf5_5
lib_ignore = ${esp32_common_LittleFS_ETH.lib_ignore}
ESP32_ping
${esp32_base_idf5.lib_ignore}
build_flags = ${esp32_base_idf5.build_flags}
${esp32_base_idf5_5.lib_ignore}
build_flags = ${esp32_base_idf5_5.build_flags}
; -mtext-section-literals
-DFEATURE_ARDUINO_OTA=1
-DFEATURE_ETHERNET=1
-DUSE_LITTLEFS
-DESP32S3
extra_scripts = ${esp32_base_idf5.extra_scripts}
build_unflags = ${esp32_base_idf5.build_unflags}
extra_scripts = ${esp32_base_idf5_5.extra_scripts}
build_unflags = ${esp32_base_idf5_5.build_unflags}
-fexceptions
board_build.filesystem = littlefs
+25 -2
View File
@@ -36,7 +36,7 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string)
{
auto& dev = Device[++deviceCount];
dev.Number = PLUGIN_ID_111;
dev.Type = DEVICE_TYPE_SPI2;
dev.Type = DEVICE_TYPE_SPI3;
dev.VType = Sensor_VType::SENSOR_TYPE_ULONG;
dev.ValueCount = 1;
dev.SendDataOption = true;
@@ -59,9 +59,23 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string)
{
event->String1 = formatGpioName_output(F("CS PIN")); // P111_CS_PIN
event->String2 = formatGpioName_output_optional(F("RST PIN ")); // P111_RST_PIN
event->String3 = formatGpioName_input_optional(F("IRQ PIN ")); // P111_IRQ_PIN
break;
}
case PLUGIN_WEBFORM_SHOW_GPIO_DESCR:
{
string = event->String1;
string += concat(F("CS: "), formatGpioLabel(CONFIG_PIN1, false));
string += event->String1;
string += concat(F("RST: "), formatGpioLabel(CONFIG_PIN2, false));
string += event->String1;
string += concat(F("IRQ: "), formatGpioLabel(CONFIG_PIN3, false));
success = true;
break;
}
case PLUGIN_SET_DEFAULTS:
{
P111_REMOVALTIMEOUT = 500; // Default 500 msec reset delay
@@ -70,8 +84,17 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormSubHeader(F("Options"));
P111_data_struct *P111_data = static_cast<P111_data_struct *>(getPluginTaskData(event->TaskIndex));
if (nullptr != P111_data) {
uint8_t v{};
const String version = P111_data->PCD_getVersion(v);
if (v != 0 && v != 0xFF) {
addRowLabel(F("Reader Version"));
addHtml(version);
}
}
addFormSubHeader(F("Options"));
{
const __FlashStringHelper *removaltype[] = {
F("None"),
+56 -4
View File
@@ -26,6 +26,8 @@ void P111_data_struct::init() {
if (mfrc522 != nullptr) {
mfrc522->PCD_Init(); // Initialize MFRC522 reader
mfrc522->PCD_WriteRegister(MFRC522::ComIEnReg, 0b10100000); // enable receiver interrupt
mfrc522->PCD_WriteRegister(MFRC522::DivIEnReg, 0x80); // Set as CMOS output pin
initPhase = P111_initPhases::Ready;
}
}
@@ -116,10 +118,15 @@ bool P111_data_struct::reset(int8_t csPin,
if ((resetPin != -1) &&
(initPhase == P111_initPhases::Ready)) {
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("MFRC522: Reset on pin: ");
log += resetPin;
addLogMove(LOG_LEVEL_INFO, log);
addLogMove(
LOG_LEVEL_INFO,
concat(F("MFRC522: Reset on pin: "), resetPin));
}
init();
return true;
// FIXME TD-er: Remove the rest of this function.
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, LOW);
timeToWait = 100;
@@ -140,6 +147,8 @@ bool P111_data_struct::reset(int8_t csPin,
digitalWrite(csPin, LOW);
mfrc522->PCD_Init(csPin, resetPin); // Init MFRC522 module
mfrc522->PCD_WriteRegister(MFRC522::ComIEnReg, 0b10100000); // enable receiver interrupt
mfrc522->PCD_WriteRegister(MFRC522::DivIEnReg, 0x80); // Set as CMOS output pin
// If you set Antenna Gain to Max it will increase reading distance
mfrc522->PCD_SetAntennaGain(mfrc522->RxGain_max);
@@ -226,8 +235,10 @@ bool P111_data_struct::plugin_ten_per_second(struct EventStruct *event) {
}
counter++; // This variable replaces a static variable in the original implementation
const bool ComIrqReg_bits = (mfrc522->PCD_ReadRegister(MFRC522::ComIrqReg) & (1<<5)) != 0;
mfrc522->PCD_WriteRegister(MFRC522::ComIrqReg, 0x34);
if (counter == 3) { // Only every 3rd 0.1 second we do a read
if (counter >= 10 || ComIrqReg_bits) { // Only every 3rd 0.1 second we do a read
counter = 0;
uint32_t key = P111_NO_KEY;
@@ -300,4 +311,45 @@ bool P111_data_struct::plugin_fifty_per_second() {
return true;
}
String P111_data_struct::PCD_getVersion(uint8_t& v) {
v = 0xFF;
if (mfrc522) {
v = mfrc522->PCD_ReadRegister(MFRC522::VersionReg);
if (v != 0xFF && v != 0) {
// Human readable version.
String res = concat(formatToHex(v, 2), F(" = "));
switch(v) {
case 0xb2:
res += F("FM17522_1");
break;
case 0x88:
res += F("FM17522");
break;
case 0x89:
res += F("FM17522E");
break;
case 0x90:
res += F("v0.0");
break;
case 0x91:
res += F("v1.0");
break;
case 0x92:
res += F("v2.0");
break;
case 0x12:
res += F("counterfeit chip");
break;
default:
res += F("(unknown)");
break;
}
return res;
}
}
return EMPTY_STRING;
}
#endif // ifdef USES_P111
+2
View File
@@ -39,6 +39,8 @@ struct P111_data_struct : public PluginTaskData_base {
bool plugin_ten_per_second(struct EventStruct *event);
bool plugin_fifty_per_second();
String PCD_getVersion(uint8_t& v);
private:
MFRC522 *mfrc522 = nullptr;