From 0a550a70b1bf9d2d1bbc6d4908fe8edee19d5777 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Fri, 1 Oct 2021 22:10:24 -0700 Subject: [PATCH] overdwell protection (#3220) * cancel event * looks like it works... * some tests are happy * add enable bit * undo test changes * Revert "add enable bit" This reverts commit 000afadd3fc560867302557afe26f76cd9fc4ed6. * enable bit in engine * only turn off for one test * Revert "undo test changes" This reverts commit 106db49e291b5a531a94de6ac177c6584d5337f6. --- firmware/controllers/algo/engine.h | 1 + .../controllers/engine_cycle/spark_logic.cpp | 16 ++++++++++++---- .../test_ignition_scheduling.cpp | 3 +++ .../trigger/test_real_cranking_nissan_vq40.cpp | 5 +++-- .../tests/trigger/test_trigger_decoder.cpp | 2 +- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/firmware/controllers/algo/engine.h b/firmware/controllers/algo/engine.h index e5d7d5c34a..73ff7026fb 100644 --- a/firmware/controllers/algo/engine.h +++ b/firmware/controllers/algo/engine.h @@ -88,6 +88,7 @@ public: DECLARE_ENGINE_PTR; Engine(); + bool enableOverdwellProtection = true; bool isPwmEnabled = true; int triggerActivitySecond = 0; diff --git a/firmware/controllers/engine_cycle/spark_logic.cpp b/firmware/controllers/engine_cycle/spark_logic.cpp index 8e2eae121f..e751d2e19a 100644 --- a/firmware/controllers/engine_cycle/spark_logic.cpp +++ b/firmware/controllers/engine_cycle/spark_logic.cpp @@ -378,6 +378,8 @@ static void handleSparkEvent(bool limitedSpark, uint32_t trgEventIndex, Ignition event->sparkId = engine->globalSparkIdCounter++; + efitick_t chargeTime = 0; + /** * The start of charge is always within the current trigger event range, so just plain time-based scheduling */ @@ -393,7 +395,7 @@ static void handleSparkEvent(bool limitedSpark, uint32_t trgEventIndex, Ignition * This way we make sure that coil dwell started while spark was enabled would fire and not burn * the coil. */ - scheduleByAngle(&event->dwellStartTimer, edgeTimestamp, angleOffset, { &turnSparkPinHigh, event } PASS_ENGINE_PARAMETER_SUFFIX); + chargeTime = scheduleByAngle(&event->dwellStartTimer, edgeTimestamp, angleOffset, { &turnSparkPinHigh, event } PASS_ENGINE_PARAMETER_SUFFIX); event->sparksRemaining = ENGINE(engineState.multispark.count); } else { @@ -418,10 +420,14 @@ static void handleSparkEvent(bool limitedSpark, uint32_t trgEventIndex, Ignition #if SPARK_EXTREME_LOGGING efiPrintf("to queue sparkDown ind=%d %d %s now=%d for id=%d", trgEventIndex, getRevolutionCounter(), event->getOutputForLoggins()->name, (int)getTimeNowUs(), event->sparkEvent.position.triggerEventIndex); #endif /* SPARK_EXTREME_LOGGING */ + + if (!limitedSpark && engine->enableOverdwellProtection) { + // auto fire spark at 1.5x nominal dwell + efitick_t fireTime = chargeTime + MSF2NT(1.5f * dwellMs); + engine->executor.scheduleByTimestampNt("overdwell", &event->sparkEvent.scheduling, fireTime, { fireSparkAndPrepareNextSchedule, event }); + } } - - #if EFI_UNIT_TEST if (verboseMode) { printf("spark dwell@ %d/%d spark@ %d/%d id=%d\r\n", event->dwellPosition.triggerEventIndex, (int)event->dwellPosition.angleOffsetFromTriggerEvent, @@ -482,7 +488,6 @@ static void prepareIgnitionSchedule(DECLARE_ENGINE_PARAMETER_SIGNATURE) { initializeIgnitionActions(PASS_ENGINE_PARAMETER_SIGNATURE); } - static void scheduleAllSparkEventsUntilNextTriggerTooth(uint32_t trgEventIndex, efitick_t edgeTimestamp DECLARE_ENGINE_PARAMETER_SUFFIX) { AngleBasedEvent *current, *tmp; @@ -498,6 +503,9 @@ static void scheduleAllSparkEventsUntilNextTriggerTooth(uint32_t trgEventIndex, efiPrintf("time to invoke ind=%d %d %d", trgEventIndex, getRevolutionCounter(), (int)getTimeNowUs()); #endif /* SPARK_EXTREME_LOGGING */ + // In case this event was scheduled by overdwell protection, cancel it so we can re-schedule at the correct time + engine->executor.cancel(sDown); + scheduleByAngle( sDown, edgeTimestamp, diff --git a/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp b/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp index 8e98554573..f8147640eb 100644 --- a/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp +++ b/unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp @@ -40,6 +40,9 @@ TEST(ignition, twoCoils) { TEST(ignition, trailingSpark) { WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + // TODO #3220: this feature makes this test sad, eventually remove this line (and the ability to disable it altogether) + engine->enableOverdwellProtection = false; + EXPECT_CALL(eth.mockAirmass, getAirmass(_)) .WillRepeatedly(Return(AirmassResult{0.1008f, 50.0f})); diff --git a/unit_tests/tests/trigger/test_real_cranking_nissan_vq40.cpp b/unit_tests/tests/trigger/test_real_cranking_nissan_vq40.cpp index b3b58008d7..a13f876ce2 100644 --- a/unit_tests/tests/trigger/test_real_cranking_nissan_vq40.cpp +++ b/unit_tests/tests/trigger/test_real_cranking_nissan_vq40.cpp @@ -32,7 +32,8 @@ TEST(realCrankingVQ40, normalCranking) { ASSERT_EQ(241, GET_RPM())<< reader.lineIndex(); // TODO: why warnings? - ASSERT_EQ(2, eth.recentWarnings()->getCount()); + ASSERT_EQ(3, eth.recentWarnings()->getCount()); ASSERT_EQ(CUSTOM_SYNC_COUNT_MISMATCH, eth.recentWarnings()->get(0)); - ASSERT_EQ(CUSTOM_SYNC_ERROR, eth.recentWarnings()->get(1)); + ASSERT_EQ(CUSTOM_OUT_OF_ORDER_COIL, eth.recentWarnings()->get(1)); // this is from a coil being protected by overdwell protection + ASSERT_EQ(CUSTOM_SYNC_ERROR, eth.recentWarnings()->get(2)); } diff --git a/unit_tests/tests/trigger/test_trigger_decoder.cpp b/unit_tests/tests/trigger/test_trigger_decoder.cpp index 07743251e8..939c7bada3 100644 --- a/unit_tests/tests/trigger/test_trigger_decoder.cpp +++ b/unit_tests/tests/trigger/test_trigger_decoder.cpp @@ -1134,7 +1134,7 @@ TEST(big, testSparkReverseOrderBug319) { ASSERT_EQ( 3000, GET_RPM()) << "testSparkReverseOrderBug319: RPM"; - ASSERT_EQ( 7, engine->executor.size()) << "testSparkReverseOrderBug319: queue size"; + ASSERT_EQ( 8, engine->executor.size()) << "testSparkReverseOrderBug319: queue size"; eth.executeActions(); printf("***************************************************\r\n");