diff --git a/README.md b/README.md index ebac169..255c82d 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,6 @@ If you got a bad board and you can tell us how to detect those boards (silk, chi * Use of IRQ pin. But there is a proof-of-concept example. * With Intel Galileo (Gen2) see [#310](https://github.com/miguelbalboa/rfid/issues/310), not supported by software. * Power reduction modes [#269](https://github.com/miguelbalboa/rfid/issues/269), not supported by software. - * UART instead of SPI [#281](https://github.com/miguelbalboa/rfid/issues/281), not supported by software. * **Need more?** diff --git a/examples/CustomUART/CustomUART.ino b/examples/CustomUART/CustomUART.ino new file mode 100644 index 0000000..ecec6c3 --- /dev/null +++ b/examples/CustomUART/CustomUART.ino @@ -0,0 +1,67 @@ +#include +#include "MFRC522v2.h" +#include "MFRC522DriverPinSimple.h" +#include "MFRC522Debug.h" +#include "MFRC522DriverUART.h" +#include "MFRC522DriverSPI.h" + +// This exampe was tested with an ESP32. +// It needs the following wiring (which can be fully customized due to the powerful pinmux of the ESP32): +// RC-522 module | ESP32 +// SDA (RX) | 22 (txPin) +// MISO (TX) | 23 (rxPin) +// RESET | 21 +// +// Don't forget to modify the RC-522: Disconnect the EA pin (32) from Vcc and wire it to GND. +// See RC522-UART-mod.jpg for reference. + +MFRC522DriverUART driver{Serial1}; // Create UART driver. + +MFRC522 mfrc522{driver}; // Create MFRC522 instance. + +#define RESET_PIN 21 + +void setup() +{ + pinMode(RESET_PIN, OUTPUT); + digitalWrite(RESET_PIN, LOW); // power down + delay(100); + digitalWrite(RESET_PIN, HIGH); // Reset by positive edge. + //--- Start serial + Serial.begin (115200) ; +#ifdef ESP32 + Serial1.begin(9600, SERIAL_8N1, /* rxPin */ 23, /* txPin */ 22); +#else + // AVR does not support specifying of the pins when initializing a Serial device. + Serial1.begin(9600, SERIAL_8N1); +#endif + //--- Wait for serial (blink led at 10 Hz during waiting) + while (!Serial) { + delay (50) ; + } + + while (!Serial1) { + delay (50) ; + } + + delay(1000); + + driver.PCD_ReadRegister(MFRC522Constants::PCD_Register::VersionReg); + mfrc522.PCD_Init(); // Init MFRC522 board. + MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial); // Show details of PCD - MFRC522 Card Reader details. + + Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks...")); +} + +void loop() +{ + Serial.println("Checking for card..."); + if ( mfrc522.PICC_IsNewCardPresent()) + { + Serial.println("Card present."); + if (mfrc522.PICC_ReadCardSerial()) { + MFRC522Debug::PICC_DumpToSerial(mfrc522, Serial, &(mfrc522.uid)); + } + } + delay(1000); +} \ No newline at end of file diff --git a/examples/CustomUART/RC522-UART-mod.jpg b/examples/CustomUART/RC522-UART-mod.jpg new file mode 100644 index 0000000..d5dfe21 Binary files /dev/null and b/examples/CustomUART/RC522-UART-mod.jpg differ diff --git a/src/MFRC522Debug.cpp b/src/MFRC522Debug.cpp index f9f9f11..7303a41 100644 --- a/src/MFRC522Debug.cpp +++ b/src/MFRC522Debug.cpp @@ -432,3 +432,61 @@ void MFRC522Debug::PICC_DumpMifareUltralightToSerial(MFRC522 &device, Print &log } } } // End PICC_DumpMifareUltralightToSerial() + +String MFRC522Debug::toString(PCD_Register reg) +{ + switch(reg) + { + case PCD_Register::CommandReg : return "CommandReg "; + case PCD_Register::ComIEnReg : return "ComIEnReg "; + case PCD_Register::DivIEnReg : return "DivIEnReg "; + case PCD_Register::ComIrqReg : return "ComIrqReg "; + case PCD_Register::DivIrqReg : return "DivIrqReg "; + case PCD_Register::ErrorReg : return "ErrorReg "; + case PCD_Register::Status1Reg : return "Status1Reg "; + case PCD_Register::Status2Reg : return "Status2Reg "; + case PCD_Register::FIFODataReg : return "FIFODataReg "; + case PCD_Register::FIFOLevelReg : return "FIFOLevelReg "; + case PCD_Register::WaterLevelReg : return "WaterLevelReg "; + case PCD_Register::ControlReg : return "ControlReg "; + case PCD_Register::BitFramingReg : return "BitFramingReg "; + case PCD_Register::CollReg : return "CollReg "; + case PCD_Register::ModeReg : return "ModeReg "; + case PCD_Register::TxModeReg : return "TxModeReg "; + case PCD_Register::RxModeReg : return "RxModeReg "; + case PCD_Register::TxControlReg : return "TxControlReg "; + case PCD_Register::TxASKReg : return "TxASKReg "; + case PCD_Register::TxSelReg : return "TxSelReg "; + case PCD_Register::RxSelReg : return "RxSelReg "; + case PCD_Register::RxThresholdReg : return "RxThresholdReg "; + case PCD_Register::DemodReg : return "DemodReg "; + case PCD_Register::MfTxReg : return "MfTxReg "; + case PCD_Register::MfRxReg : return "MfRxReg "; + case PCD_Register::SerialSpeedReg : return "SerialSpeedReg "; + case PCD_Register::CRCResultRegH : return "CRCResultRegH "; + case PCD_Register::CRCResultRegL : return "CRCResultRegL "; + case PCD_Register::ModWidthReg : return "ModWidthReg "; + case PCD_Register::RFCfgReg : return "RFCfgReg "; + case PCD_Register::GsNReg : return "GsNReg "; + case PCD_Register::CWGsPReg : return "CWGsPReg "; + case PCD_Register::ModGsPReg : return "ModGsPReg "; + case PCD_Register::TModeReg : return "TModeReg "; + case PCD_Register::TPrescalerReg : return "TPrescalerReg "; + case PCD_Register::TReloadRegH : return "TReloadRegH "; + case PCD_Register::TReloadRegL : return "TReloadRegL "; + case PCD_Register::TCounterValueRegH : return "TCounterValueRegH"; + case PCD_Register::TCounterValueRegL : return "TCounterValueRegL"; + case PCD_Register::TestSel1Reg : return "TestSel1Reg "; + case PCD_Register::TestSel2Reg : return "TestSel2Reg "; + case PCD_Register::TestPinEnReg : return "TestPinEnReg "; + case PCD_Register::TestPinValueReg : return "TestPinValueReg "; + case PCD_Register::TestBusReg : return "TestBusReg "; + case PCD_Register::AutoTestReg : return "AutoTestReg "; + case PCD_Register::VersionReg : return "VersionReg "; + case PCD_Register::AnalogTestReg : return "AnalogTestReg "; + case PCD_Register::TestDAC1Reg : return "TestDAC1Reg "; + case PCD_Register::TestDAC2Reg : return "TestDAC2Reg "; + case PCD_Register::TestADCReg : return "TestADCReg "; + default : return String("Unknown Register: ") + reg; + } +} diff --git a/src/MFRC522Debug.h b/src/MFRC522Debug.h index 6ef590a..24baa88 100644 --- a/src/MFRC522Debug.h +++ b/src/MFRC522Debug.h @@ -13,6 +13,7 @@ class MFRC522Debug { using PCD_Version = MFRC522Constants::PCD_Version; using Uid = MFRC522Constants::Uid; using MIFARE_Key = MFRC522Constants::MIFARE_Key; + using PCD_Register = MFRC522Constants::PCD_Register; public: // Get human readable code and type @@ -30,4 +31,6 @@ class MFRC522Debug { static void PICC_DumpMifareClassicToSerial(MFRC522 &device, Print &logPrint, Uid *uid, PICC_Type piccType, MIFARE_Key *key); static void PICC_DumpMifareClassicSectorToSerial(MFRC522 &device, Print &logPrint, Uid *uid, MIFARE_Key *key, byte sector); static void PICC_DumpMifareUltralightToSerial(MFRC522 &device, Print &logPrint); + + static String toString(PCD_Register reg); }; diff --git a/src/MFRC522DriverUART.cpp b/src/MFRC522DriverUART.cpp new file mode 100644 index 0000000..5594165 --- /dev/null +++ b/src/MFRC522DriverUART.cpp @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +#include "MFRC522Debug.h" +#include "MFRC522DriverUART.h" + +///////////////////////////////////////////////////////////////////////////////////// +// Basic interface functions for communicating with the MFRC522DriverUART +///////////////////////////////////////////////////////////////////////////////////// + +bool MFRC522DriverUART::init() { + // Surrounding code should initialize the serial port. + _serial.setTimeout(10); + return true; +} + +/** + * Writes a byte to the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.4. + */ +void MFRC522DriverUART::PCD_WriteRegister(const PCD_Register reg, ///< The register to write to. One of the PCD_Register enums. + const byte value ///< The value to write. + ) { + // PCD_ReadRegister(reg); + _serial.write(reg); + // read back the echoes address: + byte readBack = 0xff; + _serial.readBytes(&readBack, 1); + _serial.write(value); +} // End PCD_WriteRegister(). + +/** + * Writes a number of bytes to the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.4. + */ +void MFRC522DriverUART::PCD_WriteRegister(const MFRC522Constants::PCD_Register reg, ///< The register to write to. One of the PCD_Register enums. + const byte count, ///< The number of bytes to write to the register. + byte *const values ///< The values to write. Byte array. + ) { + for (byte i = 0; i < count; i++) + { + PCD_WriteRegister(reg, values[i]); + } +} // End PCD_WriteRegister() + +/** + * Reads a byte from the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.4. + */ +byte MFRC522DriverUART::PCD_ReadRegister(const PCD_Register reg ///< The register to read from. One of the PCD_Register enums. + ) { + byte value = 0; + byte regRead = reg | 0xC0; + _serial.write(regRead); + _serial.readBytes(&value, 1); + return value; +} // End PCD_ReadRegister() + +/** + * Reads a number of bytes from the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + */ +void MFRC522DriverUART::PCD_ReadRegister(const PCD_Register reg, ///< The register to read from. One of the PCD_Register enums. + const byte count, ///< The number of bytes to read. + byte *const values, ///< Byte array to store the values in. + const byte rxAlign ///< Only bit positions rxAlign..7 in values[0] are updated. + ) { + // Sanity check. + if(count == 0 || values == nullptr) { + return; + } + + byte index = 0; + + while(index < count) { + if(index == 0 && rxAlign) { // Only update bit positions rxAlign..7 in values[0] + // Create bit mask for bit positions rxAlign..7 + byte mask = 0; + + for(byte i = rxAlign; i <= 7; i++) { + mask |= (1 << i); + } + byte value = PCD_ReadRegister(reg); + + // Apply mask to both current value of values[0] and the new data in value. + values[0] = (values[index] & ~mask) | (value & mask); + } else { // Normal case + values[index] = PCD_ReadRegister(reg); + } + index++; + } +} // End PCD_ReadRegister() diff --git a/src/MFRC522DriverUART.h b/src/MFRC522DriverUART.h new file mode 100644 index 0000000..37f5fd0 --- /dev/null +++ b/src/MFRC522DriverUART.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +#pragma once + +#include +#include + +class MFRC522DriverUART : public MFRC522Driver { +public: + //using PCD_Register = MFRC522Constants::PCD_Register; + ///////////////////////////////////////////////////////////////////////////////////// + // Functions for setting up the Arduino. + ///////////////////////////////////////////////////////////////////////////////////// + + bool init() override; + + ///////////////////////////////////////////////////////////////////////////////////// + // Basic interface functions for communicating with the MFRC522. + ///////////////////////////////////////////////////////////////////////////////////// + void PCD_WriteRegister(const PCD_Register reg, const byte value) override; + void PCD_WriteRegister(const PCD_Register reg, const byte count, byte *const values) override; + byte PCD_ReadRegister(const PCD_Register reg) override; + void PCD_ReadRegister(const PCD_Register reg, const byte count, byte *const values, const byte rxAlign = 0) override; + + + MFRC522DriverUART(Stream& serial) : + MFRC522Driver(), + _serial(serial) + {} + +protected: + Stream& _serial; +};