From 892e05d2fccf22da861425246ffe25723945ef1e Mon Sep 17 00:00:00 2001 From: iLeeeZi Date: Fri, 8 Nov 2019 07:40:53 +0200 Subject: [PATCH] Add idle ignition timing correction feature (#275) * Add idle advance and idle switch settings Add idle RPM target based ignition timing correction * Change few names to avoid confusion changed idle switch to closed throttle position sensor (CTPS) and moved CTPS settings under idle advance settings dialog for now --- reference/speeduino.ini | 49 ++++++++++++++++++++++++++++++++++----- speeduino/corrections.h | 1 + speeduino/corrections.ino | 31 ++++++++++++++++++++++++- speeduino/globals.h | 21 ++++++++++++++--- speeduino/init.ino | 18 ++++++++++++++ speeduino/sensors.ino | 7 ++++++ 6 files changed, 117 insertions(+), 10 deletions(-) diff --git a/reference/speeduino.ini b/reference/speeduino.ini index 7da7606d..692958b0 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -316,8 +316,16 @@ page = 1 #else primeBins = array, U08, 87, [4], "F", 1.8, -22.23, -40, 215, 0 #endif + CTPSPin = bits, U08, 91, [0:5], "Board Default", "INVALID", "INVALID", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15", "INVALID" + CTPSPolarity = bits, U08, 91, [6:6], "Normal", "Inverted" + CTPSEnabled = bits, U08, 91, [7:7], "Off", "On" + idleAdvEnabled = bits, U08, 92, [0:1], "Off", "Added", "Switched", "INVALID" + idleAdvAlgorithm = bits, U08, 92, [2:2], "TPS", "CTPS" + unused_idle_bits = bits, U08, 92, [3:7] + idleAdvRPM = scalar, U08, 93, "rpm", 100, 0.0, 100, 25500, 0 + idleAdvTPS = scalar, U08, 94, "%", 1, 0, 0, 120, 0 - unused2-91 = array, U08, 91, [37], "%", 1.0, 0.0, 0.0, 255, 0 + unused2-95 = array, U08, 95, [33], "%", 1.0, 0.0, 0.0, 255, 0 ;Page 2 is the fuel map and axis bins only page = 2 @@ -444,7 +452,11 @@ page = 4 baroFuelBins = array, U08, 92, [8], "kPa", 1.0, 0, 80, 120, 0 ; Bins for the Baro correction curve baroFuelValues = array, U08, 100, [8], "%", 1.0, 0, 0, 255, 0 ; % Values for same - unused4-92 = array, U08, 108,[20], "%", 1.0, 0.0, 0.0, 255, 0 +;Idle timing advance + idleAdvBins = array, U08, 108, [6], "RPM", 10.0, -50, -500, 500, 0 + idleAdvValues = array, U08, 114, [6], "deg", 1.0, -15, -15, 50, 0 + + unused4-120 = array, U08, 120, [8], "%", 1.0, 0.0, 0.0, 255, 0 ;-------------------------------------------------- ;Start AFR page @@ -1027,6 +1039,9 @@ page = 11 requiresPowerCycle = knock_trigger requiresPowerCycle = knock_pullup requiresPowerCycle = idleUpEnabled + requiresPowerCycle = CTPSEnabled + requiresPowerCycle = CTPSPin + requiresPowerCycle = CTPSPolarity requiresPowerCycle = legacyMAP requiresPowerCycle = fuel2InputPin requiresPowerCycle = fuel2InputPolarity @@ -1236,6 +1251,8 @@ menuDialog = main subMenu = sparkTbl, "Spark Table", 2 subMenu = dwellSettings, "Dwell settings" subMenu = dwell_correction_curve, "Dwell Compensation" + subMenu = idleAdvanceSettings, "Idle Advance Settings" + subMenu = idle_advance_curve, "Idle Advance" { idleAdvEnabled >= 1 } subMenu = iat_retard_curve, "IAT Retard" subMenu = clt_advance_curve, "Cold Advance" ;subMenu = knockSettings, "Knock Settings" @@ -1248,7 +1265,7 @@ menuDialog = main subMenu = ASE, "Afterstart Enrichment (ASE)" subMenu = std_separator subMenu = idleSettings, "Idle Control" - subMenu = iacClosedLoop_curve, "Idle - Closed loop targets", 7, { iacAlgorithm == 3 || iacAlgorithm == 5 } + subMenu = iacClosedLoop_curve, "Idle - RPM targets", 7, { iacAlgorithm == 3 || iacAlgorithm == 5 || idleAdvEnabled >= 1 } subMenu = iacPwm_curve, "Idle - PWM Duty Cycle", 7, { iacAlgorithm == 2 } subMenu = iacPwmCrank_curve, "Idle - PWM Cranking Duty Cycle", 7, { iacAlgorithm == 2 } subMenu = iacStep_curve, "Idle - Stepper Motor", 7, { iacAlgorithm == 4 } @@ -1361,7 +1378,10 @@ menuDialog = main iacCLmaxDuty= "When using closed loop idle control, this is the maximum duty cycle that the PID loop will allow. Combined with the minimum value, this specifies the working range of your idle valve" iacFastTemp = "Below this temperature, the idle output will be high (On). Above this temperature, it will turn off." idleUpPolarity = "Normal polarity is a ground switch where an earthed signal activates the Idle Up. The internal pullup will be enabled with Normal polarity. \n Inverted may be used if a 5v signal is used to enable the Idle Up." + CTPSPolarity = "Normal polarity is a ground switch where an earthed signal activates the closed throttle position. The internal pullup will be enabled with Normal polarity. \n Inverted may be used if a 5v signal is used to enable the closed throttle position." idleUpAdder = "The amount (In either Duty Cycle % or Steps (Depending on the idle control method in use), that the idle control will increase by when Idle Up is active" + idleAdvEnabled = "Added setting adds curve values to current spark table values when user defined idle is active. \n Switched setting overrides spark table values and uses curve values for idle ignition timing. + idleAdvAlgorithm = "Use Throttle position sensor (TPS) or closed throttle position sensor (CTPS) to detect idle state." oddfire2 = "The ATDC angle of channel 2 for oddfire engines. This is relative to the TDC angle of channel 1" oddfire3 = "The ATDC angle of channel 3 for oddfire engines. This is relative to the TDC angle of channel 1 (NOT channel 2)" @@ -1889,6 +1909,15 @@ menuDialog = main field = "Max dwell time", dwellLim, { useDwellLim } field = "Note: Set the maximum dwell time at least 3ms above" field = "your desired dwell time (Including cranking)" + + dialog = idleAdvanceSettings,"Idle Advance Settings",4 + field = "Idle advance mode", idleAdvEnabled + field = "Idle detect mode", idleAdvAlgorithm, { idleAdvEnabled >= 1 } + field = "Active Below RPM", idleAdvRPM, { idleAdvEnabled >= 1 } + field = "Active Below TPS", idleAdvTPS, { idleAdvEnabled >= 1 && idleAdvAlgorithm == 0 } + field = "Closed Throttle Sensor Enabled", CTPSEnabled, { idleAdvEnabled >= 1 && idleAdvAlgorithm == 1 } + field = "Closed Throttle Sensor Pin", CTPSPin, { idleAdvEnabled >= 1 && idleAdvAlgorithm == 1 && CTPSEnabled == 1 } + field = "Closed Throttle Sensor Pin Polarity", CTPSPolarity, { idleAdvEnabled >= 1 && idleAdvAlgorithm == 1 && CTPSEnabled == 1 } dialog = rotary_ignition, "Rotary Ignition", 4 field = "Ignition Configuration", rotaryType @@ -2835,6 +2864,14 @@ cmdtestspk450dc = "E\x03\x0C" xBins = cltAdvBins, coolant yBins = cltAdvValues +; Idle RPM target based ignition timing + curve = idle_advance_curve, "Idle Advance" + columnLabel = "RPM Delta", "Advance" + xAxis = -500, 500, 5 + yAxis = -15, 50, 5 + xBins = idleAdvBins, CLIdleDelta + yBins = idleAdvValues + ; Curves for idle control ; Standard duty table for PWM valves curve = iacPwm_curve, "IAC PWM Duty" @@ -2874,7 +2911,7 @@ cmdtestspk450dc = "E\x03\x0C" xBins = iacCrankBins, coolant yBins = iacCrankSteps - curve = iacClosedLoop_curve, "IAC Closed Loop Targets" + curve = iacClosedLoop_curve, "Idle RPM Targets" columnLabel = "Coolant Temperature", "Motor" xAxis = -40, 120, 6 yAxis = 0, 2000, 4 @@ -3469,8 +3506,8 @@ cmdtestspk450dc = "E\x03\x0C" entry = hardLimitOn , "Hard Limiter", int, "%d" entry = idleControlOn, "Idle Control", int, "%d" entry = idleLoad, "IAC value", int, "%d" - entry = CLIdleTarget, "Idle Target RPM", int, "%%d", { iacAlgorithm == 3 || iacAlgorithm == 5 } ;Only show for closed loop idle modes - entry = CLIdleDelta, "Idle RPM Delta", int, "%d", { iacAlgorithm == 3 || iacAlgorithm == 5 } ;Only show for closed loop idle modes + entry = CLIdleTarget, "Idle Target RPM", int, "%%d", { iacAlgorithm == 3 || iacAlgorithm == 5 || idleAdvEnabled >= 1 } ;Only show for closed loop idle modes and if idle advance is enabled + entry = CLIdleDelta, "Idle RPM Delta", int, "%d", { iacAlgorithm == 3 || iacAlgorithm == 5 || idleAdvEnabled >= 1 } ;Only show for closed loop idle modes and if idle advance is enabled entry = baro, "Baro Pressure",int, "%d" entry = nitrousOn, "Nitrous", int, "%d", { n2o_enable > 0 } entry = syncLossCounter, "Sync Loss #", int, "%d" diff --git a/speeduino/corrections.h b/speeduino/corrections.h index 9cd647a8..f7afe22e 100644 --- a/speeduino/corrections.h +++ b/speeduino/corrections.h @@ -28,6 +28,7 @@ static inline int8_t correctionFlexTiming(int8_t); static inline int8_t correctionIATretard(int8_t); static inline int8_t correctionBaro(int8_t); static inline int8_t correctionCLTadvance(int8_t); +static inline int8_t correctionIdleAdvance(int8_t); static inline int8_t correctionSoftRevLimit(int8_t); static inline int8_t correctionNitrous(int8_t); static inline int8_t correctionSoftLaunch(int8_t); diff --git a/speeduino/corrections.ino b/speeduino/corrections.ino index 626c2630..7c00c1a0 100644 --- a/speeduino/corrections.ino +++ b/speeduino/corrections.ino @@ -472,6 +472,7 @@ int8_t correctionsIgn(int8_t base_advance) advance = correctionFlexTiming(base_advance); advance = correctionIATretard(advance); advance = correctionCLTadvance(advance); + advance = correctionIdleAdvance(advance); advance = correctionSoftRevLimit(advance); advance = correctionNitrous(advance); advance = correctionSoftLaunch(advance); @@ -480,7 +481,7 @@ int8_t correctionsIgn(int8_t base_advance) //Fixed timing check must go last advance = correctionFixedTiming(advance); - advance = correctionCrankingFixedTiming(advance); //This overrrides the regular fixed timing, must come last + advance = correctionCrankingFixedTiming(advance); //This overrides the regular fixed timing, must come last return advance; } @@ -532,6 +533,34 @@ static inline int8_t correctionCLTadvance(int8_t advance) return ignCLTValue; } +static inline int8_t correctionIdleAdvance(int8_t advance) +{ + + int8_t ignIdleValue = advance; + //Adjust the advance based on idle target rpm. + if(configPage2.idleAdvEnabled >= 1) + { + currentStatus.CLIdleTarget = (byte)table2D_getValue(&idleTargetTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //All temps are offset by 40 degrees + int idleRPMdelta = (currentStatus.CLIdleTarget - currentStatus.RPM / 10) + 50; + // Limit idle rpm delta between -500rpm - 500rpm + if(idleRPMdelta > 100) { idleRPMdelta = 100; } + if(idleRPMdelta < 0) { idleRPMdelta = 0; } + if(configPage2.idleAdvAlgorithm == 0 && ((currentStatus.RPM < (unsigned int)(configPage2.idleAdvRPM * 100)) && (currentStatus.TPS < configPage2.idleAdvTPS))) // TPS based idle state + { + int8_t advanceIdleAdjust = (int16_t)(table2D_getValue(&idleAdvanceTable, idleRPMdelta)) - 15; + if(configPage2.idleAdvEnabled == 1) { ignIdleValue = (advance + advanceIdleAdjust); } + else if(configPage2.idleAdvEnabled == 2) { ignIdleValue = advanceIdleAdjust; } + } + else if(configPage2.idleAdvAlgorithm == 1 && (currentStatus.RPM < (unsigned int)(configPage2.idleAdvRPM * 100) && currentStatus.CTPSActive == 1)) // closed throttle position sensor (CTPS) based idle state + { + int8_t advanceIdleAdjust = (int16_t)(table2D_getValue(&idleAdvanceTable, idleRPMdelta)) - 15; + if(configPage2.idleAdvEnabled == 1) { ignIdleValue = (advance + advanceIdleAdjust); } + else if(configPage2.idleAdvEnabled == 2) { ignIdleValue = advanceIdleAdjust; } + } + } + return ignIdleValue; +} + static inline int8_t correctionSoftRevLimit(int8_t advance) { byte ignSoftRevValue = advance; diff --git a/speeduino/globals.h b/speeduino/globals.h index e1f92a1f..edbe1b7a 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -283,7 +283,8 @@ struct table2D injectorVCorrectionTable; //6 bin injector voltage correction (2D struct table2D IATDensityCorrectionTable; //9 bin inlet air temperature density correction (2D) struct table2D baroFuelTable; //8 bin baro correction curve (2D) struct table2D IATRetardTable; //6 bin ignition adjustment based on inlet air temperature (2D) -struct table2D IDLEAdvanceTable; //6 bin idle advance adjustment table based on RPM difference (2D) +struct table2D idleTargetTable; //10 bin idle target table for idle timing (2D) +struct table2D idleAdvanceTable; //6 bin idle advance adjustment table based on RPM difference (2D) struct table2D CLTAdvanceTable; //6 bin ignition adjustment based on coolant temperature (2D) struct table2D rotarySplitTable; //8 bin ignition split curve for rotary leading/trailing (2D) struct table2D flexFuelTable; //6 bin flex fuel correction table for fuel adjustments (2D) @@ -437,6 +438,7 @@ struct statuses { byte idleDuty; /**< The current idle duty cycle amount if PWM idle is selected and active */ byte CLIdleTarget; /**< The target idle RPM (when closed loop idle control is active) */ bool idleUpActive; /**< Whether the externally controlled idle up is currently active */ + bool CTPSActive; /**< Whether the externally controlled closed throttle position sensor is currently active */ bool fanOn; /**< Whether or not the fan is turned on */ volatile byte ethanolPct; /**< Ethanol reading (if enabled). 0 = No ethanol, 100 = pure ethanol. Eg E85 = 85. */ unsigned long AEEndTime; /**< The target end time used whenever AE is turned on */ @@ -603,7 +605,16 @@ struct config2 { byte aseBins[4]; //Afterstart enrichment temp axis byte primePulse[4]; //Priming pulsewidth byte primeBins[4]; //Priming temp axis - byte unused2_91[37]; + + byte CTPSPin : 6; + byte CTPSPolarity : 1; + byte CTPSEnabled : 1; + byte idleAdvEnabled : 2; + byte idleAdvAlgorithm : 1; + byte idleUnused : 5; + byte idleAdvRPM; + byte idleAdvTPS; + byte unused2_95[33]; #if defined(CORE_AVR) }; @@ -688,7 +699,10 @@ struct config4 { byte baroFuelBins[8]; byte baroFuelValues[8]; - byte unused2_91[20]; + byte idleAdvBins[6]; + byte idleAdvValues[6]; + + byte unused4_120[8]; #if defined(CORE_AVR) }; @@ -1021,6 +1035,7 @@ byte pinFuelPump; //Fuel pump on/off byte pinIdle1; //Single wire idle control byte pinIdle2; //2 wire idle control (Not currently used) byte pinIdleUp; //Input for triggering Idle Up +byte pinCTPS; //Input for triggering closed throttle state byte pinFuel2Input; //Input for switching to the 2nd fuel table byte pinSpareTemp1; // Future use only byte pinSpareTemp2; // Future use only diff --git a/speeduino/init.ino b/speeduino/init.ino index 6d2016f5..f278b19a 100644 --- a/speeduino/init.ino +++ b/speeduino/init.ino @@ -122,6 +122,16 @@ void initialiseAll() CLTAdvanceTable.xSize = 6; CLTAdvanceTable.values = (byte*)configPage4.cltAdvValues; CLTAdvanceTable.axisX = configPage4.cltAdvBins; + idleTargetTable.valueSize = SIZE_BYTE; + idleTargetTable.axisSize = SIZE_BYTE; //Set this table to use byte axis bins + idleTargetTable.xSize = 10; + idleTargetTable.values = configPage6.iacCLValues; + idleTargetTable.axisX = configPage6.iacBins; + idleAdvanceTable.valueSize = SIZE_BYTE; + idleAdvanceTable.axisSize = SIZE_BYTE; //Set this table to use byte axis bins + idleAdvanceTable.xSize = 6; + idleAdvanceTable.values = (byte*)configPage4.idleAdvValues; + idleAdvanceTable.axisX = configPage4.idleAdvBins; rotarySplitTable.valueSize = SIZE_BYTE; rotarySplitTable.axisSize = SIZE_BYTE; //Set this table to use byte axis bins rotarySplitTable.xSize = 8; @@ -1962,6 +1972,9 @@ void setPinMapping(byte boardID) //Currently there's no default pin for Idle Up pinIdleUp = pinTranslate(configPage2.idleUpPin); + //Currently there's no default pin for closed throttle position sensor + pinCTPS = pinTranslate(configPage2.CTPSPin); + /* Reset control is a special case. If reset control is enabled, it needs its initial state set BEFORE its pinMode. If that doesn't happen and reset control is in "Serial Command" mode, the Arduino will end up in a reset loop because the control pin will go low as soon as the pinMode is set to OUTPUT. */ @@ -2079,6 +2092,11 @@ void setPinMapping(byte boardID) if (configPage2.idleUpPolarity == 0) { pinMode(pinIdleUp, INPUT_PULLUP); } //Normal setting else { pinMode(pinIdleUp, INPUT); } //inverted setting } + if(configPage2.CTPSEnabled > 0) + { + if (configPage2.CTPSPolarity == 0) { pinMode(pinCTPS, INPUT_PULLUP); } //Normal setting + else { pinMode(pinCTPS, INPUT); } //inverted setting + } if(configPage10.fuel2Mode == FUEL2_MODE_INPUT_SWITCH) { if (configPage10.fuel2InputPullup == true) { pinMode(pinFuel2Input, INPUT_PULLUP); } //With pullup diff --git a/speeduino/sensors.ino b/speeduino/sensors.ino index b8cdc360..44be6435 100644 --- a/speeduino/sensors.ino +++ b/speeduino/sensors.ino @@ -307,6 +307,13 @@ void readTPS() currentStatus.TPS = map(tempADC, configPage2.tpsMax, configPage2.tpsMin, 0, 100); } + //Check whether the closed throttle position sensor is active + if(configPage2.CTPSEnabled == true) + { + if(configPage2.CTPSPolarity == 0) { currentStatus.CTPSActive = !digitalRead(pinCTPS); } //Normal mode (ground switched) + else { currentStatus.CTPSActive = digitalRead(pinCTPS); } //Inverted mode (5v activates closed throttle position sensor) + } + else { currentStatus.CTPSActive = 0; } TPS_time = micros(); }