2022-07-26 09:04 PM
Hello, I tried to implement the card emulator using CR95HF to refer to the datasheet, but it failed. Could you provide the sample code data for the cmd read write cmd procedure in the form of Hex value? I'd appreciate your help.
Ex)
Write cmd 0x 02 04 68 41
Read cne 0x 01. . .
Card emulator write cmd 0x02008. Etc
Solved! Go to Solution.
2022-09-02 02:41 AM
Hi
this is a great achievement:
0x00, 0x80, 0x05, 0xe0, 0x80, 0x31, 0x73, 0x08, 0x00, 0x00 is basically the E0 80 RATS frame (Request for Answer To Select) that is sent by the Android Phone after the anti collision and the activation. This means the anti collision (AC Filter) is properly working and the Android Phone is now trying to move to ISO14443-4 layer (aka ISO-DEP) with the RATS command. I see that you send the ATS answer (05 78 80 80 00), then make sure to then send the Listen command to trigger the reception of the next command. Note that the logging of the various exchanges may have an impact on the real time: for example the phone is waiting for the ATS within a certain timeout, if the logging through UART is delaying too much the sending of the ATS, the waiting time on phone side may elapse and this can cause a communication failure.
Rgds
BT
2022-07-27 02:06 AM
Hi,
here is an example of Type 4 Card Emulation:
;protocolSelect Card emulation for ISO/IEC 14443 Type A
>>02 02 12 0A
<< 00 00
;activate anticollition filter ATQA=02 00 SAK=20 (ISO14443-4 compliant) 4 bytes UID = 5F 53 54 4D
>> 0D 07 02 00 20 5F 53 54 4D
<< 00 00
;listen
>> 05 00
<< 00 00
;wait for IRQ_OUT (or use SPI poll)
;when data are received from the reader:
<< 80 05 E0 70 BE 84 08
;a RATS command has been received (E0 70)
;send ATS answer to RATS
>> 06 06 05 78 80 80 00 28
<< 00 00
;listen
>> 05 00
<< 00 00
;wait for IRQ_OUT (or use SPI poll)
;when data are received from the reader:
<< 80 11 02 00 A4 04 00 07 D2 76 00 00 85 01 01 00 35 C0 08
;an ISO 7816 Select application has been received (00 A4 04 00 07 D2 76 00 00 85 01 01 00)
;send the 90 00 status word response
>> 06 04 02 90 00 28
<< 00 00
;listen
>> 05 00
<< 00 00
;wait for IRQ_OUT (or use SPI poll)
Rgds
BT
2022-08-16 12:06 AM
Thank you for your answer. I wrote it through a translator because I am not good at English.
My reply was late because of personal matters.
We tried to implement the card emulator mode by referring to the data you provided, but failed.
I will provide you with the Arduino code I wrote, so I would appreciate it if you could help me implement the CR95HF card emulator mode.
<Set code >
// Configure GPIO pins : CS = 15, SCK=5, MOSI=6, MISO=7, IRQ IN= 2, IRQ OUT = 1
if (CS != -1) { pinMode(CS, OUTPUT); Serial.println("(1). SPI Chip Select OK"); }
if (IRQ_IN != -1) { pinMode(IRQ_IN, OUTPUT); Serial.println("(2). SPI Interrupt Request Ok");}
if (SSI_0 != -1) { pinMode(SSI_0, OUTPUT); Serial.println("(3). SPI SSI_0 Pin Ok");}
if (SSI_0 == -1) { Serial.println("(3). SPI SSI_0 Pin No use");}
if (SSI_1 != -1) { pinMode(SSI_1, OUTPUT); Serial.println("(4). SPI SSI_1 pin Ok");}
if (SSI_1 == -1) { Serial.println("(4). SPI SSI_1 pin No use");}
// Set in SPI mode
if (SSI_0 != -1) { digitalWrite(SSI_0, HIGH); }
if (SSI_1 != -1) { digitalWrite(SSI_1, LOW); }
if (IRQ_IN != -1) { digitalWrite(IRQ_IN, HIGH);}
delay(1);
if (IRQ_IN != -1) { digitalWrite(IRQ_IN, LOW); delay(1); }
if (IRQ_IN != -1) { digitalWrite(IRQ_IN, HIGH); delay(1); }
SPI.begin(); // arduino sketch SPI begin
while (!EchoResponse()) {
if (IRQ_IN != -1) { digitalWrite(IRQ_IN, HIGH); delay(1);}
if (IRQ_IN != -1) { digitalWrite(IRQ_IN, LOW); delay(1);}
}
2. function code
char RFID_CR95HF::EchoResponse() {
digitalWrite(CS, LOW);
SPI.beginTransaction(SETTINGS);
SPI.transfer(0x00); // Send cmd to CR95HF
SPI.transfer(ECHO);
SPI.endTransaction();
digitalWrite(CS, HIGH);
while (1) {
digitalWrite(CS, LOW);
SPI.beginTransaction(SETTINGS);
SPI.transfer(0x03);
tmp = SPI.transfer(0);
SPI.endTransaction();
digitalWrite(CS, HIGH);
if ((tmp & 0x08) >> 3) {
digitalWrite(CS, LOW);
SPI.beginTransaction(SETTINGS);
SPI.transfer(0x02);
tmp = SPI.transfer(0);
SPI.endTransaction();
digitalWrite(CS, HIGH);
if (tmp == ECHO) {
return 1;
}
return 0;
}
}
}
void RFID_CR95HF::writeCmd(unsigned short cmd, unsigned short dataLen) {
unsigned short i = 0;
digitalWrite(CS, LOW);
SPI.beginTransaction(SETTINGS);
SPI.transfer(0x00); // contol byte :
SPI.transfer(cmd); // command
SPI.transfer(dataLen); // length
while (dataLen == 0) {
digitalWrite(CS, HIGH);
break;
}
Serial.printf("write cmd :");
for (i = 0; i < dataLen; i++) {
SPI.transfer(sdata[i]);
Serial.printf("0x%x ", sdata[i]);
}
Serial.println("");
SPI.endTransaction();
digitalWrite(CS, HIGH);
delay(10);
}
// Poll the CR95HF
void RFID_CR95HF::readCmd() {
unsigned short i = 0;
while (1)
{
digitalWrite(CS, LOW);
SPI.beginTransaction(SETTINGS);
SPI.transfer(0x03);
res = SPI.transfer(0);
SPI.endTransaction();
digitalWrite(CS, HIGH);
//Serial.printf("==== Read cmd :");
for (i = 0; i < dataNum; i++) {
rdata[i] = SPI.transfer(0);
// Serial.printf("0x%x ", rdata[i]);
}
if ((res & 0x08) >> 3) {
digitalWrite(CS, LOW);
SPI.beginTransaction(SETTINGS);
SPI.transfer(0x02);
res = SPI.transfer(0);
dataNum = SPI.transfer(0);
Serial.printf("Read cmd :");
for (i = 0; i < dataNum; i++) {
rdata[i] = SPI.transfer(0);
Serial.printf("0x%x ", rdata[i]);
}
Serial.println("");
SPI.endTransaction();
digitalWrite(CS, HIGH);
break;
}
SPI.endTransaction();
digitalWrite(CS, HIGH);
delay(10);
}
}
=============================================
Function usage is as follows
<example card emulation mode packet >
sdata[0] = 0x12; // data 0
sdata[1] = 0x0A; // data 1
writeCmd(0x02, 2); // protocol select cmd, length SPI write
readCmd() // SPI Read
<debug result>
2022-08-17 12:35 AM
Hi,
please use a logic analyzer and verify the sequence against the one provided by Brian. If it still doesn't work please provide the logic analyzer traces.
Best Regards, Ulysses
2022-08-17 03:35 AM
Please refer to the article below
2022-08-17 04:45 AM
Hi,
hard to follow your sequences. Please write full sequences as described by Brian and please use a Logic Analyzer to follow the timing of your commands as well.
Best Regards, Ulysses
2022-08-17 06:28 PM
This is the order in which my code works
1) slave(CS) pin Low -> SPI Setting() -> packet Tx : 0x00 (control byte), 0x55(ECHO cmd), 0x00 (len)
-> slave Pin High -> SPI.endTransaction
※Tx packet : 0x00, 0x55, 0x00
2) slave(CS) pin Low -> SPI Setting() -> SPI transfer() packet Tx : 0x02(control byte), 0x00 -> slave Pin High
->SPI.endTransaction
※ Tx packet : 0x02, 0x00
4. Read Chip ID (CR95HF)
1) slave(CS) pin Low -> SPI Setting(); ->SPI transfer() packet Tx : 0x00(control byte), 0x01 (IDN cmd), 0x00(len)
-> slave Pin High -> SPI.endTransaction
※Tx packet : 0x00, 0x51, 0x00
2) slave(CS) pin Low -> SPI Setting(); -> packet Tx : 0x03(control byte), 0x00
-> slave Pin High -> SPI.endTransaction -> for( i=0; i<data; i++) save[i] = SPI transfer(); packet Tx : 0x03,
0x00
※Tx packet : 0x03, 0x00 after -> if (SPI transfer & 0x08) -> slave(CS) pin Low -> SPI Setting(); -> packet
Tx : 0x02(control byte), 0x00 -> for(i=0; i<data; i++) rdata[i]=SPI transfer(); -> slave Pin High
-> SPI.endTransaction
※Tx packet : 0x02, 0x00
※Rx packet(rdata[]) : 0x4e 0x46 0x43 0x20 0x46 0x53 0x32 0x4a 0x41 0x53 0x54 0x34 0x0 0x2a 0xce
result : RFID Reader CR95HF IDN : NFC FS2JAST4
5. Card Emulation Mode Set up
1) select protocol
Tx packet : 0x00 (controlbyte), 0x02(protocol select cmd), 0x02(len), 0x12, 0x08
rx packet : 0x00 should be returned if read normally, but no actual value is returned
2) AC filter
Tx packet : 0x00( controlbyte), 0x0D(AC_filter cmd), 0x07(len), 0x02, 0x00, 0x20, 0x5F(UID), .0x53(UID),
0x54(UID), 0x4D(UID)
Rx packet : 0x00 should be returned if read normally, but no actual value is returned
3) Listen : I wrote a write code, but this part is not written :sad_but_relieved_face:
Tx packet : 0x00(controlbyte), 0x05 (listen cmd), 0x00 (len)
Rx :0x00 should be returned if read normally, but no actual value is returned
4) Tag Send
Tx packet :0x00(control byte), 0x06, 0x06, 0x05, 0x78, 0x80, 0x80, 0x00, 0x28
Rx : 0x00 should be returned if read normally, but no actual value is returned
I've written it up to here
0
Since there is no logic analyzer, we replaced it with a terminal window provided by Arduino Integrated Development Environment
card emulation code : help me plz :sad_but_relieved_face:
void card_Emulation_14443A(void)
{
Serial.println("Caed Emulation Mode Set up");
sdata[0] = 0x12;
sdata[1] = 0x08;
writeCmd(ProtocolSelect, 2); // Card Emulation Mode Tag type select 14443A
readCmd();
sdata[0] = 0x02; //ATQA
sdata[1] = 0x00;
sdata[2] = 0x20; // sak
sdata[3] = 0x5F; // User Tag UID
sdata[4] = 0x53; // User Tag UID
sdata[5] = 0x54; // User Tag UID
sdata[6] = 0x4D; // User Tag UID
writeCmd(AC_filter ,7);
readCmd();
writeCmd(Listen ,0);
readCmd();
while(!EchoResponse()) {
if (IRQ_IN != -1) { digitalWrite(IRQ_IN, HIGH); delay(10);}
if (IRQ_IN != -1) { digitalWrite(IRQ_IN, LOW); delay(10);}
readCmd();
}
sdata[0] = 0x05;
sdata[1] = 0x78;
sdata[2] = 0x80;
sdata[3] = 0x80;
sdata[4] = 0x00;
sdata[5] = 0x28;
writeCmd(Tag_Send ,6);
readCmd();
writeCmd(Listen ,0);
readCmd();
}
2022-08-17 06:44 PM
-
2022-08-18 02:03 AM
Hi,
I think you will need a logic analyzer in the end. Changing the low level/porting will require looking at signals (SPI+IRQ_IN+IRQ_OUT, etc.) and timing. If you are lucky then you can get it working without but experience is that often there are subtle problems in SPI, IRQ handing, timing which cause it not working.
Of course you can go, create hypothesis of what could be the reason or what is happening, change something here and there and you may get it working. But a logic analyzer will tell you straight away what is happening and removes a lot of guessing.
There are inexpensive USB based logic analyzers, please get one!
Best Regards, Ulysses
2022-08-18 04:52 AM
Thank you for your late reply.
Can you provide sample code data for the cmd read write cmd procedure in Hex value format? I'd appreciate your help. The entire process from CR95HF start to card emulator activation is required.
I may have entered the wrong cmd due to lack of code data while implementing it. What I can do at this point is look at the data in the form of cmd read write hex values and implement it throughout the process. I'd appreciate your help.
ex)
CR95HF set ~ Full process Hex cmd data from card emulator activation
cmd 0x02046841 write
Read cmd 0x01, 0x04, 0x80.
Card emulator write cmd 0x02008. etc