To build a functional RFID tag reader Raspberry Pi project, you need a 13.56 MHz RC522 module wired to the Pi's hardware SPI0 bus. This guide targets the Raspberry Pi 4 Model B (4GB or 8GB) running Raspberry Pi OS (Bookworm or Bullseye). We use the Pi 4 specifically because the newer Raspberry Pi 5 utilizes the RP1 southbridge chip, which breaks legacy Python GPIO libraries like RPi.GPIO that most RC522 Python wrappers still depend on in 2026.
The direct answer for hardware selection: buy the standard RFID-RC522 breakout board (often branded by HiLetgo or SunFounder) and use the hardware SPI pins, not software I2C or UART bit-banging. Below is the complete build procedure, pin mapping, and production-ready Python code.
Choosing Your RFID Hardware: RC522 vs Alternatives
Before wiring, you must match the RFID module to your tag ecosystem. The RC522 operates at 13.56 MHz (High Frequency), meaning it will not read the thick 125 kHz proximity cards used in older office buildings. Here is how the standard hobbyist modules compare on the bench.
| Module | Frequency | Protocol | Read/Write | Logic Level | Avg Price (2026) |
|---|---|---|---|---|---|
| RC522 (MFRC522) | 13.56 MHz | ISO 14443A (Mifare) | Read & Write | 3.3V Strict | $3 - $5 |
| PN532 | 13.56 MHz | ISO 14443A/B, FeliCa | Read & Write | 3.3V / 5V Tolerant | $8 - $12 |
| RDM6300 | 125 kHz | EM4100 / TK4100 | Read Only | 5V TTL | $2 - $4 |
Bench Note: If you need to read NFC Type 4 tags or FeliCa transit cards, the RC522 will fail. You must step up to the PN532. For standard Mifare Classic 1K fobs and access cards, the RC522 is the most cost-effective choice.
Parts List and SPI Pin Mapping
The RC522 communicates via SPI (Serial Peripheral Interface). While the module has an I2C mode, it requires hardware modifications (soldering the I2C pull-up pads on the PCB) that most pre-assembled Amazon/AliExpress boards do not have enabled out of the box. Stick to SPI.
Required Components
- Microcontroller: Raspberry Pi 4 Model B (4GB+)
- RFID Module: RC522 breakout board with 3.3V onboard LDO regulator
- Tags: Mifare Classic 1K (S50) RFID fobs or cards
- Wiring: 7x Female-to-Female Dupont jumper wires
- Optional: 10kΩ pull-up resistor for the MISO line if your wires exceed 15cm
Wiring Pinout Table
The RC522 uses 8 pins, but we only need 7 for basic SPI reading. Never connect the RC522 VCC to the Pi's 5V pin. The Pi's SPI GPIO pins are strictly 3.3V tolerant; feeding 5V into the MISO or MOSI lines will permanently destroy the Pi's SoC.
| RC522 Pin | Raspberry Pi 4 GPIO (BCM) | Pi Physical Pin # | Function |
|---|---|---|---|
| SDA (SS) | GPIO 8 | Pin 24 | SPI Chip Enable 0 (CE0) |
| SCK | GPIO 11 | Pin 23 | SPI Clock (SCLK) |
| MOSI | GPIO 10 | Pin 19 | Master Out Slave In |
| MISO | GPIO 9 | Pin 21 | Master In Slave Out |
| IRQ | Not Connected | - | Interrupt (leave floating) |
| GND | GND | Pin 6 | Common Ground |
| RST | GPIO 25 | Pin 22 | Reset / Power Down |
| 3.3V | 3.3V Power | Pin 1 | VCC Input (3.3V ONLY) |
Software Configuration and SPI Enablement
By default, Raspberry Pi OS disables the SPI hardware bus to save memory and prevent GPIO conflicts. You must enable it before the Python code can talk to the reader.
- Open the terminal and run the configuration tool:
sudo raspi-config - Navigate to Interface Options > SPI and select Yes to enable it.
- Reboot the Pi:
sudo reboot - After rebooting, verify the SPI bus is visible in the filesystem:
ls -l /dev/spidev*. You should seespidev0.0andspidev0.1. - Install the required Python dependencies:
sudo apt update sudo apt install python3-pip python3-spidev python3-rpi.gpio pip3 install mfrc522
Complete Python Code with Error Handling
The following script targets the mfrc522 library. It includes explicit SPI speed throttling. Pro-tip: Many cheap RC522 clones use off-spec crystals that fail to lock at the default 1 MHz SPI speed. Dropping the spd parameter to 500 kHz (500000) in the constructor eliminates silent read failures.
#!/usr/bin/env python3
import sys
import time
import RPi.GPIO as GPIO
from mfrc522 import MFRC522
# Pin definitions for Raspberry Pi 4 (BCM Mode)
RST_PIN = 25
# Initialize GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(RST_PIN, GPIO.OUT)
GPIO.output(RST_PIN, GPIO.HIGH)
def main():
try:
# Initialize reader on SPI0, CE0.
# Speed throttled to 500kHz for clone board stability.
reader = MFRC522(dev='/dev/spidev0.0', spd=500000)
print("[INFO] RC522 Initialized successfully.")
print("[INFO] Hold a Mifare tag near the reader. Press Ctrl+C to exit.")
while True:
# Request tag (REQA command)
(status, TagType) = reader.MFRC522_Request(reader.PICC_REQIDL)
if status == reader.MI_OK:
# Anti-collision to get UID
(status, uid) = reader.MFRC522_Anticoll()
if status == reader.MI_OK:
# Convert UID list to hex string
uid_hex = ' '.join(['{:02X}'.format(x) for x in uid[:4]])
print(f"[READ] Tag UID: {uid_hex}")
# Halt the tag to prevent duplicate rapid reads
reader.MFRC522_HaltA()
time.sleep(1) # Debounce delay
except FileNotFoundError as e:
print(f"[FATAL] SPI Bus Error: {e}")
print("[FIX] Ensure SPI is enabled in raspi-config and /dev/spidev0.0 exists.")
sys.exit(1)
except RuntimeError as e:
print(f"[FATAL] GPIO Library Error: {e}")
print("[FIX] You may be running on a Pi 5. Switch to Pi 4 or use the 'lgpio' library.")
sys.exit(1)
except KeyboardInterrupt:
print("\n[INFO] Exiting gracefully...")
finally:
GPIO.cleanup()
if __name__ == '__main__':
main()
For deeper protocol details, refer to the NXP Mifare Classic 1K Datasheet, which documents the exact memory sector layouts and authentication keys (default Key A is FF FF FF FF FF FF) you will need if you decide to write data to the tags.
Debugging: First Three Things to Check When It Fails
When building embedded SPI projects, silent failures are common. If your script crashes or hangs, check these exact failure modes in order.
Error 1: FileNotFoundError: [Errno 2] No such file or directory: '/dev/spidev0.0'
- Cause: The SPI kernel module is not loaded. This is the most common error.
- Fix: Run
sudo raspi-config, enable SPI, and reboot. Verify withlsmod | grep spi_bcm2835.
Error 2: Script runs, prints "Initialized", but never detects a tag
- Cause A (Wiring): MISO and MOSI are swapped. The Pi's MOSI must go to the RC522's MOSI. Double-check against the pinout table above.
- Cause B (Voltage): The 3.3V LDO on the RC522 board is dead, or you are powering it from the 5V pin while the logic lines are 3.3V, causing a ground loop or logic threshold mismatch. Measure the VCC pin on the module with a multimeter; it must read exactly 3.25V to 3.35V.
- Cause C (Tag Type): You are trying to scan a 125 kHz HID card or an NFC Type 4 phone emulation. The RC522 physically cannot read these. Test with the included blue Mifare 1K fob.
Error 3: RuntimeError: This module can only be run on a Raspberry Pi!
- Cause: You are using a Raspberry Pi 5. The
RPi.GPIOlibrary hardcodes memory addresses for the BCM2711 SoC and crashes on the Pi 5's RP1 chip. - Fix: Migrate to a Raspberry Pi 4, or rewrite the SPI initialization using the modern
gpiodandspidevlibraries directly, bypassing the legacymfrc522wrapper.
Extending and Simplifying the Build
Depending on your end goal, you may want to scale this project up for home automation or scale it down to avoid breadboard wiring entirely.
How to Simplify (The USB Alternative)
If you do not need to write data to the tags and only need to read UIDs for a door lock or PC login, skip the RC522 entirely. Purchase a generic USB RFID Reader (125kHz or 13.56MHz HID emulator) for about $12. These devices act as standard USB HID keyboards. When you scan a tag, the Pi simply receives keystrokes. You can read them in Python using the evdev library, completely eliminating SPI wiring, voltage level concerns, and GPIO permissions.
How to Extend (Home Assistant & MQTT)
To integrate this Pi into a smart home network, add the paho-mqtt library. Instead of printing the UID to the console, publish it to an MQTT broker:
import paho.mqtt.client as mqtt
client = mqtt.Client("RFID_Pi4")
client.connect("192.168.1.100", 1883, 60)
# Inside your read loop:
client.publish("home/rfid/scanner1", uid_hex)
From there, Home Assistant can subscribe to home/rfid/scanner1 and trigger automations, such as disarming the alarm or unlocking a solenoid strike plate wired to the Pi's GPIO via a 5V relay module.
For official hardware interface documentation, always cross-reference the Raspberry Pi SPI Configuration Guide to ensure your OS version hasn't deprecated legacy device tree overlays.






