ST25R100

Hex.pmDocs

An Elixir driver for the ST25R100 NFC reader chip.

This library supports a single, on-demand read of ISO14443A/NFC-A tags (both 4-byte single-size and 7-byte double-size UIDs) using a simple, pure functional API. The driver state is maintained in a simple struct passed directly into functions.

It can also read the full memory contents of Type 2 Tags (NTAG213/215/216, Mifare Ultralight, and similar). Other tag types (e.g. Type 4 / ISO-DEP tags) are not yet supported - support may be added in the future. Feel free to open an issue if you need these features.

Installation

The package can be installed by adding st25r100 to your list of dependencies in mix.exs:

def deps do
[
{:st25r100, "~> 0.1.0"},
]
end

Hardware Connections

The ST25R100 communicates over a 4-wire SPI interface. Connect it to a Raspberry Pi's primary SPI bus (spidev0.0 or spidev0.1) as follows, plus one free GPIO for the chip's reset line:

Raspberry Pi PinST25R100 Pin
GPIO10MOSI
GPIO9MISO
GPIO11SCLK
GPIO8 (CE0) / GPIO7 (CE1)BSS
Any free GPIO (e.g. GPIO25)RESET

Important

The SPI mode must be mode: 1 (CPOL = 0, CPHA = 1). Any other mode will prevent the driver from communicating with the chip.

Quick Start Example

You can initialize and configure the ST25R100 chip by creating and configuring a %ST25R100{} struct. This example detects a tag, resolves its UID, and (since read_uid/1 only succeeds for Type 2 Tags) reads its full memory contents:

# Open the SPI bus (assuming "spidev0.0" on Nerves target)
{:ok, spi} = Circuits.SPI.open("spidev0.0", mode: 1, speed_hz: 1_000_000)
# Instantiate the driver state with an optional reset GPIO pin
driver = ST25R100.new(spi, reset_pin: "GPIO25")
# Initialize the chip clocks and registers
{:ok, driver} = ST25R100.init(driver)
# Turn the RF field ON
{:ok, driver} = ST25R100.set_field(driver, true)
# Poll for an NFC-A tag's presence
case ST25R100.detect_tag(driver) do
{:ok, atqa} ->
IO.puts("Tag detected! ATQA: #{inspect(atqa, base: :hex)}")
# Resolve the tag UID - only succeeds for Type 2 Tags (NTAG21x, Mifare Ultralight, etc)
case ST25R100.read_uid(driver) do
{:ok, uid} ->
IO.puts("Tag UID: #{inspect(uid, base: :hex)}")
# Read the tag's full memory contents
case ST25R100.read_data(driver) do
{:ok, data} ->
IO.puts("Read #{byte_size(data)} bytes: #{inspect(data, base: :hex)}")
{:error, reason} ->
IO.puts("Failed to read tag data: #{inspect(reason)}")
end
{:error, :unsupported_tag} ->
IO.puts("Tag detected, but it isn't a Type 2 Tag - not currently supported.")
{:error, reason} ->
IO.puts("Failed to resolve tag UID: #{inspect(reason)}")
end
{:error, :timeout} ->
IO.puts("No tag present in the RF field.")
{:error, reason} ->
IO.puts("Failed to detect tag: #{inspect(reason)}")
end
# Turn the RF field OFF when done
{:ok, driver} = ST25R100.set_field(driver, false)
# Cleanly release opened GPIO resources on exit
ST25R100.close(driver)

Hardware Enable and Reset Control

The ST25R100 chip has a dedicated hardware Enable/Reset pin controlling chip power-down. If a reset pin is provided to new/2 (highly recommended), the driver automatically opens and toggles it via Circuits.GPIO.

License

ST25R100 is released under the MIT License. See LICENSE for details.