cancel
Showing results for 
Search instead for 
Did you mean: 

Can't communicate with CR95HF over UART

PGupt.17
Associate II

We've connected CR95HF with arduino uno via UART but it seems to give random outputs on the serial monitor.

The arduino code:

#include <SoftwareSerial.h>
SoftwareSerial BTserial(4, 5);
 
 
 
void setup() {
  // put your setup code here, to run once:
  pinMode(5,OUTPUT);
  digitalWrite(5,HIGH);
  delay(5000);
  digitalWrite(5,LOW);
  delay(250);
  digitalWrite(5,HIGH);
  delay(200);
  
  BTserial.begin(57600);
Serial.begin(9600);
 
 
BTserial.write(0x55);
Serial.println(BTserial.read());
BTserial.write(0x55);
Serial.println(BTserial.read());
BTserial.write(0x55);
Serial.println(BTserial.read());
BTserial.write(0x55);
Serial.println(BTserial.read());
BTserial.write(0x55);
Serial.println(BTserial.read());
 
 
 
 
delay(1000);
 
BTserial.write(0x01);
BTserial.write((byte)0x00);
Serial.println(BTserial.read());
delay(1000);
 
BTserial.write(0x02);
BTserial.write(0x02);
BTserial.write(0x01);
BTserial.write(0x0D);
 
Serial.println(BTserial.read());
delay(1000);
}
 
void loop() {
BTserial.write(0x04);
BTserial.write(0x03);
BTserial.write(0x26);
BTserial.write(0x01);
BTserial.write((byte)0x00);
Serial.println(BTserial.read());
delay(1000);
 
 
 
}

The Serial Monitor:

0690X0000088DN6QAM.jpg

9 REPLIES 9
Brian TIDAL
ST Employee

Hi,

the UART should use the following parameters:

  • Baud Rate 57600
  • Word Length 8
  • Stop Bits 1
  • Parity NONE

Make sure to properly follow the startup sequence as described in the CR95HF Datasheet § 3.2:

  • SSI_0 = 0 and SSI_1 = 0 for UART selection
  • wait for t3 before sending any commands after the nIRQ_IN pulse . If I have well understood your code, your t3 value is 200 µs which is not aligned with the t3 value recommended in the Datasheet (10ms)

On my side, I use the following startup sequence (delay unit is ms)

Init:
   retry = 5
   Send_nIRQ_IN_Pulse
   while (Send_Echo == Error) && (retry --!= 0);
   if retry ==0
      abort
End_init
 
 
Send_nIRQ_IN_Pulse
    
    /* Start up sequence */
    Delay(1); /* wait t0 */
    /* Send null char to have nIRQ_IN/UART_TX low for more than 10µs (t1) */
    UartTx(0x00)
    Delay(11); /* wait t3 */
 
End_Send_nIRQ_IN_Pulse:

Let me know if this solve your issue.

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.
PGupt.17
Associate II

@Brian TIDAL_O​  I don't think so it solved much.

New Code:

#include <SoftwareSerial.h>
SoftwareSerial BTserial(4, 5);
 
 
 
void setup() {
    BTserial.begin(57600);
Serial.begin(9600);
  // put your setup code here, to run once:
delay(1);
BTserial.write((byte)0x00);
delay(11);
  
delay(2000);
 
 
BTserial.write(0x55);
if (BTserial.available()){
 float c = BTserial.read();
Serial.println(c);
}
BTserial.write(0x55);
if (BTserial.available()){
 float c = BTserial.read();
Serial.println(c);
}
BTserial.write(0x55);
if (BTserial.available()){
 float c = BTserial.read();
Serial.println(c);
}
Serial.println(BTserial.read());
if (BTserial.available()){
 float c = BTserial.read();
Serial.println(c);
}
BTserial.write(0x55);
if (BTserial.available()){
 float c = BTserial.read();
Serial.println(c);
}
 
BTserial.write(0x55);
if (BTserial.available()){
 float c = BTserial.read();
Serial.println(c);
}
 
 
 
 
delay(1000);
 
 
BTserial.write(0x02);
BTserial.write(0x02);
BTserial.write(0x02);
BTserial.write(0x01);
 
if (BTserial.available()){
 float c = BTserial.read();
Serial.println(c);
}
delay(1000);
}
 
void loop() {
BTserial.write(0x04);
BTserial.write(0x02);
BTserial.write(0x26);
BTserial.write(0x07);
if (BTserial.available()){
 float c = BTserial.read();
Serial.println(c);
}
delay(1000);
 
 
 
}

Serial Monitor:

0690X0000089kILQAY.jpg

can you help me out with a working library for arduino?

Brian TIDAL
ST Employee

​Hi,

