Skip to the content
PCBKitNew board
2 layers52.7 × 39.6 mmNFC harness V0, the printed circuit board in 3D

NFC exploration with st25 and raspberry pico

Size
52.7 × 39.6 mm
Copper layers
2
Thickness
1.6 mm
Parts
22
Nets
41
Pads
145
Tracks, vias
108, 0
Pours
1
Routed
Yes
KiCad
KiCad 9.0 (file 20241229)
Created
5 Apr 2026
Updated
25 Apr 2026

Overview

NFC harness V0 is an open-source printed circuit board by c0de111, from the c0de111/NFC_exploration repository on GitHub. It is a 2-layer board of 52.7 × 39.6 mm with 22 parts on 41 nets, routed with 108 tracks and 0 vias.

It is built around the ST25DV04KC-IE6S3, JZ400 and MMBT3904, with the TSM260P02CX6 among its other parts. Its parts include 7 resistors, 6 capacitors, 4 connectors, 2 transistors and 1 IC. It belongs with the radio and wireless boards and the RP2040 boards of this library.

Main components

4

README

README.md

NFC exploration

Sandbox repo to explore ST25DV04KC (ISO15693 / NFC-V) tap-to-trigger flows for power control and waking circuits such as inki.

Goal

Build a small, reproducible test platform (ST25DV04KC + Raspberry Pi Pico/RP2040 + antenna + simple enclosure) to validate:

  • RF-field / V_EH wake behavior in the real case
  • Phone → tag writes (EEPROM / Type 5)
  • MCU reads request over I²C and clears/acks
  • End-to-end timing assumptions for a future “tap-to-book” workflow

Current validated behavior

  • ST25DV04KC bring-up over I2C is stable on Pico (GP20/GP21), with ST25 power switched by GP18.
  • End-to-end NFC-V write from phone to tag user memory is working.
  • Firmware parses 16-byte INKI request payloads from the last user-memory slot (0x01F0 on ST25DV04KC).
  • Firmware command opcode handling is active:
    • 0x11 -> LED1 slow blink
    • 0x12 -> LED1 fast blink (same onboard LED)
    • 0x01 -> legacy alias mapped to LED1 slow blink
  • Incomplete/invalid INKI frames are ignored (to avoid partial-write races).
  • Valid requests are cleared only after RF field goes OFF (reduces interference with phone-side readback).
  • Power latch is asserted early by Pico on boot (GP28) and auto-released after NFC_AUTO_POWER_OFF_MS (default 10000 ms).
  • Runtime logging is event-driven: startup diagnostics once, then RF field edges and request actions only.

Tuning firmware (antenna / power characterization)

A dedicated firmware (nfc_tune, source: firmware/src/tune_main.c) for real-time RF energy-harvesting characterization. It samples the ST25DV V_EH output via Pico ADC and renders a live scrolling bar graph in the terminal showing harvested power delta above baseline.

What it measures

  • ADC voltage on V_EH pin (default ADC1 = GP27), averaged and EMA-smoothed
  • Delta above a startup baseline capture (no-RF reference)
  • RF field state derived from voltage thresholds (configurable ON/OFF hysteresis)
  • ST25 EH control register state (EH_EN, EH_ON, FIELD_ON, VCC_ON) via I2C

Build and flash

bash
make firmware-tune                    # build nfc_tune
# then either:
make firmware-tune-flash              # flash via SWD
# or drag-and-drop firmware/build/nfc_tune.uf2 in BOOTSEL mode

Tuning workflow

  1. Connect Pico via USB (serial + power).
  2. Open terminal: sudo tio /dev/ttyACM0
  3. Wait for baseline capture (keep RF away for ~2 seconds at boot).
  4. Tap phone to antenna — the live graph shows V_EH delta in mV, RF ON/OFF transitions, session peak, and EH register state.
  5. Adjust antenna matching (C2/C3 on NFC_harness_V0) and re-tap to compare coupling.
  6. Ctrl+C to stop.

Key CMake tuning parameters

All defaults are in firmware/CMakeLists.txt:

  • NFC_TUNE_ADC_INPUT – ADC channel (default 1 = GP27)
  • NFC_TUNE_FIELD_ON_MV / NFC_TUNE_FIELD_OFF_MV – RF detection hysteresis thresholds (default 9 / 4 mV)
  • NFC_TUNE_GRAPH_WIDTH / NFC_TUNE_GRAPH_HEIGHT – terminal graph dimensions (default 72x20)
  • NFC_TUNE_GRAPH_MAX_MV – vertical scale (default 3000 mV)
  • NFC_TUNE_SAMPLE_COUNT / NFC_TUNE_REPORT_INTERVAL_MS – samples per report and update rate

Current Wake/Latch Circuitry (PCB: NFC_harness_V0)

  • Q1 (TSM260P02CX, P-MOS) is the high-side power switch:
    • source -> Vbatt
    • drain -> Pico VSYS
  • ST25 GPO_(OPEN_DRAIN) and the Q1 gate share the same control net (wake/power-on net).
  • Gate network shaping:
    • R4=1M pull-up to Vbatt
    • C5=22n to GND (pulse shaping / hold)
  • Pico latch-hold path:
    • Pico GPIO28 (NFC_POWER_HOLD_PIN) -> R5=100k -> Q2 base
    • R9=50k pulls base to GND
    • Q2 collector also sinks the same gate-control net
  • On this PCB revision, Pico GPIO19 is unconnected.
  • LED wiring status on this PCB revision:
    • Both blink commands (0x11 slow, 0x12 fast) use the firmware power-LED output (onboard Pico/Pico W path).
    • NFC_STATUS_LED_PIN (default GP15) is currently not routed to a dedicated onboard LED footprint here (external LED/wire may be needed).

Command Flow (Phone -> ST25 -> Pico)

  1. Board is fully off (Vbatt connected, no USB, Pico unpowered).
  2. Phone tap powers ST25 RF side and writes the 16-byte INKI payload (including opcode byte) over NFC-V into ST25 EEPROM, while Pico can still be fully off.
  3. ST25 asserts GPO low on configured wake event (RF_WRITE), pulling Q1 gate low and powering Pico.
  4. Pico boots and immediately asserts GPIO28 high to latch power through Q2.
  5. Data transfer from ST25 to Pico happens after boot over I2C (not on GPO):
    • Pico powers ST25 VCC via GP18
    • firmware reads request bytes from the last ST25 user-memory slot
  6. Firmware validates the payload, applies opcode behavior, queues clear for RF-OFF, and later clears the slot.
  7. Firmware releases the latch after timeout (NFC_AUTO_POWER_OFF_MS, default 10000 ms; re-armed on accepted commands).

Note:

  • Runtime-loop request processing still runs while RF field is ON, with clear deferred to RF field OFF.
  • Additionally, at boot firmware now checks for a stored valid request. If RF field is already OFF, it applies the command immediately and clears it at boot.
  • If no valid INKI request is found after wake and RF is already OFF, firmware releases the power latch immediately.

Repository layout

  • docs/context.md – running notes, decisions, history, and solved problems
  • firmware/ – Pico SDK firmware scaffold (RP2040) for ST25 I²C exploration
    • src/ app entry (main.c harness, tune_main.c tuning) and bus adapter
    • third_party/st25dv/ vendored ST25DV driver (git subtree)
    • scripts/ build/flash/reset helpers
    • cmake/ Pico SDK import helper
  • pcb/NFC_harness_V0/ – KiCad project (schematic, layout, CAM profile)
  • pcb/tools/run_pcb2gcode.sh – shared pcb2gcode runner
  • pcb/components/ + pcb/project-libraries/ – KiCad symbols/footprints (includes ST25DV package lib submodule)
  • datasheet/ – ST25DV04KC datasheet + app notes
  • android/ – NFC‑V test apps (writer + hello) (not needed for Pico-only workflow)

