RFID reader/writer (again).. help on where to begin in the datasheet?

hey gang-

I have this RFID reader/writer, that I still dont understand enough to WRITE or edit any data on it…

Its an SPI RFID reader/writer…

and I have read up about the SPI protocol a bit here:

and understand the master/slave architecture/set-up

(I read the comments & understood (by default) enough on how to read a card that is swiped… get the S/N of the card… and use that as a ‘hard coded’ check to see if its the white card or the blue key fob I’m swiping)

not really a true understanding by any stretch… all done so far by searching the net for others who have the same ‘product’… and compiling comments from all edited sketches and putting them into this one. (attached: RFID_commented_code.txt)

I have attached datasheet and some other .pdfs that came along with it… (and the default sketches in case I messed something up in mine) (attached: RFID_SOURCE_FILES.zip)

I know I have it hooked up correctly (physically, as I am getting reads…etc)…

I guess Im looking for a kind soul to take pity on a noob and help me make some sense of the datasheet… where I should be focused…(what area)

I think section 9.1 is (what I thought) the place to be focused on… as that is the REGISTERS section?

But Im not really understanding how to “USE” this data in the read/write functions I see available to us?

I see in the sketch there are a bunch of ‘registers’ DEFINED# at the top… (but again not really sure how Im suppose to correctly use them… and handle the returned (if any) data…)

once the most recurring questions I saw on every post & forums around was HOW are we supposed to:

1.) read the password? (in something legible)
2.) how are we supposed to write/change the password to another one? (in a legible manner again)

but in the grander scheme… I want to be able to use the datasheet… and unfortunately, need some direction/help.

My own personal questions (in no particular order, and I know are a bit vague/broad)

1.) without code… a general explanation of how the the read/write functions with this RFID card work…

basically you take one of the functions…

give it an ‘address’ it needs to either read or write to?.. and the second params is the ‘data/value’ to be written? (if its a write function for example)

I have things commented out next to each function… but I think Im missing an understanding of the registers ‘stuff’ to make it all click/work?

