Files
hpsg5-controller_v2-stm32g4/Core/Phi/phi.h

264 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file phi.h
* @brief T06215 injection-angle algorithm — compact public interface.
*
* AUTO-GENERATED by tools/extract_t06215_cal.py
* Source ROM: rom_eeprom_dump_0000-9FFF_424026.bin
* Bases: RWA4 = 0x9BD8, RWC6 = 0x7E56
*
* DO NOT EDIT -- regenerate with:
* python tools/extract_t06215_cal.py --target compact
*
* Companion to phi.c (single-translation-unit port of the per-function
* verbose tree under variants/T06215/src/) and the auto-generated
* phi_cal_tables.c. Callers see only this header; embedded
* `runtime_state_t` / `calibration_t` fields are IMPLEMENTATION DETAIL
* — touch only the outputs struct and the getter vtable.
*
* Lifecycle:
*
* phi_input_getters_t getters = { .get_rpm = ..., ... };
* phi_state_t state;
* phi_cal_t cal = phi_t06215_cal; // copy from auto-extracted master
* phi_outputs_t out;
*
* phi_init(&state, &cal, &getters); // boot-once
* for each tick:
* phi_service(&state, &cal, &out);
* use(out.target_inj_angle, ...);
*
* The producer chain runs in this fixed order each tick (see
* variants/T06211/docs/open-questions.md §4 / §5 — fused scheduler
* `FUN_698C` enclosing `0x6a3f LCALL FUN_7453` is authoritative):
*
* 1. CAN / external inputs pulled via the getter vtable.
* 2. compute_tein_overtemp_guard (FUN_5ca1) -> temperature, tein_overtemp_guard
* 3. compute_accel_comp_gain (FUN_72b0) -> accel_comp_gain @ *(0x0164)
* 4. compute_accel_comp_offset (FUN_732d) -> RW3C, REC.0
* 5. compute_gate_0220 (orphan @ 0x77ff) -> gate_0220 hysteresis
* 6. compute_tein_valve_fault_guard (FUN_62a2) -> RW7A
* 7. compute_target_injection_angle (FUN_7453) -> RW48 / RW5A
*
* The orphan temperature-kick chain (compute_temp_comp_factor → orphan
* FUN_5D58 angle_kick + `RW52 += RW3E` fold-in @ 0x7A3E) is ported in
* variants/T06215/src/ and wired into this compact phi_service.
* RW9E (the IIR state high word consumed by compute_temp_comp_factor)
* is produced internally by compute_temp_phi_comp — see
* compute_temp_phi_comp.h for the 1 kHz hook the host must drive.
* See variants/T06211/docs/open-questions.md §9.
*/
#ifndef PHI_T06215_H
#define PHI_T06215_H
#include <stdint.h>
#include <stddef.h>
/* ─── Internal runtime / calibration types ───────────────────────────
* Inlined verbatim from variants/T06215/src/injection_angle_state.h.
* Treat all fields as IMPLEMENTATION DETAIL — see the lifecycle
* comment above; the supported surface is `phi_outputs_t` and the
* getter vtable. */
typedef struct {
int16_t stride_bytes; /* +0: 2 * stride_items */
int16_t delta; /* +2: axis[idx-1] - axis[idx] */
int16_t fraction; /* +4: input_var - axis[idx] */
int16_t index_bytes; /* +6: byte offset into the axis array */
} submap_scratch_t;
typedef struct {
int16_t runtime_slot; /* +0: written by eval_submap_to_scratch */
int16_t *input_var; /* +2: pointer to the RW input variable */
int16_t stride_items; /* +4: breakpoints in the axis */
const int16_t *axis; /* +6: axis breakpoint table (descending) */
} submap_descriptor_t;
typedef struct {
/* ---- Per-tick inputs (produced elsewhere / by earlier producers) ---- */
uint16_t rpm; /* RW40 @ 0x0040 — engine RPM (external, HSI.0 ISR) */
int16_t angle_dec_cmd; /* RW42 @ 0x0042 — angle-dec command (external input) */
int16_t inj_qty_demand; /* RW44 @ 0x0044 — injection-quantity command. EXTERNAL CAN input. */
int16_t accel_comp_offset; /* RW3C @ 0x003C — internally produced by compute_accel_comp_offset (FUN_732d). */
int16_t tein_valve_fault_guard; /* RW7A @ 0x007A — internally produced by compute_tein_valve_fault_guard (FUN_62a2). */
/* ---- Reset/run flag byte (REC) ---- */
uint8_t rec; /* REC — bit 0 tested by FUN_7453 at 0x745c. */
/* ---- Persistent accumulator ---- */
int16_t angle_accumulator; /* RW52 @ 0x0052 — class-B state, updated in-place by FUN_7453. */
/* ---- Per-tick angle-kick fold-in (orphan FUN_5D58 / 0x7A3E) ---- */
int16_t angle_kick_2d; /* RW3E @ 0x003E — produced by compute_angle_kick_2d (port of orphan
* FUN_5D58 @ 0x5D58). Folded into angle_accumulator at 0x7A3E
* before FUN_7453. */
/* ---- Outputs of the chain ---- */
int16_t target_inj_angle; /* RW48 @ 0x0048 — SOLE writer is FUN_7453 @ 0x749f */
int16_t target_eoi; /* RW5A @ 0x005A — written @ 0x74a2 as target_inj_angle + phi1. */
/* ---- Absolute-address RAM touched by FUN_7453 ---- */
int16_t scratch_0200; /* *(0x0200) — event accumulator. */
int16_t tein_overtemp_guard; /* *(0x011a) — seed addend, produced by FUN_5ca1 @ 0x5d3e. */
int16_t dphi; /* *(0x014c) — angle delta. */
/* ---- Inputs to FUN_732d (compute_accel_comp_offset) ---- */
int16_t rpm_baseline; /* *(0x0138) — slow RPM baseline. */
int16_t accel_comp_gain; /* *(0x0164) — Δ-rpm × gain multiplier. */
uint8_t reset_gate_0226; /* *(0x0226) — accel_comp_offset enable gate. */
uint8_t gate_0220; /* *(0x0220) — RPM-hysteresis gate. */
/* ---- Inputs/state for FUN_5ca1 (compute_tein_overtemp_guard) ---- */
int16_t temperature; /* *(0x0146) — engine temperature (external input boundary). */
/* ---- Per-tick temperature-compensation factor (orphan FUN_5DAB / 0x5DE2) ----
* The R0CB-gated `ADD RW20, RWCE` branch at 0x5DC40x5DCB is
* intentionally not modeled — both slots are observed zero. */
int16_t temp_comp_factor; /* *(0x02F4) — produced by compute_temp_comp_factor (port of orphan
* FUN_5DAB @ 0x5DAB). Consumed by compute_angle_kick_2d at 0x5D8D. */
int16_t rw9a; /* RW9A @ 0x009A — published by compute_temp_comp_factor at 0x5DBD. */
int16_t rw9c; /* RW9C @ 0x009C — low word of the {rw9e:rw9c} signed IIR-filter
* state pair updated by compute_temp_phi_comp (port of FUN_6b4e
* @ 0x6b4e). Boot-zero (FUN_6ba3 @ 0x6bbf clears it). */
int16_t rw9e; /* RW9E @ 0x009E — high word of the {rw9e:rw9c} signed IIR-filter
* state pair, sole writer is phi_tick_1khz at the 10 Hz
* derived rate (port of FUN_6b2a @ 0x6b2a). Consumed by
* compute_temp_comp_factor at 0x6AFC. */
uint8_t temp_phi_comp_r94; /* R94 byte register slot driven by Timer_1khz at 0x79e2 / 0x7a26.
* Prescaler that gates the IIR step inside phi_tick_1khz: counts
* down on every 1 ms call, IIR fires when it reaches 0 and reloads
* to DAT_6061 = 0x64 = 100 → effective 10 Hz cadence. Seeded to
* 100 by phi_init. */
/* ---- 3-D angle-accumulator submap scratches (FUN_722e @ 0x722e) ---- */
submap_scratch_t scratch_rpm; /* *(0x0184) — RPM axis scratch. */
submap_scratch_t scratch_demand; /* *(0x0194) — inj_qty_demand axis scratch. */
submap_scratch_t scratch_dec_cmd; /* *(0x018c) — angle_dec_cmd axis scratch. */
int16_t scratch_0158; /* *(0x0158) — debug mirror of angle_accumulator result. */
/* ---- State for FUN_62a2 (compute_tein_valve_fault_guard, RW7A producer) ---- */
uint16_t rwc2; /* RWC2 — timing-baseline scratch compared against dat_604c. */
uint8_t rf5_gate; /* RF5 byte — peripheral input gate. */
uint8_t scratch_0221; /* *(0x0221) — FUN_62a2 early-out gate (baked to 1 in phi_init). */
uint8_t scratch_010e; /* *(0x010e) — Phase-1 counter byte. */
uint8_t scratch_010f; /* *(0x010f) — Phase-2 state byte. */
uint8_t scratch_0103; /* *(0x0103) — Phase-1 counter firing threshold. */
uint8_t scratch_0108; /* *(0x0108) — Phase-2 init/re-load value. */
} runtime_state_t;
typedef struct {
/* ---- RWA4-relative scalar calibration ---- */
int16_t tein_nominal; /* CAL[0x1e] — seed base added to tein_valve_fault_guard at 0x747b. */
int16_t cal_48; /* CAL[0x48] — value loaded into RW7A when FUN_62a2 fires (= 0x04B0). */
int16_t phi0; /* CAL[0x4c] — base/initial angle. */
uint8_t cal_byte_9c; /* CAL_byte[0x9c] — counter increment in FUN_62a2 (= 0x03). */
int16_t cal_54; /* CAL[0x54] — UPPER clamp on target_inj_angle at 0x7493. */
int16_t cal_74; /* CAL[0x74] — LOWER RPM threshold for gate_0220 hysteresis. */
int16_t cal_76; /* CAL[0x76] — gate_0220 hysteresis width. */
int16_t cal_78; /* CAL[0x78] — UPPER clamp on accel_comp_offset. */
int16_t cal_7a; /* CAL[0x7a] — LOWER clamp on accel_comp_offset. */
int16_t cal_7e; /* CAL[0x7e] — temperature reference subtrahend in compute_temp_comp_factor (FUN_5DAB 0x5DD1). */
int16_t cal_temp_comp_switch_dynamic; /* CAL[0x80] — boot value of *(0x02F6) (German label TK_AT_W). */
int16_t cal_82; /* CAL[0x82] — IIR input-gain `b` (Q16 unsigned) used by compute_temp_phi_comp
* at the FUN_6b4e MULU @ 0x6B66. Read via (uint16_t) cast. */
int16_t cal_84; /* CAL[0x84] — IIR pole `a` (Q16 unsigned) used by compute_temp_phi_comp
* at the FUN_6b4e MULUs @ 0x6B4E / 0x6B57. Read via (uint16_t) cast.
* On this ROM cal_82 + (uint16_t)cal_84 == 0x10000 (unity DC). */
int16_t cal_temp_comp_switch_complete; /* CAL[0x86] — boot value of *(0x02F2) (German label F_TK_TE_W). */
int16_t cal_92; /* CAL[0x92] — temperature offset subtracted in FUN_5ca1. */
int16_t cal_94; /* CAL[0x94] — multiplier in FUN_5ca1. */
int16_t cal_96; /* CAL[0x96] — UPPER clamp on RW1C in FUN_5ca1 (unsigned). */
int16_t cal_98; /* CAL[0x98] — LOWER rpm threshold for tein_overtemp_guard. */
int16_t cal_9a; /* CAL[0x9a] — UPPER rpm threshold for tein_overtemp_guard. */
/* ---- accel_comp_gain (FUN_72b0) submaps & tables (RWA4-relative) ---- */
submap_descriptor_t desc_accel_rpm; /* CAL+0x58 — RPM axis */
submap_descriptor_t desc_accel_demand; /* CAL+0x60 — inj_qty_demand axis */
submap_descriptor_t desc_accel_temp; /* CAL+0x68 — temperature axis */
const int16_t *accel_combine_table; /* CAL+0x70 — 2D RPM×demand combine table */
const int16_t *accel_refine_table; /* CAL+0x72 — 1D temperature refine table */
/* ---- ROM constants ---- */
int16_t dat_604c; /* *(0x604c) = 0x0444 — RWC2 timing threshold in FUN_62a2. */
int16_t cal_byte_402; /* *(0x0402) — boot sign-extended byte. Subtracted in FUN_5DAB at 0x5DD6. */
/* ---- RWC6-relative: 3-D angle-accumulator submap (FUN_722e) ---- */
submap_descriptor_t desc_rpm; /* RWC6+0x00 — RPM axis */
submap_descriptor_t desc_demand; /* RWC6+0x08 — inj_qty_demand axis */
submap_descriptor_t desc_dec_cmd; /* RWC6+0x10 — angle_dec_cmd axis */
const int16_t *data_table_3d; /* word @ RWC6+0x1a — 3-D table data */
/* ---- RWC6-relative: 2-D angle-kick submap + scalar (FUN_5D58) ---- */
const int16_t *data_table_2d_kick; /* word @ RWC6+0x32 — 2-D kick table (RPM × demand). */
int16_t cal_rwc6_34; /* CAL[RWC6+0x34] — demand-weight multiplier in FUN_5D58. */
} calibration_t;
/* ─── Outputs surfaced after every phi_service ───────────────────── */
typedef struct {
int16_t target_inj_angle; /* RW48 — primary output (FUN_7453 @ 0x749f) */
int16_t target_eoi; /* RW5A — target_inj_angle + phi1; phi1 = phi0 + dphi */
int16_t angle_accumulator; /* RW52 — class-B accumulator state */
int16_t accel_comp_offset; /* RW3C — FUN_732d output */
int16_t accel_comp_gain; /* *(0x0164) — FUN_72b0 output */
int16_t tein_valve_fault_guard; /* RW7A — FUN_62a2 output */
int16_t tein_overtemp_guard; /* *(0x011a) — FUN_5ca1 seed addend */
int16_t temperature; /* *(0x0146) — FUN_5ca1 filtered temperature */
int16_t temp_comp_factor; /* *(0x02F4) — compute_temp_comp_factor (FUN_5DAB) output */
int16_t angle_kick_2d; /* RW3E — compute_angle_kick_2d (FUN_5D58) output (folded into angle_accumulator) */
uint8_t gate_0220; /* *(0x0220) — RPM hysteresis gate */
uint8_t flags; /* bit 0: target_inj_angle invalid (sign bit set);
* bit 1: REC.0 was set entering FUN_7453;
* bit 2: gate_0220 active */
} phi_outputs_t;
/* ─── Getter vtable ────────────────────────────────────────────────── */
typedef struct {
int16_t (*get_inj_qty_demand)(void); /* RW44 */
int16_t (*get_angle_dec_cmd)(void); /* RW42 */
uint16_t (*get_rpm)(void); /* RW40 */
int16_t (*get_temperature)(void); /* *(0x0146) */
int16_t (*get_rpm_baseline)(void); /* *(0x0138) */
uint16_t (*get_rwc2)(void); /* RWC2 */
uint8_t (*get_reset_gate_0226)(void); /* *(0x0226) */
int16_t (*get_dphi)(void); /* *(0x014c) */
uint8_t (*get_scratch_0103)(void); /* *(0x0103) — boot-only */
uint8_t (*get_scratch_0108)(void); /* *(0x0108) — boot-only */
} phi_input_getters_t;
/* ─── Lifecycle types ────────────────────────────────────────────────── */
typedef struct {
runtime_state_t rt;
const phi_input_getters_t *getters;
} phi_state_t;
typedef calibration_t phi_cal_t;
/* ─── Public API ───────────────────────────────────────────────────── */
void phi_init(phi_state_t *state,
const phi_cal_t *cal,
const phi_input_getters_t *getters);
void phi_service(phi_state_t *state,
const phi_cal_t *cal,
phi_outputs_t *out);
/** 1 kHz hook. Host invokes once every 1 ms from its millisecond timer.
* Internally decrements `state->rt.temp_phi_comp_r94`; on R94 == 0 runs
* the IIR step (port of FUN_6b2a + FUN_6b4e @ 0x6b2a / 0x6b4e) and
* reloads R94 to 100 (DAT_6061). The IIR updates `{rt->rw9e, rt->rw9c}`
* in place using `rt->rw9a` as the input and `cal->cal_82` / `cal->cal_84`
* as coefficients. Reentrant per phi_state_t — the prescaler lives in
* runtime_state_t. */
void phi_tick_1khz(phi_state_t *state, const phi_cal_t *cal);
size_t phi_state_size(void);
size_t phi_cal_size(void);
/* ─── Auto-generated cal export (defined in phi_cal_tables.c) ──────── */
extern calibration_t phi_t06215_cal;
void phi_t06215_bind_inputs(runtime_state_t *rt, calibration_t *cal);
#endif /* PHI_T06215_H */