“This is the 25th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

1. Introduction to MF-RC522 module

MFRC522 is a highly integrated read-write card chip applied in 13.56mhz contactless communication. It is a low-voltage, low-cost, small contactless read-write card chip for “three meters” applications. It is a good choice for the research and development of intelligent meters and portable handheld devices. Portable handheld device research and development of a better choice. The MFRC522 leverages advanced modulation and demodulation concepts and integrates all types of passive non-contact communication methods and protocols at 13.56MHz. Support for 14443A compatible transponder signals. The digital part handles ISO14443A frames and error detection. In addition, it also supports fast CRYPTO1 encryption algorithms and verifies the MIFARE series of products. The MFRC522 supports faster contactless communication in the MI FARE series, with two-way data transfer rates up to 424kbit/s. As a new member of the 13.56MHz high integration read-write card family,MFRC522 has many similarities with MF RC500 and MFRC530, and also has many characteristics and differences. It adopts SPI mode to communicate with the host, which is beneficial to reduce the connection, reduce the size of PCB board and reduce the cost.

Taobao MFRC522 finished modules are very many, purchase will send several white cards (IC cards), complete the reading and writing experiment.

The MF-RC522 module bought on Taobao is basically the SPI interface introduced. In fact, MF-RC522 itself also supports IIC and UART protocols. Compared with SPI, the protocols are simpler and faster.

At present, I use taobao to buy a packaged finished product module, using MFRC522 original chip design card reading circuit, easy to use, low cost, suitable for equipment development, card reader development and other high application users, the need for rf card terminal design/production users. This module can be directly loaded into a variety of card reader mold. The module adopts a voltage of 3.3V, which can be directly connected and communicated with any CPU motherboard of the user through a few simple lines of SPI interface, which can ensure the stable and reliable work of the module and the long distance of card reading.

The current article introduces how to write MF-RC522 module driver in Linux system, cooperate with the application layer, complete IC card number reading, sector reading, password verification and so on. The current development board uses friendly arm Tiny4412, and the chip is Samsung EXYNOS4412. The driver code does not use SPI subsystem, and directly controls the communication between IO port simulation SPI timing completion and MF-RC522.

When purchasing modules, you will receive an IC white card and a key chain. Although the shapes are different, the internal chip models are all S50 cards, and commonly used bus cards, subway cards, supermarket membership cards and so on are all S50 cards. The shampoo also comes with an S70 card, which has four times more space than the S50. The S50 card contains an EEPROM space, which can store any data. The space is divided into 16 sectors. Each sector consists of four blocks (0, 1, 2, and 3). In actual operation, divide 16 sectors into 64 blocks numbered from 0 to 63.

IC card has no power supply, it is composed of IC chip and induction antenna, encapsulated in a standard PVC card, chip and antenna without any exposed part. It is a new technology developed in the world in recent years. It successfully combines rfid technology and IC card technology, ending the problem of passive (no power supply in the card) and contactless, which is a great breakthrough in the field of electronic devices. The card is close to the reader surface at a certain distance (usually 5-10cm), and the data is read and written through the transmission of radio waves.

2. Connect cables for hardware principles

3. Driver code examples

3.1 RC522.c source code

#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/delay.h>
#include "rfid_rc522.h"
#include <linux/miscdevice.h>
#include <linux/fs.h>


/ * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- RC522 related operation code -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /

/* RC522 initialtinY4412 Hardware connection: DO--MISO :GPB_2 DI--MOSI :GPB_3 clK-SCLK :GPB_0 CS--CS :GPB_1 RST-- :GPB_4 */
void RC522_IO_Init(void)
{
	/ * 1. Registered GPIO * /
	gpio_request(EXYNOS4_GPB(0), "RC522_CLK-SCLK");
	gpio_request(EXYNOS4_GPB(1), "RC522_CS");
	gpio_request(EXYNOS4_GPB(2), "MOSI");
	gpio_request(EXYNOS4_GPB(3), "RC522_MOSI");
	gpio_request(EXYNOS4_GPB(4), "RST");
	
	/*2. Configure the GPIO port mode */
	s3c_gpio_cfgpin(EXYNOS4_GPB(0), S3C_GPIO_OUTPUT);  / / the clock
	s3c_gpio_cfgpin(EXYNOS4_GPB(1), S3C_GPIO_OUTPUT);  / / selected
	s3c_gpio_cfgpin(EXYNOS4_GPB(2), S3C_GPIO_INPUT);  // Input mode
	s3c_gpio_cfgpin(EXYNOS4_GPB(3), S3C_GPIO_OUTPUT); // Output mode
	s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_OUTPUT); // Output mode
	
	/*3. Pull the GPIO port */
	gpio_set_value(EXYNOS4_GPB(0), 1);
	gpio_set_value(EXYNOS4_GPB(1), 1);
	gpio_set_value(EXYNOS4_GPB(3), 1);
	gpio_set_value(EXYNOS4_GPB(4), 1);
}


/* The SPI sequence function reads and writes a byte
u8 RC522_SPI_ReadWriteOneByte(u8 data_tx)
{
	 u8 data_rx=0;
	 u8 i;
	 for(i=0; i<8; i++) {gpio_set_value(EXYNOS4_GPB(0), 0);
		if(data_tx&0x80)gpio_set_value(EXYNOS4_GPB(3), 1);
		else gpio_set_value(EXYNOS4_GPB(3), 0);
		data_tx<<=1; // Continue to send the next data

		gpio_set_value(EXYNOS4_GPB(0), 1);
		data_rx<<=1;
		if(gpio_get_value(EXYNOS4_GPB(2)))data_rx|=0x01;
	 }
	 return data_rx;
}



/* Function description: Select the card to read the card memory capacity input parameter :serNum Incoming card serial number return value: successfully returned card capacity */
u8 RC522_MFRC522_SelectTag(u8 *serNum) // Read the memory capacity of the card
{     
	u8 i;     
	u8 status;     
	u8 size;     
	u8 recvBits;     
	u8 buffer[9];
	     
	buffer[0]=PICC_ANTICOLL1;	  // Collision-proof code 1
	buffer[1] =0x70;
	buffer[6] =0x00;						     
	for(i=0; i<4; i++) { buffer[i+2]=*(serNum+i);	//buffer[2]- Buffer [5] is the card serial number
		buffer[6]^=*(serNum+i);	  // Check code
	}
	
	RC522_CalulateCRC(buffer,7,&buffer[7]);	// Buffer [7]- Buffer [8] is the RCR check code
	RC522_ClearBitMask(Status2Reg,0x08);
	status=RC522_PcdComMF522(PCD_TRANSCEIVE,buffer,9,buffer,&recvBits);
	
	if((status==MI_OK)&&(recvBits==0x18))    
		size=buffer[0];     
	else    
		size=0;
	return size; 
}


/* Delay function, nanosecond */
void RC522_Delay(u32 ns)
{
	ndelay(ns);
}


/* Function function: RC522 chip initialization */
void RC522_Init(void)
{
  RC522_IO_Init(a);/ / RC522 initialization
  RC522_PcdReset(a);/ / reset RC522
  RC522_PcdAntennaOff(a);// Turn off the antenna
  msleep(2);  		  		 // Delay is 2 milliseconds
  RC522_PcdAntennaOn(a);// Turn on the antenna
  M500PcdConfigISOType('A'); // Set the working mode of RC632
}


/* Reset RC522 */
void RC522_Reset(void)
{
  RC522_PcdReset(a);/ / reset RC522
  RC522_PcdAntennaOff(a);// Turn off the antenna
  msleep(2);  		  		    // Delay is 2 milliseconds
  RC522_PcdAntennaOn(a);// Turn on the antenna
}     


/* Power: search card Req_code [IN]: Card search mode 0x52 = Search for all cards that meet 14443A standards 0x26 = Search for cards that do not enter sleep state pTagType[OUT]: card type code 0x4400 = Mifare_UltraLight 0x0400 = Mifare_One(S50) 0x0200 = Mifare_One(S70) 0x0800 = Mifare_Pro(X) 0x4403 = Mifare_DESFire Return value: MI_OK */ is returned successfully
char RC522_PcdRequest(u8 req_code,u8 *pTagType)
{
	char status;  
	u8 unLen;
	u8 ucComMF522Buf[MAXRLEN];  	   		// MAXRLEN 18

	RC522_ClearBitMask(Status2Reg,0x08);	// clear RC522 register bit,/ / receive data command
	RC522_WriteRawRC(BitFramingReg,0x07);   // Write the RC632 register
	RC522_SetBitMask(TxControlReg,0x03);    // set RC522 register bit
 
	ucComMF522Buf[0]=req_code; 	    // Card search
	
	status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen); // Through RC522 and ISO14443 cartoon message
	
	if((status==MI_OK)&&(unLen==0x10))
	{    
		*pTagType=ucComMF522Buf[0];
		*(pTagType+1)=ucComMF522Buf[1];
	}
	else
	{
	  status = MI_ERR;
	}  
	return status;
}


