34. Chapter RFID

In this chapter, we will learn how to use RFID.

34.1. Project RFID

In this project, we will use RC522 RFID card reader to read and write the M1-S50 card.

  1. Raspberry Pi (with 40 GPIO) x1

  2. GPIO Extension Board & Ribbon Cable x1

  3. Breadboard x1

RC522 module x1

RC522

Jumper Wires x7

jumper-wire

Mifare1 S50 Standard card x1

card

Mifare1 S50 Non-standard card x1

Non_card

34.1.1. Component Knowledge

34.1.1.1. RFID

RFID(Radio Frequency Identification)is a form of wireless communication technology. A complete RFID system is generally composed of a transponder and a reader. Generally, the transponder may be known as a tag, and each tag has a unique code, which is attached to an object to identify the target object. The reader is a device that reads (or writes) information in the tag.

Products derived from RFID technology can be divided into three categories: passive RFID products, active RFID products and semi active RFID products, among which, Passive RFID products are the earliest, the most mature and most widely used products in the market. It can be seen everywhere in our daily life such as, the bus card, dining card, bank card, hotel access cards, etc., and all of them are classified as close-range contact recognition. The main operating frequency of Passive RFID products are: 125KHZ (low frequency), 13.56MHZ (high frequency), 433MHZ (ultrahigh frequency), 915MHZ (ultrahigh frequency). Active and semi active RFID products work at higher frequencies.

The RFID module we use is a passive RFID product with the operating frequency of 13.56MHz.

34.1.1.2. MFRC522

The MFRC522 is a highly integrated reader/writer IC for contactless communication at 13.56MHz.

The MFRC522’s internal transmitter is able to drive a reader/writer antenna designed to communicate with ISO/IEC 14443 A/MIFARE cards and transponders without additional active circuitry. The receiver module provides a robust and efficient implementation for demodulating and decoding signals from ISO/IEC 14443 A/MIFARE compatible cards and transponders. The digital module manages the complete ISO/IEC 14443A framing and error detection (parity and CRC) functionality

This RFID Module uses MFRC522 as the control chip, and SPI (Peripheral Interface Serial) as the reserved interface.

Technical specs:

Operating Voltage

13-26mA(DC)3.3V

Idle current

10-13mA(DC)3.3V

Sleep current in the

<80uA

Peak current

<30mA

Operating frequency

13.56MHz

Supported card type

Mifare1 S50、Mifare1 S70、Mifare Ultralight、Mifare Pro、Mifare Desfire

Size

40mmX60mm

Operation temperature

20-80 degrees(Celsius)

Storage temperature

40-85 degrees (Celsius)

Operation humidity

5%-95%(Relative humidity)

34.1.1.3. Mifare1 S50 Card

Mifare S50 is often called Mifare Standard with the capacity of 1K bytes. And each card has a 4-bytes global unique identifier number (USN/UID), which can be rewritten 100 thousand times and read infinite times. Its storage period can last for 10 years.

The Mifare S50 capacity (1K byte) is divided into 16 sectors (Sector0-Sector15). Each sector contains 4 data block (Block0-Block3. 64 blocks of 16 sectors will be numbered according absolute address, from 0 to 63).

And each block contains 16 bytes (Byte0-Byte15), 64*16=1024. As is shown in the following table:

Sector No.

Block No.

Storage area

Block type

Absolute block No.

sector 0

block 0

vendor code

vendor block

0

block 1

data block

1

block 2

data block

2

block 3

Password A-access control-password B

control block

3

sector 1

block 0

data block

4

block 1

data block

5

block 2

data block

6

block 3

Password A-access control-password B

control block

7

......

......

......

......

......

sector 15

block 0

data block

60

block 0

data block

61

block 0

data block

62

block 3

Password A-access control-password B

control block

63

Each sector has a set of independent password and access control put in its last block, that is, Block 3, which is also known as sector trailer. Sector 0, block 0 (namely absolute address 0) of S50 is used to store the card serial number and vendor code, which has been solidified and can’t be changed. Except the manufacturer and the control block, the rest of the cards are data blocks, which can be used to store data. Data block can be used for two kinds of applications:

  1. used as general data storage and can be operated for reading and writing data.

  2. used as data value, and can be operated for initializing, adding, subtracting and reading the value.

The sector trailer block in each sector is the control block, including a 6-byte password A, a 4-byte access control and a 6-byte password B. For example, the control block of a brand new card is as follows:

A0 A1 A2 A3 A4 A5

FF 07 80 69

B0 B1 B2 B3 B4 B5

password A

access control

password B

The default password of a brand new card is generally 0A1A2A3A4A5 for password A and B0B1B2B3B4B5 for password B, or both the password A and password B are 6 FF. Access control is used to set the access conditions for each block (including the control block itself) in a sector.

For more details about how to set data blocks and control blocks, please refer to Datasheet.

By default, after verifying password A or password B, we can do reading or writing operation to data blocks. And after verifying password A, we can do reading or writing operation to control blocks. But password A can never be read, so if you choose to verify password A but forget the password A, the block will never be able to read again.

Hint

If you have any concerns, please contact us via: support@freenove.com

For Mifare1 S50 card equipped in Freenove RFID Kit, the default password A and B are both FFFFFFFFFFFF.

Schematic diagram

RFID_Sc

Hardware connection. If you need any support,please feel free to contact us via:

support@freenove.com

RFID_Fr

34.1.2. Configure SPI

34.1.2.1. Enable SPI

The SPI interface of raspberry pi is closed by default. You need to open it manually. You can enable the SPI interface in the following way.

Type the following command in the terminal:

$ sudo raspi-config

Then open the following dialog box:

../../../_images/dialog_box1.png

Choose “5 Interfacing Options” -> “P4 SPI” -> “Yes” -> “Finish” in order and then restart your RPi. Then the SPI module is started.

Type the following command to check whether the module SPI is loaded successfully:

$ ls /dev/sp*

The following result indicates that the module SPI has been loaded successfully:

../../../_images/SPI_Success.png

34.1.3. Code

The project code uses human-computer interaction command line mode to read and write the M1-S50 card.

34.1.3.1. Python Code RFID

There are two code files for this project. They are respectively under Python2 folder and Python3 folder. Their functions are the same, but they are not compatible. Code under Python2 folder can only run on Python2. And code under Python3 folder can only run on Python3.

First observe the project result, and then learn about the code in detail.

Hint

If you have any concerns, please contact us via: support@freenove.com

  1. Use cd command to enter RFID directory of Python code.

$ cd ~/Freenove_Kit/Code/Python_GPIOZero_Code/34.1.1_RFID
  1. Use python command to execute code “RFID.py”.

$ python RFID.py

After the program is executed, the following contents will be displayed in the terminal:

../../../_images/py_RFID_code.png

Here, type the command “quit” to exit the program.

Type command “scan”, then the program begins to detect whether there is a card close to the sensing area of MFRC522 reader. Place a M1-S50 card in the sensing area. The following results indicate that the M1-S50 card has been detected, the UID of which is E6CF5C8EFB (HEX).

../../../_images/py_RFID_code_1.png

When the Card is placed in the sensing area, you can read and write the card with the following command.

../../../_images/py_RFID_code_2.png

In the command read<blockstart>, the parameter blockstart is the address of the data block, and the range is 0-63. As is shown below:

In the command read<blockstart>, the parameter blockstart is the address of the data block, and the range is 0-63. This command is used to read the data of data block with address “blockstart”. For example, using command “read 0” can display the content of data block 0. Using the command “read 1” can display the content of data block 1. As is shown below:

../../../_images/py_RFID_code_3.png

Command “dump” is used to display the content of all data blocks in all sectors.

Command <address> <data> is used to write “data” to data block with address “address”, where the address range is 0-63 and the data length is 0-16. In the process of writing data to the data block, both the contents of data block before written and after written will be displayed. For example, if you want to write the string “Freenove” to the data block with address “1”, you can type the following command.

$ write 1 Freenove
../../../_images/py_RFID_code_4.png

Command “clean <address>” is used remove the contents of the data block with address “address”. For example, if you want to clear the contents of the data block 1 that has just been written, you can type the following command.

$ clean 1
../../../_images/py_RFID_code_5.png

Command “halt” is used to quit the selection state of the card.

../../../_images/py_RFID_code_6.png

The following is the program code :

  1#!/usr/bin/env python3
  2########################################################################
  3# Filename    : RFID.py
  4# Description : Use MFRC522 read and write Mifare Card.
  5# auther      : www.freenove.com
  6# modification: 2021/1/1
  7########################################################################
  8from gpiozero import OutputDevice
  9import MFRC522
 10import sys
 11import os
 12
 13# Create an object of the class MFRC522
 14mfrc = MFRC522.MFRC522()
 15
 16
 17def dis_ConmandLine():
 18	print ("RC522>",end="")
 19def dis_CardID(cardID):
 20	print ("%2X%2X%2X%2X%2X>"%(cardID[0],cardID[1],cardID[2],cardID[3],cardID[4]),end="")
 21def setup():
 22	print ("Program is starting ... "	)
 23	print ("Press Ctrl-C to exit.")
 24	pass
 25	
 26def loop():
 27	global mfrc3s
 28	while(True):
 29		dis_ConmandLine()
 30		inCmd = input()
 31		print (inCmd)
 32		if (inCmd == "scan"):
 33			print ("Scanning ... ")
 34			mfrc = MFRC522.MFRC522()
 35			isScan = True
 36			while isScan:
 37				# Scan for cards    
 38				(status,TagType) = mfrc.MFRC522_Request(mfrc.PICC_REQIDL)
 39				# If a card is found
 40				if status == mfrc.MI_OK:
 41					print ("Card detected")
 42				# Get the UID of the card
 43				(status,uid) = mfrc.MFRC522_Anticoll()				
 44				# If we have the UID, continue
 45				if status == mfrc.MI_OK:
 46					print ("Card UID: "+ str(map(hex,uid)))
 47					# Select the scanned tag
 48					if mfrc.MFRC522_SelectTag(uid) == 0:
 49						print ("MFRC522_SelectTag Failed!")
 50					if cmdloop(uid) < 1 :
 51						isScan = False
 52			
 53		elif inCmd == "quit":
 54			destroy()
 55			exit(0)
 56		else :
 57			print ("\tUnknown command\n"+"\tscan:scan card and dump\n"+"\tquit:exit program\n")
 58				
 59def cmdloop(cardID):
 60	pass
 61	while(True):
 62		dis_ConmandLine()
 63		dis_CardID(cardID)
 64		inCmd = input()
 65		cmd = inCmd.split(" ")
 66		print (cmd)
 67		if(cmd[0] == "read"):
 68			blockAddr = int(cmd[1])
 69			if((blockAddr<0) or (blockAddr>63)):
 70				print ("Invalid Address!")
 71			# This is the default key for authentication
 72			key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]			
 73			# Authenticate
 74			status = mfrc.MFRC522_Auth(mfrc.PICC_AUTHENT1A, blockAddr, key, cardID)
 75			# Check if authenticated
 76			if status == mfrc.MI_OK:
 77				mfrc.MFRC522_Readstr(blockAddr)
 78			else:
 79				print ("Authentication error")
 80				return 0
 81				
 82		elif cmd[0] == "dump":
 83			# This is the default key for authentication
 84			key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
 85			mfrc.MFRC522_Dump_Str(key,cardID)
 86			
 87		elif cmd[0] == "write":
 88			blockAddr = int(cmd[1])
 89			if((blockAddr<0) or (blockAddr>63)):
 90				print ("Invalid Address!")
 91			data = [0]*16
 92			if(len(cmd)<2):
 93				data = [0]*16
 94			else:	
 95				data = cmd[2][0:17]
 96				data = map(ord,data)
 97				data = list(data)
 98				lenData = len(list(data))
 99				if lenData<16:
100					data+=[0]*(16-lenData)
101			# This is the default key for authentication
102			key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]			
103			# Authenticate
104			status = mfrc.MFRC522_Auth(mfrc.PICC_AUTHENT1A, blockAddr, key, cardID)
105			# Check if authenticated
106			if status == mfrc.MI_OK:
107				print ("Before writing , The data in block %d  is: "%(blockAddr))
108				mfrc.MFRC522_Readstr(blockAddr)
109				mfrc.MFRC522_Write(blockAddr, data)
110				print ("After written , The data in block %d  is: "%(blockAddr))
111				mfrc.MFRC522_Readstr(blockAddr)
112			else:
113				print ("Authentication error")
114				return 0
115			
116		elif cmd[0] == "clean":
117			blockAddr = int(cmd[1])
118			if((blockAddr<0) or (blockAddr>63)):
119				print ("Invalid Address!")
120			data = [0]*16
121			# This is the default key for authentication
122			key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]			
123			# Authenticate
124			status = mfrc.MFRC522_Auth(mfrc.PICC_AUTHENT1A, blockAddr, key, cardID)
125			# Check if authenticated
126			if status == mfrc.MI_OK:
127				print ("Before cleaning , The data in block %d  is: "%(blockAddr))
128				mfrc.MFRC522_Readstr(blockAddr)
129				mfrc.MFRC522_Write(blockAddr, data)
130				print ("After cleaned , The data in block %d  is: "%(blockAddr))
131				mfrc.MFRC522_Readstr(blockAddr)
132			else:
133				print ("Authentication error")
134				return 0
135		elif cmd[0] == "halt":
136			return 0
137		else :
138			print ("Usage:\r\n" "\tread <blockstart>\r\n" "\tdump\r\n" "\thalt\r\n" "\tclean <blockaddr>\r\n" "\twrite <blockaddr> <data>\r\n")
139				
140def destroy():
141    print("Ending program")
142
143if __name__ == "__main__":
144	setup()
145	try:
146		loop()
147	except KeyboardInterrupt:  # Ctrl+C captured, exit
148		destroy()
149 
150	

In the code, first create an MFRC522 class object.

1mfrc = MFRC522.MFRC522()

In the function loop, wait for the command input. If command “scan” is received, the function will begin to detect whether there is a card close to the sensing area. If a card is detected, the card will be selected and card UID will be acquired. Then enter the function scan_loop (). If command “quit” or “exit” is received, the program will exit.

 1if (inCmd == "scan"):
 2	print ("Scanning ... ")
 3	mfrc = MFRC522.MFRC522()
 4	isScan = True
 5	while isScan:
 6		# Scan for cards    
 7		(status,TagType) = mfrc.MFRC522_Request(mfrc.PICC_REQIDL)
 8		# If a card is found
 9		if status == mfrc.MI_OK:
10			print ("Card detected")
11		# Get the UID of the card
12		(status,uid) = mfrc.MFRC522_Anticoll()				
13		# If we have the UID, continue
14		if status == mfrc.MI_OK:
15			print ("Card UID: "+ str(map(hex,uid)))
16			# Select the scanned tag
17			if mfrc.MFRC522_SelectTag(uid) == 0:
18				print ("MFRC522_SelectTag Failed!")
19			if cmdloop(uid) < 1 :
20				isScan = False
21
22elif inCmd == "quit":
23	destroy()
24	exit(0)
25else :
26	print ("\tUnknown command\n"+"\tscan:scan card and dump\n"+"\tquit:exit program\n")

The function cmdloop() will detect command read, write, clean, halt, dump and do the corresponding processing to each command. The functions of each command and the method have been introduced before.

 1def cmdloop(cardID):
 2	pass
 3	while(True):
 4		dis_ConmandLine()
 5		dis_CardID(cardID)
 6		inCmd = input()
 7		cmd = inCmd.split(" ")
 8		print (cmd)
 9		if(cmd[0] == "read"):
10			blockAddr = int(cmd[1])
11			if((blockAddr<0) or (blockAddr>63)):
12				print ("Invalid Address!")
13			# This is the default key for authentication
14			key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]			
15			# Authenticate
16			status = mfrc.MFRC522_Auth(mfrc.PICC_AUTHENT1A, blockAddr, key, cardID)
17			# Check if authenticated
18			if status == mfrc.MI_OK:
19				mfrc.MFRC522_Readstr(blockAddr)
20			else:
21				print ("Authentication error")
22				return 0
23
24		elif cmd[0] == "dump":
25			# This is the default key for authentication
26			key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
27			mfrc.MFRC522_Dump_Str(key,cardID)
28
29		elif cmd[0] == "write":
30			blockAddr = int(cmd[1])
31			if((blockAddr<0) or (blockAddr>63)):
32				print ("Invalid Address!")
33			data = [0]*16
34			if(len(cmd)<2):
35				data = [0]*16
36			else:	
37				data = cmd[2][0:17]
38				data = map(ord,data)
39				data = list(data)
40				lenData = len(list(data))
41				if lenData<16:
42					data+=[0]*(16-lenData)
43			# This is the default key for authentication
44			key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]			
45			# Authenticate
46			status = mfrc.MFRC522_Auth(mfrc.PICC_AUTHENT1A, blockAddr, key, cardID)
47			# Check if authenticated
48			if status == mfrc.MI_OK:
49				print ("Before writing , The data in block %d  is: "%(blockAddr))
50				mfrc.MFRC522_Readstr(blockAddr)
51				mfrc.MFRC522_Write(blockAddr, data)
52				print ("After written , The data in block %d  is: "%(blockAddr))
53				mfrc.MFRC522_Readstr(blockAddr)
54			else:
55				print ("Authentication error")
56				return 0
57
58		elif cmd[0] == "clean":
59			blockAddr = int(cmd[1])
60			if((blockAddr<0) or (blockAddr>63)):
61				print ("Invalid Address!")
62			data = [0]*16
63			# This is the default key for authentication
64			key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]			
65			# Authenticate
66			status = mfrc.MFRC522_Auth(mfrc.PICC_AUTHENT1A, blockAddr, key, cardID)
67			# Check if authenticated
68			if status == mfrc.MI_OK:
69				print ("Before cleaning , The data in block %d  is: "%(blockAddr))
70				mfrc.MFRC522_Readstr(blockAddr)
71				mfrc.MFRC522_Write(blockAddr, data)
72				print ("After cleaned , The data in block %d  is: "%(blockAddr))
73				mfrc.MFRC522_Readstr(blockAddr)
74			else:
75				print ("Authentication error")
76				return 0
77		elif cmd[0] == "halt":
78			return 0
79		else :
80			print ("Usage:\r\n" "\tread <blockstart>\r\n" "\tdump\r\n" "\thalt\r\n" "\tclean <blockaddr>\r\n" "\twrite <blockaddr> <data>\r\n")

The file “MFRC522.py” contains the associated operation method for the MFRC522. You can open the file to view all the definitions and functions.