NFC with Arduino and Raspberry Pi

Hardware Integration Guide

NFC with Arduino and Raspberry Pi

Embedded NFC opens up projects that smartphones cannot: fixed-installation readers, kiosk systems, industrial automation, and custom hardware. The PN532 and RC522 are the two most common breakout modules for hobbyist and prototyping use.

Hardware Overview

Module Chip Protocol Interface Price Supported Tag Types
PN532 NXP PN532 iso-14443 A/B, FeliCa, ISO 18092 I²C, SPI, UART $5–$12 Types 1–4, MIFARE
RC522 NXP MFRC522 ISO 14443-A only SPI $2–$5 Type 2 (NTAG/MIFARE)
ST25R3911B STMicro ISO 14443, 15693, 18000-3 SPI $15–$30 Types 1–5

The PN532 is the recommended choice: it supports all four major nfc-a and nfc-b tag types, has mature libraries for both Arduino and Raspberry Pi, and handles the full iso-14443 T=CL protocol needed for DESFire communication. The RC522 is cheaper but limited to ISO 14443-A and lacks ISO 14443-4 support.

Arduino: PN532 Wiring (I²C)

PN532 VCC  → Arduino 5V (or 3.3V — check your module)
PN532 GND  → Arduino GND
PN532 SDA  → Arduino SDA (A4 on Uno, 20 on Mega)
PN532 SCL  → Arduino SCL (A5 on Uno, 21 on Mega)
PN532 IRQ  → Arduino D2 (interrupt pin)
PN532 RST  → Arduino D3 (optional reset)

Set the DIP switches on the PN532 breakout to 1=ON, 2=OFF for I²C mode.

Arduino: Reading a Tag UID

#include <Wire.h>
#include <Adafruit_PN532.h>

#define PN532_IRQ 2
#define PN532_RST 3

Adafruit_PN532 nfc(PN532_IRQ, PN532_RST);

void setup() {
    Serial.begin(115200);
    nfc.begin();
    uint32_t versiondata = nfc.getFirmwareVersion();
    if (!versiondata) { Serial.println("PN532 not found"); while(1); }
    nfc.SAMConfig(); // configure the SAM (Security Access Module)
}

void loop() {
    uint8_t uid[7];
    uint8_t uidLength;
    if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500)) {
        Serial.print("UID: ");
        for (uint8_t i = 0; i < uidLength; i++) {
            Serial.print(uid[i], HEX); Serial.print(" ");
        }
        Serial.println();
    }
}

The uid is printed as hex. For NTAG213 tags, uidLength is 7 bytes. For older MIFARE Classic 1K, it is 4 bytes.

Raspberry Pi: PN532 via SPI (Python)

import board
import busio
import adafruit_pn532.spi as pn532_spi
import digitalio

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
cs = digitalio.DigitalInOut(board.D4)
pn532 = pn532_spi.PN532_SPI(spi, cs, debug=False)
pn532.SAM_configuration()

print("Waiting for NFC card...")
while True:
    uid = pn532.read_passive_target(timeout=0.5)
    if uid:
        print("Found card with UID:", [hex(i) for i in uid])

Install dependencies: pip install adafruit-circuitpython-pn532

RC522 with Arduino

The RC522 uses SPI only and works exclusively with ISO 14443-A (nfc-a) tags. The MFRC522 library is the standard:

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN 9
#define SS_PIN 10

MFRC522 mfrc522(SS_PIN, RST_PIN);

void setup() {
    SPI.begin();
    mfrc522.PCD_Init();
}

void loop() {
    if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
        for (byte i = 0; i < mfrc522.uid.size; i++) {
            Serial.print(mfrc522.uid.uidByte[i], HEX);
        }
        Serial.println();
        mfrc522.PICC_HaltA();
    }
}

Choosing Between PN532 and RC522

Need Recommendation
Read NTAG tags only RC522 (cheaper)
Read + write NDEF PN532 (better library support)
DESFire / ISO 14443-4 PN532 only
Raspberry Pi PN532 (SPI or I²C)
Battery-powered / low cost RC522

The nfc-controller chip in both modules handles the RF protocol layer — analog RF generation, anti-collision, and framing — so your microcontroller only needs to exchange commands over SPI/I²C.

Use the NFC Compatibility Checker to verify that your chosen module supports the tag type you plan to read.

See also: NFC Chip Comparison Guide and How to Read and Write NFC Tags.

Terms in This Guide