[SOLVED] I2C communication with an M24SR64-Y NFC tag

Hey guys,

First post here, and I'm pretty new to I2C.

As the title implies, I'm having difficulty communicating with an M24SR64-Y NFC tag by ST. It's an NFC shield, and the module is called: X-NUCLEO-NFC01A1.

So far, all I've been trying to do, is to read data from the NFC tag itself, to see if the information I've stored in the tag corresponds to what read from the Arduino. The Information has been stored onto the tag using ST's M24SR android app found on the Play Store.

I'm just generally having trouble understanding whether I'm communicating with tag in the right way, or not. According to the Datasheet, (section 7.8 ), when addressing the tag, you have the addresses: 0xAC and 0xAD.

With the Wire-library only doing 7-bit addressing, if you do the I2C scanner, you will find that the addresses you can write to are 0x56 and 0x2D, which correspond to 0xAC (LSB removed) and 0xAD (MSB removed). So far so good.

The thing is. From what I understand and according to the datasheet, is that there are a couple of "Functional Procedures" (Section 8.) that have to be executed by NFC tag, before you can read any information saved on the tag.

When sending commands to the tag, from what the datasheet refers to as C-APDU (payload format)-> consisting of data-blocks such as an I-Block, it seems like you're supposed to expect a response.

Am I supposed to expect an0 R-APDU (payload) to be sent data back to the arduino?

There is this homepage I've been referring to, a lot. The homepage uses an ST Microcontroller for its example, however, the commands that are being sent back and forth between the MCU and the NFC tag, are the exact same. Going off of the homepage's examples, there appears to be data sent back to the MCU after every "functional procedure" (command) has been sent to the NFC tag. You can find the homepage here:

http://www.nfcdynamictag.com/m24srcookbook

Another thing worth mentioning, it appears that there is a CRC operation at the end of each sent command. And when reading about the functional procedures (Section 8, datasheet), there appears to be password protection on the NDef files. I have made sure, with the android app, to remove all password protection, but I cannot help but wonder if there is a default 0x00000... password on the NDEF files.

There appears to be a german guy, who has made a library for communicating with M24SR, but it no longer works for the newest Arduino IDE. Here is his blog (german) and Github:

In the source code, he appears to be doing a CRC 16 operation. But when I do the same, and check an online CRC 16 calculator, my results are drastically different from what is to be expected (according to the data sheet - see section 7.9.1 NDef tag application command, and try doing a CRC check on the SOD field and Payload field together).

If you're wondering however, no - I do not have experience with CRC algorithms, as of yet. So I really need help :frowning:

Long story short, my first I2C project is killing me. So any help would be highly appreciated. Also, if anyone has any resources that I could check up on, I would definitely appreciate it.

I have attached my code and the datasheet to this post

If the datasheet doesn't work: here's the link:

http://www.st.com/content/ccc/resource/technical/document/datasheet/group3/a5/1d/51/09/f6/13/4f/5b/DM00067892/files/DM00067892.pdf/jcr:content/translations/en.DM00067892.pdf

Thanks in advance

Btw, I'm aware that this is horrible code, but as of right now I'm just trying to get something to work. Have I gone blind over the basics?

NFC_test2.ino (4.4 KB)

Getting the arduino library to run is not that hard. The biggest part is getting the necessary infrastructure from the various places. To simplify the task I copied the needed libraries with the modified M24SR library within a ZIP file to my web server:

http://www.linotux.ch/arduino/M24SR.zip

With that you can compile the NDefWrite example on the newest Arduino IDE 1.6.12.

Hey! Thank you so much for your help. I really appreciate it. (Where did you find the libraries?? I looked everywhere)

I'm curious though, out of the three examples, the NFCTagDisplay example does not work giving an error with "toString();". Why does "toString();" not work?

I tried looking into the library, as well as the net, there is nothing to be found regarding "toString();" function. Is there an alternative to "toString();"?

Did you install the libraries in my ZIP? I replaced the toString() call there, so it shouldn't be called anymore. If you still get the error, please post the complete error output.
The author of the M24SR library patched a library to have some new methods which the original doesn't have. So I patched his library to not use this methods anymore. A toString() method is just a waste of resources. The original library has a print method which does what you probably need.

When compiling the NfcTagDisplay, the code gets stuck in the "void displayNdefRecord()" function. What he seems to be doing is, he appears to be gathering data with "rec" from the getRecord(0), and then convert "rec" into a string.

I haven't really played that much around with it as of yet, but it gives the following error.


NfcTagDisplay:134: error: 'class NdefRecord' has no member named 'toString'

String txt = rec.toString();

^

exit status 1
'class NdefRecord' has no member named 'toString'


