PN532 Complete Guide: NXP's Most Popular NFC Controller
The PN532 is NXP's most widely deployed NFC nfc-controller for hobbyist and prototyping use. Released in 2007, it remains the default choice for Arduino, Raspberry Pi, and ESP32 NFC projects because of its mature library ecosystem and dual-interface (I2C + SPI + HSU) support.
PN532 at a Glance
| Property | Value |
|---|---|
| Manufacturer | NXP Semiconductors |
| Operating frequencyOperating frequency13.56 MHz ISM band frequency used by all NFC communicationsView full → | 13.56 MHz |
| Supply voltage | 3.3 V (I/O tolerant to 5 V via level shifter) |
| Current (active) | ~100 mA (RF on) |
| Current (standby) | ~5 mA |
| Interface | I2C, SPI (up to 5 MHz), HSU (UART) |
| Tag support | ISO 14443A/B, iso-15693, FeliCa, MIFARE |
| Host controller modes | Reader/Writer, card-emulation-mode, peer-to-peer-mode |
| Max read-range | ~5 cm (antenna dependent) |
Hardware Interface Selection
The PN532 exposes three interfaces simultaneously but activates only one based on the I0/I1 pin states at power-up:
| I1 | I0 | Interface |
|---|---|---|
| 0 | 0 | HSU (UART, 115200 baud default) |
| 0 | 1 | I2C |
| 1 | 0 | SPI |
Most breakout boards (Adafruit PN532, Elechouse v3) provide DIP switches or solder jumpers for I0/I1. SPI is the fastest and most reliable for long cable runs. I2C allows address configuration but is limited to ~400 kHz and sensitive to bus capacitance.
Connecting to Arduino
SPI wiring (recommended):
| PN532 Pin | Arduino Uno |
|---|---|
| VCC | 3.3 V (or 5 V via onboard regulator) |
| GND | GND |
| SCK | 13 (SCK) |
| MISO | 12 (MISO) |
| MOSI | 11 (MOSI) |
| SSEL | 10 (SS, configurable) |
Install the Adafruit PN532 library via Library Manager. The library abstracts the TFI (Transport Frame Interface) framing and handles the PN532's acknowledgement handshake automatically.
#include <Adafruit_PN532.h>
#define PN532_SS 10
Adafruit_PN532 nfc(PN532_SS);
void setup() {
nfc.begin();
nfc.SAMConfig(); // Configure the Secure Access Module
}
void loop() {
uint8_t uid[7];
uint8_t uidLength;
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {
// Tag detected
}
}
Connecting to Raspberry Pi
On Raspberry Pi, use the I2C or SPI interface via the GPIO header.
I2C setup:
1. Enable I2C: sudo raspi-config → Interface Options → I2C → Enable
2. Install libnfc: sudo apt install libnfc-bin libnfc-dev
3. Configure /etc/nfc/libnfc.conf:
device.name = "PN532 I2C"
device.connstring = "pn532_i2c:/dev/i2c-1"
- Test:
nfc-list— should print connected tags
The Python nfcpy library also supports the PN532 and provides a higher-level ndef read/write API:
import nfc
def on_connect(tag):
print(tag.ndef.message)
with nfc.ContactlessFrontend('i2c') as clf:
clf.connect(rdwr={'on-connect': on_connect})
Supported Tag Operations
| Operation | Tags Supported | Library Function |
|---|---|---|
| Read UID | All ISO 14443A/B, FeliCa, ISO 15693ISO 15693Standard for vicinity-range smart cards, 1+ meter read rangeView full → | readPassiveTargetID() |
| Read NDEF | Type 1/2/3/4/5 | readNdefMessage() |
| Write NDEF | Type 2/4 (with password if protected) | writeNdefMessage() |
| MIFARE Classic auth | MIFARE Classic 1K/4K | mifareclassic_AuthenticateBlock() |
| MIFARE read/write | MIFARE Classic | mifareclassic_ReadDataBlock() |
| DESFire AES auth | DESFire EV1/EV2/EV3 | Via raw APDU commands |
| Card emulation | ISO 14443ISO 14443Standard for contactless smart cards at 13.56 MHz (Types A and B)View full →-4 (HCE-like) | tgInitAsTarget() |
Raw APDU Commands
For Type 4 tags and DESFire, the PN532 passes ISO 7816 APDUs directly. Use InDataExchange to send APDUs and receive responses:
uint8_t apdu[] = {0x00, 0xA4, 0x04, 0x00, 0x07,
0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
uint8_t response[64];
uint8_t responseLen = sizeof(response);
nfc.inDataExchange(apdu, sizeof(apdu), response, &responseLen);
Performance Tuning
| Tuning Parameter | Default | Optimised |
|---|---|---|
| RF field on/off timing | Continuous | Pulse on demand (saves power) |
InListPassiveTarget timeout |
100 ms | Reduce for faster polling |
| Retry count | 3 | Set to 1 for single-poll scan |
| Baud rate (HSU) | 115200 | 460800 for lower latency |
PN532 vs Alternatives
| Controller | Interface | NDEF Library | Cost | Best For |
|---|---|---|---|---|
| PN532 | SPI/I2C/UART | Mature (Adafruit, nfcpy) | ~$5–15 | General prototyping |
| PN7150 | I2C (NCI) | NCI stack required | ~$10–20 | Linux embedded, Android |
| ST25R3916 | SPI | ST25R SDK | ~$8–20 | Multi-protocol, HF RFID |
| RC522 | SPI | MFRC522 library | ~$1–3 | MIFARE Classic only |
| ACR122U | USB | libnfc | ~$30 | PC-attached reader |
Common Issues and Fixes
| Issue | Likely Cause | Fix |
|---|---|---|
nfc.begin() hangs |
Wrong interface selected (I0/I1 mismatch) | Check DIP switch matches code |
| Tag not detected | Antenna detuned by nearby metal | Move away from metal; use ferrite-backed tag |
| MIFARE auth fails | Wrong key (default 0xFF×6) | Try both key A and key B; try default keys |
| SPI data corruption | Long cable, no decoupling caps | Shorten cable; add 100 nF cap on VCC |
| I2C address conflict | Another I2C device at 0x24 | Change I2C address or use SPI |