From 86683afca22ed1a8af8fd5ac9231442e2124646e Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Fri, 9 Jul 2021 05:37:46 -0700 Subject: [PATCH] trailing spark scheduling (#2932) * enable bit * implement trailing sparks * test trailing spark * it helps to call the correct function * add pins * gobblin ram --- firmware/controllers/algo/engine2.cpp | 4 ++ firmware/controllers/algo/engine_state.h | 4 ++ firmware/controllers/algo/event_registry.h | 3 + firmware/controllers/engine_controller.cpp | 2 +- .../controllers/engine_cycle/spark_logic.cpp | 33 ++++++++-- firmware/controllers/system/efi_gpio.h | 1 + firmware/integration/rusefi_config.txt | 2 +- .../test_ignition_scheduling.cpp | 62 ++++++++++++++++++- 8 files changed, 102 insertions(+), 9 deletions(-) diff --git a/firmware/controllers/algo/engine2.cpp b/firmware/controllers/algo/engine2.cpp index 70786585fd..dc4e065659 100644 --- a/firmware/controllers/algo/engine2.cpp +++ b/firmware/controllers/algo/engine2.cpp @@ -171,6 +171,10 @@ void EngineState::periodicFastCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) { float ignitionLoad = getIgnitionLoad(PASS_ENGINE_PARAMETER_SIGNATURE); timingAdvance = getAdvance(rpm, ignitionLoad PASS_ENGINE_PARAMETER_SUFFIX); + + // TODO: calculate me from a table! + trailingSparkAngle = 10; + multispark.count = getMultiSparkCount(rpm PASS_ENGINE_PARAMETER_SUFFIX); #if EFI_LAUNCH_CONTROL diff --git a/firmware/controllers/algo/engine_state.h b/firmware/controllers/algo/engine_state.h index ff6ec5e5e0..1fccb868c0 100644 --- a/firmware/controllers/algo/engine_state.h +++ b/firmware/controllers/algo/engine_state.h @@ -47,6 +47,10 @@ 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 between firing the main (primary) spark and the secondary (trailing) spark + angle_t trailingSparkAngle = 0; + // fuel-related; float fuelCutoffCorrection = 0; efitick_t coastingFuelCutStartTime = 0; diff --git a/firmware/controllers/algo/event_registry.h b/firmware/controllers/algo/event_registry.h index aa84175ee7..3b312fa303 100644 --- a/firmware/controllers/algo/event_registry.h +++ b/firmware/controllers/algo/event_registry.h @@ -99,6 +99,9 @@ public: scheduling_s dwellStartTimer; AngleBasedEvent sparkEvent; + scheduling_s trailingSparkCharge; + scheduling_s trailingSparkFire; + // How many additional sparks should we fire after the first one? // For single sparks, this should be zero. uint8_t sparksRemaining = 0; diff --git a/firmware/controllers/engine_controller.cpp b/firmware/controllers/engine_controller.cpp index 77e6605ce0..f3b78cf032 100644 --- a/firmware/controllers/engine_controller.cpp +++ b/firmware/controllers/engine_controller.cpp @@ -698,7 +698,7 @@ void initEngineContoller(DECLARE_ENGINE_PARAMETER_SUFFIX) { * UNUSED_SIZE constants. */ #ifndef RAM_UNUSED_SIZE -#define RAM_UNUSED_SIZE 1400 +#define RAM_UNUSED_SIZE 1000 #endif #ifndef CCM_UNUSED_SIZE #define CCM_UNUSED_SIZE 300 diff --git a/firmware/controllers/engine_cycle/spark_logic.cpp b/firmware/controllers/engine_cycle/spark_logic.cpp index b44b2dc70f..a6cb2011aa 100644 --- a/firmware/controllers/engine_cycle/spark_logic.cpp +++ b/firmware/controllers/engine_cycle/spark_logic.cpp @@ -128,6 +128,14 @@ static void prepareCylinderIgnitionSchedule(angle_t dwellAngleDuration, floatms_ #endif /* FUEL_MATH_EXTREME_LOGGING */ } +static void chargeTrailingSpark(IgnitionOutputPin* pin) { + pin->setValue(1); +} + +static void fireTrailingSpark(IgnitionOutputPin* pin) { + pin->setValue(0); +} + void fireSparkAndPrepareNextSchedule(IgnitionEvent *event) { for (int i = 0; i< MAX_OUTPUTS_FOR_IGNITION;i++) { IgnitionOutputPin *output = event->outputs[i]; @@ -186,8 +194,7 @@ if (engineConfiguration->debugMode == DBG_DWELL_METRIC) { } // If there are more sparks to fire, schedule them - if (event->sparksRemaining > 0) - { + if (event->sparksRemaining > 0) { event->sparksRemaining--; efitick_t nextDwellStart = nowNt + engine->engineState.multispark.delay; @@ -196,9 +203,16 @@ if (engineConfiguration->debugMode == DBG_DWELL_METRIC) { // We can schedule both of these right away, since we're going for "asap" not "particular angle" engine->executor.scheduleByTimestampNt(&event->dwellStartTimer, nextDwellStart, { &turnSparkPinHigh, event }); engine->executor.scheduleByTimestampNt(&event->sparkEvent.scheduling, nextFiring, { fireSparkAndPrepareNextSchedule, event }); - } - else - { + } else { + if (CONFIG(enableTrailingSparks)) { + // Trailing sparks are enabled - schedule an event for the corresponding trailing coil + scheduleByAngle( + &event->trailingSparkFire, nowNt, ENGINE(engineState.trailingSparkAngle), + { &fireTrailingSpark, &enginePins.trailingCoils[event->cylinderNumber] } + PASS_ENGINE_PARAMETER_SUFFIX + ); + } + // If all events have been scheduled, prepare for next time. prepareCylinderIgnitionSchedule(dwellAngleDuration, sparkDwell, event PASS_ENGINE_PARAMETER_SUFFIX); } @@ -269,6 +283,15 @@ void turnSparkPinHigh(IgnitionEvent *event) { startDwellByTurningSparkPinHigh(event, output); } } + + if (CONFIG(enableTrailingSparks)) { + // Trailing sparks are enabled - schedule an event for the corresponding trailing coil + scheduleByAngle( + &event->trailingSparkCharge, nowNt, ENGINE(engineState.trailingSparkAngle), + { &chargeTrailingSpark, &enginePins.trailingCoils[event->cylinderNumber] } + PASS_ENGINE_PARAMETER_SUFFIX + ); + } } static bool assertNotInIgnitionList(AngleBasedEvent *head, AngleBasedEvent *element) { diff --git a/firmware/controllers/system/efi_gpio.h b/firmware/controllers/system/efi_gpio.h index 1cd49bc298..26630702b8 100644 --- a/firmware/controllers/system/efi_gpio.h +++ b/firmware/controllers/system/efi_gpio.h @@ -209,6 +209,7 @@ public: InjectorOutputPin injectors[MAX_CYLINDER_COUNT]; IgnitionOutputPin coils[MAX_CYLINDER_COUNT]; + IgnitionOutputPin trailingCoils[MAX_CYLINDER_COUNT]; NamedOutputPin auxValve[AUX_DIGITAL_VALVE_COUNT]; OutputPin tcuSolenoids[TCU_SOLENOID_COUNT]; diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index ff00088f6a..2dbc4ffdff 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -541,7 +541,7 @@ bit enableFan1WithAc;+Turn on this fan when AC is on. bit enableFan2WithAc;+Turn on this fan when AC is on. bit disableFan1WhenStopped;+Inhibit operation of this fan while the engine is not running. bit disableFan2WhenStopped;+Inhibit operation of this fan while the engine is not running. -bit unused_294_8 +bit enableTrailingSparks;+Enable secondary spark outputs that fire after the primary (rotaries, twin plug engines). bit isCJ125Verbose;enable cj125verbose/disable cj125verbose bit cj125isUaDivided;+Is your UA CJ125 output wired to MCU via resistor divider? Ua can go over 3.3v but only at lambda >3, i.e very lean AFR above 44.1\nWhen exposed to free air and 17x gain, Ua will be 4.17 volt bit cj125isLsu49 diff --git a/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp b/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp index 151afb186f..e896052ad3 100644 --- a/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp +++ b/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp @@ -8,6 +8,8 @@ #include "engine_test_helper.h" #include "spark_logic.h" +using ::testing::_; + TEST(ignition, twoCoils) { WITH_ENGINE_TEST_HELPER(BMW_M73_F); @@ -33,9 +35,65 @@ TEST(ignition, twoCoils) { ASSERT_EQ(engine->ignitionEvents.elements[3].sparkAngle, 3 * 720 / 12); ASSERT_EQ((void*)engine->ignitionEvents.elements[3].outputs[0], (void*)&enginePins.coils[6]); - - } +TEST(ignition, trailingSpark) { + WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + EXPECT_CALL(eth.mockAirmass, getAirmass(_)) + .WillRepeatedly(Return(AirmassResult{0.1008f, 50.0f})); + setupSimpleTestEngineWithMafAndTT_ONE_trigger(ð); + CONFIG(specs.cylindersCount) = 1; + CONFIG(specs.firingOrder) = FO_1; + CONFIG(isInjectionEnabled) = false; + CONFIG(isIgnitionEnabled) = true; + + // Fire trailing spark 10 degrees after main spark + ENGINE(engineState.trailingSparkAngle) = 10; + + engineConfiguration->injectionMode = IM_SEQUENTIAL; + + eth.fireTriggerEventsWithDuration(20); + // still no RPM since need to cycles measure cycle duration + eth.fireTriggerEventsWithDuration(20); + eth.clearQueue(); + + /** + * Trigger up - scheduling fuel for full engine cycle + */ + eth.fireRise(20); + + // Primary coil should be high + EXPECT_EQ(enginePins.coils[0].getLogicValue(), true); + EXPECT_EQ(enginePins.trailingCoils[0].getLogicValue(), false); + + // Should be a TDC callback + spark firing + EXPECT_EQ(engine->executor.size(), 2); + + // execute all actions + eth.clearQueue(); + + // Primary and secondary coils should be low - primary just fired + EXPECT_EQ(enginePins.coils[0].getLogicValue(), false); + EXPECT_EQ(enginePins.trailingCoils[0].getLogicValue(), false); + + // Now enable trailing sparks + CONFIG(enableTrailingSparks) = true; + + // Fire trigger fall - should schedule ignition chargings (rising edges) + eth.fireFall(20); + eth.clearQueue(); + + // Primary and secondary coils should be low + EXPECT_EQ(enginePins.coils[0].getLogicValue(), true); + EXPECT_EQ(enginePins.trailingCoils[0].getLogicValue(), true); + + // Fire trigger rise - should schedule ignition firings + eth.fireRise(20); + eth.clearQueue(); + + // Primary and secondary coils should be low + EXPECT_EQ(enginePins.coils[0].getLogicValue(), false); + EXPECT_EQ(enginePins.trailingCoils[0].getLogicValue(), false); +}