Add hall sensor circuit design, NTAG5 config check tool, I2C bus docs

- 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>
This commit is contained in:
michael
2026-03-03 14:06:11 -08:00
parent e4195d2583
commit db492050e3
8 changed files with 874 additions and 50 deletions

View File

@@ -80,6 +80,12 @@ This gives us real pattern data to inform the EEPROM storage format later (M5),
**Important**: The MCU accesses NTAG5Link as a standard I2C slave at address 0x54 — plain register read/write. This is NOT the NFC-side ISO15693 custom commands used by the Python ntag5sensor tooling.
**I2C bus management**: LP5562 (0x30) and NTAG5Link (0x54) share the same I2C bus (A4/A5). Both addresses are used simultaneously — the MCU talks to each device by its address. Key considerations:
- Both are I2C slave devices with non-conflicting addresses
- LP5562 engines run autonomously after programming — no ongoing I2C traffic needed
- Pause LP5562 engines (set exec to Hold) before lengthy NTAG5 I2C transactions to avoid any bus contention edge cases
- NTAG5Link's use_case must be set to `i2c_slave` (not `i2c_master`) so it doesn't drive the bus
**Tasks**:
1. Write `src/ntag5/mod.rs``Ntag5Link<I2C>` struct, generic over `embedded_hal::i2c::I2c`
2. Write `src/ntag5/registers.rs` — register map constants from `ntag5link.py`
@@ -182,24 +188,37 @@ Typical 3-engine pattern: 16 + 3×34 + 4 = **122 bytes** (fits easily in 2048B E
| LP5562 quiescent | ~0.5mA | ~0.5mA |
| LP5562 LEDs (4ch @ 3mA) | ~12mA | ~12mA |
| NTAG5Link | ~100µA | ~1µA |
| Hall sensor (DRV5032) | ~1.6µA | ~1.6µA |
| EN pull-up (1M @ 3V) | ~0 | ~0 (3µA only when EN low) |
| **Total** | **~17mA** | **~12.5mA** |
Key insight: LED current dominates. MCU sleep saves ~4mA. Total must stay under EH max (~12.5mA), so LED current must be limited.
**Done when**: MCU sleeps after boot, LP5562 runs patterns, MCU wakes on NFC to accept new pattern.
### M8: Recovery Mode
### M8: Recovery Mode + Pattern Swap
**Goal**: Hall sensor provides safe mode entry for post-implant recovery.
**Goal**: Hall sensor provides pattern cycling (tap) and safe mode entry (hold + confirm).
**Circuit**: Wired-AND on LP5562 EN — hall sensor (open-drain) + MCU GPIO (open-drain) + pull-up resistor. Magnet presence forces EN low at hardware level, independent of MCU state. Hall output also connected to MCU EIC pin for interrupt/wake. See `docs/plans/2026-03-03-hall-en-design.md`.
**Interaction model**:
- **Boot-time recovery**: Hall asserted at power-on → EN held low (hardware), MCU skips EEPROM, loads default pattern, stays awake
- **Tap (<1s)**: LEDs off instantly (hardware EN drop) → magnet removed → MCU loads next pattern → LEDs back
- **Hold (>3s + confirm)**: LEDs off (hardware) → magnet removed → MCU blinks warning (3x red) → 2s window for confirmation tap → if confirmed, enters recovery mode. No second tap → resumes normal operation
- **MCU crashed + magnet**: Hall still kills EN (hardware safety)
**Tasks**:
1. Wire hall sensor to EIC-capable GPIO pin
2. Boot-time check: if hall sensor asserted → recovery mode
3. Recovery behavior: load hardcoded solid white (low brightness), skip EEPROM, stay awake
4. Set recovery flag in SRAM so phone app can detect it
5. Add hall sensor as runtime EIC wake source (e.g., cycle patterns)
1. Wire hall sensor: open-drain output to EN line (wired-AND) + separate wire to EIC pin
2. Add pull-up resistor (100k-1M) on EN line
3. Configure MCU GPIO (D0/A0) as open-drain for EN control
4. Implement EIC interrupt handler for hall sensor pin
5. Implement boot-time recovery: read hall GPIO at startup, if asserted → default pattern, skip EEPROM
6. Implement runtime state machine: tap detection, hold timing, warning blink, recovery confirmation
7. Recovery behavior: load hardcoded solid white (low brightness), skip EEPROM, stay awake
8. Set recovery flag in SRAM so phone app can detect it
**Done when**: Holding magnet near hall sensor at boot triggers recovery mode with default LED pattern.
**Done when**: Boot-time recovery works (magnet at power-on), tap cycles patterns at runtime, hold + confirm enters runtime recovery, hardware EN kill works even if MCU is unresponsive.
### M9: Power Characterization
@@ -272,7 +291,7 @@ Deferred until Groups A-D are solid.
| Risk | Severity | Mitigation |
|------|----------|------------|
| Power budget too tight for 4ch LED | High | Limit current to 2-3mA/ch, use pulsed patterns, run fewer channels |
| I2C bus contention (LP5562 + NTAG5) | Medium | Pause LP5562 engines before NTAG5 I2C access, resume after |
| I2C bus contention (LP5562 + NTAG5) | Medium | Non-conflicting addresses (0x30 vs 0x54). Pause LP5562 engines during NTAG5 I2C bursts. Verify NTAG5 is in i2c_slave mode (not i2c_master) |
| EEPROM write endurance (~100K cycles) | Low | SRAM for transient comms, EEPROM only for pattern persistence |
| Boot time too slow | Low | Estimated ~15-20ms appears instant to user |
| NFC coupling distance too short | Medium | Optimize antenna, low field strength EH mode, accept 1-3cm |

View File

@@ -131,6 +131,9 @@
| Firmware update strategy | Deferred | UF2 for dev, NFC OTA evaluated later |
| NTAG5Link I2C slave address | Assumed 0x54 | Verify in M4 with Click board |
| Pattern binary format | Deferred to M5 | Design after M2-M3 engine experience |
| Hall sensor + EN circuit | Designed | Wired-AND: hall + MCU open-drain on EN with 1M pull-up. See `docs/plans/2026-03-03-hall-en-design.md` |
| Hall sensor part selection | Decided | DRV5032FB (SOT-23, 8.4mT, prototype) → DRV5032FE (X2SON 1x1mm, final PCB) |
| EN pull-up value | Decided | 1M — zero steady-state draw, 3µA when EN low, ~10µs rise time |
## Hardware Inventory
@@ -140,6 +143,6 @@
| LP5562EVM | Available | TI eval module, RGBW LEDs, I2C addr 0x30 |
| Mini-USB cable | Not on hand | Needed to flash XIAO M0 |
| NTAG5 Link Click | Available, partially wired | Missing I2C jumper to XIAO |
| Hall effect sensor | Not available | Need to source |
| Hall effect sensor | Not available | Need to source — TI DRV5032FB (SOT-23) for prototype |
| ACR1552 PCSC reader | Available | For ntag5sensor Python tooling |
| Multimeter | Available | For power budget measurements |

View File

@@ -0,0 +1,159 @@
# Hall Sensor + LP5562 EN Wired-AND Circuit Design
**Date**: 2026-03-03
**Status**: Design in progress
## Problem
The implant needs a hall sensor for three functions:
1. **Pattern swap** — quick magnet tap cycles to the next stored pattern
2. **Runtime recovery** — long hold + confirmation tap enters safe mode
3. **Boot-time recovery** — magnet present at power-on skips EEPROM, loads default
4. **Hardware safety** — LEDs forced off by magnet even if MCU firmware has crashed
These must work within extreme space and power constraints (energy-harvested implant).
## Circuit: Wired-AND on LP5562 EN
Zero extra active components. Hall sensor and MCU share the EN line via open-drain outputs.
```
VCC (3.0V from NTAG5Link EH)
|
1M (pull-up resistor)
|
EN ------+------- MCU D0/A0 (open-drain)
|
+------- Hall sensor OUT (open-drain, active-low)
|
LP5562 EN pin
Hall sensor OUT ---- MCU EIC pin (separate connection for interrupt/wake)
```
### How it works
| State | MCU pin | Hall sensor | EN line | LP5562 |
|-------|---------|-------------|---------|--------|
| Normal operation | High-Z | High-Z (no magnet) | High (pull-up) | On |
| Magnet present | High-Z | Driving low | Low | Off |
| MCU disabling LP5562 | Driving low | High-Z | Low | Off |
| Magnet + MCU low | Driving low | Driving low | Low | Off |
### Pull-up resistor: 1M
- Steady-state current: ~0 (both open-drains high-Z, no path to ground)
- Current when EN low: 3V / 1M = 3 µA (only during magnet or MCU-driven low)
- Rise time: ~10 µs (1M x ~10pF parasitic) — instant from human perspective
- LP5562 EN input is high-impedance CMOS — no DC loading
## Hall Sensor: TI DRV5032
| Variant | Use | Iq | Threshold | Output | Package |
|---------|-----|-----|-----------|--------|---------|
| **DRV5032FB** | Prototype | 1.6 µA | 8.4 mT (omnipolar) | Open-drain | SOT-23 |
| **DRV5032FE** | Final PCB | 0.55 µA | 4.5 mT (omnipolar) | Open-drain | X2SON (1x1mm) |
- **Omnipolar**: Triggers on either magnetic pole (user doesn't need to orient magnet)
- **8.4 mT threshold (FB)**: Higher threshold = harder to accidentally trigger. Requires deliberate, close magnet interaction. Good for "don't accidentally enter recovery" requirement.
- **Open-drain, active-low**: Required for wired-AND topology
- **SOT-23 for prototyping**: Easy to hand-solder; X2SON for final implant PCB
## Interaction Model
### Pattern Swap (tap <1s)
1. Magnet near → hall pulls EN low → LEDs off instantly (hardware, zero MCU latency)
2. MCU wakes via EIC interrupt on hall sensor pin, starts timer
3. Magnet removed (hall goes high-Z, pull-up restores EN)
4. MCU detects short press (<1s) loads next stored pattern LEDs back on
### Runtime Recovery (hold >3s + confirm)
1. Magnet near EN low (hardware), MCU wakes via EIC
2. MCU counts hold duration while hall stays asserted
3. Magnet removed after >3s → MCU notes "long hold detected"
4. MCU re-enables LP5562 → blinks warning pattern (3x red flash)
5. MCU waits 2s for confirmation tap
6. Confirmation tap received → enters recovery mode
7. No confirmation → resumes normal operation (reloads previous pattern)
### Boot-time Recovery
1. NFC field arrives, VOUT powers system
2. Hall sensor already active (magnet was present before power) → EN held low by hardware
3. MCU boots, reads hall GPIO → asserted → boot-time recovery
4. Loads hardcoded default pattern (solid white, low brightness)
5. Skips EEPROM pattern data
6. Sets recovery flag in SRAM for phone app detection
7. When magnet removed, EN goes high, default pattern runs
### Hardware Safety (MCU crashed)
- Holding magnet forces EN low at circuit level regardless of MCU state
- No firmware dependency — pure hardware path
- Magnet removal restores EN via pull-up (LP5562 resumes last-programmed pattern)
## Firmware State Machine (M8)
```
┌─────────────┐
power-on -->│ BOOT_CHECK │
└──────┬──────┘
hall low? │
┌───yes─────┼────no───┐
v │ v
┌──────────┐ │ ┌─────────────┐
│ RECOVERY │ │ │ RUNNING │<──────────────┐
└──────────┘ │ └──────┬──────┘ │
│ hall EIC │ │
│ interrupt│ │
│ v │
│ ┌─────────────┐ │
│ │ HALL_ACTIVE │ │
│ └──────┬──────┘ │
│ hall released │
│ │ │ │
│ <1s >3s │
│ │ │ │
│ v v │
│ ┌──────┐ ┌──────────────┐ │
│ │ SWAP │ │ WARN_BLINK │ │
│ └──┬───┘ └──────┬───────┘ │
│ │ hall tap │ no tap │
│ │ in 2s? │ │
│ │ ┌──yes ┌──no │
│ │ v v │
│ │ ┌────────┐ │ │
│ │ │RECOVERY│ │ │
│ │ └────────┘ │ │
│ └──────────────┴──────────┘
```
States:
- **BOOT_CHECK**: Read hall GPIO. If asserted → RECOVERY. Else → RUNNING.
- **RUNNING**: LP5562 engines active, MCU in STANDBY sleep. Wakes on hall EIC.
- **HALL_ACTIVE**: Magnet detected. Timer running. Waiting for release.
- **SWAP**: Load next pattern, re-enable LP5562 → RUNNING.
- **WARN_BLINK**: Blink 3x red. Wait 2s for confirmation tap.
- **RECOVERY**: Default pattern, skip EEPROM, stay awake, set SRAM flag.
## Power Impact
| Component | Added draw | When |
|-----------|-----------|------|
| Hall sensor (DRV5032FB) | 1.6 µA | Always (quiescent) |
| Pull-up resistor (1M) | 3 µA | Only when EN is low (magnet or MCU-driven) |
| Pull-up resistor (1M) | ~0 | Steady state (EN high, no current path) |
Total added quiescent: **~1.6 µA** — negligible vs LP5562 LED current (~12 mA).
## Open Questions
| Question | Notes |
|----------|-------|
| Debounce needed? | Hall sensors are usually clean (no mechanical bounce), but verify with DRV5032 |
| EIC pin selection on SAMD21E | Must be EIC-capable for wake from STANDBY. Check SAMD21E pinout. |
| Magnet strength/distance | What N52 neodymium size triggers DRV5032FB at implant depth (~3-5mm subdermal)? |
| Multiple stored patterns | How many patterns to cycle through? Currently TBD (depends on EEPROM format, M5) |

View File

@@ -0,0 +1,90 @@
# NTAG5Link Config Verification via uFR Zero
**Date**: 2026-03-03
**Status**: Tool written, reader connection blocked
## Goal
Read-only verification that the NTAG5Link Click board's configuration matches xblink requirements, using the Digital Logic uFR Zero Multi-ISO reader.
## Tool
`tools/ntag5_config_check.py` — Python script using uFCoder library (ctypes) in ISO15693 transparent mode.
Features:
- ISO15693 INVENTORY to discover all tags by UID
- Addressed mode for all config reads (supports multiple tags in field)
- Reads CONFIG block (0x37) and EH/ED CONFIG block (0x3D)
- NXP system info for interface type verification
- Checks against xblink expected config values
## Expected Config
| Setting | Expected | Config Location |
|---------|----------|----------------|
| EH mode | low_field_strength | CONFIG byte 0, bits 3:2 = 10 |
| Use case | i2c_slave | CONFIG byte 1, bits 5:4 = 00 |
| SRAM enabled | true | CONFIG byte 1, bit 1 = 1 |
| Arbiter mode | sram_passthrough | CONFIG byte 1, bits 3:2 = 10 |
| EH enable | true | EH_CONFIG byte 0, bit 0 = 1 |
| EH voltage | 3.0V | EH_CONFIG byte 0, bits 2:1 = 10 |
## Reader Connection Issue
**Problem**: uFCoder library returns `UFR_TIMEOUT_ERR` (0x1002) for all `ReaderOpenEx` parameter combinations.
**USB device**: `10c4:ea60` — Silicon Labs CP2102 USB to UART Bridge Controller, iSerial "0001". Generic descriptor, no D-Logic branding in USB strings.
**Raw serial investigation**:
- At 1 Mbps (expected uFR baud): responds with `00 80` (2 bytes) — not a valid uFR protocol frame (expected 6+ bytes with `0x55...0xAA` framing)
- At 115200 bps: returns ASCII shell commands mentioning "systemctl", "proxmark3" paths
- At 250 Kbps: returns structured but unrecognized data
**Possible causes**:
1. Device may not be a uFR Zero — the CP210x bridge has generic descriptors
2. Reader firmware may need updating
3. Reader may be in a non-standard mode
4. Different hardware variant requiring different protocol
**Next steps**:
1. Physically verify the device is indeed the uFR Zero (check labels, LEDs)
2. Try the D-Logic `ufr_online` Windows utility to confirm reader identity
3. If confirmed as uFR Zero, check firmware version and update if needed
4. Alternative: use the ACR1552 PCSC reader with ntag5sensor directly (requires porting the reader to share the field with NTAG5 Click)
## Fallback Plan: ntag5sensor + ACR1552
If the uFR Zero connection cannot be resolved, use the existing ntag5sensor Python tooling with the ACR1552 PCSC reader:
```python
# From ntag5sensor — already has full config read/write support
chip = NTAG5Link(reader)
config = chip.get_config_info()
eh_config = chip.get_eh_ed_config_info()
```
The ACR1552 is already proven with ntag5sensor. Only change needed: physically position the ACR1552 over the NTAG5 Click board instead of the uFR Zero.
## Config Change Plan (if mismatches found)
Use ntag5sensor's write functions (via ACR1552 or adapted for uFR Zero):
```python
# Set I2C slave mode + SRAM passthrough + SRAM enable
chip.write_config1(
sram_enable=True,
arbiter_mode=NXP_CONFIG_1_ARBITER_MODE_SRAM_PASSTHROUGH,
use_case=NXP_CONFIG_1_USE_CASE_CONF_I2C_SLAVE
)
# Set EH: 3.0V, enabled, current limit TBD
chip.write_eh_ed_config(
enable=True,
voltage=NXP_EH_CONFIG_EH_VOUT_V_SEL_3_0,
current=NXP_EH_CONFIG_EH_VOUT_I_SEL_12_5, # max for testing
ed_config=NXP_ED_CONFIG_NFC_FIELD_DETECT
)
# Set EH mode in CONFIG byte 0
chip.write_config0(eh_mode=NXP_CONFIG_0_EH_MODE_LOW_FIELD_STRENGTH)
```