My Cart

RFID 13.56 MHz / NFC Module for Arduino and Raspberry Pi

Difficulty Level: Intermediate -

Introduction

RFID (Radio Frequency Identification) is a technology that uses electromagnetic fields to identify objects in a contactless way; it is also called proximity identification. There are 2 elements in RFID communications: the RFID module (or reader/writer device) and an RFID card (or tag). The RFID module acts as the master and the card acts as the slave; this means the module queries the card and sends instructions to it. In a normal RFID communication, the RFID module is fixed and the user takes his card near it when he needs to start the interaction.

Ingredients:

Preparation Time: 20 minutes

Cooking Hacks offers Mifare® Classic 1k cards tags, stickers and key rings along with the RFID/NFC module for Arduino and Raspberry Pi. A Mifare® Classic 1k tag has 1024 bytes of internal storage capacity, divided into 16 sectors. Each sector is composed of 4 blocks, and each block is composed of 16 bytes. That is to say, each card has 64 blocks, from number 0 to 63. Blocks number 3, 7, 11 is called the sector trailer. This block stores the 2 keys or passwords and controls the access to the rest of the blocks in the sector.

Step 1: Connecting the RFID/NFC module

Connecting the RFID/NFC module to Arduino

Setting up the hardware is very easy, just plug the XBee shield with the RFID/NFC module to Arduino. The jumpers in the XBee shield have to be set to XBEE position. See the picture.

Now you can program the Arduino and communicate it with the RFID/NFC module using the serial port (Serial.read(), Serial.print()...). Remember you must unplug the XBee shield when uploading code to Arduino.

Connecting the RFID/NFC module to Raspberry Pi

Connect the RFID module to Raspberry Pi using the Raspberry Pi to Arduino shields connection bridge as shown in the picture.

Step 2 : Reading tags (read only cards)

In this part we show an example of the Arduino reading Mifare tags. We use the Auto Read mode. Arduino is waiting all the time, when a tag is detected, we read its code, and print the code over USB port.

Arduino:

Code:
/*  
 *  RFID 13.56 MHz / NFC Module
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Ahmad Saad & Javier Solobera
 */

uint8_t dataRX[35];//Receive buffer.
uint8_t dataTX[35];//Transmit buffer.
uint8_t _UID[4];// stores the UID (unique identifier) of a card.
uint8_t keyAccess[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } ;// stores the key or password.
uint8_t address = 0x04;//Address to read.
uint8_t ATQ[2];//Answer to request
uint8_t state;//state of the process
uint8_t aux[16];//Auxiliar buffer. 

void setup()
{
	//Start serial port 115200 bps:
	Serial.begin(115200);
	delay(100);
	Serial.print("RFID/NFC @ 13.56 MHz module started");
	delay(1000);
	//!It is needed to launch a simple command to sycnchronize
	getFirmware();
	configureSAM();
}

void loop()
{
	Serial.print("\n");
	Serial.println("Ready to read...");
	/////////////////////////////////////////////////////////////
	//Get the UID Identifier
	init(_UID, ATQ);
	Serial.print("\n");
	Serial.print( "The UID : ");
	print(_UID , 4);
	/////////////////////////////////////////////////////////////
	//Auntenticate a block with his keyAccess
	state = authenticate(_UID, address, keyAccess);
	Serial.print("\n");

	if ( state == 0) {
		Serial.println("Authentication block OK");
	} else {
	Serial.println("Authentication failed");
	}
	/////////////////////////////////////////////////////////////
	//Read from address after authentication
	state = readData(address, aux);
	Serial.print("\n");

	if (state == 0) {
		Serial.println("Read block OK");
	} else {
		Serial.println("Read failed");
	}

	Serial.print("\n");
	Serial.print("Data readed : ");
	print(aux , 16);
	Serial.print("\n");
	delay(2000);
}
//**********************************************************************
//!The goal of this command is to detect as many targets (maximum MaxTg)
// as possible in passive mode.
uint8_t init(uint8_t *UID , uint8_t *ATQ)   //! Request InListPassive
{
  Serial.flush();

	dataTX[0] = 0x04; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x4A; // Code
	dataTX[4] = 0x01; //MaxTarget
	dataTX[5] = 0x00; //BaudRate = 106Kbps
	dataTX[6] = 0x00; // Clear checkSum position
	checkSum(dataTX); 

	sendTX(dataTX , 7 ,23);

	for (int i = 17; i < (21) ; i++){
		_UID[i-17] = dataRX[i];
	UID[i-17] = _UID[i-17];
	}

	ATQ[0] = dataRX[13];
	ATQ[1] = dataRX[14];

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x4B) & (dataRX[11] == 0x01)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!A block must be authenticated before read and write operations
uint8_t authenticate(uint8_t *UID, uint8_t blockAddress, uint8_t *keyAccess)
{
	dataTX[0] = 0x0F;
	lengthCheckSum(dataTX);
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40; // inDataEchange
	dataTX[4] = 0x01; //Number of targets
	dataTX[5] = 0x60; // Authentication code
	dataTX[6] = blockAddress;
	for (int i = 0; i < 6 ; i++) {
		dataTX[i + 7] = keyAccess[i];
	}
	dataTX[13] = UID[0];  dataTX[14] = UID[1];
	dataTX[15] = UID[2];  dataTX[16] = UID[3];
	dataTX[17] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 18 ,14);

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Write 16 bytes in address .
uint8_t writeData(uint8_t address, uint8_t *blockData)  //!Writing
{
	Serial.print("                ");
	dataTX[0] = 0x15;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40;//inDataEchange CODE
	dataTX[4] = 0x01;//Number of targets
	dataTX[5] = 0xA0;//Write Command
	dataTX[6] = address; //Address		

	for (int i = 0; i < 16; i++) {
		dataTX[i+7] = blockData[i];
	}

	dataTX[23] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 24 ,14);		

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Read 16 bytes from  address .
uint8_t readData(uint8_t address, uint8_t *readData) //!Reading
{
	Serial.print("                ");

	dataTX[0] = 0x05;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // Code
	dataTX[3] = 0x40; // Code
	dataTX[4] = 0x01; // Number of targets
	dataTX[5] = 0x30; //ReadCode
	dataTX[6] = address;  //Read address
	dataTX[7] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 8, 30);
	memset(readData, 0x00, 16);  

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		for (int i = 12; i < 28; i++) {
			readData[i-12] = dataRX[i];
		}
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!The PN532 sends back the version of the embedded firmware.
bool getFirmware(void)  //! It is needed to launch a simple command to sycnchronize
{
  Serial.print("                ");

	memset(dataTX, 0x00, 35);
	dataTX[0] = 0x02; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // CODE
	dataTX[3] = 0x02; //TFI
	checkSum(dataTX); //0x2A; //Checksum   

	sendTX(dataTX , 5 , 17);
	Serial.print("\n");
	Serial.print("Your Firmware version is : ");

	for (int i = 11; i < (15) ; i++){
		Serial.print(dataRX[i], HEX);
		Serial.print(" ");
	}
	Serial.print("\n");
}