PSnr [OUT]: card serial number, 4 bytes return: MI_OK */
char RC522_PcdAnticoll(u8 *pSnr)
{
    char status;
    u8 i,snr_check=0;
    u8 unLen;
    u8 ucComMF522Buf[MAXRLEN]; 
    
    RC522_ClearBitMask(Status2Reg,0x08);  // Clear the RC522 register bit
    RC522_WriteRawRC(BitFramingReg,0x00); / / write
    RC522_ClearBitMask(CollReg,0x80);     / / clear
 
    ucComMF522Buf[0]=PICC_ANTICOLL1;   	 //PICC_ANTICOLL1 = 0x93
    ucComMF522Buf[1] =0x20;
	
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen); //0x0c, through RC522 and ISO14443
											 //PCD_TRANSCEIVE = transmit and receive data
											 //2: indicates the length of data bytes written to the card
											 //ucComMF522Buf: address for storing data
											 //unLen: The length of data read from the card
    if(status==MI_OK)
    {
    	 for(i=0; i<4; i++) { *(pSnr+i)=ucComMF522Buf[i];// Assign the read card number to pSnr
					 snr_check^=ucComMF522Buf[i];
			 }
			 if(snr_check!=ucComMF522Buf[i])
			 {
					status = MI_ERR;
			 }
    }   
    RC522_SetBitMask(CollReg,0x80);
    return status;
}


PSnr [IN]: serial number of the card, 4 bytes return: MI_OK */ is returned successfully
char RC522_PcdSelect(u8 *pSnr)
{
    char status;
    u8 i;
    u8 unLen;
    u8 ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0]=PICC_ANTICOLL1;
    ucComMF522Buf[1] =0x70;
    ucComMF522Buf[6] =0;
	
    for(i=0; i<4; i++) { ucComMF522Buf[i+2]=*(pSnr+i);
    	ucComMF522Buf[6]^=*(pSnr+i);
    }
		
    RC522_CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]); // use MF522 to calculate CRC16 function
    RC522_ClearBitMask(Status2Reg,0x08);	                // Clear the RC522 register bit
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
    if((status==MI_OK)&&(unLen==0x18))status=MI_OK;
    else status=MI_ERR;
		
    return status;
}


Parameter description: auth_mode[IN]: Password Authentication mode 0x60 = Verify A key 0x61 = Verify B Key ADDR [IN] : block address pKey[IN] : sector password pSnr[IN] : serial number of the card, 4 bytes Back: MI_OK */ is returned successfully               
char RC522_PcdAuthState(u8 auth_mode,u8 addr,u8 *pKey,u8 *pSnr)
{
    char status;
    u8 unLen;
    u8 ucComMF522Buf[MAXRLEN];  //MAXRLEN 18(array size)
	  
	  Authentication mode + block address + Sector password + card serial number
    ucComMF522Buf[0]=auth_mode;		
    ucComMF522Buf[1]=addr;				
    memcpy(&ucComMF522Buf[2],pKey,6); // Copy, copy
    memcpy(&ucComMF522Buf[8],pSnr,4); 
	 
    status=RC522_PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
    if((status! = MI_OK)||(! (RC522_ReadRawRC(Status2Reg)&0x08)))status = MI_ERR;
    return status;
}


/* Power: read a block of data from the M1 card Parameter description: addr: block address P: read block data, 16 bytes return: MI_OK */ is returned successfully 
char RC522_PcdRead(u8 addr,u8 *p)
{
    char status;
    u8 unLen;
    u8 i,ucComMF522Buf[MAXRLEN]; / / 18

    ucComMF522Buf[0]=PICC_READ;
    ucComMF522Buf[1]=addr;
    RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);// Through RC522 and ISO14443 cartoon message
    if((status==MI_OK&&(unLen==0x90)))
    {
		for(i=0; i<16;i++)
		{
				*(p +i)=ucComMF522Buf[i];
		}
    }
    else
	{   
		status=MI_ERR;
	}
    return status;
}


