Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 096001c869 | |||
| bf0254f854 | |||
| 6d09ee3d79 | |||
| d4523e3c7e | |||
| 7ff62ccabc | |||
| 98a835026e | |||
| de8a09361b |
@@ -157,7 +157,7 @@ void FBKW_service(void) {
|
||||
fbkw_rt.system_flags_110 &= ~0x20u; // clear ONLY bit 5 (OL gate). Leave other bits alone.
|
||||
|
||||
#if defined(T06211)
|
||||
fbkw_rt.pi_open_loop_flag = 0x00; //0x2000
|
||||
//fbkw_rt.pi_open_loop_flag = 0x00; //0x2000
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,13 @@ const pwm_calibration_t pwm_cal_rom = {
|
||||
.target_5e_min_clamp = (int16_t)0xFE00, /* cal+0x12A */
|
||||
.can_aux_12e_max = 1451, /* cal+0x002 */
|
||||
|
||||
/* CKP-zero acquisition — values re-extracted from this ROM
|
||||
* (RWA4=0x9BD8); cal slot offsets differ from T06235 (T06215 has
|
||||
* cal+0x4E/0x50/0xA0 vs T06235 cal+0x50/0x52/0xA2). */
|
||||
.ckp_zero_anchor = 4147, /* cal+0x04E @ 0x9C26 = 0x1033 */
|
||||
.can_dckp_offset_bias = -427, /* cal+0x050 @ 0x9C28 = 0xFE55 */
|
||||
.ckp_modulus = 7680, /* cal+0x0A0 @ 0x9C78 = 0x1E00 (90°) */
|
||||
|
||||
/* Recovery / sustained-error machinery */
|
||||
.pi_state_c2_reload = 100, /* cal+0x114 (ROM 0x9CEC = 0x0064) */
|
||||
.inj_qty_thresh = 96, /* cal+0x116 (ROM 0x9CEE = 0x0060) */
|
||||
|
||||
@@ -14,9 +14,14 @@
|
||||
* ~cal+0x9E (the new ADR-SV-* / KW_SIM_UMSCHALTUNG diagnostic fields per
|
||||
* doc.txt 30.08.02). All T06215 cal field roles map to T06235 with the
|
||||
* +0x14 offset; the actual values were re-extracted from this ROM.
|
||||
* NOTE: there is also a +0x02 shift in the lower region — at minimum
|
||||
* cal+0x4c → cal+0x4e and cal+0xa0 → cal+0xa2 (both confirmed in FUN_6a4b
|
||||
* @ 0x6a4b). Lower-region scalars must be re-checked, not assumed unchanged.
|
||||
*
|
||||
* Notable value deltas vs T06215:
|
||||
* - setpoint_offset = cal+0x4c − cal+0x4e = 4399 − 3499 = +900 (T06215: -648).
|
||||
* - setpoint_offset = cal+0x4e − cal+0x50 = 3499 − 4228 = -729 (T06215 cal+0x4c−cal+0x4e = -648).
|
||||
* Cal-block +0x02 shift in this lower region; T06215's cal+0xa0 modulo
|
||||
* also moves to cal+0xa2 in T06235 (verified in FUN_6a4b @ 0x6a4b).
|
||||
* - init_p_gain_normal = +368 (T06215: +336)
|
||||
* - init_p_slope_large_pos = +2047 (T06215: +1792)
|
||||
* - init_integ_step_normal = +320 (T06215: +256)
|
||||
@@ -112,10 +117,16 @@ const pwm_calibration_t pwm_cal_rom = {
|
||||
/* CAN-decoded setpoint cal constants (lower region — invariant offsets) */
|
||||
.b_fb_kw_upper_bound = 7680, /* cal+0x004 */
|
||||
.b_fb_kw_lower_bound = (int16_t)0xFD00, /* cal+0x006 */
|
||||
.setpoint_offset = 900, /* cal+0x4c − cal+0x4e = 4399 − 3499 = 900 (T06215: -648) */
|
||||
.setpoint_offset = -729, /* cal+0x4e − cal+0x50 = 3499 − 4228 = -729 (T06215 cal+0x4c−cal+0x4e = -648) */
|
||||
.target_5e_min_clamp = (int16_t)0xFE00, /* cal+0x13E = -512 (T06215 cal+0x12A +0x14) */
|
||||
.can_aux_12e_max = 1451, /* cal+0x002 */
|
||||
|
||||
/* CKP-zero acquisition (FUN_55e0 + FUN_6a4b chain) — values read from
|
||||
* rom_eeprom_dump_0000-9FFF_504042.bin at RWA4 + offset. */
|
||||
.ckp_zero_anchor = 4228, /* cal+0x050 @ 0x9C08 = 0x1084 */
|
||||
.can_dckp_offset_bias = 0, /* cal+0x052 @ 0x9C0A = 0x0000 */
|
||||
.ckp_modulus = 7680, /* cal+0x0A2 @ 0x9C5A = 0x1E00 (90° at 256/3°/unit) */
|
||||
|
||||
/* Recovery / sustained-error machinery */
|
||||
.pi_state_c2_reload = 100, /* cal+0x128 (was T06215 cal+0x114) */
|
||||
.inj_qty_thresh = 96, /* cal+0x12A (was T06215 cal+0x116) */
|
||||
|
||||
@@ -192,6 +192,13 @@ struct pwm_calibration {
|
||||
int16_t target_5e_min_clamp; /* cal+0x12A */
|
||||
int16_t can_aux_12e_max; /* cal+0x002 */
|
||||
|
||||
/* CKP-zero acquisition (FUN_70d8 chain) cal constants — see
|
||||
* docs/algorithm-ckp-zero-acquisition.md. T06215 cal slot offsets
|
||||
* differ from T06235 (T06235 has +0x02 lower-region shift). */
|
||||
int16_t ckp_zero_anchor; /* cal+0x04E — FUN_70d8 additive anchor */
|
||||
int16_t can_dckp_offset_bias; /* cal+0x050 — Stage-1/Stage-2 bias */
|
||||
int16_t ckp_modulus; /* cal+0x0A0 — FUN_70d8 modulo wrap */
|
||||
|
||||
/* Recovery / sustained-error machinery */
|
||||
int16_t pi_state_c2_reload; /* cal+0x114 — reload value for pi_state_c2 on latch */
|
||||
int16_t inj_qty_thresh; /* cal+0x116 — inj-qty threshold for recovery vs reset */
|
||||
|
||||
@@ -193,6 +193,11 @@ struct pwm_calibration {
|
||||
int16_t target_5e_min_clamp; /* cal+0x12A */
|
||||
int16_t can_aux_12e_max; /* cal+0x002 */
|
||||
|
||||
/* CKP-zero acquisition (FUN_55e0 + FUN_6a4b chain) cal constants */
|
||||
int16_t ckp_zero_anchor; /* cal+0x050 — FUN_6a4b additive anchor */
|
||||
int16_t can_dckp_offset_bias; /* cal+0x052 — FUN_55e0/FUN_6a4b bias */
|
||||
int16_t ckp_modulus; /* cal+0x0A2 — FUN_6a4b modulo wrap */
|
||||
|
||||
/* Recovery / sustained-error machinery */
|
||||
int16_t pi_state_c2_reload; /* cal+0x114 — reload value for pi_state_c2 on latch */
|
||||
int16_t inj_qty_thresh; /* cal+0x116 — inj-qty threshold for recovery vs reset */
|
||||
|
||||
@@ -1,76 +1,47 @@
|
||||
/**
|
||||
* @file cal_tables_rom.c (variant/T06235/compact_src)
|
||||
* @brief ROM-decoded T06235 calibration.
|
||||
* @file cal_tables_rom.c (variant/t06211/compact_src)
|
||||
* @brief ROM-decoded t06211 calibration.
|
||||
*
|
||||
* Source ROM: rom_eeprom_dump_0000-9FFF_504042.bin
|
||||
* Bosch P/N header: '16700 69T63\0' (24-byte ASCII header at flash 0x9BA0)
|
||||
* Calibration base: RWA4 = 0x9BB8
|
||||
* Flash anchor: 0x9618
|
||||
* Generated: 2026-05-01 (extracted via tools/extract_calibration.py
|
||||
* + direct flash readback per Step 7)
|
||||
* AUTO-GENERATED by tools/extract_calibration.py
|
||||
* Source ROM: rom_eeprom_dump_0000-9FFF_504012.bin
|
||||
* Calibration base (RWA4): 0x9BD8
|
||||
* Flash anchor: 0x7E18
|
||||
* Generated: 2026-05-05 10:31:48
|
||||
*
|
||||
* Field-name → ROM-address binding lives in pwm_addr_map.h. T06235 is a
|
||||
* recompile of T06215 with a uniform +0x14 cal-block insertion above
|
||||
* ~cal+0x9E (the new ADR-SV-* / KW_SIM_UMSCHALTUNG diagnostic fields per
|
||||
* doc.txt 30.08.02). All T06215 cal field roles map to T06235 with the
|
||||
* +0x14 offset; the actual values were re-extracted from this ROM.
|
||||
* NOTE: there is also a +0x02 shift in the lower region — at minimum
|
||||
* cal+0x4c → cal+0x4e and cal+0xa0 → cal+0xa2 (both confirmed in FUN_6a4b
|
||||
* @ 0x6a4b). Lower-region scalars must be re-checked, not assumed unchanged.
|
||||
*
|
||||
* Notable value deltas vs T06215:
|
||||
* - setpoint_offset = cal+0x4e − cal+0x50 = 3499 − 4228 = -729 (T06215 cal+0x4c−cal+0x4e = -648).
|
||||
* Cal-block +0x02 shift in this lower region; T06215's cal+0xa0 modulo
|
||||
* also moves to cal+0xa2 in T06235 (verified in FUN_6a4b @ 0x6a4b).
|
||||
* - init_p_gain_normal = +368 (T06215: +336)
|
||||
* - init_p_slope_large_pos = +2047 (T06215: +1792)
|
||||
* - init_integ_step_normal = +320 (T06215: +256)
|
||||
* - init_integ_step_large_pos= +831 (T06215: +512)
|
||||
* - init_integ_step_large_neg= +255 (T06215: +256)
|
||||
* - rpm_threshold_recovery = 2726 (T06215: 2936)
|
||||
* - pwm_rpm_windows[1] = 6795 (T06215: 6837)
|
||||
* - setpoint_y[] = [1707,1707,1707,1195,768,427]
|
||||
* (T06215: [1707,1707,1195,768,427,427])
|
||||
* - pwm Y-table values mostly re-tuned (90 entries); see arrays below.
|
||||
*
|
||||
* All other scalars match T06215 exactly.
|
||||
* DO NOT EDIT — regenerate with:
|
||||
* python tools/extract_calibration.py --variant t06211
|
||||
*/
|
||||
#include "pwm.h"
|
||||
|
||||
/* ── Submap x/y arrays ──────────────────────────────────────────────── */
|
||||
|
||||
static const int16_t setpoint_x[6] = { 8389, 5872, 3775, 2726, 1426, 0 };
|
||||
static const int16_t setpoint_y[6] = { 1707, 1707, 1707, 1195, 768, 427 };
|
||||
static const int16_t setpoint_x[6] = { 8389, 5872, 4614, 2726, 1426, 0 };
|
||||
static const int16_t setpoint_y[6] = { 1707, 1707, 1707, 939, 427, 427 };
|
||||
|
||||
static const int16_t pwm_A_x[9] = { 25166, 18455, 13841, 8389, 5872, 3775, 2726, 1426, 0 };
|
||||
static const int16_t pwm_A_y[9] = { 1707, 1365, 1195, 768, 427, 85, 0, -171, -469 };
|
||||
static const int16_t pwm_A_x[9] = { 25166, 18455, 13841, 8389, 5872, 4614, 2726, 1426, 0 };
|
||||
static const int16_t pwm_A_y[9] = { 1707, 1365, 1195, 768, 427, 85, 0, -171, -469 };
|
||||
|
||||
static const int16_t pwm_B_x[10] = { 1707, 1365, 1195, 768, 427, 85, 0, -171, -469, -512 };
|
||||
static const int16_t pwm_B_y[10] = { 819, 737, 492, 0, 41, 49, 82, 102, 205, 205 };
|
||||
static const int16_t pwm_B_y[10] = { 819, 737, 492, 0, 41, 49, 82, 102, 205, 205 };
|
||||
|
||||
/* T06215 inferred shape map kept verbatim — needs Step 7 follow-up to
|
||||
* re-extract from T06235 for accuracy if shape stage is exercised. */
|
||||
static const int16_t shape_x[4] = { 819, 737, 492, 0 };
|
||||
static const int16_t shape_y[4] = { 41, 49, 82, 102 };
|
||||
static const int16_t shape_y[4] = { 41, 49, 82, 102 };
|
||||
|
||||
/* ── Y-tables ────────────────────────────────────────────────────────── */
|
||||
/* ── Y-tables (dereferenced from pwm_y_table_ptr / shape_y_table_ptr) ── */
|
||||
|
||||
static const int16_t shape_y_table_rom[4] = { 41, 49, 82, 102 };
|
||||
|
||||
/* PWM bilinear Y-table at flash 0x9E20 (T06235; T06215 was 0x9E30) —
|
||||
* 10 rows × 9 cols (90 entries). Re-extracted 2026-05-01 from this
|
||||
* ROM; values differ from T06215 (recalibrated). */
|
||||
static const int16_t pwm_y_table_rom[90] = {
|
||||
/* row 0 */ 205, 205, 205, 205, 205, 205, 205, 205, 0,
|
||||
/* row 1 */ 1638, 1433, 1229, 1024, 819, 205, 205, 205, 0,
|
||||
/* row 2 */ 1843, 1658, 1474, 1229, 1024, 205, 205, 205, 0,
|
||||
/* row 3 */ 2375, 2211, 2068, 1802, 1577, 1167, 205, 205, 0,
|
||||
/* row 4 */ 2744, 2621, 2580, 2457, 2273, 1904, 1372, 205, 0,
|
||||
/* row 5 */ 3358, 3276, 3235, 3194, 3092, 2867, 2539, 1351, 205,
|
||||
/* row 6 */ 3686, 3604, 3522, 3440, 3358, 3215, 2867, 1761, 614,
|
||||
/* row 7 */ 3890, 3890, 3890, 3890, 3890, 3890, 3890, 2518, 1527,
|
||||
/* row 0 */ 205, 205, 205, 205, 205, 205, 0, 0, 0,
|
||||
/* row 1 */ 1638, 1392, 1229, 962, 778, 512, 0, 0, 0,
|
||||
/* row 2 */ 1843, 1577, 1433, 1208, 1003, 758, 0, 0, 0,
|
||||
/* row 3 */ 2457, 2109, 1986, 1761, 1577, 1229, 287, 0, 0,
|
||||
/* row 4 */ 2867, 2744, 2641, 2457, 2314, 2129, 1269, 205, 205,
|
||||
/* row 5 */ 3686, 3481, 3460, 3378, 3276, 3174, 2907, 1024, 737,
|
||||
/* row 6 */ 3890, 3870, 3849, 3829, 3808, 3788, 3235, 1310, 1024,
|
||||
/* row 7 */ 3890, 3890, 3890, 3890, 3890, 3890, 3890, 2076, 1638,
|
||||
/* row 8 */ 3890, 3890, 3890, 3890, 3890, 3890, 3890, 3890, 3481,
|
||||
/* row 9 */ 3890, 3890, 3890, 3890, 3890, 3890, 3890, 3890, 4095,
|
||||
/* row 9 */ 3890, 3890, 3890, 3890, 3890, 3890, 3890, 3890, 3890,
|
||||
};
|
||||
|
||||
/* ── Descriptors ────────────────────────────────────────────────────── */
|
||||
@@ -98,87 +69,96 @@ const int16_t *pwm_submap_y_of(uint16_t idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case PWM_SUBMAP_SETPOINT_INTERP: return setpoint_y;
|
||||
case PWM_SUBMAP_PWM_A: return pwm_A_y;
|
||||
case PWM_SUBMAP_PWM_B: return pwm_B_y;
|
||||
case PWM_SUBMAP_SHAPE_EVAL: return shape_y;
|
||||
default: return NULL;
|
||||
case PWM_SUBMAP_PWM_A: return pwm_A_y;
|
||||
case PWM_SUBMAP_PWM_B: return pwm_B_y;
|
||||
case PWM_SUBMAP_SHAPE_EVAL: return shape_y;
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Scalars ────────────────────────────────────────────────────────── */
|
||||
|
||||
const pwm_calibration_t pwm_cal_rom = {
|
||||
/* PI controller error-band thresholds (T06235 cal+0x122/0x124 = T06215 +0x14) */
|
||||
.large_pos_error_thresh = 128, /* cal+0x122 (was T06215 cal+0x10E) */
|
||||
.large_neg_error_thresh = (int16_t)0xFF00, /* cal+0x124 = -256 */
|
||||
.pi_low_clamp = (int16_t)0xFE00, /* cal+0x13C = -512 */
|
||||
.pi_high_clamp = 1707, /* fallback; runtime uses pi_high_clamp_ceiling */
|
||||
.large_pos_error_thresh = 128, /* cal+0x10E */
|
||||
.large_neg_error_thresh = (int16_t)0xFF00, /* cal+0x110 */
|
||||
.pi_low_clamp = (int16_t)0xFE00, /* cal+0x120 */
|
||||
.pi_high_clamp = 1707, /* cal+0x124 */
|
||||
|
||||
/* CAN-decoded setpoint cal constants (lower region — invariant offsets) */
|
||||
.b_fb_kw_upper_bound = 7680, /* cal+0x004 */
|
||||
.b_fb_kw_lower_bound = (int16_t)0xFD00, /* cal+0x006 */
|
||||
.setpoint_offset = -729, /* cal+0x4e − cal+0x50 = 3499 − 4228 = -729 (T06215 cal+0x4c−cal+0x4e = -648) */
|
||||
.target_5e_min_clamp = (int16_t)0xFE00, /* cal+0x13E = -512 (T06215 cal+0x12A +0x14) */
|
||||
.can_aux_12e_max = 1451, /* cal+0x002 */
|
||||
/* CAN-decoded setpoint (FUN_64c3) cal constants */
|
||||
.b_fb_kw_upper_bound = 7680, /* cal+0x004 */
|
||||
.b_fb_kw_lower_bound = (int16_t)0xFD00, /* cal+0x006 */
|
||||
/* setpoint_offset = cal+0x4c - cal+0x4e = 3499 - 4156 = -657 */
|
||||
.setpoint_offset = (int16_t)0xFD6F,
|
||||
.target_5e_min_clamp = (int16_t)0xFE00, /* cal+0x122 */
|
||||
.can_aux_12e_max = 1451, /* cal+0x002 */
|
||||
|
||||
/* CKP-zero acquisition (FUN_55e0 + FUN_6a4b chain) — values read from
|
||||
* rom_eeprom_dump_0000-9FFF_504042.bin at RWA4 + offset. */
|
||||
.ckp_zero_anchor = 4228, /* cal+0x050 @ 0x9C08 = 0x1084 */
|
||||
.can_dckp_offset_bias = 0, /* cal+0x052 @ 0x9C0A = 0x0000 */
|
||||
.ckp_modulus = 7680, /* cal+0x0A2 @ 0x9C5A = 0x1E00 (90° at 256/3°/unit) */
|
||||
/* CKP-zero acquisition (FUN_6b67 chain) — values re-extracted from
|
||||
* rom_eeprom_dump_0000-9FFF_504012.bin (RWA4=0x9BD8). */
|
||||
.ckp_zero_anchor = 4156, /* cal+0x04E @ 0x9C26 = 0x103C */
|
||||
.can_dckp_offset_bias = -427, /* cal+0x050 @ 0x9C28 = 0xFE55 */
|
||||
.ckp_modulus = 7680, /* cal+0x0A0 @ 0x9C78 = 0x1E00 (90°) */
|
||||
|
||||
/* CKP process-tooth derivation (FUN_6c70 — feeds get_ckp_process_tooth()).
|
||||
* Read direct from rom_eeprom_dump_0000-9FFF_504042.bin at RWA4=0x9BB8
|
||||
* + offset; default-family analogs are at cal+0x120/0x0A3/0x0A4. */
|
||||
.ckp_advance_per_tick = 1707, /* cal+0x140 @ 0x9CF8 = 0x06AB (= 20° per tick;
|
||||
* t06211 cal+0x124, T06215 cal+0x12C, default cal+0x120 = 1536 = 18°) */
|
||||
.ckp_seg_wrap_threshold = 29, /* cal+0x09F @ 0x9C57 (default cal+0x0A3) */
|
||||
.ckp_teeth_per_seg = 26, /* cal+0x0A0 @ 0x9C58 (default cal+0x0A4; same value across all variants) */
|
||||
/* CKP process-tooth derivation (FUN_6d4a @ 0x6d4a). cal+0x124 is
|
||||
* aliased with pi_high_clamp — same value (1707) used by both. */
|
||||
.ckp_advance_per_tick = 1707, /* cal+0x124 @ 0x9CFC = 0x06AB (= 20° per tick;
|
||||
* matches T06215 cal+0x12C semantically). */
|
||||
.ckp_seg_wrap_threshold = 29, /* cal+0x09D @ 0x9C75 (byte) */
|
||||
.ckp_teeth_per_seg = 26, /* cal+0x09E @ 0x9C76 (byte; same value across all variants) */
|
||||
|
||||
/* Recovery / sustained-error machinery */
|
||||
.pi_state_c2_reload = 100, /* cal+0x128 (was T06215 cal+0x114) */
|
||||
.inj_qty_thresh = 96, /* cal+0x12A (was T06215 cal+0x116) */
|
||||
.pi_sat_count_threshold = 800, /* cal+0x126 (was T06215 cal+0x112) */
|
||||
.rpm_threshold_recovery = 2726, /* cal+0x13A (was T06215 cal+0x126; T06215 = 2936 — value Δ) */
|
||||
.pi_cl_rpm_floor = 420, /* flash[0x605C] = 0x01A4 — invariant */
|
||||
.error_thresh_114 = 100, /* cal+0x114 */
|
||||
.pi_thresh_116 = 96, /* cal+0x116 */
|
||||
.pi_sat_count_threshold = 800, /* cal+0x112 = 0x0320 */
|
||||
.rpm_threshold_11E = 2936, /* cal+0x11E */
|
||||
.pi_cl_rpm_floor = 420, /* RAM[0x605c] = 0x01A4 (flash mirror) */
|
||||
|
||||
/* PI runtime-reset values (T06235-extracted from cal block at RWA4=0x9BB8 + offset). */
|
||||
.init_p_shape_bound_pos = +107, /* cal+0x11E (T06215 cal+0x10A) */
|
||||
.init_p_shape_bound_neg = -107, /* cal+0x120 (T06215 cal+0x10C) */
|
||||
.init_p_gain_normal = +368, /* cal+0x12C (T06215 cal+0x118; was +336 — value Δ) */
|
||||
.init_p_slope_large_pos = +2047, /* cal+0x12E (T06215 cal+0x11A; was +1792 — value Δ) */
|
||||
.init_p_slope_large_neg = +512, /* cal+0x130 (T06215 cal+0x11C) */
|
||||
.init_integ_step_normal = +320, /* cal+0x132 (T06215 cal+0x11E; was +256 — value Δ) */
|
||||
.init_integ_step_large_pos = +831, /* cal+0x134 (T06215 cal+0x120; was +512 — value Δ) */
|
||||
.init_integ_step_large_neg = +255, /* cal+0x136 (T06215 cal+0x122; was +256 — value Δ) */
|
||||
.init_open_loop_p_gain = +6, /* cal+0x138 byte (T06215 cal+0x124; same value, clamped to 15) */
|
||||
.pwm_detail_x0 = (int16_t)0x9C40, /* cal+0x0EE */
|
||||
.pwm_detail_x1 = (int16_t)0x8235, /* cal+0x0F0 */
|
||||
.pwm_cached_ptr_0F2 = 5662, /* cal+0x0F2 (legacy scalar) */
|
||||
.pwm_cached_ptr_102 = 168, /* cal+0x102 (legacy scalar) */
|
||||
|
||||
/* CL correction normalizers — boot-cached at DAT_0340/DAT_0342. */
|
||||
.init_pos_error_normalizer = 350, /* cal+0x11C (T06215 cal+0x108) */
|
||||
.init_neg_error_normalizer = 350, /* cal+0x11A (T06215 cal+0x106) */
|
||||
|
||||
/* PWM stage scalars — entire block shifted +0x14 in T06235 */
|
||||
.pwm_detail_x0 = (int16_t)0x9C40, /* cal+0x102 = 40000 unsigned (period_max) */
|
||||
.pwm_detail_x1 = (int16_t)0x8235, /* cal+0x104 = 33333 unsigned (period_min) */
|
||||
.pwm_cached_ptr_0F2 = 5662, /* cal+0x106 (T06215 cal+0x0F2) */
|
||||
.pwm_cached_ptr_102 = 168, /* cal+0x116 = halfwidth (T06215 cal+0x102) */
|
||||
.pwm_const_104 = 354, /* cal+0x118 = slew_step (T06215 cal+0x104) */
|
||||
|
||||
/* RPM-window block — index 1 differs (6795 vs T06215 6837) */
|
||||
/* RPM-window matching: inline 8-int16 band array at cal+0x0F2..0x100
|
||||
* (4 (lo,hi) pairs) plus halfwidth at cal+0x102. Drives the three-
|
||||
* phase pwm_period slew in FUN_5314 (open-questions §5 closeout). */
|
||||
.pwm_rpm_windows = { 5662, 6795, 8808, 10486, 11954, 13422, 18036, 19713 },
|
||||
.pwm_window_halfwidth = 168, /* cal+0x116 */
|
||||
.pwm_slew_step = 354, /* cal+0x118 */
|
||||
.pwm_window_halfwidth = 168,
|
||||
|
||||
.pwm_y_table = pwm_y_table_rom,
|
||||
.shape_y_table = shape_y_table_rom,
|
||||
/* pwm_const_104 / pwm_slew_step are the same value (cal+0x104 = 354);
|
||||
* pwm_const_104 retained for backward compat, pwm_slew_step is the
|
||||
* semantic name used by the RPM-window matcher (per-cycle pwm_period
|
||||
* slew magnitude, applied at Phase 1 / Phase 3). Cached to
|
||||
* RAM[0x02ec] at FUN_5314:0x53b9. */
|
||||
.pwm_const_104 = 354, /* cal+0x104 (legacy alias) */
|
||||
.pwm_slew_step = 354, /* cal+0x104 (semantic) */
|
||||
|
||||
.closed_loop_gain_const = 10, /* flash[0x6056] = 0x000A — invariant */
|
||||
.pwm_y_table = pwm_y_table_rom, /* cal+0x154 @ 0x9E28 */
|
||||
.shape_y_table = shape_y_table_rom, /* cal+0x15E @ 0x9E20 */
|
||||
|
||||
.pwm_period_min = 33333, /* cal+0x104 = 60.0 Hz */
|
||||
.pwm_period_max = 40000, /* cal+0x102 = 50.0 Hz */
|
||||
/* CL-correction gain — cached at absolute ROM[0x6056], not cal-relative. */
|
||||
.closed_loop_gain_const = 10, /* ROM[0x6056] */
|
||||
|
||||
.pwm_min = 0x00CD, /* flash[0x6058] = 205 */
|
||||
.pwm_max = 0x0F32, /* flash[0x605A] = 3890 */
|
||||
/* PI runtime-reset values — boot-derived in ROM (FUN_76aa @ 0x76aa).
|
||||
* Trim bytes at RAM[0x0410-0x0416] have no writers so each cal base
|
||||
* passes through verbatim. Field shape mirrors T06215's
|
||||
* pwm_calibration_t for cross-family consistency. */
|
||||
.init_p_shape_bound_pos = 853, /* cal+0x10A */
|
||||
.init_p_shape_bound_neg = (int16_t)0xFCAB, /* cal+0x10C */
|
||||
.init_p_gain_normal = 480, /* cal+0x118 */
|
||||
.init_integ_step_normal = 256, /* cal+0x11A */
|
||||
.init_open_loop_p_gain = 6, /* cal+0x11C low byte (clamped <=15) */
|
||||
.init_pos_error_normalizer = 350, /* cal+0x108 */
|
||||
.init_neg_error_normalizer = 350, /* cal+0x106 */
|
||||
|
||||
/* PWM period endpoints (alias of pwm_detail_x0/x1) as unsigned. */
|
||||
.pwm_period_min = 33333, /* cal+0x0F0 */
|
||||
.pwm_period_max = 40000, /* cal+0x0EE */
|
||||
|
||||
/* Duty clamp bounds — RAM[0x6058]/RAM[0x605a] flash mirrors with the
|
||||
* same defaults as the default family's pwm_min/pwm_max. */
|
||||
.pwm_min = 0x00CD, /* RAM[0x6058] = 205 */
|
||||
.pwm_max = 0x0F32, /* RAM[0x605a] = 3890 */
|
||||
};
|
||||
|
||||
/* Family-1 API parity placeholder — t06211 keeps Y-tables inside
|
||||
* pwm_cal_rom, so pwm_flash_rom has no data. Callers pass &pwm_flash_rom
|
||||
* to pwm_init() purely for signature compatibility. */
|
||||
const pwm_flash_t pwm_flash_rom = { 0 };
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* @file cal_tables_rom.h (variant/T06235/compact_src)
|
||||
* @brief Extern decls for the ROM-decoded T06235 calibration.
|
||||
* @file cal_tables_rom.h (families/t06211/compact_src)
|
||||
* @brief Extern decls for the ROM-decoded t06211 calibration.
|
||||
* All declarations live in pwm.h; this file just re-exports the enum
|
||||
* and array symbols for the compact_src/pwm.c translation unit.
|
||||
*/
|
||||
#ifndef CAL_TABLES_ROM_T06235_COMPACT_H
|
||||
#define CAL_TABLES_ROM_T06235_COMPACT_H
|
||||
#ifndef CAL_TABLES_ROM_T06211_COMPACT_H
|
||||
#define CAL_TABLES_ROM_T06211_COMPACT_H
|
||||
|
||||
#include "pwm.h"
|
||||
|
||||
#endif /* CAL_TABLES_ROM_T06235_COMPACT_H */
|
||||
#endif /* CAL_TABLES_ROM_T06211_COMPACT_H */
|
||||
|
||||
@@ -1,72 +1,63 @@
|
||||
/*
|
||||
* ckp_acquisition.c
|
||||
* ckp_acquisition.c (variant/T06215/compact_src)
|
||||
*
|
||||
* Created on: May 5, 2026
|
||||
* Author: herli
|
||||
* Mirrors ROM Stage-1 caller @ 0x6330 (LCALL FUN_70d8) → FUN_70d8 @ 0x70d8
|
||||
* for the CKP-zero acquisition path. Body verbatim from T06235; only the
|
||||
* cal-field bindings (ckp_zero_anchor / can_dckp_offset_bias / ckp_modulus)
|
||||
* carry T06215-specific cal slots — see pwm_addr_map.h.
|
||||
*
|
||||
* Mirrors ROM FUN_55e0 @ 0x55e0 → FUN_6a4b @ 0x6a4b for the CKP-zero
|
||||
* acquisition path. See ckp_acquisition.h for the data-flow summary.
|
||||
* Stage-1 caller sequence (T06215 ROM 0x62b0..0x6332):
|
||||
* RW1E = dCKP_OFFSET + cal+0x50 ; biased current
|
||||
* RW1C = SHRA(B_CKP_OFFSET, 1) ; signed half
|
||||
* if RW1C != RW1E:
|
||||
* DAT_01e7 |= 0x80
|
||||
* dCKP_OFFSET = RW1C - cal+0x50
|
||||
* (flash commit gated by AD_resultlo == cal+0xCD)
|
||||
* DAT_01e7 &= 0x7F
|
||||
* LCALL FUN_70d8
|
||||
*
|
||||
* Stage-2 body (FUN_70d8 @ 0x70d8..0x7128):
|
||||
* RW1E = cal+0x4e + DAT_0430
|
||||
* v = RW1E - DAT_0434 - cal+0x50 + (int8_t)DAT_0404
|
||||
* while v < 0 : v += cal+0xa0 ; signed JGE
|
||||
* while v > cal+0xa0 : v -= cal+0xa0 ; signed JLE
|
||||
* DAT_0152 = v
|
||||
* DAT_0150 = cal+0x4c - RW1E
|
||||
*/
|
||||
|
||||
#include "ckp_acquisition.h"
|
||||
#include "pwm.h" /* pwm_cal_rom + shra16 */
|
||||
#include "pwm.h"
|
||||
#include "ee_manager.h"
|
||||
|
||||
/* Inputs */
|
||||
int16_t B_CKP_OFFSET = 0;
|
||||
uint8_t commitCKP_offset = 0;
|
||||
|
||||
/* RAM trims (DAT_0430 word, DAT_0404 signed byte) — see header. */
|
||||
/* RAM trims */
|
||||
int16_t CKP_RAM_TRIM_0430 = 0;
|
||||
int8_t CKP_RAM_TRIM_0404 = 0;
|
||||
|
||||
/* Outputs */
|
||||
int16_t dCKP_OFFSET = 0;
|
||||
int16_t CKP_ZERO_OFFSET = 0;
|
||||
|
||||
/* FUN_6a4b @ 0x6a4b core — DAT_0152 derivation only.
|
||||
*
|
||||
* ROM body (fulldissasembly.txt:20025–20061):
|
||||
* RW1E = cal[+0x50] + DAT_0430
|
||||
* RW1C = RW1E - DAT_0434 - cal[+0x52] + (int8_t)DAT_0404
|
||||
* while RW1C < 0 : RW1C += cal[+0xa2] ; JGE LAB_6a7e (signed)
|
||||
* while RW1C > cal[+0xa2] : RW1C -= cal[+0xa2] ; JLE LAB_6a8c (signed)
|
||||
* DAT_0152 = RW1C
|
||||
*
|
||||
* Side-effects (FUN_6c70 R8F/R90 derivation, DAT_02cb/R2C/R2D clears,
|
||||
* DAT_017a=5, DAT_0278 reload) belong to the CKP-decode synchronization
|
||||
* stage and are intentionally not ported here — see the plan's
|
||||
* "Out of scope" section.
|
||||
*/
|
||||
static void ckp_recompute_zero_offset(void)
|
||||
{
|
||||
int16_t anchor = (int16_t)((int16_t)pwm_cal_rom.ckp_zero_anchor
|
||||
+ CKP_RAM_TRIM_0430);
|
||||
|
||||
/* LDBSE at fulldissasembly.txt:20038 sign-extends the byte to a
|
||||
* word before the ADD. */
|
||||
int16_t v = (int16_t)(anchor
|
||||
- dCKP_OFFSET
|
||||
- pwm_cal_rom.can_dckp_offset_bias
|
||||
+ (int16_t)s_dfi_code);
|
||||
+ (int16_t)s_dfi_code);
|
||||
|
||||
int16_t mod = pwm_cal_rom.ckp_modulus;
|
||||
|
||||
/* Verbatim ROM modulo. JGE/JLE in the ROM are signed compares, so
|
||||
* the loops bracket v into [0, mod] inclusive. Replacing with `%`
|
||||
* would diverge for negative v under C90/C99 implementation-defined
|
||||
* sign-of-remainder rules. */
|
||||
while (v < 0) v = (int16_t)(v + mod);
|
||||
while (v > mod) v = (int16_t)(v - mod);
|
||||
|
||||
CKP_ZERO_OFFSET = v;
|
||||
}
|
||||
|
||||
/* FUN_55e0 @ 0x55e0 entry — detect change in (B_CKP_OFFSET >> 1) and
|
||||
* update dCKP_OFFSET; on change, FUN_6a4b is invoked. We always re-run
|
||||
* FUN_6a4b on the first call so consumers see a coherent
|
||||
* CKP_ZERO_OFFSET even before B_CKP_OFFSET first moves.
|
||||
*/
|
||||
int16_t get_ckp_zero(void)
|
||||
{
|
||||
static uint8_t initialized = 0;
|
||||
@@ -78,10 +69,6 @@ int16_t get_ckp_zero(void)
|
||||
if (halved != biased_now) {
|
||||
dCKP_OFFSET = (int16_t)(halved
|
||||
- pwm_cal_rom.can_dckp_offset_bias);
|
||||
/* commitCKP_offset stays unused per user direction; future hook
|
||||
* for the FUN_56d8 flash-write sequence and the DAT_01e7 bit-7
|
||||
* persist-pending flag. */
|
||||
//(void)commitCKP_offset;
|
||||
ckp_recompute_zero_offset();
|
||||
initialized = 1;
|
||||
} else if (!initialized) {
|
||||
@@ -92,27 +79,28 @@ int16_t get_ckp_zero(void)
|
||||
return CKP_ZERO_OFFSET;
|
||||
}
|
||||
|
||||
/* FUN_6c70 @ 0x6c70 — process-tooth derivation (R90 byte store path).
|
||||
/* FUN_7293 @ 0x7293 — process-tooth derivation (R90 byte store path).
|
||||
*
|
||||
* Translates fulldissasembly.txt:20453–20471 (the second half of FUN_6c70
|
||||
* after the R8F clamp; only the R90 byte path is reproduced here since
|
||||
* R8F is computed by the caller from word[0x152] high byte directly):
|
||||
* Translates t06215 dissasembly.txt:21346–21364 (the second half of
|
||||
* FUN_7293 after the R8F clamp; only the R90 byte path is reproduced
|
||||
* here since R8F is computed by the caller from word[0x152] high byte
|
||||
* directly):
|
||||
*
|
||||
* 6c8b LD RW1C, [0x152] ; CKP_ZERO_OFFSET
|
||||
* 6c90 ADD RW1C, cal+0x140 ; ckp_advance_per_tick
|
||||
* 6c95 INCB R1D ; high byte += 1
|
||||
* 6c97 CMPB R1D, cal+0x09F ; ckp_seg_wrap_threshold (=29)
|
||||
* 6c9c JLE LAB_6ca5
|
||||
* 6c9e SUB RW1C, cal+0x0A2 ; ckp_modulus (low byte=0 → R1D-=30)
|
||||
* 6ca3 SJMP LAB_6cae
|
||||
* LAB_6ca5:
|
||||
* 6ca5 CMPB R1D, cal+0x0A0 ; ckp_teeth_per_seg (=26)
|
||||
* 6caa JLE LAB_6cae
|
||||
* 6cac CLRB R1D
|
||||
* LAB_6cae:
|
||||
* 6cae STB R1D, R90
|
||||
* 72ae LD RW1C, [0x152] ; CKP_ZERO_OFFSET
|
||||
* 72b3 ADD RW1C, cal+0x12C ; ckp_advance_per_tick
|
||||
* 72b8 INCB R1D ; high byte += 1
|
||||
* 72ba CMPB R1D, cal+0x09D ; ckp_seg_wrap_threshold (=29)
|
||||
* 72bf JLE LAB_72c8
|
||||
* 72c1 SUB RW1C, cal+0x0A0 ; ckp_modulus (low byte=0 → R1D-=30)
|
||||
* 72c6 SJMP LAB_72d1
|
||||
* LAB_72c8:
|
||||
* 72c8 CMPB R1D, cal+0x09E ; ckp_teeth_per_seg (=26)
|
||||
* 72cd JLE LAB_72d1
|
||||
* 72cf CLRB R1D
|
||||
* LAB_72d1:
|
||||
* 72d1 STB R1D, R90
|
||||
*
|
||||
* The word SUB at 6c9e operates on RW1C, but cal+0x0A2 = 0x1E00 has a
|
||||
* The word SUB at 72c1 operates on RW1C, but cal+0x0A0 = 0x1E00 has a
|
||||
* zero low byte, so the high byte (R1D) decreases by exactly
|
||||
* (ckp_modulus >> 8) = 30 with no borrow into the low byte. We
|
||||
* therefore reproduce the byte-level effect directly without keeping
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
/*
|
||||
* ckp_acquisition.h
|
||||
* ckp_acquisition.h (variant/t06211/compact_src)
|
||||
*
|
||||
* Created on: May 5, 2026
|
||||
* Author: herli
|
||||
*
|
||||
* Translates the CAN-supplied raw CKP offset (B_CKP_OFFSET, RW134 /
|
||||
* DAT_0134) into the ROM-equivalent runtime delta dCKP_OFFSET (DAT_0434)
|
||||
* and then into the canonical CKP zero-crossing offset CKP_ZERO_OFFSET
|
||||
* (DAT_0152). Mirrors ROM FUN_55e0 @ 0x55e0 → FUN_6a4b @ 0x6a4b.
|
||||
* CKP-zero acquisition chain for t06211. Mirrors ROM Stage-1 caller @
|
||||
* 0x65c7 (LCALL FUN_6b67) → FUN_6b67 @ 0x6b67. Body verbatim from T06235;
|
||||
* cal-field bindings differ — see pwm_addr_map / cal_offsets.py.
|
||||
*/
|
||||
|
||||
#ifndef ADVANCE_CONTROL_CKP_ACQUISITION_H_
|
||||
#define ADVANCE_CONTROL_CKP_ACQUISITION_H_
|
||||
#ifndef PWM_T06211_CKP_ACQUISITION_H
|
||||
#define PWM_T06211_CKP_ACQUISITION_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Inputs */
|
||||
extern int16_t B_CKP_OFFSET; /* RW134 / DAT_0134 — CAN raw input */
|
||||
extern uint8_t commitCKP_offset; /* unused for now (commit gate hook) */
|
||||
extern int16_t B_CKP_OFFSET;
|
||||
extern uint8_t commitCKP_offset;
|
||||
|
||||
/* Internal RAM trims (DAT_0430 word, DAT_0404 signed byte). No runtime
|
||||
* writer was found in this ROM/car (project memory:
|
||||
* project_t06235_ckp_processing.md), so they sit at 0 unless a future
|
||||
* step wires them up. Exposed for diagnostic poking. */
|
||||
extern int16_t CKP_RAM_TRIM_0430;
|
||||
extern int8_t CKP_RAM_TRIM_0404;
|
||||
|
||||
/* Outputs */
|
||||
extern int16_t dCKP_OFFSET; /* DAT_0434 — output of FUN_55e0 */
|
||||
extern int16_t CKP_ZERO_OFFSET; /* DAT_0152 — output of FUN_6a4b */
|
||||
extern int16_t dCKP_OFFSET; /* DAT_0434 */
|
||||
extern int16_t CKP_ZERO_OFFSET; /* DAT_0152 */
|
||||
|
||||
/* Recompute dCKP_OFFSET from B_CKP_OFFSET (FUN_55e0), then recompute
|
||||
* CKP_ZERO_OFFSET (FUN_6a4b core derivation), then return
|
||||
* CKP_ZERO_OFFSET. The commit/flash-persist side-effects (FUN_56d8
|
||||
* sequence + DAT_01e7 bit-7) are stubbed via commitCKP_offset for a
|
||||
* future wiring step.
|
||||
*/
|
||||
int16_t get_ckp_zero(void);
|
||||
|
||||
/* Get the next process-tooth index — mirrors the byte stored to R90
|
||||
* in ROM FUN_6d4a @ 0x6d4a (analog of T06215 FUN_7293 / default
|
||||
* FUN_87ea). Same body shape as T06215; the only difference is the
|
||||
* cal slot for `ckp_advance_per_tick` (cal+0x124 in t06211 vs cal+0x12C
|
||||
* in T06215). cal+0x124 is **aliased** with pi_high_clamp — same flash
|
||||
* word, value 1707, used both as the PI Block-4 ceiling and the
|
||||
* per-tick CKP angular advance.
|
||||
*
|
||||
* advanced = CKP_ZERO_OFFSET + ckp_advance_per_tick (16-bit ADD)
|
||||
* tooth = (advanced >> 8) + 1 (byte INC of high)
|
||||
* if (tooth > ckp_seg_wrap_threshold) (t06211: 29)
|
||||
* tooth -= (ckp_modulus >> 8) (= 30 — angular wrap)
|
||||
* else if (tooth > ckp_teeth_per_seg) (t06211: 26)
|
||||
* tooth = 0 (hard reset)
|
||||
* return tooth;
|
||||
*
|
||||
* No side-effects on CKP_ZERO_OFFSET or dCKP_OFFSET.
|
||||
*/
|
||||
uint8_t get_ckp_process_tooth(void);
|
||||
|
||||
#endif /* ADVANCE_CONTROL_CKP_ACQUISITION_H_ */
|
||||
#endif /* PWM_T06211_CKP_ACQUISITION_H */
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
/**
|
||||
* @file pwm.c (variant/T06235/compact_src)
|
||||
* @brief Compact single-file implementation of the T06235 PWM control
|
||||
* pipeline. Body copied verbatim from variant/T06215/compact_src/pwm.c
|
||||
* per the pillar-port-verbatim rule — T06235's pipeline is a 1:1
|
||||
* structural mirror of T06215 (only addresses + cal offsets shift;
|
||||
* the C body is invariant by design of the semantic field names).
|
||||
* @file pwm.c (families/t06211/compact_src)
|
||||
* @brief Compact single-file implementation of the t06211 PWM control
|
||||
* pipeline. Merges the 10 per-module files from
|
||||
* families/t06211/src/ into one translation unit.
|
||||
*
|
||||
* Pipeline (pwm_service @ 0x7a1e in T06235; analog of T06215 @ 0x7772):
|
||||
* 0. setpoint interp (FUN_732c) — writes pi_high_clamp_ceiling (DAT_0344)
|
||||
* 1. supervisor (FUN_7f12) — reset + counter + error + clamp
|
||||
* 2. publish_cl (FUN_7fca) — calls cl_correction, publishes est_angle
|
||||
* 3. pi_update (FUN_5809) — open/closed-loop PI body
|
||||
* 4. pwm_output (s_pwm_output) — eval+eval+combine+saturate+HW shadow
|
||||
* Pipeline (t06211 FUN_77b3 @ 0x77b3):
|
||||
* 1. setpoint (FUN_7168) — single-submap RPM-indexed interp
|
||||
* 2. supervisor (FUN_7beb) — reset + counter + error + clamp
|
||||
* 3. publish_cl (FUN_7cd8) — calls cl_correction, publishes est_angle
|
||||
* 4. pi_controller (FUN_67c4) — open/closed-loop branch
|
||||
* 5. pwm_output (FUN_5314) — eval+eval+combine+saturate+HW shadow
|
||||
*
|
||||
* The PI block (s_pi_update + s_recovery) was re-translated 1:1 from the
|
||||
* t06215 disasm at 0x542f / 0x53a2 on 2026-04-29. Earlier versions of this
|
||||
* file inherited a t06211-shaped body (separate s_pi_compensation /
|
||||
* s_pi_integrator_step / pi_flag_338 / pi_flag_c7) whose cited addresses
|
||||
* (0x67c4, 0x66ad, 0x672b, 0x7c85) do not exist in this binary.
|
||||
* Per-block address citations follow the families/t06211/src/ per-module
|
||||
* ports verbatim; see those files for expanded commentary.
|
||||
*/
|
||||
#include "pwm.h"
|
||||
|
||||
/* Forward decls. */
|
||||
/* Forward decls for file-static helpers. */
|
||||
static void s_eval_submap(const pwm_submap_descr_t *d,
|
||||
pwm_interp_slot_t *slot);
|
||||
static int16_t s_combine(const int16_t *y_base,
|
||||
@@ -40,8 +35,6 @@ static void s_pi_update (pwm_runtime_t *rt,
|
||||
const pwm_calibration_t *cal);
|
||||
static void s_pwm_output (pwm_runtime_t *rt,
|
||||
const pwm_calibration_t *cal);
|
||||
static void s_recovery (pwm_runtime_t *rt,
|
||||
const pwm_calibration_t *cal);
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Init / binding
|
||||
@@ -50,21 +43,24 @@ static void s_recovery (pwm_runtime_t *rt,
|
||||
static void apply_cal(pwm_runtime_t *rt,
|
||||
const pwm_calibration_t *cal)
|
||||
{
|
||||
/* All boot-derived constants come from cal — no literals here. */
|
||||
rt->setpoint_offset = cal->setpoint_offset;
|
||||
/* All boot-derived constants come from cal — no literals here.
|
||||
* Mirrors FUN_76aa @ 0x76aa, which copies cal+0x108/0x106 into
|
||||
* RAM[0x0332]/[0x0334] (normalizers), cal+0x10A/0x10C into
|
||||
* RAM[0x0450]/[0x0452] (P-shape bounds; trim bytes at RAM[0x414]/
|
||||
* [0x416] have no writers in the ROM so the bases pass through),
|
||||
* cal+0x118/0x11A into RAM[0x0454]/[0x0456] (P-gain + integ step;
|
||||
* same trim-byte note for RAM[0x0410]/[0x0412]), and cal+0x11C
|
||||
* (byte, clamped to 15) into RAM[0x0330]. */
|
||||
rt->setpoint_offset = cal->setpoint_offset;
|
||||
|
||||
rt->p_shape_bound_pos = cal->init_p_shape_bound_pos;
|
||||
rt->p_shape_bound_neg = cal->init_p_shape_bound_neg;
|
||||
rt->p_gain_normal = cal->init_p_gain_normal;
|
||||
rt->integ_step_normal = cal->init_integ_step_normal;
|
||||
rt->p_slope_large_pos = cal->init_p_slope_large_pos;
|
||||
rt->p_slope_large_neg = cal->init_p_slope_large_neg;
|
||||
rt->integ_step_large_pos = cal->init_integ_step_large_pos;
|
||||
rt->integ_step_large_neg = cal->init_integ_step_large_neg;
|
||||
rt->open_loop_p_gain = cal->init_open_loop_p_gain;
|
||||
rt->p_shape_bound_pos = cal->init_p_shape_bound_pos;
|
||||
rt->p_shape_bound_neg = cal->init_p_shape_bound_neg;
|
||||
rt->p_gain_normal = cal->init_p_gain_normal;
|
||||
rt->integ_step_normal = cal->init_integ_step_normal;
|
||||
rt->open_loop_p_gain = cal->init_open_loop_p_gain;
|
||||
|
||||
rt->pos_error_normalizer = cal->init_pos_error_normalizer;
|
||||
rt->neg_error_normalizer = cal->init_neg_error_normalizer;
|
||||
rt->pos_error_normalizer = cal->init_pos_error_normalizer;
|
||||
rt->neg_error_normalizer = cal->init_neg_error_normalizer;
|
||||
}
|
||||
|
||||
static void runtime_reset(pwm_runtime_t *rt)
|
||||
@@ -77,7 +73,7 @@ void pwm_init(pwm_runtime_t *rt,
|
||||
const pwm_flash_t *flash,
|
||||
const pwm_input_getters_t *getters)
|
||||
{
|
||||
(void)flash;
|
||||
(void)flash; /* family-1 API parity; t06211 keeps Y-tables in cal */
|
||||
runtime_reset(rt);
|
||||
rt->bound_cal = cal;
|
||||
rt->bound_getters = getters;
|
||||
@@ -91,18 +87,22 @@ static void read_inputs(pwm_runtime_t *rt)
|
||||
void *ctx = g->ctx;
|
||||
rt->inputs.ckp_in = g->ckp_in (ctx);
|
||||
rt->inputs.rpm = g->rpm (ctx);
|
||||
rt->inputs.angle_dec_cmd = g->angle_dec_cmd (ctx);
|
||||
rt->inputs.angle_dec_cmd = g->angle_dec_cmd (ctx); /* accepted; unused */
|
||||
rt->inputs.inj_qty_demand = g->inj_qty_demand(ctx);
|
||||
rt->inputs.b_fb_kw = g->b_fb_kw (ctx);
|
||||
rt->inputs.cl_gate_input = g->cl_gate_input (ctx);
|
||||
rt->inputs.cl_gate_input = g->cl_gate_input (ctx);
|
||||
rt->inputs.supply_voltage = g->supply_voltage(ctx);
|
||||
rt->inputs.temperature = g->temperature (ctx);
|
||||
rt->inputs.temperature = g->temperature (ctx); /* accepted; unused */
|
||||
|
||||
/* The b_fb_kw getter result drives the CAN-decoded setpoint chain
|
||||
* (FUN_64c3). Mirrors the real ROM where RAM[0x12c] is written by
|
||||
* the CAN parser before FUN_64c3 runs. */
|
||||
rt->can_raw_b_fb_kw = rt->inputs.b_fb_kw;
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Interpolation (FUN_7168, fingerprint #3)
|
||||
* Interpolation — FUN_7168 (0x7168-0x71d7), fingerprint #3
|
||||
* Raw helper; also drives the setpoint stage via descriptor.
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
int16_t pwm_interp_lookup(const int16_t *x, const int16_t *y,
|
||||
@@ -121,11 +121,19 @@ int16_t pwm_interp_lookup(const int16_t *x, const int16_t *y,
|
||||
|
||||
int32_t prod = MUL_S16(num, dy);
|
||||
int16_t quot = (int16_t)(prod / (int32_t)dx);
|
||||
/* Disasm 0x71c5: ADD RW1C, -0x2[RW20]. After the disasm's pointer
|
||||
* advance to the y[] half (0x71b2 ADD RW20, RW1E), RW20 points one
|
||||
* past the breakpoint where the search settled, so -0x2[RW20] is
|
||||
* y at that breakpoint — which is y[k] in C's k-naming (k = first
|
||||
* index where in >= x[k] given descending x). Earlier this returned
|
||||
* y[k-1], producing wrong-polarity setpoints (e.g. pi_high_clamp_ceiling
|
||||
* = 1962 instead of 1195 at rpm=3355). */
|
||||
return (int16_t)(quot + y[k]);
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Submap eval / bilinear combine / refine
|
||||
* Submap eval / bilinear combine / refine — t06211 FUN_6fb8 / FUN_7035 /
|
||||
* FUN_7014. Scratch layout matches the family-1 ROM convention.
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
static void s_eval_submap(const pwm_submap_descr_t *d,
|
||||
@@ -147,6 +155,7 @@ static void s_eval_submap(const pwm_submap_descr_t *d,
|
||||
}
|
||||
|
||||
if (k == 1u && input >= d->x[0]) {
|
||||
/* Upper-clamp sentinel [_, 2, 2, 2] */
|
||||
slot->x_interval = 2;
|
||||
slot->x_offset = 2;
|
||||
slot->y_byte_off = 2;
|
||||
@@ -202,6 +211,7 @@ static int16_t s_refine(const int16_t *y_base,
|
||||
return (int16_t)(y_here + (int32_t)(diff / (int32_t)den));
|
||||
}
|
||||
|
||||
/* Descriptor-driven wrapper used only by the setpoint stage. */
|
||||
static int16_t s_interp_descr(const pwm_submap_descr_t *d,
|
||||
const int16_t *y_array)
|
||||
{
|
||||
@@ -210,8 +220,7 @@ static int16_t s_interp_descr(const pwm_submap_descr_t *d,
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Stage 0 — Setpoint interp (pwm_service:0x7780 → FUN_7051(cal+0x142))
|
||||
* Writes pi_high_clamp_ceiling (DAT_0344 in ROM).
|
||||
* Stage 1 — Setpoint (FUN_77b3:77b3-77c7 + FUN_7168)
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
static void s_setpoint(pwm_runtime_t *rt)
|
||||
@@ -223,20 +232,29 @@ static void s_setpoint(pwm_runtime_t *rt)
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Stage 0b — CAN-decoded setpoint (FUN_64c3 family)
|
||||
* Stage 1b — CAN-decoded setpoint (FUN_64c3 @ 0x64c3-0x650a)
|
||||
* Real ROM call site: FUN_6192:0x61cc (CAN parser dispatcher).
|
||||
* For the C model, invoked from pwm_service after read_inputs so the
|
||||
* harness's per-cycle b_fb_kw value flows into target before PI runs.
|
||||
* Skip the RE7 gate and error path (sim trusts caller).
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
static void s_setpoint_can_decode(pwm_runtime_t *rt,
|
||||
const pwm_calibration_t *cal)
|
||||
{
|
||||
int16_t raw = rt->can_raw_b_fb_kw;
|
||||
/* [0x64ca-0x64d6] Bounds check */
|
||||
if (raw > cal->b_fb_kw_upper_bound) return;
|
||||
if (raw < cal->b_fb_kw_lower_bound) return;
|
||||
|
||||
/* [0x64dd] half = raw >> 1 (SHRA — sign-extending) */
|
||||
int16_t half = shra16(raw, 1);
|
||||
rt->can_half_12a = half;
|
||||
|
||||
/* [0x64e5-0x64ea] result = half + RAM[0x150] + RW42 */
|
||||
int16_t result = (int16_t)(half + rt->setpoint_offset + rt->rw42_state);
|
||||
|
||||
/* [0x64ed-0x64f9] Lower clamp */
|
||||
if (result < cal->target_5e_min_clamp) {
|
||||
result = cal->target_5e_min_clamp;
|
||||
}
|
||||
@@ -244,57 +262,47 @@ static void s_setpoint_can_decode(pwm_runtime_t *rt,
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Stage 1 — Supervisor (s_supervisor @ 0x7d26)
|
||||
*
|
||||
* 1:1 re-translation 2026-04-29. Earlier port body was inherited from
|
||||
* t06211 and used `compensation_angle` (no t06215 producer) and a
|
||||
* `b_fb_kw_baseline` reset stash (no t06215 binding). The actual t06215
|
||||
* supervisor adds the **PI P-term** (DAT_0276) and stashes the
|
||||
* integrator high word into DAT_02ec on reset (a dead store, but kept
|
||||
* here for parity).
|
||||
*
|
||||
* Disasm:
|
||||
* 7d26 LDBZE pi_shape_flag-adjacent (R2E = reset_flag)
|
||||
* 7d2b CMP #1 ; JNE LAB_7d4c
|
||||
* ; --- reset path ---
|
||||
* 7d31 reset_flag = 0
|
||||
* 7d36 cl_enable_counter (DAT_02ee) = 0
|
||||
* 7d3b supervisor_state (RW17E) = 0
|
||||
* 7d40-7d45 DAT_02ec = pi_integ_hi (DAT_028a snapshot — dead store)
|
||||
* 7d4a SJMP LAB_7d5b
|
||||
* ; --- non-reset path ---
|
||||
* LAB_7d4c LD RW1C, cl_enable_counter; RW1E = RW1C+1; ST cl_enable_counter
|
||||
* ; --- common publish ---
|
||||
* LAB_7d5b SUB RW1C, RW5E, ckp_in
|
||||
* ADD RW1C, pi_p_term (DAT_0276)
|
||||
* ST angle_error_raw (DAT_02f0), RW1C
|
||||
* CMP RW1C, pi_high_clamp_ceiling (DAT_0344)
|
||||
* JLE exit
|
||||
* angle_error_raw = pi_high_clamp_ceiling
|
||||
* Stage 2 — Supervisor (FUN_7beb @ 0x7beb-0x7c41)
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
static void s_supervisor(pwm_runtime_t *rt)
|
||||
{
|
||||
/* Reset-flag branch (0x7beb-0x7c0c). Disasm:
|
||||
* 7bf6 reset_flag = 0
|
||||
* 7bfb cl_enable_counter (DAT_033c) = 0
|
||||
* 7c00 supervisor_state (RW17E) = 0
|
||||
* 7c05 LD RW1C, DAT_02b4 ; pi_integ_hi
|
||||
* 7c0a ST RW1C, DAT_033a ; snapshot pi_integ_hi
|
||||
* The DAT_033a store is a dead-store (no readers anywhere in the
|
||||
* ROM); kept here for parity. The earlier port assigned
|
||||
* rt->inputs.b_fb_kw to this slot — that was inherited from the
|
||||
* family-1 idiom and is wrong for this variant. */
|
||||
if (rt->reset_flag == 1u) {
|
||||
rt->reset_flag = 0u;
|
||||
rt->cl_enable_counter = 0u;
|
||||
rt->supervisor_state = 0;
|
||||
rt->pi_integ_hi_snapshot = rt->pi_integ_hi; /* dead-store parity */
|
||||
rt->reset_flag = 0u;
|
||||
rt->cl_enable_counter = 0u;
|
||||
rt->supervisor_state = 0;
|
||||
rt->pi_integ_hi_snapshot = rt->pi_integ_hi; /* dead-store parity */
|
||||
} else {
|
||||
/* Counter tick (0x7c11-0x7c1b) */
|
||||
rt->cl_enable_counter = (uint16_t)(rt->cl_enable_counter + 1u);
|
||||
}
|
||||
|
||||
/* Error compute (0x7c20-0x7c2b)
|
||||
* Disasm: SUB RW1C, RW5E, DAT_02f8 — primary setpoint is target_5e. */
|
||||
int16_t error = (int16_t)(rt->target_5e - rt->inputs.ckp_in);
|
||||
error = (int16_t)(error + rt->pi_p_term);
|
||||
rt->angle_error_raw = error;
|
||||
|
||||
/* Ceiling clamp (0x7c30-0x7c41)
|
||||
* Disasm: CMP RW1C, DAT_0336 — clamp uses RPM-derived ceiling. */
|
||||
if (error > rt->pi_high_clamp_ceiling) {
|
||||
rt->angle_error_raw = rt->pi_high_clamp_ceiling;
|
||||
}
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Stage 2a — Closed-loop correction
|
||||
* Stage 3a — Closed-loop correction (FUN_5f1f @ 0x5f1f-0x5f66)
|
||||
* Fingerprint #10 bit-for-bit match to family-1 algorithm.
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
static void s_cl_correct(pwm_runtime_t *rt,
|
||||
@@ -302,6 +310,7 @@ static void s_cl_correct(pwm_runtime_t *rt,
|
||||
{
|
||||
int16_t correction;
|
||||
|
||||
/* Gate on low byte of cl_enable_counter (0x5f1f-0x5f24). */
|
||||
if ((rt->cl_enable_counter & 0xFFu) == 0u) {
|
||||
correction = 0;
|
||||
} else {
|
||||
@@ -322,7 +331,7 @@ static void s_cl_correct(pwm_runtime_t *rt,
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Stage 2 — Publish CL
|
||||
* Stage 3 — Publish CL (FUN_7cd8 @ 0x7cd8-0x7cea)
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
static void s_publish_cl(pwm_runtime_t *rt,
|
||||
@@ -333,119 +342,202 @@ static void s_publish_cl(pwm_runtime_t *rt,
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Stage 3 — PI controller
|
||||
*
|
||||
* 1:1 re-translation from t06215 disasm s_pi_update @ 0x542f and
|
||||
* s_recovery @ 0x53a2 (live Ghidra session, 2026-04-29). Cross-reference:
|
||||
* the trailing byte rotate at LAB_56e8 (56e8–5708) saves bits 4,5 of the
|
||||
* current cycle into bits 6,7 for next cycle's s_recovery sustained-band
|
||||
* detector.
|
||||
* Stage 4 — PI controller (FUN_67c4 @ 0x67c4 + FUN_66a8 + FUN_672b)
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* s_recovery @ 0x53a2.
|
||||
*
|
||||
* Disasm:
|
||||
* 53a2 LDBZE RW1C, pi_shape_flag ; zero-extended into 16-bit
|
||||
* 53a7 SHL RW1C, #2 ; <<2 (in 16-bit reg)
|
||||
* 53aa LDBZE RW1E, pi_shape_flag
|
||||
* 53af AND RW1C, RW1E ; (flag<<2) & flag
|
||||
* 53b2 CMP RW1C, #0x30
|
||||
* 53b6 JNH LAB_5421 ; <= 0x30 → "no sustained" path
|
||||
* ; --- Sustained large-error detected (this+previous cycle bit4 or bit5) ---
|
||||
* 53b8 LD RW1C, pi_state_118
|
||||
* 53bd CMP RW1C, RAM[0x027a] ; RAM[0x027a] = cal+0x112 boot-cached
|
||||
* 53c2 JNC LAB_53ea ; counter < threshold → gated-increment
|
||||
* ; --- Latch path: counter saturated ---
|
||||
* 53c4 system_flags_110 |= 1
|
||||
* 53d1 pi_state_118 = 0
|
||||
* 53e1 pi_state_c2 = cal[0x114] ; reload cooldown
|
||||
* 53e9 RET
|
||||
* LAB_53ea: ; counter still < threshold
|
||||
* 53f5 CMP rpm, cal[0x126]
|
||||
* 53f8 JLE LAB_542e (RET) ; rpm <= threshold → no increment
|
||||
* 53fa-5407 if (system_flags_110 & 0x30) RET
|
||||
* 540a if pi_state_c2 != 0 RET
|
||||
* 5411 pi_state_118 += 1
|
||||
* 5420 RET
|
||||
* LAB_5421: ; no sustained large-error
|
||||
* 5421 if (system_flags_110 & 1) RET ; latched → keep counter
|
||||
* 5429 pi_state_118 = 0
|
||||
* 542e RET
|
||||
/* FUN_66a8 — saturation-latch recovery handler. Role-equivalent to the
|
||||
* default family's `s_recovery` / `fast_recovery`; same name across
|
||||
* variants for cross-family alignment. Disasm/source mapping (audit
|
||||
* table — keep the cooldown gate and gated-increment branches in this
|
||||
* exact order):
|
||||
* 66ad-66b2 CMPB pi_shape_flag, pi_flag_c6 ; JNE LAB_671d
|
||||
* 66b9-66be CMP pi_state_118, [0x02c0]=cal+0x112 ; JNC LAB_66e6
|
||||
* JNC ⇒ counter < threshold ⇒ gated-increment
|
||||
* fall-through ⇒ counter ≥ threshold ⇒ latch+reset
|
||||
* 66c0-66e5 latch bit0 ; counter = 0 ; pi_state_c2 ← cal+0x114
|
||||
* 66e6-66f4 CMP rpm, [cal+0x11E] ; JLE exit
|
||||
* 66f6-6705 JBS bit4 / JBS bit5 — exit
|
||||
* 6706-670b CMP ZR, pi_state_c2 ; JNE exit
|
||||
* 670d-6717 pi_state_118 += 1
|
||||
* 671d-6725 JBS bit0 exit ; pi_state_118 = 0
|
||||
*/
|
||||
static void s_recovery(pwm_runtime_t *rt,
|
||||
const pwm_calibration_t *cal)
|
||||
{
|
||||
uint16_t flag_u16 = (uint16_t)rt->pi_shape_flag;
|
||||
uint16_t fold = (uint16_t)((flag_u16 << 2) & flag_u16);
|
||||
|
||||
if (fold > 0x30u) {
|
||||
/* Sustained large-error detected. */
|
||||
if ((uint16_t)rt->pi_state_118 < (uint16_t)cal->pi_sat_count_threshold) {
|
||||
/* Counter still below threshold — gated increment. */
|
||||
if ((int16_t)rt->inputs.rpm <= cal->rpm_threshold_recovery) return;
|
||||
if ((rt->system_flags_110 & 0x10u) != 0u) return;
|
||||
if ((rt->system_flags_110 & 0x20u) != 0u) return;
|
||||
if (rt->pi_state_c2 != 0) return;
|
||||
rt->pi_state_118 = (int16_t)(rt->pi_state_118 + 1);
|
||||
} else {
|
||||
/* Saturated — latch + reset. */
|
||||
rt->system_flags_110 = (uint8_t)(rt->system_flags_110 | 0x01u);
|
||||
rt->pi_state_118 = 0;
|
||||
rt->pi_state_c2 = cal->pi_state_c2_reload;
|
||||
}
|
||||
} else {
|
||||
/* No sustained large-error this cycle. */
|
||||
if (rt->pi_shape_flag != rt->pi_flag_c6) {
|
||||
if ((rt->system_flags_110 & 0x01u) == 0u) {
|
||||
rt->pi_state_118 = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* Counter ≥ threshold → latch+reset. Threshold is boot-cached at
|
||||
* RAM[0x02c0] from cal+0x112 by FUN_6b7b:0x6bd4. */
|
||||
if ((uint16_t)rt->pi_state_118 >= (uint16_t)cal->pi_sat_count_threshold) {
|
||||
rt->system_flags_110 = (uint8_t)(rt->system_flags_110 | 0x01u);
|
||||
rt->pi_state_118 = 0;
|
||||
rt->pi_state_c2 = cal->error_thresh_114;
|
||||
return;
|
||||
}
|
||||
/* Gated increment: rpm > rpm_threshold_11E required. */
|
||||
if ((int16_t)rt->inputs.rpm <= cal->rpm_threshold_11E) return;
|
||||
/* Bits 4 or 5 of system_flags abort. */
|
||||
if ((rt->system_flags_110 & 0x30u) != 0u) return;
|
||||
/* c2 cooldown gate — counter advances only after c2 has decayed to 0. */
|
||||
if (rt->pi_state_c2 != 0) return;
|
||||
rt->pi_state_118 = (int16_t)(rt->pi_state_118 + 1);
|
||||
}
|
||||
|
||||
/* FUN_7c85 @ 0x7c85-0x7cbf — PI integrator step. Anti-windup gates
|
||||
* the update direction against pi_flag_c7 (0=in-range, 1=clamped low,
|
||||
* 2=clamped high). Updates the {pi_integ_hi:pi_integ_lo} 32-bit pair.
|
||||
* Disasm:
|
||||
* 7c85 LD RW1C, err
|
||||
* 7c8a MUL RL1C, [0x0456] ; signed 32-bit, RL1C = err*integ_step_normal
|
||||
* 7c90 SHLL RL1C, #0x4 ; RL1C <<= 4
|
||||
* 7c93 JGE LAB_7ca1 ; if signed result >= 0
|
||||
* 7c95-7c9d if pi_flag_c7==1 RET ; (clamped-low → don't push more negative)
|
||||
* 7c9f SJMP LAB_7cab ; else update
|
||||
* LAB_7ca1: if pi_flag_c7==2 RET ; (clamped-high → don't push more positive)
|
||||
* LAB_7cab: integrator += RL1C ; ADD lo, ADDC hi
|
||||
*/
|
||||
static void s_pi_integrator_step(pwm_runtime_t *rt)
|
||||
{
|
||||
int32_t prod = MUL_S16(rt->angle_error_pi, rt->integ_step_normal);
|
||||
int32_t step = (int32_t)((uint32_t)prod << 4);
|
||||
|
||||
if (step >= 0) {
|
||||
if (rt->pi_flag_c7 == 0x02) return; /* anti-windup: clamped-high */
|
||||
} else {
|
||||
if (rt->pi_flag_c7 == 0x01) return; /* anti-windup: clamped-low */
|
||||
}
|
||||
|
||||
/* Combine {hi:lo} as int32 -> add step -> split back. */
|
||||
int32_t accum = ((int32_t)rt->pi_integ_hi << 16)
|
||||
| (uint16_t)rt->pi_integ_lo;
|
||||
accum += step;
|
||||
rt->pi_integ_lo = (int16_t)(accum & 0xFFFF);
|
||||
rt->pi_integ_hi = (int16_t)((accum >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
/* FUN_672b @ 0x672b-0x67c3 — PI compensation + final clamp.
|
||||
* Two arms decided by (pi_flag_338==1 || pi_open_loop_flag==0):
|
||||
* "fresh" → reset pi_integ_hi from a new (err*open_loop_p_gain>>4)+ckp
|
||||
* "settled" → step the integrator via FUN_7c85
|
||||
* Then compute pi_p_term = (p_gain_normal * err) >> 8 and
|
||||
* active_request = pi_p_term + pi_integ_hi, clamped to
|
||||
* [pi_low_clamp, pi_high_clamp_ceiling].
|
||||
*/
|
||||
static void s_pi_compensation(pwm_runtime_t *rt,
|
||||
const pwm_calibration_t *cal)
|
||||
{
|
||||
int16_t error = rt->angle_error_pi;
|
||||
|
||||
/* [0x672b-0x673a] Branch select. */
|
||||
bool fresh = (rt->pi_flag_338 == 0x01) || (rt->pi_open_loop_flag == 0u);
|
||||
|
||||
if (fresh) {
|
||||
/* [LAB_673c 0x673c-0x6762] Reset pi_integ_hi. Disasm:
|
||||
* STB ZRlo, DAT_0338 ; pi_flag_338 = 0
|
||||
* LD RW1C, err
|
||||
* EXT RL1C ; sign-extend to 32-bit
|
||||
* MUL RL1C, [0x0330] ; signed: RL1C = err32 * open_loop_p_gain
|
||||
* SHRA RW1C, #0x4 ; LOW WORD shifted (high word discarded)
|
||||
* ADD RW1C, RW1C, ckp_in
|
||||
* ST RW1C, DAT_02b4 ; pi_integ_hi = result
|
||||
*/
|
||||
rt->pi_flag_338 = 0;
|
||||
int32_t prod = MUL_S16(error, rt->open_loop_p_gain);
|
||||
int16_t scaled = shra16((int16_t)(prod & 0xFFFF), 4);
|
||||
rt->pi_integ_hi = (int16_t)(scaled + rt->inputs.ckp_in);
|
||||
} else {
|
||||
/* [LAB_6764 0x6764] LCALL FUN_7c85 — integrator step. */
|
||||
s_pi_integrator_step(rt);
|
||||
}
|
||||
|
||||
/* [LAB_6767 0x6767-0x6779] pi_p_term = (RL1C = p_gain_normal*err) >> 8.
|
||||
* Disasm:
|
||||
* LD RW1C, [0x0454] ; p_gain_normal (cal+0x118 default +480)
|
||||
* MUL RL1C, err ; RL1C = p_gain_normal * err (signed)
|
||||
* SHRAL RL1C, #0x8 ; arithmetic shift right 8 (32-bit)
|
||||
* ST RW1C, DAT_02b8 ; pi_p_term = lo16
|
||||
*/
|
||||
int32_t comp32 = MUL_S16(rt->p_gain_normal, error);
|
||||
int16_t comp = (int16_t)(shra32(comp32, 8) & 0xFFFF);
|
||||
rt->pi_p_term = comp;
|
||||
|
||||
/* [0x677a-0x677f] active_request = pi_p_term + pi_integ_hi */
|
||||
int16_t combined = (int16_t)(comp + rt->pi_integ_hi);
|
||||
rt->active_request = combined;
|
||||
|
||||
/* [0x6782-0x67a8] Lower clamp: if active_request < pi_low_clamp,
|
||||
* pin to pi_low_clamp and set pi_flag_c7=1. */
|
||||
if (rt->active_request < cal->pi_low_clamp) {
|
||||
rt->active_request = cal->pi_low_clamp;
|
||||
rt->pi_flag_c7 = 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
/* [LAB_67a9 0x67a9-0x67bd] Upper clamp: if active_request >
|
||||
* pi_high_clamp_ceiling, pin to ceiling and set pi_flag_c7=2.
|
||||
* Disasm 0x67a9-0x67b0: CMP RW46, DAT_0336 — upper clamp uses
|
||||
* the RPM-derived ceiling, not the CAN-decoded primary setpoint. */
|
||||
if (rt->active_request > rt->pi_high_clamp_ceiling) {
|
||||
rt->active_request = rt->pi_high_clamp_ceiling;
|
||||
rt->pi_flag_c7 = 0x02;
|
||||
return;
|
||||
}
|
||||
|
||||
/* [LAB_67be 0x67be-0x67c3] In-range: pi_flag_c7 = 0. */
|
||||
rt->pi_flag_c7 = 0;
|
||||
}
|
||||
|
||||
/* s_pi_update @ 0x542f. See doc-comment at top of "Stage 3". */
|
||||
static void s_pi_update(pwm_runtime_t *rt,
|
||||
const pwm_calibration_t *cal)
|
||||
{
|
||||
/* ── Phase A — Open-loop gate [0x542f-0x5489] ──
|
||||
* Disasm: bit-test R110.5; CMP RW130 < 0; CMP rpm < flash[0x605c]. */
|
||||
/* PI CL-gate threshold = cached ROM[0x605c]. Disasm site:
|
||||
* FUN_67c4:67d9 `CMP RW1C, DAT_605c` (literal 0x01A4 = 420). In the
|
||||
* real ECU, cl_gate_input is almost always negative (CAN inactive
|
||||
* sentinel) which forces OL at line 67d4 before this RPM gate is
|
||||
* reached. Lifted to cal->pi_cl_rpm_floor. */
|
||||
int16_t rpm_floor = cal->pi_cl_rpm_floor;
|
||||
bool open_loop = false;
|
||||
if ((rt->system_flags_110 & 0x20u) != 0u) open_loop = true;
|
||||
else if (rt->inputs.cl_gate_input < 0) open_loop = true;
|
||||
else if ((int16_t)rt->inputs.rpm < cal->pi_cl_rpm_floor) open_loop = true;
|
||||
if ((rt->system_flags_110 & 0x20u) != 0u) open_loop = true;
|
||||
else if (rt->inputs.cl_gate_input < 0) open_loop = true;
|
||||
else if ((int16_t)rt->inputs.rpm < rpm_floor) open_loop = true;
|
||||
|
||||
if (open_loop) {
|
||||
/* 0x544b-0x5453: pi_shape_flag |= 0x01 */
|
||||
rt->pi_shape_flag = (uint8_t)(rt->pi_shape_flag | 0x01u);
|
||||
/* 0x5458: DAT_0274 = RW5E */
|
||||
rt->pi_preclamp_out = rt->target_5e;
|
||||
/* 0x5468-0x5482: if (RW5E < cal[0x128]) DAT_0274 = cal[0x128] */
|
||||
if (rt->target_5e < cal->pi_low_clamp) {
|
||||
rt->pi_preclamp_out = cal->pi_low_clamp;
|
||||
rt->pi_open_loop_flag = 0;
|
||||
/* Disasm 0x67e5: LD RW46, RW5E — open-loop assigns the CAN-decoded
|
||||
* primary setpoint, NOT the RPM-derived ceiling. */
|
||||
rt->active_request = rt->target_5e;
|
||||
/* cal+0x120 is a LOWER bound here (disasm: JLT clamps when
|
||||
* active_request < limit). Same constant also serves as the
|
||||
* Block-4 low clamp, hence `pi_low_clamp`. See
|
||||
* families/t06211/src/pi_controller_t06211.c for the full-disasm
|
||||
* annotation. */
|
||||
if (rt->active_request < cal->pi_low_clamp) {
|
||||
rt->active_request = cal->pi_low_clamp;
|
||||
}
|
||||
goto trailing_rotate;
|
||||
goto final_flag;
|
||||
}
|
||||
|
||||
/* ── Phase B — Error-band classify [0x5489-0x554e] ──
|
||||
* Disasm 0x5489: SUB RW1C, RW5E, DAT_02cc → DAT_0278. */
|
||||
int16_t err = (int16_t)(rt->target_5e - rt->estimated_angle);
|
||||
rt->angle_error_pi = err;
|
||||
/* Disasm 0x680a: SUB RW1C, RW5E, DAT_02cc — CL error uses target. */
|
||||
rt->angle_error_pi = (int16_t)(rt->target_5e - rt->estimated_angle);
|
||||
int16_t err = rt->angle_error_pi;
|
||||
|
||||
if (err > cal->large_pos_error_thresh) {
|
||||
/* 0x54a4-0x54af: flag = (flag | 0x10) & 0xDF */
|
||||
rt->pi_shape_flag = (uint8_t)((rt->pi_shape_flag | 0x10u) & 0xDFu);
|
||||
rt->pi_shape_flag = 0;
|
||||
s_recovery(rt, cal);
|
||||
} else if (err < cal->large_neg_error_thresh) {
|
||||
/* 0x54cd-0x54d8: flag = (flag | 0x20) & 0xEF */
|
||||
rt->pi_shape_flag = (uint8_t)((rt->pi_shape_flag | 0x20u) & 0xEFu);
|
||||
/* 0x54dd-0x54f9: JH check is unsigned; matches CMP RW44, cal[0x116]. */
|
||||
if ((uint16_t)rt->inputs.inj_qty_demand > (uint16_t)cal->inj_qty_thresh) {
|
||||
s_recovery(rt, cal);
|
||||
} else {
|
||||
rt->pi_shape_flag = 0x01;
|
||||
if (rt->inputs.inj_qty_demand <= cal->pi_thresh_116) {
|
||||
rt->pi_state_118 = 0;
|
||||
} else {
|
||||
s_recovery(rt, cal);
|
||||
}
|
||||
} else {
|
||||
/* 0x54fb-0x554e: flag &= 0xCF; decrement c2 (clear latch when 0); decrement 118 */
|
||||
rt->pi_shape_flag = (uint8_t)(rt->pi_shape_flag & 0xCFu);
|
||||
if ((uint16_t)rt->pi_state_c2 != 0u) {
|
||||
rt->pi_shape_flag = 0x20;
|
||||
if (rt->pi_state_c2 > 0) {
|
||||
rt->pi_state_c2 = (int16_t)(rt->pi_state_c2 - 1);
|
||||
}
|
||||
if (rt->pi_state_c2 == 0) {
|
||||
@@ -456,125 +548,73 @@ static void s_pi_update(pwm_runtime_t *rt,
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Phase C — P-shape into pi_p_term / pi_p_gain_active [0x554e-0x560c] ── */
|
||||
int32_t pterm32; /* 32-bit accumulator for the SHRAL (>>8) */
|
||||
/* ── Block 4: error-window decision [0x68b7-0x68ef] ──
|
||||
* Strict > / < per disasm JLE 68c9 / JGE 68ed. P-shape bounds at
|
||||
* DAT_0450 / DAT_0452 are set once at boot by FUN_76aa — see
|
||||
* docs/open-questions.md §2 closeout. */
|
||||
if (err > rt->p_shape_bound_pos) {
|
||||
/* 0x555a-0x558f: large-positive arm. */
|
||||
rt->pi_shape_flag = (uint8_t)(rt->pi_shape_flag | 0x02u);
|
||||
rt->pi_p_gain_active = rt->integ_step_large_pos; /* DAT_0286 = DAT_0282 */
|
||||
int32_t slope_part = MUL_S16((int16_t)(err - rt->p_shape_bound_pos),
|
||||
rt->p_slope_large_pos);
|
||||
int32_t anchor_part = MUL_S16(rt->p_gain_normal, rt->p_shape_bound_pos);
|
||||
pterm32 = slope_part + anchor_part;
|
||||
rt->pi_p_term = (int16_t)(shra32(pterm32, 8) & 0xFFFF);
|
||||
rt->active_request = cal->pi_high_clamp;
|
||||
rt->pi_flag_338 = 0x01;
|
||||
} else if (err < rt->p_shape_bound_neg) {
|
||||
/* 0x559d-0x55cc: large-negative arm. */
|
||||
rt->pi_shape_flag = (uint8_t)(rt->pi_shape_flag | 0x02u);
|
||||
rt->pi_p_gain_active = rt->integ_step_large_neg; /* DAT_0286 = DAT_0284 */
|
||||
int32_t slope_part = MUL_S16((int16_t)(err - rt->p_shape_bound_neg),
|
||||
rt->p_slope_large_neg);
|
||||
int32_t anchor_part = MUL_S16(rt->p_gain_normal, rt->p_shape_bound_neg);
|
||||
pterm32 = slope_part + anchor_part;
|
||||
rt->pi_p_term = (int16_t)(shra32(pterm32, 8) & 0xFFFF);
|
||||
rt->active_request = cal->pi_low_clamp;
|
||||
rt->pi_flag_338 = 0x01;
|
||||
} else {
|
||||
/* 0x55e2-0x5607: normal-range arm. */
|
||||
rt->pi_shape_flag = (uint8_t)(rt->pi_shape_flag & 0xFDu);
|
||||
rt->pi_p_gain_active = rt->integ_step_normal; /* DAT_0286 = DAT_0456 */
|
||||
int32_t prod = MUL_S16(rt->p_gain_normal, err);
|
||||
rt->pi_p_term = (int16_t)(shra32(prod, 8) & 0xFFFF);
|
||||
s_pi_compensation(rt, cal);
|
||||
}
|
||||
|
||||
/* ── Phase D — Integrator gate [0x560c-0x5679] ──
|
||||
* Disasm 0x560c-0x5611: if pi_shape_flag.bit0 set (open-loop, but we
|
||||
* returned earlier in that case) → take fast-path that overrides
|
||||
* pi_integ_hi from open_loop_p_gain. We never enter here in the
|
||||
* closed-loop path, but preserve the structure.
|
||||
* 0x563b onward: closed-loop integrator step with anti-windup. */
|
||||
if ((rt->pi_shape_flag & 0x01u) != 0u) {
|
||||
/* Open-loop fast-path (defensive — the open-loop early-return
|
||||
* above means this branch is unreachable from the closed-loop
|
||||
* path; preserved here in case a future cycle enters with bit 0
|
||||
* latched from elsewhere). */
|
||||
int32_t prod = MUL_S16(rt->open_loop_p_gain, err);
|
||||
int16_t shifted = shra16((int16_t)(prod & 0xFFFF), 4);
|
||||
rt->pi_integ_hi = (int16_t)(shifted + rt->inputs.ckp_in);
|
||||
rt->pi_shape_flag = (uint8_t)(rt->pi_shape_flag & 0xFEu);
|
||||
} else {
|
||||
/* 0x563b-0x5654: anti-windup gate via previous-cycle clamp bits. */
|
||||
bool gate_skip;
|
||||
if (err < 0) {
|
||||
gate_skip = (rt->pi_shape_flag & 0x04u) != 0u; /* bit 2: clamped low */
|
||||
} else {
|
||||
gate_skip = (rt->pi_shape_flag & 0x08u) != 0u; /* bit 3: clamped high */
|
||||
}
|
||||
if (!gate_skip) {
|
||||
/* 0x5657-0x5674: 32-bit signed integrator step.
|
||||
* step = (err * pi_p_gain_active) << 4
|
||||
* {hi:lo} += step
|
||||
* MCS-96 SHLL is logical, so cast through unsigned. */
|
||||
int32_t prod = MUL_S16(err, rt->pi_p_gain_active);
|
||||
int32_t step = (int32_t)((uint32_t)prod << 4);
|
||||
int32_t accum = ((int32_t)rt->pi_integ_hi << 16)
|
||||
| (uint16_t)rt->pi_integ_lo;
|
||||
accum += step;
|
||||
rt->pi_integ_lo = (int16_t)(accum & 0xFFFF);
|
||||
rt->pi_integ_hi = (int16_t)((accum >> 16) & 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Phase E — Combine + clamp [0x5679-0x56e3] ── */
|
||||
rt->pi_preclamp_out = (int16_t)(rt->pi_p_term + rt->pi_integ_hi);
|
||||
|
||||
if (rt->pi_preclamp_out < cal->pi_low_clamp) {
|
||||
/* 0x5696-0x56b6: clamp low; flag = (flag & 0xF7) | 4 */
|
||||
rt->pi_preclamp_out = cal->pi_low_clamp;
|
||||
rt->pi_shape_flag = (uint8_t)((rt->pi_shape_flag & 0xF7u) | 0x04u);
|
||||
} else if (rt->pi_preclamp_out > rt->pi_high_clamp_ceiling) {
|
||||
/* 0x56c2-0x56d9: clamp high; flag = (flag & 0xFB) | 8 */
|
||||
rt->pi_preclamp_out = rt->pi_high_clamp_ceiling;
|
||||
rt->pi_shape_flag = (uint8_t)((rt->pi_shape_flag & 0xFBu) | 0x08u);
|
||||
} else {
|
||||
/* 0x56db-0x56e0: in-range — clear bits 2,3 */
|
||||
rt->pi_shape_flag = (uint8_t)(rt->pi_shape_flag & 0xF3u);
|
||||
}
|
||||
|
||||
trailing_rotate:
|
||||
/* ── Trailing rotate [LAB_56e8 0x56e8-0x5708] ──
|
||||
* Disasm 0x56e8: ST DAT_0274, RW46 ; publish active_request
|
||||
* 0x56ed-0x5703: pi_shape_flag = (flag & 0x3F) | ((flag<<2) & 0xC0)
|
||||
* Saves this cycle's bits 4,5 into bits 6,7 for the next cycle's
|
||||
* s_recovery sustained-band detector.
|
||||
*/
|
||||
rt->active_request = rt->pi_preclamp_out;
|
||||
{
|
||||
uint8_t f = rt->pi_shape_flag;
|
||||
rt->pi_shape_flag = (uint8_t)((f & 0x3Fu) | (uint8_t)((f << 2) & 0xC0u));
|
||||
}
|
||||
final_flag:
|
||||
rt->pi_open_loop_flag = 0x01;
|
||||
rt->pi_flag_c6 = rt->pi_shape_flag;
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Stage 4 — PWM output (FUN_5314 @ 0x5314-0x565f)
|
||||
* Stage 5 — PWM output (FUN_5314 @ 0x5314-0x565f)
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
static void s_pwm_output(pwm_runtime_t *rt,
|
||||
const pwm_calibration_t *cal)
|
||||
{
|
||||
/* A. eval pwm_A */
|
||||
s_eval_submap(&pwm_submap_descrs[PWM_SUBMAP_PWM_A],
|
||||
&rt->pwm_slot_a);
|
||||
|
||||
/* B. eval pwm_B */
|
||||
s_eval_submap(&pwm_submap_descrs[PWM_SUBMAP_PWM_B],
|
||||
&rt->pwm_slot_b);
|
||||
|
||||
/* C. combine bilinear */
|
||||
int16_t duty = s_combine(cal->pwm_y_table, &rt->pwm_slot_a, &rt->pwm_slot_b);
|
||||
rt->pwm_duty = (uint16_t)duty;
|
||||
|
||||
/* D. Duty-range classification [0x5361-0x538b] — based on pre-shape duty. */
|
||||
if (rt->pwm_duty < 0x29u) rt->pwm_duty_range_flag = 1u;
|
||||
else if (rt->pwm_duty > 0xFD7u) rt->pwm_duty_range_flag = 2u;
|
||||
else rt->pwm_duty_range_flag = 0u;
|
||||
|
||||
/* E1. RPM-window three-phase matcher [0x53be-0x552a].
|
||||
*
|
||||
* Phase 1 (strict-band): rpm strictly inside any of 4 bands at
|
||||
* cal+0xF2 → slew_increment = +pwm_slew_step.
|
||||
* Phase 2 (hysteresis margin): rpm in any band's halfwidth-extended
|
||||
* region → HOLD (preserve previous slew_increment).
|
||||
* Phase 3 (deep-out): rpm clear of every extended band AND
|
||||
* pwm_period < pwm_period_max → slew_increment = -pwm_slew_step.
|
||||
*
|
||||
* Slew applied as `pwm_period -= slew_increment` (subtraction;
|
||||
* positive increment shrinks period → faster PWM).
|
||||
* pwm_slew_increment lives in rt and persists across cycles so the
|
||||
* HOLD path keeps the previous direction.
|
||||
*
|
||||
* Disasm note: high-edge tests use JC (db) at 0x5463/0x5497 for
|
||||
* bands 0/1 and JNC (d3) at 0x54cb/0x54fd for bands 2/3 — these
|
||||
* encodings produce equivalent control flow (HOLD on rpm < hi+hw,
|
||||
* advance on rpm >= hi+hw). See open-questions.md §5 closeout. */
|
||||
uint16_t *pwm_period = (uint16_t *)&rt->pwm_shape_state[0];
|
||||
const int16_t rpm_s = (int16_t)rt->inputs.rpm;
|
||||
const int16_t halfwidth = cal->pwm_window_halfwidth;
|
||||
const int16_t step_mag = cal->pwm_slew_step;
|
||||
|
||||
/* Phase 1 — strict-band test [0x53be-0x542d] */
|
||||
int slew_set = 0;
|
||||
for (int bi = 0; bi < 4; bi++) {
|
||||
int16_t lo = cal->pwm_rpm_windows[bi * 2];
|
||||
@@ -587,31 +627,38 @@ static void s_pwm_output(pwm_runtime_t *rt,
|
||||
}
|
||||
|
||||
if (!slew_set) {
|
||||
/* Phase 2 — fine hysteresis margin [0x5434-0x54fe] */
|
||||
int phase3 = 1;
|
||||
for (int bi = 0; bi < 4; bi++) {
|
||||
int16_t lo = cal->pwm_rpm_windows[bi * 2];
|
||||
int16_t hi = cal->pwm_rpm_windows[bi * 2 + 1];
|
||||
if (rpm_s <= (int16_t)(lo - halfwidth)) {
|
||||
continue;
|
||||
continue; /* below extended low: try next band */
|
||||
}
|
||||
if (rpm_s < (int16_t)(hi + halfwidth)) {
|
||||
phase3 = 0;
|
||||
phase3 = 0; /* HOLD */
|
||||
break;
|
||||
}
|
||||
/* rpm_s >= hi + halfwidth: advance to next band */
|
||||
}
|
||||
if (phase3 && *pwm_period < cal->pwm_period_max) {
|
||||
/* Phase 3 — deep-out negative slew [0x54ff-0x551b] */
|
||||
rt->pwm_slew_increment = (int16_t)(-step_mag);
|
||||
}
|
||||
/* else: HOLD (no write) */
|
||||
}
|
||||
|
||||
/* Slew application [0x5520-0x552a] */
|
||||
int32_t period_next = (int32_t)*pwm_period - (int32_t)rt->pwm_slew_increment;
|
||||
if (period_next < 0) period_next = 0;
|
||||
if (period_next > 0xFFFF) period_next = 0xFFFF;
|
||||
*pwm_period = (uint16_t)period_next;
|
||||
|
||||
/* Final clamp [0x552f-0x5575] */
|
||||
if (*pwm_period < cal->pwm_period_min) *pwm_period = cal->pwm_period_min;
|
||||
if (*pwm_period > cal->pwm_period_max) *pwm_period = cal->pwm_period_max;
|
||||
|
||||
/* E2. Shape detail [0x557a-0x5608] */
|
||||
pwm_interp_slot_t shape_slot;
|
||||
s_eval_submap(&pwm_submap_descrs[PWM_SUBMAP_SHAPE_EVAL],
|
||||
&shape_slot);
|
||||
@@ -620,6 +667,11 @@ static void s_pwm_output(pwm_runtime_t *rt,
|
||||
if (shape_height > 0x199) shape_height = 0x199;
|
||||
rt->pwm_shape_state[5] = shape_height;
|
||||
|
||||
/* E3. Shape composition additive [0x55cb-0x560f]. ROM formula:
|
||||
* slope = (period_max - period_min) >> 8
|
||||
* numerator = ((period_max - pwm_period) >> 8) * shape_height
|
||||
* pwm_duty += numerator / slope
|
||||
* Shifts happen before multiply (MCS-96 16-bit intermediate). */
|
||||
int16_t slope = (int16_t)(((int32_t)cal->pwm_period_max
|
||||
- (int32_t)cal->pwm_period_min) >> 8);
|
||||
int16_t pmx_delta = (int16_t)(((int32_t)cal->pwm_period_max
|
||||
@@ -629,10 +681,14 @@ static void s_pwm_output(pwm_runtime_t *rt,
|
||||
: 0;
|
||||
int32_t duty_new = (int32_t)rt->pwm_duty + shape_add;
|
||||
|
||||
/* F. Duty bounds clamp [0x5614-0x5636] — ROM reads RAM[0x6058]/[0x605a]
|
||||
* (producers open-questions §3). Lifted to cal->pwm_min/cal->pwm_max
|
||||
* (defaults 205/3890, same as the default family). */
|
||||
if (duty_new < (int32_t)cal->pwm_min) duty_new = (int32_t)cal->pwm_min;
|
||||
if (duty_new > (int32_t)cal->pwm_max) duty_new = (int32_t)cal->pwm_max;
|
||||
rt->pwm_duty = (uint16_t)duty_new;
|
||||
|
||||
/* G. HW shadow writes [0x563b-0x565f] using the slewed pwm_period. */
|
||||
uint32_t on_product = (uint32_t)(*pwm_period) * (uint32_t)rt->pwm_duty;
|
||||
rt->pwm_on_time = (uint16_t)(on_product / 0xFFFu);
|
||||
rt->pwm_off_time = (uint16_t)(*pwm_period - rt->pwm_on_time);
|
||||
@@ -640,7 +696,10 @@ static void s_pwm_output(pwm_runtime_t *rt,
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Bypass-PI LUT helper
|
||||
* Bypass-PI LUT helper: query the ROM Y-table directly with (rpm, fbkw)
|
||||
* as the two axes, applying the same eval+combine+clamp the PWM stage
|
||||
* does. Useful for plotting the static (rpm, fbkw) → duty surface
|
||||
* without the PI controller in the loop.
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
uint16_t pwm_lut_duty(const pwm_calibration_t *cal,
|
||||
@@ -661,7 +720,8 @@ uint16_t pwm_lut_duty(const pwm_calibration_t *cal,
|
||||
}
|
||||
|
||||
/* ═════════════════════════════════════════════════════════════════════
|
||||
* Public entry — pwm_service (mirrors pwm_service @ 0x7780)
|
||||
* Public entry — pwm_service
|
||||
* Mirrors FUN_77b3 (0x77b3-0x77d8) — 5-call linear dispatcher.
|
||||
* ═════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
void pwm_service(pwm_runtime_t *rt)
|
||||
@@ -670,10 +730,10 @@ void pwm_service(pwm_runtime_t *rt)
|
||||
|
||||
const pwm_calibration_t *cal = rt->bound_cal;
|
||||
|
||||
s_setpoint(rt); /* writes pi_high_clamp_ceiling */
|
||||
s_setpoint_can_decode(rt, cal);
|
||||
s_supervisor(rt);
|
||||
s_publish_cl(rt, cal);
|
||||
s_pi_update(rt, cal);
|
||||
s_pwm_output(rt, cal);
|
||||
s_setpoint(rt); /* [0x77b3-0x77c7] pi_high_clamp_ceiling = setpoint_interp(rpm) */
|
||||
s_setpoint_can_decode(rt, cal); /* CAN-decoded target (FUN_64c3 in ROM) */
|
||||
s_supervisor(rt); /* [0x77cc] */
|
||||
s_publish_cl(rt, cal);/* [0x77cf] */
|
||||
s_pi_update(rt, cal); /* [0x77d2] */
|
||||
s_pwm_output(rt, cal);/* [0x77d5] */
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/**
|
||||
* @file pwm.h (variant/T06235/compact_src)
|
||||
* @brief Compact single-header API for the T06235 PWM controller.
|
||||
* @file pwm.h (families/t06211/compact_src)
|
||||
* @brief Compact single-header API for the t06211 PWM controller.
|
||||
*
|
||||
* Variant note: this header was copied verbatim from variant/T06215/compact_src
|
||||
* per the pillar-port-verbatim rule (docs/pillar-functions.md). T06235 is a
|
||||
* recompile of T06215 with a +0x14 cal-block insertion and one RAM slot move
|
||||
* (reset_flag 0x002e → 0x002c) — see variant/T06235/docs/algorithm-diff-vs-T06215.md.
|
||||
* Runtime-struct field names are purely semantic; the address binding for
|
||||
* any field lives in `pwm_addr_map.h` (documentation-only; not included
|
||||
* by pwm.c).
|
||||
* Mirrors the public shape of the default family's `compact_src/pwm.h`
|
||||
* but tailored to t06211's 5-stage pipeline (no standalone max_cl_error
|
||||
* lookup, single-submap setpoint, factor+offset target compute).
|
||||
*
|
||||
* Public API:
|
||||
* Public API is just two functions:
|
||||
* pwm_init() — one-time setup
|
||||
* pwm_service() — per-cycle update (5-stage pipeline)
|
||||
* pwm_service() — per-cycle update (pulls inputs via getters,
|
||||
* runs the 5-stage pipeline, writes rt outputs)
|
||||
*
|
||||
* External inputs arrive through a getter vtable; callbacks return one
|
||||
* signal in native PWM units.
|
||||
* External inputs arrive through a getter vtable; each callback returns
|
||||
* one signal in native PWM units.
|
||||
*
|
||||
* Every arithmetic choice mirrors the MCS-96 assembly; see
|
||||
* families/t06211/src/ for per-stage commentary.
|
||||
*/
|
||||
#ifndef PWM_H
|
||||
#define PWM_H
|
||||
@@ -44,37 +44,49 @@ static inline int32_t shra32(int32_t v, unsigned n) {
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════
|
||||
* 1D INTERPOLATION SLOT
|
||||
* Layout matches family-1's pwm_interp_slot_t and the family-1 ROM
|
||||
* convention [count*2, range, offset, seg_bytes] — t06211's FUN_6fb8
|
||||
* fingerprints identically, so the same layout applies.
|
||||
* ══════════════════════════════════════════════════════════════════════ */
|
||||
typedef struct pwm_interp_slot {
|
||||
int16_t row_stride;
|
||||
int16_t x_interval;
|
||||
int16_t x_offset;
|
||||
int16_t y_byte_off;
|
||||
int16_t row_stride; /* count * 2 (byte stride for Y-table rows) */
|
||||
int16_t x_interval; /* x[k-1] - x[k] */
|
||||
int16_t x_offset; /* input - x[k] */
|
||||
int16_t y_byte_off; /* k * 2 */
|
||||
} pwm_interp_slot_t;
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════
|
||||
* EXTERNAL INPUTS
|
||||
* Populated each cycle by pwm_service via the getter vtable.
|
||||
* t06211-specific set: no temperature, no angle_dec_cmd in the setpoint
|
||||
* (the family-2 setpoint is single-submap RPM-indexed).
|
||||
* ══════════════════════════════════════════════════════════════════════ */
|
||||
typedef struct pwm_inputs {
|
||||
int16_t ckp_in; /* sensed position */
|
||||
uint16_t rpm; /* engine RPM */
|
||||
int16_t angle_dec_cmd; /* accepted for cross-family API parity; unused here */
|
||||
int16_t inj_qty_demand; /* CAN: injection-quantity demand */
|
||||
int16_t b_fb_kw; /* CAN: plunger feedback baseline (drives target) */
|
||||
int16_t cl_gate_input; /* CAN: open/closed-loop discriminant (was state_130) */
|
||||
uint16_t supply_voltage; /* shape_eval submap input */
|
||||
int16_t temperature; /* accepted for cross-family API parity; unused here */
|
||||
int16_t ckp_in; /* 0x02f8 — sensed position */
|
||||
uint16_t rpm; /* 0x0040 — engine RPM */
|
||||
int16_t angle_dec_cmd; /* 0x0042 — accepted for family-1 API parity; unused here */
|
||||
int16_t inj_qty_demand; /* 0x0044 — CAN: inj quantity demand (PI large-neg gate) */
|
||||
int16_t b_fb_kw; /* CAN: plunger feedback baseline. Gets copied into
|
||||
can_raw_b_fb_kw and decoded by s_setpoint_can_decode
|
||||
(port of FUN_64c3) to produce target. */
|
||||
int16_t cl_gate_input; /* 0x0130 — CAN: open/closed-loop discriminant */
|
||||
uint16_t supply_voltage; /* 0x0142 — shape_eval submap input */
|
||||
int16_t temperature; /* 0x0146 — accepted for family-1 API parity; unused here */
|
||||
} pwm_inputs_t;
|
||||
|
||||
/** Getter vtable. 8-callback layout matches family-1's pwm_input_getters_t
|
||||
* so a single FBKW.c can drive either family's pwm.c without changes.
|
||||
* t06211 does not consume angle_dec_cmd or temperature; those getters are
|
||||
* called and stored into rt->inputs but the pipeline ignores them. */
|
||||
typedef struct pwm_input_getters {
|
||||
int16_t (*ckp_in) (void *ctx);
|
||||
uint16_t (*rpm) (void *ctx);
|
||||
int16_t (*angle_dec_cmd) (void *ctx);
|
||||
int16_t (*angle_dec_cmd) (void *ctx); /* accepted; unused by t06211 */
|
||||
int16_t (*inj_qty_demand)(void *ctx);
|
||||
int16_t (*b_fb_kw) (void *ctx);
|
||||
int16_t (*cl_gate_input) (void *ctx);
|
||||
int16_t (*cl_gate_input) (void *ctx);
|
||||
uint16_t (*supply_voltage)(void *ctx);
|
||||
int16_t (*temperature) (void *ctx);
|
||||
int16_t (*temperature) (void *ctx); /* accepted; unused by t06211 */
|
||||
void *ctx;
|
||||
} pwm_input_getters_t;
|
||||
|
||||
@@ -83,95 +95,135 @@ typedef struct pwm_submap_descr pwm_submap_descr_t;
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════
|
||||
* RUNTIME STATE
|
||||
* Field names are purely semantic. ROM-address bindings live in
|
||||
* pwm_addr_map.h (documentation-only).
|
||||
* RAM-address comments reference the t06211 MCS-96 map (see
|
||||
* families/t06211/docs/variable-glossary.md).
|
||||
* ══════════════════════════════════════════════════════════════════════ */
|
||||
typedef struct pwm_runtime {
|
||||
/* External inputs — refreshed each cycle from getters */
|
||||
pwm_inputs_t inputs;
|
||||
|
||||
/* Async flags. */
|
||||
uint8_t reset_flag;
|
||||
uint8_t system_flags_110; /* bit 5 = OL force; bit 0 = recovery latch */
|
||||
/* Async flags.
|
||||
* reset_flag — set on reset edge; supervisor clears.
|
||||
* system_flags_110 — bit 5 forces open-loop; bit 0 is fast-recovery latch.
|
||||
*/
|
||||
uint8_t reset_flag; /* 0x002e */
|
||||
uint8_t system_flags_110; /* 0x0110 */
|
||||
|
||||
/* ── Setpoint architecture ── */
|
||||
/* target_5e: PRIMARY CAN-decoded setpoint (RW5E in t06215). */
|
||||
int16_t target_5e;
|
||||
/* pi_high_clamp_ceiling: SECONDARY RPM-derived ceiling — written each
|
||||
* cycle by pwm_service from the setpoint submap interp; consumed as
|
||||
* the PI integrator output upper-clamp inside s_pi_update and the
|
||||
* supervisor error ceiling. (DAT_0344 in t06215; was misnamed
|
||||
* target_336 in the original fork from t06211.) */
|
||||
/* ── Dual-target setpoint architecture ── */
|
||||
/* target (RW5E = RAM[0x005e]): PRIMARY CAN-driven setpoint
|
||||
* computed by FUN_64c3 (called from CAN parser FUN_6192). Drives
|
||||
* the PI controller in both open-loop (FUN_67c4:67e5) and
|
||||
* closed-loop (FUN_67c4:680a) paths, and supervisor error compute
|
||||
* (FUN_7beb:7c20). Formula: raw/2 + setpoint_offset + rw42_state,
|
||||
* clamped >= cal->target_5e_min_clamp. */
|
||||
int16_t target_5e; /* RW5E — primary CAN-decoded setpoint */
|
||||
/* pi_high_clamp_ceiling (DAT_0336): SECONDARY RPM-derived ceiling
|
||||
* computed by FUN_7168(setpoint_descr) + FUN_77b3:77c7. Used ONLY as
|
||||
* upper-clamp in FUN_672b PI compensation (0x67a9/0x67b0) and
|
||||
* FUN_7beb supervisor (0x7c30/0x7c37). Does not drive control
|
||||
* directly. (Was misnamed `target_336` across earlier ports — the
|
||||
* address-suffixed style hid that this is a PI clamp, not a target.) */
|
||||
int16_t pi_high_clamp_ceiling;
|
||||
|
||||
/* CAN-staging buffers — written before pwm_service so s_setpoint_can_decode
|
||||
* can transform them into target_5e. */
|
||||
int16_t can_raw_b_fb_kw;
|
||||
int16_t can_aux_12e;
|
||||
int16_t can_half_12a;
|
||||
int16_t setpoint_offset; /* runtime copy of cal->setpoint_offset */
|
||||
int16_t rw42_state;
|
||||
int16_t angle_error_raw; /* DAT_02f0 — supervisor's published error */
|
||||
int16_t pi_integ_hi_snapshot; /* DAT_02ec — supervisor reset stash; dead store but kept for parity */
|
||||
uint16_t cl_enable_counter; /* DAT_02ee */
|
||||
/* CAN-staging buffers — written externally before pwm_service so
|
||||
* s_setpoint_can_decode can transform them into target. */
|
||||
int16_t can_raw_b_fb_kw; /* 0x012c — raw b_fb_kw from CAN */
|
||||
int16_t can_aux_12e; /* 0x012e — secondary CAN field (drives rw42_state) */
|
||||
int16_t can_half_12a; /* 0x012a — cached raw>>1 (debug visibility) */
|
||||
/* setpoint_offset (RAM[0x0150]) is copied at runtime_init from
|
||||
* cal.setpoint_offset (mirrors family-1's pattern at
|
||||
* compact_src/pwm.c:66). The REAL ROM derives it at boot via
|
||||
* FUN_6b7b @ 0x6bb5: RAM[0x150] = cal+0x4c - RW1E. Because RW1E's
|
||||
* source at the call site (0x6c46) is in a Ghidra-unrecognised code
|
||||
* region, we expose the field directly through cal so the user can
|
||||
* set it to the match-fitted value without needing to simulate the
|
||||
* full FUN_6b7b boot path. */
|
||||
int16_t setpoint_offset; /* runtime copy of cal->setpoint_offset (DAT_0150 in ROM) */
|
||||
int16_t rw42_state; /* RW42 register — = can_aux_12e when valid */
|
||||
/* DAT_033a — supervisor reset stash: snapshots pi_integ_hi at the
|
||||
* reset edge (FUN_7beb:7c05-7c0a). Dead store (no readers anywhere
|
||||
* in the ROM); kept here for parity with the disasm. NOT a baseline
|
||||
* of b_fb_kw — that name was inherited from the family-1 idiom and
|
||||
* is incorrect for this variant. */
|
||||
int16_t pi_integ_hi_snapshot;
|
||||
/* PI P-term — produced by FUN_672b @ 0x6775 as `(p_gain_normal * err) >> 8`
|
||||
* and consumed by the supervisor at FUN_7beb:0x7c26 as the additive
|
||||
* shaping term on the error. (DAT_02b8 in ROM; was named
|
||||
* `compensation_angle` in earlier ports.) */
|
||||
int16_t pi_p_term;
|
||||
int16_t angle_error_raw; /* DAT_033e — supervisor output (raw + ceiling-clamped) */
|
||||
uint16_t cl_enable_counter; /* DAT_033c */
|
||||
|
||||
/* ── CL correction ── */
|
||||
int16_t cl_correction_raw;
|
||||
int16_t angle_offset;
|
||||
int16_t supervisor_state;
|
||||
int16_t pos_error_normalizer; /* runtime copy of cal->pos_error_normalizer */
|
||||
int16_t neg_error_normalizer; /* runtime copy of cal->neg_error_normalizer */
|
||||
int16_t cl_correction_raw; /* DAT_0176 */
|
||||
int16_t angle_offset; /* DAT_017c */
|
||||
int16_t supervisor_state; /* RW17E — CL accumulator */
|
||||
int16_t pos_error_normalizer; /* runtime copy of cal->init_pos_error_normalizer (DAT_0332 in ROM) */
|
||||
int16_t neg_error_normalizer; /* runtime copy of cal->init_neg_error_normalizer (DAT_0334 in ROM) */
|
||||
|
||||
/* ── Publish + PI ── */
|
||||
int16_t estimated_angle;
|
||||
int16_t angle_error_pi; /* target_5e − estimated_angle (DAT_0278) */
|
||||
int16_t active_request; /* PI output = pre-clamp output (RW46 + DAT_0274) */
|
||||
int16_t estimated_angle; /* DAT_02cc */
|
||||
int16_t angle_error_pi; /* DAT_02be — target_5e − estimated_angle */
|
||||
int16_t active_request; /* RW46 — published PI output / PWM feed-forward */
|
||||
uint8_t pi_open_loop_flag; /* DAT_02c4 */
|
||||
uint8_t pi_shape_flag; /* DAT_02c5 */
|
||||
uint8_t pi_flag_c6; /* DAT_02c6 — previous-cycle pi_shape_flag latch */
|
||||
uint8_t pi_flag_338; /* DAT_0338 — Block-4 cal-pinned latch */
|
||||
|
||||
/* PI flag byte (DAT_028c). Bit layout (s_pi_update @ 0x542f):
|
||||
* bit 0 = open-loop indicator (consumed by integrator gate)
|
||||
* bit 1 = P-shape large-error arm taken
|
||||
* bit 2 = output clamped to pi_low_clamp this cycle
|
||||
* bit 3 = output clamped to pi_high_clamp_ceiling this cycle
|
||||
* bit 4 = error > large_pos_error_thresh this cycle
|
||||
* bit 5 = error < large_neg_error_thresh this cycle
|
||||
* bits 6,7 = previous cycle's bits 4,5 (rotated by trailing op) */
|
||||
uint8_t pi_shape_flag;
|
||||
/* P-shape segment bounds (boot-init from cal+0x10A/0x10C). PI Block-4
|
||||
* error-window bounds (independent int16s, NOT a 32-bit integrator).
|
||||
* Trim bytes at RAM[0x0414]/[0x0416] have no writers in the ROM, so
|
||||
* bounds resolve to the cal bases verbatim. See open-questions §2. */
|
||||
int16_t p_shape_bound_pos; /* DAT_0450 */
|
||||
int16_t p_shape_bound_neg; /* DAT_0452 */
|
||||
|
||||
/* PI working state used by s_pi_update */
|
||||
int16_t pi_p_term; /* DAT_0276 — output of P-shape segment */
|
||||
int16_t pi_p_gain_active; /* DAT_0286 — selected gain for integrator step */
|
||||
int16_t pi_preclamp_out; /* DAT_0274 — pre-publish active_request */
|
||||
int16_t pi_state_118; /* DAT_0118 — recovery counter */
|
||||
int16_t pi_state_c2; /* DAT_02c2 — cooldown counter */
|
||||
|
||||
/* PI integrator pair {hi:lo} = {DAT_028a:DAT_0288} */
|
||||
int16_t pi_integ_lo;
|
||||
int16_t pi_integ_hi;
|
||||
/* PI integrator pair {hi:lo} at {DAT_02b4 : DAT_02b6}. Disasm
|
||||
* `disasm_nav rw 0x02b4` shows only internal writers (FUN_672b,
|
||||
* FUN_76aa, FUN_7c85), confirming this is a PI integrator state,
|
||||
* not an external/CAN input. (Was misnamed `b_fb_kw` in the original
|
||||
* glossary; renamed via the address-suffixed `pi_b4_state`/`pi_b6_state`
|
||||
* intermediate; final semantic name aligns with the cross-family pair.) */
|
||||
int16_t pi_integ_hi; /* DAT_02b4 — integrator high word */
|
||||
int16_t pi_integ_lo; /* DAT_02b6 — integrator low word */
|
||||
|
||||
/* P-shape segment bounds (boot-init from cal+0x10A/0x10C). */
|
||||
int16_t p_shape_bound_pos;
|
||||
int16_t p_shape_bound_neg;
|
||||
/* PI gains — boot-set by FUN_76aa from cal scalars (with optional
|
||||
* trim bytes at RAM[0x0410]/[0x0412] which have no writers anywhere
|
||||
* in the ROM, so the cal bases pass through unchanged). */
|
||||
int16_t p_gain_normal; /* DAT_0454 — boot from cal+0x118; multiplier in pi_p_term = (gain*err)>>8 */
|
||||
int16_t integ_step_normal; /* DAT_0456 — boot from cal+0x11A; multiplier in FUN_7c85 integrator step */
|
||||
int16_t open_loop_p_gain; /* DAT_0330 — boot from cal+0x11C byte (clamped ≤15); used in `pi_integ_hi = (gain*err)>>4 + ckp` reset branch */
|
||||
|
||||
/* P-shape gains and integrator steps (boot-init from cal). */
|
||||
int16_t p_gain_normal; /* DAT_0454 — normal-range P-term multiplier */
|
||||
int16_t integ_step_normal; /* DAT_0456 — normal-range integrator multiplier */
|
||||
int16_t p_slope_large_pos; /* DAT_027e */
|
||||
int16_t p_slope_large_neg; /* DAT_0280 */
|
||||
int16_t integ_step_large_pos; /* DAT_0282 */
|
||||
int16_t integ_step_large_neg; /* DAT_0284 */
|
||||
int16_t open_loop_p_gain; /* DAT_033e (byte, boot-clamped to 15) */
|
||||
|
||||
int16_t pi_state_118; /* recovery counter */
|
||||
int16_t pi_state_c2; /* cooldown counter */
|
||||
/* Anti-windup flag set by FUN_672b clamps; consulted by FUN_7c85
|
||||
* to gate integration direction. Values: 0 (in-range), 1 (clamped
|
||||
* low), 2 (clamped high). */
|
||||
uint8_t pi_flag_c7; /* DAT_02c7 */
|
||||
|
||||
/* ── PWM output ── */
|
||||
uint16_t pwm_duty;
|
||||
uint16_t pwm_on_time;
|
||||
uint16_t pwm_off_time;
|
||||
uint16_t pwm_duty; /* 0x02d2 */
|
||||
uint16_t pwm_on_time; /* 0x02ce */
|
||||
uint16_t pwm_off_time; /* 0x02d0 */
|
||||
/* pwm_period — total period in Timer2 ticks = on_time + off_time.
|
||||
* Mirrored from t06211 RAM[0x02e4] (computed each cycle by the PWM
|
||||
* output stage). Exposed for family-1 FBKW.c API parity
|
||||
* (UpdatePWM(&htim4, ch, pwm_on_time, pwm_period)). */
|
||||
uint16_t pwm_period;
|
||||
uint8_t pwm_duty_range_flag;
|
||||
pwm_interp_slot_t pwm_slot_a;
|
||||
pwm_interp_slot_t pwm_slot_b;
|
||||
int16_t pwm_shape_state[6];
|
||||
int16_t pwm_slew_increment;
|
||||
uint8_t pwm_duty_range_flag; /* 0x00d1 */
|
||||
pwm_interp_slot_t pwm_slot_a; /* 0x02d4 */
|
||||
pwm_interp_slot_t pwm_slot_b; /* 0x02dc */
|
||||
/* pwm_shape_state[6] mirrors RAM[0x02e4..0x02ee]:
|
||||
* [0] pwm_period working value (RAM 0x02e4)
|
||||
* [1] (unused — was slew_increment, broken out as field below)
|
||||
* [2] (RAM 0x02e8 — ROM band-array ptr, unused in C)
|
||||
* [3] (RAM 0x02ea — ROM halfwidth ptr, unused in C)
|
||||
* [4] (RAM 0x02ec — slew step magnitude, unused; read from cal)
|
||||
* [5] shape_height (RAM 0x02ee, E2 output) */
|
||||
int16_t pwm_shape_state[6]; /* 0x02e4-0x02ee */
|
||||
/* Persistent slew_increment (RAM[0x02e6]). Carried across cycles so
|
||||
* the hysteresis-margin HOLD path can preserve previous direction.
|
||||
* Subtracted from pwm_period each cycle. See open-questions §5. */
|
||||
int16_t pwm_slew_increment; /* 0x02e6 */
|
||||
|
||||
/* ── Bindings (set once by pwm_init) ── */
|
||||
const pwm_calibration_t *bound_cal;
|
||||
@@ -180,93 +232,122 @@ typedef struct pwm_runtime {
|
||||
|
||||
/* ── Calibration (decoded ROM values) ───────────────────────────────── */
|
||||
struct pwm_calibration {
|
||||
/* PI controller error-band thresholds */
|
||||
/* Scalars (from families/t06211/cal_offsets.py FLASH_OFFSETS) */
|
||||
int16_t large_pos_error_thresh; /* cal+0x10E */
|
||||
int16_t large_neg_error_thresh; /* cal+0x110 */
|
||||
int16_t pi_low_clamp; /* cal+0x128 — output low clamp + open-loop lower bound */
|
||||
int16_t pi_high_clamp; /* fallback upper clamp; runtime uses pi_high_clamp_ceiling */
|
||||
int16_t pi_low_clamp; /* cal+0x120 = -512 — Block-4 low clamp + open-loop lower bound */
|
||||
int16_t pi_high_clamp; /* cal+0x124 = +1707 — Block-4 high clamp */
|
||||
|
||||
/* CAN-decoded setpoint (FUN_64c3 family) cal constants */
|
||||
int16_t b_fb_kw_upper_bound; /* cal+0x004 */
|
||||
int16_t b_fb_kw_lower_bound; /* cal+0x006 */
|
||||
int16_t setpoint_offset; /* = cal+0x4c − cal+0x4e */
|
||||
int16_t target_5e_min_clamp; /* cal+0x12A */
|
||||
int16_t can_aux_12e_max; /* cal+0x002 */
|
||||
/* CAN-decoded setpoint (FUN_64c3) cal constants */
|
||||
int16_t b_fb_kw_upper_bound; /* cal+0x004 = +7680 — raw b_fb_kw upper sanity bound */
|
||||
int16_t b_fb_kw_lower_bound; /* cal+0x006 = -768 — raw b_fb_kw lower sanity bound */
|
||||
|
||||
/* CKP-zero acquisition (FUN_55e0 + FUN_6a4b chain) cal constants */
|
||||
int16_t ckp_zero_anchor; /* cal+0x050 — FUN_6a4b additive anchor */
|
||||
int16_t can_dckp_offset_bias; /* cal+0x052 — FUN_55e0/FUN_6a4b bias */
|
||||
int16_t ckp_modulus; /* cal+0x0A2 — FUN_6a4b modulo wrap (also reused
|
||||
* by the FUN_6c70 process-tooth derivation
|
||||
* below; high byte = ckp_modulus>>8 = 30). */
|
||||
/* CKP process-tooth derivation (FUN_6c70 @ 0x6c70 — analog of default-
|
||||
* family FUN_87ea @ 0x87ea). Computes the byte stored to R90: a
|
||||
* segment-counter view of (CKP_ZERO_OFFSET + advance) with wrap rules.
|
||||
* Consumed by get_ckp_process_tooth() in ckp_acquisition.c. */
|
||||
int16_t ckp_advance_per_tick; /* cal+0x140 — angular advance added to
|
||||
* word[0x152] before tooth derivation
|
||||
* (T06235: 1707 = 20° at 85.33/°). */
|
||||
int16_t ckp_seg_wrap_threshold; /* cal+0x09F — tooth-counter test:
|
||||
* if tooth > threshold → tooth -= 30
|
||||
* (T06235: 29). */
|
||||
int16_t ckp_teeth_per_seg; /* cal+0x0A0 — per-segment clamp:
|
||||
* if tooth > teeth_per_seg → tooth = 0
|
||||
* (T06235: 26 teeth / 90° segment). */
|
||||
/* setpoint_offset — static bias added after halving raw b_fb_kw.
|
||||
* Family-1 analog: CAL+0x0052 - CAL+0x0054 (compact_src/pwm.h:210).
|
||||
* For t06211, FUN_6b7b computes the equivalent as cal+0x4c - cal+0x4e
|
||||
* (= 3499 - 4156 = -657) at boot and stores at RAM[0x150].
|
||||
* Copied into runtime.setpoint_offset by runtime_reset. */
|
||||
int16_t setpoint_offset; /* = cal+0x4c - cal+0x4e */
|
||||
int16_t target_5e_min_clamp; /* cal+0x122 = -512 — RW5E lower clamp */
|
||||
int16_t can_aux_12e_max; /* cal+0x002 — upper bound for RAM[0x12e] (FUN_649e) */
|
||||
|
||||
/* Recovery / sustained-error machinery */
|
||||
int16_t pi_state_c2_reload; /* cal+0x114 — reload value for pi_state_c2 on latch */
|
||||
int16_t inj_qty_thresh; /* cal+0x116 — inj-qty threshold for recovery vs reset */
|
||||
int16_t pi_sat_count_threshold; /* cal+0x112 — recovery counter latch threshold */
|
||||
int16_t rpm_threshold_recovery; /* cal+0x126 — s_recovery RPM gate (was wrongly cal+0x11E in t06211 idiom) */
|
||||
int16_t pi_cl_rpm_floor; /* flash[0x605C] — s_pi_update OL gate threshold */
|
||||
/* CKP-zero acquisition (FUN_6b67 chain — caller @ 0x65c7).
|
||||
* Slot offsets verified at FUN_6b67:0x6b71/0x6b81/0x6b93 + Stage-1
|
||||
* caller @ 0x654f/0x656d. */
|
||||
int16_t ckp_zero_anchor; /* cal+0x04E — FUN_6b67 additive anchor */
|
||||
int16_t can_dckp_offset_bias; /* cal+0x050 — Stage-1/Stage-2 bias */
|
||||
int16_t ckp_modulus; /* cal+0x0A0 — FUN_6b67 modulo wrap (also
|
||||
* reused by FUN_6d4a process-tooth
|
||||
* below; high byte = ckp_modulus>>8 = 30). */
|
||||
|
||||
/* PI runtime-reset values (boot-derived in ROM; cal-resident here so
|
||||
* each variant carries its own values without code edits). */
|
||||
/* CKP process-tooth derivation (FUN_6d4a @ 0x6d4a — analog of T06215
|
||||
* FUN_7293 / default FUN_87ea). Same body shape; cal slot for the
|
||||
* per-tick advance is at cal+0x124 (NOT cal+0x12C as in T06215),
|
||||
* verified as the sole `TABLE[RWA4]` reader at FUN_6d4a:0x6d6a.
|
||||
* Consumed by get_ckp_process_tooth() in ckp_acquisition.c.
|
||||
*
|
||||
* Note: cal+0x124 is **aliased** with `pi_high_clamp` (FUN_67c4
|
||||
* reads it via the indirect cal-address idiom at 0x68c3/0x68d9).
|
||||
* The value 1707 happens to serve both roles in this ROM. */
|
||||
int16_t ckp_advance_per_tick; /* cal+0x124 — angular advance per tick
|
||||
* (t06211: 1707 = same value as
|
||||
* pi_high_clamp; alias by coincidence). */
|
||||
int16_t ckp_seg_wrap_threshold; /* cal+0x09D — tooth-counter test
|
||||
* (t06211: 29; if tooth > threshold
|
||||
* → tooth -= 30). */
|
||||
int16_t ckp_teeth_per_seg; /* cal+0x09E — per-segment clamp
|
||||
* (t06211: 26 teeth / 90° segment;
|
||||
* if tooth > teeth_per_seg → 0). */
|
||||
int16_t error_thresh_114; /* cal+0x114 */
|
||||
int16_t pi_thresh_116; /* cal+0x116 */
|
||||
/* pi_state_118 saturation threshold — when the recovery counter
|
||||
* reaches this, FUN_66a8 latches bit0 of system_flags_110, zeroes
|
||||
* the counter, and reloads pi_state_c2 from error_thresh_114.
|
||||
* Boot-cached at RAM[0x02c0] by FUN_6b7b:0x6bd4. ROM literal 0x0320 = 800. */
|
||||
int16_t pi_sat_count_threshold; /* cal+0x112 */
|
||||
int16_t rpm_threshold_11E; /* cal+0x11E — RPM gate inside FUN_66a8 */
|
||||
/* Closed-loop entry RPM floor (FUN_67c4:0x67d9). Sourced from
|
||||
* RAM[0x605c] (flash mirror; ROM literal 0x01A4 = 420). */
|
||||
int16_t pi_cl_rpm_floor;
|
||||
|
||||
int16_t pwm_detail_x0; /* cal+0x0EE */
|
||||
int16_t pwm_detail_x1; /* cal+0x0F0 */
|
||||
int16_t pwm_cached_ptr_0F2; /* cal+0x0F2 — first RPM-window breakpoint (legacy scalar) */
|
||||
int16_t pwm_cached_ptr_102; /* cal+0x102 — window halfwidth (legacy scalar) */
|
||||
int16_t pwm_const_104; /* cal+0x104 */
|
||||
|
||||
/* RPM-window matching for pwm_period slew (ROM 0x538b-0x5575).
|
||||
* Eight breakpoints at cal+0xF2 define four bands (lo,hi); the
|
||||
* cal+0x102 halfwidth adds hysteresis. RPM INSIDE any band drives
|
||||
* pwm_period toward pwm_period_min (→ non-zero shape contribution
|
||||
* adds ~49 duty ticks). RPM OUTSIDE all bands drives pwm_period
|
||||
* toward pwm_period_max (→ zero contribution; Y-table floor). */
|
||||
int16_t pwm_rpm_windows[8]; /* cal+0xF2 — 4 (lo,hi) pairs */
|
||||
int16_t pwm_window_halfwidth; /* cal+0x102 — hysteresis halfwidth */
|
||||
/* Per-cycle slew step magnitude for pwm_period. Sourced from
|
||||
* cal+0x104 (= 354); cached to RAM[0x02ec] at FUN_5314:0x53b9 and
|
||||
* read at the Phase 1 and Phase 3 sites. Aliases pwm_const_104 —
|
||||
* same offset, semantic name. */
|
||||
int16_t pwm_slew_step; /* cal+0x104 — slew magnitude */
|
||||
|
||||
const int16_t *pwm_y_table; /* cal+0x154 (indirect) */
|
||||
const int16_t *shape_y_table; /* cal+0x15E (indirect) */
|
||||
|
||||
int16_t closed_loop_gain_const; /* cached at ROM 0x6056 = 0x000A */
|
||||
|
||||
/* PI runtime-reset values — boot-derived in ROM (FUN_76aa @ 0x76aa);
|
||||
* cal-resident here so each variant carries its own values without
|
||||
* code edits. Trim bytes at RAM[0x0410-0x0416] have no writers in the
|
||||
* ROM (EEPROM trim slots, default 0), so each cal base is used
|
||||
* verbatim — see open-questions §2 closeout. Field shape mirrors
|
||||
* T06215's pwm_calibration_t for cross-family consistency. */
|
||||
int16_t init_p_shape_bound_pos; /* cal+0x10A — copied to rt->p_shape_bound_pos */
|
||||
int16_t init_p_shape_bound_neg; /* cal+0x10C — copied to rt->p_shape_bound_neg */
|
||||
int16_t init_p_gain_normal; /* cal+0x118 — copied to rt->p_gain_normal */
|
||||
int16_t init_integ_step_normal; /* cal+0x11E — copied to rt->integ_step_normal */
|
||||
int16_t init_p_slope_large_pos; /* cal+0x11A — copied to rt->p_slope_large_pos */
|
||||
int16_t init_p_slope_large_neg; /* cal+0x11C — copied to rt->p_slope_large_neg */
|
||||
int16_t init_integ_step_large_pos;/* cal+0x120 — copied to rt->integ_step_large_pos */
|
||||
int16_t init_integ_step_large_neg;/* cal+0x122 — copied to rt->integ_step_large_neg */
|
||||
int16_t init_open_loop_p_gain; /* cal+0x124 byte, clamped to 15 — copied to rt->open_loop_p_gain */
|
||||
int16_t init_integ_step_normal; /* cal+0x11A — copied to rt->integ_step_normal */
|
||||
int16_t init_open_loop_p_gain; /* cal+0x11C byte clamped to 15 — copied to rt->open_loop_p_gain */
|
||||
int16_t init_pos_error_normalizer;/* cal+0x108 — copied to rt->pos_error_normalizer */
|
||||
int16_t init_neg_error_normalizer;/* cal+0x106 — copied to rt->neg_error_normalizer */
|
||||
|
||||
/* CL correction normalizers (RAM in ROM, cal-resident here for parity). */
|
||||
int16_t init_pos_error_normalizer;
|
||||
int16_t init_neg_error_normalizer;
|
||||
uint16_t pwm_period_min; /* hypothesised; see cal_tables_rom.c */
|
||||
uint16_t pwm_period_max; /* hypothesised */
|
||||
|
||||
/* PWM stage scalars */
|
||||
int16_t pwm_detail_x0;
|
||||
int16_t pwm_detail_x1;
|
||||
int16_t pwm_cached_ptr_0F2;
|
||||
int16_t pwm_cached_ptr_102;
|
||||
int16_t pwm_const_104;
|
||||
|
||||
int16_t pwm_rpm_windows[8];
|
||||
int16_t pwm_window_halfwidth;
|
||||
int16_t pwm_slew_step;
|
||||
|
||||
const int16_t *pwm_y_table;
|
||||
const int16_t *shape_y_table;
|
||||
|
||||
int16_t closed_loop_gain_const;
|
||||
|
||||
uint16_t pwm_period_min;
|
||||
uint16_t pwm_period_max;
|
||||
uint16_t pwm_min;
|
||||
uint16_t pwm_max;
|
||||
/* PWM duty clamp bounds — RAM[0x6058]/RAM[0x605a] flash mirrors.
|
||||
* Defaults 0x00CD/0x0F32 match the default family's pwm_min/pwm_max. */
|
||||
uint16_t pwm_min; /* RAM[0x6058] cache */
|
||||
uint16_t pwm_max; /* RAM[0x605a] cache */
|
||||
};
|
||||
|
||||
/* ── Submap descriptor ──────────────────────────────────────────────── */
|
||||
struct pwm_submap_descr {
|
||||
uint16_t flags;
|
||||
const int16_t *input_ptr;
|
||||
uint16_t count;
|
||||
const int16_t *x;
|
||||
uint16_t flags; /* +0 */
|
||||
const int16_t *input_ptr; /* +2 (bound at runtime) */
|
||||
uint16_t count; /* +4 */
|
||||
const int16_t *x; /* +6 */
|
||||
uint16_t input_addr;
|
||||
};
|
||||
|
||||
/** Bind descriptor input_ptr fields to rt inputs. */
|
||||
static inline void pwm_bind_submap_inputs(
|
||||
pwm_runtime_t *rt,
|
||||
pwm_submap_descr_t *descrs,
|
||||
@@ -287,8 +368,15 @@ static inline void pwm_bind_submap_inputs(
|
||||
* PUBLIC API
|
||||
* ══════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/** pwm_flash_t — placeholder for family-1 API parity. Family-1 has Y-tables
|
||||
* in a separate `pwm_flash_t` struct; t06211 keeps them inside
|
||||
* pwm_calibration_t so this struct is empty. Kept so FBKW.c / callers
|
||||
* can pass &pwm_flash_rom without the call failing. */
|
||||
typedef struct pwm_flash { char _unused; } pwm_flash_t;
|
||||
|
||||
/** 4-argument init matching family-1's pwm_init signature. The `flash`
|
||||
* pointer is accepted (must be non-NULL — pass &pwm_flash_rom) and
|
||||
* ignored by the t06211 pipeline. */
|
||||
void pwm_init(pwm_runtime_t *rt,
|
||||
const pwm_calibration_t *cal,
|
||||
const pwm_flash_t *flash,
|
||||
@@ -296,17 +384,44 @@ void pwm_init(pwm_runtime_t *rt,
|
||||
|
||||
void pwm_service(pwm_runtime_t *rt);
|
||||
|
||||
/** @brief CKP-edge reset hook — call from the CKP interrupt handler.
|
||||
*
|
||||
* Sets rt->reset_flag = 1 so the next pwm_service() call zeroes the
|
||||
* closed-loop accumulator (supervisor_state) and the enable counter
|
||||
* (cl_enable_counter). Byte store is atomic on all mainstream targets;
|
||||
* no locking required as long as it is not called concurrently with
|
||||
* pwm_service().
|
||||
*
|
||||
* Pattern parity with the default family. See
|
||||
* docs/re-guide-ckp-reset-pattern.md for the full rationale.
|
||||
*
|
||||
* **Variant note for t06211:** the reset_flag producer is **absent from
|
||||
* the ROM** (no STB #1 site writing to 0x002e). The supervisor at 0x7beb
|
||||
* still consumes reset_flag == 1 and clears it, but nothing inside the
|
||||
* ROM ever sets it. Consequence: the accumulator walk-off hazard is
|
||||
* structurally identical to family-1, and the application layer must
|
||||
* drive this hook itself at engine-rev rate (typically 4 pulses per
|
||||
* revolution on VP44, ~12–15 scheduler cycles apart at 1200 rpm with a
|
||||
* 1 kHz scheduler). Without it, supervisor_state integrates forever.
|
||||
*/
|
||||
static inline void pwm_ckp_isr(pwm_runtime_t *rt) { rt->reset_flag = 1; }
|
||||
|
||||
/** Utility: 1D descending-X piecewise-linear lookup. */
|
||||
int16_t pwm_interp_lookup(const int16_t *x, const int16_t *y,
|
||||
uint16_t n, int16_t in);
|
||||
|
||||
/** Utility: bypass-PI bilinear LUT — eval(pwm_A, rpm), eval(pwm_B, fbkw),
|
||||
* combine over Y-table, then apply [205, 3890] clamp. Use this to query
|
||||
* the ROM Y-table directly as a (rpm, fbkw) lookup, skipping the PI
|
||||
* controller entirely. Returns the clamped duty. */
|
||||
uint16_t pwm_lut_duty(const pwm_calibration_t *cal,
|
||||
uint16_t rpm, int16_t fbkw);
|
||||
|
||||
/* ── ROM-decoded cal + flash placeholder (defined in cal_tables_rom.c) ── */
|
||||
extern const pwm_calibration_t pwm_cal_rom;
|
||||
extern const pwm_flash_t pwm_flash_rom;
|
||||
|
||||
/** Descriptor array indices. */
|
||||
enum pwm_submap_id {
|
||||
PWM_SUBMAP_SETPOINT_INTERP = 0,
|
||||
PWM_SUBMAP_PWM_A = 1,
|
||||
|
||||
@@ -54,11 +54,13 @@
|
||||
/* ===== Extern RAM variables declared elsewhere ===== */
|
||||
extern uint16_t BitStatus;
|
||||
extern float PHI_AD;
|
||||
extern float RPM;
|
||||
extern float RPM, MT_offset_RPM, MT_RPM;
|
||||
extern float Temp;
|
||||
extern float ME, MEPI, B_FB_KW, dFi, B_PHIAD;
|
||||
extern int16_t B_FB_NW;
|
||||
extern int16_t B_CKP_OFFSET;
|
||||
extern int8_t s_dfi_code;
|
||||
extern int16_t rw3e, rw3c, rw164;
|
||||
|
||||
extern uint8_t cilCount, safetySHUTOFF;
|
||||
extern uint8_t inj_mode, request_syncout_activation, commitCKP_offset;
|
||||
@@ -97,6 +99,7 @@ static const CanScaleDef SCALE_ME_RAM = { "mg/H", 1.0f/32.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_DC = { "%", 100.0f/4095.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_TEIN = { "uS", 1.0f/2.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_RPM = { "1/min", 1.0f/4.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_RPM_OUT = { "1/min", 1.0f/8.388f, 0.0f };
|
||||
|
||||
static const CanScaleDef SCALE_VOLTAGE= { "V", 0.0185f, -0.05f };
|
||||
|
||||
@@ -151,6 +154,14 @@ const CanAddressEntry CAN_ANSWERS[] = {
|
||||
|
||||
{ 0x7800, &T_ein, CAN_SYM_UX, &SCALE_TEIN , CAN_STORE_FLOAT },
|
||||
{ 0x4201, &PSG_Voltage, CAN_SYM_UX, &SCALE_VOLTAGE, CAN_STORE_FLOAT },
|
||||
{ 0x3E00, &rw3e, CAN_SYM_SX, NULL, CAN_STORE_S16 },
|
||||
{ 0x3C00, &rw3c, CAN_SYM_SX, NULL, CAN_STORE_S16 },
|
||||
|
||||
{ 0x6401, &rw164, CAN_SYM_SX, NULL, CAN_STORE_S16 },
|
||||
|
||||
{ 0x4000, &MT_RPM, CAN_SYM_UX, &SCALE_RPM_OUT, CAN_STORE_FLOAT },
|
||||
{ 0x3801, &MT_offset_RPM, CAN_SYM_UX, &SCALE_RPM_OUT, CAN_STORE_FLOAT },
|
||||
|
||||
{ 0x4400, &ME, CAN_SYM_UX, &SCALE_ME_RAM, CAN_STORE_FLOAT },
|
||||
{ 0x4800, &PHI_AD, CAN_SYM_SX, &SCALE_DEG_KW, CAN_STORE_FLOAT },
|
||||
{ 0x4C00, &actual_phi1, CAN_SYM_SX, &SCALE_DEG_KW, CAN_STORE_FLOAT },
|
||||
@@ -301,7 +312,7 @@ static CanSymbolDef SYM_ID_SEND1[] = {
|
||||
|
||||
#elif defined(T06215)
|
||||
{ "MESOLL", 0, 12, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &ME, &SCALE_ME, CAN_STORE_FLOAT},
|
||||
{ "B_PHIAD", 12, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_PHIAD, &SCALE_PHIAD, CAN_STORE_FLOAT},
|
||||
{ "B_PHIAD", 16, 16, CAN_ENDIAN_INTEL, CAN_SYM_SX, 0,0, &B_PHIAD, &SCALE_PHIAD, CAN_STORE_FLOAT},
|
||||
{ "FB_KW", 32, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_FB_KW, &SCALE_FBKW, CAN_STORE_FLOAT},
|
||||
{ "FB_NW", 48, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_FB_NW, &SCALE_FBKW, CAN_STORE_FLOAT},
|
||||
#elif defined(T15021) || defined(T31804)
|
||||
@@ -327,7 +338,7 @@ static CanSymbolDef SYM_ID_SEND4[] = {
|
||||
#endif
|
||||
|
||||
static CanSymbolDef SYM_ID_SEND3[] = {
|
||||
#if defined(T06235)
|
||||
#if defined(T06235) || defined(T06215) || defined(T06211)
|
||||
|
||||
{ "CKP_OFFSET", 0, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_CKP_OFFSET, NULL, CAN_STORE_S16},
|
||||
{ "commit", 16, 1, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &commitCKP_offset, NULL, CAN_STORE_U8},
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
//#define T15021 //audi 506 -> 030 033
|
||||
//#define T31804 //audi 506 -> 037 038
|
||||
//#define T06209 //eq: T06216
|
||||
//#define T06211
|
||||
#define T06215
|
||||
#define T06235 //no hace nada pero habria que verificar vcon la t06215
|
||||
|
||||
|
||||
#define _504042
|
||||
|
||||
/* FORD */
|
||||
@@ -38,7 +40,7 @@
|
||||
|
||||
/* ALL FBKW */
|
||||
|
||||
#define FBKW_FEEDBACK_ZERO 49.571
|
||||
#define FBKW_FEEDBACK_ZERO 49.571 //49.559
|
||||
|
||||
#define FBKW_FEEDBACK_MIN -5.367
|
||||
#define FBKW_FEEDBACK_MAX 21.27
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
//#define T15021 //audi 506 -> 030 033
|
||||
//#define T31804 //audi 506 -> 037 038
|
||||
//#define T06209 //eq: T06216
|
||||
//#define T06211
|
||||
#define T06215
|
||||
#define T06235 //no hace nada pero habria que verificar vcon la t06215
|
||||
#define T06211
|
||||
|
||||
|
||||
#define _504042
|
||||
#define _504012
|
||||
|
||||
/* FORD */
|
||||
#define FORD_SYNC_PULSE_OUT 0
|
||||
@@ -40,24 +37,18 @@
|
||||
|
||||
/* ALL FBKW */
|
||||
|
||||
#define FBKW_FEEDBACK_ZERO 49.571 //49.559
|
||||
#define FBKW_FEEDBACK_ZERO 53.719
|
||||
|
||||
#define FBKW_FEEDBACK_MIN -5.367
|
||||
#define FBKW_FEEDBACK_MAX 21.27
|
||||
|
||||
#define FBKW_FEEDBACK_IC_DT 19
|
||||
#define FBKW_FEEDBACK_IC_DT 18
|
||||
|
||||
/* CAN DEFINITIONS */
|
||||
#define CAN_BAUDRATE 500
|
||||
#define CAN_RPM_SEND_ASYNC 250
|
||||
#define CAN_EMPF2_INSTANT 0
|
||||
|
||||
/* ALL FUELMAP */
|
||||
#define FM_N_RPM 6
|
||||
#define FM_N_ME 11
|
||||
#define FM_N_T 5
|
||||
|
||||
|
||||
/* PEAK AND HOLD */
|
||||
#define PH_PEAK_DEF 600
|
||||
|
||||
|
||||
@@ -749,6 +749,116 @@ static void compute_accel_comp_offset(runtime_state_t *rt, const calibration_t *
|
||||
(void)rw1c; /* rw1c is discarded after MUL; preserved for block-mapping */
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
* tooth_isr / reset_tooth_state — port of FUN_51e1 @ 0x51e1 (producer)
|
||||
* and FUN_5210 @ 0x5210 (DIVU helper) from the T06215 ROM.
|
||||
*
|
||||
* The producer fires once per cylinder when R88 == cal_byte_56 (= 13).
|
||||
* It computes rpm_baseline = 0x0F000000 / period_ticks where period is
|
||||
* the elapsed EPA timer ticks between two consecutive phase-13 hits.
|
||||
* ====================================================================== */
|
||||
|
||||
/* 0x0F000000 = 251,658,240 — the fixed dividend (cal+0xA2:cal+0xA4). */
|
||||
#define RPM_DIVIDEND_HI ((uint16_t)0x0F00u)
|
||||
#define RPM_DIVIDEND_LO ((uint16_t)0x0000u)
|
||||
|
||||
/* Period saturation (cal+0xA6:cal+0xA8) = 0x001B7740 = 1,800,000 ticks. */
|
||||
#define PERIOD_CLAMP_LO ((uint16_t)0x7740u)
|
||||
#define PERIOD_CLAMP_HI ((uint16_t)0x001Bu)
|
||||
|
||||
/* 0x5210–0x529c: period_to_rpm_div helper (FUN_5210). */
|
||||
static int16_t period_to_rpm_div(uint16_t period_lo, uint16_t period_hi)
|
||||
{
|
||||
/* 0x5255–0x526a: period saturation. */
|
||||
if (period_hi > PERIOD_CLAMP_HI) {
|
||||
period_lo = PERIOD_CLAMP_LO;
|
||||
period_hi = PERIOD_CLAMP_HI;
|
||||
} else if (period_hi == PERIOD_CLAMP_HI) {
|
||||
if (period_lo > PERIOD_CLAMP_LO) {
|
||||
period_lo = PERIOD_CLAMP_LO;
|
||||
period_hi = PERIOD_CLAMP_HI;
|
||||
}
|
||||
}
|
||||
|
||||
/* 0x526f–0x5274: load dividend RL1C = 0x0F000000. */
|
||||
uint16_t rw1c = RPM_DIVIDEND_LO;
|
||||
uint16_t rw1e = RPM_DIVIDEND_HI;
|
||||
|
||||
/* 0x5279–0x527c: if high word == 0, simple 32÷16 DIVU. */
|
||||
if (period_hi == 0u) {
|
||||
/* 0x527e: DIVU RL1C, RW80. */
|
||||
if (period_lo == 0u) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t dividend = ((uint32_t)rw1e << 16) | (uint32_t)rw1c;
|
||||
rw1c = (uint16_t)(dividend / (uint32_t)period_lo);
|
||||
} else {
|
||||
/* 0x5283–0x5295: long-period scaling loop. */
|
||||
uint8_t shift_count = 0u;
|
||||
uint32_t divisor = ((uint32_t)period_hi << 16) | (uint32_t)period_lo;
|
||||
while ((divisor >> 16) != 0u) {
|
||||
divisor >>= 1;
|
||||
shift_count++;
|
||||
}
|
||||
uint32_t dividend = ((uint32_t)rw1e << 16) | (uint32_t)rw1c;
|
||||
uint16_t scaled_divisor = (uint16_t)divisor;
|
||||
if (scaled_divisor == 0u) {
|
||||
return 0;
|
||||
}
|
||||
rw1c = (uint16_t)(dividend / (uint32_t)scaled_divisor);
|
||||
/* 0x5292: SHR RW1C, R20 — rescale quotient. */
|
||||
rw1c >>= shift_count;
|
||||
}
|
||||
|
||||
return (int16_t)rw1c;
|
||||
}
|
||||
|
||||
void phi_tooth_isr(phi_state_t *state,
|
||||
const phi_cal_t *cal,
|
||||
uint8_t current_tooth,
|
||||
uint16_t current_capture)
|
||||
{
|
||||
runtime_state_t *rt = &state->rt;
|
||||
|
||||
/* 0x7aa4–0x7aa9: gate on phase comparand. */
|
||||
if (current_tooth != cal->cal_byte_56) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* First call after reset: seed snapshot, skip divide. */
|
||||
if (!rt->mt_rpm_seeded) {
|
||||
rt->mt_rpm_capture_prev = current_capture;
|
||||
rt->mt_rpm_index_prev = 0u;
|
||||
rt->rpm_baseline = 0;
|
||||
rt->mt_rpm_seeded = 1u;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 0x5247–0x524b: SUB RW80, RW64, [RW1C]+ / SUBC RW82, [RW1C]. */
|
||||
uint16_t period_lo = (uint16_t)(current_capture - rt->mt_rpm_capture_prev);
|
||||
uint16_t borrow = (current_capture < rt->mt_rpm_capture_prev) ? 1u : 0u;
|
||||
uint16_t period_hi = (uint16_t)(0u - rt->mt_rpm_index_prev - borrow);
|
||||
|
||||
/* 0x524e–0x5251: persist new snapshot. */
|
||||
rt->mt_rpm_capture_prev = current_capture;
|
||||
rt->mt_rpm_index_prev = 0u;
|
||||
|
||||
/* 0x5255–0x5298: helper → quotient. */
|
||||
int16_t result = period_to_rpm_div(period_lo, period_hi);
|
||||
|
||||
/* 0x51ec: ST RW1C, 0x138. */
|
||||
rt->rpm_baseline = result;
|
||||
}
|
||||
|
||||
void phi_reset_tooth_state(phi_state_t *state)
|
||||
{
|
||||
runtime_state_t *rt = &state->rt;
|
||||
rt->rpm_baseline = 0;
|
||||
rt->mt_rpm_capture_prev = 0u;
|
||||
rt->mt_rpm_index_prev = 0u;
|
||||
rt->mt_rpm_seeded = 0u;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1:1 translation of the RPM-hysteresis block at 0x7801–0x7825 inside
|
||||
* the orphan scheduler at 0x77FF (T06211 variant). Bytes were not
|
||||
@@ -1052,6 +1162,10 @@ void phi_init(phi_state_t *state, const phi_cal_t *cal,
|
||||
* already zeroed rt->rw9c / rt->rw9e (mirrors FUN_6ba3 @ 0x6bbf–0x6bc1). */
|
||||
state->rt.temp_phi_comp_r94 = 100u;
|
||||
|
||||
/* Tooth-ISR pipeline: memset already zeroed mt_rpm_capture_prev,
|
||||
* mt_rpm_index_prev, rpm_baseline, and mt_rpm_seeded — matching
|
||||
* reset_toothed_wheel @ 0x5301 boot behaviour. */
|
||||
|
||||
/* Bake scratch_0221 = 1 — FUN_62a2's early-out gate. In the live
|
||||
* ROM this is written by FUN_5a97 with an RPM-correlated condition
|
||||
* via RW68 (whose actual writer lives in the unreadable ROM gap
|
||||
@@ -1078,7 +1192,8 @@ void phi_service(phi_state_t *state, const phi_cal_t *cal, phi_outputs_t *out)
|
||||
rt->inj_qty_demand = g->get_inj_qty_demand();
|
||||
rt->angle_dec_cmd = g->get_angle_dec_cmd();
|
||||
rt->temperature = g->get_temperature();
|
||||
rt->rpm_baseline = g->get_rpm_baseline();
|
||||
/* rpm_baseline is now produced internally by tooth_isr (FUN_51e1);
|
||||
* no longer pulled from a getter. */
|
||||
rt->rwc2 = g->get_rwc2();
|
||||
rt->reset_gate_0226 = g->get_reset_gate_0226();
|
||||
rt->dphi = g->get_dphi();
|
||||
|
||||
@@ -102,7 +102,14 @@ typedef struct {
|
||||
int16_t dphi; /* *(0x014c) — angle delta. */
|
||||
|
||||
/* ---- Inputs to FUN_732d (compute_accel_comp_offset) ---- */
|
||||
int16_t rpm_baseline; /* *(0x0138) — slow RPM baseline. */
|
||||
int16_t rpm_baseline; /* *(0x0138) — RPM baseline produced internally by tooth_isr
|
||||
* (FUN_51e1 @ 0x51e1). No longer an external input. */
|
||||
|
||||
/* ---- Tooth-ISR pipeline state (FUN_51e1 @ 0x51e1 + FUN_5210 @ 0x5210) ---- */
|
||||
uint16_t mt_rpm_capture_prev; /* *(0x02A8) — RW64 from previous phase-13 hit */
|
||||
uint16_t mt_rpm_index_prev; /* *(0x02AA) — RW7E (capture index) at previous hit */
|
||||
uint8_t mt_rpm_seeded; /* 0 = first phase-13 after reset; skip divide and seed only */
|
||||
|
||||
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. */
|
||||
@@ -150,6 +157,7 @@ typedef struct {
|
||||
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_56; /* CAL_byte[0x56] — tooth phase comparand for rpm_baseline producer (= 0x0D = 13). */
|
||||
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. */
|
||||
@@ -216,7 +224,6 @@ typedef struct {
|
||||
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) */
|
||||
@@ -251,6 +258,19 @@ void phi_service(phi_state_t *state,
|
||||
* runtime_state_t. */
|
||||
void phi_tick_1khz(phi_state_t *state, const phi_cal_t *cal);
|
||||
|
||||
/** Per-accepted-tooth ISR entry point. Updates rt->rpm_baseline when
|
||||
* current_tooth == cal->cal_byte_56 (=13). No-op for other phases.
|
||||
* The caller invokes this once per accepted tooth event at HSI.0 rate,
|
||||
* separate from the phi_service scheduler cadence. */
|
||||
void phi_tooth_isr(phi_state_t *state,
|
||||
const phi_cal_t *cal,
|
||||
uint8_t current_tooth,
|
||||
uint16_t current_capture);
|
||||
|
||||
/** Clear the tooth-ISR pipeline (mirrors reset_toothed_wheel @ 0x5301).
|
||||
* Next phi_tooth_isr call will seed without dividing. */
|
||||
void phi_reset_tooth_state(phi_state_t *state);
|
||||
|
||||
size_t phi_state_size(void);
|
||||
size_t phi_cal_size(void);
|
||||
|
||||
|
||||
@@ -159,6 +159,7 @@ calibration_t phi_t06215_cal = {
|
||||
.tein_nominal = (int16_t)0x0C28, /* CAL+0x1E @ 0x9BF6 -- tein_nominal — nominal TE_IN base added to tein_valve_fault_guard / tein_overtemp_guard (T06211 FUN_7453 0x747b; T06215 FUN_74EA -- see README) */
|
||||
.cal_48 = (int16_t)0x04B0, /* CAL+0x48 @ 0x9C20 -- RW7A latch value when FUN_62a2 fires (0x62d8) */
|
||||
.phi0 = (int16_t)0x0DAB, /* CAL+0x4C @ 0x9C24 -- phi0: base/initial angle. ROM addend baked into phi1 (= *(0x014e)) by FUN_6aaf (0x6ad2); T06211 FUN_7453 reads phi0 + dphi at 0x74a2 */
|
||||
.cal_byte_56 = 0x0Du, /* CAL+0x56 @ 0x9C2E -- tooth phase comparand for rpm_baseline producer (FUN_51e1 at Tooth_scheduler? 0x7aa4) */
|
||||
.cal_byte_9c = 0x03u, /* CAL+0x9C @ 0x9C74 -- FUN_62a2 counter increment (0x62c6) */
|
||||
.cal_54 = (int16_t)0x0B2B, /* CAL+0x54 @ 0x9C2C -- UPPER clamp on target_inj_angle (T06211 FUN_7453 0x7493) */
|
||||
.cal_74 = (int16_t)0x20C5, /* CAL+0x74 @ 0x9C4C -- gate_0220 lower RPM threshold */
|
||||
|
||||
326
Core/Phi/phi.c
326
Core/Phi/phi.c
@@ -1,17 +1,14 @@
|
||||
/**
|
||||
* @file phi.c
|
||||
* @brief T06235 compact-port — monolithic single-translation-unit
|
||||
* @brief T06211 compact-port — monolithic single-translation-unit
|
||||
* implementation of the injection-angle producer chain.
|
||||
*
|
||||
* All seven producer stages and the shared submap helpers are inlined
|
||||
* directly into this file as `static` functions (1:1 translations of
|
||||
* the verbose modules under variants/T06215/src/, brought along
|
||||
* the verbose modules under variants/T06211/src/, brought along
|
||||
* verbatim so per-block disassembly-address comments remain
|
||||
* authoritative). The producer itself (s_final_injection_angle @
|
||||
* 0x754D) is byte-equivalent to T06211's FUN_7453 — see
|
||||
* variants/T06215/README.md — so the inlined bodies and assembly
|
||||
* address ranges are shared with T06211. The call order in
|
||||
* `phi_service` matches T06211's fused-scheduler walk
|
||||
* authoritative). The call order in `phi_service` matches the
|
||||
* disassembly walk through the fused scheduler at FUN_698C
|
||||
* (variants/T06211/docs/open-questions.md §4 / §5).
|
||||
*
|
||||
* Pipeline (Stages 2–7 in `phi_service`):
|
||||
@@ -25,7 +22,7 @@
|
||||
*
|
||||
* Every MCS-96 arithmetic choice (MUL vs MULU, SHRA vs SHR logical, JGE
|
||||
* vs JC) mirrors the disassembly — see the per-block comments with
|
||||
* disassembly address ranges, and variants/T06215/src/ for the
|
||||
* disassembly address ranges, and variants/T06211/src/ for the
|
||||
* long-form function-level commentary these stages were ported from.
|
||||
*/
|
||||
#include "phi.h"
|
||||
@@ -40,7 +37,7 @@
|
||||
* combine_three_submaps_to_word, refine_submap_result), plus two
|
||||
* file-static utilities (bytes_to_words, bilinear_at_plane).
|
||||
*
|
||||
* Brought verbatim from variants/T06215/src/submap_eval.c with
|
||||
* Brought verbatim from variants/T06211/src/submap_eval.c with
|
||||
* external linkage demoted to `static`.
|
||||
* ══════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
@@ -232,7 +229,7 @@ static int16_t refine_submap_result(const int16_t *data_table,
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════
|
||||
* Producer stages — 1:1 ports of the seven verbose modules under
|
||||
* variants/T06215/src/, brought along verbatim with external linkage
|
||||
* variants/T06211/src/, brought along verbatim with external linkage
|
||||
* demoted to `static`. Each docstring identifies the originating ROM
|
||||
* function (FUN_xxxx @ 0xyyyy).
|
||||
* ══════════════════════════════════════════════════════════════════════ */
|
||||
@@ -349,6 +346,13 @@ reset_path:
|
||||
* 5. refine_submap_result over the 1-D table at CAL+0x72
|
||||
* 6. signed MUL: rl1c = refined × combined; SHLL by 8; high word → rt->accel_comp_gain
|
||||
*/
|
||||
|
||||
/* Forward declaration — compute_angle_accumulator_3d (defined below) embeds
|
||||
* the Alternate_phiad_calc gate that conditionally calls this producer.
|
||||
* The producer body sits further down in the file alongside its gated
|
||||
* wrapper, so the forward decl lets the gate compile against the prototype. */
|
||||
static void compute_accel_comp_offset(runtime_state_t *rt, const calibration_t *cal);
|
||||
|
||||
static void compute_accel_comp_gain(runtime_state_t *rt, const calibration_t *cal)
|
||||
{
|
||||
submap_scratch_t scratch_rpm;
|
||||
@@ -432,8 +436,35 @@ static void compute_angle_accumulator_3d(runtime_state_t *rt, const calibration_
|
||||
/* 0x7288–0x728a: LD RW52, RW1C — write angle_accumulator. */
|
||||
rt->angle_accumulator = result;
|
||||
|
||||
/* 0x728b–0x72af: conditional accel_comp_gain / accel_comp_offset
|
||||
* sub-calls — handled by Stages 3 and 4 of phi_service. */
|
||||
/* 0x728b–0x72af: Alternate_phiad_calc embedded gate (FUN_5dd0 tail in
|
||||
* T06031, FUN_5df3 in T06215; T06211 mirrors the same structure).
|
||||
*
|
||||
* Below the hysteresis threshold (gate_0220 == 0) the live ROM both
|
||||
* recomputes the accel_comp_gain and force-flags REC.1 so the next
|
||||
* Try_calc_accel_offset visit will produce a value despite low RPM.
|
||||
* Stage 3 of phi_service has already run compute_accel_comp_gain
|
||||
* unconditionally this tick, so we only need to mirror the REC.1 flag
|
||||
* here.
|
||||
*
|
||||
* The compute_accel_comp_offset call is gated on REC.2 (set by
|
||||
* compute_accel_comp_offset_gated when phi_per_cylinder_event has
|
||||
* fired this cylinder cycle) AND REC.0 clear (consumer has drained
|
||||
* any prior value). This is the PTS-event fallback path — at high
|
||||
* RPM the per-cylinder hook will have already set REC.0, so this
|
||||
* gate skips and the producer fires from the per-cylinder side
|
||||
* exclusively.
|
||||
*
|
||||
* Note: in T06211, this function only runs from the orchestrator's
|
||||
* else-branch (inj_qty_demand != 0), which matches the live ROM
|
||||
* behavior where Alternate_phiad_calc lives inside the kick chain
|
||||
* skipped on demand=0. The per-cylinder hook fires the producer
|
||||
* independently of demand. */
|
||||
if (rt->gate_0220 == 0u) {
|
||||
rt->rec = (uint8_t)(rt->rec | 0x02u);
|
||||
}
|
||||
if (((rt->rec & 0x04u) != 0u) && ((rt->rec & 0x01u) == 0u)) {
|
||||
compute_accel_comp_offset(rt, cal);
|
||||
}
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════
|
||||
@@ -443,8 +474,8 @@ static void compute_angle_accumulator_3d(runtime_state_t *rt, const calibration_
|
||||
* Sole producer of `rt->rw9e` — the high word of the signed 32-bit
|
||||
* IIR-filter accumulator `{rt->rw9e:rt->rw9c}`. Low-passes the
|
||||
* rpm-derived term `rt->rw9a` (produced by compute_temp_comp_factor at
|
||||
* 0x6AF9). `rt->rw9e` is consumed by the same compute_temp_comp_factor
|
||||
* at 0x6AFC.
|
||||
* 0x5DBD). `rt->rw9e` is consumed by the same compute_temp_comp_factor
|
||||
* at 0x5DC0.
|
||||
*
|
||||
* Cadence: in the ROM the IIR step runs from Timer_1khz (1 kHz) gated
|
||||
* by an R94 prescaler that reloads from DAT_6061 = 0x64 = 100, so the
|
||||
@@ -578,20 +609,17 @@ void phi_tick_1khz(phi_state_t *state, const phi_cal_t *cal)
|
||||
}
|
||||
|
||||
/*
|
||||
* 1:1 translation of orphan calc_temp_comp_factor @ 0x6AE7–0x6B29
|
||||
* (T06235 variant; algorithmically byte-equivalent to T06211 FUN_5DAB
|
||||
* @ 0x5DAB).
|
||||
* 1:1 translation of orphan FUN_5DAB @ 0x5DAB–0x5DED (T06211 variant).
|
||||
*
|
||||
* Per-tick producer of `rt->temp_comp_factor` (the runtime mirror of
|
||||
* *(0x02FC) in T06215; T06211 uses *(0x02F4)). Reached on-tick by
|
||||
* `LCALL calc_temp_comp_factor` at 0x7B14 inside the per-cylinder gate
|
||||
* that precedes the orphan scheduler at FUN_7b1c.
|
||||
* Per-tick producer of `rt->temp_comp_factor` (= the runtime mirror of
|
||||
* *(0x02F4)). Reached on-tick by `LCALL 0x5DAB` at 0x79D9 inside the
|
||||
* per-cylinder gate that precedes the orphan scheduler at 0x79E1.
|
||||
*
|
||||
* Both MULs in this function carry the FE prefix → signed 16×16→32.
|
||||
* The final store at 0x6B1E is `ST RW1C, temp_comp` — the LOW word of
|
||||
* The final store at 0x5DE2 is `ST RW1C, *(0x02F4)` — the LOW word of
|
||||
* the second product, NOT the high word.
|
||||
*
|
||||
* The R0CB-gated `ADD RW20, RWCE` branch at 0x6B00–0x6B07 is
|
||||
* The R0CB-gated `ADD RW20, RWCE` branch at 0x5DC4–0x5DCB is
|
||||
* INTENTIONALLY DROPPED — both register-bank slots are observed zero in
|
||||
* nominal operation, so the branch is dead. Restore it if a future
|
||||
* live-ECU dump shows R0CB transitioning out of zero.
|
||||
@@ -600,98 +628,95 @@ void phi_tick_1khz(phi_state_t *state, const phi_cal_t *cal)
|
||||
*/
|
||||
static void compute_temp_comp_factor(runtime_state_t *rt, const calibration_t *cal)
|
||||
{
|
||||
/* 0x6AE7–0x6AEC: prologue (PUSH RW1C, RW1E, RW20) — handled by C locals. */
|
||||
/* 0x5DAB–0x5DB0: prologue (PUSH RW1C, RW1E, RW20) — handled by C locals. */
|
||||
|
||||
/* 0x6AED–0x6AEF: LD RW1C, RW40 — rw1c = rpm. */
|
||||
/* 0x5DB1–0x5DB3: LD RW1C, RW40 — rw1c = rpm. */
|
||||
int16_t rpm_signed = (int16_t)rt->rpm;
|
||||
|
||||
/* 0x6AF0–0x6AF5: MUL RL1C, RW1C, temp_comp_dynamic — signed (FE prefix);
|
||||
* cal_temp_comp_switch_dynamic mirrors temp_comp_dynamic.
|
||||
* 0x6AF6–0x6AF8: SHRAL RL1C, #2 — arithmetic right shift on the
|
||||
/* 0x5DB4–0x5DB9: MUL RL1C, RW1C, *(0x02F6) — signed (FE prefix);
|
||||
* cal_temp_comp_switch_dynamic mirrors *(0x02F6).
|
||||
* 0x5DBA–0x5DBC: SHRAL RL1C, #2 — arithmetic right shift on the
|
||||
* 32-bit signed product. */
|
||||
int32_t rl1c = (int32_t)rpm_signed
|
||||
* (int32_t)cal->cal_temp_comp_switch_dynamic;
|
||||
rl1c = rl1c >> 2; /* arithmetic */
|
||||
int16_t rw1e = (int16_t)((rl1c >> 16) & 0xFFFF); /* high word */
|
||||
|
||||
/* 0x6AF9–0x6AFB: LD RW9A, RW1E — publish high word as state.
|
||||
* Consumed by other orphans outside the RW48 chain. */
|
||||
/* 0x5DBD–0x5DBF: LD RW9A, RW1E — publish high word as state.
|
||||
* Consumed by other orphans (FUN_5E12) outside the RW48 chain. */
|
||||
rt->rw9a = rw1e;
|
||||
|
||||
/* 0x6AFC–0x6AFF: SUB RW20, RW9E, RW1E (3-op) — rw20 = RW9E − rw1e. */
|
||||
/* 0x5DC0–0x5DC3: SUB RW20, RW9E, RW1E (3-op) — rw20 = RW9E − rw1e. */
|
||||
int16_t rw20 = (int16_t)(rt->rw9e - rw1e);
|
||||
|
||||
/* 0x6B00–0x6B07: R0CB-gated `ADD RW20, RWCE` — DROPPED (see docstring). */
|
||||
/* 0x5DC4–0x5DCB: R0CB-gated `ADD RW20, RWCE` — DROPPED (see docstring). */
|
||||
|
||||
/* 0x6B08–0x6B0C: ADD RW20, *(0x0146) — fold in temperature. */
|
||||
/* 0x5DCC–0x5DD0: ADD RW20, *(0x0146) — fold in temperature. */
|
||||
rw20 = (int16_t)(rw20 + rt->temperature);
|
||||
|
||||
/* 0x6B0D–0x6B11: SUB RW20, [RWA4+0x007E] — temperature reference. */
|
||||
/* 0x5DD1–0x5DD5: SUB RW20, [RWA4+0x007E] — temperature reference. */
|
||||
rw20 = (int16_t)(rw20 - cal->cal_7e);
|
||||
|
||||
/* 0x6B12–0x6B16: SUB RW20, *(0x0402) — sign-extended boot byte
|
||||
* (cal_byte_402 = 0xFFF2 = -14 in this T06215 image). */
|
||||
/* 0x5DD6–0x5DDA: SUB RW20, *(0x0402) — sign-extended boot byte
|
||||
* (cal_byte_402 = 0xFFF8 = -8 in this image). */
|
||||
rw20 = (int16_t)(rw20 - cal->cal_byte_402);
|
||||
|
||||
/* 0x6B17–0x6B1D: MUL RL1C, RW20, temp_comp_complete — signed (FE prefix);
|
||||
* cal_temp_comp_switch_complete mirrors temp_comp_complete.
|
||||
/* 0x5DDB–0x5DE1: MUL RL1C, RW20, *(0x02F2) — signed (FE prefix);
|
||||
* cal_temp_comp_switch_complete mirrors *(0x02F2).
|
||||
* With switch == 1, rl1c == rw20 (sign-extended). */
|
||||
int32_t prod = (int32_t)rw20
|
||||
* (int32_t)cal->cal_temp_comp_switch_complete;
|
||||
|
||||
/* 0x6B1E–0x6B22: ST RW1C, temp_comp — LOW word of RL1C.
|
||||
/* 0x5DE2–0x5DE6: ST RW1C, *(0x02F4) — LOW word of RL1C.
|
||||
* NOTE: stores the LOW 16 bits of the signed 32-bit product, not
|
||||
* the high word. Anything that overflows int16 wraps. */
|
||||
rt->temp_comp_factor = (int16_t)((uint32_t)prod & 0xFFFFu);
|
||||
|
||||
/* 0x6B23–0x6B29: epilogue. */
|
||||
/* 0x5DE7–0x5DED: epilogue. */
|
||||
}
|
||||
|
||||
/*
|
||||
* 1:1 translation of orphan compute_angle_kick_2d @ 0x6A94–0x6AE6
|
||||
* (T06235 variant; algorithmically byte-equivalent to T06211 FUN_5D58
|
||||
* @ 0x5D58).
|
||||
* 1:1 translation of orphan FUN_5D58 @ 0x5D58–0x5DAA (T06211 variant).
|
||||
*
|
||||
* Per-tick producer of `rt->angle_kick_2d` (RW3E). Reached by
|
||||
* `LCALL compute_angle_kick_2d` at 0x7B76 in the orphan scheduler
|
||||
* FUN_7b1c, immediately after the angle-accumulator-3D analog and
|
||||
* immediately before `RW52 += RW3E` at 0x7B79. Reuses scratch_rpm /
|
||||
* scratch_demand already populated by compute_angle_accumulator_3d
|
||||
* earlier in the same tick.
|
||||
* `LCALL 0x5D58` at 0x7A3B in the orphan scheduler, immediately after
|
||||
* `compute_angle_accumulator_3d` (FUN_722E) and immediately before
|
||||
* `RW52 += RW3E` at 0x7A3E. Reuses scratch_rpm / scratch_demand
|
||||
* already populated by compute_angle_accumulator_3d earlier in the
|
||||
* same tick.
|
||||
*
|
||||
* Both MULs are SIGNED (FE prefix). SHRAL is arithmetic; SHLL is
|
||||
* logical.
|
||||
*/
|
||||
static void compute_angle_kick_2d(runtime_state_t *rt, const calibration_t *cal)
|
||||
{
|
||||
/* 0x6A94–0x6AA3: prologue (PUSH RW1C/.../RW2A) — handled by C locals.
|
||||
* 0x6AA4–0x6AAA: RW2A = RWC6 + 0x32 — points at the kick table cal slot. */
|
||||
/* 0x5D58–0x5D67: prologue (PUSH RW1C/.../RW2A) — handled by C locals.
|
||||
* 0x5D68–0x5D6E: RW2A = RWC6 + 0x32 — points at the kick table cal slot. */
|
||||
|
||||
/* 0x6AAB–0x6AB6: PUSH #0x194 / #0x184 / [RW2A] / LCALL FUN_6f1e
|
||||
* (T06215's combine_two_submaps_to_word analog).
|
||||
/* 0x5D6F–0x5D79: PUSH #0x194 / #0x184 / [RW2A] / LCALL FUN_7035.
|
||||
* 2-D bilinear combine on (rpm, demand) over data_table_2d_kick.
|
||||
* 0x6AB6: ST RW1C, RW3E — RW3E = bilinear result. */
|
||||
* 0x5D7A: ST RW1C, RW3E — RW3E = bilinear result. */
|
||||
int16_t bilinear = combine_two_submaps_to_word(cal->data_table_2d_kick,
|
||||
&rt->scratch_rpm,
|
||||
&rt->scratch_demand);
|
||||
rt->angle_kick_2d = bilinear;
|
||||
|
||||
/* 0x6ABD–0x6AC2: MUL RL1C, RW42, [RWC6+0x34] — signed (FE prefix);
|
||||
* 0x6AC3–0x6AC5: SHRAL RL1C, #0x8 (arithmetic).
|
||||
* 0x6AC6–0x6AC8: ADD RW3E, RW1C — fold demand-weighted offset in. */
|
||||
/* 0x5D81–0x5D89: MUL RL1C, RW42, [RWC6+0x34] — signed (FE prefix);
|
||||
* SHRAL RL1C, #0x8 (arithmetic).
|
||||
* 0x5D8A: ADD RW3E, RW1C — fold demand-weighted offset in. */
|
||||
int32_t dem_prod = (int32_t)rt->angle_dec_cmd * (int32_t)cal->cal_rwc6_34;
|
||||
int32_t dem_shifted = dem_prod >> 8; /* arithmetic */
|
||||
int16_t dem_low = (int16_t)(dem_shifted & 0xFFFF);
|
||||
rt->angle_kick_2d = (int16_t)(rt->angle_kick_2d + dem_low);
|
||||
|
||||
/* 0x6AC9–0x6ACF: MUL RL1C, RW3E, temp_comp — signed (FE prefix);
|
||||
* 0x6AD0–0x6AD2: SHLL RL1C, #0x2 (LOGICAL); take HIGH word.
|
||||
* 0x6AD3–0x6AD5: ST RW1E, RW3E — RW3E = high_word((RW3E × temp_comp_factor) << 2). */
|
||||
/* 0x5D8D–0x5D97: MUL RL1C, RW3E, *(0x02F4) — signed (FE prefix);
|
||||
* SHLL RL1C, #0x2 (LOGICAL); take HIGH word.
|
||||
* 0x5D97: ST RW1E, RW3E — RW3E = high_word((RW3E × temp_comp_factor) << 2). */
|
||||
int32_t scale_prod = (int32_t)rt->angle_kick_2d * (int32_t)rt->temp_comp_factor;
|
||||
uint32_t scale_shifted = ((uint32_t)scale_prod) << 2; /* logical */
|
||||
rt->angle_kick_2d = (int16_t)(uint16_t)(scale_shifted >> 16);
|
||||
|
||||
/* 0x6AD6–0x6AE6: epilogue. */
|
||||
/* 0x5D9A–0x5DAA: epilogue. */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -749,6 +774,42 @@ static void compute_accel_comp_offset(runtime_state_t *rt, const calibration_t *
|
||||
(void)rw1c; /* rw1c is discarded after MUL; preserved for block-mapping */
|
||||
}
|
||||
|
||||
/*
|
||||
* 1:1 translation of FUN_736e @ 0x736e–0x7388 (T06211 — Try_calc_accel_offset
|
||||
* analog; byte-equivalent in shape to T06215's FUN_5f33 and T06031's
|
||||
* FUN_736e — same address in T06211 / T06031, different in T06215). The
|
||||
* verbose tree's compute_accel_comp_offset_gated translates the same
|
||||
* function. Triggered from the live-ROM tooth dispatcher at the per-cylinder
|
||||
* cal_byte_56 (=13) tooth event, immediately after Calculate_mid_rpm
|
||||
* updates RW138. Wired into the public API as phi_per_cylinder_event.
|
||||
*
|
||||
* 0x7372: ORB REC, #0x4 ; REC.2 := 1 (wrapper visited flag)
|
||||
* 0x7375: JBS REC, 0x0, exit ; REC.0 set → fresh value pending, skip
|
||||
* 0x7378: JBS REC, 0x1, compute ; REC.1 set → forced compute path
|
||||
* 0x737b: CMPB ZRlo, *(0x0220) ; gate_0220 (is_rpm_above_1000_hyst.)
|
||||
* 0x7380: JE exit ; gate_0220 == 0 → skip
|
||||
* 0x7382: SCALL FUN_732d ; compute_accel_comp_offset
|
||||
* 0x7384: epilogue
|
||||
*/
|
||||
static void compute_accel_comp_offset_gated(runtime_state_t *rt,
|
||||
const calibration_t *cal)
|
||||
{
|
||||
/* 0x7372: REC |= 0x04 — set unconditionally, even on skip paths. */
|
||||
rt->rec = (uint8_t)(rt->rec | 0x04u);
|
||||
|
||||
/* 0x7375: REC.0 set → consumer (FUN_7453) hasn't drained the previous
|
||||
* RW3C yet; skip recomputation to avoid losing the pending value. */
|
||||
if ((rt->rec & 0x01u) != 0u) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 0x7378–0x7381: REC.1 forces the compute path; otherwise gate on
|
||||
* the live-byte hysteresis at *(0x0220). */
|
||||
if (((rt->rec & 0x02u) != 0u) || (rt->gate_0220 != 0u)) {
|
||||
compute_accel_comp_offset(rt, cal);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 1:1 translation of the RPM-hysteresis block at 0x7801–0x7825 inside
|
||||
* the orphan scheduler at 0x77FF (T06211 variant). Bytes were not
|
||||
@@ -1011,7 +1072,7 @@ static void compute_target_injection_angle(runtime_state_t *rt, const calibratio
|
||||
/* 0x74a2–0x74a7: ADD RW5A, RW1C, 0x14e (3-op, TABLE[ZR])
|
||||
* target_eoi = target_inj_angle + phi1, where phi1 is the precomputed
|
||||
* cell at *(0x014e). The C model recomputes phi1 = phi0 + dphi inline
|
||||
* (see variants/T06215/docs/open-questions.md §6). */
|
||||
* (see variants/T06211/docs/open-questions.md §6). */
|
||||
{
|
||||
int16_t phi1 = (int16_t)(cal->phi0 + rt->dphi);
|
||||
rt->target_eoi = (int16_t)(rw1c + phi1);
|
||||
@@ -1035,7 +1096,7 @@ void phi_init(phi_state_t *state, const phi_cal_t *cal,
|
||||
* input_var field is runtime-bound by design (the C model treats the
|
||||
* cal as a writable buffer, not flash-resident, since extract_*.py
|
||||
* emits a non-const initializer for this very reason). */
|
||||
phi_t06235_bind_inputs(&state->rt, (phi_cal_t *)cal);
|
||||
phi_t06211_bind_inputs(&state->rt, (phi_cal_t *)cal);
|
||||
|
||||
/* Pull boot-only getters — Phase-1 / Phase-2 thresholds for the
|
||||
* FUN_62a2 state machine. */
|
||||
@@ -1078,13 +1139,21 @@ void phi_service(phi_state_t *state, const phi_cal_t *cal, phi_outputs_t *out)
|
||||
rt->inj_qty_demand = g->get_inj_qty_demand();
|
||||
rt->angle_dec_cmd = g->get_angle_dec_cmd();
|
||||
rt->temperature = g->get_temperature();
|
||||
rt->rpm_baseline = g->get_rpm_baseline();
|
||||
/* rt->rpm_baseline is intentionally NOT pulled here — its cadence is
|
||||
* tooth-13-event-driven, not main-loop-driven. The pull happens at
|
||||
* the two consumer-side entry points instead:
|
||||
* - phi_per_cylinder_event (the per-cylinder hook)
|
||||
* - just before compute_angle_accumulator_3d in Stage 3b's
|
||||
* else-branch (the PTS-event fallback path's embedded
|
||||
* Alternate_phiad_calc gate; on demand=0 the orchestrator's
|
||||
* alt-path skips this branch, matching the live-ROM behavior).
|
||||
* See the comment at each pull site. */
|
||||
rt->rwc2 = g->get_rwc2();
|
||||
rt->reset_gate_0226 = g->get_reset_gate_0226();
|
||||
rt->dphi = g->get_dphi();
|
||||
/* rt->rw9e is produced internally by compute_temp_phi_comp on its
|
||||
* 10 Hz cadence; it is not pulled from a getter. The host drives the
|
||||
* 1 kHz hook compute_temp_phi_comp_tick_1khz from a separate timer. */
|
||||
/* rt->rw9e is produced internally by phi_tick_1khz on its 10 Hz
|
||||
* cadence; it is not pulled from a getter. The host drives the 1 kHz
|
||||
* hook from a separate timer. */
|
||||
|
||||
/* Per-tick constants — hard-wire chain inputs that the live ECU drives
|
||||
* but the simulation pins to a single value:
|
||||
@@ -1114,50 +1183,75 @@ void phi_service(phi_state_t *state, const phi_cal_t *cal, phi_outputs_t *out)
|
||||
* unconditionally so the gain is fresh each tick. */
|
||||
compute_accel_comp_gain(rt, cal);
|
||||
|
||||
/* ── Stage 3b: compute_angle_accumulator_3d (FUN_722e @ 0x722e) ────
|
||||
* Three RWC6-relative submap evals (RPM, demand, angle_dec_cmd) through
|
||||
* FUN_7092 (3-D trilinear = combine_three_submaps_to_word) → writes
|
||||
* rt->angle_accumulator (RW52) and rt->scratch_0158 debug mirror.
|
||||
* Also populates rt->scratch_rpm and rt->scratch_demand which the
|
||||
* angle-kick stage (3d) reuses without re-evaluating. The ROM's
|
||||
* conditional gain/offset sub-calls inside FUN_722e (FUN_72b0 and
|
||||
* FUN_732d at 0x7292 / 0x729d) are handled by Stage 3 and Stage 4. */
|
||||
/* ── Stages 3b–3e: angle accumulator + temperature-kick fold ──────
|
||||
* (Aligned with T06215/T06235: no orchestration-level demand-zero
|
||||
* guard — the demand=0 alt path is handled inside
|
||||
* compute_target_injection_angle at Stage 7.)
|
||||
*
|
||||
* ── Stage 3b: compute_angle_accumulator_3d (FUN_722e @ 0x722e)
|
||||
* Three RWC6-relative submap evals (RPM, demand, angle_dec_cmd)
|
||||
* through FUN_7092 (3-D trilinear) → writes rt->angle_accumulator
|
||||
* (RW52) and rt->scratch_0158 debug mirror. Also populates
|
||||
* rt->scratch_rpm and rt->scratch_demand which the angle-kick
|
||||
* stage (3d) reuses without re-evaluating.
|
||||
*
|
||||
* The Alternate_phiad_calc embedded gate at the tail of this
|
||||
* function may fire compute_accel_comp_offset (the "PTS-event
|
||||
* fallback path"). Pull rpm_baseline FRESH right before this
|
||||
* gate so the producer reads the latest tooth-13 snapshot rather
|
||||
* than whatever stale value Stage 1 left behind — phi_service's
|
||||
* main-loop cadence is not synchronised with the per-cylinder
|
||||
* tooth-13 event. Mirrors the pull at the top of
|
||||
* phi_per_cylinder_event so both producer entry points see the
|
||||
* same snapshot ordering. */
|
||||
rt->rpm_baseline = g->get_rpm_baseline();
|
||||
compute_angle_accumulator_3d(rt, cal);
|
||||
|
||||
/* ── Stage 3c: compute_temp_comp_factor (orphan calc_temp_comp_factor @ 0x6AE7) ─
|
||||
* Per-tick rebuild of *(0x02FC) in T06215 (T06211: *(0x02F4)) from rpm,
|
||||
* temperature, the two boot switches (cal_temp_comp_switch_complete /
|
||||
* _dynamic), and the external rw9e state input. Mirrors the orphan call
|
||||
* at 0x7B14 that fires before the angle scheduler at FUN_7b1c. */
|
||||
/* ── Stage 3c: compute_temp_comp_factor (orphan FUN_5DAB @ 0x5DAB)
|
||||
* Per-tick rebuild of *(0x02F4) from rpm, temperature, the two
|
||||
* boot switches (cal_temp_comp_switch_complete / _dynamic), and
|
||||
* the external rw9e state input. Mirrors the orphan call at
|
||||
* 0x79D9 that fires before the angle scheduler at 0x79E1. */
|
||||
compute_temp_comp_factor(rt, cal);
|
||||
|
||||
/* ── Stage 3d: compute_angle_kick_2d (orphan @ 0x6A94) ─────────────
|
||||
/* ── Stage 3d: compute_angle_kick_2d (orphan FUN_5D58 @ 0x5D58)
|
||||
* 2-D bilinear kick over the table at *(RWC6+0x32), reusing the
|
||||
* scratches populated by Stage 3b, plus a demand-weighted offset
|
||||
* `(angle_dec_cmd × cal_rwc6_34) >> 8`, post-scaled by
|
||||
* temp_comp_factor (Stage 3c output). Mirrors `LCALL compute_angle_kick_2d`
|
||||
* at 0x7B76. Writes rt->angle_kick_2d (RW3E). */
|
||||
* temp_comp_factor (Stage 3c output). Mirrors `LCALL 0x5D58` at
|
||||
* 0x7A3B. Writes rt->angle_kick_2d (RW3E). */
|
||||
compute_angle_kick_2d(rt, cal);
|
||||
|
||||
/* ── Stage 3e: fold the kick into the accumulator + saturate ──────
|
||||
* Mirrors `ADD RW52, RW3E` at 0x7B79 followed by the `JBC R53.7 /
|
||||
* CLR RW52` saturate at 0x7B7C–0x7B7F. This happens BEFORE
|
||||
* compute_target_injection_angle (FUN_7453 analog @ 0x754D);
|
||||
* FUN_7453's own REC.0 fold of accel_comp_offset (RW3C) and
|
||||
* *(0x0200) drain run later inside Stage 7. */
|
||||
/* ── Stage 3e: fold the kick into the accumulator + saturate ──
|
||||
* Mirrors `ADD RW52, RW3E` at 0x7A3E followed by the `JBC R53.7
|
||||
* / CLR RW52` saturate at 0x7A41–0x7A44. This happens BEFORE
|
||||
* compute_target_injection_angle (FUN_7453); FUN_7453's own
|
||||
* REC.0 fold of accel_comp_offset (RW3C) and *(0x0200) drain
|
||||
* run later inside Stage 7. */
|
||||
rt->angle_accumulator = (int16_t)(rt->angle_accumulator + rt->angle_kick_2d);
|
||||
if (rt->angle_accumulator < 0) {
|
||||
rt->angle_accumulator = 0;
|
||||
}
|
||||
|
||||
/* ── Stage 4: compute_accel_comp_offset (FUN_732d @ 0x732d) ─────
|
||||
* Δ-rpm × accel_comp_gain → high-word of (signed MUL << 4),
|
||||
* clamped against [cal_7a, cal_78]. Forced to 0 when
|
||||
* reset_gate_0226 == 0, then ORs REC with 0x01 so FUN_7453's reset
|
||||
* branch folds RW3C into the accumulator next tick. We invoke the
|
||||
* raw producer (not the gated wrapper FUN_736e) to match the spec —
|
||||
* the gate_0220 update in stage 5 is informational only. */
|
||||
compute_accel_comp_offset(rt, cal);
|
||||
/* ── Stage 4: compute_accel_comp_offset is no longer called here ──
|
||||
* The producer is now driven by the live-ROM cadence:
|
||||
*
|
||||
* 1. Per-cylinder path — host calls phi_per_cylinder_event() at the
|
||||
* cal_byte_56 (=13) tooth (mirrors Tooth_scheduler @ 0x7abe in
|
||||
* T06215; T06211 same tooth value). This sets REC.2 and may run
|
||||
* compute_accel_comp_offset depending on gate_0220 / REC.1 state.
|
||||
*
|
||||
* 2. PTS-event fallback path — the Alternate_phiad_calc embedded
|
||||
* gate at the tail of compute_angle_accumulator_3d (Stage 3b)
|
||||
* runs compute_accel_comp_offset when REC.2 is set AND REC.0
|
||||
* is clear. In T06211 this lives inside the demand!=0 else-branch,
|
||||
* so on demand=0 the fallback is skipped (matching the live-ROM
|
||||
* alt-path); the per-cylinder hook still fires the producer
|
||||
* independently of demand.
|
||||
*
|
||||
* Calling the bare producer here would overwrite RW3C every tick
|
||||
* regardless of cadence, which is the divergence the live-ECU
|
||||
* comparison surfaced. */
|
||||
|
||||
/* ── Stage 5: compute_gate_0220 (orphan @ 0x77ff) ───────────────
|
||||
* Updates rt->gate_0220 from current rpm with hysteresis bands at
|
||||
@@ -1208,3 +1302,43 @@ void phi_service(phi_state_t *state, const phi_cal_t *cal, phi_outputs_t *out)
|
||||
|
||||
size_t phi_state_size(void) { return sizeof(phi_state_t); }
|
||||
size_t phi_cal_size(void) { return sizeof(phi_cal_t); }
|
||||
|
||||
/*
|
||||
* phi_per_cylinder_event — public per-cylinder hook for T06211.
|
||||
*
|
||||
* Models the live-ROM tooth dispatcher path that fires once per cylinder
|
||||
* at the cal_byte_56 = 13 tooth event:
|
||||
*
|
||||
* if (R88 == cal_byte_56) {
|
||||
* Calculate_mid_rpm(); // updates rpm_baseline (RW138)
|
||||
* compute_accel_comp_offset_gated(); // FUN_736e @ 0x736e
|
||||
* }
|
||||
*
|
||||
* Pulls rpm_baseline from the getter at hook entry — the host computes
|
||||
* the fresh tooth-13 snapshot just before invoking this hook, but
|
||||
* phi_service's Stage 1 used to capture rpm_baseline at main-loop cadence
|
||||
* (independent of tooth-13 events), leaving rt->rpm_baseline stale at
|
||||
* this moment. The fresh pull here guarantees the producer sees the
|
||||
* just-computed snapshot. The mirror pull just before Stage 3b in
|
||||
* phi_service does the same for the PTS-event fallback path.
|
||||
*
|
||||
* Cadence (per the live-ECU side-by-side traces):
|
||||
* - High RPM (gate_0220 == 1): hook fires the producer; REC.0 is set;
|
||||
* phi_service's Stage 3b fallback gate observes REC.0 and skips.
|
||||
* - Low RPM (gate_0220 == 0): hook only sets REC.2; phi_service's
|
||||
* Stage 3b runs the producer because REC.1 was set there and REC.0
|
||||
* is still clear (provided demand != 0; on demand=0 only the hook
|
||||
* can fire the producer).
|
||||
* - In all cases compute_target_injection_angle (Stage 7) clears the
|
||||
* entire REC byte after consuming RW3C, so REC reads back as 0
|
||||
* between events — matching the live observation that *(0x00ec)
|
||||
* stays at zero on the bus probe.
|
||||
*
|
||||
* Reentrant per phi_state_t. Safe to invoke from a tooth-edge ISR
|
||||
* provided the host serialises against phi_service.
|
||||
*/
|
||||
void phi_per_cylinder_event(phi_state_t *state, const phi_cal_t *cal)
|
||||
{
|
||||
state->rt.rpm_baseline = state->getters->get_rpm_baseline();
|
||||
compute_accel_comp_offset_gated(&state->rt, cal);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,16 @@
|
||||
/**
|
||||
* @file phi.h
|
||||
* @brief T06235 injection-angle algorithm — compact public interface.
|
||||
* @brief T06211 injection-angle algorithm — compact public interface.
|
||||
*
|
||||
* AUTO-GENERATED by tools/extract_t06235_cal.py
|
||||
* Source ROM: rom_eeprom_dump_0000-9FFF_504042.bin
|
||||
* Bases: RWA4 = 0x9BB8, RWC6 = 0x8002
|
||||
*
|
||||
* Cal scalars from offset 0x48 onwards are shifted +0x02 vs T06215.
|
||||
* Field names retain T06215 semantics so forked C bodies reuse unchanged.
|
||||
* AUTO-GENERATED by tools/extract_t06211_cal.py
|
||||
* Source ROM: rom_eeprom_dump_0000-9FFF_504012.bin
|
||||
* Bases: RWA4 = 0x9BD8, RWC6 = 0x7D0E
|
||||
*
|
||||
* DO NOT EDIT -- regenerate with:
|
||||
* python tools/extract_t06235_cal.py --target compact
|
||||
*
|
||||
* 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
|
||||
* python tools/extract_t06211_cal.py --target compact
|
||||
*
|
||||
* Companion to phi.c (single-translation-unit port of the per-function
|
||||
* verbose tree under variants/T06235/src/) and the auto-generated
|
||||
* verbose tree under variants/T06211/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.
|
||||
@@ -29,7 +19,7 @@
|
||||
*
|
||||
* phi_input_getters_t getters = { .get_rpm = ..., ... };
|
||||
* phi_state_t state;
|
||||
* phi_cal_t cal = phi_t06235_cal; // copy from auto-extracted master
|
||||
* phi_cal_t cal = phi_t06211_cal; // copy from auto-extracted master
|
||||
* phi_outputs_t out;
|
||||
*
|
||||
* phi_init(&state, &cal, &getters); // boot-once
|
||||
@@ -50,21 +40,20 @@
|
||||
* 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/T06235/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.
|
||||
* FUN_5D58 angle_kick + `RW52 += RW3E` fold-in @ 0x7A3E) is wired into
|
||||
* this compact phi_service. RW9E (the IIR state high word consumed by
|
||||
* compute_temp_comp_factor) is produced internally by phi_tick_1khz —
|
||||
* the host must drive it once per 1 ms from its own millisecond timer.
|
||||
* See variants/T06211/docs/open-questions.md §9.
|
||||
*/
|
||||
#ifndef PHI_T06235_H
|
||||
#define PHI_T06235_H
|
||||
#ifndef PHI_T06211_H
|
||||
#define PHI_T06211_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* ─── Internal runtime / calibration types ───────────────────────────
|
||||
* Inlined verbatim from variants/T06235/src/injection_angle_state.h.
|
||||
* Inlined verbatim from variants/T06211/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. */
|
||||
@@ -127,12 +116,12 @@ typedef struct {
|
||||
* 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
|
||||
* state pair updated by phi_tick_1khz (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. */
|
||||
* compute_temp_comp_factor at 0x5DC0. */
|
||||
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
|
||||
@@ -160,6 +149,11 @@ typedef struct {
|
||||
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_56; /* CAL_byte[0x56] — tooth phase comparand for the ROM's rpm_baseline
|
||||
* producer (T06211 producer @ 0x5153 fires when current_tooth == this
|
||||
* byte; = 0x0D = 13). The C port treats rpm_baseline as an external
|
||||
* input — this byte is published so the host knows which tooth phase
|
||||
* to gate its capture on. */
|
||||
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. */
|
||||
@@ -168,9 +162,9 @@ typedef struct {
|
||||
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
|
||||
int16_t cal_82; /* CAL[0x82] — IIR input-gain `b` (Q16 unsigned) used by phi_tick_1khz
|
||||
* 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
|
||||
int16_t cal_84; /* CAL[0x84] — IIR pole `a` (Q16 unsigned) used by phi_tick_1khz
|
||||
* 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). */
|
||||
@@ -226,7 +220,15 @@ typedef struct {
|
||||
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) */
|
||||
int16_t (*get_rpm_baseline)(void); /* *(0x0138) — tooth-13 snapshot.
|
||||
* Called by phi_per_cylinder_event AND by phi_service
|
||||
* just before Stage 3b (NOT from Stage 1's bulk pull).
|
||||
* Must return the rpm sampled at the most recent
|
||||
* cal_byte_56=13 tooth event — a point sample, not
|
||||
* a moving average. Doing the unit conversion (e.g.
|
||||
* MT_offset_RPM × scale) inside the getter body is
|
||||
* the right place; the algorithm reads it as an
|
||||
* already-converted int16 Q-unit value. */
|
||||
uint16_t (*get_rwc2)(void); /* RWC2 */
|
||||
uint8_t (*get_reset_gate_0226)(void); /* *(0x0226) */
|
||||
int16_t (*get_dphi)(void); /* *(0x014c) */
|
||||
@@ -261,13 +263,43 @@ void phi_service(phi_state_t *state,
|
||||
* runtime_state_t. */
|
||||
void phi_tick_1khz(phi_state_t *state, const phi_cal_t *cal);
|
||||
|
||||
/** Per-cylinder hook. Host invokes once per cylinder cycle, on the tooth
|
||||
* edge where `current_tooth == cal->cal_byte_56` (= 13 in this ROM),
|
||||
* AFTER the host has computed the fresh rpm_baseline (RW138).
|
||||
*
|
||||
* Mirrors the live-ROM Tooth_scheduler dispatch (T06211 mirrors T06215's
|
||||
* 0x7abe path):
|
||||
*
|
||||
* if (R88 == cal_byte_56) {
|
||||
* Calculate_mid_rpm(); // host responsibility — host's
|
||||
* // get_rpm_baseline() must return
|
||||
* // this fresh value when called.
|
||||
* Try_calc_accel_offset(); // this function
|
||||
* }
|
||||
*
|
||||
* Internally calls compute_accel_comp_offset_gated (FUN_5f33 analog),
|
||||
* which pulls rpm_baseline fresh from the host getter at hook entry,
|
||||
* then sets REC.2 unconditionally and conditionally fires
|
||||
* compute_accel_comp_offset based on REC.0 / REC.1 / gate_0220:
|
||||
* - REC.0 set → skip (fresh value already pending)
|
||||
* - REC.1 set OR gate_0220 != 0 → run producer (writes RW3C, sets REC.0)
|
||||
* - otherwise → REC.2 only, no compute
|
||||
*
|
||||
* This is the cadence-matched entry point. Hosts that previously relied
|
||||
* on phi_service alone to drive RW3C should switch to:
|
||||
* per cylinder edge → phi_per_cylinder_event(...)
|
||||
* per main control tick → phi_service(...)
|
||||
*
|
||||
* Reentrant per phi_state_t. */
|
||||
void phi_per_cylinder_event(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_t06235_cal;
|
||||
extern calibration_t phi_t06211_cal;
|
||||
|
||||
void phi_t06235_bind_inputs(runtime_state_t *rt, calibration_t *cal);
|
||||
void phi_t06211_bind_inputs(runtime_state_t *rt, calibration_t *cal);
|
||||
|
||||
#endif /* PHI_T06235_H */
|
||||
#endif /* PHI_T06211_H */
|
||||
|
||||
@@ -1,179 +1,197 @@
|
||||
/**
|
||||
* @file phi_cal_tables.c
|
||||
* @brief T06235 compact-port calibration data (auto-generated).
|
||||
* @brief T06211 compact-port calibration data (auto-generated).
|
||||
*
|
||||
* AUTO-GENERATED by tools/extract_t06235_cal.py
|
||||
* Source ROM: rom_eeprom_dump_0000-9FFF_504042.bin
|
||||
* Bases: RWA4 = 0x9BB8, RWC6 = 0x8002
|
||||
*
|
||||
* Cal scalars from offset 0x48 onwards are shifted +0x02 vs T06215.
|
||||
* Field names retain T06215 semantics so forked C bodies reuse unchanged.
|
||||
* AUTO-GENERATED by tools/extract_t06211_cal.py
|
||||
* Source ROM: rom_eeprom_dump_0000-9FFF_504012.bin
|
||||
* Bases: RWA4 = 0x9BD8, RWC6 = 0x7D0E
|
||||
*
|
||||
* DO NOT EDIT -- regenerate with:
|
||||
* python tools/extract_t06235_cal.py --target compact
|
||||
* python tools/extract_t06211_cal.py --target compact
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include "phi.h"
|
||||
|
||||
/* Accel RPM axis -- 7 words @ 0x9D34. */
|
||||
/* ======================================================================
|
||||
* Accel axes + data tables (file-local; expose only phi_t06211_cal).
|
||||
* Angle accumulator axes + 3-D table (FUN_722e producer chain).
|
||||
* ====================================================================== */
|
||||
|
||||
/* Accel RPM axis -- 7 words @ 0x9D38. */
|
||||
static const int16_t phi_accel_axis_rpm[7] = {
|
||||
(int16_t)0x4B5E, (int16_t)0x3127, (int16_t)0x16F0, (int16_t)0x1206, (int16_t)0x09D5, (int16_t)0x068E, (int16_t)0x0000
|
||||
};
|
||||
|
||||
/* Accel inj_qty_demand axis -- 6 words @ 0x9D42. */
|
||||
/* Accel inj_qty_demand axis -- 6 words @ 0x9D46. */
|
||||
static const int16_t phi_accel_axis_demand[6] = {
|
||||
(int16_t)0x08C0, (int16_t)0x0640, (int16_t)0x0460, (int16_t)0x0280, (int16_t)0x01E0, (int16_t)0x0000
|
||||
(int16_t)0x08C0, (int16_t)0x0640, (int16_t)0x0320, (int16_t)0x0280, (int16_t)0x01E0, (int16_t)0x0000
|
||||
};
|
||||
|
||||
/* Accel temperature axis -- 5 words @ 0x9D4E. */
|
||||
/* Accel temperature axis -- 5 words @ 0x9D52. */
|
||||
static const int16_t phi_accel_axis_temp[5] = {
|
||||
(int16_t)0x12F0, (int16_t)0x1250, (int16_t)0x1110, (int16_t)0x0FD0, (int16_t)0x0000
|
||||
};
|
||||
|
||||
/* Accel 2-D combine (RPM x demand) -- 42 words @ 0x9D58. */
|
||||
/* Accel 2-D combine (RPM x demand) -- 42 words @ 0x9D5C. */
|
||||
static const int16_t phi_accel_combine_table[42] = {
|
||||
(int16_t)0x0000, (int16_t)0x01F8, (int16_t)0x0500, (int16_t)0x07E4, (int16_t)0x07E4, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x01F8, (int16_t)0x0500,
|
||||
(int16_t)0x07E4, (int16_t)0x07E4, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x01F8, (int16_t)0x0500, (int16_t)0x07E4, (int16_t)0x07E4, (int16_t)0x0000,
|
||||
(int16_t)0x0000, (int16_t)0x0000, (int16_t)0x01F8, (int16_t)0x0500, (int16_t)0x07E4, (int16_t)0x07E4, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x01F8,
|
||||
(int16_t)0x0500, (int16_t)0x07E4, (int16_t)0x07E4, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x01F8, (int16_t)0x0500, (int16_t)0x07E4, (int16_t)0x07E4,
|
||||
(int16_t)0x0000, (int16_t)0x020A, (int16_t)0x052C, (int16_t)0x082A, (int16_t)0x082A, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x020A, (int16_t)0x052C,
|
||||
(int16_t)0x082A, (int16_t)0x082A, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x020A, (int16_t)0x052C, (int16_t)0x082A, (int16_t)0x082A, (int16_t)0x0000,
|
||||
(int16_t)0x0000, (int16_t)0x0000, (int16_t)0x020A, (int16_t)0x052C, (int16_t)0x082A, (int16_t)0x082A, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x020A,
|
||||
(int16_t)0x052C, (int16_t)0x082A, (int16_t)0x082A, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x020A, (int16_t)0x052C, (int16_t)0x082A, (int16_t)0x082A,
|
||||
(int16_t)0x0000, (int16_t)0x0000
|
||||
};
|
||||
|
||||
/* Accel 1-D refine (temperature) -- 5 words @ 0x9DAC. */
|
||||
/* Accel 1-D refine (temperature) -- 5 words @ 0x9DB0. */
|
||||
static const int16_t phi_accel_refine_table[5] = {
|
||||
(int16_t)0x00FF, (int16_t)0x00FF, (int16_t)0x00FF, (int16_t)0x00FF, (int16_t)0x00FF
|
||||
};
|
||||
|
||||
/* Angle RPM axis -- 13 words @ 0x8038. */
|
||||
static const int16_t phi_angle_axis_rpm[13] = {
|
||||
(int16_t)0x4EA5, (int16_t)0x4817, (int16_t)0x4189, (int16_t)0x3AFB, (int16_t)0x346E, (int16_t)0x2DE0, (int16_t)0x240B, (int16_t)0x1A37, (int16_t)0x1206, (int16_t)0x0B78,
|
||||
(int16_t)0x068E, (int16_t)0x0347, (int16_t)0x0000
|
||||
/* Angle RPM axis -- 15 words @ 0x7D44. */
|
||||
static const int16_t phi_angle_axis_rpm[15] = {
|
||||
(int16_t)0x51EC, (int16_t)0x4D01, (int16_t)0x4817, (int16_t)0x4189, (int16_t)0x3AFB, (int16_t)0x346E, (int16_t)0x2DE0, (int16_t)0x2752, (int16_t)0x20C5, (int16_t)0x1A37,
|
||||
(int16_t)0x13A9, (int16_t)0x0D1B, (int16_t)0x068E, (int16_t)0x0347, (int16_t)0x0000
|
||||
};
|
||||
|
||||
/* Angle inj_qty_demand axis -- 15 words @ 0x8052. */
|
||||
/* Angle inj_qty_demand axis -- 15 words @ 0x7D62. */
|
||||
static const int16_t phi_angle_axis_demand[15] = {
|
||||
(int16_t)0x0F90, (int16_t)0x0C73, (int16_t)0x0A60, (int16_t)0x084D, (int16_t)0x0743, (int16_t)0x063A, (int16_t)0x0530, (int16_t)0x0426, (int16_t)0x031D, (int16_t)0x0213,
|
||||
(int16_t)0x0C73, (int16_t)0x0A60, (int16_t)0x08D2, (int16_t)0x07C8, (int16_t)0x06BE, (int16_t)0x05B5, (int16_t)0x04AB, (int16_t)0x03A2, (int16_t)0x0298, (int16_t)0x018E,
|
||||
(int16_t)0x010A, (int16_t)0x0085, (int16_t)0x0035, (int16_t)0x000D, (int16_t)0x0000
|
||||
};
|
||||
|
||||
/* Angle angle_dec_cmd axis -- 3 words @ 0x8070. */
|
||||
/* Angle angle_dec_cmd axis -- 3 words @ 0x7D80. */
|
||||
static const int16_t phi_angle_axis_dec_cmd[3] = {
|
||||
(int16_t)0x0300, (int16_t)0x01C4, (int16_t)0x0000
|
||||
};
|
||||
|
||||
/* 3-D angle combine (RPM x demand x angle_dec_cmd) -- 585 words @ 0x8076. */
|
||||
static const int16_t phi_angle_3d_table[585] = {
|
||||
(int16_t)0x05F8, (int16_t)0x0838, (int16_t)0x08EE, (int16_t)0x09B4, (int16_t)0x0A3A, (int16_t)0x0927, (int16_t)0x0781, (int16_t)0x05E0, (int16_t)0x0494, (int16_t)0x03EC,
|
||||
(int16_t)0x03CD, (int16_t)0x04A2, (int16_t)0x04A2, (int16_t)0x05F8, (int16_t)0x0838, (int16_t)0x08EE, (int16_t)0x09B4, (int16_t)0x0A3A, (int16_t)0x0927, (int16_t)0x0781,
|
||||
(int16_t)0x05E0, (int16_t)0x0494, (int16_t)0x03EC, (int16_t)0x0331, (int16_t)0x039C, (int16_t)0x039C, (int16_t)0x05F8, (int16_t)0x0838, (int16_t)0x08EE, (int16_t)0x09B4,
|
||||
(int16_t)0x0A3A, (int16_t)0x0927, (int16_t)0x0781, (int16_t)0x05E0, (int16_t)0x0494, (int16_t)0x037A, (int16_t)0x02C9, (int16_t)0x02ED, (int16_t)0x02ED, (int16_t)0x05F8,
|
||||
(int16_t)0x0838, (int16_t)0x08EE, (int16_t)0x09B4, (int16_t)0x08D1, (int16_t)0x07F4, (int16_t)0x0692, (int16_t)0x052E, (int16_t)0x0400, (int16_t)0x0314, (int16_t)0x0277,
|
||||
(int16_t)0x0276, (int16_t)0x0276, (int16_t)0x05F8, (int16_t)0x0838, (int16_t)0x08EE, (int16_t)0x08EE, (int16_t)0x081F, (int16_t)0x0753, (int16_t)0x0615, (int16_t)0x04C6,
|
||||
(int16_t)0x03BE, (int16_t)0x02D9, (int16_t)0x0252, (int16_t)0x021E, (int16_t)0x021E, (int16_t)0x0601, (int16_t)0x0841, (int16_t)0x08F7, (int16_t)0x0833, (int16_t)0x077B,
|
||||
(int16_t)0x06C3, (int16_t)0x059A, (int16_t)0x046B, (int16_t)0x0375, (int16_t)0x029E, (int16_t)0x0228, (int16_t)0x0204, (int16_t)0x0204, (int16_t)0x060B, (int16_t)0x084B,
|
||||
(int16_t)0x082C, (int16_t)0x0783, (int16_t)0x06DC, (int16_t)0x063B, (int16_t)0x0527, (int16_t)0x0406, (int16_t)0x032F, (int16_t)0x026D, (int16_t)0x0204, (int16_t)0x01E8,
|
||||
(int16_t)0x01E8, (int16_t)0x0614, (int16_t)0x0854, (int16_t)0x07A2, (int16_t)0x0700, (int16_t)0x065D, (int16_t)0x05C2, (int16_t)0x04BD, (int16_t)0x03B4, (int16_t)0x02E6,
|
||||
(int16_t)0x0242, (int16_t)0x01E9, (int16_t)0x0175, (int16_t)0x0175, (int16_t)0x0624, (int16_t)0x0798, (int16_t)0x06F3, (int16_t)0x0664, (int16_t)0x05DD, (int16_t)0x0554,
|
||||
(int16_t)0x045A, (int16_t)0x0358, (int16_t)0x02A2, (int16_t)0x0217, (int16_t)0x01D0, (int16_t)0x0160, (int16_t)0x0160, (int16_t)0x0634, (int16_t)0x0725, (int16_t)0x0685,
|
||||
(int16_t)0x05E7, (int16_t)0x054A, (int16_t)0x04C4, (int16_t)0x03DF, (int16_t)0x030D, (int16_t)0x025A, (int16_t)0x01D7, (int16_t)0x01B0, (int16_t)0x014C, (int16_t)0x014C,
|
||||
(int16_t)0x0634, (int16_t)0x060F, (int16_t)0x059B, (int16_t)0x0534, (int16_t)0x04A9, (int16_t)0x042E, (int16_t)0x0381, (int16_t)0x02C1, (int16_t)0x021C, (int16_t)0x0198,
|
||||
(int16_t)0x018C, (int16_t)0x0134, (int16_t)0x0134, (int16_t)0x0634, (int16_t)0x05F0, (int16_t)0x056A, (int16_t)0x0503, (int16_t)0x0476, (int16_t)0x0404, (int16_t)0x034D,
|
||||
(int16_t)0x02AA, (int16_t)0x01FB, (int16_t)0x0186, (int16_t)0x017B, (int16_t)0x0128, (int16_t)0x0128, (int16_t)0x0634, (int16_t)0x05CE, (int16_t)0x054E, (int16_t)0x04E7,
|
||||
(int16_t)0x045D, (int16_t)0x03D4, (int16_t)0x0323, (int16_t)0x027D, (int16_t)0x01ED, (int16_t)0x017E, (int16_t)0x016C, (int16_t)0x0121, (int16_t)0x0121, (int16_t)0x0634,
|
||||
(int16_t)0x05B4, (int16_t)0x0534, (int16_t)0x04CE, (int16_t)0x0443, (int16_t)0x03C8, (int16_t)0x0309, (int16_t)0x0263, (int16_t)0x01D4, (int16_t)0x0168, (int16_t)0x0164,
|
||||
(int16_t)0x011C, (int16_t)0x011C, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000,
|
||||
(int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x06AC, (int16_t)0x094A, (int16_t)0x09DC, (int16_t)0x0A89, (int16_t)0x0AF5,
|
||||
(int16_t)0x09D9, (int16_t)0x083A, (int16_t)0x06A5, (int16_t)0x054E, (int16_t)0x04AE, (int16_t)0x045E, (int16_t)0x046B, (int16_t)0x046B, (int16_t)0x06AC, (int16_t)0x094A,
|
||||
(int16_t)0x09DC, (int16_t)0x0A89, (int16_t)0x0AF5, (int16_t)0x09D9, (int16_t)0x083A, (int16_t)0x06A5, (int16_t)0x054E, (int16_t)0x04AE, (int16_t)0x03D3, (int16_t)0x03F3,
|
||||
(int16_t)0x03F3, (int16_t)0x06AC, (int16_t)0x094A, (int16_t)0x09DC, (int16_t)0x0A89, (int16_t)0x0AF5, (int16_t)0x09D9, (int16_t)0x083A, (int16_t)0x06A5, (int16_t)0x054E,
|
||||
(int16_t)0x044F, (int16_t)0x0376, (int16_t)0x03A2, (int16_t)0x03A2, (int16_t)0x06AC, (int16_t)0x094A, (int16_t)0x09DC, (int16_t)0x0A89, (int16_t)0x09A3, (int16_t)0x08B0,
|
||||
(int16_t)0x0755, (int16_t)0x05F2, (int16_t)0x04C6, (int16_t)0x03E5, (int16_t)0x0330, (int16_t)0x02F3, (int16_t)0x02F3, (int16_t)0x06AC, (int16_t)0x094A, (int16_t)0x09DC,
|
||||
(int16_t)0x09D6, (int16_t)0x08F2, (int16_t)0x081C, (int16_t)0x06DB, (int16_t)0x0594, (int16_t)0x047C, (int16_t)0x03B0, (int16_t)0x0314, (int16_t)0x02E3, (int16_t)0x02E3,
|
||||
(int16_t)0x06B5, (int16_t)0x0953, (int16_t)0x09E5, (int16_t)0x091B, (int16_t)0x0852, (int16_t)0x078D, (int16_t)0x065F, (int16_t)0x053D, (int16_t)0x0436, (int16_t)0x037E,
|
||||
(int16_t)0x02ED, (int16_t)0x02CF, (int16_t)0x02CF, (int16_t)0x06BF, (int16_t)0x095D, (int16_t)0x0938, (int16_t)0x087C, (int16_t)0x07BE, (int16_t)0x070A, (int16_t)0x05F5,
|
||||
(int16_t)0x04E2, (int16_t)0x03F9, (int16_t)0x034E, (int16_t)0x02C2, (int16_t)0x02B9, (int16_t)0x02B9, (int16_t)0x06C8, (int16_t)0x0966, (int16_t)0x0895, (int16_t)0x07E0,
|
||||
(int16_t)0x0735, (int16_t)0x068B, (int16_t)0x058A, (int16_t)0x048B, (int16_t)0x03BC, (int16_t)0x031E, (int16_t)0x029F, (int16_t)0x0238, (int16_t)0x0238, (int16_t)0x06D8,
|
||||
(int16_t)0x08B9, (int16_t)0x07F6, (int16_t)0x075B, (int16_t)0x06B2, (int16_t)0x060D, (int16_t)0x0518, (int16_t)0x042C, (int16_t)0x0375, (int16_t)0x02ED, (int16_t)0x027D,
|
||||
(int16_t)0x0221, (int16_t)0x0221, (int16_t)0x06E8, (int16_t)0x07BA, (int16_t)0x0734, (int16_t)0x06B7, (int16_t)0x061E, (int16_t)0x0585, (int16_t)0x04B2, (int16_t)0x03D1,
|
||||
(int16_t)0x032B, (int16_t)0x02BB, (int16_t)0x025F, (int16_t)0x0210, (int16_t)0x0210, (int16_t)0x06E8, (int16_t)0x071E, (int16_t)0x06A8, (int16_t)0x0623, (int16_t)0x0589,
|
||||
(int16_t)0x0500, (int16_t)0x043F, (int16_t)0x0372, (int16_t)0x02D9, (int16_t)0x0284, (int16_t)0x023E, (int16_t)0x01F8, (int16_t)0x01F8, (int16_t)0x06E8, (int16_t)0x0707,
|
||||
(int16_t)0x066E, (int16_t)0x05EB, (int16_t)0x055B, (int16_t)0x04E0, (int16_t)0x0424, (int16_t)0x0357, (int16_t)0x02BD, (int16_t)0x026A, (int16_t)0x022D, (int16_t)0x01EC,
|
||||
(int16_t)0x01EC, (int16_t)0x06E8, (int16_t)0x06E1, (int16_t)0x064E, (int16_t)0x05C8, (int16_t)0x053F, (int16_t)0x04C3, (int16_t)0x0406, (int16_t)0x0341, (int16_t)0x02AF,
|
||||
(int16_t)0x025B, (int16_t)0x0225, (int16_t)0x01E4, (int16_t)0x01E4, (int16_t)0x06E8, (int16_t)0x06C5, (int16_t)0x0631, (int16_t)0x05AC, (int16_t)0x052A, (int16_t)0x04A0,
|
||||
(int16_t)0x03E5, (int16_t)0x032D, (int16_t)0x0297, (int16_t)0x0243, (int16_t)0x0210, (int16_t)0x01CF, (int16_t)0x01CF, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000,
|
||||
/* 3-D angle combine (RPM x demand x angle_dec_cmd) -- 675 words @ 0x7D86. */
|
||||
static const int16_t phi_angle_3d_table[675] = {
|
||||
(int16_t)0x0A88, (int16_t)0x0A45, (int16_t)0x09CC, (int16_t)0x0905, (int16_t)0x0943, (int16_t)0x0881, (int16_t)0x079F, (int16_t)0x074F, (int16_t)0x06C2, (int16_t)0x0665,
|
||||
(int16_t)0x0532, (int16_t)0x04C3, (int16_t)0x03E6, (int16_t)0x036F, (int16_t)0x036F, (int16_t)0x0A88, (int16_t)0x0A45, (int16_t)0x09CC, (int16_t)0x0905, (int16_t)0x0943,
|
||||
(int16_t)0x0881, (int16_t)0x079F, (int16_t)0x074F, (int16_t)0x06C2, (int16_t)0x0665, (int16_t)0x0532, (int16_t)0x043A, (int16_t)0x0365, (int16_t)0x02E1, (int16_t)0x02E1,
|
||||
(int16_t)0x0A88, (int16_t)0x0A45, (int16_t)0x09CC, (int16_t)0x0905, (int16_t)0x0943, (int16_t)0x0881, (int16_t)0x079F, (int16_t)0x074F, (int16_t)0x06C2, (int16_t)0x05BE,
|
||||
(int16_t)0x04B2, (int16_t)0x03D5, (int16_t)0x0309, (int16_t)0x028C, (int16_t)0x028C, (int16_t)0x0A88, (int16_t)0x0A45, (int16_t)0x09CC, (int16_t)0x0905, (int16_t)0x0943,
|
||||
(int16_t)0x0881, (int16_t)0x079F, (int16_t)0x074F, (int16_t)0x064D, (int16_t)0x0558, (int16_t)0x045E, (int16_t)0x0392, (int16_t)0x02C9, (int16_t)0x0247, (int16_t)0x0247,
|
||||
(int16_t)0x0A88, (int16_t)0x0A45, (int16_t)0x09CC, (int16_t)0x0905, (int16_t)0x0943, (int16_t)0x0881, (int16_t)0x079F, (int16_t)0x06AD, (int16_t)0x05CA, (int16_t)0x04EB,
|
||||
(int16_t)0x040A, (int16_t)0x0351, (int16_t)0x029A, (int16_t)0x0214, (int16_t)0x0214, (int16_t)0x0A88, (int16_t)0x0A45, (int16_t)0x09CC, (int16_t)0x0905, (int16_t)0x083F,
|
||||
(int16_t)0x0786, (int16_t)0x06D0, (int16_t)0x0600, (int16_t)0x053E, (int16_t)0x0485, (int16_t)0x03C1, (int16_t)0x0312, (int16_t)0x0250, (int16_t)0x01CF, (int16_t)0x01CF,
|
||||
(int16_t)0x0990, (int16_t)0x0957, (int16_t)0x08DD, (int16_t)0x081E, (int16_t)0x075F, (int16_t)0x06C3, (int16_t)0x0624, (int16_t)0x056A, (int16_t)0x04AC, (int16_t)0x0413,
|
||||
(int16_t)0x036E, (int16_t)0x02D8, (int16_t)0x020F, (int16_t)0x01AE, (int16_t)0x01AE, (int16_t)0x08DD, (int16_t)0x0866, (int16_t)0x07FD, (int16_t)0x075C, (int16_t)0x06C7,
|
||||
(int16_t)0x0637, (int16_t)0x058C, (int16_t)0x04EB, (int16_t)0x043B, (int16_t)0x03A3, (int16_t)0x0314, (int16_t)0x029B, (int16_t)0x01D0, (int16_t)0x018C, (int16_t)0x018C,
|
||||
(int16_t)0x0832, (int16_t)0x07A9, (int16_t)0x073F, (int16_t)0x06A6, (int16_t)0x0614, (int16_t)0x0579, (int16_t)0x0508, (int16_t)0x0477, (int16_t)0x03C9, (int16_t)0x0348,
|
||||
(int16_t)0x02BF, (int16_t)0x024F, (int16_t)0x01A6, (int16_t)0x0165, (int16_t)0x0165, (int16_t)0x0798, (int16_t)0x0738, (int16_t)0x06CB, (int16_t)0x0643, (int16_t)0x05BB,
|
||||
(int16_t)0x053B, (int16_t)0x04A5, (int16_t)0x042E, (int16_t)0x0389, (int16_t)0x0313, (int16_t)0x027C, (int16_t)0x0205, (int16_t)0x0175, (int16_t)0x014C, (int16_t)0x014C,
|
||||
(int16_t)0x0721, (int16_t)0x06BA, (int16_t)0x0654, (int16_t)0x05DC, (int16_t)0x055F, (int16_t)0x04E0, (int16_t)0x0460, (int16_t)0x03C7, (int16_t)0x0346, (int16_t)0x02C8,
|
||||
(int16_t)0x0242, (int16_t)0x01C9, (int16_t)0x013C, (int16_t)0x0125, (int16_t)0x0125, (int16_t)0x067F, (int16_t)0x061F, (int16_t)0x05C3, (int16_t)0x054B, (int16_t)0x04E7,
|
||||
(int16_t)0x047A, (int16_t)0x0408, (int16_t)0x038D, (int16_t)0x0312, (int16_t)0x029D, (int16_t)0x0213, (int16_t)0x0192, (int16_t)0x0117, (int16_t)0x00FF, (int16_t)0x00FF,
|
||||
(int16_t)0x064B, (int16_t)0x05E5, (int16_t)0x0590, (int16_t)0x0510, (int16_t)0x04AF, (int16_t)0x0436, (int16_t)0x03C4, (int16_t)0x0348, (int16_t)0x02DF, (int16_t)0x027F,
|
||||
(int16_t)0x01F5, (int16_t)0x017B, (int16_t)0x0108, (int16_t)0x00E1, (int16_t)0x00E1, (int16_t)0x0618, (int16_t)0x05BA, (int16_t)0x0565, (int16_t)0x04EE, (int16_t)0x0472,
|
||||
(int16_t)0x040B, (int16_t)0x0388, (int16_t)0x031E, (int16_t)0x02B4, (int16_t)0x025B, (int16_t)0x01E0, (int16_t)0x0166, (int16_t)0x00F7, (int16_t)0x00D0, (int16_t)0x00D0,
|
||||
(int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000,
|
||||
(int16_t)0x07F1, (int16_t)0x0AFA, (int16_t)0x0B98, (int16_t)0x0C54, (int16_t)0x0CB6, (int16_t)0x0B9C, (int16_t)0x0A01, (int16_t)0x0868, (int16_t)0x0715, (int16_t)0x0676,
|
||||
(int16_t)0x0727, (int16_t)0x06B2, (int16_t)0x06B2, (int16_t)0x07F1, (int16_t)0x0AFA, (int16_t)0x0B98, (int16_t)0x0C54, (int16_t)0x0CB6, (int16_t)0x0B9C, (int16_t)0x0A01,
|
||||
(int16_t)0x0868, (int16_t)0x0715, (int16_t)0x0676, (int16_t)0x0598, (int16_t)0x05B6, (int16_t)0x05B6, (int16_t)0x07F1, (int16_t)0x0AFA, (int16_t)0x0B98, (int16_t)0x0C54,
|
||||
(int16_t)0x0CB6, (int16_t)0x0B9C, (int16_t)0x0A01, (int16_t)0x0868, (int16_t)0x0715, (int16_t)0x0616, (int16_t)0x053B, (int16_t)0x0559, (int16_t)0x0559, (int16_t)0x07F1,
|
||||
(int16_t)0x0AFA, (int16_t)0x0B98, (int16_t)0x0C54, (int16_t)0x0B6B, (int16_t)0x0A78, (int16_t)0x0915, (int16_t)0x07B5, (int16_t)0x068D, (int16_t)0x05A9, (int16_t)0x04F4,
|
||||
(int16_t)0x04B8, (int16_t)0x04B8, (int16_t)0x07F1, (int16_t)0x0AFA, (int16_t)0x0B98, (int16_t)0x0B99, (int16_t)0x0ABC, (int16_t)0x09E1, (int16_t)0x089D, (int16_t)0x0755,
|
||||
(int16_t)0x0642, (int16_t)0x0574, (int16_t)0x04D8, (int16_t)0x04A7, (int16_t)0x04A7, (int16_t)0x07FA, (int16_t)0x0B03, (int16_t)0x0BA1, (int16_t)0x0ADB, (int16_t)0x0A17,
|
||||
(int16_t)0x0951, (int16_t)0x0826, (int16_t)0x06FE, (int16_t)0x05FC, (int16_t)0x0543, (int16_t)0x04B1, (int16_t)0x0495, (int16_t)0x0495, (int16_t)0x0804, (int16_t)0x0B0D,
|
||||
(int16_t)0x0AF4, (int16_t)0x0A39, (int16_t)0x097D, (int16_t)0x08C8, (int16_t)0x07BA, (int16_t)0x06A5, (int16_t)0x05C0, (int16_t)0x0514, (int16_t)0x0486, (int16_t)0x047E,
|
||||
(int16_t)0x047E, (int16_t)0x080D, (int16_t)0x0B16, (int16_t)0x0A59, (int16_t)0x09A3, (int16_t)0x08F4, (int16_t)0x084B, (int16_t)0x074E, (int16_t)0x064E, (int16_t)0x0580,
|
||||
(int16_t)0x04E4, (int16_t)0x0463, (int16_t)0x03FC, (int16_t)0x03FC, (int16_t)0x081D, (int16_t)0x0A3B, (int16_t)0x09AD, (int16_t)0x0908, (int16_t)0x0862, (int16_t)0x07C2,
|
||||
(int16_t)0x06DB, (int16_t)0x05F1, (int16_t)0x053A, (int16_t)0x04B2, (int16_t)0x0442, (int16_t)0x03E5, (int16_t)0x03E5, (int16_t)0x082D, (int16_t)0x097D, (int16_t)0x08ED,
|
||||
(int16_t)0x0863, (int16_t)0x07CF, (int16_t)0x0737, (int16_t)0x0662, (int16_t)0x0593, (int16_t)0x04EE, (int16_t)0x047F, (int16_t)0x0424, (int16_t)0x03D2, (int16_t)0x03D2,
|
||||
(int16_t)0x082D, (int16_t)0x086E, (int16_t)0x07EE, (int16_t)0x077E, (int16_t)0x070C, (int16_t)0x0692, (int16_t)0x05E8, (int16_t)0x053B, (int16_t)0x049E, (int16_t)0x0448,
|
||||
(int16_t)0x0402, (int16_t)0x03BB, (int16_t)0x03BB, (int16_t)0x082D, (int16_t)0x0824, (int16_t)0x07A6, (int16_t)0x0738, (int16_t)0x06BC, (int16_t)0x0653, (int16_t)0x05B5,
|
||||
(int16_t)0x0516, (int16_t)0x047F, (int16_t)0x042E, (int16_t)0x03F2, (int16_t)0x03AF, (int16_t)0x03AF, (int16_t)0x082D, (int16_t)0x07FF, (int16_t)0x078A, (int16_t)0x071B,
|
||||
(int16_t)0x06A4, (int16_t)0x063D, (int16_t)0x05A0, (int16_t)0x0503, (int16_t)0x0470, (int16_t)0x041E, (int16_t)0x03E6, (int16_t)0x03A7, (int16_t)0x03A7, (int16_t)0x082D,
|
||||
(int16_t)0x07D6, (int16_t)0x0769, (int16_t)0x0705, (int16_t)0x068D, (int16_t)0x0628, (int16_t)0x058C, (int16_t)0x04F3, (int16_t)0x0460, (int16_t)0x040D, (int16_t)0x03D8,
|
||||
(int16_t)0x039B, (int16_t)0x039B, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000,
|
||||
(int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000
|
||||
(int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0003, (int16_t)0x0003, (int16_t)0x0B84, (int16_t)0x0B26, (int16_t)0x0BDB, (int16_t)0x0AE0, (int16_t)0x0AAE,
|
||||
(int16_t)0x09F4, (int16_t)0x094A, (int16_t)0x0890, (int16_t)0x0805, (int16_t)0x07A5, (int16_t)0x0655, (int16_t)0x0545, (int16_t)0x048F, (int16_t)0x0436, (int16_t)0x0436,
|
||||
(int16_t)0x0B84, (int16_t)0x0B26, (int16_t)0x0BDB, (int16_t)0x0AE0, (int16_t)0x0AAE, (int16_t)0x09F4, (int16_t)0x094A, (int16_t)0x0890, (int16_t)0x0805, (int16_t)0x06E2,
|
||||
(int16_t)0x05C9, (int16_t)0x04CF, (int16_t)0x0417, (int16_t)0x03C7, (int16_t)0x03C7, (int16_t)0x0B84, (int16_t)0x0B26, (int16_t)0x0BDB, (int16_t)0x0AE0, (int16_t)0x0AAE,
|
||||
(int16_t)0x09F4, (int16_t)0x094A, (int16_t)0x0890, (int16_t)0x077E, (int16_t)0x066B, (int16_t)0x0566, (int16_t)0x0480, (int16_t)0x03C4, (int16_t)0x0369, (int16_t)0x0369,
|
||||
(int16_t)0x0B84, (int16_t)0x0B26, (int16_t)0x0BDB, (int16_t)0x0AE0, (int16_t)0x0AAE, (int16_t)0x09F4, (int16_t)0x08E8, (int16_t)0x080B, (int16_t)0x070C, (int16_t)0x060B,
|
||||
(int16_t)0x051B, (int16_t)0x0440, (int16_t)0x0387, (int16_t)0x0325, (int16_t)0x0325, (int16_t)0x0B84, (int16_t)0x0B26, (int16_t)0x0BDB, (int16_t)0x0AE0, (int16_t)0x09F4,
|
||||
(int16_t)0x0936, (int16_t)0x0843, (int16_t)0x076C, (int16_t)0x068E, (int16_t)0x05A0, (int16_t)0x04C9, (int16_t)0x0403, (int16_t)0x0350, (int16_t)0x02D8, (int16_t)0x02D8,
|
||||
(int16_t)0x0B84, (int16_t)0x0B26, (int16_t)0x0AB2, (int16_t)0x09D7, (int16_t)0x0912, (int16_t)0x0851, (int16_t)0x0787, (int16_t)0x06BE, (int16_t)0x060A, (int16_t)0x053C,
|
||||
(int16_t)0x0476, (int16_t)0x03BD, (int16_t)0x0316, (int16_t)0x0297, (int16_t)0x0297, (int16_t)0x0ADD, (int16_t)0x0A4E, (int16_t)0x09C4, (int16_t)0x0909, (int16_t)0x0853,
|
||||
(int16_t)0x07A0, (int16_t)0x06DD, (int16_t)0x062B, (int16_t)0x0581, (int16_t)0x04DC, (int16_t)0x042A, (int16_t)0x038B, (int16_t)0x02E5, (int16_t)0x0269, (int16_t)0x0269,
|
||||
(int16_t)0x09B2, (int16_t)0x0937, (int16_t)0x08BF, (int16_t)0x082F, (int16_t)0x0795, (int16_t)0x0702, (int16_t)0x0669, (int16_t)0x05B4, (int16_t)0x0509, (int16_t)0x0477,
|
||||
(int16_t)0x03DA, (int16_t)0x0355, (int16_t)0x02A9, (int16_t)0x0246, (int16_t)0x0246, (int16_t)0x0929, (int16_t)0x08B8, (int16_t)0x0836, (int16_t)0x078A, (int16_t)0x06FC,
|
||||
(int16_t)0x0670, (int16_t)0x05C4, (int16_t)0x053B, (int16_t)0x04A7, (int16_t)0x0418, (int16_t)0x038D, (int16_t)0x031D, (int16_t)0x026F, (int16_t)0x021D, (int16_t)0x021D,
|
||||
(int16_t)0x0832, (int16_t)0x07BB, (int16_t)0x0754, (int16_t)0x06CB, (int16_t)0x0643, (int16_t)0x05DD, (int16_t)0x0549, (int16_t)0x04C3, (int16_t)0x0430, (int16_t)0x03AD,
|
||||
(int16_t)0x0334, (int16_t)0x02C0, (int16_t)0x0234, (int16_t)0x01F5, (int16_t)0x01F5, (int16_t)0x07FF, (int16_t)0x077F, (int16_t)0x0725, (int16_t)0x0698, (int16_t)0x0611,
|
||||
(int16_t)0x0594, (int16_t)0x0519, (int16_t)0x0491, (int16_t)0x040C, (int16_t)0x0392, (int16_t)0x030D, (int16_t)0x028D, (int16_t)0x0218, (int16_t)0x01EB, (int16_t)0x01EB,
|
||||
(int16_t)0x07C3, (int16_t)0x0733, (int16_t)0x06CB, (int16_t)0x066B, (int16_t)0x05F0, (int16_t)0x056A, (int16_t)0x04F7, (int16_t)0x046B, (int16_t)0x03C6, (int16_t)0x0346,
|
||||
(int16_t)0x02C6, (int16_t)0x024E, (int16_t)0x01FB, (int16_t)0x01DD, (int16_t)0x01DD, (int16_t)0x0790, (int16_t)0x070E, (int16_t)0x0698, (int16_t)0x061E, (int16_t)0x05B4,
|
||||
(int16_t)0x052D, (int16_t)0x04B4, (int16_t)0x0440, (int16_t)0x03AE, (int16_t)0x0322, (int16_t)0x02AC, (int16_t)0x0230, (int16_t)0x01DD, (int16_t)0x01CD, (int16_t)0x01CD,
|
||||
(int16_t)0x0754, (int16_t)0x06CB, (int16_t)0x066E, (int16_t)0x05E5, (int16_t)0x057B, (int16_t)0x04FB, (int16_t)0x0488, (int16_t)0x040D, (int16_t)0x0381, (int16_t)0x030B,
|
||||
(int16_t)0x027E, (int16_t)0x020C, (int16_t)0x01BB, (int16_t)0x01B6, (int16_t)0x01B6, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000,
|
||||
(int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0003, (int16_t)0x0003,
|
||||
(int16_t)0x0CA6, (int16_t)0x0CA6, (int16_t)0x0D83, (int16_t)0x0C7C, (int16_t)0x0B98, (int16_t)0x0B71, (int16_t)0x0A7A, (int16_t)0x0A0E, (int16_t)0x0913, (int16_t)0x080E,
|
||||
(int16_t)0x0724, (int16_t)0x0636, (int16_t)0x0667, (int16_t)0x059D, (int16_t)0x059D, (int16_t)0x0CA6, (int16_t)0x0CA6, (int16_t)0x0D83, (int16_t)0x0C7C, (int16_t)0x0B98,
|
||||
(int16_t)0x0B71, (int16_t)0x0A7A, (int16_t)0x0A0E, (int16_t)0x0913, (int16_t)0x080E, (int16_t)0x0724, (int16_t)0x0636, (int16_t)0x05E6, (int16_t)0x0527, (int16_t)0x0527,
|
||||
(int16_t)0x0CA6, (int16_t)0x0CA6, (int16_t)0x0D83, (int16_t)0x0C7C, (int16_t)0x0B98, (int16_t)0x0B71, (int16_t)0x0A7A, (int16_t)0x0A0E, (int16_t)0x0913, (int16_t)0x080E,
|
||||
(int16_t)0x0724, (int16_t)0x0636, (int16_t)0x0598, (int16_t)0x04DC, (int16_t)0x04DC, (int16_t)0x0CA6, (int16_t)0x0CA6, (int16_t)0x0D83, (int16_t)0x0C7C, (int16_t)0x0B98,
|
||||
(int16_t)0x0B71, (int16_t)0x0A7A, (int16_t)0x0987, (int16_t)0x089F, (int16_t)0x07AC, (int16_t)0x06D6, (int16_t)0x05FD, (int16_t)0x0556, (int16_t)0x04AE, (int16_t)0x04AE,
|
||||
(int16_t)0x0CA6, (int16_t)0x0CA6, (int16_t)0x0D83, (int16_t)0x0C7C, (int16_t)0x0B98, (int16_t)0x0ABC, (int16_t)0x09E0, (int16_t)0x0905, (int16_t)0x082C, (int16_t)0x0751,
|
||||
(int16_t)0x068D, (int16_t)0x05C3, (int16_t)0x051B, (int16_t)0x048A, (int16_t)0x048A, (int16_t)0x0CA6, (int16_t)0x0CA6, (int16_t)0x0C36, (int16_t)0x0B72, (int16_t)0x0AAE,
|
||||
(int16_t)0x09F6, (int16_t)0x093A, (int16_t)0x0879, (int16_t)0x07B5, (int16_t)0x06F1, (int16_t)0x063F, (int16_t)0x0589, (int16_t)0x04DE, (int16_t)0x045B, (int16_t)0x045B,
|
||||
(int16_t)0x0C62, (int16_t)0x0BDD, (int16_t)0x0B57, (int16_t)0x0A9C, (int16_t)0x09EE, (int16_t)0x0943, (int16_t)0x0893, (int16_t)0x07EB, (int16_t)0x0741, (int16_t)0x0691,
|
||||
(int16_t)0x05F6, (int16_t)0x0554, (int16_t)0x04A9, (int16_t)0x042C, (int16_t)0x042C, (int16_t)0x0B8C, (int16_t)0x0B19, (int16_t)0x0AA6, (int16_t)0x0A01, (int16_t)0x0953,
|
||||
(int16_t)0x08AA, (int16_t)0x0806, (int16_t)0x0769, (int16_t)0x06D0, (int16_t)0x0635, (int16_t)0x05AB, (int16_t)0x0522, (int16_t)0x046D, (int16_t)0x03FF, (int16_t)0x03FF,
|
||||
(int16_t)0x0B04, (int16_t)0x0A74, (int16_t)0x09E5, (int16_t)0x0959, (int16_t)0x08BC, (int16_t)0x081F, (int16_t)0x0780, (int16_t)0x06EE, (int16_t)0x065E, (int16_t)0x05C9,
|
||||
(int16_t)0x056C, (int16_t)0x04E6, (int16_t)0x042D, (int16_t)0x03D2, (int16_t)0x03D2, (int16_t)0x09CD, (int16_t)0x0966, (int16_t)0x08FF, (int16_t)0x084B, (int16_t)0x07E2,
|
||||
(int16_t)0x0775, (int16_t)0x06F2, (int16_t)0x066E, (int16_t)0x05F3, (int16_t)0x0579, (int16_t)0x050D, (int16_t)0x0481, (int16_t)0x03E8, (int16_t)0x03A4, (int16_t)0x03A4,
|
||||
(int16_t)0x096E, (int16_t)0x08F9, (int16_t)0x0883, (int16_t)0x07F8, (int16_t)0x0785, (int16_t)0x0726, (int16_t)0x06BF, (int16_t)0x0642, (int16_t)0x05C8, (int16_t)0x0548,
|
||||
(int16_t)0x04C9, (int16_t)0x0449, (int16_t)0x03C8, (int16_t)0x0394, (int16_t)0x0394, (int16_t)0x0921, (int16_t)0x08B2, (int16_t)0x0843, (int16_t)0x07A2, (int16_t)0x074E,
|
||||
(int16_t)0x06C9, (int16_t)0x065E, (int16_t)0x05EC, (int16_t)0x056A, (int16_t)0x04F4, (int16_t)0x047A, (int16_t)0x0407, (int16_t)0x03A9, (int16_t)0x035B, (int16_t)0x035B,
|
||||
(int16_t)0x0880, (int16_t)0x083A, (int16_t)0x07F4, (int16_t)0x077B, (int16_t)0x06F3, (int16_t)0x0699, (int16_t)0x060B, (int16_t)0x05B0, (int16_t)0x052C, (int16_t)0x04BF,
|
||||
(int16_t)0x044C, (int16_t)0x03DB, (int16_t)0x0392, (int16_t)0x0338, (int16_t)0x0338, (int16_t)0x07FF, (int16_t)0x07CA, (int16_t)0x0794, (int16_t)0x074F, (int16_t)0x06D8,
|
||||
(int16_t)0x067C, (int16_t)0x05E7, (int16_t)0x0587, (int16_t)0x0509, (int16_t)0x04A2, (int16_t)0x0437, (int16_t)0x03C6, (int16_t)0x0354, (int16_t)0x0327, (int16_t)0x0327,
|
||||
(int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000,
|
||||
(int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0000, (int16_t)0x0003, (int16_t)0x0003
|
||||
};
|
||||
|
||||
/* 2-D angle-kick combine (RPM x demand) -- consumed by compute_angle_kick_2d @ T06235 0x6D6B -- 195 words @ 0x8508. */
|
||||
static const int16_t phi_angle_2d_kick_table[195] = {
|
||||
(int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0B3A, (int16_t)0x0962, (int16_t)0x07B5, (int16_t)0x0607, (int16_t)0x053C, (int16_t)0x0499,
|
||||
(int16_t)0x0512, (int16_t)0x0A37, (int16_t)0x0949, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0B3A, (int16_t)0x0962, (int16_t)0x07B5,
|
||||
(int16_t)0x0607, (int16_t)0x053C, (int16_t)0x0499, (int16_t)0x0512, (int16_t)0x0A37, (int16_t)0x0949, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0CCD,
|
||||
(int16_t)0x0B3A, (int16_t)0x0962, (int16_t)0x07B5, (int16_t)0x0607, (int16_t)0x053C, (int16_t)0x0499, (int16_t)0x0512, (int16_t)0x0A37, (int16_t)0x0949, (int16_t)0x0CCD,
|
||||
(int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0B3A, (int16_t)0x0962, (int16_t)0x07B5, (int16_t)0x0607, (int16_t)0x053C, (int16_t)0x0499, (int16_t)0x0512,
|
||||
(int16_t)0x0A37, (int16_t)0x0949, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0CCD, (int16_t)0x0B3A, (int16_t)0x0962, (int16_t)0x07B5, (int16_t)0x0607,
|
||||
(int16_t)0x053C, (int16_t)0x0499, (int16_t)0x0512, (int16_t)0x0A37, (int16_t)0x0949, (int16_t)0x09FD, (int16_t)0x09FD, (int16_t)0x09FD, (int16_t)0x09FD, (int16_t)0x08B2,
|
||||
(int16_t)0x073D, (int16_t)0x0603, (int16_t)0x04CA, (int16_t)0x0472, (int16_t)0x042C, (int16_t)0x0504, (int16_t)0x0D6A, (int16_t)0x0748, (int16_t)0x072D, (int16_t)0x072D,
|
||||
(int16_t)0x072D, (int16_t)0x072D, (int16_t)0x062A, (int16_t)0x0517, (int16_t)0x0452, (int16_t)0x038C, (int16_t)0x03A8, (int16_t)0x03BF, (int16_t)0x04F6, (int16_t)0x109C,
|
||||
(int16_t)0x0547, (int16_t)0x04FA, (int16_t)0x04FA, (int16_t)0x04FA, (int16_t)0x04FA, (int16_t)0x03EF, (int16_t)0x03C2, (int16_t)0x031A, (int16_t)0x0273, (int16_t)0x030D,
|
||||
(int16_t)0x0388, (int16_t)0x048D, (int16_t)0x0BCB, (int16_t)0x04F6, (int16_t)0x02C6, (int16_t)0x02C6, (int16_t)0x02C6, (int16_t)0x02C6, (int16_t)0x01B3, (int16_t)0x026D,
|
||||
(int16_t)0x01E3, (int16_t)0x0159, (int16_t)0x0272, (int16_t)0x0352, (int16_t)0x0424, (int16_t)0x06FA, (int16_t)0x04A6, (int16_t)0x018E, (int16_t)0x018E, (int16_t)0x018E,
|
||||
(int16_t)0x018E, (int16_t)0x00FA, (int16_t)0x014C, (int16_t)0x0132, (int16_t)0x0118, (int16_t)0x0211, (int16_t)0x02D8, (int16_t)0x03A0, (int16_t)0x0657, (int16_t)0x04CB,
|
||||
(int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0040, (int16_t)0x002B, (int16_t)0x0081, (int16_t)0x00D7, (int16_t)0x01B0, (int16_t)0x025E,
|
||||
(int16_t)0x031C, (int16_t)0x05B4, (int16_t)0x04F0, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0040, (int16_t)0x002B, (int16_t)0x0081,
|
||||
(int16_t)0x00D7, (int16_t)0x01B0, (int16_t)0x025E, (int16_t)0x031C, (int16_t)0x05B4, (int16_t)0x04F0, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0055,
|
||||
(int16_t)0x0040, (int16_t)0x002B, (int16_t)0x0081, (int16_t)0x00D7, (int16_t)0x01B0, (int16_t)0x025E, (int16_t)0x031C, (int16_t)0x05B4, (int16_t)0x04F0, (int16_t)0x0055,
|
||||
(int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0040, (int16_t)0x002B, (int16_t)0x0081, (int16_t)0x00D7, (int16_t)0x01B0, (int16_t)0x025E, (int16_t)0x031C,
|
||||
(int16_t)0x05B4, (int16_t)0x04F0, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0055, (int16_t)0x0040, (int16_t)0x002B, (int16_t)0x0081, (int16_t)0x00D7,
|
||||
(int16_t)0x01B0, (int16_t)0x025E, (int16_t)0x031C, (int16_t)0x05B4, (int16_t)0x04F0
|
||||
/* 2-D angle-kick combine (RPM x demand) -- consumed by orphan FUN_5D58 @ 0x5D8D -- 225 words @ 0x82CC. */
|
||||
static const int16_t phi_angle_2d_kick_table[225] = {
|
||||
(int16_t)0x0B0D, (int16_t)0x0B0D, (int16_t)0x0CAD, (int16_t)0x0D73, (int16_t)0x0BFB, (int16_t)0x0B63, (int16_t)0x0A4B, (int16_t)0x08F7, (int16_t)0x085F, (int16_t)0x0720,
|
||||
(int16_t)0x0838, (int16_t)0x0CEE, (int16_t)0x0616, (int16_t)0x05B2, (int16_t)0x05B2, (int16_t)0x0B0D, (int16_t)0x0B0D, (int16_t)0x0CAD, (int16_t)0x0D73, (int16_t)0x0BFB,
|
||||
(int16_t)0x0B63, (int16_t)0x0A4B, (int16_t)0x08F7, (int16_t)0x085F, (int16_t)0x0720, (int16_t)0x0838, (int16_t)0x0CEE, (int16_t)0x0616, (int16_t)0x05B2, (int16_t)0x05B2,
|
||||
(int16_t)0x0B0D, (int16_t)0x0B0D, (int16_t)0x0CAD, (int16_t)0x0D73, (int16_t)0x0BFB, (int16_t)0x0B63, (int16_t)0x0A4B, (int16_t)0x08F7, (int16_t)0x085F, (int16_t)0x0720,
|
||||
(int16_t)0x0838, (int16_t)0x0CEE, (int16_t)0x0616, (int16_t)0x05B2, (int16_t)0x05B2, (int16_t)0x0B0D, (int16_t)0x0B0D, (int16_t)0x0CAD, (int16_t)0x0D73, (int16_t)0x0BFB,
|
||||
(int16_t)0x0B63, (int16_t)0x0A4B, (int16_t)0x08F7, (int16_t)0x085F, (int16_t)0x0720, (int16_t)0x0838, (int16_t)0x0CEE, (int16_t)0x0616, (int16_t)0x05B2, (int16_t)0x05B2,
|
||||
(int16_t)0x0B0D, (int16_t)0x0B0D, (int16_t)0x0CAD, (int16_t)0x0D73, (int16_t)0x0BFB, (int16_t)0x0B63, (int16_t)0x0A4B, (int16_t)0x08F7, (int16_t)0x085F, (int16_t)0x0720,
|
||||
(int16_t)0x0838, (int16_t)0x0CEE, (int16_t)0x0616, (int16_t)0x05B2, (int16_t)0x05B2, (int16_t)0x0B0D, (int16_t)0x0B0D, (int16_t)0x0CAD, (int16_t)0x0B30, (int16_t)0x0AA5,
|
||||
(int16_t)0x08BC, (int16_t)0x07E7, (int16_t)0x07E9, (int16_t)0x06A6, (int16_t)0x0613, (int16_t)0x0831, (int16_t)0x0CF2, (int16_t)0x04EB, (int16_t)0x05FE, (int16_t)0x05FE,
|
||||
(int16_t)0x0686, (int16_t)0x0686, (int16_t)0x0632, (int16_t)0x0886, (int16_t)0x06A4, (int16_t)0x0661, (int16_t)0x05C9, (int16_t)0x04A3, (int16_t)0x0526, (int16_t)0x0525,
|
||||
(int16_t)0x06B5, (int16_t)0x09CF, (int16_t)0x039E, (int16_t)0x04BA, (int16_t)0x04BA, (int16_t)0x0660, (int16_t)0x0660, (int16_t)0x05D3, (int16_t)0x067D, (int16_t)0x0572,
|
||||
(int16_t)0x04B2, (int16_t)0x0495, (int16_t)0x032B, (int16_t)0x044F, (int16_t)0x0403, (int16_t)0x0579, (int16_t)0x06D7, (int16_t)0x0443, (int16_t)0x0431, (int16_t)0x0431,
|
||||
(int16_t)0x05C5, (int16_t)0x05C5, (int16_t)0x0388, (int16_t)0x045D, (int16_t)0x048D, (int16_t)0x0427, (int16_t)0x0306, (int16_t)0x029E, (int16_t)0x0230, (int16_t)0x02D8,
|
||||
(int16_t)0x055D, (int16_t)0x0397, (int16_t)0x031F, (int16_t)0x03BC, (int16_t)0x03BC, (int16_t)0x0235, (int16_t)0x0235, (int16_t)0x0423, (int16_t)0x0463, (int16_t)0x01B4,
|
||||
(int16_t)0x0236, (int16_t)0x0371, (int16_t)0x01A1, (int16_t)0x0215, (int16_t)0x0274, (int16_t)0x025F, (int16_t)0x0255, (int16_t)0x0286, (int16_t)0x028E, (int16_t)0x028E,
|
||||
(int16_t)0x0235, (int16_t)0x0235, (int16_t)0x0154, (int16_t)0x005D, (int16_t)0x02B8, (int16_t)0x004B, (int16_t)0x01A0, (int16_t)0x0134, (int16_t)0x0133, (int16_t)0x015B,
|
||||
(int16_t)0x0152, (int16_t)0x022F, (int16_t)0x0202, (int16_t)0x0224, (int16_t)0x0224, (int16_t)0x0235, (int16_t)0x0235, (int16_t)0x0154, (int16_t)0x005D, (int16_t)0x02B8,
|
||||
(int16_t)0x004B, (int16_t)0x01A0, (int16_t)0x0134, (int16_t)0x0133, (int16_t)0x015B, (int16_t)0x0152, (int16_t)0x022F, (int16_t)0x0202, (int16_t)0x0224, (int16_t)0x0224,
|
||||
(int16_t)0x0235, (int16_t)0x0235, (int16_t)0x0154, (int16_t)0x005D, (int16_t)0x02B8, (int16_t)0x004B, (int16_t)0x01A0, (int16_t)0x0134, (int16_t)0x0133, (int16_t)0x015B,
|
||||
(int16_t)0x0152, (int16_t)0x022F, (int16_t)0x0202, (int16_t)0x0224, (int16_t)0x0224, (int16_t)0x0235, (int16_t)0x0235, (int16_t)0x0154, (int16_t)0x005D, (int16_t)0x02B8,
|
||||
(int16_t)0x004B, (int16_t)0x01A0, (int16_t)0x0134, (int16_t)0x0133, (int16_t)0x015B, (int16_t)0x0152, (int16_t)0x022F, (int16_t)0x0202, (int16_t)0x0224, (int16_t)0x0224,
|
||||
(int16_t)0x0235, (int16_t)0x0235, (int16_t)0x0154, (int16_t)0x005D, (int16_t)0x02B8, (int16_t)0x004B, (int16_t)0x01A0, (int16_t)0x0134, (int16_t)0x0133, (int16_t)0x015B,
|
||||
(int16_t)0x0152, (int16_t)0x022F, (int16_t)0x0202, (int16_t)0x0224, (int16_t)0x0224
|
||||
};
|
||||
|
||||
/* ======================================================================
|
||||
* Master calibration literal.
|
||||
* ====================================================================== */
|
||||
|
||||
calibration_t phi_t06235_cal = {
|
||||
/* RWA4-relative scalars (base 0x9BB8) */
|
||||
.tein_nominal = (int16_t)0x0C28, /* CAL+0x1E @ 0x9BD6 -- tein_nominal -- nominal TE_IN base (T06215 cal+0x1E unchanged) */
|
||||
.cal_48 = (int16_t)0x04B0, /* CAL+0x4A @ 0x9C02 -- RW7A latch value when FUN_62a2 fires (T06235 shift +0x02 from T06215 cal+0x48) */
|
||||
.phi0 = (int16_t)0x0DAB, /* CAL+0x4E @ 0x9C06 -- phi0: base/initial angle (T06215 cal+0x4C, T06235 +0x02) */
|
||||
.cal_byte_9c = 0x03u, /* CAL+0x9E @ 0x9C56 -- FUN_62a2 counter increment (T06215 cal+0x9C, T06235 +0x02) */
|
||||
.cal_54 = (int16_t)0x08DE, /* CAL+0x56 @ 0x9C0E -- UPPER clamp on target_inj_angle (T06215 cal+0x54, T06235 +0x02; value differs) */
|
||||
.cal_74 = (int16_t)0x20C5, /* CAL+0x76 @ 0x9C2E -- gate_0220 lower RPM threshold (T06215 cal+0x74, T06235 +0x02) */
|
||||
.cal_76 = (int16_t)0x01A3, /* CAL+0x78 @ 0x9C30 -- gate_0220 hysteresis width (T06215 cal+0x76, T06235 +0x02) */
|
||||
.cal_78 = (int16_t)0x007F, /* CAL+0x7A @ 0x9C32 -- accel_comp_offset upper clamp (T06215 cal+0x78, T06235 +0x02) */
|
||||
.cal_7a = (int16_t)0xFFCF, /* CAL+0x7C @ 0x9C34 -- accel_comp_offset lower clamp (T06215 cal+0x7A, T06235 +0x02) */
|
||||
.cal_7e = (int16_t)0x1390, /* CAL+0x80 @ 0x9C38 -- temperature reference subtrahend in compute_temp_comp_factor (read at T06235 0x6DE4; T06215 cal+0x7E) */
|
||||
.cal_temp_comp_switch_dynamic = (int16_t)0x1702, /* CAL+0x82 @ 0x9C3A -- boot value of temp_comp_dynamic = TK_AT_W switch (T06215 cal+0x80, T06235 +0x02) */
|
||||
.cal_82 = (int16_t)0x026F, /* CAL+0x84 @ 0x9C3C -- IIR input gain b for iir_step_unsigned (read at T06235 0x6E3D; T06215 cal+0x82) */
|
||||
.cal_84 = (int16_t)0xFD91, /* CAL+0x86 @ 0x9C3E -- IIR pole coefficient a for iir_step_unsigned (read at T06235 0x6E25/0x6E2E; T06215 cal+0x84) */
|
||||
.cal_temp_comp_switch_complete = (int16_t)0x0001, /* CAL+0x88 @ 0x9C40 -- boot value of temp_comp_complete = F_TK_TE_W switch (T06215 cal+0x86, T06235 +0x02) */
|
||||
.cal_92 = (int16_t)0x1750, /* CAL+0x94 @ 0x9C4C -- temperature offset subtracted in tein_overtemp_guard (T06215 cal+0x92, T06235 +0x02) */
|
||||
.cal_94 = (int16_t)0x0008, /* CAL+0x96 @ 0x9C4E -- tein_overtemp_guard multiplier (T06215 cal+0x94, T06235 +0x02) */
|
||||
.cal_96 = (int16_t)0x04B0, /* CAL+0x98 @ 0x9C50 -- tein_overtemp_guard RW1C upper clamp (T06215 cal+0x96, T06235 +0x02) */
|
||||
.cal_98 = (int16_t)0x1D7E, /* CAL+0x9A @ 0x9C52 -- tein_overtemp_guard lower RPM (T06215 cal+0x98, T06235 +0x02) */
|
||||
.cal_9a = (int16_t)0x3127, /* CAL+0x9C @ 0x9C54 -- tein_overtemp_guard upper RPM (T06215 cal+0x9A, T06235 +0x02) */
|
||||
/* RWC6-relative scalars (base 0x8002) */
|
||||
.cal_rwc6_34 = (int16_t)0x0831, /* RWC6+0x34 @ 0x8036 -- demand-weight multiplier in compute_angle_kick_2d (T06235 0x6D9D; same RWC6 offset as T06215) */
|
||||
calibration_t phi_t06211_cal = {
|
||||
/* RWA4-relative scalars (base 0x9BD8) */
|
||||
.tein_nominal = (int16_t)0x0C28, /* CAL+0x1E @ 0x9BF6 -- tein_nominal — nominal TE_IN base added to tein_valve_fault_guard / tein_overtemp_guard (FUN_7453 0x747b) */
|
||||
.cal_48 = (int16_t)0x04B0, /* CAL+0x48 @ 0x9C20 -- RW7A latch value when FUN_62a2 fires (0x62d8) */
|
||||
.phi0 = (int16_t)0x0DAB, /* CAL+0x4C @ 0x9C24 -- phi0: base/initial angle. ROM addend baked into phi1 (= *(0x014e)) by FUN_6aaf (0x6ad2); FUN_7453 reads phi0 + dphi at 0x74a2 */
|
||||
.cal_byte_56 = 0x0Du, /* CAL+0x56 @ 0x9C2E -- tooth phase comparand for rpm_baseline producer (T06211 producer @ 0x5153 from dispatcher 0x7969) */
|
||||
.cal_byte_9c = 0x03u, /* CAL+0x9C @ 0x9C74 -- FUN_62a2 counter increment (0x62c6) */
|
||||
.cal_54 = (int16_t)0x0B2B, /* CAL+0x54 @ 0x9C2C -- UPPER clamp on target_inj_angle (FUN_7453 0x7493) */
|
||||
.cal_74 = (int16_t)0x20C5, /* CAL+0x74 @ 0x9C4C -- gate_0220 lower RPM threshold */
|
||||
.cal_76 = (int16_t)0x01A3, /* CAL+0x76 @ 0x9C4E -- gate_0220 hysteresis width (upper = cal_74 + cal_76) */
|
||||
.cal_78 = (int16_t)0x007F, /* CAL+0x78 @ 0x9C50 -- accel_comp_offset upper clamp (FUN_732d 0x7340) */
|
||||
.cal_7a = (int16_t)0xFFCF, /* CAL+0x7A @ 0x9C52 -- accel_comp_offset lower clamp (FUN_732d 0x734e) */
|
||||
.cal_7e = (int16_t)0x13C0, /* CAL+0x7E @ 0x9C56 -- temperature reference subtrahend in compute_temp_comp_factor (FUN_5DAB 0x5DD1) */
|
||||
.cal_temp_comp_switch_dynamic = (int16_t)0x1702, /* CAL+0x80 @ 0x9C58 -- boot value of *(0x02F6) = TK_AT_W switch (compute_temp_comp_factor 0x5DB4) */
|
||||
.cal_82 = (int16_t)0x026F, /* CAL+0x82 @ 0x9C5A -- IIR input gain b for phi_tick_1khz (FUN_6b4e MULU at 0x6B66; Q16 unsigned) */
|
||||
.cal_84 = (int16_t)0xFD91, /* CAL+0x84 @ 0x9C5C -- IIR pole coefficient a for phi_tick_1khz (FUN_6b4e MULU at 0x6B4E and 0x6B57; Q16 unsigned) */
|
||||
.cal_temp_comp_switch_complete = (int16_t)0x0001, /* CAL+0x86 @ 0x9C5E -- boot value of *(0x02F2) = F_TK_TE_W switch (compute_temp_comp_factor 0x5DDB) */
|
||||
.cal_92 = (int16_t)0x1750, /* CAL+0x92 @ 0x9C6A -- temperature offset subtracted in FUN_5ca1 (0x5cf7) */
|
||||
.cal_94 = (int16_t)0x0008, /* CAL+0x94 @ 0x9C6C -- FUN_5ca1 multiplier (0x5d05) */
|
||||
.cal_96 = (int16_t)0x04B0, /* CAL+0x96 @ 0x9C6E -- FUN_5ca1 RW1C upper clamp (0x5d0b, unsigned) */
|
||||
.cal_98 = (int16_t)0x1D7E, /* CAL+0x98 @ 0x9C70 -- tein_overtemp_guard lower RPM (FUN_5ca1 0x5d1a, unsigned) */
|
||||
.cal_9a = (int16_t)0x3127, /* CAL+0x9A @ 0x9C72 -- tein_overtemp_guard upper RPM (FUN_5ca1 0x5d21, unsigned) */
|
||||
/* RWC6-relative scalars (base 0x7D0E) */
|
||||
.cal_rwc6_34 = (int16_t)0x0831, /* RWC6+0x34 @ 0x7D42 -- demand-weight multiplier in compute_angle_kick_2d (orphan FUN_5D58 @ 0x5D81) */
|
||||
|
||||
/* Accel descriptors (input_var bound at runtime by phi_t06235_bind_inputs). */
|
||||
/* Accel descriptors (input_var bound at runtime by phi_t06211_bind_inputs). */
|
||||
.desc_accel_rpm = {
|
||||
.runtime_slot = 0,
|
||||
.input_var = NULL,
|
||||
@@ -198,14 +216,14 @@ calibration_t phi_t06235_cal = {
|
||||
.accel_refine_table = phi_accel_refine_table,
|
||||
|
||||
/* Absolute-address ROM constants. */
|
||||
.dat_604c = (int16_t)0x0444, /* *(0x604C) -- FUN_62a2 RWC2 timing threshold (T06215 = 0x0444; verify) */
|
||||
.cal_byte_402 = (int16_t)0xFFF5, /* *(0x0402) -- FUN_6ba3-equivalent sign-extends byte 0x0402 in temp_comp_factor (T06235 0x6DE9 reads abs *(0x0402)) */
|
||||
.dat_604c = (int16_t)0x0444, /* *(0x604C) -- FUN_62a2 RWC2 timing threshold (= 0x0444) */
|
||||
.cal_byte_402 = (int16_t)0xFFF8, /* *(0x0402) -- FUN_5e67 sign-extends byte 0x0402 (compute_temp_comp_factor 0x5DD6) */
|
||||
|
||||
/* Angle accumulator descriptors (RWC6-relative; identical to T06215; input_var bound at runtime). */
|
||||
/* Angle accumulator descriptors (FUN_722e, RWC6-relative; input_var bound at runtime). */
|
||||
.desc_rpm = {
|
||||
.runtime_slot = 0,
|
||||
.input_var = NULL,
|
||||
.stride_items = 13,
|
||||
.stride_items = 15,
|
||||
.axis = phi_angle_axis_rpm,
|
||||
},
|
||||
.desc_demand = {
|
||||
@@ -226,7 +244,11 @@ calibration_t phi_t06235_cal = {
|
||||
.data_table_2d_kick = phi_angle_2d_kick_table,
|
||||
};
|
||||
|
||||
void phi_t06235_bind_inputs(runtime_state_t *rt, calibration_t *cal)
|
||||
/* ======================================================================
|
||||
* Runtime input binder.
|
||||
* ====================================================================== */
|
||||
|
||||
void phi_t06211_bind_inputs(runtime_state_t *rt, calibration_t *cal)
|
||||
{
|
||||
cal->desc_accel_rpm.input_var = (int16_t *)&rt->rpm;
|
||||
cal->desc_accel_demand.input_var = &rt->inj_qty_demand;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "phi.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "ee_manager.h"
|
||||
|
||||
#define CF_TMS 8.388f
|
||||
#define CF_ME 32.0f
|
||||
@@ -34,6 +35,8 @@
|
||||
/* Per-call input cache. FM_GET_PHIAD's float args land here so the
|
||||
* nullary phi getters can read them. */
|
||||
static float s_rpm = 0.0f;
|
||||
static float s_rpm_offset = 0.0f;
|
||||
|
||||
static float s_me = 0.0f;
|
||||
static float s_temp = 0.0f;
|
||||
|
||||
@@ -44,6 +47,13 @@ static phi_input_getters_t s_phi_getters;
|
||||
static phi_outputs_t s_phi_out;
|
||||
static float *s_phiad_out = NULL;
|
||||
|
||||
float s_c2;
|
||||
float s_103;
|
||||
float s_108;
|
||||
|
||||
extern float MT_offset_RPM;
|
||||
extern float B_PHIAD;
|
||||
|
||||
/* ──── Getters (nullary; T06215 vtable shape) ────────────────────────── */
|
||||
|
||||
static uint16_t get_rpm(void) { return (uint16_t)(s_rpm * CF_TMS); }
|
||||
@@ -55,18 +65,18 @@ static int16_t get_temperature(void) { return (int16_t) (s_temp * CF_T_M +
|
||||
* extern float B_PHIAD;
|
||||
* return (int16_t)(B_PHIAD * CF_KW);
|
||||
*/
|
||||
static int16_t get_angle_dec_cmd(void) { return 0; }
|
||||
static int16_t get_angle_dec_cmd(void) { return (uint16_t)(B_PHIAD * CF_KW); }
|
||||
|
||||
/* Steady-state default: baseline tracks current RPM, so Δ-rpm = 0 and
|
||||
* the accel-comp branch contributes nothing. Override if modelling
|
||||
* transients. */
|
||||
static int16_t get_rpm_baseline(void) { return (int16_t)(s_rpm * CF_TMS); }
|
||||
static int16_t get_rpm_baseline(void) { return (int16_t)(MT_offset_RPM * CF_TMS); }
|
||||
|
||||
static uint16_t get_rwc2(void) { return 0; } /* slow timing scratch */
|
||||
static uint8_t get_reset_gate_0226(void) { return 0xFF; } /* accel-comp enabled */
|
||||
static int16_t get_dphi(void) { return 0; }
|
||||
static uint8_t get_scratch_0103(void) { return 0xFF; } /* matches sim_t06215_sweep.c */
|
||||
static uint8_t get_scratch_0108(void) { return 0xFF; }
|
||||
static int16_t get_dphi(void) { return (int16_t)(s_dfi_code); }
|
||||
static uint8_t get_scratch_0103(void) { return 0x78; } /* matches sim_t06215_sweep.c */
|
||||
static uint8_t get_scratch_0108(void) { return 0x9A; }
|
||||
|
||||
/* ──── Public API ─────────────────────────────────────────────────────── */
|
||||
|
||||
@@ -79,12 +89,12 @@ void init_FuelMap(float *PHIAD) {
|
||||
s_phi_getters.get_angle_dec_cmd = get_angle_dec_cmd;
|
||||
s_phi_getters.get_rpm_baseline = get_rpm_baseline;
|
||||
s_phi_getters.get_rwc2 = get_rwc2;
|
||||
s_phi_getters.get_reset_gate_0226 = get_reset_gate_0226;
|
||||
s_phi_getters.get_reset_gate_0226 = get_reset_gate_0226; //this is is_accel_comp_disabled
|
||||
s_phi_getters.get_dphi = get_dphi;
|
||||
s_phi_getters.get_scratch_0103 = get_scratch_0103;
|
||||
s_phi_getters.get_scratch_0108 = get_scratch_0108;
|
||||
|
||||
s_phi_cal = phi_t06235_cal;
|
||||
s_phi_cal = phi_t06211_cal;
|
||||
phi_init(&s_phi_state, &s_phi_cal, &s_phi_getters);
|
||||
|
||||
/* Pre-latch to skip the cranking-phase ramp (mirrors
|
||||
@@ -98,20 +108,32 @@ void Timer1_FM_ISR(){
|
||||
phi_tick_1khz(&s_phi_state, &s_phi_cal);
|
||||
}
|
||||
|
||||
void TW_FM_ISR(uint8_t currentTooth, uint32_t ic){
|
||||
//phi_tick_1khz(&s_phi_state, &s_phi_cal);
|
||||
}
|
||||
extern float forceTemp, MT_RPM;
|
||||
int16_t rw3e = 0;
|
||||
int16_t rw3c = 0;
|
||||
int16_t rw164 = 0;
|
||||
|
||||
extern float forceTemp;
|
||||
float FM_GET_PHIAD(float RPM, float ME, float Temp) {
|
||||
s_rpm = RPM;
|
||||
s_rpm = MT_RPM;
|
||||
//s_rpm_offset = MT_offset_RPM;
|
||||
s_me = ME;
|
||||
s_temp = Temp;
|
||||
|
||||
phi_service(&s_phi_state, &s_phi_cal, &s_phi_out);
|
||||
|
||||
float Z = (float)s_phi_out.angle_accumulator * ANGLE_DEG_PER_RAW;
|
||||
rw3e = s_phi_out.angle_kick_2d;
|
||||
rw164 = s_phi_out.accel_comp_gain;
|
||||
rw3c = s_phi_out.accel_comp_offset;
|
||||
|
||||
Z = s_me ? Z : 0; // el terrano se apagaba
|
||||
|
||||
if (s_phiad_out) *s_phiad_out = Z;
|
||||
return Z;
|
||||
}
|
||||
void TW_midrpm_isr(){
|
||||
phi_per_cylinder_event(&s_phi_state, &s_phi_cal);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -89,6 +89,9 @@ extern float last_accel;
|
||||
uint8_t awaitingInj = 0;
|
||||
|
||||
float INJ_GET_NOMINAL_EOI();
|
||||
void INJ_UPDATE_PHIAD(){
|
||||
FM_GET_PHIAD(MT_RPM, ME, Temp);
|
||||
}
|
||||
void INJ_UPDATE_ALPHA(){
|
||||
/*float rp_sum = MT_RPM + last_MT_RPM;
|
||||
float dt = (PHI1 + dFi) / 90 * (1.0f / CYLINDERS) * (120.0f / rp_sum);
|
||||
@@ -98,7 +101,6 @@ void INJ_UPDATE_ALPHA(){
|
||||
//FM_GET_PHIAD(MT_RPM, ME, forceTemp);
|
||||
|
||||
//correction_eoi_accel = TM_GET_ACCEL_CORRECTION(last_MT_RPM, MT_RPM, TEETH_RPM);
|
||||
FM_GET_PHIAD(MT_RPM, ME, Temp);
|
||||
|
||||
float target = INJ_UPDATE_TARGET_EOI() + correction_eoi;
|
||||
|
||||
@@ -138,7 +140,7 @@ void INJ_PREPARE_ONCE(){
|
||||
TIM1->PSC = 20-1;
|
||||
}
|
||||
INJ_PREPARE_BIP(0);
|
||||
INJ_UPDATE_ALPHA();
|
||||
//INJ_UPDATE_ALPHA();
|
||||
INJ_UPDATE_TYPE();
|
||||
|
||||
}
|
||||
@@ -148,7 +150,7 @@ void INJ_PREPARE_BIP(uint8_t teeth){
|
||||
if(teeth < triggerTeeth || !triggerTeeth)
|
||||
{
|
||||
INJ_UPDATE_BOI_TRIGGER();
|
||||
INJ_UPDATE_ALPHA();
|
||||
//INJ_UPDATE_ALPHA();
|
||||
}
|
||||
//correction_boi_accel_2 = TM_UPDATE_ACCEL_CORRECTION_BIP(last_MT_RPM, MT_RPM, TEETH_RPM);
|
||||
//correction_beta = s_boi_corr_deg + correction_boi_accel_2;
|
||||
@@ -470,7 +472,9 @@ void SEND1_Handler(
|
||||
#if defined(T06301)
|
||||
startupiscar = 1;
|
||||
#endif
|
||||
if(!isInjecting && !hasInjectionEnded){
|
||||
if(!isInjecting && !hasInjectionEnded){//
|
||||
INJ_UPDATE_PHIAD();
|
||||
|
||||
INJ_UPDATE_ALPHA();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ volatile float RPM;
|
||||
|
||||
volatile float MT_frequency = 0;
|
||||
volatile float MT_RPM = 0;
|
||||
volatile float MT_offset_RPM = 0;
|
||||
|
||||
//volatile float next_MT_RPM = 0;
|
||||
|
||||
volatile float last_MT_RPM = 0;
|
||||
@@ -46,6 +48,7 @@ volatile float last_TEETHRPM = 0;
|
||||
volatile uint8_t SYNCOUT_clear = 0;
|
||||
|
||||
volatile uint32_t RPM_Difference;
|
||||
volatile uint32_t RPM_offset_Difference;
|
||||
|
||||
volatile uint8_t startedEngine = 0;
|
||||
volatile uint8_t count_CKP = 0;
|
||||
@@ -191,7 +194,16 @@ void TW_TEETH_CAPTURE(){
|
||||
INJ_EVAL_EOI_COMPENSATION();
|
||||
}
|
||||
INJ_EVAL_END();
|
||||
if(currentTooth == 13){
|
||||
|
||||
RPM_offset_Difference = IC_RPM_Val2 - edgeBuf[currentTooth].ic;
|
||||
MT_offset_RPM = fclamp(60.0 * (refClock/RPM_offset_Difference) / CYLINDERS, MIN_RPM, 4000);
|
||||
if(MT_RPM <15){
|
||||
MT_offset_RPM = MT_RPM;
|
||||
}
|
||||
TW_midrpm_isr();
|
||||
|
||||
}
|
||||
UpdateEdgeBuffer(IC_RPM_Val2, TEETH_RPM, currentTooth, isInjecting);
|
||||
|
||||
if(!hasInjected){
|
||||
@@ -225,7 +237,6 @@ void TW_TEETH_CAPTURE(){
|
||||
INJ_END();
|
||||
}
|
||||
|
||||
|
||||
hasCapturedTeeth = 1;
|
||||
|
||||
if(hasInjectionEndedFlag == 1){
|
||||
@@ -394,7 +405,6 @@ void TW_CALC_FBKW_FEEDBACK(){
|
||||
diffbot = FBKW_FEEDBACK_MIN - fb_1;
|
||||
difftop = fb_1 - FBKW_FEEDBACK_MAX;
|
||||
}
|
||||
FBKW_CKP_ISR();
|
||||
|
||||
}
|
||||
|
||||
@@ -424,6 +434,7 @@ void TW_CALC_FBKW_FEEDBACK(){
|
||||
}
|
||||
|
||||
FBKW_FEEDBACK -= lpf_fb*(FBKW_FEEDBACK - new_fb - fbkw_offset);
|
||||
FBKW_CKP_ISR();
|
||||
|
||||
ckp_process_pending=0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user