Skip to content

adafruit_pn532

Works with

Any board with I2C or SPI. The PN532 breakout board supports both interfaces — select with jumpers.

What it does

adafruit_pn532 drives the PN532 NFC/RFID controller chip, which can read and write NFC tags and cards. It works with MIFARE Classic (the most common access card format), MIFARE Ultralight, and NTAG2xx tags (the sticker-style NFC tags used with phones). You can read a tag's unique UID for identification, read data blocks for more detailed information, and write data to blank tags. Common use cases include access control, event attendance tracking, interactive art installations, NFC-triggered actions, and building prop replicas with embedded tags.

The library supports the PN532 over both I2C and SPI. SPI gives slightly faster communication; I2C uses fewer pins.

Installing the library

Copy all of the following to CIRCUITPY/lib/:

  • adafruit_pn532/ (folder)
  • adafruit_bus_device/ (folder)

Quick start

import board
import busio
import adafruit_pn532.i2c

# I2C connection
i2c = busio.I2C(board.SCL, board.SDA)
pn532 = adafruit_pn532.i2c.PN532_I2C(i2c, debug=False)

# Configure the chip for reading passive NFC tags
pn532.SAM_configuration()
print("PN532 ready. Firmware version:", pn532.firmware_version)

print("Waiting for NFC tag...")
while True:
    uid = pn532.read_passive_target(timeout=0.5)
    if uid is not None:
        print("Tag found! UID:", [hex(i) for i in uid])

        # Read a block of data from a MIFARE Classic card
        # (requires authentication first)
        key_a = b"\xFF\xFF\xFF\xFF\xFF\xFF"  # default factory key
        authenticated = pn532.mifare_classic_authenticate_block(
            uid, block_number=4, key_number=0x60, key=key_a
        )
        if authenticated:
            data = pn532.mifare_classic_read_block(4)
            print("Block 4 data:", data)

        # Write to an NTAG2xx tag (no auth needed)
        # pn532.ntag2xx_write_block(4, b"Hello World!    ")

Key things you can do

What you want How to do it
Initialize over I2C PN532_I2C(i2c) then pn532.SAM_configuration()
Initialize over SPI PN532_SPI(spi, cs) then pn532.SAM_configuration()
Wait for and read a tag's UID uid = pn532.read_passive_target(timeout=0.5) — returns bytes or None
Check firmware version pn532.firmware_version
Authenticate a MIFARE Classic block pn532.mifare_classic_authenticate_block(uid, block, key_number, key)
Read a MIFARE Classic block pn532.mifare_classic_read_block(block_number)
Write a MIFARE Classic block pn532.mifare_classic_write_block(block_number, data) — 16 bytes
Read an NTAG2xx page pn532.ntag2xx_read_block(page)
Write an NTAG2xx page pn532.ntag2xx_write_block(page, data) — 4 bytes
Compare UIDs if uid == expected_uid:
Detect tag type from UID length 4-byte UID = MIFARE Classic, 7-byte = MIFARE Ultralight/NTAG

Reading the official docs

Full API reference: https://docs.circuitpython.org/projects/pn532/en/latest/

Projects using this library