RFID Reader

This experiment focuses on reading RFID tags using a Raspberry Pi Pico microcontroller connected to an RFID reader. RFID (Radio Frequency Identification) technology allows for the wireless transfer of data between a reader and a tag, enabling applications such as inventory management, access control, and object tracking. The goal of this experiment is to interface the Pico with an RFID reader, read the tag data, and display it on a console.



  1. Scope:

The scope of this experiment includes:

  • Understanding the principles of RFID technology.

  • Setting up hardware connections between the Pico and RFID reader.

  • Implementing the communication protocol (SPI/I2C) for data exchange.

  • Writing and testing application code in both MicroPython and Embedded C.

  • Displaying the read tag data on the serial console.





  1. Prerequisite:

3.1. Hardware:

  • Pico microcontroller

  • RFID reader

  • RFID Tag

  • Breadboard

  • Jumper wires

  • USB cable (to connect the computer)

3 .2. Software:

  • Thonny Software(For micro python)

  • MicroPython firmware installed on Raspberry Pi Pico

  • ubuntu Terminal(For embedded C)

  • CMake,Pico SDK,GNU Arm Embedded Toolchain,WSL.



  1. Connection Details:



Raspberry Pi Pico

MFRC522 RFID module

GND

GND

3V3

3.3V

GP5

SDA

GP6

SCK

GP7

MOSI

GP4

MISO

IRQ

GPIO22

RST

Then connect the RGB LED Module R, G & B Pins to GP0, GP1 & GP2 of Raspberry Pi Pico.




  1. Working Principle:

RFID technology works on the principle of electromagnetic fields to transfer data between the reader and the tag. The RFID reader emits a signal, which powers the passive RFID tag. The tag then transmits its stored data back to the reader. The microcontroller processes this data and displays it accordingly.

SPI (Serial Peripheral Interface) Overview

SPI (Serial Peripheral Interface) is a synchronous serial communication protocol primarily used for short-distance communication, mainly in embedded systems, sensors, and microcontrollers. It allows a microcontroller (or master device) to communicate with one or more peripheral devices (slave devices). SPI is widely used due to its simplicity, high-speed data transfer capabilities, and low power consumption.

Key Features of SPI:

  • Full-Duplex Communication: Data can be sent and received simultaneously.

  • Master-Slave Architecture: There is always one master and one or more slaves.

  • Synchronous Communication: It uses a shared clock line, meaning both devices use the same clock for data transmission.

  • High-Speed Communication: SPI can achieve high data transfer speeds, making it ideal for communication with high-speed devices like displays, sensors, and SD cards.

  • Flexible Data Size: It allows the transmission of data in 8-bit, 16-bit, or other sizes, depending on the configuration.

SPI Signals and Pins

SPI uses four main signal lines:

  1. MISO (Master In Slave Out):

    • This line is used to transmit data from the slave to the master.

    • Data is output from the slave and input to the master.

  2. MOSI (Master Out Slave In):

    • This line is used to transmit data from the master to the slave.

    • Data is output from the master and input to the slave.

  3. SCK (Serial Clock):

    • This clock signal is generated by the master and shared with the slave(s).

    • It synchronizes the data transmission.

  4. SS (Slave Select) (also called CS – Chip Select):

    • This signal is used to select a particular slave device for communication.

    • When SS is low (active), the slave listens to the master, and when SS is high (inactive), the slave ignores communication.

In multi-slave systems, each slave has its own SS/CS pin.

SPI Communication Modes

The SPI communication can operate in four different modes, determined by two parameters: Clock Polarity (CPOL) and Clock Phase (CPHA).

  • CPOL: Defines whether the clock is idle high (1) or idle low (0).

  • CPHA: Defines when data is sampled, either on the leading edge or the trailing edge of the clock pulse.

The combinations of CPOL and CPHA give four possible SPI modes:

  • Mode 0: CPOL = 0, CPHA = 0 (Clock idle low, data captured on rising edge)

  • Mode 1: CPOL = 0, CPHA = 1 (Clock idle low, data captured on falling edge)

  • Mode 2: CPOL = 1, CPHA = 0 (Clock idle high, data captured on falling edge)

  • Mode 3: CPOL = 1, CPHA = 1 (Clock idle high, data captured on rising edge)

These modes ensure flexibility in how the master and slave communicate, depending on device specifications.

SPI in Master-Slave Configuration

  • Master: The device that controls the clock signal (SCK) and manages communication.

  • Slave: The device that responds to the master and sends/receives data when selected via SS/CS.

Multiple Slave Communication

SPI supports multiple slaves through multiple SS/CS lines. The master can select any one slave at a time by pulling its SS/CS line low, while keeping others high (inactive).



