Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

trailing spark scheduling #2932

Merged
merged 7 commits into from Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions firmware/controllers/algo/engine2.cpp
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions firmware/controllers/algo/engine_state.h
Expand Up @@ -47,6 +47,10 @@ class EngineState : public engine_state2_s {
* 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;
Expand Down
3 changes: 3 additions & 0 deletions firmware/controllers/algo/event_registry.h
Expand Up @@ -99,6 +99,9 @@ class IgnitionEvent {
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;
Expand Down
2 changes: 1 addition & 1 deletion firmware/controllers/engine_controller.cpp
Expand Up @@ -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
Expand Down
33 changes: 28 additions & 5 deletions firmware/controllers/engine_cycle/spark_logic.cpp
Expand Up @@ -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];
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions firmware/controllers/system/efi_gpio.h
Expand Up @@ -209,6 +209,7 @@ class EnginePins {

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];

Expand Down
2 changes: 1 addition & 1 deletion firmware/integration/rusefi_config.txt
Expand Up @@ -536,7 +536,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
Expand Down
60 changes: 59 additions & 1 deletion unit_tests/tests/ignition_injection/test_ignition_scheduling.cpp
Expand Up @@ -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);

Expand All @@ -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(&eth);
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);
}