*Edit,
I've also found where you've removed the toString(); that's not the section of concern. The problem appears more rooted than that. The problem seems to lie with the fact, that the author seems to be trying to convert a nonscalar object into a String with the "toString();", a method nowhere to be found.

As of right now, I've been trying to find ways to convert whatever the "rec" object points to, into a String. Nothing seems to work, as of right now.

*Edit2, I've tried looking for the NdefRecord class in the libraries, I can't seem to find it anywhere. It's only found in 3 places on the m24sr.cpp file and nowhere to be found on the header file. I was thinking of making my own toString(); function.

I did not check all examples, please excuse.

Change these lines:

       String txt = rec.toString();
       Serial.print(F("NDefRecord: "));
       Serial.println(txt);

to

       Serial.print(F("NDefRecord: "));
       rec.print();

and it will compile and probably work as expected.

LOL, omg, thanks dude It appears to be working now - I must have been going nuts for a while. I can at least read the data I've saved on the NFC tag

Sweet baby jesus

Hi,
I'm using the M24SR64-Y NFC. I would like the NFC device to trigger an Interrupt and this needs to be handled by a callback function. I would appreciate if anyone can help me on this with a sample code.

Thanks
Aswin Paranji

Hi,
I try the above examples, but always had troubles and freezing of software, so looking around I founded this code that working for me:

/* NFC.ino  02/04/2015  D.J.Whale
 *
 * Please note: This program is a hardware test program only.
 * It was written under extreme time pressure, and should only
 * be used as a reference that defines a set of sequences that
 * are known to work with the boards listed below. It is not
 * in any way a representation of good programming practice...
 * ... that takes more than a couple of hours to achieve.
 *
 * Test program for Arduino Uno to read a URI NDEF record from M24SR.
 * Wire up a X-NUCLEO-NFC01A1 to the SCL/SCA pins.
 * Download this program and run it.
 * On the serial monitor, you should see a series of trace messages
 * for each step, plus the URL near the end that is read back from the
 * NDEF record.
 * If you get loads of 00 or FF data back, you probably don't have
 * 4.7K pullup resistors on both of SCL and SDA.
 */
 
#include <Wire.h>

// LEDs on X-NUCLEO board
#define LED1 5
#define LED2 4
#define LED3 2

// LED2 is used to put a capture region around the NDEF read, so that
// a scope or logic analyser can easily find the frames of interest
// by triggering on rising-high of that pin.
#define CAPTURE LED2

#define NFC_ADDR_7BIT 0x56

void setup() 
{                
  pinMode(LED1, OUTPUT); 
  pinMode(LED2, OUTPUT); 
  pinMode(LED3, OUTPUT); 
  Wire.begin();
  Serial.begin(9600);
}

byte selectI2C[]      = {0x52};
byte selectNFCApp[]   = {0x02,0x00,0xA4,0x04,0x00,0x07,0xD2,0x76,0x00,0x00,0x85,0x01,0x01,0x00,0x35,0xC0};
byte selectCCFile[]   = {0x03,0x00,0xA4,0x00,0x0C,0x02,0xE1,0x03,0xD2,0xAF};
byte readCCLen[]      = {0x02,0x00,0xB0,0x00,0x00,0x02,0x6B,0x7D};
byte readCCFile[]     = {0x03,0x00,0xB0,0x00,0x00,0x0F,0xA5,0xA2};
byte selectNDEFFile[] = {0x02,0x00,0xA4,0x00,0x0C,0x02,0x00,0x01,0x3E,0xFD};
byte readNDEFLen[]    = {0x03,0x00,0xB0,0x00,0x00,0x02,0x40,0x79};
byte readNDEFMsg[]    = {0x02,0x00,0xB0,0x00,0x02,0x0C,0xA5,0xA7};
byte deselectI2C[]    = {0xC2,0xE0,0xB4};

// The delays are required, to allow the M24SR time to process commands.

