Allow min and max duty cycles for closed loop idle and boost

This commit is contained in:
Josh Stewart 2017-02-20 17:57:46 +11:00
parent a881ddc405
commit 0d055dc7f1
4 changed files with 97 additions and 80 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -17,18 +17,18 @@ integerPID idlePID(&currentStatus.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() { }