“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 / / sleep
MF522 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 register
char 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