diff --git a/reference/speeduino.ini b/reference/speeduino.ini index d9077b33..91c81044 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -221,7 +221,7 @@ delayAfterPortOpen=1000 ;validateArrayBounds = true blockReadTimeout = 2000 - ;tsWriteBlocks = on + tsWriteBlocks = on interWriteDelay = 1 ;Ignored when tsWriteBlocks is on pageActivationDelay = 10 restrictSquirtRelationship = false ;This requires TS 3.1 or above @@ -688,7 +688,7 @@ page = 6 iacCrankBins = array, U08, 112, [4], "F", 1.8, -22.23, -40, 215, 0 #endif - iacAlgorithm = bits , U08, 116, [0:2], "None", "On/Off", "PWM Open loop", "PWM Closed loop", "Stepper Open Loop", "Stepper Closed Loop", "PWM Closed+Open loop", "INVALID" + iacAlgorithm = bits , U08, 116, [0:2], "None", "On/Off", "PWM Open loop", "PWM Closed loop", "Stepper Open Loop", "Stepper Closed Loop", "PWM Closed+Open loop", "Stepper Closed+Open loop" iacStepTime = bits , U08, 116, [3:5], "INVALID","1", "2", "3", "4", "5", "6","INVALID" iacChannels = bits, U08, 116, [6:6], "1", "2" iacPWMdir = bits , U08, 116, [7:7], "Normal", "Reverse" @@ -1723,13 +1723,13 @@ menuDialog = main subMenu = ASE, "Afterstart Enrichment (ASE)" subMenu = std_separator subMenu = idleSettings, "Idle Control" - subMenu = iacClosedLoop_curve, "Idle - RPM targets", 7, { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6 || idleAdvEnabled >= 1 } + subMenu = iacClosedLoop_curve, "Idle - RPM targets", 7, { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6 || iacAlgorithm == 7 || idleAdvEnabled >= 1 } subMenu = iacPwm_curve, "Idle - PWM Duty Cycle", 7, { iacAlgorithm == 2 || iacAlgorithm == 6} subMenu = iacPwmCrank_curve, "Idle - PWM Cranking Duty Cycle", 7, { iacAlgorithm == 2 || iacAlgorithm == 3 || iacAlgorithm == 6} - subMenu = iacStep_curve, "Idle - Stepper Motor", 7, { iacAlgorithm == 4 } - subMenu = iacStepCrank_curve, "Idle - Stepper Motor Cranking", 7, { iacAlgorithm == 4 || iacAlgorithm == 5 } + subMenu = iacStep_curve, "Idle - Stepper Motor", 7, { iacAlgorithm == 4 || iacAlgorithm == 7 } + subMenu = iacStepCrank_curve, "Idle - Stepper Motor Cranking", 7, { iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 7 } subMenu = std_separator - subMenu = idleUpSettings, "Idle Up Settings", { iacAlgorithm == 2 || iacAlgorithm == 3 || iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 6 } + subMenu = idleUpSettings, "Idle Up Settings", { iacAlgorithm == 2 || iacAlgorithm == 3 || iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 6 || iacAlgorithm == 7 } subMenu = std_separator subMenu = idleAdvanceSettings, "Idle Advance Settings" @@ -2503,12 +2503,12 @@ menuDialog = main panel = pwm_fan_curve, dialog = stepper_idle, "Stepper Idle" - field = "Step time (ms)", iacStepTime, { iacAlgorithm == 4 || iacAlgorithm == 5 } - field = "Cool time (ms)", iacCoolTime, { iacAlgorithm == 4 || iacAlgorithm == 5 } - field = "Home steps", iacStepHome, { iacAlgorithm == 4 || iacAlgorithm == 5 } - field = "Minimum Steps", iacStepHyster, { iacAlgorithm == 4 || iacAlgorithm == 5 } - field = "Don't exceed", iacMaxSteps, { iacAlgorithm == 4 || iacAlgorithm == 5 } - field = "Stepper Inverted", iacStepperInv, { iacAlgorithm == 4 || iacAlgorithm == 5 } + field = "Step time (ms)", iacStepTime, { iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 7 } + field = "Cool time (ms)", iacCoolTime, { iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 7 } + field = "Home steps", iacStepHome, { iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 7 } + field = "Minimum Steps", iacStepHyster, { iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 7 } + field = "Don't exceed", iacMaxSteps, { iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 7 } + field = "Stepper Inverted", iacStepperInv, { iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 7 } dialog = pwm_idle, "PWM Idle" field = "Number of outputs", iacChannels, { iacAlgorithm == 2 || iacAlgorithm == 3 || iacAlgorithm == 6 } @@ -2517,18 +2517,19 @@ menuDialog = main field = "Run before start", iacPWMrun, { iacAlgorithm == 2 || iacAlgorithm == 3 || iacAlgorithm == 6 } dialog = closedloop_idle, "Closed loop Idle" - field = "P", idleKP, { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6} - field = "I", idleKI, { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6} - field = "D", idleKD, { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6} - field = "Minimum valve duty", iacCLminDuty, { iacAlgorithm == 3 || iacAlgorithm == 6} - field = "Maximum valve duty", iacCLmaxDuty, { iacAlgorithm == 3 || iacAlgorithm == 6} - field = "Integeral reset above TPS", iacTPSlimit, { iacAlgorithm == 6 } - field = "Integeral reset RPM Hysteresis", iacRPMlimitHysteresis, { iacAlgorithm == 6 } + displayOnlyField = "# !!! Please note that 1.0 means 100% !!!" + field = "P", idleKP, { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6 || iacAlgorithm == 7 } + field = "I", idleKI, { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6 || iacAlgorithm == 7 } + field = "D", idleKD, { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6 || iacAlgorithm == 7 } + field = "Minimum valve duty", iacCLminDuty, { iacAlgorithm == 3 || iacAlgorithm == 6 } + field = "Maximum valve duty", iacCLmaxDuty, { iacAlgorithm == 3 || iacAlgorithm == 6 } + field = "Integeral reset above TPS", iacTPSlimit, { iacAlgorithm == 6 || iacAlgorithm == 7 } + field = "Integeral reset RPM Hysteresis", iacRPMlimitHysteresis, { iacAlgorithm == 6 || iacAlgorithm == 7 } dialog = idleSettings, "Idle Settings" topicHelp = "https://wiki.speeduino.com/en/configuration/Idle" field = "Idle control type", iacAlgorithm - field = "Crank to run taper", idleTaperTime, { iacAlgorithm == 2 || iacAlgorithm == 4 } + field = "Crank to run taper", idleTaperTime, { iacAlgorithm == 2 || iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 7 } field = "#Fast Idle" field = "Fast idle temp", iacFastTemp, { iacAlgorithm == 1 } panel = pwm_idle @@ -2645,6 +2646,7 @@ menuDialog = main field = " Use dwell map", useDwellMap field = " Running dwell", dwellrun, { useDwellMap == 0 } field = " Spark duration", sparkDur + field = " Dwell scale for repeated spark", ignRptScale, { crankIgnOutRpt } field = "" field = "#Note" field = "The above times are for 12V. Voltage correction" @@ -2673,7 +2675,7 @@ menuDialog = main topicHelp = "https://wiki.speeduino.com/en/configuration/IdleAdvance" panel = idleAdvanceSettings_east panel = idle_advance_curve, { idleAdvEnabled >= 1 } - panel = iacClosedLoop_curve, { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6 || idleAdvEnabled >= 1 } + panel = iacClosedLoop_curve, { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6 || iacAlgorithm == 7|| idleAdvEnabled >= 1 } dialog = rotary_ignition, "Rotary Ignition", 4 @@ -2942,6 +2944,7 @@ menuDialog = main field = "Minimum Cam angle", vvtCLMinAng field = "Maximum Cam angle", vvtCLMaxAng field = "" + displayOnlyField = "# !!! Please note that 1.0 means 100% !!!" field = "Proportional Gain", vvtCLKP field = "Integral Gain", vvtCLKI field = "Differential Gain", vvtCLKD @@ -5041,8 +5044,8 @@ cmdVSSratio6 = "E\x99\x06" 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 || iacAlgorithm == 6 || 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 || iacAlgorithm == 6 || idleAdvEnabled >= 1 } ;Only show for closed loop idle modes and if idle advance is enabled + entry = CLIdleTarget, "Idle Target RPM", int, "%%d", { iacAlgorithm == 3 || iacAlgorithm == 5 || iacAlgorithm == 6 || iacAlgorithm == 7 || 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 || iacAlgorithm == 6 || iacAlgorithm == 7 || 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 = fanStatus, "Fan", int, "%d" diff --git a/speeduino/idle.h b/speeduino/idle.h index c72864d5..5a40e6a3 100644 --- a/speeduino/idle.h +++ b/speeduino/idle.h @@ -12,6 +12,7 @@ #define IAC_ALGORITHM_STEP_OL 4 #define IAC_ALGORITHM_STEP_CL 5 #define IAC_ALGORITHM_PWM_OLCL 6 //Openloop plus closedloop IAC control +#define IAC_ALGORITHM_STEP_OLCL 7 //Openloop plus closedloop IAC control #define STEPPER_FORWARD 0 #define STEPPER_BACKWARD 1 @@ -51,6 +52,7 @@ volatile PORT_TYPE *idleUpOutput_pin_port; volatile PINMASK_TYPE idleUpOutput_pin_mask; volatile bool idle_pwm_state; +bool lastDFCOValue; unsigned int idle_pwm_max_count; //Used for variable PWM frequency volatile unsigned int idle_pwm_cur_value; long idle_pid_target_value; diff --git a/speeduino/idle.ino b/speeduino/idle.ino index f7f60a4d..02d1b45d 100644 --- a/speeduino/idle.ino +++ b/speeduino/idle.ino @@ -26,7 +26,7 @@ static inline void enableIdle() { IDLE_TIMER_ENABLE(); } - else if ( (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OL) ) + else if ( (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OLCL) ) { } @@ -85,6 +85,7 @@ void initialiseIdle() break; case IAC_ALGORITHM_PWM_OLCL: + //Case 6 is PWM closed loop with open loop table used as feed forward iacPWMTable.xSize = 10; iacPWMTable.valueSize = SIZE_BYTE; iacPWMTable.axisSize = SIZE_BYTE; @@ -113,7 +114,8 @@ void initialiseIdle() idlePID.SetOutputLimits(percentage(configPage2.iacCLminDuty, idle_pwm_max_count<<2), percentage(configPage2.iacCLmaxDuty, idle_pwm_max_count<<2)); idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD); idlePID.SetMode(AUTOMATIC); //Turn PID on - + idle_pid_target_value = 0; + idlePID.Initialize(); idleCounter = 0; break; @@ -142,8 +144,10 @@ void initialiseIdle() idlePID.SetOutputLimits(percentage(configPage2.iacCLminDuty, idle_pwm_max_count<<2), percentage(configPage2.iacCLmaxDuty, idle_pwm_max_count<<2)); idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD); idlePID.SetMode(AUTOMATIC); //Turn PID on - + idle_pid_target_value = table2D_getValue(&iacCrankDutyTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); + idlePID.Initialize(); idleCounter = 0; + break; case IAC_ALGORITHM_STEP_OL: @@ -162,9 +166,14 @@ void initialiseIdle() iacStepTime_uS = configPage6.iacStepTime * 1000; iacCoolTime_uS = configPage9.iacCoolTime * 1000; - completedHomeSteps = 0; - idleStepper.curIdleStep = 0; - idleStepper.stepperStatus = SOFF; + if( completedHomeSteps < (configPage6.iacStepHome * 3) ) + { + //Change between modes running make engine stall + completedHomeSteps = 0; + idleStepper.curIdleStep = 0; + idleStepper.stepperStatus = SOFF; + } + if (! configPage9.iacStepperInv) { idleStepper.lessAirDirection = STEPPER_BACKWARD; @@ -194,10 +203,13 @@ void initialiseIdle() iacStepTime_uS = configPage6.iacStepTime * 1000; iacCoolTime_uS = configPage9.iacCoolTime * 1000; - completedHomeSteps = 0; - idleCounter = 0; - idleStepper.curIdleStep = 0; - idleStepper.stepperStatus = SOFF; + if( completedHomeSteps < (configPage6.iacStepHome * 3) ) + { + //Change between modes running make engine stall + completedHomeSteps = 0; + idleStepper.curIdleStep = 0; + idleStepper.stepperStatus = SOFF; + } if (! configPage9.iacStepperInv) { @@ -210,11 +222,63 @@ void initialiseIdle() idleStepper.moreAirDirection = STEPPER_BACKWARD; } - idlePID.SetSampleTime(100); - idlePID.SetOutputLimits(0, (configPage9.iacMaxSteps * 3)<<2); //Maximum number of steps; always less than home steps count. + idlePID.SetSampleTime(250); //4Hz means 250ms + idlePID.SetOutputLimits((configPage6.iacOLStepVal[9]*3)<<1, (configPage9.iacMaxSteps * 3)<<2); //Maximum number of steps; always less than home steps count. idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD); idlePID.SetMode(AUTOMATIC); //Turn PID on configPage6.iacPWMrun = false; // just in case. This needs to be false with stepper idle + idle_pid_target_value = table2D_getValue(&iacClosedLoopTable, (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET)) * 3; + idlePID.Initialize(); + break; + + case IAC_ALGORITHM_STEP_OLCL: + //Case 7 is Stepper closed loop with open loop table used as feed forward + iacStepTable.xSize = 10; + iacStepTable.valueSize = SIZE_BYTE; + iacStepTable.axisSize = SIZE_BYTE; + iacStepTable.values = configPage6.iacOLStepVal; + iacStepTable.axisX = configPage6.iacBins; + + iacClosedLoopTable.xSize = 10; + iacClosedLoopTable.valueSize = SIZE_BYTE; + iacClosedLoopTable.axisSize = SIZE_BYTE; + iacClosedLoopTable.values = configPage6.iacCLValues; + iacClosedLoopTable.axisX = configPage6.iacBins; + + iacCrankStepsTable.xSize = 4; + iacCrankStepsTable.valueSize = SIZE_BYTE; + iacCrankStepsTable.axisSize = SIZE_BYTE; + iacCrankStepsTable.values = configPage6.iacCrankSteps; + iacCrankStepsTable.axisX = configPage6.iacCrankBins; + iacStepTime_uS = configPage6.iacStepTime * 1000; + iacCoolTime_uS = configPage9.iacCoolTime * 1000; + + if( completedHomeSteps < (configPage6.iacStepHome * 3) ) + { + //Change between modes running make engine stall + completedHomeSteps = 0; + idleStepper.curIdleStep = 0; + idleStepper.stepperStatus = SOFF; + } + + if (! configPage9.iacStepperInv) + { + idleStepper.lessAirDirection = STEPPER_BACKWARD; + idleStepper.moreAirDirection = STEPPER_FORWARD; + } + else + { + idleStepper.lessAirDirection = STEPPER_FORWARD; + idleStepper.moreAirDirection = STEPPER_BACKWARD; + } + + idlePID.SetSampleTime(250); //4Hz means 250ms + idlePID.SetOutputLimits((configPage6.iacOLStepVal[9]*3)<<1, (configPage9.iacMaxSteps * 3)<<2); //Maximum number of steps; always less than home steps count. + idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD); + idlePID.SetMode(AUTOMATIC); //Turn PID on + configPage6.iacPWMrun = false; // just in case. This needs to be false with stepper idle + idle_pid_target_value = 0; + idlePID.Initialize(); break; default: @@ -504,7 +568,7 @@ void idleControl() idle_pid_target_value = idle_pwm_target_value << 2; //Resolution increased idlePID.Initialize(); //Update output to smooth transition } - else + else { //Read the OL table as feedforward term FeedForwardTerm = percentage(table2D_getValue(&iacPWMTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET), idle_pwm_max_count<<2); //All temps are offset by 40 degrees @@ -542,7 +606,7 @@ void idleControl() if( (checkForStepping() == false) && (isStepperHomed() == true) ) //Check that homing is complete and that there's not currently a step already taking place. MUST BE IN THIS ORDER! { //Check for cranking pulsewidth - if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) + if( !BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN) ) //If ain't running it means off or cranking { //Currently cranking. Use the cranking table idleStepper.targetIdleStep = table2D_getValue(&iacCrankStepsTable, (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET)) * 3; //All temps are offset by 40 degrees. Step counts are divided by 3 in TS. Multiply back out here @@ -559,9 +623,7 @@ void idleControl() else { //Standard running - //Only do a lookup of the required value around 4 times per second. Any more than this can create too much jitter and require a hyster value that is too high - //We must also have more than zero RPM for the running state - if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_4HZ) && (currentStatus.RPM > 0)) + if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_10HZ) && (currentStatus.RPM > 0)) { if ( runSecsX10 < configPage2.idleTaperTime ) { @@ -595,11 +657,12 @@ void idleControl() else { BIT_CLEAR(currentStatus.spark, BIT_SPARK_IDLE); } break; + case IAC_ALGORITHM_STEP_OLCL: //Case 7 is closed+open loop stepper control case IAC_ALGORITHM_STEP_CL: //Case 5 is closed loop stepper control //First thing to check is whether there is currently a step going on and if so, whether it needs to be turned off if( (checkForStepping() == false) && (isStepperHomed() == true) ) //Check that homing is complete and that there's not currently a step already taking place. MUST BE IN THIS ORDER! { - if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) + if( !BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN) ) //If ain't running it means off or cranking { //Currently cranking. Use the cranking table idleStepper.targetIdleStep = table2D_getValue(&iacCrankStepsTable, (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET)) * 3; //All temps are offset by 40 degrees. Step counts are divided by 3 in TS. Multiply back out here @@ -613,45 +676,78 @@ void idleControl() doStep(); idle_pid_target_value = idleStepper.targetIdleStep << 2; //Resolution increased - idlePID.Initialize(); //Update output to smooth transition + idlePID.ResetIntegeral(); + FeedForwardTerm = idle_pid_target_value; } else { - if( (idleCounter & 31) == 1) + if( BIT_CHECK(LOOP_TIMER, BIT_TIMER_10HZ) ) { - //This only needs to be run very infrequently, once every 32 calls to idleControl(). This is approx. once per second - idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD); - iacStepTime_uS = configPage6.iacStepTime * 1000; - iacCoolTime_uS = configPage9.iacCoolTime * 1000; + currentStatus.CLIdleTarget = (byte)table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //All temps are offset by 40 degrees + idle_cl_target_rpm = (uint16_t)currentStatus.CLIdleTarget * 10; //Multiply the byte target value back out by 10 + if( runSecsX10 < configPage2.idleTaperTime ) + { + uint16_t minValue = table2D_getValue(&iacCrankStepsTable, (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET)) * 3; + if( idle_pid_target_value < minValue<<2 ) { idle_pid_target_value = minValue<<2; } + uint16_t maxValue = idle_pid_target_value>>2; + if( configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OLCL ) { maxValue = table2D_getValue(&iacStepTable, (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET)) * 3; } + + //Tapering between cranking IAC value and running + FeedForwardTerm = map(runSecsX10, 0, configPage2.idleTaperTime, minValue, maxValue)<<2; + idle_pid_target_value = FeedForwardTerm; + } + else if (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OLCL) + { + //Standard running + FeedForwardTerm = (table2D_getValue(&iacStepTable, (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET)) * 3)<<2; //All temps are offset by 40 degrees. Step counts are divided by 3 in TS. Multiply back out here + //reset integeral to zero when TPS is bigger than set value in TS (opening throttle so not idle anymore). OR when RPM higher than Idle Target + RPM Histeresis (comming back from high rpm with throttle closed) + if (((currentStatus.RPM - idle_cl_target_rpm) > configPage2.iacRPMlimitHysteresis*10) || (currentStatus.TPS > configPage2.iacTPSlimit) || lastDFCOValue ) + { + idlePID.ResetIntegeral(); + } + } + else { FeedForwardTerm = idle_pid_target_value; } } - currentStatus.CLIdleTarget = (byte)table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //All temps are offset by 40 degrees - idle_cl_target_rpm = (uint16_t)currentStatus.CLIdleTarget * 10; //All temps are offset by 40 degrees - PID_computed = idlePID.Compute(true); - idleStepper.targetIdleStep = idle_pid_target_value >> 2; //Increase resolution - if(currentStatus.idleUpActive == true) { idleStepper.targetIdleStep += configPage2.idleUpAdder; } //Add Idle Up amount if active + PID_computed = idlePID.Compute(true, FeedForwardTerm); - //limit to the configured max steps. This must include any idle up adder, to prevent over-opening. - if (idleStepper.targetIdleStep > (configPage9.iacMaxSteps * 3) ) + //If DFCO conditions are met keep output from changing + if( (currentStatus.TPS > configPage2.iacTPSlimit) || lastDFCOValue + || ((configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OLCL) && (runSecsX10 < configPage2.idleTaperTime)) ) { - idleStepper.targetIdleStep = configPage9.iacMaxSteps * 3; + idle_pid_target_value = FeedForwardTerm; } + idleStepper.targetIdleStep = idle_pid_target_value>>2; //Increase resolution - doStep(); - idleCounter++; } + if(currentStatus.idleUpActive == true) { idleStepper.targetIdleStep += configPage2.idleUpAdder; } //Add Idle Up amount if active + //limit to the configured max steps. This must include any idle up adder, to prevent over-opening. + if (idleStepper.targetIdleStep > (configPage9.iacMaxSteps * 3) ) + { + idleStepper.targetIdleStep = configPage9.iacMaxSteps * 3; + } + doStep(); + if( ( (uint16_t)configPage9.iacMaxSteps * 3) > 255 ) { currentStatus.idleLoad = idleStepper.curIdleStep / 2; }//Current step count (Divided by 2 for byte) else { currentStatus.idleLoad = idleStepper.curIdleStep; } } //Set or clear the idle active flag if(idleStepper.targetIdleStep != idleStepper.curIdleStep) { BIT_SET(currentStatus.spark, BIT_SPARK_IDLE); } else { BIT_CLEAR(currentStatus.spark, BIT_SPARK_IDLE); } + if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_1HZ)) //Use timer flag instead idle count + { + //This only needs to be run very infrequently, once per second + idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD); + iacStepTime_uS = configPage6.iacStepTime * 1000; + iacCoolTime_uS = configPage9.iacCoolTime * 1000; + } break; default: //There really should be a valid idle type break; } + lastDFCOValue = BIT_CHECK(currentStatus.status1, BIT_STATUS1_DFCO); } @@ -663,7 +759,7 @@ void disableIdle() IDLE_TIMER_DISABLE(); digitalWrite(pinIdle1, LOW); } - else if ((configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OL) ) + else if( (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OLCL) ) { //Only disable the stepper motor if homing is completed if( (checkForStepping() == false) && (isStepperHomed() == true) ) @@ -680,6 +776,7 @@ void disableIdle() { idleStepper.targetIdleStep = configPage9.iacMaxSteps * 3; } + idle_pid_target_value = idleStepper.targetIdleStep<<2; } } BIT_CLEAR(currentStatus.spark, BIT_SPARK_IDLE); //Turn the idle control flag off diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index 5ea09f1c..d8ae4b3f 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -408,7 +408,12 @@ void loop() } //1Hz timer - if( (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_CL) ) { idleControl(); } //Run idlecontrol every loop for stepper idle. + if( (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OL) + || (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_CL) + || (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OLCL) ) + { + idleControl(); //Run idlecontrol every loop for stepper idle. + } //VE and advance calculation were moved outside the sync/RPM check so that the fuel and ignition load value will be accurately shown when RPM=0