//**********************************************************************
//!Print data stored in vectors .
void print(uint8_t * _data, uint8_t length)
{
	for (int i = 0; i < length ; i++){
		Serial.print(_data[i], HEX);
		Serial.print(" ");
	}
	Serial.print("\n");
}
//**********************************************************************
//!This command is used to set internal parameters of the PN532,
bool configureSAM(void)//! Configure the SAM
{
	Serial.print("               ");

	dataTX[0] = 0x05; //Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x14;
	dataTX[4] = 0x01; // Normal mode
	dataTX[5] = 0x14; // TimeOUT
	dataTX[6] = 0x00; // IRQ
	dataTX[7] = 0x00; // Clean checkSum position
	checkSum(dataTX);

	sendTX(dataTX , 8, 13);
}
//**********************************************************************
//!Send data stored in dataTX
void sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength)
{
	Serial.print(char(0x00));
	Serial.print(char(0x00));
	Serial.print(char(0xFF)); 

	for (int i = 0; i < length; i++) {
		Serial.print(char(dataTX[i]));
	}

	Serial.print(char(0x00));
	getACK();
	waitResponse();// Receive response
	getData(outLength);
}
//**********************************************************************
//!Wait for ACK response and stores it in the dataRX buffer
void getACK(void)
{
	delay(5);
	waitResponse();
	for (int i = 0; i < 5 ; i++) {
		dataRX[i] = Serial.read();
	}
}
//**********************************************************************
//!Wait the response of the module
void waitResponse(void)
{
	int val = 0xFF;
	int cont = 0x00;
	while(val != 0x00) { //Wait for 0x00 response
		val = Serial.read();
		delay(5);
		cont ++;
	}
}
//**********************************************************************
//!Get data from the module
void getData(uint8_t outLength)
{
	for (int i=5; i < outLength; i++) {
		dataRX[i] = Serial.read();//read data from the module.
	}
}
//**********************************************************************
//!Calculates the checksum and stores it in dataTX buffer
void checkSum(uint8_t *dataTX)
{
	for (int i = 0; i < dataTX[0] ; i++) {
		dataTX[dataTX[0] + 2] += dataTX[i + 2];
	}
	byte(dataTX[dataTX[0] + 2]= - dataTX[dataTX[0] + 2]);
}
//**********************************************************************
//!Calculates the length checksum and sotres it in the buffer.
uint8_t lengthCheckSum(uint8_t *dataTX)
{
	dataTX[1] = byte(0x100 - dataTX[0]);
}

    

Raspberry Pi:

Code:
/*  
 *  RFID 13.56 MHz / NFC Module
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Ahmad Saad & Javier Solobera
 */

//Include ArduPi library
#include "arduPi.h"


uint8_t init(uint8_t *UID , uint8_t *ATQ);
uint8_t authenticate(uint8_t *UID, uint8_t blockAddress, uint8_t *keyAccess);
uint8_t writeData(uint8_t address, uint8_t *blockData);
uint8_t readData(uint8_t address, uint8_t *readData);
bool getFirmware(void);
void print(uint8_t * _data, uint8_t length);
bool configureSAM(void);
void sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength);
void getACK(void);
void waitResponse(void);
void getData(uint8_t outLength);
void checkSum(uint8_t *dataTX);
uint8_t lengthCheckSum(uint8_t *dataTX);


uint8_t dataRX[35];//Receive buffer.
uint8_t dataTX[35];//Transmit buffer.
uint8_t _UID[4];// stores the UID (unique identifier) of a card.
uint8_t keyAccess[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } ;// stores the key or password.
uint8_t address = 0x04;//Address to read.
uint8_t ATQ[2];//Answer to request
uint8_t state;//state of the process
uint8_t aux[16];//Auxiliar buffer.

void setup()
{
	//Start serial port 115200 bps:
	Serial.begin(115200);
	delay(100);
	printf("RFID/NFC @ 13.56 MHz module started\n");
	delay(1000);
	//!It is needed to launch a simple command to sycnchronize
	getFirmware();
	configureSAM();
}

void loop()
{
	printf("Ready to read...\n");
	/////////////////////////////////////////////////////////////
	//Get the UID Identifier
	init(_UID, ATQ);
	printf("The UID : ");
	print(_UID , 4);
	/////////////////////////////////////////////////////////////
	//Auntenticate a block with his keyAccess
	state = authenticate(_UID, address, keyAccess);
	printf("\n");

	if ( state == 0) {
		printf("Authentication block OK\n");

	} else {
	printf("Authentication failed\n");

	}
	/////////////////////////////////////////////////////////////
	//Read from address after authentication
	state = readData(address, aux);

	if (state == 0) {
		printf("Read block OK\n");
	} else {
		printf("Read failed\n");
	}

	printf("Data read: \n");
	print(aux , 16);
	printf("\n\n");
	delay(1000);
}
//**********************************************************************
//!The goal of this command is to detect as many targets (maximum MaxTg)
// as possible in passive mode.
uint8_t init(uint8_t *UID , uint8_t *ATQ)   //! Request InListPassive
{
  Serial.flush();

	dataTX[0] = 0x04; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x4A; // Code
	dataTX[4] = 0x01; //MaxTarget
	dataTX[5] = 0x00; //BaudRate = 106Kbps
	dataTX[6] = 0x00; // Clear checkSum position
	checkSum(dataTX); 

	sendTX(dataTX , 7 ,23);

	for (int i = 17; i < (21) ; i++){
		_UID[i-17] = dataRX[i];
	UID[i-17] = _UID[i-17];
	}

	ATQ[0] = dataRX[13];
	ATQ[1] = dataRX[14];

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x4B) & (dataRX[11] == 0x01)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!A block must be authenticated before read and write operations
uint8_t authenticate(uint8_t *UID, uint8_t blockAddress, uint8_t *keyAccess)
{
	dataTX[0] = 0x0F;
	lengthCheckSum(dataTX);
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40; // inDataEchange
	dataTX[4] = 0x01; //Number of targets
	dataTX[5] = 0x60; // Authentication code
	dataTX[6] = blockAddress;
	for (int i = 0; i < 6 ; i++) {
		dataTX[i + 7] = keyAccess[i];
	}
	dataTX[13] = UID[0];  dataTX[14] = UID[1];
	dataTX[15] = UID[2];  dataTX[16] = UID[3];
	dataTX[17] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 18 ,14);

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Write 16 bytes in address .
uint8_t writeData(uint8_t address, uint8_t *blockData)  //!Writing
{
	Serial.print("                ");
	dataTX[0] = 0x15;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40;//inDataEchange CODE
	dataTX[4] = 0x01;//Number of targets
	dataTX[5] = 0xA0;//Write Command
	dataTX[6] = address; //Address		

	for (int i = 0; i < 16; i++) {
		dataTX[i+7] = blockData[i];
	}

	dataTX[23] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 24 ,14);		

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Read 16 bytes from  address .
uint8_t readData(uint8_t address, uint8_t *readData) //!Reading
{
	Serial.print("                ");
	dataTX[0] = 0x05;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // Code
	dataTX[3] = 0x40; // Code
	dataTX[4] = 0x01; // Number of targets
	dataTX[5] = 0x30; //ReadCode
	dataTX[6] = address;  //Read address
	dataTX[7] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 8, 30);
	memset(readData, 0x00, 16);  

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		for (int i = 12; i < 28; i++) {
			readData[i-12] = dataRX[i];
		}
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!The PN532 sends back the version of the embedded firmware.
bool getFirmware(void)  //! It is needed to launch a simple command to sycnchronize
{
	Serial.print("                ");
	memset(dataTX, 0x00, 35);
	dataTX[0] = 0x02; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // CODE
	dataTX[3] = 0x02; //TFI
	checkSum(dataTX); //0x2A; //Checksum   

	sendTX(dataTX , 5 , 17);
	printf("\nYour Firmware version is : ");

	for (int i = 11; i < (15) ; i++){
		printf("%x",dataRX[i]);
		printf(" ");
	}
	printf("\n");
}

//**********************************************************************
//!Print data stored in vectors .
void print(uint8_t * _data, uint8_t length)
{
	for (int i = 0; i < length ; i++){
		printf("%x",_data[i]);
		printf(" ");
	}
	printf("\n");
}
//**********************************************************************
//!This command is used to set internal parameters of the PN532,
bool configureSAM(void)//! Configure the SAM
{
	Serial.print("               ");
	dataTX[0] = 0x05; //Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x14;
	dataTX[4] = 0x01; // Normal mode
	dataTX[5] = 0x14; // TimeOUT
	dataTX[6] = 0x00; // IRQ
	dataTX[7] = 0x00; // Clean checkSum position
	checkSum(dataTX);

	sendTX(dataTX , 8, 13);
}
//**********************************************************************
//!Send data stored in dataTX
void sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength)
{
	Serial.print(0x00, BYTE);
	Serial.print(0x00, BYTE);
	Serial.print(0xFF, BYTE); 

	for (int i = 0; i < length; i++) {
		Serial.print(dataTX[i], BYTE);
	}

	Serial.print(0x00, BYTE);
	getACK();
	waitResponse();// Receive response
	getData(outLength);
}
//**********************************************************************
//!Wait for ACK response and stores it in the dataRX buffer
void getACK(void)
{
	delay(5);
	waitResponse();
	for (int i = 0; i < 5 ; i++) {
		dataRX[i] = Serial.read();
	}
}
//**********************************************************************
//!Wait the response of the module
void waitResponse(void)
{
	int val = 0xFF;
	int cont = 0x00;
	while(val != 0x00) { //Wait for 0x00 response
		val = Serial.read();
		delay(5);
		cont ++;
	}
}
//**********************************************************************
//!Get data from the module
void getData(uint8_t outLength)
{
	for (int i=5; i < outLength; i++) {
		dataRX[i] = Serial.read();//read data from the module.
	}
}
//**********************************************************************
//!Calculates the checksum and stores it in dataTX buffer
void checkSum(uint8_t *dataTX)
{
	for (int i = 0; i < dataTX[0] ; i++) {
		dataTX[dataTX[0] + 2] += dataTX[i + 2];
	}
	byte(dataTX[dataTX[0] + 2]= - dataTX[dataTX[0] + 2]);
}
//**********************************************************************
//!Calculates the length checksum and sotres it in the buffer.
uint8_t lengthCheckSum(uint8_t *dataTX)
{
	dataTX[1] = byte(0x100 - dataTX[0]);
}

int main (){
	setup();
	while(1){
		loop();
	}
	return (0);
}

    

Here is the USB output using the Arduino IDE serial port terminal:

Step 3 : Reading / writing Mifare tags

The next example for this module is the writing/reading of tags.
Warning!!!
Don't write address 0, 3, 7, 11, 15, ... if you are not an advanced user!!! You could leave your tag unaccesable.

Each tag has some special blocks:

  • Address 0 - . It contains the IC manufacturer data. Due to security and system requirements this block has read-only access after having been programmed by the IC manufacturer at production.
  • Address 3, 7, 11... - Each sector has a sector trailer containing the secret keys A and B (optional), which return logical “0”s when read. Writing in them will change the access keys and access conditions!!!

Arduino:

Code:
/*  
 *  RFID 13.56 MHz / NFC Module
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Ahmad Saad & Javier Solobera
 */

uint8_t dataRX[35];//Receive buffer.
uint8_t dataTX[35];//Transmit buffer.
uint8_t _UID[4]; // stores the UID (unique identifier) of a card.
uint8_t blockData[] =	{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
				0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};//Data to write (16 bytes).
uint8_t keyAccess[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} ;// stores the key or password.
uint8_t address = 0x04;//Address to read.
uint8_t ATQ[2];//Answer to request
uint8_t state;//state of the process
uint8_t aux[16];//Auxiliar buffer. 

void setup()
{
	//Start serial port 115200 bps:
	Serial.begin(115200);
	delay(100);
	Serial.print("RFID/NFC @ 13.56 MHz module started");
	delay(1000);

//! It is needed to launch a simple command to sycnchronize
	getFirmware();
	configureSAM();
}
void loop()
{
	Serial.print("\n");
	Serial.println("Ready to read...");
	/////////////////////////////////////////////////////////////
	//Get the Card Identifier
	init(_UID, ATQ);
	Serial.print("\n");
	Serial.print( "The Card NUID : ");
	print(_UID , 4);
	/////////////////////////////////////////////////////////////
	//Auntenticate a block with his keyAccess
	state = authenticate(_UID, address, keyAccess);
	Serial.print("\n");

	if ( state == 0) {
		Serial.println("Authentication block OK");
	} else {
		Serial.println("Authentication failed");
	}
	/////////////////////////////////////////////////////////////
	//Write blockData in a address, after authentication.
	if ( state == 0 ) {
		state = writeData(address, blockData);
		Serial.print("\n");
			if ( state == 0) {
				Serial.println("Write block OK");
			} else {
				Serial.println("Write failed");
			}
	/////////////////////////////////////////////////////////////
	//Read from address after authentication
		state = readData(address, aux);
		Serial.print("\n");

		if (state == 0) {
			Serial.println("Read block OK");
		} else {
			Serial.println("Read failed");
		}

		Serial.print("Data readed : ");
		print(aux , 16);
		Serial.print("\n");
	}
   delay(2000);
}
//**********************************************************************
//!The goal of this command is to detect as many targets (maximum MaxTg)
// as possible in passive mode.
uint8_t init(uint8_t *UID , uint8_t *ATQ)   //! Request InListPassive
{
	Serial.flush();

	dataTX[0] = 0x04; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x4A; // Code
	dataTX[4] = 0x01; //MaxTarget
	dataTX[5] = 0x00; //BaudRate = 106Kbps
	dataTX[6] = 0x00; // Clear checkSum position
	checkSum(dataTX); 

	sendTX(dataTX , 7 ,23);

	for (int i = 17; i < (21) ; i++){
		_UID[i-17] = dataRX[i];
		UID[i-17] = _UID[i-17];
	}

	ATQ[0] = dataRX[13];
	ATQ[1] = dataRX[14];

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x4B) & (dataRX[11] == 0x01)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
 //!A block must be authenticated before read and write operations