/* Power: write data to M1 card block Parameter description: addr: block address P: write data to block, 16-byte return: MI_OK */ is returned successfully                  
char RC522_PcdWrite(u8 addr,u8 *p)
{
    char status;
    u8 unLen;
    u8 i,ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0]=PICC_WRITE;// 0xA0 // write block
    ucComMF522Buf[1]=addr;      / / block address
    RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

    if((status! = MI_OK)||(unLen ! =4)||((ucComMF522Buf[0] &0x0F)! =0x0A))
	{
		status = MI_ERR;
	}
		
    if(status==MI_OK)
    {
        for(i=0; i<16; i++)// Write 16 bytes to the FIFO
        {    
        	ucComMF522Buf[i]=*(p +i);   
        }
        RC522_CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);
        status = RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);
        if((status ! = MI_OK)||(unLen ! =4)||((ucComMF522Buf[0] &0x0F)! =0x0A)) { status = MI_ERR; }}return status;
}


/* Power: the command card is in hibernation state
char RC522_PcdHalt(void)
{
    u8 status;
    u8 unLen;
    u8 ucComMF522Buf[MAXRLEN]; //MAXRLEN==18
	status=status;
    ucComMF522Buf[0]=PICC_HALT;
    ucComMF522Buf[1] =0;
    RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
    status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    return MI_OK;
}


*pIn: CRC data to read len: - data length *pOut: CRC result calculated */
void RC522_CalulateCRC(u8 *pIn ,u8 len,u8 *pOut )
{
    u8 i,n;
    RC522_ClearBitMask(DivIrqReg,0x04);  //CRCIrq = 0  
    RC522_WriteRawRC(CommandReg,PCD_IDLE);
    RC522_SetBitMask(FIFOLevelReg,0x80); // Clear the FIFO pointer
    
  // Write data to the FIFO
	for(i=0; i<len; i++) {RC522_WriteRawRC(FIFODataReg,*(pIn +i));  // Start RCR calculation
	}
	
	RC522_WriteRawRC(CommandReg,PCD_CALCCRC);   // Wait for the CRC calculation to complete
	i=0xFF;
	do 
	{
		n=RC522_ReadRawRC(DivIrqReg);
		i--;
	}
    while((i! =0) &&! (n&0x04));//CRCIrq = 1
	  
	// Read the result of CRC calculation
	pOut[0] =RC522_ReadRawRC(CRCResultRegL);
	pOut[1] =RC522_ReadRawRC(CRCResultRegM);
}


/* Power: reset RC522 return: MI_OK */
char RC522_PcdReset(void)
{
	gpio_set_value(EXYNOS4_GPB(4), 1);   / / write 1 PF1
    RC522_Delay(10);
	gpio_set_value(EXYNOS4_GPB(4), 0);   / / PF1 0
    RC522_Delay(10);
	gpio_set_value(EXYNOS4_GPB(4), 1);	 / / write 1 PF1
    RC522_Delay(10);
    RC522_WriteRawRC(CommandReg,PCD_RESETPHASE);  // Write RC632 register, reset
	RC522_WriteRawRC(CommandReg,PCD_RESETPHASE);	// Write RC632 register, reset
    RC522_Delay(10);
    
    RC522_WriteRawRC(ModeReg,0x3D);             // and Mifare, CRC initial value 0x6363
    RC522_WriteRawRC(TReloadRegL,30);           // Write the RC632 register
    RC522_WriteRawRC(TReloadRegH,0);
    RC522_WriteRawRC(TModeReg,0x8D);
    RC522_WriteRawRC(TPrescalerReg,0x3E);
	
	RC522_WriteRawRC(TxAutoReg,0x40);/ / have to
    return MI_OK;
}


/* Set the RC632 working mode */
char M500PcdConfigISOType(u8 type)
{
   if(type=='A')                        //ISO14443_A
   { 
		 RC522_ClearBitMask(Status2Reg,0x08);     // Clear the RC522 register bit
		 RC522_WriteRawRC(ModeReg,0x3D);          //3F// The initial CRC value is 0x6363
		 RC522_WriteRawRC(RxSelReg,0x86);         / / 84
		 RC522_WriteRawRC(RFCfgReg,0x7F);         //4F // Adjust the card induction distance //RxGain = 48dB Adjust the card induction distance
		 RC522_WriteRawRC(TReloadRegL,30);        //tmoLength); // TReloadVal = 'h6a =tmoLength(dec)
	     RC522_WriteRawRC(TReloadRegH,0);
		 RC522_WriteRawRC(TModeReg,0x8D);
	     RC522_WriteRawRC(TPrescalerReg,0x3E);
	     RC522_Delay(1000);
        RC522_PcdAntennaOn(a);// Turn on the antenna
   }
   else return 1;       // Fail, return 1
   return MI_OK;				// Success returns 0
}


