project
Adom Custom Electronic Load
Public Made by Adomby adom
Two-layer digitally controlled electronic-load prototype. Compact R11 is under active electrical, cooling and probe-access review; not a manufacturing release.
← Commit history
Review insulating stack clip and verify fan-fault software timing
11 files changed
+99−5
README.md+1−1@@ -18,7 +18,7 @@ The [current board model review](docs/board-model-review.md) includes the export - D1 now uses [SBR10U45SP5-13](https://wiki.adom.inc/adom/sbr10u45sp5-13), with published symbol, footprint and drawing-derived nominal STEP/GLB assets. Its local thermal study excludes Q1 and is not complete assembly acceptance. - The fan has a [component page with GLB motion states](https://wiki.adom.inc/adom/mf40200v1-1000u-g99). Its preview is simulated; shared viewer integration remains proposed. - The [thermal budget](docs/thermal-budget.md) now matches the 55 °C firmware trip ceiling. The earlier 25 W assumption is retained as an unqualified future option; R0 targets 5 W and still requires cooling validation.-- There are 90 unique raw takes, 34 reviewed excerpts and 30 storyboard clips. Failed/static captures remain identified in the shot log; the final narrated 4–5 minute film is unfinished.+- There are 90 unique raw takes, 35 reviewed excerpts and 31 storyboard clips. Failed/static captures remain identified in the shot log; the final narrated 4–5 minute film is unfinished. Read the [engineering status](docs/status.md), [placement review](docs/placement-review.md), [library review](docs/library-review.md), [cost breakdown](docs/cost/README.md), [firmware/control-panel contract](docs/firmware-contract.md), and [raw clip log](videos/shotlog.json). The [AI Flow report](docs/runs/board-codex-20261007-1749/README.md) records the run.
design/fan-shutdown-review.jsonadded+20@@ -0,0 +1,20 @@+{+ "kind": "host-software-review",+ "cases": 240,+ "pollIntervalsMs": [+ 1,+ 15+ ],+ "result": "pass",+ "hardwareQualified": false,+ "thermalAcceptanceChanged": false,+ "inputs": {+ "firmware/fan_tach.c": "844f00c1f77e39529bd8f667d543ecee187ff4fe91108aedb7a2c36eb22846fa",+ "firmware/load_core.c": "85017ff0a3e37e7b5e41604989326fe623e7f73427ecd8e1a29c63a38d003638",+ "firmware/stm32/fan_input.c": "d4ebe5572dbbcd1a3ea84c4e31442732a7237e94d554ec8acdc07142486e92f8",+ "firmware/stm32/main.c": "a132ee37a6e9a9261d70389fdf5d5d7d8d7e23f8c389ac1d840f26e891137cf1",+ "tests/test_fan_shutdown.c": "673502c846e39cd1e817b736535848500daa0c5adb73e940a41320098819d44d",+ "tools/check_firmware.sh": "f63202537184bee6bc35a6689bc1d55726e6945652fcd106904c061d8dbc0137"+ },+ "testLogSha256": "9e3393a9c5e7f4a7ccac1e6567c3d285bbf4933fe06125d54ee72ab2b99d94dc"+}
docs/build-clips.md+4@@ -205,3 +205,7 @@ The inventory now contains **89 raw takes and 33 reviewed excerpts**. Raw takes ## PEEK fastener inspection [Watch the 3.5-second 2× excerpt](clips/peek-fastener-review.mp4). Actual nominal-model inspection with the heatsink hidden explicitly. The excerpt excludes later frames obscured by a carrier pillar; it does not establish insulation, preload or thermal performance. Raw take 90; full decode, contact sheet and poster reviewed. Current inventory: 90 raw takes, 34 reviewed excerpts and 30 storyboard candidates. Three scenes have draft narration; final film remains unassembled.++## Insulating thermal stack++[Watch the 4.5-second 2× excerpt](clips/aln-stack-review.mp4). Actual insertion of the nominal AlN pad and PEEK fastener, with the sink hidden. Grease gaps are assumed; preload and cooling remain unqualified. Take 91 was decoded and visually reviewed. Current inventory: **91 raw takes, 35 reviewed excerpts and 31 storyboard candidates**. Human scene approval and final assembly remain pending.
docs/clips/aln-stack-review.jpgadded⋯ 1 unchanged line ⋯
docs/clips/aln-stack-review.mp4added⋯ 1 unchanged line ⋯
docs/completion-plan.md+2−2@@ -18,12 +18,12 @@ Continue the custom electronic load through AIFlow, firmware/control-panel and m 3. After supported physical/spec changes, rerun exact-input current and thermal acceptance. Continue fields, net tour, silkscreen, native 3D, finish and export in enforced order. Review-only manufacturing exports already exist; do not present them as released. 4. Complete firmware/calibration and molecule integration. Control panel 0.0.4 drives the digital rotor only from fresh valid hardware RPM; stale/disconnected means unknown/paused. Host tests pass; output remains locked and hardware unflashed. Physical timing, sensor calibration and load accuracy remain unverified. 5. Complete procurement and component provenance. [Cost review](cost/README.md) lists $70.88 known proposed subtotal with 63 board references unpriced and substantial assembly/process exclusions. Candidate hardware is not an approved BOM.-6. Continue significant-action captures. Inventory is 90 raw takes, 34 reviewed excerpts and 30 storyboard candidates. Three scenes have draft narration in `videos/narrated-review`; storyboard is `videos/build-storyboard.json`, port 8798. Obtain per-clip feedback before final assembly as required by aiflow-process-video. No final film exists.+6. Continue significant-action captures. Inventory is 91 raw takes, 35 reviewed excerpts and 31 storyboard candidates. Three scenes have draft narration in `videos/narrated-review`; storyboard is `videos/build-storyboard.json`, port 8798. Obtain per-clip feedback before final assembly as required by aiflow-process-video. No final film exists. ## Tool and delivery boundaries AIFlow 0.1.87 source, registry and installed executable were verified separately; direct updates are authorized but must use fresh upstream state. Fields owner PRs remain review-only; never merge them or replace shared Fields 8875. The isolated solver is in `fields-package-load-target/release/adom-fields`. -Keep the timeline visible at `http://8893.localhost:63548/`. Wrap real external engineering in `adom-aiflow exec`; no idle heartbeat. Register unique artifact filenames to avoid the known basename collision. Keep public fabrication terminology to 3rdPartyFab. Preserve other threads, pinned bridges and user browser tabs.+Keep the timeline visible at `http://8893.localhost:63548/`. Wrap real external engineering in `adom-aiflow exec`; no idle heartbeat. AIFlow 0.1.87 preserves artifact snapshots by content hash; use its returned registered path for replacements. Keep public fabrication terminology to 3rdPartyFab. Preserve other threads, pinned bridges and user browser tabs. Before a final handoff run `finish-guard --json`. Continue while useful authorized work remains; a failed thermal gate or pending owner review is not by itself a global stop. [Historical checkpoints](completion-history-2026-10-10.md) are retained for evidence, not as current instructions.
docs/fan-shutdown-review.mdadded+17@@ -0,0 +1,17 @@+# Fan-fault shutdown review++The portable tachometer and load-policy modules pass 240 combined host cases covering every scheduler phase at 1–15 ms polling intervals, both normally and across the 32-bit millisecond clock wrap. These tests use synthetic sensor values and the actual C modules. They do not measure MCU or analog shutdown timing.++The tachometer accepts eight consecutive periods of 3000–6000 µs (two pulses per revolution), rejects bad periods, and invalidates a reading strictly more than 15000 µs after the last edge. In this test, the load policy latches FAN fault and commands zero DAC/disabled output at the first subsequent policy poll: greater than 15 ms and no later than 15 ms plus the assumed polling interval after the last pulse. The STM32 adapter additionally discards qualification after a polling gap greater than 15 ms. The policy's 250 ms last-tach fallback is not the normal missing-pulse detector.++`tests/test_fan_shutdown.c` supplements the existing noise, recovery, latch, stale sample, protocol and timer-wrap tests. `tools/check_firmware.sh` passed with address/undefined-behavior sanitizers and 25 Python tests on this review. The existing fan demonstration separately checks that returning pulses do not restart a faulted load.++## What still needs measurement++- Worst-case foreground/interrupt latency under USB traffic and failed I2C transactions; a host scheduler bound is not an MCU deadline guarantee.+- Time from the last physical tach pulse to enable deassertion, DAC clearing and measured drain-current decay.+- Temperature-sensor attachment, lag, tolerance, calibration and the peak case/junction temperature during each fault.+- Fan unplug/stall, tach wire open/short/noise, and blocked airflow while RPM remains apparently healthy.+- Independent hardware protection and power-on/reset behavior with a qualified assembly.++The current STM32 bring-up image unconditionally keeps the load off and sets assembly qualification false. No production enable path was added or flashed. A spinning fan cannot prove installed airflow. The full-power still-air thermal failure remains open; these software tests do not waive it or establish a safe transient thermal margin.
tests/test_fan_shutdown.cadded+39@@ -0,0 +1,39 @@+/* Host integration: real tach/policy modules, synthetic scheduler and sensors.+ * Bounds software observation only, not GPIO, analog decay or temperature. */+#include "../firmware/load_core.h"+#include "../firmware/fan_tach.h"+#include <assert.h>+#include <stdio.h>+static void run(unsigned cadence_ms, unsigned phase_ms, uint32_t origin_ms) {+ fan_tach f; load_core c; fan_tach_init(&f); load_init(&c,origin_ms);+ uint32_t last=0; unsigned next=0, trip=0; bool armed=false;+ for(unsigned t=0;t<1300;t++) {+ while(next<=t*1000 && next<1000000) {+ last=next;fan_tach_edge(&f,origin_ms*1000+next);next+=4286;+ }+ if(t%cadence_ms!=phase_ms)continue;+ float rpm; bool valid=fan_tach_read(&f,origin_ms*1000+t*1000,&rpm);+ load_sample s={.now_ms=origin_ms+t,.sample_ms=origin_ms+t,+ .last_tach_ms=origin_ms+last/1000,.volts=5,.amps=0.5f,.case_c=40,+ .fan_rpm=rpm,.fan_rpm_valid=valid,.sensors_valid=true,.hw_ok=true,+ .assembly_qualified=true,.latch_q=armed};+ load_heartbeat(&c,s.now_ms);+ if(!armed && t>=100) {assert(load_set_current(&c,.5f));assert(load_arm(&c,&s));armed=true;s.latch_q=true;}+ load_tick(&c,&s);+ if(armed && t<990)assert(c.state==LOAD_RUNNING);+ if(c.state==LOAD_FAULT && !trip) {+ trip=t;assert(c.faults&F_FAN);assert(!c.enable && !c.dac_code);+ assert(t*1000-last>15000);+ assert(t*1000-last<=15000+cadence_ms*1000);+ }+ if(trip)assert(c.state==LOAD_FAULT && !c.enable && !c.dac_code);+ }+ assert(trip);+}+int main(void) {+ unsigned cases=0;+ for(unsigned cadence=1;cadence<=15;cadence++)for(unsigned phase=0;phase<cadence;phase++) {+ run(cadence,phase,0);run(cadence,phase,UINT32_MAX-500);cases+=2;+ }+ printf("fan shutdown: %u synthetic scheduler cases passed; observation <=15ms + poll interval; no hardware timing claim\n",cases);+}
tools/check_firmware.sh+2@@ -12,6 +12,8 @@ gcc "${cc_args[@]}" firmware/load_core.c tests/test_load_core.c -lm -o "$load_ch "$load_check_dir/core" gcc "${cc_args[@]}" firmware/fan_tach.c tests/test_fan_tach.c -lm -o "$load_check_dir/tach" "$load_check_dir/tach"+gcc "${cc_args[@]}" firmware/load_core.c firmware/fan_tach.c tests/test_fan_shutdown.c -lm -o "$load_check_dir/fan-shutdown"+"$load_check_dir/fan-shutdown" gcc "${cc_args[@]}" firmware/load_core.c firmware/load_protocol.c tests/test_load_protocol.c -lm -o "$load_check_dir/protocol" "$load_check_dir/protocol" gcc "${cc_args[@]}" demos/fan-safety/trace.c firmware/load_core.c firmware/fan_tach.c -lm -o "$load_check_dir/fan-demo"
videos/build-storyboard.json+6@@ -192,6 +192,12 @@ "title": "Check space for the insulating fastener", "description": "Nominal screw and nut review at 2x. Sink hidden for inspection; threads omitted. Fit does not qualify preload, insulation or cooling. Later obscured frames excluded.", "raw_path": "/home/adom/project/adom-custom-electronic-load/docs/clips/peek-fastener-review.mp4"+ },+ {+ "id": "aln-stack-review",+ "title": "Add the insulating thermal interface",+ "description": "Actual nominal AlN and PEEK model insertion at 2x. Sink hidden; grease gaps assumed. Mechanical fit does not qualify insulation, preload or cooling.",+ "raw_path": "/home/adom/project/adom-custom-electronic-load/docs/clips/aln-stack-review.mp4" } ] }
videos/inventory.json+8−2@@ -1,6 +1,6 @@ {- "rawTakeCount": 90,- "reviewedExcerptCount": 34,+ "rawTakeCount": 91,+ "reviewedExcerptCount": 35, "countingRule": "Unique raw window recording filenames in this project; excludes derivative action/speed exports and reference projects. Raw count includes rejected takes.", "takes": [ {@@ -542,6 +542,12 @@ "durationSeconds": 12.233333, "topic": "Nominal PEEK screw and nut clearance inspection", "review": "Full raw and excerpt decode; contact sheet and poster reviewed. 3.5-second 2x excerpt excludes later carrier occlusion; browser chrome cropped. Sink hidden explicitly; threads omitted. No thermal, insulation or preload qualification."+ },+ {+ "file": "videos/raw/window-10291968-20261010-182413.mp4",+ "durationSeconds": 9.866667,+ "topic": "Add nominal AlN insulator and PEEK fastener stack",+ "review": "Full raw and excerpt decode, contact sheet and poster reviewed. 4.5-second 2x excerpt, browser chrome cropped. Sink hidden explicitly. Assumed grease gaps; no preload, insulation or thermal qualification." } ] }