Hi all. I am trying to communicate with PN532 in ISO-14443-4 Tag mode with using RC522 Mini module.
There is my code for PN532 side. I am using C# and Iot.Device.Bindings library 3.1.0
using Iot.Device.Bmxx80;
using Iot.Device.Common;
using Iot.Device.FtCommon;
using Iot.Device.Pn532;
using Iot.Device.Pn532.AsTarget;
using Iot.Device.Pn532.RfConfiguration;
using Microsoft.Extensions.Logging;
using System.Text;
namespace pn532_clean
{
class Device : IDisposable
{
public Device(string port)
{
_device = new Pn532(port);
_device.SetAnalog106kbpsTypeA(new Analog106kbpsTypeAMode());
Console.WriteLine($"Firmware version: {_device.FirmwareVersion}");
}
public void Dispose()
{
_device?.Dispose();
_device = null;
}
private Pn532? _device;
}
class Program
{
public static Pn532 CreateDevice(string port)
{
var device = new Pn532(port);
Console.WriteLine($"Firmware version: {device.FirmwareVersion}");
Console.WriteLine($"Parameters flags: {device.ParametersFlags}");
return device;
}
public static string ModeToString(TargetModeInitialized? mode)
{
var stringBuilder = new StringBuilder();
if (mode != null)
{
stringBuilder.AppendLine($"Is ISO14443-4: {mode.IsISO14443_4Picc}");
stringBuilder.Append("Framing type: ");
switch (mode.TargetFramingType)
{
case TargetFramingType.Mifare:
stringBuilder.AppendLine("Mifare");
break;
case TargetFramingType.ActiveMode:
stringBuilder.AppendLine("Active mode");
break;
case TargetFramingType.FeliCa:
stringBuilder.AppendLine("FeliCa");
break;
}
stringBuilder.Append("Baud rate: ");
switch (mode.TargetBaudRate)
{
case TargetBaudRateInialized.B106kbps:
stringBuilder.AppendLine("106 kbps");
break;
case TargetBaudRateInialized.B212kbps:
stringBuilder.AppendLine("212 kbps");
break;
case TargetBaudRateInialized.B424kbps:
stringBuilder.AppendLine("424 kbps");
break;
}
}
return stringBuilder.ToString();
}
public static void Main(string[] args)
{
var port = "COM3";
if (args.Length == 1)
{
port = args[0];
}
Console.WriteLine($"Port: {port}");
// setup logs
var loggerFactory = new SimpleConsoleLoggerFactory(LogLevel.Debug);
LogDispatcher.LoggerFactory = loggerFactory;
// setup device
var device = CreateDevice(port);
var mifareParams = new TargetMifareParameters();
mifareParams.Atqa = [0x04, 0x00];
mifareParams.Sak = 0x20;
mifareParams.NfcId3 = [0x21, 0x22, 0x23];
var felicaParams = new TargetFeliCaParameters();
var piccParams = new TargetPiccParameters();
while (true)
{
try
{
var (mode, initiator) = device.InitAsTarget(TargetModeInitialization.PiccOnly, mifareParams, felicaParams, piccParams);
Console.Write(ModeToString(mode));
if (initiator != null)
{
Console.WriteLine($"Initiator: {BitConverter.ToString(initiator)}");
if (mode.IsISO14443_4Picc)
{
Span<byte> dataOut = [0x90, 0x00];
Span<byte> dataIn = new byte[100];
var numberOfBytes = device.ReadDataAsTarget(dataIn);
if (numberOfBytes > 0)
{
Console.WriteLine($"Read from PCD [{numberOfBytes} bytes]: {BitConverter.ToString(dataIn.ToArray(), 0, numberOfBytes)}");
dataOut[0] = 0x90;
dataOut[1] = 0x00;
device.WriteDataAsTarget(dataOut);
}
else
{
Console.WriteLine("Read from PCD failed");
dataOut[0] = 0x90;
dataOut[0] = 0x00;
device.WriteDataAsTarget(dataOut);
}
}
}
}
catch (TimeoutException ex)
{
Console.WriteLine($"Timeout exception: {ex}");
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex}");
device.Dispose();
device = CreateDevice(port);
}
}
}
}
}
Below is RC522 side. I am using library miguelbalboa/rfid 1.4.11:
#include <SPI.h>
#include <MFRC522Extended.h>
#include <array>
#define SS_PIN (D8)
#define RST_PIN (D4)
MFRC522Extended mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
void setup() {
Serial.begin(115200); // Initiate a serial communication
while(!Serial)
delay(50);
SPI.begin(); // Initiate SPI bus
mfrc522.PCD_Init(); // Initiate MFRC522
Serial.println("Approximate your card to the reader...");
Serial.println();
mfrc522.PCD_SetAntennaGain(MFRC522::RxGain_48dB);
Serial.print("Antenna gain: ");
Serial.println(mfrc522.PCD_GetAntennaGain());
Serial.print("Final antenna gain: ");
Serial.println(mfrc522.PCD_GetAntennaGain());
}
void loop() {
// Look for new cards
if (!mfrc522.PICC_IsNewCardPresent()) {
delay(50);
return;
}
// Select one of the cards
if (!mfrc522.PICC_ReadCardSerial()) {
delay(50);
return;
}
mfrc522.PICC_DumpDetailsToSerial(&mfrc522.uid);
mfrc522.PICC_DumpISO14443_4(&mfrc522.tag);
dumpAts(&mfrc522.tag.ats);
std::array<byte, 100> dataIn = {};
byte dataInSize = dataIn.size();
std::array<byte, 14> dataOut = {0x00, 0x00, 0xa4, 0x04, 0x00, 0x07, 0xd2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
for (auto i = 0; i < dataOut.size(); ++i) {
dataOut[i] = i;
}
auto status = mfrc522.TCL_Transceive(&mfrc522.tag, dataOut.data(), dataOut.size(), dataIn.data(), &dataInSize);
// auto status = mfrc522.PCD_TransceiveData(dataOut.data(), dataOut.size(), dataIn.data(), &dataInSize);
if (status == MFRC522::STATUS_OK) {
Serial.printf("Received [%d bytes]: ", dataInSize);
for (int i = 0; i < dataInSize; ++i) {
Serial.printf("%02x ", dataIn[i]);
}
Serial.println("");
} else {
Serial.printf("Transfer failed with status: %s\n", MFRC522::GetStatusCodeName(status));
}
mfrc522.TCL_Deselect(&mfrc522.tag);
}
I have received next ATS from PN532:
05 75 33 92 03
what means
T0:
TA1 = True
TB1 = True
TC1 = True
FSCI = 5
TA1:
DiffDivs = False
DS8 = False
DS4 = True
DS2 = True
DR8 = False
DR4 = True
DR2 = True
TC1:
CID = True
NAD = True
Based on erceived ATS values RC522 library check DS2 bit in TA1 byte and send PPS request to card to accept speed of 212 kBd. PN532 and answer OK to PPS and RC522 apply this speed to itself.
Then PN532 exit out of call InitAsTarget and tell me, that mode is 106 kBd, what's seems wrong. Afterwards PN532 TgGetData alwasy return or 0x2 error, or 0x13.
I've tried to force 106 kBd speed in RC522 library (change the code after receiveing ATS) but it didn't help.
Maybe somebody faced with similar problem or have an idea, what i need to check to resolve communication issues?
Forget to say, that with NFC tool on the phone all works. Not stable, but works.