Created
November 26, 2025 22:19
-
-
Save VIRUXE/eefa0443a9cd4a0e1a7cff45141c79b8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * ============================================================================ | |
| * HONDA P30 OBD1 ECU FIRMWARE - PSEUDO-C CONVERSION | |
| * ============================================================================ | |
| * | |
| * Original File: P30_203.asm | |
| * Target MCU: OKI M66207 (OBD1) | |
| * ECU Type: Honda P30 (USDM B16A3, B18C1, etc.) | |
| * | |
| * This is a PSEUDO-C representation of the OBD1 ECU firmware. | |
| * NOT compilable code - documentation format for understanding assembly logic. | |
| * | |
| * Conversion includes: | |
| * - All 2,394 labels renamed with meaningful context | |
| * - RAM variables inferred from usage patterns | |
| * - All 14 interrupt handlers | |
| * - 8 VCAL helper functions | |
| * - Complete main engine logic | |
| * - Data tables documented | |
| * | |
| * ============================================================================ | |
| */ | |
| #include <stdint.h> | |
| #include <stdbool.h> | |
| /*============================================================================ | |
| * SECTION 1: OKI M66207 HARDWARE REGISTER DEFINITIONS | |
| * | |
| * The M66207 is a 16-bit CMOS microcontroller with: | |
| * - 16-bit data bus, 20-bit address bus | |
| * - 8 channels of 10-bit ADC | |
| * - 4 timers (16-bit) | |
| * - 2 PWM channels | |
| * - Serial communication (UART) | |
| * - Watchdog timer | |
| *============================================================================*/ | |
| /* ---- CPU Control Registers ---- */ | |
| #define REG_PSW (*(volatile uint16_t*)0x0004) // Processor Status Word | |
| #define REG_PSWL (*(volatile uint8_t*)0x0004) // PSW Low (flags) | |
| #define REG_PSWH (*(volatile uint8_t*)0x0005) // PSW High (bank select) | |
| #define REG_ACC (*(volatile uint16_t*)0x0006) // 16-bit Accumulator | |
| #define REG_ACCH (*(volatile uint8_t*)0x0007) // Accumulator High byte | |
| #define REG_LRB (*(volatile uint8_t*)0x0008) // Local Register Bank pointer | |
| #define REG_DP (*(volatile uint16_t*)0x000A) // Data Pointer | |
| #define REG_USP (*(volatile uint16_t*)0x000C) // User Stack Pointer | |
| #define REG_SSP (*(volatile uint16_t*)0x000E) // System Stack Pointer | |
| #define REG_SBYCON (*(volatile uint8_t*)0x0010) // Standby Control | |
| #define REG_WDT (*(volatile uint8_t*)0x0011) // Watchdog Timer | |
| #define REG_STPACP (*(volatile uint8_t*)0x0013) // Stop/Accept control | |
| /* ---- Interrupt Control ---- */ | |
| #define REG_IRQ (*(volatile uint8_t*)0x0018) // Interrupt Request flags | |
| #define REG_IRQH (*(volatile uint8_t*)0x0019) // IRQ High byte | |
| #define REG_IE (*(volatile uint16_t*)0x001A) // Interrupt Enable | |
| /* ---- Port Registers ---- */ | |
| #define REG_P0 (*(volatile uint8_t*)0x0020) // Port 0 (CEL, AC clutch, purge) | |
| #define REG_P0IO (*(volatile uint8_t*)0x0021) // Port 0 Direction | |
| #define REG_P1 (*(volatile uint8_t*)0x0022) // Port 1 (VTEC, CEL LED) | |
| #define REG_P1IO (*(volatile uint8_t*)0x0023) // Port 1 Direction | |
| #define REG_P2 (*(volatile uint8_t*)0x0024) // Port 2 (Injectors 1-4) | |
| #define REG_P2IO (*(volatile uint8_t*)0x0025) // Port 2 Direction | |
| #define REG_P2SF (*(volatile uint8_t*)0x0026) // Port 2 Special Function | |
| #define REG_P3 (*(volatile uint8_t*)0x0028) // Port 3 (Ignition output) | |
| #define REG_P3IO (*(volatile uint8_t*)0x0029) // Port 3 Direction | |
| #define REG_P3SF (*(volatile uint8_t*)0x002A) // Port 3 Special Function | |
| #define REG_P4 (*(volatile uint8_t*)0x002C) // Port 4 (External inputs) | |
| #define REG_P4IO (*(volatile uint8_t*)0x002D) // Port 4 Direction | |
| #define REG_P4SF (*(volatile uint8_t*)0x002E) // Port 4 Special Function | |
| #define REG_P5 (*(volatile uint8_t*)0x0030) // Port 5 | |
| #define REG_P5IO (*(volatile uint8_t*)0x0031) // Port 5 Direction | |
| /* ---- Timer Registers ---- */ | |
| #define REG_TM0 (*(volatile uint16_t*)0x0030) // Timer 0 Counter (Injector timing) | |
| #define REG_TMR0 (*(volatile uint16_t*)0x0032) // Timer 0 Reload/Compare | |
| #define REG_TM1 (*(volatile uint16_t*)0x0034) // Timer 1 Counter (RPM/TDC) | |
| #define REG_TMR1 (*(volatile uint16_t*)0x0036) // Timer 1 Reload/Compare | |
| #define REG_TM2 (*(volatile uint16_t*)0x0038) // Timer 2 Counter (Ignition dwell) | |
| #define REG_TMR2 (*(volatile uint16_t*)0x003A) // Timer 2 Reload/Compare | |
| #define REG_TM3 (*(volatile uint16_t*)0x003C) // Timer 3 Counter | |
| #define REG_TMR3 (*(volatile uint16_t*)0x003E) // Timer 3 Reload/Compare | |
| #define REG_TCON0 (*(volatile uint8_t*)0x0040) // Timer 0 Control | |
| #define REG_TCON1 (*(volatile uint8_t*)0x0041) // Timer 1 Control | |
| #define REG_TCON2 (*(volatile uint8_t*)0x0042) // Timer 2 Control (Ignition) | |
| #define REG_TCON3 (*(volatile uint8_t*)0x0043) // Timer 3 Control | |
| #define REG_TRNSIT (*(volatile uint8_t*)0x0046) // Timer Transit register | |
| /* ---- Serial Communication ---- */ | |
| #define REG_STTM (*(volatile uint8_t*)0x0048) // Serial TX Timer | |
| #define REG_STTMR (*(volatile uint8_t*)0x0049) // Serial TX Timer Reload | |
| #define REG_STTMC (*(volatile uint8_t*)0x004A) // Serial TX Control | |
| #define REG_SRTM (*(volatile uint8_t*)0x004C) // Serial RX Timer | |
| #define REG_SRTMR (*(volatile uint8_t*)0x004D) // Serial RX Timer Reload | |
| #define REG_SRTMC (*(volatile uint8_t*)0x004E) // Serial RX Timer Control | |
| #define REG_STCON (*(volatile uint8_t*)0x0050) // Serial TX Control | |
| #define REG_STBUF (*(volatile uint8_t*)0x0051) // Serial TX Buffer | |
| #define REG_SRCON (*(volatile uint8_t*)0x0054) // Serial RX Control | |
| #define REG_SRBUF (*(volatile uint8_t*)0x0055) // Serial RX Buffer | |
| #define REG_SRSTAT (*(volatile uint8_t*)0x0056) // Serial Status | |
| /* ---- ADC Registers ---- */ | |
| #define REG_ADSCAN (*(volatile uint8_t*)0x0058) // ADC Scan Control | |
| #define REG_ADSEL (*(volatile uint8_t*)0x0059) // ADC Channel Select | |
| #define REG_ADCR0 (*(volatile uint16_t*)0x0060) // ADC Ch0 (MUX'd: ECT/IAT) | |
| #define REG_ADCR0H (*(volatile uint8_t*)0x0061) // ADC Ch0 High byte | |
| #define REG_ADCR1 (*(volatile uint16_t*)0x0062) // ADC Ch1 (Window demister) | |
| #define REG_ADCR2 (*(volatile uint16_t*)0x0064) // ADC Ch2 (O2 Secondary) | |
| #define REG_ADCR2H (*(volatile uint8_t*)0x0065) // ADC Ch2 High byte | |
| #define REG_ADCR3 (*(volatile uint16_t*)0x0066) // ADC Ch3 (O2 Primary) | |
| #define REG_ADCR4 (*(volatile uint16_t*)0x0068) // ADC Ch4 (TPS) | |
| #define REG_ADCR5 (*(volatile uint16_t*)0x006A) // ADC Ch5 (MAP Sensor) | |
| #define REG_ADCR6 (*(volatile uint16_t*)0x006C) // ADC Ch6 (Battery/ECT) | |
| #define REG_ADCR6H (*(volatile uint8_t*)0x006D) // ADC Ch6 High byte | |
| #define REG_ADCR7 (*(volatile uint16_t*)0x006E) // ADC Ch7 (IAT) | |
| /* ---- PWM Registers ---- */ | |
| #define REG_PWMC0 (*(volatile uint16_t*)0x0070) // PWM 0 Counter (IACV) | |
| #define REG_PWMR0 (*(volatile uint16_t*)0x0072) // PWM 0 Reload | |
| #define REG_PWMC1 (*(volatile uint16_t*)0x0074) // PWM 1 Counter | |
| #define REG_PWMR1 (*(volatile uint16_t*)0x0076) // PWM 1 Reload | |
| #define REG_PWCON0 (*(volatile uint8_t*)0x0078) // PWM 0 Control | |
| #define REG_PWCON1 (*(volatile uint8_t*)0x007A) // PWM 1 Control | |
| /*============================================================================ | |
| * SECTION 2: RAM VARIABLE DEFINITIONS | |
| * | |
| * Memory map inferred from code analysis: | |
| * 0x98-0xBF: Sensor readings (raw and processed) | |
| * 0xC0-0xDF: Timing/counter values | |
| * 0xE0-0xFF: State flags and cycle counters | |
| * 0x100-0x1FF: Extended flags and calculations | |
| * 0x200-0x3FF: Final values, buffers, IACV | |
| *============================================================================*/ | |
| /* ---- Sensor Readings (0x98-0xBF) ---- */ | |
| uint8_t g_coolantTempRaw; // 0x98 - ECT sensor raw value | |
| uint8_t g_intakeAirTempRaw; // 0x99 - IAT sensor raw value | |
| uint8_t g_batteryVoltageRaw; // 0x9A - Battery voltage (12V scaled) | |
| uint8_t g_ecuVoltageRaw; // 0x9B - ECU internal 5V reference | |
| uint8_t g_groundReference; // 0x9C - Ground reference check | |
| uint8_t g_timingAdjustInput; // 0x9D - Timing adjust connector (B20) | |
| uint8_t g_brakeSwitch; // 0x9E - Brake switch input (B9) | |
| uint8_t g_auxInput; // 0x9F - Auxiliary input (B18) | |
| uint8_t g_sensorFlags; // 0xA0 - Sensor status flags | |
| uint8_t g_o2PrimaryRaw; // 0xA1 - O2 primary sensor value (0-50 decimal) | |
| uint8_t g_o2SecondaryRaw; // 0xA2 - O2 secondary sensor value | |
| uint8_t g_tempCalculated; // 0xA3 - Temperature intermediate calculation | |
| uint8_t g_iatProcessed; // 0xA4 - IAT processed value | |
| uint8_t g_alternatorFeedback; // 0xA5 - Alternator feedback signal | |
| uint8_t g_rpmByteNonVtec; // 0xA6 - RPM byte (non-VTEC scale) | |
| uint8_t g_rpmByteVtec; // 0xA7 - RPM byte (VTEC scale) | |
| uint8_t g_ambientPressure; // 0xA8 - Ambient pressure (internal sensor) | |
| uint8_t g_baroSensorRaw; // 0xA9 - Barometric pressure sensor | |
| uint8_t g_tpsSensorRaw; // 0xAA - TPS raw value (0-255) | |
| uint8_t g_tpsSensorFiltered; // 0xAB - TPS filtered/averaged | |
| uint8_t g_tpsDelta; // 0xAC - TPS delta (acceleration rate) | |
| uint8_t g_tpsDeltaOld; // 0xAD - Previous TPS delta | |
| uint8_t g_tpsSmoothed; // 0xAE - TPS smoothed value | |
| uint8_t g_tpsRelated; // 0xAF - TPS related calculation | |
| uint16_t g_mapSensorRaw; // 0xB0 - MAP sensor value (from ADCR5) | |
| uint16_t g_mapSensorOld; // 0xB2 - Previous MAP value (for delta calc) | |
| uint8_t g_mapImageBase; // 0xB4 - MAP image (0-DF, before delta) | |
| uint8_t g_mapImageFinal; // 0xB5 - MAP image after delta adjustment | |
| uint16_t g_mapInitialHigh; // 0xB6 - Initial MAP high byte (for Code 5) | |
| uint8_t g_mapDeltaCalc; // 0xB7 - MAP delta calculation result | |
| uint16_t g_rpmTimerDelta; // 0xB8 - Delta timer ticks (for RPM change) | |
| uint16_t g_rpmTimerCurrent; // 0xBA - Current revs timer count (45° period) | |
| uint8_t g_rpmChangeRate; // 0xBC - RPM acceleration/deceleration rate | |
| uint8_t g_rpmChangeDir; // 0xBD - RPM change direction indicator | |
| uint16_t g_rpmTimerAverage; // 0xBE - Average of last 4 rev counts | |
| /* ---- Timing and Counter Values (0xC0-0xDF) ---- */ | |
| uint16_t g_rpmAsymptotic; // 0xC0 - Asymptotic RPM follower | |
| uint16_t g_rpmTargetDiff; // 0xC2 - |current RPM - target idle| | |
| uint16_t g_vehicleSpeedWord; // 0xC4 - Vehicle speed (processed) | |
| uint16_t g_timer1OldCapture; // 0xC6 - Old Timer 1 capture value | |
| uint16_t g_timer1CurrentCapture; // 0xC8 - Current Timer 1 capture (INT0) | |
| uint16_t g_oldE2; // 0xCA - Old 0xE2 value | |
| uint8_t g_vehicleSpeedByte; // 0xCB - Vehicle speed sensor byte | |
| uint16_t g_interruptEnableNormal; // 0xCC - IE value normally | |
| uint16_t g_interruptEnableISR; // 0xCE - IE value in interrupt | |
| uint16_t g_injectorTiming0; // 0xD0 - Injector timing slot 0 | |
| uint16_t g_injectorTiming1; // 0xD2 - Injector timing slot 1 | |
| uint16_t g_injectorTiming2; // 0xD4 - Injector timing slot 2 | |
| uint16_t g_injectorPulseWidth; // 0xD6 - Final fuel pulse width | |
| uint16_t g_ignitionDwellStart; // 0xD8 - Ignition dwell start time | |
| uint16_t g_ignitionFireTime; // 0xDA - Ignition fire time | |
| uint16_t g_ignitionCalc1; // 0xDC - Ignition calculation temp | |
| uint8_t g_ignitionCalc2; // 0xDE - Ignition calculation temp | |
| uint8_t g_iacvDutyCycle; // 0xDF - IACV PWM duty cycle | |
| /* ---- State Flags and Cycle Counters (0xE0-0xFF) ---- */ | |
| uint16_t g_timer1OldValue; // 0xE0 - Old Timer 1 for RPM calc | |
| uint8_t g_timer1OverflowFlag; // 0xE2 - Timer 1 overflow indicator (VSS) | |
| uint8_t g_tdcCounter; // 0xE3 - TDC position counter | |
| uint8_t g_crankPosition; // 0xE4 - Crank position (0-3, 45° each) | |
| uint8_t g_cylinderFiring; // 0xE5 - Cylinder firing order index | |
| uint8_t g_firingOrderPhase; // 0xE6 - Firing order phase | |
| uint8_t g_enginePosition; // 0xE7 - Engine position tracking | |
| uint8_t g_celCodeCounter; // 0xE8 - CEL code timing counter | |
| uint8_t g_diagnosticState; // 0xE9 - Diagnostic state machine | |
| uint8_t g_syncState; // 0xEA - Crank sync state | |
| uint8_t g_lifeCounter; // 0xEB - Reboot life counter (starts 0x20) | |
| uint8_t g_mainLoopCounter; // 0xEC - Main loop iteration counter | |
| uint8_t g_miscCounter; // 0xED - Miscellaneous counter | |
| uint8_t g_timerCounter; // 0xEE - General timer counter | |
| uint8_t g_rebootReason; // 0xF0 - Error code after reboot | |
| uint8_t g_eldStatus; // 0xF1 - ELD (Electrical Load Detector) | |
| uint8_t g_eldValue; // 0xF2 - ELD reading (twice per cycle) | |
| uint8_t g_eldRelated; // 0xF3 - ELD related calculation | |
| uint8_t g_savedInterruptLow; // 0xF4 - Saved IE low byte | |
| uint8_t g_savedInterruptHigh; // 0xF5 - Saved IE high byte | |
| uint8_t g_savedFlags; // 0xF6 - Saved flags | |
| uint8_t g_timerScratch; // 0xF7 - Timer scratch register | |
| uint8_t g_oilPressureSwitch; // 0xF8 - Oil pressure (>0x32 = OK) | |
| uint8_t g_starterSignal; // 0xF9 - Starter signal input | |
| uint8_t g_eldCalc; // 0xFA - ELD calculation temp | |
| uint8_t g_eldTrim; // 0xFB - ELD fuel trim | |
| uint8_t g_celBlinkPattern; // 0xFC - CEL blink pattern (high/low nibble) | |
| uint8_t g_celBlinkState; // 0xFD - CEL blink state machine | |
| uint8_t g_processingFlags; // 0xFE - Processing state flags | |
| uint8_t g_externalInputs; // 0xFF - External input chip reading | |
| /* ---- Extended Flags (0x100-0x13F) ---- */ | |
| uint8_t g_inputPortMirror; // 0x110 - External input mirror | |
| uint8_t g_sensorFlags1; // 0x111 - Sensor validation flags | |
| uint8_t g_errorFlags1; // 0x112 - Error condition flags 1 | |
| uint8_t g_errorFlags2; // 0x113 - Error condition flags 2 | |
| uint8_t g_errorFlags3; // 0x114 - Error condition flags 3 | |
| uint8_t g_errorFlags4; // 0x115 - Error condition flags 4 | |
| uint8_t g_vtecFlags1; // 0x116 - VTEC control flags 1 | |
| uint8_t g_vtecFlags2; // 0x117 - VTEC control flags 2 | |
| uint8_t g_engineStateFlags; // 0x118 - Engine state (CKP, VSS, starter) | |
| uint8_t g_mapStateFlags; // 0x119 - MAP state flags | |
| uint8_t g_tempStateFlags; // 0x11A - Temperature state flags | |
| uint8_t g_o2SensorFlags; // 0x11B - O2 sensor state flags | |
| uint8_t g_o2LoopFlags; // 0x11C - O2 closed loop flags | |
| uint8_t g_fuelCutFlags; // 0x11D - Fuel cut conditions | |
| uint8_t g_rpmStateFlags; // 0x11E - RPM state flags | |
| uint8_t g_engineRunFlags; // 0x11F - Engine running flags | |
| uint8_t g_ignitionFlags; // 0x120 - Ignition state flags | |
| uint8_t g_tdcStateFlags; // 0x121 - TDC validation flags | |
| uint8_t g_enginePhaseFlags; // 0x122 - Engine phase flags | |
| uint8_t g_tpsChangeFlags; // 0x123 - TPS rate of change flags | |
| uint8_t g_acFlags; // 0x124 - AC clutch control flags | |
| uint8_t g_idleFlags; // 0x125 - Idle control flags | |
| uint8_t g_miscFlags1; // 0x126 - Miscellaneous flags | |
| uint8_t g_miscFlags2; // 0x127 - Miscellaneous flags | |
| uint8_t g_miscFlags3; // 0x128 - Miscellaneous flags | |
| uint8_t g_vtecStateFlags; // 0x129 - VTEC engagement state | |
| uint8_t g_vtecQualifyFlags; // 0x12A - VTEC qualification counter | |
| uint8_t g_vtecHoldCounter; // 0x12B - VTEC hold counter | |
| uint8_t g_celSensorFlags; // 0x12C - CEL sensor error bits | |
| uint8_t g_celSystemFlags; // 0x12D - CEL system error bits | |
| uint8_t g_celCriticalFlags; // 0x12E - CEL critical error bits | |
| uint8_t g_celMiscFlags; // 0x12F - CEL misc error bits | |
| uint8_t g_faultCode1; // 0x130 - Fault codes 1-8 | |
| uint8_t g_faultCode2; // 0x131 - Fault codes 9-16 | |
| uint8_t g_faultCode3; // 0x132 - Fault codes 17-24 | |
| uint8_t g_faultCodeActive; // 0x133 - Currently active fault | |
| uint8_t g_ignitionFinal; // 0x134 - Final ignition advance value | |
| uint8_t g_ignitionRpmEctTrim; // 0x135 - RPM/ECT ignition trim | |
| uint8_t g_ignitionComplement; // 0x136 - 2's complement of ignition | |
| uint8_t g_ignitionCorrection1; // 0x137 - Ignition correction 1 | |
| uint8_t g_ignitionMapRaw; // 0x138 - Raw ignition map interpolation | |
| uint8_t g_ignitionBrakeTrim; // 0x139 - Brake switch timing trim | |
| uint8_t g_ignitionEctTrim; // 0x13A - ECT ignition trim | |
| uint8_t g_ignitionIdleTrim; // 0x13B - Idle adjust timing trim | |
| uint8_t g_ignitionCorrection2; // 0x13C - Ignition correction 2 | |
| uint8_t g_ignitionKnockTrim; // 0x13D - Knock retard correction | |
| uint8_t g_ignitionCorrection3; // 0x13E - Ignition correction 3 | |
| uint8_t g_ignitionEctErrorTrim; // 0x13F - ECT error fallback trim | |
| /* ---- Fuel Calculations (0x140-0x17F) ---- */ | |
| uint16_t g_fuelMapNonVtec; // 0x140 - Fuel map value (non-VTEC) | |
| uint16_t g_fuelMapVtec; // 0x142 - Fuel map value (VTEC) | |
| uint16_t g_fuelMainCorrected; // 0x144 - Main fuel with corrections | |
| uint16_t g_fuelAllCorrections; // 0x146 - All fuel corrections combined | |
| uint16_t g_fuelFinalNoO2; // 0x148 - Final fuel without O2 | |
| uint16_t g_fuelTpsDelta; // 0x14A - TPS acceleration enrichment | |
| uint16_t g_fuelBatteryTrim; // 0x14C - Battery voltage trim | |
| uint16_t g_fuelAcTrim; // 0x14E - AC compressor trim | |
| uint16_t g_fuelTpsRelated; // 0x150 - TPS related fuel | |
| uint16_t g_fuelTimingTrim; // 0x152 - Timing connector trim | |
| uint16_t g_fuelScratch1; // 0x154 - Scratch register | |
| uint16_t g_fuelScratch2; // 0x156 - Scratch register | |
| uint16_t g_fuelVoltageTrim; // 0x158 - Voltage-based trim | |
| uint16_t g_fuelIatTrim; // 0x15A - IAT fuel trim | |
| uint16_t g_fuelScratch3; // 0x15C - Scratch register | |
| uint16_t g_fuelWarmupMult; // 0x15E - Warmup enrichment multiplier | |
| uint16_t g_fuelScratch4; // 0x160 - Scratch register | |
| uint16_t g_fuelO2TrimPrimary; // 0x162 - Primary O2 fuel trim | |
| uint16_t g_fuelO2TrimSecondary; // 0x164 - Secondary O2 fuel trim | |
| uint16_t g_fuelTempTrim; // 0x166 - Temperature fuel trim | |
| uint16_t g_fuelScratch5; // 0x168 - Scratch register | |
| uint8_t g_fuelMapDependentTrim; // 0x169 - MAP-based fuel trim | |
| uint16_t g_fuelEctTrim; // 0x16A - ECT fuel trim | |
| uint16_t g_fuelEctTrim2; // 0x16C - ECT fuel trim 2 | |
| uint8_t g_fuelMiscFlag; // 0x16E - Fuel misc flag | |
| uint8_t g_openClosedLoopFlag; // 0x16F - Open/closed loop selector | |
| uint16_t g_targetIdleRpm; // 0x172 - Target idle RPM (timer format) | |
| uint8_t g_ectIdleTrim; // 0x176 - ECT-based idle trim | |
| uint8_t g_ectIdleAdjust; // 0x177 - ECT idle adjustment | |
| uint8_t g_vtecRpmThreshold; // 0x178 - VTEC RPM threshold calc | |
| /* ---- VTEC and O2 State (0x190-0x1FF) ---- */ | |
| uint8_t g_ectVcalResult; // 0x197 - ECT VCAL lookup result | |
| uint8_t g_celBlinkCounter; // 0x1AA - CEL blink timing counter | |
| uint8_t g_vtecHysteresis; // 0x1D5 - VTEC engage hysteresis | |
| uint8_t g_celCurrentCode; // 0x1DF - Current CEL code being blinked | |
| /* ---- IACV and Buffers (0x200-0x2FF) ---- */ | |
| uint16_t g_iacvDutyCalc; // 0x202 - IACV duty calculation | |
| uint16_t g_iacvDutyCopy; // 0x204 - IACV duty copy | |
| uint16_t g_rpmHistory0; // 0x206 - RPM history slot 0 | |
| uint16_t g_rpmHistory1; // 0x208 - RPM history slot 1 | |
| uint16_t g_rpmHistory2; // 0x20A - RPM history slot 2 | |
| uint16_t g_rpmHistory3; // 0x20C - RPM history slot 3 | |
| uint16_t g_rpmOldHistory0; // 0x20E - Old RPM history 0 | |
| uint16_t g_rpmOldHistory1; // 0x210 - Old RPM history 1 | |
| uint16_t g_rpmOldHistory2; // 0x212 - Old RPM history 2 | |
| uint16_t g_injectorTimingSlot0; // 0x214 - Injector timing buffer | |
| uint16_t g_injectorTimingSlot1; // 0x216 - Injector timing buffer | |
| uint16_t g_injectorTimingSlot2; // 0x218 - Injector timing buffer | |
| uint8_t g_injectorMask; // 0x21A - Injector selection mask | |
| uint8_t g_injectorMaskInverse; // 0x21B - Inverse injector mask | |
| uint8_t g_injectorP2Mask; // 0x21C - P2 port injector mask | |
| uint8_t g_iacvRelated; // 0x21D - IACV related | |
| uint8_t g_stateFlags210; // 0x210 - State flags bank | |
| uint8_t g_stateFlags211; // 0x211 - State flags bank | |
| uint8_t g_stateFlags212; // 0x212 - State flags bank | |
| uint8_t g_stateFlags213; // 0x213 - State flags bank | |
| uint8_t g_stateFlags214; // 0x214 - State flags bank | |
| uint8_t g_stateFlags215; // 0x215 - State flags bank | |
| uint8_t g_stateFlags216; // 0x216 - State flags bank | |
| uint8_t g_stateFlags217; // 0x217 - State flags bank | |
| uint8_t g_stateFlags218; // 0x218 - State flags bank | |
| uint8_t g_stateFlags219; // 0x219 - State flags bank | |
| uint8_t g_stateFlags21A; // 0x21A - State flags bank | |
| uint8_t g_stateFlags21B; // 0x21B - State flags bank | |
| uint8_t g_stateFlags21C; // 0x21C - State flags bank | |
| uint8_t g_stateFlags21D; // 0x21D - State flags bank | |
| uint8_t g_stateFlags21E; // 0x21E - State flags bank | |
| uint8_t g_stateFlags21F; // 0x21F - State flags bank | |
| uint8_t g_stateFlags220; // 0x220 - State flags bank | |
| uint8_t g_stateFlags221; // 0x221 - State flags bank | |
| uint8_t g_stateFlags222; // 0x222 - State flags bank | |
| uint8_t g_stateFlags223; // 0x223 - State flags bank | |
| uint8_t g_stateFlags224; // 0x224 - State flags bank | |
| uint8_t g_stateFlags225; // 0x225 - State flags bank | |
| uint8_t g_stateFlags226; // 0x226 - State flags bank | |
| uint8_t g_stateFlags227; // 0x227 - State flags bank | |
| uint8_t g_stateFlags228; // 0x228 - State flags bank | |
| uint8_t g_stateFlags229; // 0x229 - State flags bank | |
| uint8_t g_stateFlags22A; // 0x22A - State flags bank | |
| uint8_t g_stateFlags22B; // 0x22B - State flags bank | |
| uint8_t g_stateFlags22C; // 0x22C - State flags bank | |
| uint8_t g_stateFlags22D; // 0x22D - State flags bank | |
| uint8_t g_stateFlags22E; // 0x22E - State flags bank | |
| uint8_t g_stateFlags22F; // 0x22F - State flags bank | |
| uint8_t g_stateFlags230; // 0x230 - State flags bank | |
| uint8_t g_stateFlags231; // 0x231 - State flags bank | |
| uint8_t g_tpsOldValue; // 0x278 - Previous TPS value | |
| uint8_t g_tempOldValue; // 0x279 - Previous temp value | |
| uint16_t g_o2OldPrimaryTrim; // 0x274 - Old primary O2 correction | |
| uint16_t g_o2OldSecondaryTrim; // 0x276 - Old secondary O2 correction | |
| uint8_t g_celBlinkRam1; // 0x27B - CEL blink buffer (codes 1-8) | |
| uint8_t g_celBlinkRam2; // 0x27C - CEL blink buffer (codes 9-16) | |
| uint8_t g_celBlinkRam3; // 0x27D - CEL blink buffer (codes 17-24) | |
| /* ---- Serial Communication Buffer (0x350-0x3FF) ---- */ | |
| uint8_t g_serialFlags; // 0x354 - Serial communication flags | |
| uint8_t g_serialBuffer[16]; // 0x358 - Serial data buffer | |
| /*============================================================================ | |
| * SECTION 3: CONSTANTS AND TABLE ADDRESSES | |
| *============================================================================*/ | |
| /* ---- Fuel Map Tables ---- */ | |
| #define TBL_FUEL_NONVTEC_ADDR 0x6800 // Non-VTEC fuel map (10x20) | |
| #define TBL_FUEL_VTEC_ADDR 0x6900 // VTEC fuel map (10x20) | |
| #define TBL_FUEL_CRANKING_ADDR 0x6A00 // Cranking fuel enrichment | |
| /* ---- Ignition Map Tables ---- */ | |
| #define TBL_IGN_NONVTEC_ADDR 0x6A80 // Non-VTEC ignition map | |
| #define TBL_IGN_VTEC_ADDR 0x6B00 // VTEC ignition map | |
| #define TBL_IGN_CRANKING_ADDR 0x6B80 // Cranking ignition timing | |
| /* ---- Correction Tables ---- */ | |
| #define TBL_ECT_FUEL_TRIM 0x6034 // ECT fuel enrichment curve | |
| #define TBL_IAT_FUEL_TRIM 0x6042 // IAT fuel enrichment curve | |
| #define TBL_BARO_FUEL_TRIM 0x6050 // Barometric fuel trim | |
| #define TBL_O2_CLOSED_LOOP 0x605E // O2 closed loop parameters | |
| #define TBL_WARMUP_ENRICHMENT 0x606C // Warmup enrichment curve | |
| #define TBL_ACCEL_ENRICHMENT 0x607A // Acceleration enrichment | |
| #define TBL_DECEL_ENLEAN 0x608F // Deceleration enleanment | |
| #define TBL_VOLTAGE_TRIM 0x60A7 // Voltage compensation | |
| #define TBL_RPM_AXIS_NONVTEC 0x60C8 // RPM axis (non-VTEC) | |
| #define TBL_RPM_AXIS_VTEC 0x60CC // RPM axis (VTEC) | |
| #define TBL_MAP_AXIS 0x60D0 // MAP axis breakpoints | |
| #define TBL_IDLE_TARGET 0x6122 // Idle RPM target by ECT | |
| #define TBL_IDLE_IACV_BASE 0x6132 // IACV base duty by ECT | |
| #define TBL_VTEC_ENGAGE_RPM 0x6146 // VTEC engage RPM threshold | |
| #define TBL_VTEC_DISENGAGE_RPM 0x6152 // VTEC disengage RPM threshold | |
| #define TBL_VTEC_MIN_SPEED 0x615E // VTEC minimum vehicle speed | |
| #define TBL_REV_LIMITER 0x616A // Rev limiter parameters | |
| #define TBL_LAUNCH_CONTROL 0x6176 // Launch control parameters | |
| #define TBL_KNOCK_RETARD 0x6182 // Knock retard curve | |
| #define TBL_INJECTOR_DEAD_TIME 0x6190 // Injector dead time by voltage | |
| #define TBL_DWELL_TIME 0x619E // Ignition dwell time | |
| #define TBL_TIMING_CONNECTOR_TRIM 0x61AC // Timing connector adjustment | |
| #define TBL_CEL_CODE_MAP 0x6CD2 // CEL code to blink pattern | |
| #define TBL_CEL_TIMING 0x6CEA // CEL blink timing | |
| /* ---- Serial/Diagnostic Tables ---- */ | |
| #define TBL_SERIAL_ADDRESSES 0x6B56 // Serial read addresses | |
| #define TBL_DIAGNOSTIC_PARAMS 0x6D08 // Diagnostic parameters | |
| /* ---- Configuration Constants ---- */ | |
| #define TBL_CONFIG_FLAGS 0x6000 // Configuration byte flags | |
| /* ---- RPM Constants ---- */ | |
| #define RPM_COEF_NUMERATOR 1851562 // 7900000/32/8*60 | |
| #define TIMER_TICKS_PER_45DEG(rpm) (RPM_COEF_NUMERATOR / (rpm)) | |
| /* ---- Port Bit Definitions ---- */ | |
| // Port 0 | |
| #define P0_PURGE_SOLENOID (1 << 3) // P0.3 - Purge control | |
| #define P0_CEL_DASH (1 << 6) // P0.6 - CEL dashboard light | |
| #define P0_AC_CLUTCH (1 << 7) // P0.7 - AC clutch output | |
| // Port 1 | |
| #define P1_ERROR_CODE3 (1 << 0) // P1.0 - Error code 3 indicator | |
| #define P1_VTEC_SOLENOID (1 << 1) // P1.1 - VTEC solenoid output | |
| #define P1_CEL_LED (1 << 2) // P1.2 - CEL LED output | |
| // Port 2 | |
| #define P2_INJECTOR_1 (1 << 0) // P2.0 - Injector 1 | |
| #define P2_INJECTOR_2 (1 << 1) // P2.1 - Injector 2 | |
| #define P2_INJECTOR_3 (1 << 2) // P2.2 - Injector 3 | |
| #define P2_INJECTOR_4 (1 << 3) // P2.3 - Injector 4 | |
| #define P2_LIMP_MODE (1 << 4) // P2.4 - Limp mode indicator | |
| // Port 4 | |
| #define P4_IACV_OUTPUT (1 << 3) // P4.3 - IACV PWM output | |
| // External Inputs (0xFF) | |
| #define EXT_KNOCK_LOCKUP (1 << 0) // FF.0 - Knock/Auto lockup | |
| #define EXT_VTEC_FEEDBACK (1 << 2) // FF.2 - VTEC solenoid feedback | |
| #define EXT_AC_SWITCH (1 << 6) // FF.6 - AC switch input | |
| #define EXT_STARTER_SIGNAL (1 << 7) // FF.7 - Starter signal | |
| /*============================================================================ | |
| * SECTION 4: INTERRUPT VECTOR TABLE (0x0000-0x0037) | |
| * | |
| * OKI M66207 interrupt vectors are 16-bit addresses stored sequentially. | |
| *============================================================================*/ | |
| // Vector Table at 0x0000 | |
| const uint16_t VECTOR_TABLE[] = { | |
| // addr handler description | |
| 0x21E2, // 0x0000: isr_systemStart - System startup | |
| 0x21E9, // 0x0002: isr_break - Software break | |
| 0x21D1, // 0x0004: isr_watchdog - Watchdog timer | |
| 0x003C, // 0x0006: isr_nmi - Non-maskable interrupt | |
| 0x01D3, // 0x0008: isr_crankPosition - INT0: Crank position signal | |
| 0x01FD, // 0x000A: isr_serialRx - Serial receive | |
| 0x21CB, // 0x000C: isr_serialTx - Serial transmit | |
| 0x03DC, // 0x000E: isr_serialRxBrg - Serial RX baud rate generator | |
| 0x21CB, // 0x0010: isr_timer0Overflow - Timer 0 overflow (unused) | |
| 0x0086, // 0x0012: isr_timer0Match - Timer 0 match: Injector pulse | |
| 0x21CB, // 0x0014: isr_timer1Overflow - Timer 1 overflow (unused) | |
| 0x0114, // 0x0016: isr_timer1Match - Timer 1 match: ADC/TDC | |
| 0x02DD, // 0x0018: isr_timer2Overflow - Timer 2 overflow | |
| 0x014D, // 0x001A: isr_timer2Match - Timer 2 match: Ignition | |
| 0x21CB, // 0x001C: isr_timer3Overflow - Timer 3 overflow (unused) | |
| 0x02FB, // 0x001E: isr_timer3Match - Timer 3 match | |
| 0x21CB, // 0x0020: isr_adcComplete - ADC conversion complete (unused) | |
| 0x031E, // 0x0022: isr_pwmTimer - PWM timer: IACV control | |
| 0x21CB, // 0x0024: isr_serialTxBrg - Serial TX baud rate (unused) | |
| 0x037B, // 0x0026: isr_externalInt1 - INT1: Main engine processing | |
| // VCAL Vector Table (0x0028-0x0036) | |
| 0x4E62, // 0x0028: vcal_tableLookup1D - 1D table interpolation | |
| 0x4EC0, // 0x002A: vcal_tableLookup2D - 2D table interpolation | |
| 0x4E9C, // 0x002C: vcal_clampTableLookup - Clamped table lookup | |
| 0x4EAE, // 0x002E: vcal_rangeLimit - Value range limiter | |
| 0x25A1, // 0x0030: vcal_mainProcess - Main processing entry | |
| 0x4F7F, // 0x0032: vcal_multiply16 - 16-bit multiply helper | |
| 0x4F84, // 0x0034: vcal_divide16 - 16-bit divide helper | |
| 0x4FCE, // 0x0036: vcal_absValue - Absolute value helper | |
| }; | |
| /*============================================================================ | |
| * SECTION 5: INTERRUPT SERVICE ROUTINES | |
| *============================================================================*/ | |
| /** | |
| * isr_nmi - Non-Maskable Interrupt Handler | |
| * Address: 0x003C | |
| * | |
| * Handles power failure, backup RAM save, and system recovery. | |
| * Called on power glitch or NMI pin assertion. | |
| */ | |
| void isr_nmi(void) { | |
| // Clear processor status for clean state | |
| REG_PSW = 0; | |
| REG_LRB = 0x41; // Select register bank 0x41 | |
| // Check if we were in middle of error flag update | |
| if (g_stateFlags230 & 0x80) { | |
| // Save current DP to backup location | |
| *(uint16_t*)0x0084 = REG_DP; | |
| } | |
| // Wait for power stabilization with timeout | |
| REG_DP = 9; // Timeout counter | |
| while (REG_DP > 0) { | |
| // Check P4.1 for power-good signal | |
| if (REG_P4 & 0x02) | |
| goto nmi_powerGood; | |
| REG_DP--; | |
| } | |
| // Power failed - jump to emergency shutdown | |
| goto emergencyShutdown; // label_576b | |
| nmi_powerGood: | |
| // Power restored - resume normal operation | |
| goto nmi_resume; // label_5a82 | |
| emergencyShutdown: | |
| // Configure ADC for standby | |
| REG_ADSEL = (uint8_t)REG_ACC; | |
| REG_IE = 0x0040; | |
| REG_TCON1 = 0xE0; | |
| REG_IRQ = 0; | |
| // Enable Timer 1 for wakeup | |
| REG_P4SF |= 0x02; | |
| REG_TM1 = 0xFFFF; | |
| REG_TCON1 |= 0x10; | |
| // Enter standby mode | |
| REG_SBYCON |= 0x04; | |
| REG_STPACP = 0x05; | |
| REG_STPACP = 0x0A; // Double-write sequence | |
| REG_SBYCON |= 0x01; | |
| // Clear flag on wake | |
| g_sensorFlags &= ~0x02; | |
| nmi_resume: | |
| // Jump to main recovery | |
| return; // Actually jumps to label_5a82 | |
| } | |
| /** | |
| * isr_timer0Match - Injector Pulse Width Timer | |
| * Address: 0x0086 | |
| * | |
| * Controls injector on/off timing. Timer 0 generates interrupts | |
| * when injector pulse starts and ends. | |
| * | |
| * Register bank 0x37 (r0-r7 at 0x1B8-0x1BF) | |
| * r6 = injector pattern byte | |
| * r7 = injector state accumulator | |
| */ | |
| void isr_timer0Match(void) { | |
| REG_LRB = 0x37; // Bank at 0x1B8 | |
| // Clear timer 0 match flag | |
| REG_TCON0 &= 0xFB; | |
| // Check if all injectors done (r7 == 0x0F means all off) | |
| uint8_t injState = *(uint8_t*)0x1BF; | |
| if (injState == 0x0F) | |
| return; // All injectors idle, nothing to do | |
| // Get injector timing values | |
| uint16_t slot0 = g_injectorTiming0; // er0 | |
| uint16_t slot1 = g_injectorTiming1; // er1 | |
| uint16_t slot2 = g_injectorTiming2; // er2 | |
| // Determine which slot is next based on timing values | |
| if (slot0 != 0) { | |
| // Slot 0 has pending pulse | |
| REG_TMR0 += slot0; | |
| // Update injector pattern | |
| uint8_t pattern = *(uint8_t*)0x1BE; | |
| pattern = (pattern << 1) | (REG_ACC >> 7); // Rotate with carry | |
| *(uint8_t*)0x1BE = pattern; | |
| // Update state | |
| uint8_t newState = (pattern & 0x0F); | |
| injState |= newState; | |
| g_injectorP2Mask |= newState; | |
| // Shift timing slots | |
| g_injectorTiming0 = slot2; | |
| g_injectorTiming1 = 1; | |
| g_injectorTiming2 = 1; | |
| } else if (slot1 != 0) { | |
| // Slot 1 active | |
| REG_TMR0 += slot1; | |
| uint8_t pattern = *(uint8_t*)0x1BE; | |
| pattern = (pattern >> 3) | (pattern & 0x0F); | |
| // Update P2 for injector output | |
| REG_P2 |= (pattern & 0x0F); | |
| return; | |
| } else if (slot2 != 0) { | |
| // Slot 2 active - final pulse end | |
| REG_TMR0 += slot2; | |
| uint8_t pattern = *(uint8_t*)0x1BE; | |
| pattern = (pattern >> 1) | ((REG_ACC & 0x01) << 7); | |
| *(uint8_t*)0x1BE = pattern; | |
| // Invert for off-pulse | |
| uint8_t offPattern = (~pattern) & 0x0F; | |
| injState |= offPattern; | |
| g_injectorP2Mask |= offPattern; | |
| // Update P2 and reset all slots | |
| REG_P2 |= (pattern & 0x0F); | |
| g_injectorTiming0 = 1; | |
| g_injectorTiming1 = 1; | |
| g_injectorTiming2 = 1; | |
| return; | |
| } else { | |
| // All slots empty - set idle state | |
| injState = 0x0F; | |
| *(uint8_t*)0x1BF = 0x0F; | |
| g_injectorP2Mask = 0x0F; | |
| REG_P2 |= 0x0F; // All injectors off | |
| return; | |
| } | |
| // Apply final pattern to P2 | |
| REG_P2 |= (injState & 0x0F); | |
| } | |
| /** | |
| * isr_timer1Match - ADC/TDC Processing Timer | |
| * Address: 0x0114 | |
| * | |
| * Handles ADC sampling timing and TDC signal validation. | |
| * Register bank 0x19 (r0-r7 at 0xC8-0xCF) | |
| */ | |
| void isr_timer1Match(void) { | |
| REG_LRB = 0x19; // Bank at 0xC8 | |
| // Check TCON1.3 for TDC signal mode | |
| if (!(REG_TCON1 & 0x08)) { | |
| // Regular ADC sampling mode | |
| g_sensorFlags &= ~0x20; // Clear flag 0x9E.5 | |
| if (g_sensorFlags & 0x20) { | |
| // Already flagged - check for timeout | |
| if (g_timer1CurrentCapture >= 0x064A) { | |
| // Set extended flag | |
| g_sensorFlags |= 0x20; | |
| // Adjust timing by 0x3B6 (950 ticks) | |
| g_timer1CurrentCapture -= 0x03B6; | |
| REG_TMR1 += 0x03B6; | |
| return; | |
| } | |
| } | |
| // Normal sample - clear TDC mode flag | |
| REG_TCON1 &= 0xF7; | |
| // Capture TPS from ADC | |
| g_timer1CurrentCapture = REG_ADCR4; // TPS to er2 | |
| // Schedule next sample based on saved timing | |
| REG_TMR1 += g_timer1OldCapture; // Add 0xCA value | |
| return; | |
| } | |
| // TDC signal processing mode | |
| REG_TCON1 |= 0x08; // Set TCON1.3 | |
| // Increment counter | |
| (*(uint8_t*)0xCE)++; | |
| // Calculate delta from 0x0A00 base | |
| uint16_t delta = 0x0A00 - g_timer1CurrentCapture; | |
| g_timer1CurrentCapture = delta; | |
| // Schedule next based on saved timing | |
| REG_TMR1 += *(uint16_t*)0xC8; | |
| } | |
| /** | |
| * isr_timer2Match - Ignition Output Timer | |
| * Address: 0x014D | |
| * | |
| * Controls ignition coil dwell and spark timing. | |
| * Timer 2 schedules dwell charge start and spark fire events. | |
| * | |
| * Register bank 0x1A (r0-r7 at 0xD0-0xD7) | |
| */ | |
| void isr_timer2Match(void) { | |
| REG_LRB = 0x1A; // Bank at 0xD0 | |
| uint8_t phase = *(uint8_t*)0xD2; // Current phase counter | |
| if (phase < 3) { | |
| // Early phase - increment and check | |
| phase++; | |
| // On even phases, capture O2 sensor | |
| if ((phase & 0x01) == 0) | |
| g_o2SecondaryRaw = REG_ADCR6; | |
| // Check if we match target | |
| if (phase == *(uint8_t*)0xD0) | |
| goto scheduleNextCycle; | |
| if (phase > *(uint8_t*)0xD0) | |
| goto clearCoilCharge; | |
| // Schedule next check | |
| uint16_t nextTime = REG_TM3 - 1; | |
| REG_TMR3 = nextTime; | |
| goto finishInterrupt; | |
| } | |
| if (phase == 3) { | |
| // Phase 3 - increment and check limit | |
| uint8_t target = *(uint8_t*)0xD0 + 1; | |
| if (target >= 5) | |
| goto finalPhase; | |
| // Clear coil charge flag | |
| REG_TCON3 &= 0xFB; | |
| // Calculate minimum dwell | |
| uint16_t dwell = *(uint16_t*)0xD4; // er2 | |
| if (dwell < 0x001F) | |
| dwell = 0x001F; // Minimum 31 ticks | |
| // Schedule dwell start | |
| REG_TMR3 = REG_TMR2 + dwell; | |
| goto finishIgnitionSchedule; | |
| } | |
| if ((phase & 0x01) == 0) { | |
| // Even phase > 3 | |
| if (REG_TCON3 & 0x08) | |
| goto scheduleNextCheck; | |
| phase = 0; | |
| REG_TCON3 |= 0x04; // Start dwell charge | |
| goto checkPhase; | |
| } | |
| // Odd phase > 3 | |
| if (REG_TCON3 & 0x04) | |
| goto scheduleNextCheck; | |
| // Calculate spark timing | |
| uint16_t sparkTime = REG_TM3 - REG_TMR2 + 6; | |
| if (sparkTime < *(uint16_t*)0xD4) { | |
| // Time until spark is less than remaining dwell | |
| REG_TMR3 = REG_TMR2 + *(uint16_t*)0xD4; | |
| } else { | |
| REG_TMR3 = REG_TM3 + 4; | |
| } | |
| finishIgnitionSchedule: | |
| REG_TCON3 |= 0x08; // Enable coil fire | |
| finishInterrupt: | |
| REG_IRQH &= 0xF7; // Clear interrupt flag | |
| // Check transit register for sync | |
| if (REG_TRNSIT & 0x01) | |
| g_sensorFlags |= 0x04; | |
| return; | |
| clearCoilCharge: | |
| REG_TCON3 &= 0xFB; | |
| goto scheduleNextCheck; | |
| finalPhase: | |
| // Final phase - schedule next cycle | |
| REG_TMR3 = REG_TMR2 + *(uint16_t*)0xD4; | |
| *(uint16_t*)0xD6 = REG_TMR3; // er3 | |
| scheduleNextCycle: | |
| REG_TMR3 = REG_TMR2 + g_timer1OldValue; | |
| REG_TCON3 &= 0xF7; | |
| goto finishInterrupt; | |
| scheduleNextCheck: | |
| uint16_t nextCheck = REG_TM3 - 1; | |
| REG_TMR3 = nextCheck; | |
| goto finishInterrupt; | |
| checkPhase: | |
| if (phase == *(uint8_t*)0xD0) | |
| goto scheduleNextCycle; | |
| if (phase < *(uint8_t*)0xD0) | |
| goto scheduleNextCheck; | |
| goto clearCoilCharge; | |
| } | |
| /** | |
| * isr_crankPosition - INT0 Crank Position Signal | |
| * Address: 0x01D3 | |
| * | |
| * Triggered by distributor CKP (Crank Position) signal. | |
| * Captures timer value for RPM calculation. | |
| * | |
| * Register bank 0x1B (r0-r7 at 0xD8-0xDF) | |
| */ | |
| void isr_crankPosition(void) { | |
| // Save and restore IE around processing | |
| uint16_t savedIE = g_savedInterruptLow | (g_savedInterruptHigh << 8); | |
| REG_IE = savedIE; | |
| // Capture Timer 2 value | |
| uint16_t capturedTime = REG_TM2; | |
| // Enable interrupts during processing | |
| REG_PSWH |= 0x01; | |
| REG_LRB = 0x1B; // Bank at 0xD8 | |
| // Check for overflow (ACCH.7 set) | |
| if (REG_ACCH & 0x80) | |
| goto ckpHandleOverflow; | |
| // Check for spurious interrupt (IRQH.0) | |
| if (!(REG_IRQH & 0x01)) | |
| goto ckpHandleOverflow; | |
| // Valid CKP signal - increment counter | |
| (*(uint8_t*)0xDB)++; | |
| g_sensorFlags |= 0x02; | |
| ckpHandleOverflow: | |
| // Store captured time | |
| *(uint16_t*)0xDA = capturedTime; // er2 | |
| *(uint16_t*)0xD8 = capturedTime; // er0 | |
| // Clear and swap counter | |
| uint8_t count = *(uint8_t*)0xDB; | |
| *(uint8_t*)0xDB = 0; | |
| *(uint8_t*)0xDA = count; | |
| // Set sync flag | |
| g_sensorFlags |= 0x04; | |
| // Restore IE and return | |
| savedIE = *(uint16_t*)0xF2; | |
| REG_PSWH &= 0xFE; | |
| REG_IE = savedIE; | |
| } | |
| /** | |
| * isr_serialRx - K-Line Serial Receive | |
| * Address: 0x01FD | |
| * | |
| * Handles incoming serial data from diagnostic tools. | |
| * Implements Honda K-line protocol for ECU communication. | |
| * | |
| * Register bank 0x6F (r0-r7 at 0x378-0x37F) | |
| */ | |
| void isr_serialRx(void) { | |
| // Save IE and set processing mode | |
| uint16_t savedIE = g_savedInterruptLow | (g_savedInterruptHigh << 8); | |
| REG_IE = savedIE; | |
| REG_PSW = 0x0102; | |
| REG_LRB = 0x6F; // Bank at 0x378 | |
| // Check serial mode flag | |
| if (!(g_serialFlags & 0x02)) { | |
| // Response mode - sending data back | |
| if (!(g_serialFlags & 0x40)) { | |
| // Not in middle of response | |
| goto receiveNewCommand; | |
| } | |
| // Continue sending response | |
| uint8_t respIndex = *(uint8_t*)0x37D; // r5 | |
| if (respIndex == 2) { | |
| // Send count byte | |
| uint8_t count = *(uint8_t*)0x37A; // r2 | |
| (*(uint8_t*)0x37E) += count; // r6 checksum | |
| REG_STBUF = count; | |
| } else if (respIndex >= *(uint8_t*)0x37A) { | |
| // Done sending - send checksum | |
| uint8_t checksum = -(*(uint8_t*)0x37E); | |
| REG_STBUF = checksum; | |
| goto finishSerialRx; | |
| } else { | |
| // Send data byte | |
| uint8_t dataOffset = respIndex + *(uint8_t*)0x37B; // r3 base | |
| REG_DP = 0x6B56 + (dataOffset * 2); // Table address | |
| uint16_t addrPtr = *(uint16_t*)REG_DP; | |
| REG_DP = addrPtr; | |
| uint8_t dataByte = *(uint8_t*)REG_DP; | |
| (*(uint8_t*)0x37E) += dataByte; // Add to checksum | |
| REG_STBUF = dataByte; | |
| } | |
| (*(uint8_t*)0x37D)++; // Increment index | |
| g_serialFlags |= 0x40; // Mark response in progress | |
| goto finishSerialRx; | |
| } | |
| receiveNewCommand: | |
| // Receive mode - process incoming byte | |
| uint8_t rxByte = REG_SRBUF; | |
| uint8_t msgIndex = *(uint8_t*)0x37D; | |
| if (*(uint8_t*)0x37F) { | |
| // Already have header | |
| if (msgIndex == 1) { | |
| // Second byte is length | |
| *(uint8_t*)0x37A = rxByte; | |
| } else if (msgIndex == 2) { | |
| // Third byte is address | |
| *(uint8_t*)0x37B = rxByte; | |
| } else { | |
| // Data or checksum | |
| *(uint8_t*)0x37C = rxByte; | |
| } | |
| (*(uint8_t*)0x37E) += rxByte; // Add to checksum | |
| (*(uint8_t*)0x37D)++; | |
| *(uint8_t*)0x37F = 0x02; | |
| goto finishSerialRx; | |
| } | |
| // First byte - save as header | |
| *(uint8_t*)0x378 = *(uint8_t*)0x379; | |
| *(uint8_t*)0x379 = rxByte; | |
| *(uint8_t*)0x37E = rxByte; // Start checksum | |
| *(uint8_t*)0x37D = 1; | |
| *(uint8_t*)0x37F = 0x02; | |
| goto finishSerialRx; | |
| finishSerialRx: | |
| // Validate complete message | |
| if (msgIndex + 1 >= *(uint8_t*)0x37A) { | |
| // Check checksum | |
| uint8_t finalChecksum = REG_SRBUF + *(uint8_t*)0x37E; | |
| if (finalChecksum == 0) { | |
| // Valid message - check header | |
| uint8_t header = *(uint8_t*)0x379; | |
| if ((header & 0xE0) == 0x20) { | |
| // Valid read request | |
| g_serialFlags |= 0x80; | |
| } | |
| } | |
| *(uint8_t*)0x37F = 0; // Reset state | |
| } | |
| // Restore IE | |
| savedIE = *(uint16_t*)0xF2; | |
| REG_PSWH &= 0xFE; | |
| REG_IE = savedIE; | |
| } | |
| /** | |
| * isr_timer2Overflow - Timer 2 Overflow Handler | |
| * Address: 0x02DD | |
| * | |
| * Handles Timer 2 overflow for extended timing. | |
| * Updates overflow counters for ignition timing. | |
| */ | |
| void isr_timer2Overflow(void) { | |
| uint16_t savedIE = g_savedInterruptLow | (g_savedInterruptHigh << 8); | |
| REG_IE = savedIE; | |
| REG_PSWH |= 0x01; | |
| REG_LRB = 0x1B; | |
| // Check and increment overflow counters | |
| if (!(g_sensorFlags & 0x01)) | |
| (*(uint8_t*)0xDE)++; // r6 | |
| if (!(g_sensorFlags & 0x02)) | |
| (*(uint8_t*)0xDB)++; // r3 | |
| // Restore and return | |
| savedIE = *(uint16_t*)0xF2; | |
| REG_PSWH &= 0xFE; | |
| REG_IE = savedIE; | |
| } | |
| /** | |
| * isr_timer3Match - Timer 3 Match Handler | |
| * Address: 0x02FB | |
| * | |
| * Supplementary timer for ignition control. | |
| */ | |
| void isr_timer3Match(void) { | |
| uint16_t savedIE = g_savedInterruptLow | (g_savedInterruptHigh << 8); | |
| REG_IE = savedIE; | |
| REG_PSWH |= 0x01; | |
| REG_LRB = 0x1A; | |
| uint8_t count = *(uint8_t*)0xD0 + 1; | |
| if (count >= 5) { | |
| // Check TCON3.2 before firing | |
| if (!(REG_TCON3 & 0x04)) { | |
| REG_TMR3 = *(uint16_t*)0xD6; // er3 | |
| REG_TCON3 |= 0x08; | |
| } | |
| } | |
| savedIE = *(uint16_t*)0xF2; | |
| REG_PSWH &= 0xFE; | |
| REG_IE = savedIE; | |
| } | |
| /** | |
| * isr_pwmTimer - PWM Timer for IACV Control | |
| * Address: 0x031E | |
| * | |
| * Controls Idle Air Control Valve PWM output. | |
| * Runs at fixed frequency, adjusts duty cycle for idle speed. | |
| * | |
| * Register bank 0x70 (r0-r7 at 0x380-0x387) | |
| */ | |
| void isr_pwmTimer(void) { | |
| uint16_t savedIE = g_savedInterruptLow | (g_savedInterruptHigh << 8); | |
| REG_IE = savedIE; | |
| REG_PSWH |= 0x01; | |
| REG_LRB = 0x70; // Bank at 0x380 | |
| // Check operating mode | |
| if (g_serialFlags & 0x01) { | |
| // Special serial mode - use saved values | |
| uint8_t duty = *(uint8_t*)0x382; | |
| if (duty == 0) { | |
| // Load new cycle parameters | |
| *(uint8_t*)0x383 = g_firingOrderPhase; // 0xE6 | |
| *(uint16_t*)0x382 = g_crankPosition; // 0xE4 | |
| duty = 0x31; // Default duty | |
| } | |
| goto setDutyCycle; | |
| } | |
| // Normal IACV operation | |
| uint8_t counter = *(uint8_t*)0x380; | |
| counter++; | |
| // Check for cycle wrap at 100 (0x64) | |
| if (counter >= 0x64) { | |
| // Start new cycle - load target duty | |
| *(uint8_t*)0x381 = g_iacvDutyCycle; | |
| counter = 0; | |
| } | |
| *(uint8_t*)0x380 = counter; | |
| // Compare counter to duty for P4.3 output | |
| if (counter < *(uint8_t*)0x381) | |
| REG_P4 |= 0x08; // High (valve open) | |
| else | |
| REG_P4 &= ~0x08; // Low (valve closed) | |
| // Set flag when counter hits zero | |
| if (counter == 0) | |
| g_sensorFlags |= 0x08; | |
| goto finishPwm; | |
| setDutyCycle: | |
| *(uint8_t*)0x382 = duty; | |
| // Check for special duty value | |
| if (duty == 0x0D) | |
| g_sensorFlags |= 0x40; | |
| // Compare to target | |
| if (duty == *(uint8_t*)0x383) { | |
| // Match - load PWM value | |
| REG_PWMR0 = *(uint16_t*)0x382; | |
| } else { | |
| // Calculate direction | |
| if (duty >= *(uint8_t*)0x383) | |
| REG_PWMR0 = 1; | |
| else | |
| REG_PWMR0 = 0xFFFF; | |
| } | |
| finishPwm: | |
| savedIE = *(uint16_t*)0xF2; | |
| REG_PSWH &= 0xFE; | |
| REG_IE = savedIE; | |
| } | |
| /** | |
| * isr_externalInt1 - Main Engine Processing Entry | |
| * Address: 0x037B | |
| * | |
| * INT1 is triggered at key engine events. | |
| * This is the main entry point for engine calculations. | |
| */ | |
| void isr_externalInt1(void) { | |
| REG_IE = 0x00A0; // Minimal interrupts | |
| REG_PSW = 0x0102; | |
| REG_LRB = 0x21; | |
| REG_USP = 0x0280; | |
| // Call main processing function | |
| call_mainSensorScan(); // label_5262 | |
| // Set processing flag | |
| g_ignitionFlags |= 0x10; // 0x120.4 | |
| // Check various error conditions | |
| if (g_errorFlags1 & 0x80) // 0x112.7 | |
| goto mainProcessingDone; | |
| if (g_errorFlags1 & 0x08) // 0x112.3 | |
| goto processAdcAndTiming; | |
| // Check IRQH.1 | |
| if (!(REG_IRQH & 0x02)) { | |
| g_groundReference &= ~0x01; // 0x9C.0 | |
| g_vtecHoldCounter = 0x2D; // 0x1A9 | |
| } else { | |
| g_groundReference |= 0x01; | |
| } | |
| goto mainProcessingDone; | |
| processAdcAndTiming: | |
| // Capture O2 sensor | |
| g_o2SecondaryRaw = REG_ADCR6; | |
| // Capture Timer 2 for ignition reference | |
| g_ignitionDwellStart = REG_TM2; | |
| REG_TMR2 = g_ignitionDwellStart; | |
| // Initialize cycle counter | |
| g_injectorTiming1 = 0; // 0xD2 | |
| // Check timing connector | |
| uint8_t adjCount = g_vtecQualifyFlags; | |
| if (!(REG_TRNSIT & 0x01)) { | |
| adjCount += 6; | |
| if (adjCount >= 0x18) | |
| adjCount = 3; | |
| } | |
| g_vtecQualifyFlags = adjCount; | |
| // Set P4.0 output | |
| REG_P4 |= 0x01; | |
| // Continue to main processing | |
| goto call_mainProcessing; // label_5f74 | |
| } | |
| /** | |
| * isr_serialRxBrg - Serial Baud Rate Generator Handler | |
| * Address: 0x03DC | |
| * | |
| * Also used as secondary main processing entry point. | |
| * Copies flags and continues engine calculations. | |
| */ | |
| void isr_serialRxBrg(void) { | |
| REG_IE = 0x00A0; | |
| REG_PSW = 0x0102; | |
| REG_LRB = 0x21; | |
| REG_USP = 0x0280; | |
| // Copy flag banks from stack area | |
| g_errorFlags1 = *(uint8_t*)0x212; // USP-0x80+0x92 | |
| g_errorFlags3 = *(uint16_t*)0x214; | |
| g_vtecFlags1 = *(uint16_t*)0x216; | |
| g_vtecHoldCounter = 0x2D; | |
| // Check processing flags | |
| if (!(g_ignitionFlags & 0x08)) // 0x120.3 | |
| goto checkRevLimit; | |
| // Check for rev limit conditions | |
| if (g_errorFlags1 & 0x80) { | |
| g_ignitionFlags |= 0x10; | |
| goto processNormal; | |
| } | |
| if (!(REG_IRQH & 0x80) && !(g_sensorFlags & 0x80)) { | |
| goto incrementCounter; | |
| } | |
| // Rev limiting active | |
| g_ignitionFlags |= 0x10; | |
| g_ignitionFlags &= ~0x40; | |
| g_vtecHoldCounter = 0x2D; | |
| // Check cycle count | |
| uint16_t cycleCount = g_injectorTiming1; | |
| if (cycleCount == 5) | |
| goto fuelCutCheck; | |
| g_fuelCutFlags |= 0x40; // 0x11D.6 | |
| if (cycleCount < 5) { | |
| g_ignitionFlags |= 0x20; | |
| goto fuelCutCheck; | |
| } | |
| if (cycleCount >= 0x105) { | |
| g_timingAdjustInput |= 0x02; // 0x9D.1 | |
| goto clearCycleCount; | |
| } | |
| g_timingAdjustInput |= 0x01; // 0x9D.0 | |
| goto fuelCutCheck; | |
| incrementCounter: | |
| if (g_injectorTiming1 < 5) { | |
| g_injectorTiming1++; | |
| goto processIgnition; | |
| } | |
| if (!(g_errorFlags1 & 0x80)) { | |
| g_groundReference |= 0x02; | |
| g_ignitionFlags |= 0x40; | |
| } | |
| g_injectorTiming2++; | |
| g_injectorTiming1 = 0; | |
| goto processIgnition; | |
| checkRevLimit: | |
| REG_IRQH &= ~0x80; | |
| g_sensorFlags &= ~0x80; | |
| g_sensorFlags &= ~0x04; | |
| if (g_sensorFlags & 0x01) | |
| g_ignitionFlags |= 0x10; | |
| goto fuelCutCheck; | |
| fuelCutCheck: | |
| g_sensorFlags &= ~0x04; | |
| processIgnition: | |
| // Continue processing... | |
| goto continueMainProcessing; | |
| clearCycleCount: | |
| g_injectorTiming1 = 0; | |
| goto processIgnition; | |
| processNormal: | |
| goto continueMainProcessing; | |
| continueMainProcessing: | |
| // Further processing in main engine routines | |
| return; | |
| } | |
| /** | |
| * isr_serialTx - Serial Transmit (placeholder) | |
| * Address: 0x21CB | |
| * | |
| * Handles serial transmit complete interrupt. | |
| * Also used as dummy handler for unused vectors. | |
| */ | |
| void isr_serialTx(void) { | |
| // Set life counter to 'E' pattern (reboot marker) | |
| g_lifeCounter = 0x45; | |
| } | |
| /** | |
| * isr_watchdog - Watchdog Timer Reset | |
| * Address: 0x21D1 | |
| * | |
| * Called when watchdog timer expires. | |
| * Sets reboot reason code. | |
| */ | |
| void isr_watchdog(void) { | |
| g_lifeCounter = 0x44; // 'D' - WDT reset code | |
| } | |
| /** | |
| * isr_systemStart - System Startup | |
| * Address: 0x21E2 | |
| * | |
| * First code executed after reset. | |
| * Initializes registers and jumps to main init. | |
| */ | |
| void isr_systemStart(void) { | |
| g_lifeCounter = 0x46; // 'F' - Normal start | |
| // Jump to initialization code... | |
| } | |
| /** | |
| * isr_break - Software Break Handler | |
| * Address: 0x21E9 | |
| * | |
| * Handles BRK instruction - used for debugging. | |
| */ | |
| void isr_break(void) { | |
| REG_WDT = 0x3C; // Feed watchdog | |
| // Handle break... | |
| } | |
| /*============================================================================ | |
| * SECTION 6: VCAL HELPER FUNCTIONS | |
| * | |
| * VCAL (Vector Call) functions are table lookup and math helpers. | |
| * Called via special VCAL instruction with index 0-7. | |
| *============================================================================*/ | |
| /** | |
| * vcal_tableLookup1D - 1D Table Interpolation | |
| * Address: 0x4E62 (VCAL 0) | |
| * | |
| * Performs linear interpolation on a 1D table. | |
| * Input: A = lookup value, X1 = table base address | |
| * Output: A = interpolated result | |
| * | |
| * Table format: pairs of (threshold, value) ending with 0xFF threshold | |
| */ | |
| uint8_t vcal_tableLookup1D(uint8_t input, uint16_t tableAddr) { | |
| uint8_t* table = (uint8_t*)tableAddr; | |
| // Walk table until we find input >= threshold | |
| while (input >= table[2]) { | |
| table += 2; // Move to next entry | |
| } | |
| // Store found threshold for interpolation | |
| uint8_t upperThreshold = table[2]; | |
| uint8_t upperValue = table[3]; | |
| uint8_t lowerThreshold = table[1]; | |
| uint8_t lowerValue = table[0]; | |
| // Calculate interpolation | |
| uint8_t thresholdDelta = input - upperThreshold; | |
| int8_t valueDelta = lowerValue - upperValue; | |
| // Handle negative delta | |
| bool negative = false; | |
| if (valueDelta < 0) { | |
| negative = true; | |
| valueDelta = -valueDelta; | |
| } | |
| // Interpolate: result = upperValue + (delta * valueDelta / thresholdDelta) | |
| uint16_t product = thresholdDelta * valueDelta; | |
| uint8_t interpolation = product / (lowerThreshold - upperThreshold); | |
| if (negative) | |
| return upperValue - interpolation; | |
| else | |
| return upperValue + interpolation; | |
| } | |
| /** | |
| * vcal_tableLookup2D - 2D Table Interpolation | |
| * Address: 0x4EC0 (VCAL 1) | |
| * | |
| * Performs bilinear interpolation on a 2D table. | |
| * Input: A = row lookup value, X1 = table base with axis data | |
| * Output: er3 = 16-bit interpolated result | |
| * | |
| * Table format: 3-byte entries (threshold, value_low, value_high) | |
| */ | |
| uint16_t vcal_tableLookup2D(uint8_t rowInput, uint16_t tableAddr) { | |
| uint8_t* table = (uint8_t*)tableAddr; | |
| // Walk table by 3-byte entries | |
| while (rowInput >= table[3]) { | |
| table += 3; | |
| } | |
| // Get boundary values | |
| uint8_t upperThreshold = table[3]; | |
| uint8_t lowerThreshold = table[0]; | |
| uint8_t thresholdDelta = rowInput - upperThreshold; | |
| // Get 16-bit values | |
| uint16_t lowerValue = table[1] | (table[2] << 8); | |
| uint16_t upperValue = table[4] | (table[5] << 8); | |
| // Calculate delta and interpolate | |
| int16_t valueDelta = lowerValue - upperValue; | |
| bool negative = false; | |
| if (valueDelta < 0) { | |
| negative = true; | |
| valueDelta = -valueDelta; | |
| } | |
| // 16-bit multiply and divide for precision | |
| uint32_t product = (uint32_t)thresholdDelta * valueDelta; | |
| uint16_t divisor = lowerThreshold - upperThreshold; | |
| uint16_t interpolation = product / divisor; | |
| if (negative) | |
| return upperValue - interpolation; | |
| else | |
| return upperValue + interpolation; | |
| } | |
| /** | |
| * vcal_clampTableLookup - Clamped Table Lookup | |
| * Address: 0x4E9C (VCAL 2) | |
| * | |
| * Like VCAL 0 but clamps input to table range. | |
| * If input < table[0], uses table[0]. | |
| * If input > table[2], uses table[2]. | |
| */ | |
| uint8_t vcal_clampTableLookup(uint8_t input, uint16_t tableAddr) { | |
| uint8_t* table = (uint8_t*)tableAddr; | |
| // Clamp to minimum | |
| if (input < table[0]) | |
| input = table[0]; | |
| // Clamp to maximum | |
| if (input >= table[2]) | |
| input = table[2]; | |
| // Use standard lookup | |
| return vcal_tableLookup1D(input, tableAddr); | |
| } | |
| /** | |
| * vcal_rangeLimit - Value Range Limiter | |
| * Address: 0x4EAE (VCAL 3) | |
| * | |
| * Clamps input to table-defined range, 3-byte entries. | |
| * Similar to VCAL 2 but uses 3-byte table format. | |
| */ | |
| uint8_t vcal_rangeLimit(uint8_t input, uint16_t tableAddr) { | |
| uint8_t* table = (uint8_t*)tableAddr; | |
| // Clamp to range [table[0], table[3]] | |
| if (input < table[0]) | |
| input = table[0]; | |
| if (input >= table[3]) | |
| input = table[3]; | |
| return vcal_tableLookup2D(input, tableAddr); | |
| } | |
| /** | |
| * vcal_mainProcess - Main Processing Entry | |
| * Address: 0x25A1 (VCAL 4) | |
| * | |
| * Entry point called during main engine calculations. | |
| * Dispatches to various subsystem processors. | |
| */ | |
| void vcal_mainProcess(void) { | |
| // This is a complex dispatcher - NOP in simple form | |
| __asm("NOP"); | |
| // Actually continues into main engine processing | |
| // See main engine section for full implementation | |
| } | |
| /** | |
| * vcal_multiply16 - 16-bit Multiply Helper | |
| * Address: 0x4F7F (VCAL 5) | |
| * | |
| * Performs 16x16 bit multiply with 32-bit result. | |
| * Input: A, er0 = multiplicands | |
| * Output: er1:A = 32-bit product | |
| */ | |
| uint32_t vcal_multiply16(uint16_t a, uint16_t b) { | |
| // Check for sign | |
| if (a & 0x8000) { | |
| // Handle as signed | |
| return (int16_t)a * (int16_t)b; | |
| } | |
| return a * b; | |
| } | |
| /** | |
| * vcal_divide16 - 16-bit Divide Helper | |
| * Address: 0x4F84 (VCAL 6) | |
| * | |
| * Performs 32/16 bit divide. | |
| * Input: er1:A = 32-bit dividend, er0 = 16-bit divisor | |
| * Output: A = quotient, er1 = remainder | |
| */ | |
| uint16_t vcal_divide16(uint32_t dividend, uint16_t divisor) { | |
| if (divisor == 0) return 0xFFFF; // Saturate on divide by zero | |
| return dividend / divisor; | |
| } | |
| /** | |
| * vcal_absValue - Absolute Value Helper | |
| * Address: 0x4FCE (VCAL 7) | |
| * | |
| * Returns absolute value of signed 16-bit number. | |
| * Input: A = signed value | |
| * Output: A = |A| | |
| */ | |
| uint16_t vcal_absValue(int16_t value) { | |
| if (value < 0) | |
| return -value; | |
| return value; | |
| } | |
| /*============================================================================ | |
| * SECTION 7: MAIN ENGINE CONTROL FUNCTIONS | |
| * | |
| * Core engine management routines that coordinate fuel, ignition, | |
| * VTEC, and diagnostics. | |
| *============================================================================*/ | |
| /** | |
| * call_mainSensorScan - Read All Sensors | |
| * Address: 0x5262 | |
| * | |
| * Scans all ADC channels and updates sensor variables. | |
| * Called at start of each engine cycle. | |
| */ | |
| void call_mainSensorScan(void) { | |
| // Capture battery voltage from ADC6 high byte | |
| g_o2SecondaryRaw = REG_ADCR2H; | |
| // Process delta calculation | |
| uint8_t oldValue = *(uint8_t*)0x3D2; // Saved from last scan | |
| *(uint8_t*)0x3D2 = g_batteryVoltageRaw; // c5h | |
| uint8_t newValue = REG_ADCR2H; | |
| g_batteryVoltageRaw = newValue; | |
| // Calculate delta and set direction flag | |
| int8_t delta = newValue - oldValue; | |
| if (delta >= 0) | |
| g_stateFlags22B |= 0x20; | |
| else | |
| g_stateFlags22B &= ~0x20; | |
| // Store delta magnitude | |
| if (delta < 0) delta = -delta; | |
| g_ecuVoltageRaw = delta; // 0xC6 | |
| // Capture P2 injector state | |
| g_stateFlags255 = REG_P2 & 0xE0; | |
| // Prepare for ADC scan | |
| uint16_t savedIE = *(uint16_t*)0xF4; | |
| REG_IE = savedIE; | |
| REG_PSWH &= 0xFE; | |
| // Clear ADC scan flag and start conversion | |
| REG_ADSCAN &= 0xEF; | |
| REG_P2 &= 0x1F; | |
| REG_ADSCAN |= 0x10; | |
| REG_PSWH |= 0x01; | |
| savedIE = *(uint16_t*)0xF2; | |
| REG_IE = savedIE; | |
| } | |
| /** | |
| * process_rpmCalculation - Calculate Engine RPM | |
| * Address: 0x074E-0x07F3 | |
| * | |
| * Calculates RPM from timer captures and updates history buffers. | |
| * Uses formula: RPM = 1,851,562 / timer_ticks | |
| */ | |
| void process_rpmCalculation(void) { | |
| REG_DP = 0x0360; // RPM history buffer | |
| uint32_t sum = 0; | |
| // Sum last 6 timer values | |
| for (int i = 0; i < 6; i++) { | |
| uint16_t value = *(uint16_t*)REG_DP; | |
| if (value == 0) { | |
| // Invalid reading - set error flag | |
| g_stateFlags231 |= 0x20; | |
| g_rpmTimerAverage = 0xFFFF; | |
| return; | |
| } | |
| sum += value; | |
| REG_DP += 2; | |
| } | |
| // Clear error flag | |
| g_stateFlags217 &= ~0x10; | |
| g_stateFlags231 &= ~0x20; | |
| // Calculate average | |
| uint16_t average = sum / 5; | |
| if (sum % 5 != 0) { | |
| g_stateFlags231 |= 0x20; | |
| average = 0xFFFF; | |
| } | |
| // Store result | |
| g_rpmTimerAverage = average; | |
| // Shift history buffer | |
| REG_DP = 0x036C; | |
| uint16_t temp = g_mapSensorRaw; // 0xAC | |
| g_mapSensorRaw = *(uint16_t*)REG_DP; | |
| *(uint16_t*)REG_DP = temp; | |
| REG_DP += 2; | |
| temp = *(uint16_t*)REG_DP; | |
| *(uint16_t*)REG_DP = g_mapSensorRaw; | |
| REG_DP += 2; | |
| *(uint16_t*)REG_DP = temp; | |
| // Calculate delta from average | |
| uint16_t delta = g_rpmTimerAverage - temp; | |
| if (delta >= 0) | |
| g_stateFlags21B |= 0x80; | |
| else | |
| g_stateFlags21B &= ~0x80; | |
| // Absolute value | |
| if (delta < 0) delta = -delta; | |
| g_mapSensorRaw = delta; // Reusing for delta temp | |
| // Second delta calculation | |
| delta = g_rpmTimerAverage - g_mapSensorOld; | |
| if (delta >= 0) | |
| g_stateFlags21B |= 0x40; | |
| else | |
| g_stateFlags21B &= ~0x40; | |
| // Convert timer ticks to RPM byte | |
| // Using lookup table at 0x6D08 for breakpoints | |
| if (g_mapSensorRaw >= 0x00EA && g_mapSensorRaw < 0x0EA6) { | |
| // Normal operating range - calculate RPM index | |
| uint16_t rpmValue = g_mapSensorRaw; | |
| uint16_t mask = 0xFFC0; | |
| uint8_t index = 7; | |
| uint16_t tableOffset = 0x5300; | |
| REG_DP = TBL_DIAGNOSTIC_PARAMS; // 0x6D08 | |
| while (1) { | |
| uint16_t threshold = *(uint16_t*)REG_DP; | |
| if (rpmValue >= threshold) | |
| break; | |
| index >>= 1; | |
| tableOffset >>= 1; | |
| mask += 0x0040; | |
| REG_DP += 2; | |
| } | |
| // Calculate final RPM byte | |
| uint16_t remainder = tableOffset / rpmValue; | |
| remainder >>= 1; | |
| mask += remainder; | |
| // Check for edge cases | |
| if (mask >= 0xFF) { | |
| g_rpmByteNonVtec = 0xFE; | |
| } else if (mask <= 1) { | |
| g_rpmByteNonVtec = 1; | |
| } else { | |
| g_rpmByteNonVtec = mask; | |
| } | |
| } else if (g_mapSensorRaw < 0x00BB) { | |
| // Very high RPM | |
| g_rpmByteNonVtec = 0xFF; | |
| } else if (g_mapSensorRaw >= 0x0EA6) { | |
| // Very low RPM or stalled | |
| g_rpmByteNonVtec = 0; | |
| if (!(g_stateFlags217 & 0x10)) | |
| g_rpmByteNonVtec = 1; | |
| } | |
| // Set RPM direction flag | |
| if (g_rpmByteNonVtec >= 0xFE) | |
| g_sensorFlags |= 0x80; // 0xA0.7 | |
| else | |
| g_sensorFlags &= ~0x80; | |
| // Store to second RPM byte location | |
| g_stateFlags236 = g_rpmByteNonVtec; | |
| g_tpsSensorFiltered = g_rpmByteNonVtec; | |
| } | |
| /** | |
| * process_mapSensor - Process MAP Sensor Reading | |
| * Address: 0x09AB-0x09CF | |
| * | |
| * Reads manifold absolute pressure and calculates load. | |
| * Updates g_mapImageBase (0xB4) for fuel/ignition lookups. | |
| */ | |
| void process_mapSensor(void) { | |
| // Calculate MAP delta for transient detection | |
| uint16_t mapDelta = g_mapSensorRaw - g_stateFlags258; | |
| if (mapDelta >= 0) | |
| g_stateFlags21A |= 0x20; | |
| else | |
| g_stateFlags21A &= ~0x20; | |
| // Store delta direction | |
| g_mapSensorOld = mapDelta; // 0xB2 | |
| // Check for closed throttle (high vacuum) | |
| if (g_stateFlags22B & 0x01) { | |
| // Already flagged as high vacuum | |
| if (g_stateFlags236 < 0x98) | |
| goto normalMapProcessing; | |
| } else { | |
| if (g_stateFlags236 >= 0xA0) | |
| goto normalMapProcessing; | |
| } | |
| // Update closed throttle flag | |
| if (g_stateFlags236 >= 0x98) | |
| g_stateFlags22B |= 0x01; | |
| else | |
| g_stateFlags22B &= ~0x01; | |
| normalMapProcessing: | |
| // Check RPM threshold for decel fuel cut | |
| if (g_stateFlags218 & 0x80) { | |
| if (g_stateFlags236 < 0xCD) | |
| goto updateMapImage; | |
| } else { | |
| if (g_stateFlags236 >= 0xD0) | |
| goto updateMapImage; | |
| } | |
| g_stateFlags218 |= 0x80; | |
| goto updateMapImage; | |
| updateMapImage: | |
| // Update MAP image for fuel/ignition lookups | |
| // Scale raw ADC to 0-DF range | |
| // MAP image determines column in 2D tables | |
| } | |
| /** | |
| * process_tpsSensor - Process Throttle Position Sensor | |
| * Address: 0x09DB-0x0A3D | |
| * | |
| * Reads TPS and calculates rate of change for accel enrichment. | |
| */ | |
| void process_tpsSensor(void) { | |
| // Setup for table lookup | |
| uint16_t tableAddr = TBL_RPM_AXIS_NONVTEC; // 0x700A | |
| uint8_t lastInterp = *(uint8_t*)0x1D8; // Previous interpolation | |
| uint8_t currentRpm = g_stateFlags236; | |
| uint8_t interpFactor = 0x12; | |
| // Check for VTEC active to select table | |
| if (g_sensorFlags & 0x80) // 0xA0.7 | |
| interpFactor |= 0x80; // VTEC flag in high bit | |
| // Call 2D interpolation | |
| uint8_t rpmIndex = vcal_tableLookup1D(currentRpm, tableAddr); | |
| *(uint8_t*)0x1DA = rpmIndex; | |
| *(uint8_t*)0x1D8 = interpFactor; | |
| // Second axis lookup for TPS | |
| tableAddr = TBL_RPM_AXIS_VTEC; // 0x701E | |
| lastInterp = *(uint8_t*)0x1D9; | |
| uint8_t tpsValue = g_tpsSensorRaw; | |
| interpFactor = 0x12; | |
| // Check VTEC and direction flags | |
| if (g_stateFlags227 & 0x20) { | |
| currentRpm = g_stateFlags236; | |
| } | |
| if (g_sensorFlags & 0x40) // 0xA0.6 | |
| interpFactor |= 0x80; | |
| rpmIndex = vcal_tableLookup1D(currentRpm, tableAddr); | |
| *(uint8_t*)0x1DC = rpmIndex; | |
| *(uint8_t*)0x1D9 = interpFactor; | |
| // Process TPS for acceleration | |
| uint8_t iatValue = g_iatProcessed; // 0xA4 | |
| if (!(g_stateFlags212 & 0x04) && !(g_stateFlags212 & 0x10)) | |
| iatValue = g_rpmByteVtec; // 0xA7 | |
| // TPS delta calculation for accel enrichment | |
| tableAddr = TBL_ACCEL_ENRICHMENT; // 0x7000 | |
| lastInterp = *(uint8_t*)0x1D2; | |
| interpFactor = 0x08; | |
| // Clear VTEC flag for non-VTEC table | |
| uint8_t result = vcal_tableLookup1D(iatValue, tableAddr); | |
| *(uint8_t*)0x1D4 = result; | |
| *(uint8_t*)0x1D2 = interpFactor; | |
| // Repeat for VTEC table | |
| tableAddr = TBL_ACCEL_ENRICHMENT; | |
| lastInterp = *(uint8_t*)0x1D3; | |
| iatValue = g_rpmByteVtec; | |
| interpFactor = 0x08; | |
| result = vcal_tableLookup1D(iatValue, tableAddr); | |
| *(uint8_t*)0x1D6 = result; | |
| *(uint8_t*)0x1D3 = interpFactor; | |
| } | |
| /** | |
| * process_o2Sensor - Process Oxygen Sensor | |
| * Address: 0x0B4C-0x0BE7 | |
| * | |
| * Implements closed-loop fuel control using O2 sensor feedback. | |
| * Adjusts g_fuelO2TrimPrimary (0x162) and secondary (0x164). | |
| */ | |
| void process_o2Sensor(void) { | |
| // Check if closed-loop conditions are met | |
| if (g_stateFlags227 & 0x20) { | |
| // Special mode - use alternate registers | |
| uint8_t o2Value = g_stateFlags236; // 0x236 | |
| goto processO2Value; | |
| } | |
| if (!(g_stateFlags21F & 0x02)) | |
| return; // Open loop - no O2 correction | |
| processO2Value: | |
| // Get O2 sensor reading | |
| uint8_t o2Raw = g_o2PrimaryRaw; // 0xA1 | |
| // Compare to stoich threshold (typically 0x1F = 31 decimal) | |
| // < 0x1F is lean, > 0x1F is rich | |
| if (o2Raw < 0x1F) { | |
| // Lean condition - add fuel | |
| g_stateFlags21B |= 0x01; // Set lean flag | |
| } else { | |
| // Rich condition - remove fuel | |
| g_stateFlags21B &= ~0x01; // Clear lean flag | |
| } | |
| // Apply proportional + integral correction | |
| // Lookup correction rate from table | |
| uint16_t tableAddr = TBL_O2_CLOSED_LOOP; // 0x605E | |
| uint8_t correctionRate = vcal_tableLookup1D(g_rpmByteNonVtec, tableAddr); | |
| // Update O2 trim value | |
| if (g_stateFlags21B & 0x01) { | |
| // Lean - increase fuel | |
| if (g_fuelO2TrimPrimary < 0xFFFF) | |
| g_fuelO2TrimPrimary += correctionRate; | |
| } else { | |
| // Rich - decrease fuel | |
| if (g_fuelO2TrimPrimary > 0) | |
| g_fuelO2TrimPrimary -= correctionRate; | |
| } | |
| // Clamp to valid range | |
| if (g_fuelO2TrimPrimary > 0x0200) | |
| g_fuelO2TrimPrimary = 0x0200; // Max +12.5% trim | |
| if (g_fuelO2TrimPrimary < 0xFE00) | |
| g_fuelO2TrimPrimary = 0xFE00; // Max -12.5% trim | |
| } | |
| /*============================================================================ | |
| * SECTION 8: FUEL CALCULATION FUNCTIONS | |
| * | |
| * Fuel injection pulse width calculations including all corrections. | |
| *============================================================================*/ | |
| /** | |
| * calc_fuelPulseWidth - Calculate Injector Pulse Width | |
| * Address: 0x1C00-0x1F84 | |
| * | |
| * Main fuel calculation routine. Combines: | |
| * - Base fuel from 2D map | |
| * - ECT/IAT corrections | |
| * - O2 feedback trim | |
| * - Accel/decel enrichment | |
| * - Battery voltage compensation | |
| * - AC load compensation | |
| */ | |
| void calc_fuelPulseWidth(void) { | |
| // Select VTEC or non-VTEC fuel map | |
| uint16_t fuelMapBase; | |
| if (g_vtecStateFlags & 0x80) { | |
| // VTEC engaged - use VTEC map | |
| fuelMapBase = TBL_FUEL_VTEC_ADDR; | |
| } else { | |
| // Non-VTEC - use standard map | |
| fuelMapBase = TBL_FUEL_NONVTEC_ADDR; | |
| } | |
| // Look up base fuel from 2D map | |
| // Row = RPM index, Column = MAP index | |
| uint8_t rpmIndex = *(uint8_t*)0x1DA; // From TPS processing | |
| uint8_t mapIndex = g_mapImageFinal >> 4; // High nibble is column | |
| // Calculate table address | |
| uint16_t tableOffset = (rpmIndex * 20) + (mapIndex * 2); | |
| uint16_t* fuelTable = (uint16_t*)(fuelMapBase + tableOffset); | |
| // Get surrounding cells for interpolation | |
| uint16_t cellLL = fuelTable[0]; | |
| uint16_t cellLR = fuelTable[1]; | |
| uint16_t cellUL = fuelTable[20]; | |
| uint16_t cellUR = fuelTable[21]; | |
| // Interpolate based on fractional position | |
| uint8_t rpmFrac = *(uint8_t*)0x1D8 & 0x0F; // Low nibble is fraction | |
| uint8_t mapFrac = g_mapImageFinal & 0x0F; // Low nibble is fraction | |
| // Bilinear interpolation | |
| uint16_t interpL = cellLL + ((cellUL - cellLL) * rpmFrac) / 16; | |
| uint16_t interpR = cellLR + ((cellUR - cellLR) * rpmFrac) / 16; | |
| uint16_t baseFuel = interpL + ((interpR - interpL) * mapFrac) / 16; | |
| // Store base fuel value | |
| if (g_vtecStateFlags & 0x80) | |
| g_fuelMapVtec = baseFuel; | |
| else | |
| g_fuelMapNonVtec = baseFuel; | |
| // Apply warmup enrichment (ECT based) | |
| uint16_t warmupMult = g_fuelWarmupMult; // 0x15E | |
| baseFuel = (baseFuel * warmupMult) / 256; | |
| g_fuelMainCorrected = baseFuel; | |
| // Apply all additional corrections | |
| uint16_t totalCorrections = 0; | |
| // TPS acceleration enrichment | |
| totalCorrections += g_fuelTpsDelta; // 0x14A | |
| // Battery voltage dead time compensation | |
| totalCorrections += g_fuelBatteryTrim; // 0x14C | |
| // AC compressor load | |
| if (g_acFlags & 0x02) | |
| totalCorrections += g_fuelAcTrim; // 0x14E | |
| // Timing connector adjustment | |
| totalCorrections += g_fuelTimingTrim; // 0x152 | |
| // TPS steady-state adjustment | |
| totalCorrections += g_fuelTpsRelated; // 0x150 | |
| g_fuelAllCorrections = totalCorrections; | |
| // Calculate final fuel before O2 | |
| g_fuelFinalNoO2 = baseFuel + totalCorrections - g_fuelAcTrim; | |
| // Apply O2 sensor trim (closed loop) | |
| uint16_t o2Multiplier; | |
| if (g_openClosedLoopFlag & 0x01) { | |
| // Use primary O2 | |
| o2Multiplier = g_fuelO2TrimPrimary; | |
| } else { | |
| // Use secondary O2 | |
| o2Multiplier = g_fuelO2TrimSecondary; | |
| } | |
| // Final fuel = base * o2Mult / 0x10000 * 2 + corrections | |
| uint32_t finalCalc = (uint32_t)g_fuelMainCorrected * o2Multiplier; | |
| finalCalc = (finalCalc / 0x10000) * 2; | |
| finalCalc += totalCorrections; | |
| g_injectorPulseWidth = (uint16_t)finalCalc; | |
| // Store to injector timing register | |
| g_injectorTiming0 = g_injectorPulseWidth; | |
| } | |
| /** | |
| * calc_injectorDeadTime - Calculate Injector Dead Time | |
| * Address: 0x158 reference | |
| * | |
| * Compensates for injector opening time based on battery voltage. | |
| * Lower voltage = longer opening time needed. | |
| */ | |
| uint16_t calc_injectorDeadTime(uint8_t batteryVoltage) { | |
| // Table lookup at TBL_INJECTOR_DEAD_TIME (0x6190) | |
| return vcal_tableLookup1D(batteryVoltage, TBL_INJECTOR_DEAD_TIME); | |
| } | |
| /*============================================================================ | |
| * SECTION 9: IGNITION TIMING FUNCTIONS | |
| * | |
| * Spark advance calculation and dwell control. | |
| *============================================================================*/ | |
| /** | |
| * calc_ignitionTiming - Calculate Spark Advance | |
| * Address: 0x1200-0x1400 | |
| * | |
| * Calculates ignition timing from: | |
| * - Base timing from 2D map | |
| * - ECT advance/retard | |
| * - IAT correction | |
| * - Knock retard | |
| * - Idle timing trim | |
| */ | |
| void calc_ignitionTiming(void) { | |
| // Select VTEC or non-VTEC ignition map | |
| uint16_t ignMapBase; | |
| if (g_vtecStateFlags & 0x80) { | |
| ignMapBase = TBL_IGN_VTEC_ADDR; | |
| } else { | |
| ignMapBase = TBL_IGN_NONVTEC_ADDR; | |
| } | |
| // Look up base timing from 2D map | |
| uint8_t rpmIndex = *(uint8_t*)0x1DA; | |
| uint8_t mapIndex = g_mapImageFinal >> 4; | |
| // Calculate table address | |
| uint16_t tableOffset = (rpmIndex * 20) + mapIndex; | |
| uint8_t* ignTable = (uint8_t*)(ignMapBase + tableOffset); | |
| // Get surrounding cells for interpolation | |
| uint8_t cellLL = ignTable[0]; | |
| uint8_t cellLR = ignTable[1]; | |
| uint8_t cellUL = ignTable[20]; | |
| uint8_t cellUR = ignTable[21]; | |
| // Interpolate | |
| uint8_t rpmFrac = *(uint8_t*)0x1D8 & 0x0F; | |
| uint8_t mapFrac = g_mapImageFinal & 0x0F; | |
| uint8_t interpL = cellLL + ((cellUL - cellLL) * rpmFrac) / 16; | |
| uint8_t interpR = cellLR + ((cellUR - cellLR) * rpmFrac) / 16; | |
| uint8_t baseAdvance = interpL + ((interpR - interpL) * mapFrac) / 16; | |
| g_ignitionMapRaw = baseAdvance; | |
| // Apply corrections | |
| int8_t finalAdvance = baseAdvance; | |
| // ECT correction (cold = more advance) | |
| finalAdvance += g_ignitionEctTrim; | |
| // Idle timing trim (from timing connector) | |
| if (g_idleFlags & 0x01) | |
| finalAdvance += g_ignitionIdleTrim; | |
| // Knock retard (subtracts timing) | |
| finalAdvance -= g_ignitionKnockTrim; | |
| // Brake switch correction | |
| if (g_externalInputs & 0x20) // Brake applied | |
| finalAdvance += g_ignitionBrakeTrim; | |
| // Clamp to valid range (0-60 degrees typical) | |
| if (finalAdvance < 0) finalAdvance = 0; | |
| if (finalAdvance > 60) finalAdvance = 60; | |
| g_ignitionFinal = finalAdvance; | |
| // Calculate complement for timer | |
| g_ignitionComplement = -finalAdvance; | |
| } | |
| /** | |
| * calc_dwellTime - Calculate Coil Dwell Time | |
| * Address: 0x619E table reference | |
| * | |
| * Determines how long to charge ignition coil. | |
| * Longer dwell at lower voltage. | |
| */ | |
| uint16_t calc_dwellTime(uint8_t batteryVoltage) { | |
| return vcal_tableLookup1D(batteryVoltage, TBL_DWELL_TIME); | |
| } | |
| /*============================================================================ | |
| * SECTION 10: VTEC CONTROL LOGIC | |
| * | |
| * Variable valve timing engagement and disengagement. | |
| *============================================================================*/ | |
| /** | |
| * check_vtecEngagement - VTEC Engagement Logic | |
| * Address: 0x3D00-0x3E00 | |
| * | |
| * Checks conditions for VTEC engagement: | |
| * - RPM above threshold | |
| * - Vehicle speed above minimum | |
| * - Oil pressure OK | |
| * - No error codes | |
| */ | |
| void check_vtecEngagement(void) { | |
| // Check if VTEC is currently engaged | |
| if (g_vtecStateFlags & 0x80) { | |
| // VTEC ON - check disengage conditions | |
| goto checkVtecDisengage; | |
| } | |
| // VTEC OFF - check engage conditions | |
| // 1. Check RPM threshold | |
| uint8_t engageRpm = vcal_tableLookup1D(g_coolantTempRaw, TBL_VTEC_ENGAGE_RPM); | |
| if (g_rpmByteNonVtec < engageRpm) | |
| return; // RPM too low | |
| // 2. Check vehicle speed minimum | |
| uint8_t minSpeed = vcal_tableLookup1D(g_coolantTempRaw, TBL_VTEC_MIN_SPEED); | |
| if (g_vehicleSpeedByte < minSpeed) | |
| return; // Speed too low | |
| // 3. Check oil pressure | |
| if (g_oilPressureSwitch < 0x32) | |
| return; // Oil pressure low | |
| // 4. Check for blocking error codes | |
| if (g_celSensorFlags & 0x40) // VTEC solenoid error | |
| return; | |
| if (g_celSystemFlags & 0x80) // Oil pressure switch error | |
| return; | |
| // All conditions met - engage VTEC | |
| g_vtecStateFlags |= 0x80; // Set engaged flag | |
| REG_P1 |= P1_VTEC_SOLENOID; // Activate solenoid | |
| g_vtecHysteresis = 0x14; // Set hold timer (20 cycles) | |
| return; | |
| checkVtecDisengage: | |
| // Check disengage RPM threshold (with hysteresis) | |
| uint8_t disengageRpm = vcal_tableLookup1D(g_coolantTempRaw, TBL_VTEC_DISENGAGE_RPM); | |
| if (g_rpmByteNonVtec > disengageRpm) | |
| return; // RPM still above threshold | |
| // Check hysteresis timer | |
| if (g_vtecHysteresis > 0) { | |
| g_vtecHysteresis--; | |
| return; // Still in hold period | |
| } | |
| // Disengage VTEC | |
| g_vtecStateFlags &= ~0x80; // Clear engaged flag | |
| REG_P1 &= ~P1_VTEC_SOLENOID; // Deactivate solenoid | |
| } | |
| /*============================================================================ | |
| * SECTION 11: IDLE CONTROL (IACV) | |
| * | |
| * Idle Air Control Valve management for stable idle. | |
| *============================================================================*/ | |
| /** | |
| * update_idleControl - Update IACV Duty Cycle | |
| * Address: 0x2000-0x2200 | |
| * | |
| * PID-like control of idle air control valve. | |
| * Adjusts airflow to maintain target idle RPM. | |
| */ | |
| void update_idleControl(void) { | |
| // Get target idle RPM from table (ECT based) | |
| uint16_t targetIdle = vcal_tableLookup1D(g_coolantTempRaw, TBL_IDLE_TARGET); | |
| g_targetIdleRpm = targetIdle; | |
| // Calculate RPM error | |
| int16_t rpmError = g_rpmTimerAverage - targetIdle; | |
| g_rpmTargetDiff = (rpmError < 0) ? -rpmError : rpmError; | |
| // Set under/over target flag | |
| if (rpmError < 0) | |
| g_idleFlags |= 0x04; // Under target | |
| else | |
| g_idleFlags &= ~0x04; | |
| // Get base IACV duty from table | |
| uint8_t baseDuty = vcal_tableLookup1D(g_coolantTempRaw, TBL_IDLE_IACV_BASE); | |
| // Apply proportional correction | |
| int8_t correction = 0; | |
| if (g_idleFlags & 0x04) { | |
| // Under target - open valve more | |
| correction = g_rpmTargetDiff / 10; | |
| if (correction > 20) correction = 20; | |
| } else { | |
| // Over target - close valve | |
| correction = -(g_rpmTargetDiff / 10); | |
| if (correction < -20) correction = -20; | |
| } | |
| // Apply AC load compensation | |
| if (g_acFlags & 0x02) { | |
| correction += 15; // Add ~15% for AC | |
| } | |
| // Calculate final duty | |
| int16_t finalDuty = baseDuty + correction; | |
| // Clamp to valid range (0-100) | |
| if (finalDuty < 0) finalDuty = 0; | |
| if (finalDuty > 100) finalDuty = 100; | |
| g_iacvDutyCycle = (uint8_t)finalDuty; | |
| } | |
| /*============================================================================ | |
| * SECTION 12: DIAGNOSTICS AND CEL FUNCTIONS | |
| * | |
| * Check Engine Light control and error code handling. | |
| *============================================================================*/ | |
| /** | |
| * check_diagnostics - Run Diagnostic Checks | |
| * Address: 0x2300-0x2500 | |
| * | |
| * Checks all sensors and systems for fault conditions. | |
| * Sets appropriate error flags and CEL codes. | |
| */ | |
| void check_diagnostics(void) { | |
| // Check MAP sensor (Code 3) | |
| if (g_mapSensorRaw < 0x0010 || g_mapSensorRaw > 0x0FF0) { | |
| g_celSensorFlags |= 0x01; // Code 3 - MAP | |
| } else { | |
| g_celSensorFlags &= ~0x01; | |
| } | |
| // Check ECT sensor (Code 6) | |
| if (g_coolantTempRaw < 0x05 || g_coolantTempRaw > 0xFA) { | |
| g_celSensorFlags |= 0x02; // Code 6 - ECT | |
| } else { | |
| g_celSensorFlags &= ~0x02; | |
| } | |
| // Check TPS sensor (Code 7) | |
| if (g_tpsSensorRaw < 0x05 || g_tpsSensorRaw > 0xFA) { | |
| g_celSensorFlags |= 0x04; // Code 7 - TPS | |
| } else { | |
| g_celSensorFlags &= ~0x04; | |
| } | |
| // Check CKP signal (Code 4) | |
| if (g_engineStateFlags & 0x01) { | |
| g_celCriticalFlags |= 0x01; // Code 4 - CKP | |
| } else { | |
| g_celCriticalFlags &= ~0x01; | |
| } | |
| // Check TDC signal (Code 8) | |
| if (g_tdcStateFlags & 0x02) { | |
| g_celCriticalFlags |= 0x02; // Code 8 - TDC | |
| } else { | |
| g_celCriticalFlags &= ~0x02; | |
| } | |
| // Check IAT sensor (Code 10) | |
| if (g_intakeAirTempRaw < 0x05 || g_intakeAirTempRaw > 0xFA) { | |
| g_celSensorFlags |= 0x80; // Code 10 - IAT | |
| } else { | |
| g_celSensorFlags &= ~0x80; | |
| } | |
| // Check VTEC solenoid (Code 21) | |
| if (g_vtecStateFlags & 0x80) { | |
| // VTEC should be on - check feedback | |
| if (!(g_externalInputs & EXT_VTEC_FEEDBACK)) { | |
| g_celSystemFlags |= 0x40; // Code 21 - VTEC | |
| } | |
| } else { | |
| g_celSystemFlags &= ~0x40; | |
| } | |
| // Check oil pressure (Code 22) | |
| if (g_oilPressureSwitch < 0x20 && g_rpmByteNonVtec > 0x30) { | |
| g_celSystemFlags |= 0x80; // Code 22 - Oil pressure | |
| } else { | |
| g_celSystemFlags &= ~0x80; | |
| } | |
| // Update CEL output | |
| if (g_celSensorFlags || g_celSystemFlags || g_celCriticalFlags) { | |
| REG_P0 |= P0_CEL_DASH; // Turn on CEL | |
| REG_P1 |= P1_CEL_LED; // Turn on LED | |
| } else { | |
| REG_P0 &= ~P0_CEL_DASH; // Turn off CEL | |
| REG_P1 &= ~P1_CEL_LED; // Turn off LED | |
| } | |
| } | |
| /** | |
| * blink_celCode - CEL Blink Pattern Generator | |
| * Address: 0x2500-0x2700 | |
| * | |
| * Generates blink patterns for stored fault codes. | |
| * Long blinks = tens digit, short blinks = ones digit. | |
| */ | |
| void blink_celCode(void) { | |
| // Check for codes to blink | |
| uint8_t codeToShow = 0; | |
| // Scan fault bytes for set bits | |
| if (g_faultCode1) { | |
| for (int i = 0; i < 8; i++) { | |
| if (g_faultCode1 & (1 << i)) { | |
| codeToShow = i + 1; // Codes 1-8 | |
| break; | |
| } | |
| } | |
| } else if (g_faultCode2) { | |
| for (int i = 0; i < 8; i++) { | |
| if (g_faultCode2 & (1 << i)) { | |
| codeToShow = i + 9; // Codes 9-16 | |
| break; | |
| } | |
| } | |
| } else if (g_faultCode3) { | |
| for (int i = 0; i < 8; i++) { | |
| if (g_faultCode3 & (1 << i)) { | |
| codeToShow = i + 17; // Codes 17-24 | |
| break; | |
| } | |
| } | |
| } | |
| if (codeToShow == 0) { | |
| // No codes - steady LED | |
| REG_P1 |= P1_CEL_LED; | |
| return; | |
| } | |
| // Calculate blink pattern | |
| uint8_t longBlinks = codeToShow / 10; // Tens digit | |
| uint8_t shortBlinks = codeToShow % 10; // Ones digit | |
| g_celBlinkPattern = (longBlinks << 4) | shortBlinks; | |
| // State machine for blinking | |
| switch (g_celBlinkState) { | |
| case 0: // Start of pattern | |
| g_celBlinkCounter = longBlinks; | |
| g_celBlinkState = 1; | |
| break; | |
| case 1: // Long blinks | |
| if (g_celBlinkCounter > 0) { | |
| // Long blink on | |
| REG_P1 |= P1_CEL_LED; | |
| g_celCodeCounter = 30; // 300ms on | |
| g_celBlinkState = 2; | |
| } else { | |
| // Done with long blinks | |
| g_celBlinkCounter = shortBlinks; | |
| g_celBlinkState = 3; | |
| } | |
| break; | |
| case 2: // Long blink off | |
| if (g_celCodeCounter == 0) { | |
| REG_P1 &= ~P1_CEL_LED; | |
| g_celCodeCounter = 10; // 100ms off | |
| g_celBlinkCounter--; | |
| g_celBlinkState = 1; | |
| } | |
| break; | |
| case 3: // Short blinks | |
| if (g_celBlinkCounter > 0) { | |
| REG_P1 |= P1_CEL_LED; | |
| g_celCodeCounter = 10; // 100ms on | |
| g_celBlinkState = 4; | |
| } else { | |
| // Pattern complete - pause | |
| g_celCodeCounter = 100; // 1s pause | |
| g_celBlinkState = 5; | |
| } | |
| break; | |
| case 4: // Short blink off | |
| if (g_celCodeCounter == 0) { | |
| REG_P1 &= ~P1_CEL_LED; | |
| g_celCodeCounter = 10; | |
| g_celBlinkCounter--; | |
| g_celBlinkState = 3; | |
| } | |
| break; | |
| case 5: // Pause between codes | |
| if (g_celCodeCounter == 0) { | |
| g_celBlinkState = 0; // Restart pattern | |
| } | |
| break; | |
| } | |
| } | |
| /*============================================================================ | |
| * SECTION 13: MAIN LOOP | |
| *============================================================================*/ | |
| /** | |
| * main - Main Program Entry | |
| * | |
| * After initialization, enters main loop that processes | |
| * engine events and updates outputs. | |
| */ | |
| void main(void) { | |
| // System initialization | |
| system_init(); | |
| // Main loop - runs forever | |
| while (1) { | |
| // Feed watchdog | |
| REG_WDT = 0x3C; | |
| // Check for pending processing flags | |
| if (!(g_processingFlags & 0x02)) { | |
| // Idle - wait for next engine event | |
| continue; | |
| } | |
| g_processingFlags &= ~0x02; | |
| // Process sensors | |
| process_mapSensor(); | |
| process_tpsSensor(); | |
| process_o2Sensor(); | |
| process_rpmCalculation(); | |
| // Calculate fuel and timing | |
| calc_fuelPulseWidth(); | |
| calc_ignitionTiming(); | |
| // Check VTEC conditions | |
| check_vtecEngagement(); | |
| // Check rev limiter | |
| if (g_rpmByteNonVtec >= 0xF0) { | |
| // Near rev limit - cut fuel | |
| g_processingFlags |= 0x80; | |
| } | |
| // Update idle control (if at idle) | |
| if (g_idleFlags & 0x01) | |
| update_idleControl(); | |
| // Diagnostic checks (every 16 loops) | |
| if ((g_mainLoopCounter & 0x0F) == 0) | |
| check_diagnostics(); | |
| g_mainLoopCounter++; | |
| } | |
| } | |
| /** | |
| * system_init - System Initialization | |
| * | |
| * Configures all peripherals and initializes RAM. | |
| */ | |
| void system_init(void) { | |
| // Disable interrupts during init | |
| REG_IE = 0; | |
| // Initialize ports | |
| REG_P0 = 0x00; | |
| REG_P0IO = 0xC8; // CEL, AC, Purge as outputs | |
| REG_P1 = 0x00; | |
| REG_P1IO = 0x07; // VTEC, LEDs as outputs | |
| REG_P2 = 0x0F; // Injectors off (high = off) | |
| REG_P2IO = 0x0F; // Injector outputs | |
| REG_P4 = 0x00; | |
| REG_P4IO = 0x09; // IACV output | |
| // Initialize timers | |
| REG_TCON0 = 0x00; | |
| REG_TCON1 = 0x00; | |
| REG_TCON2 = 0x00; | |
| REG_TCON3 = 0x00; | |
| // Initialize ADC | |
| REG_ADSCAN = 0x00; | |
| REG_ADSEL = 0x00; | |
| // Initialize serial | |
| REG_SRCON = 0x00; | |
| REG_STCON = 0x00; | |
| // Clear RAM | |
| for (uint16_t addr = 0x0098; addr < 0x0400; addr++) | |
| *(uint8_t*)addr = 0; | |
| // Set initial values | |
| g_lifeCounter = 0x20; // Life counter | |
| g_rpmTimerAverage = 0xFFFF; // No RPM yet | |
| g_fuelO2TrimPrimary = 0x0100; // Neutral O2 trim | |
| g_fuelO2TrimSecondary = 0x0100; | |
| // Enable interrupts | |
| REG_IE = 0x00A0; // Enable key interrupts | |
| } | |
| /*============================================================================ | |
| * SECTION 14: DATA TABLES (REFERENCE) | |
| * | |
| * Calibration data tables stored in ROM. | |
| * These are referenced but not reproduced in full. | |
| *============================================================================*/ | |
| // Table: tbl_6000 - Configuration flags (16 bytes) | |
| // Address: 0x6000-0x600F | |
| // Format: Single bytes indicating feature enables | |
| // Table: tbl_601C - Sensor scaling (6 bytes) | |
| // Address: 0x601C-0x6021 | |
| // Format: Scaling factors for ADC readings | |
| // Table: tbl_6022 - TPS breakpoints (4 bytes) | |
| // Address: 0x6022-0x6025 | |
| // Table: tbl_6026 - Accel enrichment rates (6 bytes) | |
| // Address: 0x6026-0x602B | |
| // Table: tbl_602C - Decel enleanment (8 bytes) | |
| // Address: 0x602C-0x6033 | |
| // Table: tbl_6034 - ECT fuel trim curve (14 bytes) | |
| // Address: 0x6034-0x6041 | |
| // Format: (threshold, value) pairs | |
| // Table: tbl_6042 - IAT fuel trim curve (14 bytes) | |
| // Address: 0x6042-0x604F | |
| // Table: tbl_6050 - Barometric fuel trim (14 bytes) | |
| // Address: 0x6050-0x605D | |
| // Table: tbl_605E - O2 closed loop params (14 bytes) | |
| // Address: 0x605E-0x606B | |
| // Table: tbl_606C - Warmup enrichment (14 bytes) | |
| // Address: 0x606C-0x6079 | |
| // Table: tbl_607A - Acceleration enrichment (21 bytes) | |
| // Address: 0x607A-0x608E | |
| // Table: tbl_60A7 - Voltage compensation (21 bytes) | |
| // Address: 0x60A7-0x60BB | |
| // Table: tbl_60C8 - RPM axis non-VTEC (4 bytes) | |
| // Address: 0x60C8-0x60CB | |
| // Table: tbl_60CC - RPM axis VTEC (4 bytes) | |
| // Address: 0x60CC-0x60CF | |
| // Table: tbl_60D0 - MAP axis (2 bytes) | |
| // Address: 0x60D0-0x60D1 | |
| // Table: tbl_6122 - Idle target RPM by ECT (16 bytes) | |
| // Address: 0x6122-0x6131 | |
| // Table: tbl_6132 - IACV base duty (4 bytes) | |
| // Address: 0x6132-0x6135 | |
| // Table: tbl_6136 - Idle speed additional (16 bytes) | |
| // Address: 0x6136-0x6145 | |
| // Table: tbl_6146 - VTEC engage RPM (12 bytes) | |
| // Address: 0x6146-0x6151 | |
| // Table: tbl_6152 - VTEC disengage RPM (12 bytes) | |
| // Address: 0x6152-0x615D | |
| // Table: tbl_615E - VTEC min speed (12 bytes) | |
| // Address: 0x615E-0x6169 | |
| // Table: tbl_616A - Rev limiter (12 bytes) | |
| // Address: 0x616A-0x6175 | |
| // Table: tbl_6176 - Launch control (12 bytes) | |
| // Address: 0x6176-0x6181 | |
| // Table: tbl_6182 - Knock retard (14 bytes) | |
| // Address: 0x6182-0x618F | |
| // Table: tbl_6190 - Injector dead time (14 bytes) | |
| // Address: 0x6190-0x619D | |
| // Table: tbl_619E - Dwell time (14 bytes) | |
| // Address: 0x619E-0x61AB | |
| // Table: tbl_61AC - Timing connector trim (14 bytes) | |
| // Address: 0x61AC-0x61B9 | |
| // Table: tbl_6CD2 - CEL code map (24 bytes) | |
| // Address: 0x6CD2-0x6CE9 | |
| // Maps error bits to CEL code numbers | |
| // Table: tbl_6CEA - CEL timing (12 bytes) | |
| // Address: 0x6CEA-0x6CF5 | |
| // Timing parameters for CEL blink patterns | |
| // Main Fuel Map (Non-VTEC): 0x6800-0x68FF | |
| // 10 RPM rows x 20 MAP columns = 200 words (400 bytes) | |
| // Main Fuel Map (VTEC): 0x6900-0x69FF | |
| // 10 RPM rows x 20 MAP columns = 200 words (400 bytes) | |
| // Ignition Map (Non-VTEC): 0x6A80-0x6AFF | |
| // 10 RPM rows x 20 MAP columns = 200 bytes | |
| // Ignition Map (VTEC): 0x6B00-0x6B7F | |
| // 10 RPM rows x 20 MAP columns = 200 bytes | |
| // Serial Address Table: 0x6B56-0x6BFF | |
| // Addresses for serial read commands | |
| // Diagnostic Parameters: 0x6D08-0x6D1F | |
| // RPM breakpoints for diagnostic calculations | |
| /*============================================================================ | |
| * END OF PSEUDO-C CONVERSION | |
| * | |
| * This document represents the Honda P30 OBD1 ECU firmware converted | |
| * to readable pseudo-C format. The target processor is OKI M66207. | |
| * | |
| * Key differences from OBD0 (M66201/M37700): | |
| * - Different timer architecture | |
| * - Different interrupt vector layout | |
| * - Different register addresses | |
| * - VTEC logic included by default | |
| * - Different serial protocol for diagnostics | |
| * | |
| * Original assembly: P30_203.asm (15,304 lines, 2,394 labels) | |
| * | |
| *============================================================================*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment