From e25a93415f446ce3015f01ea44f5cc1e5bd46f29 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Fri, 10 Jan 2020 13:01:54 -0800 Subject: [PATCH] Schedule sparks with scheduleByAngle (#1092) * injection * injectors * add edge timestamp to ShaftPositionListener * scheduleByAngle require edgeTimestamp * schedule with nt not us * fix all schedulers * schedule spark based on edge timestamp * aux valves too * update comments * schedule dwell with new stamp * format --- .../controllers/engine_cycle/aux_valves.cpp | 3 ++ .../engine_cycle/main_trigger_callback.cpp | 2 +- .../controllers/engine_cycle/spark_logic.cpp | 54 ++++++++++--------- .../controllers/engine_cycle/spark_logic.h | 3 +- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/firmware/controllers/engine_cycle/aux_valves.cpp b/firmware/controllers/engine_cycle/aux_valves.cpp index c09b02ad80..cb620876a1 100644 --- a/firmware/controllers/engine_cycle/aux_valves.cpp +++ b/firmware/controllers/engine_cycle/aux_valves.cpp @@ -33,6 +33,7 @@ void plainPinTurnOn(AuxActor *current) { scheduleOrQueue(¤t->open, TRIGGER_EVENT_UNDEFINED, + getTimeNowNt(), current->extra + engine->engineState.auxValveStart, { plainPinTurnOn, current } PASS_ENGINE_PARAMETER_SUFFIX @@ -44,6 +45,7 @@ void plainPinTurnOn(AuxActor *current) { scheduleOrQueue(¤t->close, TRIGGER_EVENT_UNDEFINED, + getTimeNowNt(), current->extra + engine->engineState.auxValveEnd, { plainPinTurnOff, output } PASS_ENGINE_PARAMETER_SUFFIX @@ -148,6 +150,7 @@ void initAuxValves(Logging *sharedLogger DECLARE_ENGINE_PARAMETER_SUFFIX) { scheduleOrQueue(&actor->open, TRIGGER_EVENT_UNDEFINED, + getTimeNowNt(), actor->extra + engine->engineState.auxValveStart, { plainPinTurnOn, actor } PASS_ENGINE_PARAMETER_SUFFIX diff --git a/firmware/controllers/engine_cycle/main_trigger_callback.cpp b/firmware/controllers/engine_cycle/main_trigger_callback.cpp index b9ba0b73b2..be9c309923 100644 --- a/firmware/controllers/engine_cycle/main_trigger_callback.cpp +++ b/firmware/controllers/engine_cycle/main_trigger_callback.cpp @@ -509,7 +509,7 @@ static void mainTriggerCallback(trigger_event_e ckpSignalType, uint32_t trgEvent /** * For spark we schedule both start of coil charge and actual spark based on trigger angle */ - onTriggerEventSparkLogic(limitedSpark, trgEventIndex, rpm PASS_ENGINE_PARAMETER_SUFFIX); + onTriggerEventSparkLogic(limitedSpark, trgEventIndex, rpm, edgeTimestamp PASS_ENGINE_PARAMETER_SUFFIX); if (trgEventIndex == 0) { ENGINE(m.mainTriggerCallbackTime) = getTimeNowLowerNt() - ENGINE(m.beforeMainTrigger); diff --git a/firmware/controllers/engine_cycle/spark_logic.cpp b/firmware/controllers/engine_cycle/spark_logic.cpp index 66cba484fb..d324ba2840 100644 --- a/firmware/controllers/engine_cycle/spark_logic.cpp +++ b/firmware/controllers/engine_cycle/spark_logic.cpp @@ -124,7 +124,8 @@ static void prepareCylinderIgnitionSchedule(angle_t dwellAngleDuration, floatms_ void fireSparkAndPrepareNextSchedule(IgnitionEvent *event) { for (int i = 0; i< MAX_OUTPUTS_FOR_IGNITION;i++) { IgnitionOutputPin *output = event->outputs[i]; - if (output != NULL) { + + if (output) { fireSparkBySettingPinLow(event, output); } } @@ -149,7 +150,7 @@ if (engineConfiguration->debugMode == DBG_DWELL_METRIC) { } #endif -} + } #endif /* EFI_UNIT_TEST */ #if EFI_UNIT_TEST Engine *engine = event->engine; @@ -226,34 +227,32 @@ static bool assertNotInIgnitionList(AngleBasedEvent *head, AngleBasedEvent *elem */ bool scheduleOrQueue(AngleBasedEvent *event, uint32_t trgEventIndex, + efitick_t edgeTimestamp, angle_t angle, action_s action DECLARE_ENGINE_PARAMETER_SUFFIX) { event->position.setAngle(angle PASS_ENGINE_PARAMETER_SUFFIX); /** - * todo: extract a "scheduleForAngle" method with best implementation into a separate utility method - * - * Here's the status as of Nov 2018: - * "scheduleForLater" uses time only and for best precision it's best to use "scheduleForLater" only - * once we hit the last trigger tooth prior to needed event. This case we use as much trigger position angle as possible + * Here's the status as of Jan 2020: + * Once we hit the last trigger tooth prior to needed event, schedule it by time. We use as much trigger position angle as possible * and only use less precise RPM-based time calculation for the last portion of the angle, the one between two teeth closest to the * desired angle moment. - * - * At the moment we only have time-based scheduler. I believe what needs to be added is a trigger-event based scheduler on top of the - * time-based schedule. This case we would be firing events with best possible angle precision. - * */ if (trgEventIndex != TRIGGER_EVENT_UNDEFINED && event->position.triggerEventIndex == trgEventIndex) { /** * Spark should be fired before the next trigger event - time-based delay is best precision possible */ - float timeTillIgnitionUs = ENGINE(rpmCalculator.oneDegreeUs) * event->position.angleOffsetFromTriggerEvent; - - scheduling_s * sDown = &event->scheduling; - engine->executor.scheduleForLater(sDown, (int) timeTillIgnitionUs, action); + scheduleByAngle( + sDown, + edgeTimestamp, + event->position.angleOffsetFromTriggerEvent, + action + PASS_ENGINE_PARAMETER_SUFFIX + ); + return true; } else { event->action = action; @@ -273,7 +272,7 @@ bool scheduleOrQueue(AngleBasedEvent *event, } static ALWAYS_INLINE void handleSparkEvent(bool limitedSpark, uint32_t trgEventIndex, IgnitionEvent *iEvent, - int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) { + int rpm, efitick_t edgeTimestamp DECLARE_ENGINE_PARAMETER_SUFFIX) { angle_t sparkAngle = iEvent->sparkAngle; const floatms_t dwellMs = ENGINE(engineState.sparkDwell); @@ -321,18 +320,17 @@ static ALWAYS_INLINE void handleSparkEvent(bool limitedSpark, uint32_t trgEventI * This way we make sure that coil dwell started while spark was enabled would fire and not burn * the coil. */ - engine->executor.scheduleForLater(sUp, chargeDelayUs, { &turnSparkPinHigh, iEvent }); + engine->executor.scheduleByTimestampNt(sUp, edgeTimestamp + US2NT(chargeDelayUs), { &turnSparkPinHigh, iEvent }); } /** * Spark event is often happening during a later trigger event timeframe - * TODO: improve precision */ efiAssertVoid(CUSTOM_ERR_6591, !cisnan(sparkAngle), "findAngle#4"); assertAngleRange(sparkAngle, "findAngle#a5", CUSTOM_ERR_6549); - bool scheduled = scheduleOrQueue(&iEvent->sparkEvent, trgEventIndex, sparkAngle, { fireSparkAndPrepareNextSchedule, iEvent } PASS_ENGINE_PARAMETER_SUFFIX); + bool scheduled = scheduleOrQueue(&iEvent->sparkEvent, trgEventIndex, edgeTimestamp, sparkAngle, { fireSparkAndPrepareNextSchedule, iEvent } PASS_ENGINE_PARAMETER_SUFFIX); if (scheduled) { #if SPARK_EXTREME_LOGGING @@ -408,7 +406,7 @@ static ALWAYS_INLINE void prepareIgnitionSchedule(DECLARE_ENGINE_PARAMETER_SIGNA } -static void scheduleAllSparkEventsUntilNextTriggerTooth(uint32_t trgEventIndex DECLARE_ENGINE_PARAMETER_SUFFIX) { +static void scheduleAllSparkEventsUntilNextTriggerTooth(uint32_t trgEventIndex, efitick_t edgeTimestamp DECLARE_ENGINE_PARAMETER_SUFFIX) { AngleBasedEvent *current, *tmp; LL_FOREACH_SAFE2(ENGINE(angleBasedEventsHead), current, tmp, nextToothEvent) @@ -423,14 +421,18 @@ static void scheduleAllSparkEventsUntilNextTriggerTooth(uint32_t trgEventIndex D scheduleMsg(logger, "time to invoke ind=%d %d %d", trgEventIndex, getRevolutionCounter(), (int)getTimeNowUs()); #endif /* FUEL_MATH_EXTREME_LOGGING */ - - float timeTillIgnitionUs = ENGINE(rpmCalculator.oneDegreeUs) * current->position.angleOffsetFromTriggerEvent; - engine->executor.scheduleForLater(sDown, (int) timeTillIgnitionUs, current->action); + scheduleByAngle( + sDown, + edgeTimestamp, + current->position.angleOffsetFromTriggerEvent, + current->action + PASS_ENGINE_PARAMETER_SUFFIX + ); } } } -void onTriggerEventSparkLogic(bool limitedSpark, uint32_t trgEventIndex, int rpm +void onTriggerEventSparkLogic(bool limitedSpark, uint32_t trgEventIndex, int rpm, efitick_t edgeTimestamp DECLARE_ENGINE_PARAMETER_SUFFIX) { ScopePerf perf(PE::OnTriggerEventSparkLogic); @@ -449,7 +451,7 @@ void onTriggerEventSparkLogic(bool limitedSpark, uint32_t trgEventIndex, int rpm * Ignition schedule is defined once per revolution * See initializeIgnitionActions() */ - scheduleAllSparkEventsUntilNextTriggerTooth(trgEventIndex PASS_ENGINE_PARAMETER_SUFFIX); + scheduleAllSparkEventsUntilNextTriggerTooth(trgEventIndex, edgeTimestamp PASS_ENGINE_PARAMETER_SUFFIX); // scheduleSimpleMsg(&logger, "eventId spark ", eventIndex); @@ -458,7 +460,7 @@ void onTriggerEventSparkLogic(bool limitedSpark, uint32_t trgEventIndex, int rpm IgnitionEvent *event = &ENGINE(ignitionEvents.elements[i]); if (event->dwellPosition.triggerEventIndex != trgEventIndex) continue; - handleSparkEvent(limitedSpark, trgEventIndex, event, rpm PASS_ENGINE_PARAMETER_SUFFIX); + handleSparkEvent(limitedSpark, trgEventIndex, event, rpm, edgeTimestamp PASS_ENGINE_PARAMETER_SUFFIX); } } } diff --git a/firmware/controllers/engine_cycle/spark_logic.h b/firmware/controllers/engine_cycle/spark_logic.h index ce12164b59..24c8fb87fe 100644 --- a/firmware/controllers/engine_cycle/spark_logic.h +++ b/firmware/controllers/engine_cycle/spark_logic.h @@ -10,7 +10,7 @@ #include "engine.h" int isInjectionEnabled(DECLARE_ENGINE_PARAMETER_SIGNATURE); -void onTriggerEventSparkLogic(bool limitedSpark, uint32_t trgEventIndex, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX); +void onTriggerEventSparkLogic(bool limitedSpark, uint32_t trgEventIndex, int rpm, efitick_t edgeTimestamp DECLARE_ENGINE_PARAMETER_SUFFIX); void initSparkLogic(Logging *sharedLogger); void turnSparkPinHigh(IgnitionEvent *event); void fireSparkAndPrepareNextSchedule(IgnitionEvent *event); @@ -23,6 +23,7 @@ int isIgnitionTimingError(void); #define TRIGGER_EVENT_UNDEFINED -1 bool scheduleOrQueue(AngleBasedEvent *event, uint32_t trgEventIndex, + efitick_t edgeTimestamp, angle_t angle, action_s action DECLARE_ENGINE_PARAMETER_SUFFIX);