SPI Communication Steps

  1. Master starts communication: The master pulls the SS/CS line of the desired slave low.

  2. Clock pulses generated: The master generates the clock signal, which is shared with the slave.

  3. Data exchange:

    • The master sends data on the MOSI line, which the slave reads.

    • Simultaneously, the slave can send data on the MISO line, which the master reads.

  4. Communication ends: Once the data exchange is complete, the master pulls the SS/CS line of the slave high to stop communication.



 RFID?

RFID is an acronym for Radio Frequency Identification which means RFID is the wireless, non-contact use of radio frequency waves to transfer data and identify objects, animals, or humans. RFID systems are usually comprised of an RFID reader, RFID tags, and antennas. RFID is widely used in industries like healthcare, retail, hospitality, and manufacturing - just to name a few. RFID is just like barcodes but is not restricted by line-of-sight.

How Does RFID Work?

Tagging items with RFID tags allows users to automatically and uniquely identify and track inventory and assets. RFID uses radio waves sent via an RFID antenna to RFID tags in the surrounding area. RFID readers amplify energy, modulate it with data, and send the energy at a certain frequency out to an RFID antenna cable to the connected RFID antenna

The ability to identify each individual RFID tag being read is all thanks to a unique identifier (unique information) in the RFID tag’s memory. This unique identifier enables two physically identical items to be easily distinguished from one another by a simple read.

RFID takes auto-ID technology to the next level by allowing tags to be read without line of sight and up to 30+ meters away.

RFID has come a long way from its first application of identifying airplanes as friend or foe in World War II back in the 1930s. Not only does the technology continue to improve year over year, but the cost of implementing and using an RFID system continues to decrease, making RFID more cost-effective and efficient. For more information about how RFID is continuing to improve, check out our article - RFID Failed You in the Past? It May Have Improved More Than You Think.

RFID Used For?

Types of RFID Frequencies

When learning about RFID technology, it is important to note that there are three main areas or frequencies that all have different read ranges and specifications.Within the Electromagnetic Spectrum, there are three primary frequency ranges used for RFID transmissions – Low Frequency RFID (LF RFID), High Frequency RFID (HF RFID), and Ultra-High Frequency RFID (UHF RFID).

Low Frequency

  • General Frequency Range: 30 - 300 kHz

  • Primary Frequency Range: 125 - 134 kHz

  • LF RFID Read Range: Contact - 10 Centimeters

  • Average Cost Per LF RFID Tag: $0.75 - $5.00

  • Applications: Animal TrackingAccess Control, Car Key-Fob, Applications with High Volumes of Liquids and Metals

  • Pros: Works well near Liquids & Metals, Global Standards

  • Cons: Very Short Read Range, Limited Quantity of Memory, Low Data Transmission Rate, High Production Cost

High Frequency

  • Primary Frequency Range: 13.56 MHz

  • HF RFID Read Range: Near Contact - 30 Centimeters

  • Average Cost Per HF RFID Tag: $0.20 - $10.00

  • Applications: DVD Kiosks, Library Books, Personal ID Cards, Poker/Gaming Chips, NFC Applications

  • Pros: NFC Global Protocols, Larger Memory Options, Global Standards

  • Cons: Short Read Range, Low Data Transmission Rate

Ultra-High Frequency

  • General Frequency Range: 300 - 3000 MHz

  • Primary Frequency Ranges: 433 MHz, 860 - 960 MHz

There are two types of RFID that reside within the Ultra High Frequency range: Active RFID and Passive RFID.

What is Active RFID?

  • Primary Frequency Range: 433 MHz, (Can use 2.45 GHz - under the Extremely High-Frequency Range)

  • Active RFID Read Range: 30 - 100+ Meters

  • Average Cost Per Active RFID Tag: $15.00 - $50.00

  • Applications: Vehicle Tracking, Auto Manufacturing, Mining, Construction, Asset Tracking, Cargo Container Tracking, Construction Tools

  • Pros: Very Long Read Range, Lower Infrastructure Cost (vs. Passive RFID), Large Memory Capacity, High Data Transmission Rates

  • Cons: High Per Tag Cost, Shipping Restrictions (due to batteries), Complex Software may be Required, High Interference from Metal and Liquids; Few Global Standards

What is Passive RFID?

  • Primary Frequency Ranges: 860 - 960 MHz

  • Passive RFID Read Range: Near Contact - 25 Meters

  • Average Cost Per UHF RFID Tag: $0.08 - $20.00

  • Applications: Manufacturing, PharmaceuticalsTollingInventory TrackingRace TimingAsset Tracking, Supply Chain Management, IT Asset TrackingTool Tracking, Laundry Tracking, Library Management, Access Control, User Experience

  • Pros: Long Read Range, Low Cost Per Tag, Wide Variety of Tag Sizes and Shapes, Global Standards, High Data Transmission Rates

  • Cons: High Equipment Costs, Moderate Memory Capacity, High Interference from Metal and Liquids

 RFID System?

