- Hall sensor + LP5562 EN wired-AND circuit design (DRV5032FB/FE, 1M pull-up, open-drain topology) with three interaction modes: boot-time recovery, tap-to-swap, hold-to-confirm recovery - NTAG5 config check tool (tools/ntag5_config_check.py) using uFCoder library for ISO15693 transparent mode via uFR Zero reader. Supports inventory + addressed mode for multi-tag fields. - Updated DEVELOPMENT_PLAN with I2C bus management notes for LP5562 (0x30) + NTAG5Link (0x54) shared bus - Updated README with wired-AND hardware diagram, hall sensor interaction section, and updated wiring table - Updated CLAUDE.md with LP5562 EN wired-AND topology docs - Updated STATUS.md with hall sensor decisions and hardware inventory Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.3 KiB
xblink Development Guide
Embedded Rust firmware for a battery-free, NFC-powered LED implant. The NTAG5Link harvests energy from an NFC field and provides EEPROM storage for LED patterns. A SAMD21E MCU reads patterns from EEPROM, programs LP5562 execution engines, then sleeps while the LP5562 autonomously drives RGBW LEDs.
Build Commands
# Build release firmware
cargo build --release
# Flash via UF2 bootloader (XIAO M0: double-tap RST to enter bootloader)
cargo hf2 --release
# Auto-flash: watches for bootloader USB device, flashes when detected
./flash_when_ready.sh
Target
- Architecture:
thumbv6m-none-eabi(ARM Cortex-M0+) - Dev board: Seeed XIAO M0 (SAMD21G18A) — will port to bare SAMD21E18A later
- LED driver: LP5562EVM (TI evaluation module, RGBW, I2C addr 0x30)
- NFC: NTAG5Link Click board (MikroElektronika)
Dependencies
| Crate | Version | Purpose |
|---|---|---|
xiao_m0 |
0.13 | Board support package (dev board phase) |
panic-halt |
0.2 | Minimal panic handler for no_std |
cortex-m |
0.7 | Cortex-M runtime, critical-section-single-core feature |
embedded-hal |
1.0.0 | Hardware abstraction traits (I2C, GPIO, delay) |
When porting to bare SAMD21E: replace xiao_m0 with atsamd-hal = { version = "0.17", features = ["samd21e"] } and add cortex-m-rt = "0.7".
Project Structure
src/
main.rs # Entry point: boot, pattern load, sleep/wake loop
led/
mod.rs # LP5562 re-exports (LedController trait added later, M10)
lp5562.rs # LP5562 driver (from ../ntag5-samd21-lp562/)
ntag5/ # NTAG5Link I2C slave driver (M4+)
pattern/ # Pattern format and engine builder (M5+)
Architecture Conventions
no_stdonly: No heap allocation. Fixed-size arrays and stack-only data structures.embedded-halgenerics: All hardware drivers must be generic overembedded_hal::i2c::I2c(1.0 traits). Never use concrete HAL types in driver code.- Hardware-first: Get hardware working before extracting abstractions. Traits and formats are designed after hands-on experience, not before.
- Error types: Use
Error<E>enum wrapping underlying I2C error withFrom<E>impl (see LP5562 driver pattern). - Register addresses: Place in a
regsubmodule aspub constvalues. const fn: Preferconst fnwhere possible (seeEngineCommandbuilder in LP5562 driver).- No
unsafe: Avoid unless absolutely necessary for hardware access.
LP5562 Timing Constraints
The LP5562 driver does NOT enforce timing delays internally — the caller is responsible:
- >= 500 us after
enable()before any other commands - >= 488 us between consecutive ENABLE register writes (engine exec changes)
- >= 153 us between consecutive OP_MODE register writes (engine mode changes)
- When transitioning from Run, set exec to Hold first, then change mode
Key I2C Addresses
Both devices share the same I2C bus (A4/A5). Non-conflicting addresses — no bus arbitration issues.
| Device | Address | Notes |
|---|---|---|
| LP5562 | 0x30 | ADDR_SEL pins both low (LP5562EVM default) |
| NTAG5Link | 0x54 | Default NTP53x2 I2C slave address |
NTAG5Link I2C Register Map (MCU-side)
The MCU accesses NTAG5Link as a standard I2C slave — plain register read/write, NOT the NFC-side ISO15693 custom commands used by the Python ntag5sensor tooling.
| Region | Address Range | Size | Notes |
|---|---|---|---|
| Session registers | 0x00-0x06 | 7 bytes | Volatile, runtime config |
| Configuration | 0x37-0x3F | Varies | Persistent, EEPROM-backed |
| EH config | 0x3D | 1 byte | Energy harvesting voltage/current |
| SRAM | 0xF8-0xFF | 256 bytes | 64 x 4-byte blocks, volatile |
| EEPROM user memory | blocks 0x00-0x1FF | 2048 bytes | 512 x 4-byte blocks |
Key config constants (from ../ntag5sensor/vicinity/ntag5link.py):
CONFIG_1_USE_CASE_CONF_I2C_SLAVE = 0 << 4— NTAG5 as I2C slave (our mode)CONFIG_1_ARBITER_MODE_SRAM_PASSTHROUGH = 2 << 2— SRAM pass-through for NFC↔I2CCONFIG_1_SRAM_ENABLE = 1 << 1— Enable SRAM accessCONFIG_0_EH_MODE_LOW_FIELD_STRENGTH = 2 << 2— EH mode for phone NFC
Hardware Wiring (Dev Board)
| XIAO Pin | Connection | Function |
|---|---|---|
| A4 (SDA) | LP5562 SDA, NTAG5 SDA | Shared I2C data |
| A5 (SCL) | LP5562 SCL, NTAG5 SCL | Shared I2C clock |
| D0/A0 | LP5562 EN line (open-drain) | Wired-AND with hall sensor, pull-up to VCC |
| TBD (EIC) | Hall sensor output | EIC wake + wired-AND to LP5562 EN line |
| TBD (EIC) | NTAG5 FD pin | Field detect / SRAM write indication (EIC wake) |
LP5562 EN wired-AND: D0/A0 (open-drain) and hall sensor (open-drain, active-low) both connect to LP5562 EN with a 1M pull-up. Either can force EN low. Magnet kills LEDs at hardware level regardless of MCU state.
Testing
- Hardware: XIAO M0 + LP5562EVM + NTAG5Link Click (when jumpers available)
- PCSC reader: Use
../ntag5sensor/Python tooling with ACR1552 reader - Phone NFC: VivoKey RawNFC app for SRAM mailbox testing
- Phone app: DT NFC Identifier for basic tag info
Sibling Projects
../ntag5-samd21-lp562/— Original LP5562 driver + smoke test (xblink'ssrc/led/lp5562.rsis synced from here)../ntag5sensor/— NTAG5Link command reference (vicinity/ntag5link.py), I2C patterns (vicinity/i2cbase.py)