ST25R100
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 Pin | ST25R100 Pin |
|---|---|
| GPIO10 | MOSI |
| GPIO9 | MISO |
| GPIO11 | SCLK |
| 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.