While each system will vary in terms of device types and complexity, traditional (fixed) RFID systems contain at least the following four components:

  • Readers

  • Antennas

  • Tags

  • Cables

The exception to that rule is when a system uses a mobile/handheld/USB reader or other integrated reader which combines the reader, antenna, and cabling.

A mobile handheld RFID reader (with an integrated antenna) and RFID tags make up the simplest RFID system, while more complex systems are designed using multi-port readers, antenna hubs (https://www.atlasrfidstore.com/rfid-insider/antenna-multiplexers-save-thousands-of-dollars/), GPIO boxes, additional functionality devices (e.g. stack lights), multiple antennas and cables, RFID tags, and a complete software setup.

What is an RFID Tag?

An RFID tag in its most simplistic form, is comprised of two parts – an antenna for transmitting and receiving signals, and an RFID chip (or integrated circuit, IC) which stores the tag’s ID and other information. RFID tags are affixed to items in order to track them using an RFID reader and antenna.

RFID tags transmit data about an item (contained on the RFID chip) through radio waves to the antenna/reader combination. RFID tags typically do not have a battery (unless specified as Active or BAP tags); instead, they receive energy from the radio waves generated by the reader. When the RFID tag receives the transmission from the reader/antenna, the energy runs through the internal antenna to the tag’s chip. The energy activates the RFID chip, which modulates the energy with the desired information, and then transmits a signal back toward the antenna/reader.

On each RFID chip, there are four memory banks – EPC, TID, User, and Reserved. Each of these memory banks contains information about the item that is tagged or the tag itself depending on the bank and what has been specified. Two of the four memory banks, the EPC and User, can be programmed with a unique number or information for identifying the item on which it’s placed. The TID bank cannot be updated because it contains information about the tag itself as well as the unique tag identifier. The RFID tag’s Reserved memory bank is used for special tag operations, like locking the tag or expanding its available EPC memory.

Hundreds of different RFID tags are available in many shapes and sizes with features and options specific to certain environments, surface materials, and applications. It’s important to choose the ideal tag for the specific application, environment, and item material in order to get the best performance out of your tag. To learn more about how to choose RFID tags for your application and then how to test them

What is an RFID Reader?

An RFID reader is the brain of the RFID system and is necessary for any system to function. Readers, also called interrogators, are devices that transmit and receive radio waves in order to communicate with RFID tags. RFID readers are typically divided into three distinct types in terms of mobility/flexibility – Fixed RFID ReadersMobile RFID Readers, and USB Readers.

Fixed readers stay in one location and are typically mounted on walls, on desks, into portals, or in other stationary locations. Fixed RFID Readers typically have external antenna ports that can connect anywhere from one additional antenna to up to eight different antennas. With the addition of one or more multiplexers, some readers can connect to up to 64 RFID antennas. The number of antennas connected to one reader depends on the area of coverage required for the RFID application. Some desktop applications, like checking files in and out, only need a small area of coverage, so one antenna works well. Other applications with a larger area of coverage, such as a finish line in a race timing application typically require multiple antennas to create the necessary coverage zone.

Mobile readers are handheld devices that allow for flexibility when reading RFID tags while still being able to communicate with a host computer or smart device. Most mobile devices are cordless and rely on a battery for a power source and Wi-Fi or Bluetooth for data transmission. There are two primary categories of Mobile RFID readers – readers with an onboard computer, called Mobile Computing Devices, and readers that use a Bluetooth or Auxiliary connection to a smart device or tablet, called Sleds.

A common subset of fixed or mobile readers is integrated readers. Most mobile readers are integrated readers, but fixed readers are available as lone devices or as integrated devices. An integrated RFID reader is a reader with a built-in antenna that does not have to be connected to an external antenna. Integrated readers are usually aesthetically pleasing and designed to be used for indoor applications without a high traffic of tagged items.

USB Readers are a unique subset of RFID readers because, while they are fixed to a computer, they are not fixed to a wall outlet, allowing them to have more mobility than a typical fixed RFID reader. USB readers are incredibly popular for any desktop applications or specifically for reading and writing individual RFID tags.

RFID RC522 Module

The RC522 RFID module based on the MFRC522 IC from NXP Semiconductor. It usually comes with an RFID card tag and a key tag. It has 1KB of memory and it is used to write a tag. Any message can be stored using this memory.

The RC522 RFID reader module is designed to create a 13.56MHz electromagnetic field and communicate with RFID tags. The reader can communicate with any microcontroller over a 4-pin SPI. In SPI Mode it can communicate with a maximum data rate of 10 Mbps. It also supports communication over I2C and UART protocols.

The RC522 RFID module can be programmed to generate an interrupt, allowing the module to alert us when a tag approaches it. The module’s operating voltage ranges from 2.5 to 3.3V, but its SPI Pin is 5V tolerant. Therefore you can connect the RC522 Module to Arduino or Raspberry Pi Pico.

Specifications

  • Module interfaces SPI: Data transfer rate maximum 10 Mbit/s

  • Power Voltage: 2.5-3.3 V

  • Operating frequency: 13.56 MHz

  • Operating current: 13-26 mA/DC 3.3 V

  • Idle current: 10-13 mA/DC 3.3 V

  • Sleep current: <80 uA

  • Peak current: <30 mA

  • Read Range: 0 ~ 35 mm (mifare1 card)

  • Supported card types: Mifare1 S50, Mifare1 S70, MIFARE Ultralight, Mifare Pro, and MIFARE DESFire

RFID RC522 Pinout

The RFID RC522 communicates via SPI, I2C & UART Communication Mode. It has a total number of 9 pins.

  • SDA SCL: I2C Communication pins. DATA and CLOCK.

  • SS SCK MOSI MISO: SPI communication pins. Slave Select, Clock, MOSI, and MISO.

  • RX TX: UART Communication pins.

  • IRQ:  Interrupt signal from the module to indicate RFID tag detection.

  • GND: Ground pin that needs to be connected to the GND pin on the Arduino.

  • RST: Reset pin for the module

  • VCC: Supply pin for the module (2.5V to 3.3V).







  1. Application code:

  • MicroPython:

from mfrc522 import MFRC522

from machine import Pin

import utime


# Initialize the MFRC522 reader

reader = MFRC522(spi_id=0, sck=6, miso=4, mosi=7, cs=5, rst=22)


# Initialize LED pins

red = Pin(0, Pin.OUT)

green = Pin(1, Pin.OUT)

blue = Pin(2, Pin.OUT)


# Turn off all LEDs initially

red.value(0)

green.value(0)

blue.value(0)


print("Bring TAG closer...")

print("")


while True:

# Initialize RFID reader for every loop iteration

reader.init()

(stat, tag_type) = reader.request(reader.REQIDL)

if stat == reader.OK:

(stat, uid) = reader.SelectTagSN()

if stat == reader.OK:

# Convert the UID to an integer

card = int.from_bytes(bytes(uid), "little", False)

print("CARD ID: " + str(card))

# Turn off all LEDs first

red.value(0)

green.value(0)

blue.value(0)

# Control LEDs based on the card ID

if card == 4120449875:

green.value(1)

elif card == 3310611155:

blue.value(1)

else:

red.value(1) # If card is unrecognized, turn on red LED

# Sleep to avoid continuous polling

utime.sleep_ms(500)



  • MPRC522 LIBRARY:

from machine import Pin, SPI

from os import uname

class MFRC522:

DEBUG = False

OK = 0

NOTAGERR = 1

ERR = 2

REQIDL = 0x26

REQALL = 0x52

AUTHENT1A = 0x60

AUTHENT1B = 0x61

PICC_ANTICOLL1 = 0x93

PICC_ANTICOLL2 = 0x95

PICC_ANTICOLL3 = 0x97

def __init__(self, sck, mosi, miso, rst, cs,baudrate=1000000,spi_id=0):

self.sck = Pin(sck, Pin.OUT)

self.mosi = Pin(mosi, Pin.OUT)

self.miso = Pin(miso)

self.rst = Pin(rst, Pin.OUT)

self.cs = Pin(cs, Pin.OUT)

self.rst.value(0)

self.cs.value(1)

board = uname()[0]

if board == 'WiPy' or board == 'LoPy' or board == 'FiPy':

self.spi = SPI(0)

self.spi.init(SPI.MASTER, baudrate=1000000, pins=(self.sck, self.mosi, self.miso))

elif (board == 'esp8266') or (board == 'esp32'):

self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso)

self.spi.init()

elif board == 'rp2':

self.spi = SPI(spi_id,baudrate=baudrate,sck=self.sck, mosi= self.mosi, miso= self.miso)

else:

raise RuntimeError("Unsupported platform")

self.rst.value(1)

self.init()

def _wreg(self, reg, val):

self.cs.value(0)

self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e)))

self.spi.write(b'%c' % int(0xff & val))

self.cs.value(1)

def _rreg(self, reg):

self.cs.value(0)

self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80)))

val = self.spi.read(1)

self.cs.value(1)

return val[0]

def _sflags(self, reg, mask):

self._wreg(reg, self._rreg(reg) | mask)

def _cflags(self, reg, mask):

self._wreg(reg, self._rreg(reg) & (~mask))

def _tocard(self, cmd, send):

recv = []

bits = irq_en = wait_irq = n = 0

stat = self.ERR

if cmd == 0x0E:

irq_en = 0x12

wait_irq = 0x10

elif cmd == 0x0C:

irq_en = 0x77

wait_irq = 0x30

self._wreg(0x02, irq_en | 0x80)

self._cflags(0x04, 0x80)

self._sflags(0x0A, 0x80)

self._wreg(0x01, 0x00)

for c in send:

self._wreg(0x09, c)

self._wreg(0x01, cmd)

