Files
samplez/tunie/research/reference-maps/TABLES.md
uhryniuk 173f6fa0c4 Locate Keihin tables + render real fuel maps in the viewer
Reversed the inner map format from l.java (Nc/Lb) and validated it against the
stock reference maps:

- reconstruct_rom.py: decoded map -> unpack directory -> 384KB flat ROM. In the
  flat ROM, production (20187) vs aftermarket (20188) differ only 1.4% (vs 96%
  packed), i.e. real fuel enrichment.
- table_map.py + TABLES.md: fe = c.a[Qd*48]; base = (fe[0]&0x2F0)<<12 = 0x50000;
  table = base + fe[k]. Located 9 tables (main/low-throttle fuel per cylinder,
  base/idle fuel, ignition by gear x4), 32 RPM rows x 20 throttle cols, with real
  axes (RPM fe[8], throttle fe[27]) and the AFR curve (fe[2], 128=lambda 1.00).
  Validated: main-fuel delta is uniformly richer in the aftermarket map.

Viewer now has a "Triumph tables" tab: drop a real .hex (or pick two) and it
decodes, unpacks, and renders the fuel/ignition tables as heatmaps with real
axes, plus an A->B difference view. build_viewer.py embeds the c.a/s.a directory
so any map resolves in-browser.

Catalogue dropdown: download_maps.py fetches map .hex files into maps_cache/;
serve.py serves the viewer over http so the dropdown can fetch them (drag-and-drop
still works on file://).

Proprietary map binaries (*.hex, *.dec.bin, maps_cache/) are gitignored — code and
docs only.
2026-08-11 07:00:19 -05:00

2.9 KiB
Raw Blame History

Keihin SH7054 (Triumph 865 twin, mechanical odo) — table map

Reversed from Nc()/Lb() in l.java and validated against the stock reference maps. All offsets are in the reconstructed flat ROM (0x60000). Compute per map:

fe   = c.a[Qd*48]                 # Qd from the s.a directory lookup on the map signature
base = (fe[0] & 0x2F0) << 12      # = 0x50000 for the 865 twin family
offset(table) = base + fe[<field>]

Main tables are 32 rows (RPM) × 20 cols (throttle), 16-bit big-endian.

Axes

Axis fe field Entries Values (20187) Meaning
RPM (rows) fe[8] 32 0, 500, 900, 1000 … 10000 engine speed, direct RPM
Throttle (cols) fe[27] 20 0, 10, 20 … 780, 1000 throttle %, ÷10 (0–100.0%)

Tables (validated by production 20187 vs aftermarket 20188 diff)

Table fe Offset (20187) Value range Notes
Main fuel — cyl 1 11 0x56990 951–10480 strong: 75% diff, smooth VE, aftermarket richer
Main fuel — cyl 2 12 0x56E90 951–10680 strong: 67% diff
Low-throttle fuel — cyl 1 15 0x55590 0–10760 70% diff; starts at 0 (closed throttle)
Low-throttle fuel — cyl 2 16 0x55A90 0–10810 68% diff; cyl-1 pair
Fuel — base/idle 9 0x55500 0–10760 61% diff; lower values
Ignition advance — gear 1 19 0x587D0 13–600 4 evenly-spaced (0x500) 20×32 tables
Ignition advance — gears 2–5 20 0x58CD0 13–600 main operating map
Ignition advance — gear 6 21 0x591D0 13–600 overdrive
Ignition advance — neutral 22 0x596D0 60–600 idle/free-rev

AFR / target lambda

fe[2] @ 0x52260 is an interleaved (value, breakpoint) curve where 128 = λ1.00 (stoich, 14.7 AFR) — e.g. … 128, 500, 128, 400, 128, 300 …. The 128 cells are the closed-loop lambda targets; disabling closed loop (O2 delete) lets you set these richer. Exact dimensions still being confirmed.

Scaling (confidence varies)

  • Fuel values are VE/fuel-mass in the ECU's internal units (≈ 0–10800). Real units (injector µs / VE %) need the ECU's fuel constant; relative changes are exact, absolute scaling TBD.
  • Ignition 13–600 is advance in an internal unit (candidate: value ÷ 10 = °BTDC, giving ~1.3–60°; the low-RPM row 90→14→20 fits a retard-then-advance curve). TBD.
  • AFR 128 = λ1.00 is solid (standard Keihin convention).

SAI / O2 / lambda flags

Now findable via the localised flat-ROM diff (20187 vs 20188), which isolates small single-byte changes (e.g. 0x50C13, 0x534AD, 0x59759) as prime toggle candidates. Confirming which is SAI vs O2 needs either bench testing or the finer Nc device logic — a follow-up.

Status

Fuel and ignition table locations are validated end-to-end. Remaining: exact scaling constants, AFR dimensions, and confirming the individual device flags.