diff --git a/firmware/controllers/algo/obd_error_codes.h b/firmware/controllers/algo/obd_error_codes.h index 911bafe7f2..754a53a7f5 100644 --- a/firmware/controllers/algo/obd_error_codes.h +++ b/firmware/controllers/algo/obd_error_codes.h @@ -2042,7 +2042,7 @@ typedef enum { CUSTOM_ERR_6686 = 6686, CUSTOM_FIRING_LENGTH = 6687, CUSTOM_ADVANCE_SPARK = 6688, - CUSTOM_SPARK_ANGLE_9 = 6689, + CUSTOM_ERR_6689 = 6689, CUSTOM_ERR_MAP_START_ASSERT = 6690, CUSTOM_ERR_MAP_AVG_OFFSET = 6691, diff --git a/firmware/controllers/algo/rusefi_enums.h b/firmware/controllers/algo/rusefi_enums.h index 88602d9c66..77ff7c95b6 100644 --- a/firmware/controllers/algo/rusefi_enums.h +++ b/firmware/controllers/algo/rusefi_enums.h @@ -706,4 +706,10 @@ enum class TransmissionControllerMode : uint8_t { Gm4l6x = 2, }; +enum class InjectionTimingMode : uint8_t { + End = 0, + Start = 1, + Center = 2, +}; + #endif // __cplusplus diff --git a/firmware/controllers/engine_cycle/fuel_schedule.cpp b/firmware/controllers/engine_cycle/fuel_schedule.cpp index 827742b019..81f8ec7c31 100644 --- a/firmware/controllers/engine_cycle/fuel_schedule.cpp +++ b/firmware/controllers/engine_cycle/fuel_schedule.cpp @@ -11,8 +11,7 @@ FuelSchedule::FuelSchedule() { for (int cylinderIndex = 0; cylinderIndex < MAX_CYLINDER_COUNT; cylinderIndex++) { - InjectionEvent *ev = &elements[cylinderIndex]; - ev->ownIndex = cylinderIndex; + elements[cylinderIndex].ownIndex = cylinderIndex; } } @@ -26,6 +25,29 @@ void FuelSchedule::resetOverlapping() { } } +// Determines how much to adjust injection opening angle based on the injection's duration and the current phasing mode +static float getInjectionAngleCorrection(float fuelMs, float oneDegreeUs) { + auto mode = engineConfiguration->injectionTimingMode; + if (mode == InjectionTimingMode::Start) { + // Start of injection gets no correction for duration + return 0; + } + + efiAssert(CUSTOM_ERR_ASSERT, !cisnan(fuelMs), "NaN fuelMs", false); + + angle_t injectionDurationAngle = MS2US(fuelMs) / oneDegreeUs; + efiAssert(CUSTOM_ERR_ASSERT, !cisnan(injectionDurationAngle), "NaN injectionDurationAngle", false); + assertAngleRange(injectionDurationAngle, "injectionDuration_r", CUSTOM_INJ_DURATION); + + if (mode == InjectionTimingMode::Center) { + // Center of injection is half-corrected for duration + return injectionDurationAngle * 0.5f; + } else { + // End of injection gets "full correction" so we advance opening by the full duration + return injectionDurationAngle; + } +} + /** * @returns false in case of error, true if success */ @@ -37,26 +59,19 @@ bool FuelSchedule::addFuelEventsForCylinder(int i ) { return false; } - /** - * injection phase is scheduled by injection end, so we need to step the angle back - * for the duration of the injection - * - * todo: since this method is not invoked within trigger event handler and - * engineState.injectionOffset is calculated from the same utility timer should we more that logic here? - */ - floatms_t fuelMs = engine->injectionDuration; - efiAssert(CUSTOM_ERR_ASSERT, !cisnan(fuelMs), "NaN fuelMs", false); - angle_t injectionDurationAngle = MS2US(fuelMs) / oneDegreeUs; - efiAssert(CUSTOM_ERR_ASSERT, !cisnan(injectionDurationAngle), "NaN injectionDurationAngle", false); - assertAngleRange(injectionDurationAngle, "injectionDuration_r", CUSTOM_INJ_DURATION); + // injection phase may be scheduled by injection end, so we need to step the angle back + // for the duration of the injection + angle_t injectionDurationAngle = getInjectionAngleCorrection(engine->injectionDuration, oneDegreeUs); + + // User configured offset - degrees after TDC combustion floatus_t injectionOffset = engine->engineState.injectionOffset; if (cisnan(injectionOffset)) { // injection offset map not ready - we are not ready to schedule fuel events return false; } - angle_t baseAngle = injectionOffset - injectionDurationAngle; - efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseAngle), "NaN baseAngle", false); - assertAngleRange(baseAngle, "baseAngle_r", CUSTOM_ERR_6554); + + angle_t openingAngle = injectionOffset - injectionDurationAngle; + assertAngleRange(openingAngle, "openingAngle_r", CUSTOM_ERR_6554); injection_mode_e mode = engine->getCurrentInjectionMode(); @@ -102,7 +117,6 @@ bool FuelSchedule::addFuelEventsForCylinder(int i ) { InjectionEvent *ev = &elements[i]; - ev->ownIndex = i; ev->outputs[0] = output; ev->outputs[1] = secondOutput; ev->isSimultanious = isSimultanious; @@ -114,27 +128,27 @@ bool FuelSchedule::addFuelEventsForCylinder(int i ) { warning(CUSTOM_OBD_INJECTION_NO_PIN_ASSIGNED, "no_pin_inj #%s", output->name); } - float angle = baseAngle + getCylinderAngle(i, ev->cylinderNumber); + // Convert from cylinder-relative to cylinder-1-relative + openingAngle += getCylinderAngle(i, ev->cylinderNumber); if (TRIGGER_WAVEFORM(getSize()) < 1) { warning(CUSTOM_ERR_NOT_INITIALIZED_TRIGGER, "uninitialized TriggerWaveform"); return false; } - efiAssert(CUSTOM_ERR_ASSERT, !cisnan(angle), "findAngle#3", false); - assertAngleRange(angle, "findAngle#a33", CUSTOM_ERR_6544); - ev->injectionStart.setAngle(angle); + efiAssert(CUSTOM_ERR_ASSERT, !cisnan(openingAngle), "findAngle#3", false); + assertAngleRange(openingAngle, "findAngle#a33", CUSTOM_ERR_6544); + ev->injectionStart.setAngle(openingAngle); #if EFI_UNIT_TEST - printf("registerInjectionEvent angle=%.2f trgIndex=%d inj %d\r\n", angle, ev->injectionStart.triggerEventIndex, injectorIndex); + printf("registerInjectionEvent openingAngle=%.2f trgIndex=%d inj %d\r\n", openingAngle, ev->injectionStart.triggerEventIndex, injectorIndex); #endif return true; } void FuelSchedule::addFuelEvents() { for (size_t cylinderIndex = 0; cylinderIndex < engineConfiguration->specs.cylindersCount; cylinderIndex++) { - InjectionEvent *ev = &elements[cylinderIndex]; - ev->ownIndex = cylinderIndex; // todo: is this assignment needed here? we now initialize in constructor bool result = addFuelEventsForCylinder(cylinderIndex); + if (!result) { invalidate(); return; diff --git a/firmware/controllers/engine_cycle/spark_logic.cpp b/firmware/controllers/engine_cycle/spark_logic.cpp index 7312beb67d..10157f8cd4 100644 --- a/firmware/controllers/engine_cycle/spark_logic.cpp +++ b/firmware/controllers/engine_cycle/spark_logic.cpp @@ -81,8 +81,6 @@ static void prepareCylinderIgnitionSchedule(angle_t dwellAngleDuration, floatms_ // Pull any extra timing for knock retard + engine->knockController.getKnockRetard(); - efiAssertVoid(CUSTOM_SPARK_ANGLE_9, !cisnan(sparkAngle), "findAngle#9"); - efiAssertVoid(CUSTOM_SPARK_ANGLE_1, !cisnan(sparkAngle), "sparkAngle#1"); const int index = engine->ignitionPin[event->cylinderIndex]; const int coilIndex = ID2INDEX(getCylinderId(index)); diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index 69364c5c74..3c98089108 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -1199,7 +1199,10 @@ int16_t tps2Max;Full throttle#2. tpsMax value as 10 bit ADC value. Not Voltage!\ brain_input_pin_e[2 iterate] auxSpeedSensorInputPin; uint8_t totalGearsCount;;"", 1, 0, 1, @@GEARS_COUNT@@, 0 - uint8_t unused16962;;"", 1, 0, 0, 1, 0 + + custom InjectionTimingMode 1 bits, U08, @OFFSET@, [0:1], "End of injection", "Start of injection", "Center of injection" + InjectionTimingMode injectionTimingMode;Sets what part of injection's is controlled by the injection phase table. + uint32_t uartConsoleSerialSpeed;Band rate for primary TTL;"BPs", 1, 0, 0, 1000000, 0 float tpsDecelEnleanmentThreshold;For decel we simply multiply delta of TPS and tFor decel we do not use table?!;"roc", 1, 0, 0, 200, 1 float tpsDecelEnleanmentMultiplier;Magic multiplier, we multiply delta of TPS and get fuel squirt duration;"coeff", 1, 0, 0, 200, 2 diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index e784d2901e..82d1f68b00 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -1881,6 +1881,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00" field = "Individually wired Batch Fuel", twoWireBatchInjection, {isInjectionEnabled == 1 && injectionMode == @@injection_mode_e_IM_BATCH@@ } field = "Override VE table load axis", veOverrideMode, { isInjectionEnabled } field = "Override AFR table load axis", afrOverrideMode, { isInjectionEnabled } + field = "Injection phase control mode", injectionTimingMode, { isInjectionEnabled } dialog = ignitionOutputs, "Ignition Outputs" field = "Ignition Pin Mode", ignitionPinMode, {isIgnitionEnabled == 1}