diff --git a/reference/speeduino.ini b/reference/speeduino.ini index 1501d19..c9ee09f 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -199,24 +199,27 @@ page = 2 dutyLim = scalar, U08, 40, "%", 1.0, 0.0, 0.0, 100.0, 0 flexFreqLow = scalar, U08, 41, "Hz", 1.0, 0.0, 0.0, 250.0, 0 flexFreqHigh = scalar, U08, 42, "Hz", 1.0, 0.0, 0.0, 250.0, 0 - taeColdM = scalar, U08, 43, "%", 1.0, 0.0, 0.0, 250.0, 0 - tpsMin = scalar, U08, 44, "ADC", 1.0, 0.0, 0.0, 255.0, 0 - tpsMax = scalar, U08, 45, "ADC", 1.0, 0.0, 0.0, 255.0, 0 - mapMin = scalar, U08, 46, "kpa", 1.0, 0.0, 0.0, 255.0, 0 - mapMax = scalar, U16, 47, "kpa", 1.0, 0.0, 0.0, 25500, 0 - fpPrime = scalar, U08, 49, "s", 1.0, 0.0, 0.0, 255.0, 0 - stoich = scalar, U08, 50, ":1", 0.1, 0.0, 0.0, 25.5, 1 - oddfire2 = scalar, U16, 51, "deg", 1.0, 0.0, 0.0, 720, 0 ; * ( 2 byte) - oddfire3 = scalar, U16, 53, "deg", 1.0, 0.0, 0.0, 720, 0 ; * ( 2 byte) - oddfire4 = scalar, U16, 55, "deg", 1.0, 0.0, 0.0, 720, 0 ; * ( 2 byte) + + tpsMin = scalar, U08, 43, "ADC", 1.0, 0.0, 0.0, 255.0, 0 + tpsMax = scalar, U08, 44, "ADC", 1.0, 0.0, 0.0, 255.0, 0 + mapMin = scalar, U08, 45, "kpa", 1.0, 0.0, 0.0, 255.0, 0 + mapMax = scalar, U16, 46, "kpa", 1.0, 0.0, 0.0, 25500, 0 + fpPrime = scalar, U08, 48, "s", 1.0, 0.0, 0.0, 255.0, 0 + stoich = scalar, U08, 49, ":1", 0.1, 0.0, 0.0, 25.5, 1 + oddfire2 = scalar, U16, 50, "deg", 1.0, 0.0, 0.0, 720, 0 ; * ( 2 byte) + oddfire3 = scalar, U16, 52, "deg", 1.0, 0.0, 0.0, 720, 0 ; * ( 2 byte) + oddfire4 = scalar, U16, 54, "deg", 1.0, 0.0, 0.0, 720, 0 ; * ( 2 byte) - flexFuelLow = scalar, U08, 57, "%", 1.0, 0.0, 0.0, 250.0, 0 - flexFuelHigh = scalar, U08, 58, "%", 1.0, 0.0, 0.0, 250.0, 0 - flexAdvLow = scalar, U08, 59, "Deg", 1.0, 0.0, 0.0, 250.0, 0 - flexAdvHigh = scalar, U08, 60, "Deg", 1.0, 0.0, 0.0, 250.0, 0 - unused2-61 = scalar, U08, 61, "RPM", 100.0, 0.0, 100, 25500, 0 - unused2-62 = scalar, U08, 62, "RPM", 100.0, 0.0, 100, 25500, 0 - unused2-63 = scalar, U08, 63, "RPM", 100.0, 0.0, 100, 25500, 0 + flexFuelLow = scalar, U08, 56, "%", 1.0, 0.0, 0.0, 250.0, 0 + flexFuelHigh = scalar, U08, 57, "%", 1.0, 0.0, 0.0, 250.0, 0 + flexAdvLow = scalar, U08, 58, "Deg", 1.0, 0.0, 0.0, 250.0, 0 + flexAdvHigh = scalar, U08, 59, "Deg", 1.0, 0.0, 0.0, 250.0, 0 + + iacCLminDuty = scalar, U08, 60, "%", 1.0, 0.0, 0.0, 100.0, 0 ; Minimum and maximum duty cycles when using closed loop idle + iacCLmaxDuty = scalar, U08, 61, "%", 1.0, 0.0, 0.0, 100.0, 0 + boostMinDuty = scalar, U08, 62, "%", 1.0, 0.0, 0.0, 100.0, 0 ; Minimum and maximum duty cycles for boost control + boostMaxDuty = scalar, U08, 63, "%", 1.0, 0.0, 0.0, 100.0, 0 + ;-------------------------------------------------- ;Start Ignition table (Page 3) @@ -671,6 +674,10 @@ page = 10 requiresPowerCycle = oddfire2 requiresPowerCycle = oddfire3 requiresPowerCycle = oddfire4 + requiresPowerCycle = iacCLminDuty + requiresPowerCycle = iacCLmaxDuty + requiresPowerCycle = boostMinDuty + requiresPowerCycle = boostMaxDuty defaultValue = pinLayout, 1 defaultValue = TrigPattern, 0 @@ -702,6 +709,10 @@ page = 10 defaultValue = flexAdvHigh, 13 defaultValue = fuelPumpPin, 0 defaultValue = fanPin, 0 + defaultValue = iacCLminDuty, 0 + defaultValue = iacCLmaxDuty, 100 + defaultValue = boostMinDuty, 0 + defaultValue = boostMaxDuty, 100 [Menu] @@ -847,13 +858,14 @@ menuDialog = main iacStepTime = "Time between each stepper motor step.\nIncrease this if the motor appears to behave intermittently." iacStepHome = "On startup the stepper motor moves this many steps to return to its home position. Set this value to a few more than the actual number to ensure the motor has returned to its full position." iacStepHyster = "The minimum number of steps to move in any one go." - - 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)" - oddfire4 = "The ATDC angle of channel 4 for oddfire engines. This is relative to the TDC angle of channel 1 (NOT channel 3)" - iacAlgorithm = "Selects method of idle control.\nNone = no idle control valve.\nOn/Off valve.\nPWM valve (2,3 wire).\nStepper Valve (4,6,8 wire)." iacPWMdir = "Normal PWM valves increase RPM with higher duty. If RPM decreases with higher duty then select Reverse" + iacCLminDuty= "When using closed loop idle control, this is the minimum duty cycle that the PID loop will allow. Combined with the maximum value, this specifies the working range of your idle valve + 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 + + 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)" + oddfire4 = "The ATDC angle of channel 4 for oddfire engines. This is relative to the TDC angle of channel 1 (NOT channel 3)" dfcoRPM = "The RPM above which DFCO will be active. Typically set a few hundred RPM above maximum idle speed" dfcoHyster = "Hysteresis for DFCO RPM. 200-300 RPM is typical for this, however a higher value may be needed if the RPM is fluctuating around the cutout speed" @@ -1071,6 +1083,8 @@ menuDialog = main field = "P", idleKP, { iacAlgorithm == 3 } field = "I", idleKI, { iacAlgorithm == 3 } field = "D", idleKD, { iacAlgorithm == 3 } + field = "Minimum valve duty", iacCLminDuty, { iacAlgorithm == 3 } + field = "Maximum valve duty", iacCLmaxDuty, { iacAlgorithm == 3 } dialog = idleSettings, "Idle Settings" topicHelp = "http://speeduino.com/wiki/index.php/Idle" @@ -1215,6 +1229,8 @@ menuDialog = main field = "P", boostKP, { boostEnabled } field = "I", boostKI, { boostEnabled } field = "D", boostKD, { boostEnabled } + field = "Valve minimum duty cycle", boostMinDuty, { boostEnabled } + field = "Valve maximum duty cycle", boostMaxDuty, { boostEnabled } dialog = vvtSettings, "VVT Control" field = "VVT Control Enabled", vvtEnabled diff --git a/speeduino/auxiliaries.ino b/speeduino/auxiliaries.ino index 69f24d2..594758f 100644 --- a/speeduino/auxiliaries.ino +++ b/speeduino/auxiliaries.ino @@ -48,7 +48,7 @@ void initialiseAuxPWM() //TIMSK1 |= (1 << OCIE1A); //Turn on the A compare unit (ie turn on the interrupt) //Shouldn't be needed with closed loop as its turned on below TIMSK1 |= (1 << OCIE1B); //Turn on the B compare unit (ie turn on the interrupt) - boostPID.SetOutputLimits(0, boost_pwm_max_count); + boostPID.SetOutputLimits(percentage(configPage1.boostMinDuty, boost_pwm_max_count) , percentage(configPage1.boostMaxDuty, boost_pwm_max_count)); boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); boostPID.SetMode(AUTOMATIC); //Turn PID on diff --git a/speeduino/globals.h b/speeduino/globals.h index fe166f5..dd9894a 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -279,7 +279,6 @@ struct config1 { byte dutyLim; byte flexFreqLow; //Lowest valid frequency reading from the flex sensor byte flexFreqHigh; //Highest valid frequency reading from the flex sensor - byte taeColdM; byte tpsMin; byte tpsMax; byte mapMin; @@ -293,9 +292,11 @@ struct config1 { byte flexFuelHigh; //Fuel % to be used for the highest ethanol reading (Typically 163%) byte flexAdvLow; //Additional advance (in degrees) at lowest ethanol reading (Typically 0) byte flexAdvHigh; //Additional advance (in degrees) at highest ethanol reading (Varies, usually 10-20) - byte unused61; - byte unused62; - byte unused63; + + byte iacCLminDuty; + byte iacCLmaxDuty; + byte boostMinDuty; + byte boostMaxDuty; }; diff --git a/speeduino/idle.ino b/speeduino/idle.ino index 04a551f..7458fc7 100644 --- a/speeduino/idle.ino +++ b/speeduino/idle.ino @@ -17,18 +17,18 @@ integerPID idlePID(¤tStatus.longRPM, &idle_pwm_target_value, &idle_cl_targ void initialiseIdle() { -//By default, turn off the PWM interrupt (It gets turned on below if needed) +//By default, turn off the PWM interrupt (It gets turned on below if needed) #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) TIMSK4 &= ~(1 << OCIE4C); // Disable timer channel for idle #endif - + //Initialising comprises of setting the 2D tables with the relevant values from the config pages switch(configPage4.iacAlgorithm) { case 0: //Case 0 is no idle control ('None') break; - + case 1: //Case 1 is on/off idle control if (currentStatus.coolant < configPage4.iacFastTemp) @@ -36,34 +36,14 @@ void initialiseIdle() digitalWrite(pinIdle1, HIGH); } break; - + case 2: //Case 2 is PWM open loop iacPWMTable.xSize = 10; iacPWMTable.valueSize = SIZE_BYTE; iacPWMTable.values = configPage4.iacOLPWMVal; iacPWMTable.axisX = configPage4.iacBins; - - iacCrankDutyTable.xSize = 4; - iacCrankDutyTable.valueSize = SIZE_BYTE; - iacCrankDutyTable.values = configPage4.iacCrankDuty; - iacCrankDutyTable.axisX = configPage4.iacCrankBins; - - idle_pin_port = portOutputRegister(digitalPinToPort(pinIdle1)); - idle_pin_mask = digitalPinToBitMask(pinIdle1); - idle2_pin_port = portOutputRegister(digitalPinToPort(pinIdle2)); - idle2_pin_mask = digitalPinToBitMask(pinIdle2); - idle_pwm_max_count = 1000000L / (16 * configPage3.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz - enableIdle(); - break; - - case 3: - //Case 3 is PWM closed loop - iacClosedLoopTable.xSize = 10; - iacClosedLoopTable.valueSize = SIZE_BYTE; - iacClosedLoopTable.values = configPage4.iacCLValues; - iacClosedLoopTable.axisX = configPage4.iacBins; - + iacCrankDutyTable.xSize = 4; iacCrankDutyTable.valueSize = SIZE_BYTE; iacCrankDutyTable.values = configPage4.iacCrankDuty; @@ -74,39 +54,59 @@ void initialiseIdle() idle2_pin_port = portOutputRegister(digitalPinToPort(pinIdle2)); idle2_pin_mask = digitalPinToBitMask(pinIdle2); idle_pwm_max_count = 1000000L / (16 * configPage3.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz - idlePID.SetOutputLimits(0, idle_pwm_max_count); + enableIdle(); + break; + + case 3: + //Case 3 is PWM closed loop + iacClosedLoopTable.xSize = 10; + iacClosedLoopTable.valueSize = SIZE_BYTE; + iacClosedLoopTable.values = configPage4.iacCLValues; + iacClosedLoopTable.axisX = configPage4.iacBins; + + iacCrankDutyTable.xSize = 4; + iacCrankDutyTable.valueSize = SIZE_BYTE; + iacCrankDutyTable.values = configPage4.iacCrankDuty; + iacCrankDutyTable.axisX = configPage4.iacCrankBins; + + idle_pin_port = portOutputRegister(digitalPinToPort(pinIdle1)); + idle_pin_mask = digitalPinToBitMask(pinIdle1); + idle2_pin_port = portOutputRegister(digitalPinToPort(pinIdle2)); + idle2_pin_mask = digitalPinToBitMask(pinIdle2); + idle_pwm_max_count = 1000000L / (16 * configPage3.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz + idlePID.SetOutputLimits(percentage(configPage1.iacCLminDuty, idle_pwm_max_count), percentage(configPage1.iacCLmaxDuty, idle_pwm_max_count)); idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD); idlePID.SetMode(AUTOMATIC); //Turn PID on break; - + case 4: //Case 2 is Stepper open loop iacStepTable.xSize = 10; iacStepTable.valueSize = SIZE_BYTE; iacStepTable.values = configPage4.iacOLStepVal; iacStepTable.axisX = configPage4.iacBins; - + iacCrankStepsTable.xSize = 4; iacCrankStepsTable.values = configPage4.iacCrankSteps; iacCrankStepsTable.axisX = configPage4.iacCrankBins; iacStepTime = configPage4.iacStepTime * 1000; - + //homeStepper(); //Returns the stepper to the 'home' position completedHomeSteps = 0; idleStepper.stepperStatus = SOFF; break; - + case 5: //Case 5 is Stepper closed loop iacClosedLoopTable.xSize = 10; iacClosedLoopTable.values = configPage4.iacCLValues; iacClosedLoopTable.axisX = configPage4.iacBins; - + iacCrankStepsTable.xSize = 4; iacCrankStepsTable.values = configPage4.iacCrankSteps; iacCrankStepsTable.axisX = configPage4.iacCrankBins; iacStepTime = configPage4.iacStepTime * 1000; - + homeStepper(); //Returns the stepper to the 'home' position idleStepper.stepperStatus = SOFF; break; @@ -117,12 +117,12 @@ void initialiseIdle() void idleControl() { if(idleInitComplete != configPage4.iacAlgorithm) { initialiseIdle(); } - + switch(configPage4.iacAlgorithm) { case 0: //Case 0 is no idle control ('None') break; - + case 1: //Case 1 is on/off idle control if ( (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < configPage4.iacFastTemp) //All temps are offset by 40 degrees { @@ -131,7 +131,7 @@ void idleControl() } else if (idleOn) { digitalWrite(pinIdle1, LOW); idleOn = false; } break; - + case 2: //Case 2 is PWM open loop //Check for cranking pulsewidth if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) @@ -151,7 +151,7 @@ void idleControl() idleOn = true; } break; - + case 3: //Case 3 is PWM closed loop //No cranking specific value for closed loop (yet?) idle_cl_target_rpm = table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) * 10; //All temps are offset by 40 degrees @@ -162,7 +162,7 @@ void idleControl() else{ enableIdle(); } //Turn on the C compare unit (ie turn on the interrupt) //idle_pwm_target_value = 104; break; - + case 4: //Case 4 is open 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(idleStepper.stepperStatus == STEPPING || idleStepper.stepperStatus == COOLING) @@ -179,7 +179,7 @@ void idleControl() } else { - //Means we're in COOLING status but have been in this state long enough to + //Means we're in COOLING status but have been in this state long enough to idleStepper.stepperStatus = SOFF; } } @@ -207,11 +207,11 @@ void idleControl() if ( idleStepper.targetIdleStep > (idleStepper.curIdleStep - configPage4.iacStepHyster) && idleStepper.targetIdleStep < (idleStepper.curIdleStep + configPage4.iacStepHyster) ) { return; } //Hysteris check else if(idleStepper.targetIdleStep < idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_BACKWARD); idleStepper.curIdleStep--; }//Sets stepper direction to backwards else if (idleStepper.targetIdleStep > idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_FORWARD); idleStepper.curIdleStep++; }//Sets stepper direction to forwards - + digitalWrite(pinStepperStep, HIGH); idleStepper.stepStartTime = micros(); idleStepper.stepperStatus = STEPPING; - idleOn = true; + idleOn = true; } else if( (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < iacStepTable.axisX[IDLE_TABLE_SIZE-1]) { @@ -224,13 +224,13 @@ void idleControl() if ( idleStepper.targetIdleStep > (idleStepper.curIdleStep - configPage4.iacStepHyster) && idleStepper.targetIdleStep < (idleStepper.curIdleStep + configPage4.iacStepHyster) ) { return; } //Hysteris check else if(idleStepper.targetIdleStep < idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_BACKWARD); idleStepper.curIdleStep--; }//Sets stepper direction to backwards else if (idleStepper.targetIdleStep > idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_FORWARD); idleStepper.curIdleStep++; }//Sets stepper direction to forwards - + digitalWrite(pinStepperStep, HIGH); idleStepper.stepStartTime = micros(); idleStepper.stepperStatus = STEPPING; - idleOn = true; + idleOn = true; } - + break; } } @@ -250,7 +250,7 @@ void homeStepper() delayMicroseconds(iacStepTime); } digitalWrite(pinStepperDir, STEPPER_FORWARD); - idleStepper.curIdleStep = 0; + idleStepper.curIdleStep = 0; idleStepper.targetIdleStep = 0; idleStepper.stepperStatus = SOFF; } @@ -261,7 +261,7 @@ void homeStepper() static inline void disableIdle() { TIMSK4 &= ~(1 << OCIE4C); //Turn off interrupt - digitalWrite(pinIdle1, LOW); + digitalWrite(pinIdle1, LOW); } //Any common functions associated with starting the Idle @@ -275,8 +275,8 @@ ISR(TIMER4_COMPC_vect) { if (idle_pwm_state) { - if (configPage4.iacPWMdir == 0) - { + if (configPage4.iacPWMdir == 0) + { //Normal direction *idle_pin_port &= ~(idle_pin_mask); // Switch pin to low (1 pin mode) if(configPage4.iacChannels) { *idle2_pin_port |= (idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1 @@ -288,12 +288,12 @@ ISR(TIMER4_COMPC_vect) if(configPage4.iacChannels) { *idle2_pin_port &= ~(idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1 } OCR4C = TCNT4 + (idle_pwm_max_count - idle_pwm_cur_value); - idle_pwm_state = false; + idle_pwm_state = false; } else { - if (configPage4.iacPWMdir == 0) - { + if (configPage4.iacPWMdir == 0) + { //Normal direction *idle_pin_port |= (idle_pin_mask); // Switch pin high if(configPage4.iacChannels) { *idle2_pin_port &= ~(idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1 @@ -306,15 +306,15 @@ ISR(TIMER4_COMPC_vect) } OCR4C = TCNT4 + idle_pwm_target_value; idle_pwm_cur_value = idle_pwm_target_value; - idle_pwm_state = true; + idle_pwm_state = true; } - + } #elif defined (CORE_TEENSY) //This function simply turns off the idle PWM and sets the pin low static inline void disableIdle() { - digitalWrite(pinIdle1, LOW); + digitalWrite(pinIdle1, LOW); } static inline void enableIdle() { }