if cmd == 0x0C:

self._sflags(0x0D, 0x80)

i = 2000

while True:

n = self._rreg(0x04)

i -= 1

if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)):

break

self._cflags(0x0D, 0x80)

if i:

if (self._rreg(0x06) & 0x1B) == 0x00:

stat = self.OK

if n & irq_en & 0x01:

stat = self.NOTAGERR

elif cmd == 0x0C:

n = self._rreg(0x0A)

lbits = self._rreg(0x0C) & 0x07

if lbits != 0:

bits = (n - 1) * 8 + lbits

else:

bits = n * 8

if n == 0:

n = 1

elif n > 16:

n = 16

for _ in range(n):

recv.append(self._rreg(0x09))

else:

stat = self.ERR

return stat, recv, bits

def _crc(self, data):

self._cflags(0x05, 0x04)

self._sflags(0x0A, 0x80)

for c in data:

self._wreg(0x09, c)

self._wreg(0x01, 0x03)

i = 0xFF

while True:

n = self._rreg(0x05)

i -= 1

if not ((i != 0) and not (n & 0x04)):

break

return [self._rreg(0x22), self._rreg(0x21)]

def init(self):

self.reset()

self._wreg(0x2A, 0x8D)

self._wreg(0x2B, 0x3E)

self._wreg(0x2D, 30)

self._wreg(0x2C, 0)

self._wreg(0x15, 0x40)

self._wreg(0x11, 0x3D)

self.antenna_on()

def reset(self):

self._wreg(0x01, 0x0F)

def antenna_on(self, on=True):

if on and ~(self._rreg(0x14) & 0x03):

self._sflags(0x14, 0x03)

else:

self._cflags(0x14, 0x03)

def request(self, mode):

self._wreg(0x0D, 0x07)

(stat, recv, bits) = self._tocard(0x0C, [mode])

if (stat != self.OK) | (bits != 0x10):

stat = self.ERR

return stat, bits

def anticoll(self,anticolN):

ser_chk = 0

ser = [anticolN, 0x20]

self._wreg(0x0D, 0x00)

(stat, recv, bits) = self._tocard(0x0C, ser)

if stat == self.OK:

if len(recv) == 5:

for i in range(4):

ser_chk = ser_chk ^ recv[i]

if ser_chk != recv[4]:

stat = self.ERR

else:

stat = self.ERR

return stat, recv

def PcdSelect(self, serNum,anticolN):

backData = []

buf = []

buf.append(anticolN)

buf.append(0x70)

#i = 0

###xorsum=0;

for i in serNum:

buf.append(i)

#while i<5:

# buf.append(serNum[i])

# i = i + 1

pOut = self._crc(buf)

buf.append(pOut[0])

buf.append(pOut[1])

(status, backData, backLen) = self._tocard( 0x0C, buf)

if (status == self.OK) and (backLen == 0x18):

return 1

else:

return 0

def SelectTag(self, uid):

byte5 = 0

#(status,puid)= self.anticoll(self.PICC_ANTICOLL1)

#print("uid",uid,"puid",puid)

for i in uid:

byte5 = byte5 ^ i

puid = uid + [byte5]

if self.PcdSelect(puid,self.PICC_ANTICOLL1) == 0:

return (self.ERR,[])

return (self.OK , uid)

def tohexstring(self,v):

s="["

for i in v:

if i != v[0]:

s = s+ ", "

s=s+ "0x{:02X}".format(i)

s= s+ "]"

return s

def SelectTagSN(self):

valid_uid=[]

(status,uid)= self.anticoll(self.PICC_ANTICOLL1)

#print("Select Tag 1:",self.tohexstring(uid))

if status != self.OK:

return (self.ERR,[])

if self.DEBUG: print("anticol(1) {}".format(uid))

if self.PcdSelect(uid,self.PICC_ANTICOLL1) == 0:

return (self.ERR,[])

if self.DEBUG: print("pcdSelect(1) {}".format(uid))

#check if first byte is 0x88

if uid[0] == 0x88 :

#ok we have another type of card

valid_uid.extend(uid[1:4])

(status,uid)=self.anticoll(self.PICC_ANTICOLL2)

#print("Select Tag 2:",self.tohexstring(uid))

if status != self.OK:

return (self.ERR,[])

if self.DEBUG: print("Anticol(2) {}".format(uid))

rtn = self.PcdSelect(uid,self.PICC_ANTICOLL2)

if self.DEBUG: print("pcdSelect(2) return={} uid={}".format(rtn,uid))

if rtn == 0:

return (self.ERR,[])

if self.DEBUG: print("PcdSelect2() {}".format(uid))

#now check again if uid[0] is 0x88

if uid[0] == 0x88 :

valid_uid.extend(uid[1:4])

(status , uid) = self.anticoll(self.PICC_ANTICOLL3)

#print("Select Tag 3:",self.tohexstring(uid))

if status != self.OK:

return (self.ERR,[])

if self.DEBUG: print("Anticol(3) {}".format(uid))

if self.MFRC522_PcdSelect(uid,self.PICC_ANTICOLL3) == 0:

return (self.ERR,[])

if self.DEBUG: print("PcdSelect(3) {}".format(uid))

valid_uid.extend(uid[0:5])

# if we are here than the uid is ok

# let's remove the last BYTE whic is the XOR sum

return (self.OK , valid_uid[:len(valid_uid)-1])

#return (self.OK , valid_uid)

def auth(self, mode, addr, sect, ser):

return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0]

def authKeys(self,uid,addr,keyA=None, keyB=None):

status = self.ERR

if keyA is not None:

status = self.auth(self.AUTHENT1A, addr, keyA, uid)

elif keyB is not None:

status = self.auth(self.AUTHENT1B, addr, keyB, uid)

return status

def stop_crypto1(self):

self._cflags(0x08, 0x08)

def read(self, addr):

data = [0x30, addr]

data += self._crc(data)

(stat, recv, _) = self._tocard(0x0C, data)

return stat, recv

def write(self, addr, data):

buf = [0xA0, addr]

buf += self._crc(buf)

(stat, recv, bits) = self._tocard(0x0C, buf)

if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):

stat = self.ERR

else:

buf = []

for i in range(16):

buf.append(data[i])

buf += self._crc(buf)

(stat, recv, bits) = self._tocard(0x0C, buf)

if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):

stat = self.ERR

return stat

def writeSectorBlock(self,uid, sector, block, data, keyA=None, keyB = None):

absoluteBlock = sector * 4 + (block % 4)

if absoluteBlock > 63 :

return self.ERR

if len(data) != 16:

return self.ERR

if self.authKeys(uid,absoluteBlock,keyA,keyB) != self.ERR :

return self.write(absoluteBlock, data)

return self.ERR

def readSectorBlock(self,uid ,sector, block, keyA=None, keyB = None):

absoluteBlock = sector * 4 + (block % 4)

if absoluteBlock > 63 :

return self.ERR, None

if self.authKeys(uid,absoluteBlock,keyA,keyB) != self.ERR :

return self.read(absoluteBlock)

return self.ERR, None

def MFRC522_DumpClassic1K(self,uid, Start=0, End=64, keyA=None, keyB=None):

for absoluteBlock in range(Start,End):

status = self.authKeys(uid,absoluteBlock,keyA,keyB)

# Check if authenticated

print("{:02d} S{:02d} B{:1d}: ".format(absoluteBlock, absoluteBlock//4 , absoluteBlock % 4),end="")

if status == self.OK:

status, block = self.read(absoluteBlock)

if status == self.ERR:

break

else:

for value in block:

print("{:02X} ".format(value),end="")

print(" ",end="")

for value in block:

if (value > 0x20) and (value < 0x7f):

print(chr(value),end="")

else:

print('.',end="")

print("")

else:

break

if status == self.ERR:

print("Authentication error")

return self.ERR

return self.OK

  • Embedded C:

#include <stdio.h>

#include "pico/stdlib.h"

#include "hardware/spi.h"

#include "MFRC522.h"


// Pin definitions

#define RED_LED 0

#define GREEN_LED 1

#define BLUE_LED 2


void init_leds() {

gpio_init(RED_LED);

gpio_set_dir(RED_LED, GPIO_OUT);

gpio_init(GREEN_LED);

gpio_set_dir(GREEN_LED, GPIO_OUT);

gpio_init(BLUE_LED);

gpio_set_dir(BLUE_LED, GPIO_OUT);


gpio_put(RED_LED, 0);

gpio_put(GREEN_LED, 0);

gpio_put(BLUE_LED, 0);

}


int main() {

stdio_init_all();

spi_init(spi0, 1000 * 1000);

MFRC522_Init();


init_leds();

printf("Bring TAG closer...\n");


while (true) {

if (MFRC522_Request(PICC_REQIDL, NULL) == MI_OK) {

uint8_t uid[5];

if (MFRC522_Anticoll(uid) == MI_OK) {

uint32_t card = (uid[0] << 24) | (uid[1] << 16) | (uid[2] << 8) | uid[3];

printf("CARD ID: %u\n", card);


gpio_put(RED_LED, 0);

gpio_put(GREEN_LED, 0);

gpio_put(BLUE_LED, 0);


if (card == 4120449875) {

gpio_put(GREEN_LED, 1);

} else if (card == 3310611155) {

gpio_put(BLUE_LED, 1);

} else {

gpio_put(RED_LED, 1);

}

}

}

sleep_ms(500);

}

return 0;

}


  • MFRC522.h:

#ifndef MFRC522_H

#define MFRC522_H


#include <stdint.h>

#define CommandReg 0x01

#define ComIEnReg 0x02

#define DivIEnReg 0x03

#define ComIrqReg 0x04

#define ErrorReg 0x06 // Error register

#define Status1Reg 0x07

#define Status2Reg 0x08

#define ModeReg 0x11

#define TxControlReg 0x14

#define RxControlReg 0x13

#define FIFODataReg 0x09

#define FIFOLevelReg 0x0A

#define CRCResultRegL 0x22

#define CRCResultRegH 0x21

#define VersionReg 0x37


// MFRC522 Commands

#define PCD_IDLE 0x00

#define PCD_AUTHENT 0x0E

#define PCD_RECEIVE 0x08

#define PCD_TRANSMIT 0x04

#define PCD_TRANSCEIVE 0x0C

#define PCD_RESET_PH 0x0F

#define PCD_CALCCRC 0x03


// MFRC522 PICC Commands

#define PICC_REQIDL 0x26

#define PICC_ANTICOLL 0x93


// Status codes

#define MI_OK 0

#define MI_NOTAGERR 1

#define MI_ERR 2


// Function declarations

void MFRC522_Init(void);

void MFRC522_Reset(void);

void MFRC522_AntennaOn(void);

uint8_t MFRC522_Request(uint8_t reqMode, uint8_t *TagType);

uint8_t MFRC522_Anticoll(uint8_t *serNum);

void MFRC522_WriteRegister(uint8_t reg, uint8_t value);

uint8_t MFRC522_ReadRegister(uint8_t reg);

uint8_t MFRC522_ToCard(uint8_t command, uint8_t *sendData, uint8_t sendLen, uint8_t *backData, uint32_t *backLen);


#endif



  • MFRC522.c:

#include "MFRC522.h"

#include "hardware/spi.h"

#include "hardware/gpio.h"


// Pin definitions for SPI and RFID

#define SPI_PORT spi0

#define RST_PIN 22

#define CS_PIN 5


// MFRC522 Registers

#define CommandReg 0x01

#define CommIEnReg 0x02

#define DivIEnReg 0x03

#define CommIrqReg 0x04

#define FIFOLevelReg 0x0A

#define FIFODataReg 0x09

#define ControlReg 0x0C

#define BitFramingReg 0x0D

#define ModeReg 0x11

#define TxControlReg 0x14

#define ErrorReg 0x06


void MFRC522_WriteRegister(uint8_t reg, uint8_t value) {

gpio_put(CS_PIN, 0); // Select RFID

spi_write_blocking(SPI_PORT, &reg, 1);

spi_write_blocking(SPI_PORT, &value, 1);

gpio_put(CS_PIN, 1); // Deselect RFID

}


uint8_t MFRC522_ReadRegister(uint8_t reg) {

uint8_t value;

reg = (reg << 1) | 0x80;

gpio_put(CS_PIN, 0); // Select RFID

spi_write_blocking(SPI_PORT, &reg, 1);

spi_read_blocking(SPI_PORT, 0, &value, 1);

gpio_put(CS_PIN, 1); // Deselect RFID

return value;

}


void MFRC522_Init(void) {

// Initialize SPI

spi_init(SPI_PORT, 1000000);

gpio_set_function(6, GPIO_FUNC_SPI); // SCK

gpio_set_function(7, GPIO_FUNC_SPI); // MOSI

gpio_set_function(4, GPIO_FUNC_SPI); // MISO

// Initialize RST and CS

gpio_init(RST_PIN);

gpio_set_dir(RST_PIN, GPIO_OUT);

gpio_put(RST_PIN, 1); // Set RST high


gpio_init(CS_PIN);

gpio_set_dir(CS_PIN, GPIO_OUT);

gpio_put(CS_PIN, 1); // Set CS high


MFRC522_Reset();

MFRC522_WriteRegister(TxControlReg, 0x03); // Enable antenna

}


void MFRC522_Reset(void) {

MFRC522_WriteRegister(CommandReg, PCD_RESET_PH);

}


uint8_t MFRC522_Request(uint8_t reqMode, uint8_t *TagType) {

uint8_t status;

uint32_t backBits;

MFRC522_WriteRegister(BitFramingReg, 0x07);

TagType[0] = reqMode;

status = MFRC522_ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits);

return (status == MI_OK && backBits == 0x10) ? MI_OK : MI_ERR;

}


uint8_t MFRC522_Anticoll(uint8_t *serNum) {

uint8_t status;

uint8_t serNumCheck = 0;

uint32_t unLen;

MFRC522_WriteRegister(BitFramingReg, 0x00);

serNum[0] = PICC_ANTICOLL;

serNum[1] = 0x20;

status = MFRC522_ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen);

if (status == MI_OK) {

for (int i = 0; i < 4; i++) {

serNumCheck ^= serNum[i];

}

if (serNumCheck != serNum[4]) {

status = MI_ERR;

}

}

return status;

}