2.) I dont understand the difference between the TWO read functions and the TWO write functions?? (the names seems to be in different order:




(seems they return different value…one is a status and one a value?)

* Function: Read_MFRC522()
 * Description: read a byte data in one register of MR RC522
 * Input parameter: (addr--register address)
 * Return: returns the read value
uchar Read_MFRC522(uchar addr){
  uchar val;
  digitalWrite(chipSelectPin, LOW);
  SPI.transfer(((addr<<1)&0x7E) | 0x80);	
  val =SPI.transfer(0x00);
  digitalWrite(chipSelectPin, HIGH);
  return val;	

* Function: MFRC522_Read()
 * Description: Read data 
 * Input parameters: (blockAddr--block address, recvData--the block data which are read)
 * return: returns MI_OK (if success)
uchar MFRC522_Read(uchar blockAddr, uchar *recvData){
  uchar status;
  uint unLen;

  recvData[0] = PICC_READ;
  recvData[1] = blockAddr;
  CalulateCRC(recvData, 2, &recvData[2]);
  status = MFRC522_ToCard(PCD_TRANSCEIVE, recvData, 4, recvData, &unLen);

  if ((status != MI_OK) || (unLen != 0x90)){
    status = MI_ERR;
  return status;

I guess I’ll stop there…

this is doing my head in!.. I skim the info a few times every known and then… hoping it will ‘click/sink’ in… or I could see some ‘noob’ examples to make it more understandable…

but I think I need a push in the right direction here, to fully utilize the card for write abilities… (like keeping track of money on the card like the example sorta indicates…changing passwords on the card…etc…etc.)


RFID_commented_code.txt (25.4 KB)


If got a fairly simple sketch that reads an RFID reader and compares the serial number on it to a fixed list:


Hi Nick-

I was editing my post as you posted… :slight_smile:

does it matter yours is an ID-12 reader and mine is SPI based?

side questions… which is much more, beginner “C” question Im guessing…

some noob explanation of ow str is getting populated with any data? here in the beginning of the script (loop)… you see this:

***edit: I think I see how ts getting populated eventually, at the end of the MFRC522_ToCard() function call…
how and with what…I havent tried to trace it that closely… but at least I found that part…

</end edit>

#include <SPI.h>

#define	uchar	unsigned char
#define	uint	unsigned int
#define MAX_LEN 16

void loop()
  uchar i,tmp;
  uchar status;
  uchar str[MAX_LEN];
  uchar RC_size;
  uchar blockAddr;  //Select operation block address  0 - 63

  //Search card, return card types
  status = MFRC522_Request(PICC_REQIDL, str);	
  if (status == MI_OK){
    Serial.println("CARD DETECTED IN PROXIMITY....");
    Serial.print("CARD TYPE: ");
    Serial.print(" / ");
    Serial.print("STATUS CODE: ");
    //Serial.println(" ");

create a var called MAX_LEN = 16
then, to me… we create a new (empty) array called str in the beginning… it has 16 index/slots long? (based on the str[MAX_LEN] parameter correct? (rule is: you have to give your arrays a length in C, that cant be ‘dynamically filled’ to whatever amount?)

Im used to be able to do:

var someArray:Array = new Array();
and I can push/populate that to my hearts content (no defining the length prior)… I understand I have been spoiled by this… but is this correct you must define a length… (in C)… (better for memory management I guess?)

here is the function called above, that sets the ‘STATUS’ var… (again Im curious as to how str is being populated… so I am able to grab the data in each index like in the above snippet)

* Function: MFRC522_Request()
 * Description: Searching card, read card type
 * Input parameter: (reqMode--search methods, TagType--return card types)
 *     0x4400 = Mifare_UltraLight
 *     0x0400 = Mifare_One(S50)
 *     0x0200 = Mifare_One(S70)
 *     0x0800 = Mifare_Pro(X)
 *     0x4403 = Mifare_DESFire
 * return: return MI_OK (if success)
uchar MFRC522_Request(uchar reqMode, uchar *TagType){
  uchar status;  
  uint backBits;      //the data bits that received
  Write_MFRC522(BitFramingReg, 0x07);	//TxLastBists = BitFramingReg[2..0]	???

  TagType[0] = reqMode;
  status = MFRC522_ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits);

  if ((status != MI_OK) || (backBits != 0x10)){    
    status = MI_ERR;
  return status;

I see the (empty?) array is passed along to this function, as the second parameter/argument…(as TagType)… (! what does the "" mean in front? !)

then it looks like we are populating index 0 of the str array…with the reqMode (parameter we just passed the same function?) value?

from there… Im a bit lost… seems we call another function (write) and send this array (as the *sendData * *backData arguments of that function?

(posting it here in case it helps?)…

I dont wanna post to much and clutter… and i dont wanna get too lost either… (Im trying to understand piece by piece here…LOL)

toCard function:

* Function: MFRC522_ToCard()
 * Description: communicate between RC522 and ISO14443
 * Input parameter: (command--MF522 command bits, 
 		     sendData--send data to card via rc522, 
 		     sendLen--send data length, 
 		     backData--the return data from card, 
 		     backLen--the length of return data)
 *return: return MI_OK (if success)
uchar MFRC522_ToCard(uchar command, uchar *sendData, uchar sendLen, uchar *backData, uint *backLen){
  uchar status = MI_ERR;
  uchar irqEn = 0x00;
  uchar waitIRq = 0x00;
  uchar lastBits;
  uchar n;
  uint i;
  switch (command){
  case PCD_AUTHENT: // verify card password
      irqEn = 0x12;
      waitIRq = 0x10;
  case PCD_TRANSCEIVE: // send data in the FIFO
      irqEn = 0x77;
      waitIRq = 0x30;

  Write_MFRC522(CommIEnReg, irqEn|0x80);	//Allow interruption
  ClearBitMask(CommIrqReg, 0x80);		//Clear all the interrupt bits
  SetBitMask(FIFOLevelReg, 0x80);		//FlushBuffer=1, FIFO initilizate

  Write_MFRC522(CommandReg, PCD_IDLE);	//NO action / cancel current command?

  for (i=0; i<sendLen; i++){   
    Write_MFRC522(FIFODataReg, sendData[i]);    

  Write_MFRC522(CommandReg, command);
  if (command == PCD_TRANSCEIVE){    
    SetBitMask(BitFramingReg, 0x80);		//StartSend=1,transmission of data starts  

  //wait receive data is finished
  i = 2000;	//i should adjust according the clock, the maxium the waiting time should be 25 ms???
    //Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq
    n = Read_MFRC522(CommIrqReg);
  while ((i!=0) && !(n&0x01) && !(n&waitIRq));

  ClearBitMask(BitFramingReg, 0x80);			//StartSend=0
  if (i != 0){    
    if(!(Read_MFRC522(ErrorReg) & 0x1B)){  // BufferOvfl Collerr CRCErr ProtecolErr
      status = MI_OK;
      if (n & irqEn & 0x01){   
        status = MI_NOTAGERR;			//??   
      if (command == PCD_TRANSCEIVE){
        n = Read_MFRC522(FIFOLevelReg);
        lastBits = Read_MFRC522(ControlReg) & 0x07;
        if (lastBits){   
          *backLen = (n-1)*8 + lastBits;   
          *backLen = n*8;   
        if (n == 0){   
          n = 1;    
        if (n > MAX_LEN){   
          n = MAX_LEN;   

        //read the data from FIFO
        for (i=0; i<n; i++){   
          backData[i] = Read_MFRC522(FIFODataReg);    
      status = MI_ERR;  
  //SetBitMask(ControlReg,0x80);           //timer stops
  //Write_MFRC522(CommandReg, PCD_IDLE); 
  return status;

Looking at some ‘Jeremy Blum’ tutorial on-line… it looks as if the UART version is easier to work with? (shame as I already have this and it was only $20.00)

(my only redemption I have is that every thread/forum/post I have read…everyone to seems to be in the same place as I am with this ‘demo code’ LOL)



SPI isn't that hard.


My sketch wasn't that complex. I could probably advise more if I had a link to the datasheet for your reader.

some noob explanation of ow str[] is getting populated with any data? here in the beginning of the script (loop)..

I presume this line writes to str:

status = MFRC522_Request(PICC_REQIDL, str);

Hi Nick-

I have tried/did a little SPI communication with the MAX7221 chip before... but understanding this RFID is confusing for me.

(especially what registers/areas I can write to? which I cant?..etc..etc)

Also.. the link to the datasheet is in the first post.. (I zipped the .pdf's up and posted as attachment)

as far as str[] getting populated question..

I had posted an edit to the thread above saying I found it..

I didnt see it in the function you requested.. I had to follow the code a bit more to see another function that was called inside that function to see where (I posted the function above as well where it was found..etc)

I see. This chip is somewhat more complex than the serial RFID reader I linked to.

I'm sorry but I don't have time to read and understand 109 pages of the PDF right now. I gather the chip interfaces with different card types, so you would need to choose exactly what you need to achieve and work that out from the datasheet. The example code may (or may not) help understand the datasheet.

I've been working on a L6470 motor driver chip, which has similar levels of complexity (or less, even) and it has taken me a few days of work (a week maybe) to work my way through all their registers and stuff.

If you ask a specific question, I'm sure that someone will try to help.

I want to use interrupt of rc522 , but it's my badluck I couldn't understand how to configure command registers to enable RxIEn ( receive interrupt ) using MFRC522.h library . Pls help me .