iwanders / MFRC630

A library for NXP's MFRC630 NFC IC.
MIT License
59 stars 22 forks source link

ISO15693 #4

Open sgtJohnny opened 6 years ago

sgtJohnny commented 6 years ago

Hello,

Do you have any info on how to advance this library to read ISO15693 tags (with CLRC663) ?

iwanders commented 6 years ago

The RF side of things appears to be covered by the chip, protocol number 10, 11 and 12 according to AN11022, so that part is likely done after loading those protocols with the chip.

The hard part would be to implement the anticollision and transmission protocol, this is described in ISO/IEC 15693-3. Which - like a lot of standards - is not freely available unfortunately :disappointed: . If you obtain this - or a draft - it should describe the protocol that needs to be implemented. I presume it is pretty different from the ISO14443A protocol, given that a quick search for a library that implements it turns up no real results.

To get it to work one needs to implement the anti collision and transmission protocol for ISO15693. This is probably a fair bit of non-trivial work unfortunately. I don't have access to the hardware anymore, so there's little I can do to help. I'll leave this issue open, if there are others who would like to see ISO15693 implemented this may allow you to collaborate with them.

sgtJohnny commented 6 years ago

Thanks for your reply. I found a software with examples from nxp "PCSerial". My best guess is that this sends just SPI transmissions to the CLRC663 http://www.nxp.com/documents/software/210910.zip

If i look at the example with ISO14443A_4byteUID.jcf i see alot in common with your library, and the ISO15693_Inventroy.jcf looks different, but in general it looks very similar.

Maybe you could have a look?

iwanders commented 6 years ago

I took a look. Does indeed appear to necessary operations on the chip. It's probably SR = set register, GR = get register.

I don't really see any similarity between that .jcf file and the .c library, but you probably mean that the steps they take are the same. Which makes sense as the steps to read an ISO14443A card will be the same, regardless of which language you specify it in. Don't think they have proper anti-collision handling code.

You could probably try to perform the register read and writes they perform to read the UUID of the card for ISO15693. It may just work if you are trying to read one card only, but having this specific sequence of commands is a whole other thing then adding proper support for ISO15693 to the library.

LinnHtunThaw commented 6 years ago

You can get the NFC reader library from this link- https://www.nxp.com/products/identification-and-security/nfc/nfc-reader-ics/nfc-reader-library-software-support-for-nfc-frontend-solutions:NFC-READER-LIBRARY?tab=In-Depth_Tab It also includes the library for ISO15693.

benbecke commented 4 years ago

What is the status on that ? @sgtJohnny did you get this implemented ?

peturdainn commented 4 years ago

I can confirm you can talk ISO15693 with this chip (SLRC610 actually but they are close). Sadly I can't share the code (commercial customer), but you can find very good sample code for TI chips for the collision handling (lots of TI doc also leak quite a bit of the spec). It's not very hard to port it, just check what functionality in the TI chip they are touching and find the similar one in the NXP chip.

sgtJohnny commented 4 years ago

I can also confirm, i've only implemented "Inventory" without colision detection, since in my case there cannot be colision (mechanically), so it works. There is a "PcSerial" script from NXP that can be converted to this library. I've i have some time, i will create pull request and modify, i had to convert this library to C++ so i need to make changes in this C version. I'm using the CLRC663 which can be both (14443 and 15693) but the three chips : MFRC630, SLC610,CLRC663 are identical, there functionality is just software locked by nxp...

If you need code sample, send me a message

benbecke commented 4 years ago

@sgtJohnny : I would be real thankful for an example. In the meantime i will try to understand the specifications around 15693..... To the others : thank you for the information around the differences of the protocols.....

sgtJohnny commented 4 years ago

okay this is a short example, there is more values, but its to much to post in a comment:

you need to add new definiton for protocol type: #define MFRC630_PROTO_ISO15693_1_OF_4_SSC26 10

after that you need to add a parameter macro: #define MFRC630_RECOM_15693_ID2_SSC26 {0x8F, 0x10, 0x01, 0x06, 0x7B, 0x7B, 0x08, 0x00, 0x00, 0x88, 0xA9, 0x0F, 0x00, 0x02,0x10,0x44,0x12,0x06}

now its possible to modify functions AN1102_recommended_registers_skip this allows you to configure the reader to to accept ISO15693.

After this, its possible to read iso15693 using following code:

uint16_t CLRC663::iso15693_read(uint8_t* uid) {

        uint8_t status =0;
        uint8_t inventory[16];
        write_reg(MFRC630_REG_DRVMOD,0x89); //Field on

        // Set short timeout. Timer-0,Timer-1 reload values(hi,lo)
        write_reg(MFRC630_REG_T0RELOADHI,0x24);
        write_reg(MFRC630_REG_T0RELOADLO,0xEB);
        write_reg(MFRC630_REG_T1RELOADHI,0x00);
        write_reg(MFRC630_REG_T1RELOADLO,0x00);

        // Cancel any command execution.Flush FIFO. Clear IRQ0,IRQ1
        write_reg(MFRC630_REG_COMMAND,0x00);
        write_reg(MFRC630_REG_FIFOCONTROL ,0xB0);
        write_reg(MFRC630_REG_IRQ0,0x7F);
        write_reg(MFRC630_REG_IRQ1,0x7F);

        // Write: "Flags" and "Inventory" cmd in FIFO

        write_reg(MFRC630_REG_FIFODATA ,0x36);
        write_reg(MFRC630_REG_FIFODATA ,0x01);
        write_reg(MFRC630_REG_FIFODATA ,0x00);
        write_reg(MFRC630_REG_FIFODATA ,0x00);
        write_reg(MFRC630_REG_COMMAND ,0x07);

        // Wait until the command is finished
        // Enable IRQ0,IRQ1 interrupt sources
        inventory[0] = read_reg(MFRC630_REG_IRQ0EN);
        write_reg(MFRC630_REG_IRQ0EN,0x18);
        inventory[0]= read_reg(MFRC630_REG_IRQ1EN);
        write_reg(MFRC630_REG_IRQ1EN,0x42);

        inventory[1]= read_reg(MFRC630_REG_IRQ1);

        uint8_t irq0_value = 0;
        uint8_t irq1_value = 0;

        //Wait for transmission ending
        while ((irq0_value & 0x08) !=0x08){
            irq0_value = irq0();

        }

        inventory[2] = read_reg(MFRC630_REG_IRQ0);
        inventory[3] = read_reg(MFRC630_REG_IRQ1);

        //Wait for timer1 underflow irq1(0x02) or RxIrQ irq0(0x04);
        while ( ((irq1_value & 0x02) !=0x02)  && ((irq0_value & 0x04) !=0x04)   ){
            irq1_value = irq1();
            irq0_value = irq0();

        };

        if((irq1_value & 0x02)){
            status = 0xFF;
            return status;
        };

        inventory[4] = read_reg(MFRC630_REG_IRQ0);
        inventory[5] = read_reg(MFRC630_REG_IRQ1);

        // Disable IRQ0,IRQ1 interrupt sources
        inventory[6] = read_reg(MFRC630_REG_IRQ0EN);
        write_reg(MFRC630_REG_IRQ0EN,0x00);
        inventory[6] = read_reg(MFRC630_REG_IRQ1EN);
        write_reg(MFRC630_REG_IRQ1EN,0x00);

        // Get IRQ0 status
        inventory[6] = read_reg(MFRC630_REG_IRQ0);
        inventory[7]= read_reg(MFRC630_REG_IRQ1);

        //get lenght of uid
        uint8_t uidlenght = read_reg(MFRC630_REG_FIFOLENGTH);

        if(uidlenght != 10){
            status = 0xFE;
            return status;

        }

        //read uid
        uid[0] = read_reg(MFRC630_REG_FIFODATA);
        uid[1] = read_reg(MFRC630_REG_FIFODATA);
        uid[2] = read_reg(MFRC630_REG_FIFODATA);
        uid[3] = read_reg(MFRC630_REG_FIFODATA);
        uid[4] = read_reg(MFRC630_REG_FIFODATA);
        uid[5] = read_reg(MFRC630_REG_FIFODATA);
        uid[6] = read_reg(MFRC630_REG_FIFODATA);
        uid[7] = read_reg(MFRC630_REG_FIFODATA);
        uid[8] = read_reg(MFRC630_REG_FIFODATA);
        uid[9] = read_reg(MFRC630_REG_FIFODATA);

        inventory[9] = read_reg(MFRC630_REG_IRQ0);
        inventory[10] = read_reg(MFRC630_REG_IRQ1);
        inventory[11] = read_reg(MFRC630_REG_FIFOLENGTH);

        // Read Error status register

        inventory[12] = read_reg(MFRC630_REG_ERROR );

        inventory[13] = read_reg(MFRC630_REG_TXDATANUM);
        write_reg(MFRC630_REG_TXDATANUM,0x08);
        inventory[14] = read_reg(MFRC630_REG_RXBITCTRL);
        inventory[15] = read_reg(MFRC630_REG_TXDATANUM);
        write_reg(MFRC630_REG_TXDATANUM,0x08);

        //Apply waiting time
        write_reg(MFRC630_REG_T0RELOADHI,0x20);
        write_reg(MFRC630_REG_T0RELOADLO,0xFF);
        write_reg(MFRC630_REG_T1RELOADHI,0x00);
        write_reg(MFRC630_REG_T1RELOADLO,0x00);
        inventory[14] = read_reg(0x0E);
        write_reg(MFRC630_REG_IRQ1,0x7F);   // Clear all IRQ1 flags

        status = 1;
        return status;
}
benbecke commented 4 years ago

