Major firmware rebuild of the existing Fan Controller Tester (ESH10000143). Hardware stays at R0; this project covers the ground-up firmware remake on that R0 hardware.
- Primary domain: firmware; secondary: test (the unit is a test fixture).
- Predecessor product exists in the real world but was not previously tracked in Trace, so no
successor_oflink could be created at setup.
Milestones
No milestones defined.
Items (7)
| Code | Status | Severity | Kind | Title | Date |
|---|---|---|---|---|---|
| E-001 | open | info | notice | Scope: major firmware rebuild on existing R0 hardware; no PLEASE predecessor | 2026-06-09 |
| E-002 | open | info | notice | Follow-up: B6 Power Input Board (PIB) test station not yet in PLEASE | 2026-06-09 |
| E-003 | open | info | decision | Platform: Arduino Nano Every (ATmega4809), APC bus over USB serial @921600 — carried over for the rebuild | 2026-06-09 |
| E-004 | open | info | decision | Full clean-room firmware remake — no reuse of earlier code | 2026-06-09 |
| E-005 | open | info | decision | Adopt ASCII line protocol; retire APC | 2026-06-10 |
| E-006 | open | info | decision | HW capability scope from netlist: PWM duty-only, tach single-global, temperature passive | 2026-06-10 |
| E-007 | open | info | decision | Dev-loop toolchain: official arduino:megaavr core (USB flashing), refining E-003 | 2026-06-10 |
Requirements
| Code | Status | Category | Title | Statement | Acceptance |
|---|---|---|---|---|---|
| REQ-FW-001 | draft | Maintainability | Scriptable firmware build / flash / verify | The firmware shall be **buildable and flashable from a scriptable command-line path** (no IDE required), and a flash shall be **verifiable** from the host. Supported paths: `arduino-cli` over USB (the Nano Every's onboard programmer) for the dev loop, and `pymcuprog` over UPDI for field reflash. | `build.ps1` compiles and uploads without IDE interaction; it reads the expected version from `version.h`, and after upload `IDN?` returns the matching `fw=<version>` — i.e. build → flash → verify is a single step. Field reflash via `pymcuprog write -d atmega4809 -t uart -u <port> -f build/fct.ino.hex` also brings a board to a running state. See [[E-003]]. |
| REQ-FW-002 | draft | Functional | ASCII command interface exposes all board capabilities | The firmware shall expose every capability of the R0 board through a **human-readable ASCII line protocol** over USB serial @921600 (replacing APC — see [[E-005]]): exactly one response line per command (`OK [payload]` / `ERR <code> <msg>`), case-insensitive verbs, explicit numeric error codes. | Each capability is reachable via a documented command: identity/version (`IDN?`), 8-channel PWM duty read (`PWM?`/`PWM? <ch>`), raw ADC for bring-up (`PWM:RAW?`), global tach (`TACH`/`TACH?`), global PWM-load enable (`PWMEN`), status LED (`LED`), safe-state (`SAFE`), comms watchdog (`WDT`), ADC averaging (`ADC:SAMPLES`). Malformed or out-of-range input returns `ERR` with the correct code (01 overflow, 02 channel, 03 illegal, 06 malformed). |
| REQ-FW-003 | draft | Functional | 8-Channel PWM Duty Measurement (ADC) | The firmware shall measure **PWM duty** on each of **8 channels** via the RC-filtered analog inputs (`PWM_n_ADC` → A0–A7), with a **global** PWM-load enable (`~PWM_EN`, D4, active-low). PWM **frequency is not measured** (no HW edge tap on this rev). See [[E-006]]. | For each of the 8 channels, with the DUT PWM active and the load enabled, `PWM? <ch>` returns a duty proportional to the RC-filtered node voltage (full scale calibrated at bring-up); duty reads ≈0% with PWM/fan-power absent. Numeric pass limits are derived at bring-up (see TC-FW-006). |
| REQ-FW-004 | draft | Functional | Global Tach Signal Generation | The firmware shall generate a configurable square-wave tach signal (≈0–20 kHz, ~50% duty) on a **single global output (D2) shared by all channels** — the board has one tach driver, not per-channel hardware. See [[E-006]]. | A commanded frequency produces a square wave at that frequency on the tach output (scope-verified or via the DUT's tach count); `TACH 0` stops it; safe-state and watchdog timeout force it off. Tolerance derived at bring-up (see TC-FW-006). |
| REQ-FW-005 | draft | Functional | Passive Temperature Emulation (4 channels, no firmware role) | The tester shall present a **hardware-strapped forward voltage** on each of **4** remote-diode temperature channels (DXP/DXN, J9–J12) for the DUT's temperature sensor. This is **passive hardware** — no MCU pin is connected, so the **firmware has no temperature function**. See [[E-006]]. | Each of the 4 channels presents the documented Vf (≈0.6 V @ 25 °C class, set by the populated BAT54 ladder); the DUT reads the corresponding temperature within range. Verification is station/DUT-side; the fixture firmware is not involved. |
| REQ-FW-006 | draft | quality | Test Limit Derivation Documented | Every firmware test case with numeric performance limits (timing, memory budget, throughput, jitter) shall have a documented derivation explaining how those limits were chosen. | For each firmware test case with numeric limits, evidence of derivation exists — `passCriterion` cites the source (datasheet figure, calibration measurement, regulation clause), OR a linked `please_decision` documents the rationale. |
Test Cases
| Code | Status | Category | Title / Signal | Target | Pass Criterion | Linked REQ |
|---|---|---|---|---|---|---|
| TC-FW-001 | open | maintainability | Firmware Flash & Identity Verify | — | `build.ps1 -Port <COM>` compiles and uploads without IDE interaction; after reset, `IDN?` returns `FCT ESH10000143 fw=<version> hw=R0` matching `version.h`. Field reflash via `pymcuprog` also yields a running board. | REQ-FW-001 |
| TC-FW-002 | open | functional | Protocol Conformance & Error Handling | — | Every documented verb returns exactly one response line with correct `OK`/`ERR` format. Malformed args return `ERR 06`, out-of-range channel (`PWM? 9`) returns `ERR 02`, and unknown verbs return `ERR 03`. Valid commands return `OK`. | REQ-FW-002 |
| TC-FW-003 | open | functional | PWM duty | — | For each of the 8 channels, sweep the DUT PWM 0→100%; `PWM? <ch>` duty tracks the commanded duty monotonically and within the bring-up-derived tolerance band; 0% reads ≈0. Pass limits per TC-FW-006. | REQ-FW-003 |
| TC-FW-004 | open | functional | TACH | — | Commanded tach frequencies across the range produce a square wave within ±tolerance (scope or DUT tach-count); `TACH 0` and `SAFE` stop it. Tolerance derived at bring-up (TC-FW-006). Note: a single global output — all channels share one frequency. | REQ-FW-004 |
| TC-FW-005 | open | functional | DXP/DXN Vf | — | Each of the 4 temp channels presents the documented strapped Vf; the DUT reports the corresponding temperature within range. Station/DUT-side check — the fixture firmware is not involved (no MCU connection to the diode network). | REQ-FW-005 |
| TC-FW-006 | open | quality | Limit Derivation Audit | — | For each firmware test case with limits, confirm `passCriterion` cites a source OR a `please_decision` documents the derivation. | REQ-FW-006 |
Verification Records
No verification records.
Decisions
The firmware rebuild keeps the existing hardware platform (HW frozen at R0):
- MCU: Microchip ATmega4809 on an Arduino Nano Every.
- Toolchain: Visual Studio + vMicro extension, MegaCoreX core (ATmega4809), programmer JTAG2UPDI, pinout "Nano Every". Field programming via UPDI (1200 bps trigger;
pymcuprog write -t uart). - Host comms: USB Micro → serial UART at 921600 baud, framed with the Accordion Peripheral Control (APC) bus protocol (SOF
0x07… EOF0x0D, hex-ASCII payload; commands NOP/GETVER/PINCFG/WRITE/READFLOAT/TONE_FREQ/TONE_CFG, etc.). Used downstream of a Raspberry Pi "AGENT". - Function: tests fan-controller circuits across 8 fan channels (PWM drive, Tach generation, VFan ADC sense, Temp diode sense). Reference design: MAX31760.
Rationale: this is a firmware remake on unchanged R0 hardware, so MCU/toolchain/protocol are fixed inputs, not open choices.
Source: existing design doc "Fan Controller Tester" (rev 3, Richard Axelsson / Gustav Kihlberg) and firmware apc_atmega4809-main in C:\Workbook\ESH10000143_fw_remake.
The firmware is a complete rewrite from scratch. The earlier apc_atmega4809-main / CommandReceiver firmware is reference only — none of its code, structure, or architecture is carried into the new firmware.
The existing hardware (R0), schematic, Arduino Nano Every platform, and the APC bus protocol remain as fixed external constraints (see [[E-003]]); only the firmware implementation starts fresh.
Rationale: engineer directive (Mikael Svensson) at requirements capture.
Decision
The remade firmware speaks a human-readable ASCII line protocol over USB serial @921600
(verb + space-delimited args, -terminated; exactly one response line per command —
OK [payload] / ERR <code> <msg>), replacing the legacy APC (SOF/EOF hex-ASCII byte framing).
Rationale
The fixture is PC-tethered over short, clean USB and performs settled, gated measurements, so the
serial transaction is <1% of test time (a command is ~0.4 ms vs 20–50 ms physical settling per
setpoint). APC/binary wire-efficiency therefore buys nothing measurable, while readability greatly
improves bench bring-up and test authoring (type PWM? 3 in any terminal). Readable ≠ manual — the
protocol is strict request/response and fully automatable via the host driver.
Rejected alternatives
- Keep / clean up APC — retains unreadable byte-soup; clean-room rewrite ([[E-004]]) means there is no wire compatibility to preserve.
- Binary (COBS + CRC) — robustness/efficiency unneeded on short USB at low rates; opaque-on-the-wire debugging is a recurring cost.
Escape hatch
Design keeps room to add a single binary "bulk transfer" command later iff a real high-rate streaming need appears, without making the rest of the protocol opaque.
Implemented in firmware module protocol.*; host side host/fct_driver.py (FanControllerTester).
Decision
Firmware capabilities are scoped to what the R0 board actually wires — confirmed from the
production netlist.ipc (Arduino Nano Every, schematic ref A1) and physical inspection
(all-discrete, no I²C muxes; the concept-schematic ADG728/ADG729 were never populated):
- PWM = duty only, 8 channels. PWM_1..8 reach the MCU only as RC-filtered analog
(
PWM_n_ADC→ A4, A5, A6, A7, A0, A1, A2, A3). No frequency measurement — no raw edge taps a timer pin on this rev. - Tach = single GLOBAL square wave on D2, shared by all 8 channels (one frequency at a time).
- PWM load enable is GLOBAL (
~PWM_EN, D4, active-low) — not per-channel. - Temperature is PASSIVE. No MCU pin touches the DXP/DXN diode network (4 channels, J9–J12); the DUT reads a hardware-strapped Vf directly. The firmware has no temperature role.
Consequence
Supersedes the earlier assumption set (I²C muxes; per-channel PWM-enable; per-channel tach; firmware-read temperature on 8 channels). Requirements REQ-FW-002..005 and test cases TC-FW-001..005 updated to match. See also [[E-003]] (platform) and [[E-004]] (clean-room).
Future-HW candidates (need a board spin; D5–D13 / MOSI / MISO / SCK are spare)
- PWM frequency verification — wire one raw
PWM_nto a timer-capable pin. - Per-channel tach — per-channel drive hardware.
- MCU temperature control — wire the diode ladder to GPIO.
- Add a silkscreen revision mark (board currently carries none).
Decision
For the build/flash dev loop, the firmware uses the official Arduino arduino:megaavr core,
FQBN arduino:megaavr:nona4809. The genuine Nano Every has an onboard UPDI bridge, so this core
flashes over the single USB cable with no external programmer — the streamlined path. build.ps1
default FQBN updated accordingly.
Rationale
[[E-003]] named MegaCoreX + JTAG2UPDI. MegaCoreX targets the bare ATmega4809 and needs an external UPDI programmer, which contradicts the goal of a one-cable, IDE-free dev loop now that the PC drives the fixture directly. The official core removes that hardware dependency.
Scope / what stays
- MegaCoreX remains a supported option (e.g. if its extra clock/timer/bootloader control is wanted):
-Fqbn MegaCoreX:megaavr:4809:... -Programmer jtag2updi. - Field reflash via
pymcuprogover UPDI is unchanged. - This refines the toolchain/upload aspect of E-003 only; MCU, platform, and APC-replacement decisions are unaffected.
Install (once)
arduino-cli core update-index; arduino-cli core install arduino:megaavr
Notices
This project covers a ground-up firmware rebuild of the existing Fan Controller Tester (ESH10000143). Key context captured at project setup:
- Hardware is frozen at R0 — this effort does not change the board; it remakes the firmware that runs on the R0 hardware.
- The predecessor product exists in the real world but was never tracked in PLEASE, so no
successor_ofrelationship could be created. Any prior firmware behaviour/known issues must be sourced from outside PLEASE. - Classified as primary domain firmware, secondary test (the unit is a test fixture). Firmware template scaffold applied (6 requirements, 6 test cases, verification plan, 20 design rules).
Update (2026-06-10) — requirements/test-case refinement COMPLETE
The scaffolded firmware requirements and test cases have been reviewed and rewritten against the real hardware (pin map extracted from netlist.ipc; board physically inspected — all-discrete, no I²C muxes):
- REQ-FW-001..005 and TC-FW-001..005 updated; TC-FW-006 (Limit Derivation Audit) kept.
- Governing decisions recorded: [[E-005]] (ASCII protocol replaces APC) and [[E-006]] (HW capability scope: PWM duty-only, tach single-global on D2, temperature passive/4-ch with no firmware role).
- Firmware, host driver, and build/flash/verify tooling implemented in
…/Firmware/fct/.
Remaining open follow-up: confirm whether this tester relates to any existing PLEASE project (e.g. the B12 CB test-rig family) for a related_to link. (The B6 PIB station link is tracked separately under E-002.)
The Fan Controller Tester is also used in the B6 Power Input Board (PIB) test station, but that test station is not tracked as a project in PLEASE yet (only referenced indirectly in the Synopsys Support Agreement's covered-stations list, project 42).
Action: when the B6 PIB test station gets its own PLEASE project, link it related_to ESH10000143. Deferred at the engineer's request during project setup.
Design Rule Status
■ No violations ■ Warning ■ Error ■ Waived