uint8_t MFRC522_ToCard(uint8_t command, uint8_t *sendData, uint8_t sendLen, uint8_t *backData, uint32_t *backLen) {

uint8_t status = MI_ERR;

uint8_t irqEn = 0x77;

uint8_t waitIRq = 0x30;

uint8_t lastBits;

uint8_t n;

uint32_t i;

MFRC522_WriteRegister(CommIEnReg, irqEn | 0x80);

MFRC522_WriteRegister(CommandReg, PCD_IDLE);

MFRC522_WriteRegister(FIFOLevelReg, 0x80);

for (i = 0; i < sendLen; i++) {

MFRC522_WriteRegister(FIFODataReg, sendData[i]);

}

MFRC522_WriteRegister(CommandReg, command);

if (command == PCD_TRANSCEIVE) {

MFRC522_WriteRegister(BitFramingReg, 0x80);

}

i = 2000;

do {

n = MFRC522_ReadRegister(CommIrqReg);

i--;

} while (i != 0 && !(n & 0x01) && !(n & waitIRq));

if (i != 0) {

if (!(MFRC522_ReadRegister(ErrorReg) & 0x1B)) {

status = MI_OK;

if (n & irqEn & 0x01) {

status = MI_NOTAGERR;

}

if (command == PCD_TRANSCEIVE) {

n = MFRC522_ReadRegister(FIFOLevelReg);

lastBits = MFRC522_ReadRegister(ControlReg) & 0x07;

*backLen = (n - 1) * 8 + lastBits;

if (n == 0) {

n = 1;

}

if (*backLen > 0) {

for (i = 0; i < n; i++) {

backData[i] = MFRC522_ReadRegister(FIFODataReg);

}

}

}

} else {

status = MI_ERR;

}

}

return status;

}


void MFRC522_AntennaOn(void) {

uint8_t temp = MFRC522_ReadRegister(TxControlReg);

if (!(temp & 0x03)) {

MFRC522_WriteRegister(TxControlReg, temp | 0x03);

}

}






  1. Hardware Image:



  1. Output:

The expected output when running the program on the Raspberry Pi Pico will be the UID of the detected RFID tag displayed in the serial console.

  1. Video Demonstration:





  1. Appendix:

  • Common CMakeLists:

cmake_minimum_required(VERSION 3.12)


# Pull in SDK (must be before project)

include(pico_sdk_import.cmake)


project(pico_experiments C CXX ASM)


set(CMAKE_C_STANDARD 11)

set(CMAKE_CXX_STANDARD 17)


if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0")

    message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")

endif()


# Initialize the SDK

pico_sdk_init()


add_compile_options(-Wall

        -Wno-format          # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int

        -Wno-unused-function # we have some for the docs that arent called

        )

if (CMAKE_C_COMPILER_ID STREQUAL "GNU")

    add_compile_options(-Wno-maybe-uninitialized)

endif()


# Hardware-specific examples in subdirectories:

add_subdirectory(expt_10_LCD)

  • CMakeLists:

# Set the minimum CMake version required

cmake_minimum_required(VERSION 3.13)


# Define the project name

project(MFRC522_Project)


# Initialize the Pico SDK (adjust the path if required)

include(pico_sdk_import.cmake)

pico_sdk_init()


# Define your executable and source files

add_executable(MFRC522_Project

main.c # Your main application code

MFRC522.c # MFRC522 library implementation

)


# Link any libraries that your project needs

target_link_libraries(MFRC522_Project

pico_stdlib # Standard Pico SDK libraries

hardware_spi # SPI library for hardware communication

)


# Enable USB or UART (depending on your serial communication preferences)

pico_enable_stdio_usb(MFRC522_Project 1) # Enable USB for debug output

pico_enable_stdio_uart(MFRC522_Project 0) # Disable UART for this project


# Create additional output formats (like UF2, bin, hex)

pico_add_extra_outputs(MFRC522_Project)

  1. References:



Class Schedules:
# Topic Date & time Action

Curriculum

0% Completed (0/1)