/* Power: read RC632 Register Parameters: Address[IN]: register Address rollback: read value */
u8 RC522_ReadRawRC(u8 Address)
{
	u8 ucAddr;
	u8 ucResult=0;		
	gpio_set_value(EXYNOS4_GPB(1), 0);						// Select RC522
	ucAddr=((Address<<1) &0x7E) |0x80;
	RC522_SPI_ReadWriteOneByte(ucAddr);		  // Send the command
	ucResult=RC522_SPI_ReadWriteOneByte(0); // Read the data returned by RC522
	gpio_set_value(EXYNOS4_GPB(1), 1);						   // Release sheet selection (PF0)
	return ucResult;         // Return the read data
}


Parameter description: Address[IN]: register Address value[IN] : value to be written */
void RC522_WriteRawRC(unsigned char Address,unsigned char value)
{  
	unsigned char ucAddr;
	gpio_set_value(EXYNOS4_GPB(1), 0); //PF0 write 0 (SDA)(SPI1 chip select line, active low level)
	ucAddr=((Address<<1) &0x7E); 
	RC522_SPI_ReadWriteOneByte(ucAddr); //SPI1 sends a byte
	RC522_SPI_ReadWriteOneByte(value);  //SPI1 sends a byte
	gpio_set_value(EXYNOS4_GPB(1), 1);										      
}


Reg [IN]: register address mask[IN]: register value */
void RC522_SetBitMask(unsigned char reg,unsigned char mask)  
{
    char tmp=0x0;
    tmp=RC522_ReadRawRC(reg);		  // Read register RC632
    RC522_WriteRawRC(reg,tmp|mask);   // Write the RC632 register
}


Reg [IN]: register address mask[IN]: register value */
void RC522_ClearBitMask(unsigned char reg,unsigned char mask)  
{
    char tmp=0x0;
    tmp=RC522_ReadRawRC(reg);        // Read register RC632
    RC522_WriteRawRC(reg,tmp&~mask); // clear bit mask
} 


/* Power: through RC522 and ISO14443 PIn [IN]: data sent to the card through RC522 InLenByte[IN]: length of the bytes sent pOut [OUT]: data returned from the received card *pOutLenBit[OUT]: length of the bits returned */
char RC522_PcdComMF522(unsigned char Command,unsigned char *pIn,unsigned char InLenByte,unsigned char *pOut,unsigned char *pOutLenBit)
{
    char status=MI_ERR;
    unsigned char irqEn=0x00;
    unsigned char waitFor=0x00;
    unsigned char lastBits;
    unsigned char n;
    u16 i;
	
    switch(Command)
    {
			case PCD_AUTHENT:    // Verify the key
					 irqEn=0x12;
					 waitFor=0x10;
					 break;
			case PCD_TRANSCEIVE: // Send and receive data
					 irqEn=0x77;
					 waitFor=0x30;
					 break;
			default:
					 break;
    }
    RC522_WriteRawRC(ComIEnReg,irqEn|0x80);	
    RC522_ClearBitMask(ComIrqReg,0x80);			// Clear all interrupt bits
    RC522_WriteRawRC(CommandReg,PCD_IDLE);	
    RC522_SetBitMask(FIFOLevelReg,0x80);	 	// Clear the FIFO cache
    
    for(i=0; i<InLenByte; i++) {RC522_WriteRawRC(FIFODataReg,pIn[i]);
	}
		
	RC522_WriteRawRC(CommandReg,Command);	 
	if(Command==PCD_TRANSCEIVE)
	{  
		RC522_SetBitMask(BitFramingReg,0x80);	 // Start the transfer
	}
    
	// There is a problem with the following loop
	//i = 600; // According to the clock frequency adjustment, the maximum waiting time of operation M1 card is 25ms
	i=2000;
	do 
	{
		n=RC522_ReadRawRC(ComIrqReg);
		i--;
	}
	while((i! =0) &&! (n&0x01) &&! (n&waitFor));RC522_ClearBitMask(BitFramingReg,0x80);
	if(i! =0)
	{    
		if(! (RC522_ReadRawRC(ErrorReg)&0x1B))
		{
			status=MI_OK;
			if(n&irqEn&0x01)
			{
				status=MI_NOTAGERR;
			}
			if(Command==PCD_TRANSCEIVE)
			{
				n=RC522_ReadRawRC(FIFOLevelReg);
				lastBits=RC522_ReadRawRC(ControlReg)&0x07;
				if(lastBits)
				{
					*pOutLenBit=(n- 1) *8+lastBits;
				}
				else
				{   
					*pOutLenBit=n*8;   
				}
								
				if(n==0)n=1;
				if(n>MAXRLEN)n=MAXRLEN;
				for(i=0; i<n; i++)
				{   
					pOut[i]=RC522_ReadRawRC(FIFODataReg); }}}else{ status=MI_ERR; }}RC522_SetBitMask(ControlReg,0x80);// stop timer now
    RC522_WriteRawRC(CommandReg,PCD_IDLE); 
    return status;
}


