cancel
Showing results for 
Search instead for 
Did you mean: 

Cr95hf card emulation help me plz

DJeon.4
Associate II

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

1 ACCEPTED SOLUTION

Accepted Solutions
Brian TIDAL
ST Employee

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

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

View solution in original post

16 REPLIES 16
Brian TIDAL
ST Employee

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

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
DJeon.4
Associate II

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.

  1. first GPIO Pin and SPI mode Setting

<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 >

  1. ;protocolSelect Card emulation for ISO/IEC 14443 Type A
  2. >>02 02 12 0A
  3. << 00 00

sdata[0] = 0x12; // data 0

sdata[1] = 0x0A; // data 1

writeCmd(0x02, 2); // protocol select cmd, length SPI write

readCmd() // SPI Read

0693W00000QNlkzQAD.png 

<debug result>

0693W00000QNllOQAT.png 

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

DJeon.4
Associate II

Please refer to the article below

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

This is the order in which my code works

  1. CS, IRQ_IN, pin enable
  2. SPI begin setup -> function "SPI.begin();"
  3. CR95HF wake up setup

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

0693W00000QNwC0QAL.png

​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();

  

}

DJeon.4
Associate II

-

Ulysses HERNIOSUS
ST Employee

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

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