mirror of https://github.com/FOME-Tech/fome-fw.git
Compare commits
No commits in common. "51a23364e20d2584bb30194b8c13b622014b898f" and "7593cd61d4787a441d6364f721fd67d3587b6f44" have entirely different histories.
51a23364e2
...
7593cd61d4
|
@ -43,7 +43,6 @@ or
|
|||
- TunerStudio UI improvements (#436, etc)
|
||||
- Dropdown selector for popular gearbox ratios (#358, thank you @alrijleh and @nmschulte!)
|
||||
- Add two more aux linear sensors #476
|
||||
- Support wasted spark on odd cylinder count 4-stroke engines. Improves startup and allows running without a cam sensor!
|
||||
|
||||
### Fixed
|
||||
- Improve performance with Lua CAN reception of a high volume of frames
|
||||
|
|
|
@ -24,8 +24,6 @@ public:
|
|||
*/
|
||||
angle_t engineCycle;
|
||||
|
||||
bool useOddFireWastedSpark = false;
|
||||
|
||||
/**
|
||||
* this is based on sensorChartMode and sensorSnifferRpmThreshold settings
|
||||
*/
|
||||
|
|
|
@ -104,14 +104,6 @@ static void prepareCylinderIgnitionSchedule(angle_t dwellAngleDuration, floatms_
|
|||
event->sparkAngle = sparkAngle;
|
||||
|
||||
auto ignitionMode = getCurrentIgnitionMode();
|
||||
|
||||
// On an odd cylinder (or odd fire) wasted spark engine, map outputs as if in sequential.
|
||||
// During actual scheduling, the events just get scheduled every 360 deg instead
|
||||
// of every 720 deg.
|
||||
if (ignitionMode == IM_WASTED_SPARK && engine->engineState.useOddFireWastedSpark) {
|
||||
ignitionMode = IM_INDIVIDUAL_COILS;
|
||||
}
|
||||
|
||||
engine->outputChannels.currentIgnitionMode = static_cast<uint8_t>(ignitionMode);
|
||||
|
||||
const int index = getIgnitionPinForIndex(event->cylinderIndex, ignitionMode);
|
||||
|
@ -317,9 +309,20 @@ void turnSparkPinHigh(IgnitionEvent *event) {
|
|||
}
|
||||
|
||||
static void scheduleSparkEvent(bool limitedSpark, IgnitionEvent *event,
|
||||
int rpm, float dwellMs, float dwellAngle, float sparkAngle, efitick_t edgeTimestamp, float currentPhase, float nextPhase) {
|
||||
int rpm, efitick_t edgeTimestamp, float currentPhase, float nextPhase) {
|
||||
|
||||
float angleOffset = dwellAngle - currentPhase;
|
||||
angle_t sparkAngle = event->sparkAngle;
|
||||
const floatms_t dwellMs = engine->ignitionState.sparkDwell;
|
||||
if (std::isnan(dwellMs) || dwellMs <= 0) {
|
||||
warning(ObdCode::CUSTOM_DWELL, "invalid dwell to handle: %.2f at %d", dwellMs, rpm);
|
||||
return;
|
||||
}
|
||||
if (std::isnan(sparkAngle)) {
|
||||
warning(ObdCode::CUSTOM_ADVANCE_SPARK, "NaN advance");
|
||||
return;
|
||||
}
|
||||
|
||||
float angleOffset = event->dwellAngle - currentPhase;
|
||||
if (angleOffset < 0) {
|
||||
angleOffset += engine->engineState.engineCycle;
|
||||
}
|
||||
|
@ -454,12 +457,6 @@ void onTriggerEventSparkLogic(int rpm, efitick_t edgeTimestamp, float currentPha
|
|||
engine->outputChannels.sparkCutReason = (int8_t)limitedSparkState.reason;
|
||||
bool limitedSpark = !limitedSparkState.value;
|
||||
|
||||
const floatms_t dwellMs = engine->ignitionState.sparkDwell;
|
||||
if (std::isnan(dwellMs) || dwellMs <= 0) {
|
||||
warning(ObdCode::CUSTOM_DWELL, "invalid dwell to handle: %.2f at %d", dwellMs, rpm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!engine->ignitionEvents.isReady) {
|
||||
prepareIgnitionSchedule();
|
||||
}
|
||||
|
@ -470,48 +467,13 @@ void onTriggerEventSparkLogic(int rpm, efitick_t edgeTimestamp, float currentPha
|
|||
* See initializeIgnitionActions()
|
||||
*/
|
||||
|
||||
// Only apply odd cylinder count wasted logic if:
|
||||
// - odd cyl count
|
||||
// - current mode is wasted spark
|
||||
// - four stroke
|
||||
bool enableOddCylinderWastedSpark =
|
||||
engine->engineState.useOddFireWastedSpark
|
||||
&& getCurrentIgnitionMode() == IM_WASTED_SPARK;
|
||||
|
||||
// scheduleSimpleMsg(&logger, "eventId spark ", eventIndex);
|
||||
if (engine->ignitionEvents.isReady) {
|
||||
for (size_t i = 0; i < engineConfiguration->cylindersCount; i++) {
|
||||
IgnitionEvent *event = &engine->ignitionEvents.elements[i];
|
||||
|
||||
angle_t dwellAngle = event->dwellAngle;
|
||||
|
||||
angle_t sparkAngle = event->sparkAngle;
|
||||
if (std::isnan(sparkAngle)) {
|
||||
warning(ObdCode::CUSTOM_ADVANCE_SPARK, "NaN advance");
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isOddCylWastedEvent = false;
|
||||
if (enableOddCylinderWastedSpark) {
|
||||
auto dwellAngleWastedEvent = dwellAngle + 360;
|
||||
if (dwellAngleWastedEvent > 720) {
|
||||
dwellAngleWastedEvent -= 720;
|
||||
}
|
||||
|
||||
// Check whether this event hits 360 degrees out from now (ie, wasted spark),
|
||||
// and if so, twiddle the dwell and spark angles so it happens now instead
|
||||
isOddCylWastedEvent = isPhaseInRange(dwellAngleWastedEvent, currentPhase, nextPhase);
|
||||
|
||||
if (isOddCylWastedEvent) {
|
||||
dwellAngle = dwellAngleWastedEvent;
|
||||
|
||||
sparkAngle += 360;
|
||||
if (sparkAngle > 720) {
|
||||
sparkAngle -= 720;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOddCylWastedEvent && !isPhaseInRange(dwellAngle, currentPhase, nextPhase)) {
|
||||
if (!isPhaseInRange(event->dwellAngle, currentPhase, nextPhase)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -536,7 +498,7 @@ void onTriggerEventSparkLogic(int rpm, efitick_t edgeTimestamp, float currentPha
|
|||
engine->ALSsoftSparkLimiter.setTargetSkipRatio(ALSSkipRatio);
|
||||
#endif // EFI_ANTILAG_SYSTEM
|
||||
|
||||
scheduleSparkEvent(limitedSpark, event, rpm, dwellMs, dwellAngle, sparkAngle, edgeTimestamp, currentPhase, nextPhase);
|
||||
scheduleSparkEvent(limitedSpark, event, rpm, edgeTimestamp, currentPhase, nextPhase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,12 @@ static bool noFiringUntilVvtSync(vvt_mode_e vvtMode) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Odd cylinder count engines don't work properly with wasted spark, so wait for full sync (so that sequential works)
|
||||
// See https://github.com/rusefi/rusefi/issues/4195 for the issue to properly support this case
|
||||
if (engineConfiguration->cylindersCount > 1 && engineConfiguration->cylindersCount % 2 == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Symmetrical crank modes require cam sync before firing
|
||||
// non-symmetrical cranks can use faster spin-up mode (firing in wasted/batch before VVT sync)
|
||||
// Examples include Nissan MR/VQ, Miata NB, etc
|
||||
|
|
|
@ -386,7 +386,8 @@ ignition_mode_e getCurrentIgnitionMode() {
|
|||
ignition_mode_e ignitionMode = engineConfiguration->ignitionMode;
|
||||
#if EFI_SHAFT_POSITION_INPUT
|
||||
// In spin-up cranking mode we don't have full phase sync info yet, so wasted spark mode is better
|
||||
if (ignitionMode == IM_INDIVIDUAL_COILS) {
|
||||
// However, only do this on even cylinder count engines: odd cyl count doesn't fire at all
|
||||
if (ignitionMode == IM_INDIVIDUAL_COILS && (engineConfiguration->cylindersCount % 2 == 0)) {
|
||||
bool missingPhaseInfoForSequential =
|
||||
!engine->triggerCentral.triggerState.hasSynchronizedPhase();
|
||||
|
||||
|
@ -404,20 +405,7 @@ ignition_mode_e getCurrentIgnitionMode() {
|
|||
* This heavy method is only invoked in case of a configuration change or initialization.
|
||||
*/
|
||||
void prepareOutputSignals() {
|
||||
auto operationMode = getEngineRotationState()->getOperationMode();
|
||||
getEngineState()->engineCycle = getEngineCycle(operationMode);
|
||||
|
||||
bool isOddFire = false;
|
||||
for (size_t i = 0; i < engineConfiguration->cylindersCount; i++) {
|
||||
if (engineConfiguration->timing_offset_cylinder[i] != 0) {
|
||||
isOddFire = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Use odd fire wasted spark logic if not two stroke, and an odd fire or odd cylinder # engine
|
||||
getEngineState()->useOddFireWastedSpark = operationMode != TWO_STROKE
|
||||
&& (isOddFire | (engineConfiguration->cylindersCount % 2 == 1));
|
||||
getEngineState()->engineCycle = getEngineCycle(getEngineRotationState()->getOperationMode());
|
||||
|
||||
#if EFI_UNIT_TEST
|
||||
if (verboseMode) {
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
#include "spark_logic.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::InSequence;
|
||||
using ::testing::StrictMock;
|
||||
|
||||
TEST(ignition, twoCoils) {
|
||||
EngineTestHelper eth(engine_type_e::FRANKENSO_BMW_M73_F);
|
||||
|
@ -150,55 +148,3 @@ TEST(ignition, CylinderTimingTrim) {
|
|||
EXPECT_NEAR(engine->engineState.timingAdvance[2], unadjusted + 2, EPS4D);
|
||||
EXPECT_NEAR(engine->engineState.timingAdvance[3], unadjusted + 4, EPS4D);
|
||||
}
|
||||
|
||||
TEST(ignition, oddCylinderWastedSpark) {
|
||||
StrictMock<MockExecutor> mockExec;
|
||||
|
||||
EngineTestHelper eth(engine_type_e::TEST_ENGINE);
|
||||
engine->scheduler.setMockExecutor(&mockExec);
|
||||
engineConfiguration->cylindersCount = 1;
|
||||
engineConfiguration->firingOrder = FO_1;
|
||||
engineConfiguration->ignitionMode = IM_WASTED_SPARK;
|
||||
|
||||
efitick_t nowNt1 = 1000000;
|
||||
efitick_t nowNt2 = 2222222;
|
||||
|
||||
|
||||
engine->rpmCalculator.oneDegreeUs = 100;
|
||||
|
||||
{
|
||||
InSequence is;
|
||||
|
||||
// Should schedule one dwell+fire pair:
|
||||
// Dwell 5 deg from now
|
||||
float nt1deg = USF2NT(engine->rpmCalculator.oneDegreeUs);
|
||||
efitick_t startTime = nowNt1 + nt1deg * 5;
|
||||
EXPECT_CALL(mockExec, schedule(testing::NotNull(), _, startTime, _));
|
||||
// Spark 15 deg from now
|
||||
efitick_t endTime = startTime + nt1deg * 10;
|
||||
EXPECT_CALL(mockExec, schedule(testing::NotNull(), _, endTime, _));
|
||||
|
||||
|
||||
// Should schedule second dwell+fire pair, the out of phase copy
|
||||
// Dwell 5 deg from now
|
||||
startTime = nowNt2 + nt1deg * 5;
|
||||
EXPECT_CALL(mockExec, schedule(testing::NotNull(), _, startTime, _));
|
||||
// Spark 15 deg from now
|
||||
endTime = startTime + nt1deg * 10;
|
||||
EXPECT_CALL(mockExec, schedule(testing::NotNull(), _, endTime, _));
|
||||
}
|
||||
|
||||
engine->ignitionState.sparkDwell = 1;
|
||||
|
||||
// dwell should start at 15 degrees ATDC and firing at 25 deg ATDC
|
||||
engine->ignitionState.dwellAngle = 10;
|
||||
engine->engineState.timingAdvance[0] = -25;
|
||||
engine->engineState.useOddFireWastedSpark = true;
|
||||
engineConfiguration->minimumIgnitionTiming = -25;
|
||||
|
||||
// expect to schedule the on-phase dwell and spark (not the wasted spark copy)
|
||||
onTriggerEventSparkLogic(1200, nowNt1, 10, 30);
|
||||
|
||||
// expect to schedule second events, the out-of-phase dwell and spark (the wasted spark copy)
|
||||
onTriggerEventSparkLogic(1200, nowNt2, 360 + 10, 360 + 30);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue