diff --git a/firmware/console/status_loop.cpp b/firmware/console/status_loop.cpp index ac8969bb23..5d8c058024 100644 --- a/firmware/console/status_loop.cpp +++ b/firmware/console/status_loop.cpp @@ -624,7 +624,7 @@ static void updateFuelInfo() { } static void updateIgnition(int rpm) { - float timing = engine->engineState.timingAdvance; + float timing = engine->engineState.timingAdvance[0]; // that's weird logic. also seems broken for two stroke? tsOutputChannels.ignitionAdvance = timing > FOUR_STROKE_CYCLE_DURATION / 2 ? timing - FOUR_STROKE_CYCLE_DURATION : timing; // 60 diff --git a/firmware/controllers/algo/engine2.cpp b/firmware/controllers/algo/engine2.cpp index 8cd46b84f6..04f7120edb 100644 --- a/firmware/controllers/algo/engine2.cpp +++ b/firmware/controllers/algo/engine2.cpp @@ -165,7 +165,11 @@ void EngineState::periodicFastCallback() { injectionOffset = getInjectionOffset(rpm, fuelLoad); float ignitionLoad = getIgnitionLoad(); - timingAdvance = getAdvance(rpm, ignitionLoad) * luaAdjustments.ignitionTimingMult + luaAdjustments.ignitionTimingAdd; + float advance = getAdvance(rpm, ignitionLoad) * luaAdjustments.ignitionTimingMult + luaAdjustments.ignitionTimingAdd; + + for (size_t i = 0; i < engineConfiguration->specs.cylindersCount; i++) { + timingAdvance[i] = advance; + } // TODO: calculate me from a table! trailingSparkAngle = engineConfiguration->trailingSparkAngle; diff --git a/firmware/controllers/algo/engine_state.h b/firmware/controllers/algo/engine_state.h index d2f6a02f19..52413b5040 100644 --- a/firmware/controllers/algo/engine_state.h +++ b/firmware/controllers/algo/engine_state.h @@ -54,7 +54,7 @@ public: /** * timing advance is angle distance before Top Dead Center (TDP), i.e. "10 degree timing advance" means "happens 10 degrees before TDC" */ - angle_t timingAdvance = 0; + angle_t timingAdvance[MAX_CYLINDER_COUNT] = {0}; // Angle between firing the main (primary) spark and the secondary (trailing) spark angle_t trailingSparkAngle = 0; diff --git a/firmware/controllers/can/can_dash.cpp b/firmware/controllers/can/can_dash.cpp index 1d47ceca2e..a5afb0e6ba 100644 --- a/firmware/controllers/can/can_dash.cpp +++ b/firmware/controllers/can/can_dash.cpp @@ -600,7 +600,7 @@ void canDashboardHaltech(CanCycle cycle) { msg[2] = 0x00; msg[3] = 0x00; /* Ignition Angle (Leading) - y = x/10 */ - float timing = engine->engineState.timingAdvance; + float timing = engine->engineState.timingAdvance[0]; int16_t ignAngle = ((timing > 360 ? timing - 720 : timing) * 10); msg[4] = (ignAngle >> 8); msg[5] = (ignAngle & 0x00ff); diff --git a/firmware/controllers/can/can_verbose.cpp b/firmware/controllers/can/can_verbose.cpp index 722b5fa770..0a86c9fdf4 100644 --- a/firmware/controllers/can/can_verbose.cpp +++ b/firmware/controllers/can/can_verbose.cpp @@ -56,7 +56,7 @@ static void populateFrame(Speeds& msg) { auto rpm = GET_RPM(); msg.rpm = rpm; - auto timing = engine->engineState.timingAdvance; + auto timing = engine->engineState.timingAdvance[0]; msg.timing = timing > 360 ? timing - 720 : timing; msg.injDuty = getInjectorDutyCycle(rpm); diff --git a/firmware/controllers/can/obd2.cpp b/firmware/controllers/can/obd2.cpp index 0ad9c63210..67644244e6 100644 --- a/firmware/controllers/can/obd2.cpp +++ b/firmware/controllers/can/obd2.cpp @@ -138,7 +138,7 @@ static void handleGetDataRequest(const CANRxFrame& rx) { obdSendValue(_1_MODE, pid, 1, Sensor::getOrZero(SensorType::VehicleSpeed)); break; case PID_TIMING_ADVANCE: { - float timing = engine->engineState.timingAdvance; + float timing = engine->engineState.timingAdvance[0]; timing = (timing > 360.0f) ? (timing - 720.0f) : timing; obdSendValue(_1_MODE, pid, 1, (timing + 64.0f) * 2.0f); // angle before TDC. (A/2)-64 break; diff --git a/firmware/controllers/engine_cycle/knock_logic.cpp b/firmware/controllers/engine_cycle/knock_logic.cpp index bd92290a17..50ef6da21e 100644 --- a/firmware/controllers/engine_cycle/knock_logic.cpp +++ b/firmware/controllers/engine_cycle/knock_logic.cpp @@ -11,9 +11,9 @@ #include "hip9011.h" -int getCylinderKnockBank(uint8_t cylinderIndex) { +int getCylinderKnockBank(uint8_t cylinderNumber) { // C/C++ can't index in to bit fields, we have to provide lookup ourselves - switch (cylinderIndex) { + switch (cylinderNumber) { #if EFI_PROD_CODE case 0: return engineConfiguration->knockBankCyl1; @@ -45,13 +45,13 @@ int getCylinderKnockBank(uint8_t cylinderIndex) { } } -bool KnockController::onKnockSenseCompleted(uint8_t cylinderIndex, float dbv, efitick_t lastKnockTime) { +bool KnockController::onKnockSenseCompleted(uint8_t cylinderNumber, float dbv, efitick_t lastKnockTime) { bool isKnock = dbv > engine->engineState.knockThreshold; #if EFI_TUNER_STUDIO // Pass through per-cylinder peak detector - float cylPeak = peakDetectors[cylinderIndex].detect(dbv, lastKnockTime); - tsOutputChannels.knock[cylinderIndex] = roundf(cylPeak); + float cylPeak = peakDetectors[cylinderNumber].detect(dbv, lastKnockTime); + tsOutputChannels.knock[cylinderNumber] = roundf(cylPeak); // Pass through all-cylinders peak detector tsOutputChannels.knockLevel = allCylinderPeakDetector.detect(dbv, lastKnockTime); @@ -64,7 +64,7 @@ bool KnockController::onKnockSenseCompleted(uint8_t cylinderIndex, float dbv, ef // TODO: retard timing, then put it back! if (isKnock) { - auto baseTiming = engine->engineState.timingAdvance; + auto baseTiming = engine->engineState.timingAdvance[cylinderNumber]; // TODO: 20 configurable? Better explanation why 20? auto distToMinimum = baseTiming - (-20); @@ -107,13 +107,13 @@ void KnockController::periodicFastCallback() { } // This callback is to be implemented by the knock sense driver -__attribute__((weak)) void onStartKnockSampling(uint8_t cylinderIndex, float samplingTimeSeconds, uint8_t channelIdx) { - UNUSED(cylinderIndex); +__attribute__((weak)) void onStartKnockSampling(uint8_t cylinderNumber, float samplingTimeSeconds, uint8_t channelIdx) { + UNUSED(cylinderNumber); UNUSED(samplingTimeSeconds); UNUSED(channelIdx); } -static uint8_t cylinderIndexCopy; +static uint8_t cylinderNumberCopy; // Called when its time to start listening for knock // Does some math, then hands off to the driver to start any sampling hardware @@ -126,16 +126,16 @@ static void startKnockSampling(Engine* engine) { float samplingSeconds = engine->rpmCalculator.oneDegreeUs * engineConfiguration->knockSamplingDuration / US_PER_SECOND_F; // Look up which channel this cylinder uses - auto channel = getCylinderKnockBank(cylinderIndexCopy); + auto channel = getCylinderKnockBank(cylinderNumberCopy); // Call the driver to begin sampling - onStartKnockSampling(cylinderIndexCopy, samplingSeconds, channel); + onStartKnockSampling(cylinderNumberCopy, samplingSeconds, channel); } static scheduling_s startSampling; -void Engine::onSparkFireKnockSense(uint8_t cylinderIndex, efitick_t nowNt) { - cylinderIndexCopy = cylinderIndex; +void Engine::onSparkFireKnockSense(uint8_t cylinderNumber, efitick_t nowNt) { + cylinderNumberCopy = cylinderNumber; #if EFI_HIP_9011 || EFI_SOFTWARE_KNOCK scheduleByAngle(&startSampling, nowNt, @@ -143,6 +143,6 @@ void Engine::onSparkFireKnockSense(uint8_t cylinderIndex, efitick_t nowNt) { #endif #if EFI_HIP_9011 - hip9011_onFireEvent(cylinderIndex, nowNt); + hip9011_onFireEvent(cylinderNumber, nowNt); #endif } diff --git a/firmware/controllers/engine_cycle/knock_logic.h b/firmware/controllers/engine_cycle/knock_logic.h index 20562e8e64..8fbec2089f 100644 --- a/firmware/controllers/engine_cycle/knock_logic.h +++ b/firmware/controllers/engine_cycle/knock_logic.h @@ -9,12 +9,12 @@ #include "peak_detect.h" -int getCylinderKnockBank(uint8_t cylinderIndex); +int getCylinderKnockBank(uint8_t cylinderNumber); class KnockController { public: // onKnockSenseCompleted is the callback from the knock sense driver to report a sensed knock level - bool onKnockSenseCompleted(uint8_t cylinderIndex, float dbv, efitick_t lastKnockTime); + bool onKnockSenseCompleted(uint8_t cylinderNumber, float dbv, efitick_t lastKnockTime); void periodicFastCallback(); float getKnockRetard() const; diff --git a/firmware/controllers/engine_cycle/main_trigger_callback.cpp b/firmware/controllers/engine_cycle/main_trigger_callback.cpp index d9f3b7d99b..addef0fb10 100644 --- a/firmware/controllers/engine_cycle/main_trigger_callback.cpp +++ b/firmware/controllers/engine_cycle/main_trigger_callback.cpp @@ -503,7 +503,7 @@ static void showMainInfo(Engine *engine) { int rpm = GET_RPM(); float el = getFuelingLoad(); efiPrintf("rpm %d engine_load %.2f", rpm, el); - efiPrintf("fuel %.2fms timing %.2f", engine->injectionDuration, engine->engineState.timingAdvance); + efiPrintf("fuel %.2fms timing %.2f", engine->injectionDuration, engine->engineState.timingAdvance[0]); #endif /* EFI_PROD_CODE */ } diff --git a/firmware/controllers/engine_cycle/spark_logic.cpp b/firmware/controllers/engine_cycle/spark_logic.cpp index c153c8bcea..891cbbb28c 100644 --- a/firmware/controllers/engine_cycle/spark_logic.cpp +++ b/firmware/controllers/engine_cycle/spark_logic.cpp @@ -75,7 +75,7 @@ static void prepareCylinderIgnitionSchedule(angle_t dwellAngleDuration, floatms_ const angle_t sparkAngle = // Negate because timing *before* TDC, and we schedule *after* TDC - - engine->engineState.timingAdvance + - engine->engineState.timingAdvance[event->cylinderNumber] // Offset by this cylinder's position in the cycle + getCylinderAngle(event->cylinderIndex, event->cylinderNumber) // Pull any extra timing for knock retard @@ -373,7 +373,7 @@ void initializeIgnitionActions() { IgnitionEventList *list = &engine->ignitionEvents; angle_t dwellAngle = engine->engineState.dwellAngle; floatms_t sparkDwell = engine->engineState.sparkDwell; - if (cisnan(engine->engineState.timingAdvance) || cisnan(dwellAngle)) { + if (cisnan(engine->engineState.timingAdvance[0]) || cisnan(dwellAngle)) { // error should already be reported // need to invalidate previous ignition schedule list->isReady = false; diff --git a/firmware/controllers/sensors/software_knock.cpp b/firmware/controllers/sensors/software_knock.cpp index c3f472492b..6fcf7e8887 100644 --- a/firmware/controllers/sensors/software_knock.cpp +++ b/firmware/controllers/sensors/software_knock.cpp @@ -11,7 +11,7 @@ #include "ch.hpp" static NO_CACHE adcsample_t sampleBuffer[2000]; -static int8_t currentCylinderIndex = 0; +static int8_t currentCylinderNumber = 0; static efitick_t lastKnockSampleTime = 0; static Biquad knockFilter; @@ -104,7 +104,7 @@ const ADCConversionGroup* getConversionGroup(uint8_t channelIdx) { return &adcConvGroupCh1; } -void onStartKnockSampling(uint8_t cylinderIndex, float samplingSeconds, uint8_t channelIdx) { +void onStartKnockSampling(uint8_t cylinderNumber, float samplingSeconds, uint8_t channelIdx) { if (!engineConfiguration->enableSoftwareKnock) { return; } @@ -128,8 +128,8 @@ void onStartKnockSampling(uint8_t cylinderIndex, float samplingSeconds, uint8_t // Select the appropriate conversion group - it will differ depending on which sensor this cylinder should listen on auto conversionGroup = getConversionGroup(channelIdx); - // Stash the current cylinder's index so we can store the result appropriately - currentCylinderIndex = cylinderIndex; + // Stash the current cylinder's number so we can store the result appropriately + currentCylinderNumber = cylinderNumber; adcStartConversionI(&KNOCK_ADC, conversionGroup, sampleBuffer, sampleCount); lastKnockSampleTime = getTimeNowNt(); @@ -201,7 +201,7 @@ void processLastKnockEvent() { // clamp to reasonable range db = clampF(-100, db, 100); - engine->knockController.onKnockSenseCompleted(currentCylinderIndex, db, lastKnockTime); + engine->knockController.onKnockSenseCompleted(currentCylinderNumber, db, lastKnockTime); } void KnockThread::ThreadTask() { diff --git a/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp b/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp index de8380c38e..cbd1cdc82b 100644 --- a/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp +++ b/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp @@ -23,7 +23,7 @@ TEST(ignition, twoCoils) { ASSERT_EQ(engine->ignitionPin[ID2INDEX(12)], 1); // let's recalculate with zero timing so that we can focus on relation advance between cylinders - engine->engineState.timingAdvance = 0; + setArrayValues(engine->engineState.timingAdvance, 0.0f); initializeIgnitionActions(); ASSERT_EQ(engine->ignitionEvents.elements[0].sparkAngle, 0); diff --git a/unit_tests/tests/trigger/test_trigger_decoder.cpp b/unit_tests/tests/trigger/test_trigger_decoder.cpp index 7c9a3dbb88..3ef0d90b29 100644 --- a/unit_tests/tests/trigger/test_trigger_decoder.cpp +++ b/unit_tests/tests/trigger/test_trigger_decoder.cpp @@ -345,7 +345,7 @@ TEST(misc, testRpmCalculator) { eth.engine.periodicFastCallback(); - ASSERT_NEAR(engine->engineState.timingAdvance, 707, 0.1f); + ASSERT_NEAR(engine->engineState.timingAdvance[0], 707, 0.1f); assertEqualsM("fuel #1", 4.5450, engine->injectionDuration); InjectionEvent *ie0 = &engine->injectionEvents.elements[0];