# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project status Greenfield. The repository currently contains only `README.md` and `MIPI_FLICKER_SPEC.md` — no Python source, no `requirements.txt`, no tests. All implementation work is driven from the spec. **Read `MIPI_FLICKER_SPEC.md` before making any non-trivial change**; it is the source of truth for module boundaries, REST endpoints, register layouts, and timing thresholds. When the user asks to "build" or "implement" something, follow the layout in `MIPI_FLICKER_SPEC.md` §3 rather than inventing a new structure. ## Purpose A two-host test harness that hunts for a MIPI D-PHY flicker/blackout fault on a custom PCB driven by an i.MX 8M Mini → TI SN65DSI83 (DSI→LVDS) bridge. The fault is hypothesised to be timing-violation rounding in the mainline `samsung-dsim` driver that drops several D-PHY parameters below MIPI v1.1 minimums. The harness loops: power-cycle the display rail, arm the scope, restart video, capture 4-channel waveforms + bridge/SoC registers, decode timings + DSI Lane 0 packets, log a verdict. ## Architecture (from spec §2, §3) Three top-level concerns; keep them in separate packages: - **`hardware/`** — instrument I/O only. `scope.py` (DSO80204B over VXI-11), `psu.py` (Siglent SPD3303X-E over VXI-11), `target.py` (HTTP REST client to the i.MX). Each is a thin controller class; no analysis logic. - **`analysis/`** — pure functions over captured data. `waveform.py` extracts D-PHY timings and decodes Lane 0 DSI packets from CSVs; `registers.py` parses SN65 + DSIM register dumps; `report.py` writes per-run artefacts. - **`server/app.py`** — Flask REST server that runs **on the i.MX target**, not the host PC. It shells out to `memtool`, `i2cget`, and `/sys/kernel/debug/regmap/...` and exposes `/registers`, `/sn65_registers`, `/sn65_settling`, `/display`, `/video`. The host-side `hardware/target.py` is just a `requests` wrapper around it. - **`master_loop.py`** — orchestrator only. Reset → arm scope → stimulate → wait for trigger → capture → analyse → save. See spec §9. `config.py` centralises all IPs, register addresses, MIPI spec minimums, and probe attenuation. Treat it as the single tuning surface. ## Non-obvious invariants These will silently break the experiment if violated: 1. **Cache-bypass before every SN65 read.** The server **must** `echo 1 > /sys/kernel/debug/regmap/2-002c/cache_bypass` before reading `IRQ_STAT (0xE5)`, every time. Without it, reads return the last-written cached value, not hardware state — flicker events become invisible. Spec §7.2, §15.4. 2. **Scope channels are 50 Ω DC, not 1 MΩ.** The 910R+50R probe divider only gives the documented 19.2× attenuation with 50 Ω termination. Any code that configures the scope must set `:CHANnel:INPut DC50` explicitly. Spec §15.1–2. 3. **Probe attenuation 19.2× is baked into thresholds.** All voltage thresholds in `analysis/waveform.py` are post-attenuation values (e.g. LP-high > 40 mV ≈ 770 mV on wire). Don't "correct" them back to wire voltages. 4. **UI depends on pixel clock.** `UI_NS = 1e9 / DSI_CLK_HZ` and several spec minimums are `f(UI)`. If `--pixel-clock` is overridden at runtime, recompute `DPHY_SPEC` rather than using stale module-level constants. Spec §15.5. 5. **DSIM PHY_TIMING bit-field layout is undocumented** in the i.MX 8M Mini reference manual. The parser must log raw hex *and* decoded cycle counts so they can be cross-checked against kernel dmesg. Don't assume the layout in spec §10 is correct without dmesg verification. Spec §15.6. 6. **Packet-level decode is the ground truth, not the SN65 error registers.** A flicker can be confirmed only by decoding Lane 0 bytes (Fault A: first long packet payload is all `0x00`; Fault B: lane stalls in LP-11 for ~20 ms). The SN65 `IRQ_STAT` bits are a hint, not a verdict. Spec §1 (Falcon prior art), §13. ## Network topology Host PC talks to three fixed IPs on the bench LAN — these are wired into `config.py` and the spec, not discovered: - `192.168.45.3` — Siglent PSU (VXI-11) - `192.168.45.4` — Keysight DSO80204B scope (VXI-11) - `192.168.45.8:5000` — i.MX target Flask server (HTTP) ## Commands No build/test/lint commands exist yet — the project hasn't been scaffolded. Spec §4 lists the dependency set (`python-vxi11`, `requests`, `flask`, `numpy`, `pandas`, `matplotlib`) when a `requirements.txt` is created. Spec §9.3 lists the eventual `master_loop.py` CLI surface (`--max-runs`, `--timeout`, `--pixel-clock`, `--note`, `--no-video`, `--output-dir`).