uint8_t authenticate(uint8_t *UID, uint8_t blockAddress, uint8_t *keyAccess)
{
	dataTX[0] = 0x0F;
	lengthCheckSum(dataTX);
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40; // inDataEchange
	dataTX[4] = 0x01; //Number of targets
	dataTX[5] = 0x60; // Authentication code
	dataTX[6] = blockAddress;

	for (int i = 0; i < 6 ; i++) {
		dataTX[i + 7] = keyAccess[i];
	}

	dataTX[13] = UID[0];  dataTX[14] = UID[1];
	dataTX[15] = UID[2];  dataTX[16] = UID[3];
	dataTX[17] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 18 ,14);

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Write 16 bytes in address .
uint8_t writeData(uint8_t address, uint8_t *blockData)  //!Writing
{
	Serial.print("                ");
	dataTX[0] = 0x15;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40;  //inDataEchange CODE
	dataTX[4] = 0x01;  //Number of targets
	dataTX[5] = 0xA0; //Write Command
	dataTX[6] = address; //Address		

	for (int i = 0; i < 16; i++) {
		dataTX[i+7] = blockData[i];
	}

	dataTX[23] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 24 ,14);  		

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Read 16 bytes from  address .
uint8_t readData(uint8_t address, uint8_t *readData) //!Reading
{
	Serial.print("                ");		

	dataTX[0] = 0x05;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // Code
	dataTX[3] = 0x40; // Code
	dataTX[4] = 0x01; // Number of targets
	dataTX[5] = 0x30; //ReadCode
	dataTX[6] = address;  //Read address
	dataTX[7] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 8, 30);
	memset(readData, 0x00, 16);  

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		for (int i = 12; i < 28; i++) {
			readData[i-12] = dataRX[i];
		}
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!The PN532 sends back the version of the embedded firmware.
bool getFirmware(void)  //! It is needed to launch a simple command to sycnchronize
{
	Serial.print("                ");

	memset(dataTX, 0x00, 35);
	dataTX[0] = 0x02; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // CODE
	dataTX[3] = 0x02; //TFI
	checkSum(dataTX); //0x2A; //Checksum   

	sendTX(dataTX , 5 , 17);
	Serial.print("\n");
	Serial.print("Your Firmware version is : ");

	for (int i = 11; i < (15) ; i++){
		Serial.print(dataRX[i], HEX);
		Serial.print(" ");
	}
	Serial.print("\n");
}

//**********************************************************************
//!Print data stored in vectors .
void print(uint8_t * _data, uint8_t length)
{
	for (int i = 0; i < length ; i++){
		Serial.print(_data[i], HEX);
		Serial.print(" ");
	}
	Serial.print("\n");
}
//**********************************************************************
//!This command is used to set internal parameters of the PN532,
bool configureSAM(void)//! Configure the SAM
{
	Serial.print("               ");

	dataTX[0] = 0x05; //Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x14;
	dataTX[4] = 0x01; //Normal mode
	dataTX[5] = 0x14; // TimeOUT
	dataTX[6] = 0x00; // IRQ
	dataTX[7] = 0x00; // Clean checkSum position
	checkSum(dataTX);

	sendTX(dataTX , 8, 13);
}
//**********************************************************************
//!Send data stored in dataTX
void sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength)
{
	Serial.print(char(0x00));
	Serial.print(char(0x00));
	Serial.print(char(0xFF)); 

	for (int i = 0; i < length; i++) {
		Serial.print(char(dataTX[i]));
	}

	Serial.print(char(0x00));
	getACK();
	waitResponse();    // 1C - receive response
	getData(outLength);
}
//**********************************************************************
//!Wait for ACK response and stores it in the dataRX buffer
void getACK(void)
{
	delay(5);
	waitResponse();
	for (int i = 0; i < 5 ; i++) {
		dataRX[i] = Serial.read();
	}
}
//**********************************************************************
//!Wait the response of the module
void waitResponse(void)
{
	int val = 0xFF;
	int cont = 0x00;
	while(val != 0x00) {
		val = Serial.read();
		delay(5);
		cont ++;
	}
}
//**********************************************************************
//!Get data from the module
void getData(uint8_t outLength)
{
	for (int i=5; i < outLength; i++) {
		dataRX[i] = Serial.read(); // read data from the module.
	}
}
//**********************************************************************
//!Calculates the checksum and stores it in dataTX buffer
void checkSum(uint8_t *dataTX)
{
	for (int i = 0; i < dataTX[0] ; i++) {
		dataTX[dataTX[0] + 2] += dataTX[i + 2];
	}
	byte(dataTX[dataTX[0] + 2]= - dataTX[dataTX[0] + 2]);
}
//**********************************************************************
//!Calculates the length checksum and sotres it in the buffer.
uint8_t lengthCheckSum(uint8_t *dataTX)
{
	dataTX[1] = byte(0x100 - dataTX[0]);
}
    

Raspberry Pi:

Code:
/*  
 *  RFID 13.56 MHz / NFC Module
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Ahmad Saad & Javier Solobera
 */

#include "arduPi.h"


uint8_t init(uint8_t *UID , uint8_t *ATQ);
uint8_t authenticate(uint8_t *UID, uint8_t blockAddress, uint8_t *keyAccess);
uint8_t writeData(uint8_t address, uint8_t *blockData);
uint8_t readData(uint8_t address, uint8_t *readData);
bool getFirmware(void);
void print(uint8_t * _data, uint8_t length);
bool configureSAM(void);
void sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength);
void getACK(void);
void waitResponse(void);
void getData(uint8_t outLength);
void checkSum(uint8_t *dataTX);
uint8_t lengthCheckSum(uint8_t *dataTX);

uint8_t dataRX[35];//Receive buffer.
uint8_t dataTX[35];//Transmit buffer.
uint8_t _UID[4]; // stores the UID (unique identifier) of a card.
uint8_t blockData[] =	{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
				0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};//Data to write (16 bytes).
uint8_t keyAccess[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} ;// stores the key or password.
uint8_t address = 0x04;//Address to read.
uint8_t ATQ[2];//Answer to request
uint8_t state;//state of the process
uint8_t aux[16];//Auxiliar buffer. 

void setup()
{
	//Start serial port 115200 bps:
	Serial.begin(115200);
	delay(100);
	printf("RFID/NFC @ 13.56 MHz module started\n");
	delay(1000);

//! It is needed to launch a simple command to sycnchronize
	getFirmware();
	configureSAM();
}
void loop()
{
	printf("Ready to read...\n");
	/////////////////////////////////////////////////////////////
	//Get the Card Identifier
	init(_UID, ATQ);
	Serial.print( "The Card NUID : ");
	print(_UID , 4);
	/////////////////////////////////////////////////////////////
	//Auntenticate a block with his keyAccess
	state = authenticate(_UID, address, keyAccess);
	printf("\n");

	if ( state == 0) {
		printf("Authentication block OK\n");
	} else {
		printf("Authentication failed\n");
	}
	/////////////////////////////////////////////////////////////
	//Write blockData in a address, after authentication.
	if ( state == 0 ) {
		state = writeData(address, blockData);
		Serial.print("\n");
			if ( state == 0) {
				printf("Write block OK\n");
			} else {
				printf("Write failed\n");
			}
	/////////////////////////////////////////////////////////////
	//Read from address after authentication
		state = readData(address, aux);
		printf("\n");

		if (state == 0) {
			printf("Read block OK\n");
		} else {
			printf("Read failed\n");
		}

		printf("Data read: ");
		print(aux , 16);
		printf("\n");
	}
   delay(2000);
}
//**********************************************************************
//!The goal of this command is to detect as many targets (maximum MaxTg)
// as possible in passive mode.
uint8_t init(uint8_t *UID , uint8_t *ATQ)   //! Request InListPassive
{
	Serial.flush();

	dataTX[0] = 0x04; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x4A; // Code
	dataTX[4] = 0x01; //MaxTarget
	dataTX[5] = 0x00; //BaudRate = 106Kbps
	dataTX[6] = 0x00; // Clear checkSum position
	checkSum(dataTX); 

	sendTX(dataTX , 7 ,23);

	for (int i = 17; i < (21) ; i++){
		_UID[i-17] = dataRX[i];
		UID[i-17] = _UID[i-17];
	}

	ATQ[0] = dataRX[13];
	ATQ[1] = dataRX[14];

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x4B) & (dataRX[11] == 0x01)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
 //!A block must be authenticated before read and write operations
uint8_t authenticate(uint8_t *UID, uint8_t blockAddress, uint8_t *keyAccess)
{
	dataTX[0] = 0x0F;
	lengthCheckSum(dataTX);
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40; // inDataEchange
	dataTX[4] = 0x01; //Number of targets
	dataTX[5] = 0x60; // Authentication code
	dataTX[6] = blockAddress;

	for (int i = 0; i < 6 ; i++) {
		dataTX[i + 7] = keyAccess[i];
	}

	dataTX[13] = UID[0];  dataTX[14] = UID[1];
	dataTX[15] = UID[2];  dataTX[16] = UID[3];
	dataTX[17] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 18 ,14);

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Write 16 bytes in address .
uint8_t writeData(uint8_t address, uint8_t *blockData)  //!Writing
{
	Serial.print("                ");
	dataTX[0] = 0x15;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40;  //inDataEchange CODE
	dataTX[4] = 0x01;  //Number of targets
	dataTX[5] = 0xA0; //Write Command
	dataTX[6] = address; //Address		

	for (int i = 0; i < 16; i++) {
		dataTX[i+7] = blockData[i];
	}

	dataTX[23] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 24 ,14);  		

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Read 16 bytes from  address .
uint8_t readData(uint8_t address, uint8_t *readData) //!Reading
{
	Serial.print("                ");		

	dataTX[0] = 0x05;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // Code
	dataTX[3] = 0x40; // Code
	dataTX[4] = 0x01; // Number of targets
	dataTX[5] = 0x30; //ReadCode
	dataTX[6] = address;  //Read address
	dataTX[7] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 8, 30);
	memset(readData, 0x00, 16);  

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		for (int i = 12; i < 28; i++) {
			readData[i-12] = dataRX[i];
		}
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!The PN532 sends back the version of the embedded firmware.
bool getFirmware(void)  //! It is needed to launch a simple command to sycnchronize
{
	Serial.print("                ");

	memset(dataTX, 0x00, 35);
	dataTX[0] = 0x02; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // CODE
	dataTX[3] = 0x02; //TFI
	checkSum(dataTX); //0x2A; //Checksum   

	sendTX(dataTX , 5 , 17);
	printf("\n");
	printf("Your Firmware version is : ");

	for (int i = 11; i < (15) ; i++){
		printf("%x",dataRX[i]);
		printf(" ");
	}
	printf("\n");
}

//**********************************************************************
//!Print data stored in vectors .
void print(uint8_t * _data, uint8_t length)
{
	for (int i = 0; i < length ; i++){
		printf("%x",_data[i]);
		printf(" ");
	}
	printf("\n");
}
//**********************************************************************
//!This command is used to set internal parameters of the PN532,
bool configureSAM(void)//! Configure the SAM
{
	Serial.print("               ");

	dataTX[0] = 0x05; //Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x14;
	dataTX[4] = 0x01; //Normal mode
	dataTX[5] = 0x14; // TimeOUT
	dataTX[6] = 0x00; // IRQ
	dataTX[7] = 0x00; // Clean checkSum position
	checkSum(dataTX);

	sendTX(dataTX , 8, 13);
}
//**********************************************************************
//!Send data stored in dataTX
void sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength)
{
	Serial.print(0x00, BYTE);
	Serial.print(0x00, BYTE);
	Serial.print(0xFF, BYTE); 

	for (int i = 0; i < length; i++) {
		Serial.print(dataTX[i], BYTE);
	}

	Serial.print(0x00, BYTE);
	getACK();
	waitResponse();    // 1C - receive response
	getData(outLength);
}
//**********************************************************************
//!Wait for ACK response and stores it in the dataRX buffer
void getACK(void)
{
	delay(5);
	waitResponse();
	for (int i = 0; i < 5 ; i++) {
		dataRX[i] = Serial.read();
	}
}
//**********************************************************************
//!Wait the response of the module
void waitResponse(void)
{
	int val = 0xFF;
	int cont = 0x00;
	while(val != 0x00) {
		val = Serial.read();
		delay(5);
		cont ++;
	}
}
//**********************************************************************
//!Get data from the module
void getData(uint8_t outLength)
{
	for (int i=5; i < outLength; i++) {
		dataRX[i] = Serial.read(); // read data from the module.
	}
}
//**********************************************************************
//!Calculates the checksum and stores it in dataTX buffer
void checkSum(uint8_t *dataTX)
{
	for (int i = 0; i < dataTX[0] ; i++) {
		dataTX[dataTX[0] + 2] += dataTX[i + 2];
	}
	byte(dataTX[dataTX[0] + 2]= - dataTX[dataTX[0] + 2]);
}
//**********************************************************************
//!Calculates the length checksum and sotres it in the buffer.
uint8_t lengthCheckSum(uint8_t *dataTX)
{
	dataTX[1] = byte(0x100 - dataTX[0]);
}

