# ST25R100
[](https://hex.pm/packages/st25r100)
[](https://hexdocs.pm/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`:
```elixir
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:
```elixir
# 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](LICENSE) for details.