would you please share more details about your HW setup:

  • do you use a X-NUCLEO_NFC03A1 expansion board connected to your Arduino? or a PLUG-CR95HF-B? or a custom board?
  • do you use wrapping between the CR95HF board and the Arduino board?
  • what are the values of SSI_0 and SSI_1?
  • feel free to add a picture of your HW setup?

I am not sure to understand why you are using float to read the CR95HF UART output.

From what I can see in your serial monitor trace:

  • you send echo command (0x55) and you get 85 answer (i.e. 0x55 ==> echo answer) from the CR95HF
  • you repeat this 2 times then line 32 there is a strange  serial.println(BTserial.read(). I guess this is a mistake.
  • then repeat this 2 times the sending of echo command and receive the proper echo answer (85 = 0x55)
  • having the proper echo answer proves that the UART interface is operational
  • then you sent 02020201h to select protocol ISO14443 but the last parameter (01h) is invalid (bits 3:0 are RFU)  so this command is failing
  • then you try to send a REQA using SendRecv command  which return 131 (0x83 = Invalid protocol) as the ProtocolSelect has failed.

So from what I see, the UART is working properly. You have to fix the ProtocolSelect command (e.g 02020200h) and fix the reception of command response:

  • read the response code byte
  • read the length byte
  • compute the actual length according to the datasheet (see  § 4.3 support of long frame)
  • read the N bytes of data

Note: you don't need to repeat the sending of echo command when you receive a correct answer. As soon as you get 0x55 answer, you can exit the initialization phase and go to the main job.

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.

I'm using a BM019 board now for evaluation purpose. The board is connected via SPI with a ESP8266 mod - Nodemcu board. The Inventory command runs for a few cycles and then anomalies stars to follow. We're coding using Arduino IDE. Here's my code:

 
// the sensor communicates using SPI, so include the library:
#include <SPI.h>
 
const int SSPin = 4;  // Slave Select pin
const int IRQPin = 5;  // Sends wake-up pulse
byte TXBuffer[40];    // transmit buffer
byte RXBuffer[40];    // receive buffer
byte NFCReady = 0;  // used to track NFC state
 
 
void setup() {
    pinMode(IRQPin, OUTPUT);
    digitalWrite(IRQPin, HIGH); // Wake up pulse
    pinMode(SSPin, OUTPUT);
    digitalWrite(SSPin, HIGH);
 
    Serial.begin(9600);
    Serial.println("Started");
    SPI.begin();
    SPI.setDataMode(SPI_MODE0);
    SPI.setBitOrder(MSBFIRST);
    SPI.setClockDivider(SPI_CLOCK_DIV32);
 
 // The CR95HF requires a wakeup pulse on its IRQ_IN pin
 // before it will select UART or SPI mode.  The IRQ_IN pin
 // is also the UART RX pin for DIN on the BM019 board.
 
    delay(10);                      // send a wake up
    digitalWrite(IRQPin, LOW);      // pulse to put the 
    delayMicroseconds(100);         // BM019 into SPI
    digitalWrite(IRQPin, HIGH);     // mode 
    delay(10);
}
 
/* IDN_Command identifies the CR95HF connected to the Arduino.
This requires three steps.
1. send command
2. poll to see if CR95HF has data
3. read the response
 
If the correct response is received the serial monitor is used
to display the CR95HF ID number and CRC code.  This rountine is 
not that useful in using the NFC functions, but is a good way to 
verify connections to the CR95HF. 
*/
void IDN_Command()
 {
 byte i = 0;
 
// step 1 send the command
  digitalWrite(SSPin, LOW);
  SPI.transfer(0);  // SPI control byte to send command to CR95HF
  SPI.transfer(1);  // IDN command
  SPI.transfer(0);  // length of data that follows is 0
  digitalWrite(SSPin, HIGH);
  delay(1);
 
// step 2, poll for data ready
// data is ready when a read byte
// has bit 3 set (ex:  B'0000 1000')
 
  digitalWrite(SSPin, LOW);
  while(RXBuffer[0] != 8)
    {
    RXBuffer[0] = SPI.transfer(0x03);  // Write 3 until
    RXBuffer[0] = RXBuffer[0] & 0x08;  // bit 3 is set
    }
  digitalWrite(SSPin, HIGH);
  delay(1);
 
 
// step 3, read the data
  digitalWrite(SSPin, LOW);
  SPI.transfer(0x02);   // SPI control byte for read         
  RXBuffer[0] = SPI.transfer(0);  // response code
  RXBuffer[1] = SPI.transfer(0);  // length of data
  for (i=0;i<RXBuffer[1];i++)      
      RXBuffer[i+2]=SPI.transfer(0);  // data
  digitalWrite(SSPin, HIGH);
  delay(1);
 
  if ((RXBuffer[0] == 0) & (RXBuffer[1] == 15))
  {  
    Serial.println("IDN COMMAND-");  //
    Serial.print("RESPONSE CODE: ");
    Serial.print(RXBuffer[0]);
    Serial.print(" LENGTH: ");
    Serial.println(RXBuffer[1]);
    Serial.print("DEVICE ID: ");
    for(i=2;i<(RXBuffer[1]);i++)
    {
      Serial.print(RXBuffer[i],HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    Serial.print("ROM CRC: ");
    Serial.print(RXBuffer[RXBuffer[1]],HEX);
    Serial.print(RXBuffer[RXBuffer[1]+1],HEX);
    Serial.println(" ");
  }
  else
    Serial.println("BAD RESPONSE TO IDN COMMAND!");
 
  Serial.println(" ");
}
 
/* SetProtocol_Command programs the CR95HF for
ISO/IEC 15693 operation.
 
This requires three steps.
1. send command
2. poll to see if CR95HF has data
3. read the response
 
If the correct response is received the serial monitor is used
to display successful programming. 
*/
void SetProtocol_Command()
 {
 byte i = 0;
 
// step 1 send the command
  digitalWrite(SSPin, LOW);
  SPI.transfer(0x00);  // SPI control byte to send command to CR95HF
  SPI.transfer(0x02);  // Set protocol command
  SPI.transfer(0x02);  // length of data to follow
  SPI.transfer(0x01);  // code for ISO/IEC 15693
  SPI.transfer(0x0D);  // Wait for SOF, 10% modulation, append CRC
  digitalWrite(SSPin, HIGH);
  delay(1);
 
// step 2, poll for data ready
 
  digitalWrite(SSPin, LOW);
  while(RXBuffer[0] != 8)
    {
    RXBuffer[0] = SPI.transfer(0x03);  // Write 3 until
    RXBuffer[0] = RXBuffer[0] & 0x08;  // bit 3 is set
    }
  digitalWrite(SSPin, HIGH);
  delay(1);
 
// step 3, read the data
  digitalWrite(SSPin, LOW);
  SPI.transfer(0x02);   // SPI control byte for read         
  RXBuffer[0] = SPI.transfer(0);  // response code
  RXBuffer[1] = SPI.transfer(0);  // length of data
  digitalWrite(SSPin, HIGH);
 
  if ((RXBuffer[0] == 0) & (RXBuffer[1] == 0))
  {
     Serial.println("PROTOCOL SET-");  //
     NFCReady = 1; // NFC is ready
  }
  else
  {
     Serial.println("BAD RESPONSE TO SET PROTOCOL");
     NFCReady = 0; // NFC not ready
  }
  Serial.println(" ");
}
 
/* Inventory_Command chekcs to see if an RF
tag is in range of the BM019.
 
This requires three steps.
1. send command
2. poll to see if CR95HF has data
3. read the response
 
If the correct response is received the serial monitor is used
to display the the RF tag's universal ID.  
*/
void Inventory_Command()
 {
 byte i = 0;
 
// step 1 send the command
  digitalWrite(SSPin, LOW);
  SPI.transfer(0x00);  // SPI control byte to send command to CR95HF
  SPI.transfer(0x04);  // Send Receive CR95HF command
  SPI.transfer(0x03);  // length of data that follows is 0
  SPI.transfer(0x26);  // request Flags byte
  SPI.transfer(0x01);  // Inventory Command for ISO/IEC 15693
  SPI.transfer(0x00);  // mask length for inventory command
  digitalWrite(SSPin, HIGH);
  delay(1);
 
// step 2, poll for data ready
// data is ready when a read byte
// has bit 3 set (ex:  B'0000 1000')
 
  digitalWrite(SSPin, LOW);
  while(RXBuffer[0] != 8)
    {
    RXBuffer[0] = SPI.transfer(0x03);  // Write 3 until
    RXBuffer[0] = RXBuffer[0] & 0x08;  // bit 3 is set
    }
  digitalWrite(SSPin, HIGH);
  delay(1);
 
 
// step 3, read the data
  digitalWrite(SSPin, LOW);
  SPI.transfer(0x02);   // SPI control byte for read         
  RXBuffer[0] = SPI.transfer(0);  // response code
  RXBuffer[1] = SPI.transfer(0);  // length of data
  for (i=0;i<RXBuffer[1];i++)      
      RXBuffer[i+2]=SPI.transfer(0);  // data
  digitalWrite(SSPin, HIGH);
  delay(1);
 
  if (RXBuffer[0] == 128)
  {  
    Serial.println("TAG DETECTED");
    Serial.print("UID: ");
 
    for(i=11;i>=4;i--)
    {
      Serial.print(RXBuffer[i],HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
        delay(500);
  }
  else
    {
    Serial.print("NO TAG IN RANGE - ");
    Serial.print("RESPONSE CODE: ");
    Serial.println(RXBuffer[0],HEX);
    }
  Serial.println(" ");
}
 
 
void loop() {
 
  if(NFCReady == 0)
  {
    IDN_Command();  // reads the CR95HF ID
    delay(1000);
    SetProtocol_Command(); // ISO 15693 settings
    delay(1000);
  }
  else
  {
    Inventory_Command();
    delay(100);    
  }  
  
}

Here's the Serial Monitor:

0690X000008BHVQQA4.png

Brian TIDAL
ST Employee

​Hi,

1/ you should reset the value of RXBuffer[0] before each while polling loops otherwise you will have unexpected results as the previous content of the buffer will be used for the test...

  RXBuffer[0] = 0;
  while(RXBuffer[0] != 8)
    {
    RXBuffer[0] = SPI.transfer(0x03);  // Write 3 until
    RXBuffer[0] = RXBuffer[0] & 0x08;  // bit 3 is set
    }

2/ the RXBuffer size should be large enough to receive the maximum frame size (528 bytes: see ST25R95 Datasheet § 4.3)

3/ the length computation should follow §4.3 of the ST25R95 Datasheet

4/ For every command (i.e. IDN, ProtocolSelect, etc.) you should read the data according to the length value

5/ I would recommend to use a dedicated function for SPI polling and for reading the result of a command. This would simplify the code structure and would avoid copy of code.

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.

Did all the changes you suggested, still the problem exists. This code was written for an Arduino UNO and it works absolutely well with it as we have tested it with an UNO as well. But with Nodemcu this problem follows. Kindly help me out with the full code to solve this problem as we've already bought 50 CR9fHF chips and we have to make it work with a Nodemcu.

Brian TIDAL
ST Employee

Hi,

would you please share details about your hardware setup:

  • MCU: NodeMCU
  • CR95HF: BM019?
  • interface between host and CR95HF: SPI or UART? In the initial post, UART was used, now it seems to be SPI.
  • interface configuration (speed, etc.)

would you please share your code and the traces when the problem occurs?

If you are using SPI, can you try to replace the SPI polling mechanism by an IRQ_OUT polling (i.e just read the IRQ_OUT value until it goes low)?

Can you try to put a logic analyzer on the interface (if using SPI, make sure to trace MOSI/MISO/SCLK/SS and IRQ_OUT)

Thanks

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.
IFroi
Associate II

Hi,

I dont know if this thread is still active but currently I'm working in a project with the same sensor (BM019). The official code for Arduino works great on Arduino Uno, but unfortunately not on a ESP8266 and I think is something related with the SPI. The clock speed is in Arduino 16Mhz and as I set the following:

SPI.setClockDivider(SPI_CLOCK_DIV32)

The speed for the bus would be 500Khz. In the esp8266 I think the speed is 80Mhz, but I set the speed manually with this:

 SPI.beginTransaction(SPISettings(15000, MSBFIRST, SPI_MODE0)); //15khz

I think that this sensor dont handle high speeds I dont find the threshold on the datasheet, despite that apperently change clock speeds in esp8266 doesnt seems to affect the behavior. I made a couple of tests with a logic analyzer and got a weird behavior for the ESP.

0690X000009YaZfQAK.png

And this is the correct behavior for the Arduino

0690X000009YaZuQAK.png

Apart from the clock speed, looks like works completly different on the ESP, my first thought was that the data overlap because of the default high speed of the ESP but seems that do the same at any speed.

Thanks in advice

Brian TIDAL
ST Employee

​Hi,

I would suggest to create a new thread as this one was initially related to an UART communication issue. Please make sure to describe your HW setup (i.e. ESP8266 MCU connected to BM019 module over SPI), the serial communication setup and your SW setup.

Regarding your question about the SPI clock frequency, the max value is defined in the CR95HF Datasheet: 2.0 MHz. Make sure to check the various SPI parameters as defined in §6.4 SPI characteristics of the Datasheet.

I had a look to the screen shots: I believe the logic analyzer is not properly configured as the MOSI and MISO values do not make any sense. Make sure to trace SCK, MISO, MISO, SPI_SS, IRQ_IN, IRQ_OUT and to provide the logic analyzer channel configuration (i.e. what is D4, what is D5, etc.). If possible, attach the logic analyzer log file rather than screen shots. Which logic analyzer do you use?

The typical startup sequence is to send a echo command, receive the echo answer and then send an IDN command:

MOSI       00 55           02 XX          00 01 00             02 XX XX XX XX XX XX XX XX XX XX XX XX ...
MISO       XX XX           XX 55          XX XX XX             XX 00 0F 4E 46 43 20 46 53 32 4A 41 53 ...
IRQ_OUT    -------------______------------------------------_________________________________________ ...
           ECHO                           IDN
                           ECHO RSP                            IDN RSP                  

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.