/* Function function: open antenna parameter: there should be at least 1ms interval between each start or close of the sky danger transmission */
void RC522_PcdAntennaOn(void)
{
    unsigned char i;
    i=RC522_ReadRawRC(TxControlReg);
    if(! (i&0x03))
    {
        RC522_SetBitMask(TxControlReg,0x03); }}/* Function functions: closing antenna parameters: there should be at least a 1ms interval between each start or close of the celestial risk transmission */
void RC522_PcdAntennaOff(void)
{
	RC522_ClearBitMask(TxControlReg,0x03); // Clear the RC522 register bit
}



static void print_info(unsigned char *p,int cnt)
{
	int i;
	for(i=0; i<cnt; i++) {printk("0x%X ",p[i]);
	}
	printk("\r\n");
}


/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * RCC522 workflow RCC522 find card initialization if find card (= = yes) collision prevention card verification card read/write CARDS over the CARDS unsigned char req_code; // Unsigned char *pTagType; // Card type. Parameter Description: Req_code [IN]: pTagType[OUT] : pTagType[OUT] : pTagType[OUT] : pTagType[OUT] : Card Type code 0x4400 = Mifare_UltraLight 0x0400 = Mifare_One(S50) 0x0200 = Mifare_One(S70) 0x0800 = Mifare_Pro(X) 0x4403 = Mifare_DESFire */
static unsigned char SN[4]; / / card number
int read_card(a)
{
	unsigned char CT[2];/ / card type
	unsigned char status=1;
	status=RC522_PcdRequest(PICC_REQIDL ,CT);//(card search mode, card type), returns 0 on success
	if(status==MI_OK)// The card was found successfully
	{
	    status=MI_ERR;
	    status=RC522_PcdAnticoll(SN);  // Prevent collision, return 0 on success, SN is the address to read the card number
		
		printk("Card Type :");
		print_info(CT,2);// Print type
		printk("Card.");
	    print_info(SN,4);// Print the card number
	}
	if(status==MI_OK)
	{
		status=MI_ERR;	
		status=RC522_PcdSelect(SN);	// Select the card, SN: serial number of the card
	}
	return status;
}


/* Function: write data to specified block: u8 addr: address where data is stored. Blocks 0, 1, and 2 of each sector are used to store data. 3 is for storing the password. Generally fill: 0, 1, 2, 4, 5, 6, 8, 9, 10 data formats: general u8 SJ [16] = {255255255255255255255255255255255255255255255255}; // Write amount; * /
static unsigned char write_card_data(unsigned int m_data)
{
	unsigned char KEY[6] = {0xff.0xff.0xff.0xff.0xff.0xff}; // Card password - initial password - white card factory password -
	unsigned char data[16];
	int status=MI_ERR;
	
	data[0]=m_data>>24;
	data[1]=m_data>>16;
	data[2]=m_data>>8;
	data[3]=m_data;
	
	* / / * 1. Find card
	status=read_card(a);/*2. Verify the card password */
	if(status==MI_OK)
	{
		 status=RC522_PcdAuthState(PICC_AUTHENT1A,3,KEY,SN);   // Authentication card password parameters: authentication mode, block address, password, card number
	}

	/*3. Write data to card */
	if(status==MI_OK)
	{
	   status=RC522_PcdWrite(2,data); // Write data to block addr, data into the data value.
	}
	return status;
}