void loop()
{
  Serial.println("\nstarting");
  digitalWrite(LED1, HIGH);

  // kill RF, select I2C
  Serial.println("selectI2C");
  Wire.beginTransmission(NFC_ADDR_7BIT);
  Wire.write(selectI2C, sizeof(selectI2C));
  Wire.endTransmission();
  delay(1);
  
  //select NFC app
  Serial.println("selectNFCApp");
  Wire.beginTransmission(NFC_ADDR_7BIT);
  Wire.write(selectNFCApp, sizeof(selectNFCApp));
  Wire.endTransmission();
  delay(1);
  readAndDisplay(5);
  
  
  //select CC file
  Serial.println("selectCCFile");
  Wire.beginTransmission(NFC_ADDR_7BIT);
  Wire.write(selectCCFile, sizeof(selectCCFile));
  Wire.endTransmission();
  delay(1);
  readAndDisplay(5);

  //readCCLen
  Serial.println("readCCLen");
  Wire.beginTransmission(NFC_ADDR_7BIT);
  Wire.write(readCCLen, sizeof(readCCLen));
  Wire.endTransmission();
  delay(1);
  readAndDisplay(7);

  int len=20; //TODO get from above payload, not overly critical

  //readCCFile
  Serial.println("readCCFile");
  Wire.beginTransmission(NFC_ADDR_7BIT);
  Wire.write(readCCFile, sizeof(readCCFile));
  Wire.endTransmission();
  delay(1);
  readAndDisplay(len);
  
  
  //selectNDEFFile
  Serial.println("selectNDEFFile");
  Wire.beginTransmission(NFC_ADDR_7BIT);
  Wire.write(selectNDEFFile, sizeof(selectNDEFFile));
  Wire.endTransmission();
  delay(1);
  readAndDisplay(5);
  
  
  //readNDEFLen
  Serial.println("readNDEFLen");
  digitalWrite(CAPTURE, HIGH); // so we can capture on logic analyser
  Wire.beginTransmission(NFC_ADDR_7BIT);
  Wire.write(readNDEFLen, sizeof(readNDEFLen));
  Wire.endTransmission();
  delay(1);
  
  Wire.requestFrom(NFC_ADDR_7BIT, 7);
  int idx = 0;
  while (Wire.available())
  {
    byte b = Wire.read();
    Serial.print(b, HEX);
    Serial.write(' ');
    if (idx == 2) // TODO max len is 255?
    {
      len = b;
    }
    idx++;
  }
  Serial.println();


  //readNDEFMsg
  //len = full NDEF length, (5 byte prefix+actual URI)
  Serial.println("readNDEFMsg");
  Wire.beginTransmission(NFC_ADDR_7BIT);
  // Patch in the length and fix the broken CRC
  readNDEFMsg[5] = len; // this is the len returned from ReadNDEFLen
  ComputeCrc(readNDEFMsg, sizeof(readNDEFMsg)-2, &(readNDEFMsg[6]), &(readNDEFMsg[7]));
  Wire.write(readNDEFMsg, sizeof(readNDEFMsg));
  Wire.endTransmission();
  delay(1);

// (PCB,SW1,SW2,CRC0,CRC1)
#define PROTO_OVERHEAD 5
// 5 bytes for NDEF header (in URI format)
#define HEADER_LEN 5

  int msgStart = 1 + HEADER_LEN;
  int msgEnd   = 1 + HEADER_LEN + (len-HEADER_LEN);
  
  Wire.requestFrom(NFC_ADDR_7BIT, len+PROTO_OVERHEAD);
  idx = 0;
  while (Wire.available())
  {
    byte b = Wire.read();
    if (idx >= msgStart && idx <= msgEnd)
    {
      Serial.write(b);
    }
    idx++;
  }
  Serial.println();  
  //readAndDisplay(len+PROTO_OVERHEAD);
  
  digitalWrite(CAPTURE, LOW); // marks end of capture region for logic analyser


  //deselectI2C
  Serial.println("deselectI2C");
  Wire.beginTransmission(NFC_ADDR_7BIT);
  Wire.write(deselectI2C, sizeof(deselectI2C));
  Wire.endTransmission();
  delay(1);
  readAndDisplay(3);  
  
  digitalWrite(LED1, LOW);
  delay(2000);
}


void readAndDisplay(int len)
{
  Wire.requestFrom(NFC_ADDR_7BIT, len);
  while (Wire.available())
  {
    Serial.print(Wire.read(), HEX);
    Serial.write(' ');
  }
  Serial.println();
}


word UpdateCrc(byte data, word *pwCrc)
{
  data = (data^(byte)((*pwCrc) & 0x00FF));
  data = (data^(data << 4));
  *pwCrc = (*pwCrc >> 8) 
         ^ ((word)data << 8) 
         ^ ((word)data << 3) 
         ^ ((word)data >> 4);
  return *pwCrc;
}


word ComputeCrc(byte *data, unsigned int len, byte *crc0, byte *crc1)
{
  byte bBlock;
  word wCrc;

  wCrc = 0x6363;

  do
  {
    bBlock = *data++;
    UpdateCrc(bBlock, &wCrc);
  }
  while (--len);

  *crc0 = (byte) (wCrc & 0xFF);
  *crc1 = (byte) ((wCrc >> 8) & 0xFF);
  return wCrc;
}

/* END OF FILE */

But I have still troubles with the simple reading of data from a iso15693 card.
Anyone could help me?

Someone is able to read card directly?

Thanks,

Silvio