Skip to main content
Visitor II
March 19, 2019
Question

Can't communicate with CR95HF over UART

  • March 19, 2019
  • 7 replies
  • 2416 views

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

    This topic has been closed for replies.

    7 replies

    Technical Moderator
    March 23, 2019

    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

    PGupt.17Author
    Visitor II
    April 2, 2019

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

    Technical Moderator
    April 2, 2019

    ​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

    PGupt.17Author
    Visitor II
    May 6, 2019

    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

    Technical Moderator
    May 6, 2019

    ​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

    PGupt.17Author
    Visitor II
    May 11, 2019

    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.

    Technical Moderator
    May 12, 2019

    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

    Visitor II
    July 9, 2019

    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

    Technical Moderator
    July 10, 2019

    ​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