int main (){
	setup();
	while(1){
		loop();
	}
	return (0);
}

    

Here is the USB output using the Arduino IDE serial port terminal.

Step 4 : Changing the keys:

This example changes the keys and access conditions in a sector and checks the block can be accessed with the new conditions.
Warning!!!

  • Address 3, 7, 11, 15, ... contains the secret keys A and B (optional), which return logical “0”s when read. Write in them will change the access keys and access conditions!!!
  • You can change the keys, but we do not advise to change the access conditions

Arduino:

Code:
/*  
 *  RFID 13.56 MHz / NFC Module
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Ahmad Saad & Javier Solobera
 */

uint8_t dataRX[35];//Receive buffer.
uint8_t dataTX[35];//Transmit buffer.
//stores the status of the executed command:
short state;
//auxiliar buffer:
unsigned char aux[16];
//stores the UID (unique identifier) of a card:
unsigned char _CardID[4];
//stores the key or password:
unsigned char keyOld[]= {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};// Old key access.
unsigned char keyA[]= {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1};//NEW KEY ACCESS.
unsigned char keyB[]= {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};//Secundary KEY ACCESS

//only edit config if strong knowledge about the RFID/NFC module
unsigned char config[] = {0xFF, 0x07, 0x80, 0x69};
int address = 3;

void setup()
{
	// start serial port 115200 bps:
	Serial.begin(115200);
	delay(100);

	Serial.print("RFID/NFC @ 13.56 MHz module started");
 delay(1000);

//! It is needed to launch a simple command to sycnchronize
	getFirmware();
	configureSAM();
}

void loop()
{
	Serial.print("\r\n++++++++++++++++++++++++++++++++++++");
	// **** init the RFID/NFC reader
	state = init(_CardID, aux);
	if (aux[0] == aux[1]) {// if so, there is no card on the EM field
		Serial.print("\r\nRequest error - no card found");
	} else { // a card was found

		Serial.print("\r\nRequest | Answer: ");
		print(aux, 2);  //show the ATQ

		Serial.print("\r\nAnticollSelect: ");
		Serial.print(state, HEX);//show the status of the executed init command(should be 0)
		Serial.print(" | Answer: ");
		print(_CardID, 4); //show the UID (Unique IDentifier) of the read card (4 bytes)

	//Write new key in block then authenticate this address and get the new value
		state = setKeys(_CardID, keyOld, keyA, keyB, config, aux, address);
		Serial.print("\r\n**write new key, state: ");
		Serial.print(state, HEX);

		if (state == 0) {
			Serial.print(" --> correct key change ");
		} else {
			Serial.print(" --> ** ERROR: keys not changed ** ");
		}	 // ###### check block 3/7/11/15 (the keys will return 0s)
			// **** authenticate again, now with the new key A

		state = authenticate(_CardID, address , keyA);
		Serial.print("\r\n**Authentication block: ");
		Serial.print(state, HEX);

		if (state == 0) {
			Serial.print(" --> correct authentication ");
		}else {
			Serial.print(" --> ** ERROR: bad authentication ** ");
		}

	}
	delay(5000); // wait 10 seconds in each loop
} 

//**********************************************************************
//!The goal of this command is to detect as many targets (maximum MaxTg)
//  as possible in passive mode.
uint8_t init(uint8_t *CardID , uint8_t *ATQ)   //! Request InListPassive
{
  Serial.flush();

	dataTX[0] = 0x04; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x4A; // Code
	dataTX[4] = 0x01; //MaxTarget
	dataTX[5] = 0x00; //BaudRate = 106Kbps
	dataTX[6] = 0x00; // Clear checkSum position
	checkSum(dataTX); 

	sendTX(dataTX , 7 ,23);	

	for (int i = 17; i < (21) ; i++){
		_CardID[i-17] = dataRX[i];
		CardID[i-17] = _CardID[i-17];
	}

	ATQ[0] = dataRX[13];
	ATQ[1] = dataRX[14];

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x4B) & (dataRX[11] == 0x01)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
 //!A block must be authenticated before read and write operations
uint8_t authenticate(uint8_t *CardID, uint8_t blockAddress, uint8_t *keyAccess)
{
	dataTX[0] = 0x0F;
	lengthCheckSum(dataTX);
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40; // inDataEchange
	dataTX[4] = 0x01; //Number of targets
	dataTX[5] = 0x60; // Authentication code
	dataTX[6] = blockAddress;
	for (int i = 0; i < 6 ; i++) {
		dataTX[i + 7] = keyAccess[i];
	}
	dataTX[13] = CardID[0];  dataTX[14] = CardID[1];
	dataTX[15] = CardID[2];  dataTX[16] = CardID[3];
	dataTX[17] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 18 ,14);

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Write 16 bytes in address .
uint8_t writeData(uint8_t address, uint8_t *blockData)  //!Writing
{
	Serial.print("                ");
	dataTX[0] = 0x15;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40;  //inDataEchange CODE
	dataTX[4] = 0x01;  //Number of targets
	dataTX[5] = 0xA0; //Write Command
	dataTX[6] = address; //Address		

	for (int i = 0; i < 16; i++) {
		dataTX[i+7] = blockData[i];
	}

	dataTX[23] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 24 ,14);  		

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Read 16 bytes from  address .
uint8_t readData(uint8_t address, uint8_t *readData) //!Reading
{
	Serial.print("                ");		

	dataTX[0] = 0x05;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // Code
	dataTX[3] = 0x40; // Code
	dataTX[4] = 0x01; // Number of targets
	dataTX[5] = 0x30; //ReadCode
	dataTX[6] = address;  //Read address
	dataTX[7] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 8, 30);
	memset(readData, 0x00, 16);  

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		for (int i = 12; i < 28; i++) {
			readData[i-12] = dataRX[i];
		}
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!The PN532 sends back the version of the embedded firmware.
bool getFirmware(void)  //! It is needed to launch a simple command to sycnchronize
{
	Serial.print("                ");		

	memset(dataTX, 0x00, 35);
	dataTX[0] = 0x02; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // CODE
	dataTX[3] = 0x02; //TFI
	checkSum(dataTX); //0x2A; //Checksum   

	sendTX(dataTX , 5 , 17);
	Serial.print("\n");
	Serial.print("Your Firmware version is : ");

	for (int i = 11; i < (15) ; i++){
		Serial.print(dataRX[i], HEX);
		Serial.print(" ");
	}
	Serial.print("\n");
}