Typical workflow (from repo root)

  1. Build firmware: make firmware (uses PICO_SDK_PATH, default $HOME/pico/pico-sdk).
  2. Flash:
    • Drag‑and‑drop: copy firmware/build/nfc_harness.uf2 to Pico in BOOTSEL mode, or
    • SWD: make firmware-flash (OpenOCD + CMSIS-DAP).
  3. Iterate: edit firmware/src/main.c (and future helpers), rebuild, and re‑flash.
  4. CAM / milling (optional): pcb/tools/run_pcb2gcode.sh -b NFC_harness_V0 to regenerate toolpaths.

Build & flash (Pico / RP2040)

Build

bash
# from repo root (recommended)
make firmware

# or inside firmware/
cd firmware
./scripts/build.sh   # expects $PICO_SDK_PATH (defaults to $HOME/pico/pico-sdk)

More detail (pin overrides, UF2 path, picotool toggles): see firmware/README.md.

Notes:

  • Picotool is disabled by default to avoid downloads. The build script auto-fetches uf2conv.py (Microsoft UF2 tool) on first run and converts nfc_harness.bin → nfc_harness.uf2.
  • Set -DPICO_NO_PICOTOOL=OFF in cmake if you prefer the picotool UF2/signing path.

Clean build artifacts:

bash
make clean   # removes firmware/build only

Flash options:

  • USB drag‑and‑drop: copy firmware/build/nfc_harness.uf2 to the Pico mass‑storage device (BOOTSEL).
  • SWD (OpenOCD + CMSIS‑DAP probe):
    bash
    cd firmware
    ./scripts/flash.sh

Root make targets (quick reference)

  • make firmware – configure & build firmware into firmware/build/
  • make firmware-tune – build dedicated antenna tuning firmware (nfc_tune)
  • make firmware-flash – flash over SWD (OpenOCD + CMSIS‑DAP)
  • make firmware-tune-flash – flash tuning firmware ELF over SWD
  • make clean – remove firmware/build/ only

CAM workflow (pcb2gcode)

From repo root:

bash
pcb/tools/run_pcb2gcode.sh -b NFC_harness_V0

The profile lives at pcb/NFC_harness_V0/cam/pcb2gcode/profiles/default.millprojects and uses repo-relative paths.

Quick RF test (phone + Pico)

  1. Connect a loop antenna to J3 (AC0/AC1) on the PCB.
  2. Build and flash firmware:
    • make firmware
    • copy firmware/build/nfc_harness.uf2 to Pico in BOOTSEL mode (or use SWD).
  3. Open serial logs:
    • sudo tio /dev/ttyACM0
  4. On phone, open the NFC-V app (inki):
    • pick command button: LED1 Slow or LED2 Fast
  5. Tap phone to antenna and hold briefly.

Expected runtime log pattern:

  • RF field: ON
  • Request@0x01F0: ...
  • INKI request: version=... opcode=... duration_min=...
  • Command applied: opcode=... -> ...
  • Queued clear after RF field OFF
  • RF field: OFF
  • Cleared request after RF OFF (...)
  • Auto power-off: GP28 -> LOW

Sample serial log (successful run):

text
[INFO] RF field: OFF
[INFO] RF field: ON
[INFO] Request@0x01F0: 49 4E 4B 49 01 11 3C 00 ...
[OK] INKI request: version=1 opcode=0x11 duration_min=60 unix=... nonce=...
[OK] Command applied: opcode=0x11 -> LED1 slow blink
[INFO] Queued clear after RF field OFF
[INFO] RF field: OFF
[OK] Cleared request after RF OFF (16 bytes @ 0x01F0, attempts=1, 8ms)
[WARN] Auto power-off: GP28 -> LOW

Parts

22
QtyValueFootprintReferences
20Fuse:Fuse_1206_3216Metric_Pad1.42x1.75mm_HandSolderR3, R6
2100nCapacitor_SMD:C_0805_2012MetricC1, C13
24k7Fuse:Fuse_1206_3216Metric_Pad1.42x1.75mm_HandSolderR1, R2
1100kFuse:Fuse_1206_3216Metric_Pad1.42x1.75mm_HandSolderR5
110pCapacitor_SMD:C_0805_2012MetricC2
11MResistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolderR4
122nCapacitor_SMD:C_0805_2012MetricC5
14.7uCapacitor_SMD:C_1206_3216MetricC4
150kFuse:Fuse_1206_3216Metric_Pad1.42x1.75mm_HandSolderR9
1JZ400JZ400:JZ400C3
1MMBT3904Package_TO_SOT_SMD:SOT-23Q2
1RaspberryPi_Pico_WModule_RaspberryPi_Pico:RaspberryPi_Pico_W_SMDA1
1ST25DV04KC-IE6S3ST25DV04KC-IE6S3:SOIC127P600X175-8NIC1
1SW_PushTaster:Taster 9313SW1
1TSM260P02CXPackage_TO_SOT_SMD:SOT-23_HandsolderingQ1
1always onConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJ4
1antennaConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJ3
1batteryConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJ2
1energy harvestConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJ1

Questions

How big is the NFC harness V0 PCB?

It measures 52.7 × 39.6 mm and has 2 copper layers, 1.6 mm thick.

What parts does the NFC harness V0 use?

22 parts, built around the ST25DV04KC-IE6S3, JZ400, MMBT3904 and TSM260P02CX6. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the NFC harness V0 KiCad files?

From the c0de111/NFC_exploration repository on GitHub, at the commit this page was made from: the board is pcb/NFC_harness_V0/NFC_harness_V0.kicad_pcb and its schematic pcb/NFC_harness_V0/NFC_harness_V0.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the NFC harness V0 design in my own project?

Its repository states no licence, so its author keeps all rights: ask c0de111 before reusing the design.

Similar boards

  • 2 layers47.2 × 55.5 mmInki, the printed circuit board in 3D

    Inki

    c0de111/tinta

    Battery-powered e-paper sign: room signage, sensor graphs, home automation, or anything over Wi-Fi. Wakes by real-time clock, NFC tap, or button. Raspberry Pi Pico W firmware, custom PCB, and 3D-printed case included.

    54 parts39Apache-2.0
  • 2 layers180 × 38 mmIrrgiation sensor, the printed circuit board in 3D

    Irrgiation sensor

    henriheimann/prosper3-monitor

    Repository of the Prosper III Environment Monitor project ☀️🌱

    39 parts
  • 2 layers44.7 × 93.6 mmUltisense, the printed circuit board in 3D

    Ultisense

    darshg321/Ultisense

    an esp32-s3 devboard made to sense as many things as possible

    94 parts3
  • 2 layers35 × 62 mmTag, the printed circuit board in 3D

    Tag

    dgm91-pro/Attiny85_NFC_MULTI_TAG

    A small Project in bond with hackclub YSWS

    18 parts
  • 2 layers93 × 52 mmJT Business Card, the printed circuit board in 3D

    JT Business Card

    MontgomeryResearchLabs/C.A.R.D.

    Connection And Resuable Device

    527 partsMIT
  • 2 layers63.4 × 83.1 mmWO30109 FreshAir, the printed circuit board in 3D

    WO30109 FreshAir

    WOOWTECH/Woow_zigbee_fresh_air_pcb

    WO_30109 Zigbee 新風控制器 PCB(KiCad 10,git 版控;V1.3 重繪 + V2.0 安規改版)

    76 parts
  • 4 layers95 × 55.5 mmEinkPDA keyboard, the printed circuit board in 3D

    EinkPDA keyboard

    TalismanDesign/PocketMage_PDA

    An E-Ink PDA device using the ESP32 S3.

    137 parts2kApache-2.0