/* Function: read data to specified block parameter: unsigned char auth_mode: type of authentication password. (PICC_AUTHENT1A and PICC_AUTHENT1B) Unsigned char addr: indicates the address where the data is stored. Blocks 0, 1, and 2 of each sector are used to store data. 3 is for storing the password. General fill: 0, 1, 2, 4, 5, 6, 8, 9, 10 Unsigned char *Src_Key: old password Unsigned char *data: read data unsigned char *pSnr: card number Data General format: Unsigned char SJ [16] = {255255255255255255255255255255255255255255255255}; // Write amount; * /
static unsigned char read_card_data(unsigned int *m_data)
{
	unsigned char KEY[6] = {0xff.0xff.0xff.0xff.0xff.0xff}; // Card password - initial password - white card factory password -
	int status;
	unsigned char data[16];
	* / / * 1. Find card
	status=read_card(a);/*2. Verify the card password */
	if(status==MI_OK)
	{
		status=RC522_PcdAuthState(PICC_AUTHENT1A,3,KEY,SN);   // Authentication card password parameters: authentication mode, block address, password, card number
	}
	/*3. Read data */
	if(status==MI_OK)
	{
	   status=RC522_PcdRead(2,data); // Read the data value from block addr.
	}
	if(status==MI_OK)
	{
		*m_data=data[0] < <24|data[1] < <16|data[2] < <8|data[3];
	}
	return status;
}


static int tiny4412_open(struct inode *my_indoe, struct file *my_file)
{
   printk("open ok\n");
   return 0;
}

static int tiny4412_release(struct inode *my_indoe, struct file *my_file)
{
   printk("open release\n");
   return 0;
}

static ssize_t tiny4412_read(struct file *my_file, char __user *buff, size_t cnt, loff_t *loff)
{
	unsigned int data;
	read_card(a);write_card_data(9999);
	if(read_card_data(&data)==MI_OK)
	{
		printk("data=%d\n",data);
	}
   return 0;
}

static ssize_t tiny4412_write(struct file *my_file, const char __user *buff, size_t cnt, loff_t *loff)
{
	printk("open write\n");
    return 0;
}
	
static struct file_operations tiny4412_fops=
{
	.open=tiny4412_open,
	.release=tiny4412_release,
	.read=tiny4412_read,
	.write=tiny4412_write,
};

static struct miscdevice misc={
		.minor=255,
		.name="tiny4412_RC522".// /dev/name of the directory
		.fops=&tiny4412_fops,
};


static int __init RC522_init(void)
{
	/*1. Initialize the GPIO port */
	RC522_Init(a);/*2. Register the miscellaneous character device */
	misc_register(&misc);
	return 0;
}


static void __exit RC522_exit(void)
{
	/* Release GPIO port */
	gpio_free(EXYNOS4_GPB(0));
	gpio_free(EXYNOS4_GPB(1));
	gpio_free(EXYNOS4_GPB(2));
	gpio_free(EXYNOS4_GPB(3));
	gpio_free(EXYNOS4_GPB(4));
	* / / * 2. Revoked
    misc_deregister(&misc);
	printk("RC522 driver exit ok! \n");
}

module_exit(RC522_exit);
module_init(RC522_init);
MODULE_LICENSE("GPL");
Copy the code

3.2 RC522.h source code

#ifndef RFID_RC522_H
#define RFID_RC522_H/ / MF522 command word
#define PCD_IDLE              0x00               // Cancel the current command
#define PCD_AUTHENT           0x0E               // Verify the key
#define PCD_RECEIVE           0x08               // Receive data
#define PCD_TRANSMIT          0x04               // Send data
#define PCD_TRANSCEIVE        0x0C               // Send and receive data
#define PCD_RESETPHASE        0x0F               / / reset
#define PCD_CALCCRC           0x03               / / CRC calculation
​
​
//Mifare_One card command
#define PICC_REQIDL           0x26               // The antenna search area is not in hibernation state, returns the card type
#define PICC_REQALL           0x52               // Find all cards in the antenna area, return the card type
#define PICC_ANTICOLL1        0x93               / / collision prevention
#define PICC_ANTICOLL2        0x95               / / collision prevention
#define PICC_AUTHENT1A        0x60               // Verify A key
#define PICC_AUTHENT1B        0x61               // Verify the B key command authentication code
#define PICC_READ             0x30               / / read
#define PICC_WRITE            0xA0               / / write block
#define PICC_DECREMENT        0xC0               / / deductions
#define PICC_INCREMENT        0xC1               / / prepaid phone
#define PICC_RESTORE          0xC2               // Block data to the buffer
#define PICC_TRANSFER         0xB0               // Save buffer data
#define PICC_HALT             0x50               / / sleepMF522 FIFO length definition
#define DEF_FIFO_LENGTH       64                 //FIFO size=64byte
#define MAXRLEN  18
​
​
//MF522 register definition
// PAGE 0
#define     RFU00                 0x00    
#define     CommandReg            0x01    
#define     ComIEnReg             0x02    
#define     DivlEnReg             0x03    
#define     ComIrqReg             0x04    
#define     DivIrqReg             0x05
#define     ErrorReg              0x06    
#define     Status1Reg            0x07    
#define     Status2Reg            0x08    
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     WaterLevelReg         0x0B
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
#define     RFU0F                 0x0F
// PAGE 1
#define     RFU10                 0x10
#define     ModeReg               0x11
#define     TxModeReg             0x12
#define     RxModeReg             0x13
#define     TxControlReg          0x14
#define     TxAutoReg             0x15
#define     TxSelReg              0x16
#define     RxSelReg              0x17
#define     RxThresholdReg        0x18
#define     DemodReg              0x19
#define     RFU1A                 0x1A
#define     RFU1B                 0x1B
#define     MifareReg             0x1C
#define     RFU1D                 0x1D
#define     RFU1E                 0x1E
#define     SerialSpeedReg        0x1F
// PAGE 2
#define     RFU20                 0x20  
#define     CRCResultRegM         0x21
#define     CRCResultRegL         0x22
#define     RFU23                 0x23
#define     ModWidthReg           0x24
#define     RFU25                 0x25
#define     RFCfgReg              0x26
#define     GsNReg                0x27
#define     CWGsCfgReg            0x28
#define     ModGsCfgReg           0x29
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#define     TCounterValueRegH     0x2E
#define     TCounterValueRegL     0x2F// PAGE 3
#define     RFU30                 0x30
#define     TestSel1Reg           0x31
#define     TestSel2Reg           0x32
#define     TestPinEnReg          0x33
#define     TestPinValueReg       0x34
#define     TestBusReg            0x35
#define     AutoTestReg           0x36
#define     VersionReg            0x37
#define     AnalogTestReg         0x38
#define     TestDAC1Reg           0x39  
#define     TestDAC2Reg           0x3A   
#define     TestADCReg            0x3B   
#define     RFU3C                 0x3C   
#define     RFU3D                 0x3D   
#define     RFU3E                 0x3E   
#define     RFU3F                       0x3F
​
​
// Error code returned when communicating with MF522
#define     MI_OK                 0
#define     MI_NOTAGERR           1
#define     MI_ERR                2#define SHAQU1      0X01
#define KUAI4           0X04
#define KUAI7           0X07
#define REGCARD     0xa1
#define CONSUME     0xa2
#define READCARD    0xa3
#define ADDMONEY    0xa4/* RC522 various driver functions */void RC522_Init(void);                                                                          // Power: the RC522 RF card module is initialized
void RC522_ClearBitMask(u8 reg,u8 mask);                                        // Clear RC522 register bit
void RC522_WriteRawRC(u8 Address, u8 value);                                // Write to register RC632
void RC522_SetBitMask(u8 reg,u8 mask);                                          // Set RC522 register bit
char RC522_PcdComMF522(u8 Command,u8*pIn,u8 InLenByte,u8*pOut,u8*pOutLenBit);   // Function: through RC522 and ISO14443 cartoon message
void RC522_CalulateCRC(u8 *pIn,u8 len,u8 *pOut );                     // Use MF522 to calculate CRC16 function
u8 RC522_ReadRawRC(u8 Address);                                                           // Read the RC632 registerchar RC522_PcdReset(void);                                                                                      // Reset RC522
char RC522_PcdRequest(unsigned char req_code,unsigned char *pTagType);// Function: search card
void RC522_PcdAntennaOn(void);                                                                              // Power: open the antenna
void RC522_PcdAntennaOff(void);                                                                             // Power: turn off the antenna
char M500PcdConfigISOType(unsigned char type);                                        // Power: Set the working mode of RC632
char RC522_PcdAnticoll(unsigned char *pSnr);                                                    // Function: anti-collision
char RC522_PcdSelect(unsigned char *pSnr);                                                      // Power: select the card
char RC522_PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr);// Function: verify card password
char RC522_PcdWrite(unsigned char addr,unsigned char *pData);                   // Write data to M1 card block
char RC522_PcdRead(unsigned char addr,unsigned char *pData);                    // Power: read a piece of data from M1 card
char RC522_PcdHalt(void);                                                                                           // Power: The command card goes to sleep
void RC522_Reset(void);                                                                                       // Reset RC522
u8 RC522_MFRC522_SelectTag(u8 *serNum);                               // Read the memory capacity of the card
u8 RC522_SPI_ReadWriteOneByte(u8 tx_data);
#endif
Copy the code