Sandbox repo to explore ST25DV04KC (ISO15693 / NFC-V) tap-to-trigger flows for power control and waking circuits such as inki.
Build a small, reproducible test platform (ST25DV04KC + Raspberry Pi Pico/RP2040 + antenna + simple enclosure) to validate:
- RF-field /
V_EHwake 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
- ST25DV04KC bring-up over I2C is stable on Pico (
GP20/GP21), with ST25 power switched byGP18. - End-to-end NFC-V write from phone to tag user memory is working.
- Firmware parses 16-byte
INKIrequest payloads from the last user-memory slot (0x01F0on ST25DV04KC). - Firmware command opcode handling is active:
0x11->LED1slow blink0x12->LED1fast blink (same onboard LED)0x01-> legacy alias mapped toLED1slow blink
- Incomplete/invalid
INKIframes are ignored (to avoid partial-write races). - Valid requests are cleared only after
RF fieldgoesOFF(reduces interference with phone-side readback). - Power latch is asserted early by Pico on boot (
GP28) and auto-released afterNFC_AUTO_POWER_OFF_MS(default10000ms). - Runtime logging is event-driven: startup diagnostics once, then RF field edges and request actions only.
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.
- ADC voltage on
V_EHpin (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
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- Connect Pico via USB (serial + power).
- Open terminal:
sudo tio /dev/ttyACM0 - Wait for baseline capture (keep RF away for ~2 seconds at boot).
- Tap phone to antenna — the live graph shows
V_EHdelta in mV, RF ON/OFF transitions, session peak, and EH register state. - Adjust antenna matching (C2/C3 on
NFC_harness_V0) and re-tap to compare coupling. Ctrl+Cto stop.
All defaults are in firmware/CMakeLists.txt:
NFC_TUNE_ADC_INPUT– ADC channel (default1=GP27)NFC_TUNE_FIELD_ON_MV/NFC_TUNE_FIELD_OFF_MV– RF detection hysteresis thresholds (default9/4mV)NFC_TUNE_GRAPH_WIDTH/NFC_TUNE_GRAPH_HEIGHT– terminal graph dimensions (default72x20)NFC_TUNE_GRAPH_MAX_MV– vertical scale (default3000mV)NFC_TUNE_SAMPLE_COUNT/NFC_TUNE_REPORT_INTERVAL_MS– samples per report and update rate
Q1(TSM260P02CX, P-MOS) is the high-side power switch:- source ->
Vbatt - drain -> Pico
VSYS
- source ->
- ST25
GPO_(OPEN_DRAIN)and theQ1gate share the same control net (wake/power-on net). - Gate network shaping:
R4=1Mpull-up toVbattC5=22nto GND (pulse shaping / hold)
- Pico latch-hold path:
- Pico
GPIO28(NFC_POWER_HOLD_PIN) ->R5=100k->Q2base R9=50kpulls base to GNDQ2collector also sinks the same gate-control net
- Pico
- On this PCB revision, Pico
GPIO19is unconnected. - LED wiring status on this PCB revision:
- Both blink commands (
0x11slow,0x12fast) use the firmware power-LED output (onboard Pico/Pico W path). NFC_STATUS_LED_PIN(defaultGP15) is currently not routed to a dedicated onboard LED footprint here (external LED/wire may be needed).
- Both blink commands (
- Board is fully off (
Vbattconnected, no USB, Pico unpowered). - Phone tap powers ST25 RF side and writes the 16-byte
INKIpayload (including opcode byte) over NFC-V into ST25 EEPROM, while Pico can still be fully off. - ST25 asserts
GPOlow on configured wake event (RF_WRITE), pullingQ1gate low and powering Pico. - Pico boots and immediately asserts
GPIO28high to latch power throughQ2. - 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
- Pico powers ST25 VCC via
- Firmware validates the payload, applies opcode behavior, queues clear for RF-OFF, and later clears the slot.
- Firmware releases the latch after timeout (
NFC_AUTO_POWER_OFF_MS, default10000ms; 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
INKIrequest is found after wake and RF is already OFF, firmware releases the power latch immediately.
docs/context.md– running notes, decisions, history, and solved problemsfirmware/– Pico SDK firmware scaffold (RP2040) for ST25 I²C explorationsrc/app entry (main.charness,tune_main.ctuning) and bus adapterthird_party/st25dv/vendored ST25DV driver (git subtree)scripts/build/flash/reset helperscmake/Pico SDK import helper
pcb/NFC_harness_V0/– KiCad project (schematic, layout, CAM profile)pcb/tools/run_pcb2gcode.sh– shared pcb2gcode runnerpcb/components/+pcb/project-libraries/– KiCad symbols/footprints (includes ST25DV package lib submodule)datasheet/– ST25DV04KC datasheet + app notesandroid/– NFC‑V test apps (writer + hello) (not needed for Pico-only workflow)
- Build firmware:
make firmware(usesPICO_SDK_PATH, default$HOME/pico/pico-sdk). - Flash:
- Drag‑and‑drop: copy
firmware/build/nfc_harness.uf2to Pico in BOOTSEL mode, or - SWD:
make firmware-flash(OpenOCD + CMSIS-DAP).
- Drag‑and‑drop: copy
- Iterate: edit
firmware/src/main.c(and future helpers), rebuild, and re‑flash. - CAM / milling (optional):
pcb/tools/run_pcb2gcode.sh -b NFC_harness_V0to regenerate toolpaths.
# 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 convertsnfc_harness.bin→nfc_harness.uf2. - Set
-DPICO_NO_PICOTOOL=OFFincmakeif you prefer the picotool UF2/signing path.
Clean build artifacts:
make clean # removes firmware/build onlyFlash options:
- USB drag‑and‑drop: copy
firmware/build/nfc_harness.uf2to the Pico mass‑storage device (BOOTSEL). - SWD (OpenOCD + CMSIS‑DAP probe):
cd firmware ./scripts/flash.sh
make firmware– configure & build firmware intofirmware/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 SWDmake clean– removefirmware/build/only
From repo root:
pcb/tools/run_pcb2gcode.sh -b NFC_harness_V0The profile lives at pcb/NFC_harness_V0/cam/pcb2gcode/profiles/default.millprojects and uses repo-relative paths.
- Connect a loop antenna to
J3(AC0/AC1) on the PCB. - Build and flash firmware:
make firmware- copy
firmware/build/nfc_harness.uf2to Pico in BOOTSEL mode (or use SWD).
- Open serial logs:
sudo tio /dev/ttyACM0
- On phone, open the NFC-V app (
inki):- pick command button:
LED1 SloworLED2 Fast
- pick command button:
- Tap phone to antenna and hold briefly.
Expected runtime log pattern:
RF field: ONRequest@0x01F0: ...INKI request: version=... opcode=... duration_min=...Command applied: opcode=... -> ...Queued clear after RF field OFFRF field: OFFCleared request after RF OFF (...)Auto power-off: GP28 -> LOW
Sample serial log (successful run):
[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