Thank you very much. I did some tests. Code seems to be ok but always ending up in a Soft WDT Reset @ while loop checking both irq1_value and irq0_value :-/

sgtJohnny commented 4 years ago

What MCU you use? Try to print out irq values, if arduino, use Serial.print(). If STM32 use SWO Trace Debug.

benbecke commented 4 years ago

I use esp8266 and clrc663 over spi. Values always are : Inventory[2]: 13 Inventory[3]: 32 irq0_value: 13 irq1_value: 32

So interesting after reflashing mcu reset seems to be gone but no card is detected and its jumping out where uidlenght is checked for length of 10.... :-/

Maybe we better can talk over mail -bmm.becker {at} gmail.com-

iwanders commented 4 years ago

@benbecke , @sgtJohnny , ( @peturdainn ) just reading up on this now. I still don't have anything to add, but I'm really happy to see others chime in and help out where I couldn't.

@sgtJohnny , I took the liberty of putting the large piece of code in a code block:

```cpp void foo(); ```

Given that there's already three people who've worked on this, it is probably something others may be interested as well. So if you or anyone has an example and is willing (and able) to share it I'd be happy to make sure it's added to the repo.

sgtJohnny commented 4 years ago

@iwanders i already cloned the repository to my desktop and i'm currently implementing the iso15693 part and try to beautify (its just lines of uncommented code rn). I will send you request once i've finished an tested! :) I also add a few other features if implemented

sgtJohnny commented 4 years ago

Will finish work on the code this week and send to you

srcnert commented 3 years ago

Hi @sgtJohnny

Can you share code for ISO15693 standard?

iwanders commented 3 years ago

@srcnert , I think this is shared in #13 , you should be able to try that branch. I still have some concerns with that PR that prevent me from merging it into master.

@sgtJohnny , should we maybe merge that into a seperate branch in this main repo and add a link to it in the readme? It may make it easier to find for others untill the issues I raised are resolved and it can be merged into master.

ic-twist commented 4 months ago

@sgtJohnny Did you or anyone else use NXP's CLEV6630B evaluation board or CLEV6630ARD board for testing and verification of your software?

My hardware setup NXP CLEV6630B eval board connected to Arduino Mega Rev3 through SPI interface.

Software setup Using @sgtJohnny 's iso15693 branch, modified SPI clock rate from 10MHz to 5MHz as shown below. As 10MHz was too fast for my Arduino to drive good SPI signals. SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE0));

Problem Not able to read ISO15693 NFC tags.

What I've Tried

  1. I used a logic analyzer and saw correct bytes (appears to match the firmware) are sending over SPI interface from Arduino Mega to the CLRC663 chip.
  2. I also tried adding the command to turn on RF field in the setup. Please see my setup code below:

    void setup()
    {
    // Start serial communication.
    Serial.begin(9600);
    
    // Set the chip select pin to output.
    pinMode(CHIP_SELECT, OUTPUT);
    digitalWrite(CHIP_SELECT, HIGH);
    
    // Start the SPI bus.
    SPI.begin();
    delay(1000);
    const uint8_t ic_version = mfrc630_read_reg(MFRC630_REG_VERSION);
    Serial.println(ic_version);
    
    // Set the registers of the MFRC630 into the default.
    mfrc630_AN1102_recommended_registers(MFRC630_PROTO_ISO15693_1_OF_4_SSC);
    
    // RF on
    mfrc630_read_reg(MFRC630_REG_DRVMOD);
    mfrc630_write_reg(MFRC630_REG_DRVMOD, 0x89);
    }
  3. I compared the SPI traffic generated by the Arduino code with the SPI traffic generated by the NXP Cockpit GUI software and they don't seem to match up.

My Speculations I'm wondering if the command to read ISO15693 inventory was implemented correctly.