//**********************************************************************
//!Print data stored in vectors .
void print(uint8_t * _data, uint8_t length)
{
	for (int i = 0; i < length ; i++){
		Serial.print(_data[i], HEX);
		Serial.print(" ");
	}
	Serial.print("\n");
}
//**********************************************************************
//!This command is used to set internal parameters of the PN532,
bool configureSAM(void)//! Configure the SAM
{
	Serial.print("               ");

	dataTX[0] = 0x05; //Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x14;
	dataTX[4] = 0x01; //Normal mode
	dataTX[5] = 0x14; // TimeOUT
	dataTX[6] = 0x00; // IRQ
	dataTX[7] = 0x00; // Clean checkSum position
	checkSum(dataTX);

	sendTX(dataTX , 8, 13);
}
//**********************************************************************
//!Send data stored in dataTX
void sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength)
{
	Serial.print(char(0x00));
	Serial.print(char(0x00));
	Serial.print(char(0xFF)); 

	for (int i = 0; i < length; i++) {
		Serial.print(char(dataTX[i]));
	}

	Serial.print(char(0x00));
	getACK();
	waitResponse();    // 1C - receive response
	getData(outLength);
}
//**********************************************************************
//!Wait for ACK response and stores it in the dataRX buffer
void getACK(void)
{
	delay(5);
	waitResponse();
	for (int i = 0; i < 5 ; i++) {
		dataRX[i] = Serial.read();
	}
}
//**********************************************************************
//!Wait the response of the module
void waitResponse(void)
{
	int val = 0xFF;
	int cont = 0x00;
	while(val != 0x00) {
		val = Serial.read();
		delay(5);
		cont ++;
	}
}
//**********************************************************************
//!Get data from the module
void getData(uint8_t outLength)
{
	for (int i=5; i < outLength; i++) {
		dataRX[i] = Serial.read(); // read data from the module.
	}
}
//**********************************************************************
//!Calculates the checksum and stores it in dataTX buffer
void checkSum(uint8_t *dataTX)
{
	for (int i = 0; i < dataTX[0] ; i++) {
		dataTX[dataTX[0] + 2] += dataTX[i + 2];
	}
  byte(dataTX[dataTX[0] + 2]= - dataTX[dataTX[0] + 2]);
}
//**********************************************************************
//!Calculates the length checksum and sotres it in the buffer.
uint8_t lengthCheckSum(uint8_t *dataTX)
{
	dataTX[1] = byte(0x100 - dataTX[0]);
}
//**********************************************************************
//Changes both keys and access conditions to one card's sector
uint8_t setKeys(uint8_t *CardID,uint8_t *keyOld,uint8_t *keyA,uint8_t *keyB,uint8_t *config,uint8_t *data,uint8_t add)
{
	uint8_t state = 1; 

	if (((add+1) % 4) == 0){
		state = authenticate(CardID , add, keyOld);
		if (state == 0) {
			for (int i = 0; i < 6; i++) {
				data[i] = keyA[i];
				data[i+ 10] = keyB[i];
			}

			for (int i = 0; i < 4 ; i++) {
				data[i + 6] = config[i];
			}
			state = writeData(add, data);
		}
	}
	return state;
}
    

Raspberry Pi:

Code:
/*  
 *  RFID 13.56 MHz / NFC Module
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Ahmad Saad & Javier Solobera
 */

#include "arduPi.h"


uint8_t init(uint8_t *UID , uint8_t *ATQ);
uint8_t authenticate(uint8_t *UID, uint8_t blockAddress, uint8_t *keyAccess);
uint8_t writeData(uint8_t address, uint8_t *blockData);
uint8_t readData(uint8_t address, uint8_t *readData);
bool getFirmware(void);
void print(uint8_t * _data, uint8_t length);
bool configureSAM(void);
void sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength);
void getACK(void);
void waitResponse(void);
void getData(uint8_t outLength);
void checkSum(uint8_t *dataTX);
uint8_t lengthCheckSum(uint8_t *dataTX);
uint8_t setKeys(uint8_t *CardID,uint8_t *keyOld,uint8_t *keyA,uint8_t *keyB,uint8_t *config,uint8_t *data,uint8_t add);

uint8_t dataRX[35];//Receive buffer.
uint8_t dataTX[35];//Transmit buffer.
//stores the status of the executed command:
short state;
//auxiliar buffer:
unsigned char aux[16];
//stores the UID (unique identifier) of a card:
unsigned char _CardID[4];
//stores the key or password:
unsigned char keyOld[]= {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};// Old key access.
unsigned char keyA[]= {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1};//NEW KEY ACCESS.
unsigned char keyB[]= {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};//Secundary KEY ACCESS

//only edit config if strong knowledge about the RFID/NFC module
unsigned char config[] = {0xFF, 0x07, 0x80, 0x69};
int address = 3;

void setup()
{
	// start serial port 115200 bps:
	Serial.begin(115200);
	delay(100);

	printf("RFID/NFC @ 13.56 MHz module started\n");
 delay(1000);

//! It is needed to launch a simple command to sycnchronize
	getFirmware();
	configureSAM();
}

void loop()
{
	printf("\n++++++++++++++++++++++++++++++++++++\n");
	// **** init the RFID/NFC reader
	state = init(_CardID, aux);
	if (aux[0] == aux[1]) {// if so, there is no card on the EM field
		printf("Request error - no card found\n");
	} else { // a card was found

		printf("Request | Answer: \n");
		print(aux, 2);  //show the ATQ

		printf("AnticollSelect: \n");
		printf("%x",state);//show the status of the executed init command(should be 0)
		printf(" | Answer: ");
		print(_CardID, 4); //show the UID (Unique IDentifier) of the read card (4 bytes)

	//Write new key in block then authenticate this address and get the new value
		state = setKeys(_CardID, keyOld, keyA, keyB, config, aux, address);
		printf("\n**write new key, state: ");
		printf("%x",state);

		if (state == 0) {
			printf(" --> correct key change ");
		} else {
			printf(" --> ** ERROR: keys not changed ** ");
		}	 // ###### check block 3/7/11/15 (the keys will return 0s)
			// **** authenticate again, now with the new key A

		state = authenticate(_CardID, address , keyA);
		printf("\n**Authentication block: ");
		printf("%x",state);

		if (state == 0) {
			printf(" --> correct authentication ");
		}else {
			printf(" --> ** ERROR: bad authentication ** ");
		}

	}
	delay(5000); // wait 10 seconds in each loop
} 

//**********************************************************************
//!The goal of this command is to detect as many targets (maximum MaxTg)
//  as possible in passive mode.
uint8_t init(uint8_t *CardID , uint8_t *ATQ)   //! Request InListPassive
{
  Serial.flush();

	dataTX[0] = 0x04; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x4A; // Code
	dataTX[4] = 0x01; //MaxTarget
	dataTX[5] = 0x00; //BaudRate = 106Kbps
	dataTX[6] = 0x00; // Clear checkSum position
	checkSum(dataTX); 

	sendTX(dataTX , 7 ,23);	

	for (int i = 17; i < (21) ; i++){
		_CardID[i-17] = dataRX[i];
		CardID[i-17] = _CardID[i-17];
	}

	ATQ[0] = dataRX[13];
	ATQ[1] = dataRX[14];

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x4B) & (dataRX[11] == 0x01)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
 //!A block must be authenticated before read and write operations
uint8_t authenticate(uint8_t *CardID, uint8_t blockAddress, uint8_t *keyAccess)
{
	dataTX[0] = 0x0F;
	lengthCheckSum(dataTX);
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40; // inDataEchange
	dataTX[4] = 0x01; //Number of targets
	dataTX[5] = 0x60; // Authentication code
	dataTX[6] = blockAddress;
	for (int i = 0; i < 6 ; i++) {
		dataTX[i + 7] = keyAccess[i];
	}
	dataTX[13] = CardID[0];  dataTX[14] = CardID[1];
	dataTX[15] = CardID[2];  dataTX[16] = CardID[3];
	dataTX[17] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 18 ,14);

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Write 16 bytes in address .
uint8_t writeData(uint8_t address, uint8_t *blockData)  //!Writing
{
	Serial.print("                ");
	dataTX[0] = 0x15;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x40;  //inDataEchange CODE
	dataTX[4] = 0x01;  //Number of targets
	dataTX[5] = 0xA0; //Write Command
	dataTX[6] = address; //Address		

	for (int i = 0; i < 16; i++) {
		dataTX[i+7] = blockData[i];
	}

	dataTX[23] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 24 ,14);  		

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!Read 16 bytes from  address .
uint8_t readData(uint8_t address, uint8_t *readData) //!Reading
{
	Serial.print("                ");		

	dataTX[0] = 0x05;
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // Code
	dataTX[3] = 0x40; // Code
	dataTX[4] = 0x01; // Number of targets
	dataTX[5] = 0x30; //ReadCode
	dataTX[6] = address;  //Read address
	dataTX[7] = 0x00;
	checkSum(dataTX);
	sendTX(dataTX , 8, 30);
	memset(readData, 0x00, 16);  

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x41) & (dataRX[11] == 0x00)) {
		for (int i = 12; i < 28; i++) {
			readData[i-12] = dataRX[i];
		}
		return 0;
	} else {
		return 1;
	}
}
//**********************************************************************
//!The PN532 sends back the version of the embedded firmware.
bool getFirmware(void)  //! It is needed to launch a simple command to sycnchronize
{
	Serial.print("                ");		

	memset(dataTX, 0x00, 35);
	dataTX[0] = 0x02; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // CODE
	dataTX[3] = 0x02; //TFI
	checkSum(dataTX); //0x2A; //Checksum   

	sendTX(dataTX , 5 , 17);
	printf("\n");
	printf("Your Firmware version is : ");

	for (int i = 11; i < (15) ; i++){
		printf("%x",dataRX[i]);
		printf(" ");
	}
	printf("\n");
}

//**********************************************************************
//!Print data stored in vectors .
void print(uint8_t * _data, uint8_t length)
{
	for (int i = 0; i < length ; i++){
		printf("%x",_data[i]);
		printf(" ");
	}
	printf("\n");
}
//**********************************************************************
//!This command is used to set internal parameters of the PN532,
bool configureSAM(void)//! Configure the SAM
{
	Serial.print("               ");

	dataTX[0] = 0x05; //Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x14;
	dataTX[4] = 0x01; //Normal mode
	dataTX[5] = 0x14; // TimeOUT
	dataTX[6] = 0x00; // IRQ
	dataTX[7] = 0x00; // Clean checkSum position
	checkSum(dataTX);

	sendTX(dataTX , 8, 13);
}
//**********************************************************************
//!Send data stored in dataTX
void sendTX(uint8_t *dataTX, uint8_t length, uint8_t outLength)
{
	Serial.print(0x00, BYTE);
	Serial.print(0x00, BYTE);
	Serial.print(0xFF, BYTE); 

	for (int i = 0; i < length; i++) {
		Serial.print(dataTX[i], BYTE);
	}

	Serial.print(0x00, BYTE);
	getACK();
	waitResponse();    // 1C - receive response
	getData(outLength);
}
//**********************************************************************
//!Wait for ACK response and stores it in the dataRX buffer
void getACK(void)
{
	delay(5);
	waitResponse();
	for (int i = 0; i < 5 ; i++) {
		dataRX[i] = Serial.read();
	}
}
//**********************************************************************
//!Wait the response of the module
void waitResponse(void)
{
	int val = 0xFF;
	int cont = 0x00;
	while(val != 0x00) {
		val = Serial.read();
		delay(5);
		cont ++;
	}
}
//**********************************************************************
//!Get data from the module
void getData(uint8_t outLength)
{
	for (int i=5; i < outLength; i++) {
		dataRX[i] = Serial.read(); // read data from the module.
	}
}
//**********************************************************************
//!Calculates the checksum and stores it in dataTX buffer
void checkSum(uint8_t *dataTX)
{
	for (int i = 0; i < dataTX[0] ; i++) {
		dataTX[dataTX[0] + 2] += dataTX[i + 2];
	}
  byte(dataTX[dataTX[0] + 2]= - dataTX[dataTX[0] + 2]);
}
//**********************************************************************
//!Calculates the length checksum and sotres it in the buffer.
uint8_t lengthCheckSum(uint8_t *dataTX)
{
	dataTX[1] = byte(0x100 - dataTX[0]);
}
//**********************************************************************
//Changes both keys and access conditions to one card's sector
uint8_t setKeys(uint8_t *CardID,uint8_t *keyOld,uint8_t *keyA,uint8_t *keyB,uint8_t *config,uint8_t *data,uint8_t add)
{
	uint8_t state = 1; 

	if (((add+1) % 4) == 0){
		state = authenticate(CardID , add, keyOld);
		if (state == 0) {
			for (int i = 0; i < 6; i++) {
				data[i] = keyA[i];
				data[i+ 10] = keyB[i];
			}

			for (int i = 0; i < 4 ; i++) {
				data[i + 6] = config[i];
			}
			state = writeData(add, data);
		}
	}
	return state;
}

int main (){
	setup();
	while(1){
		loop();
	}
	return (0);
}

    

Device Compatibility

This shield is tested and fully compatible with the following boards:

Arduino Boards

  • Arduino Uno

Raspberry Pi Boards

  • Raspberry Pi
  • Raspberry Pi (Model B+)
  • Raspberry Pi 2
  • Raspberry Pi 3

Fritzing Libraries

RFID 13.56 MHz / NFC Module for Arduino can be connected to Arduino using a XBee shield and will communicate it using the Arduino serial port (UART).).

You can download our Fritzing libraries from this area.





If you are interested in Internet of Things (IoT) or M2M projects check our open source sensor platform Waspmote which counts with more than 100 sensors available to use 'off the shelf', a complete API with hundreds of ready to use codes and a low consumption mode of just 0.7µA to ensure years of battery life.

Know more at:

Get the Starter Kits at: