Fix issue where staging fuel channels would be active even when not required

This commit is contained in:
Josh Stewart 2023-06-26 10:46:11 +10:00
parent fcb78b2e9f
commit e44f4c7b54
7 changed files with 275 additions and 306 deletions

View File

@ -1661,10 +1661,13 @@ page = 15
defaultValue = airConPwmFanMinDuty, 80
#if CELSIUS
defaultValue = vvtMinClt, 70
defaultValue = fuelTempBins, 0 15 30 45 60 75
#else
defaultValue = vvtMinClt, 160
defaultValue = fuelTempBins, 32 59 86 113 140 157
#endif
defaultValue = vvtDelay, 60
defaultValue = fuelTempValues, 100 100 100 100 100 100
; AFR protection default values
defaultValue = afrProtectEnabled, 0

View File

@ -555,9 +555,6 @@ extern byte triggerInterrupt;
extern byte triggerInterrupt2;
extern byte triggerInterrupt3;
//These need to be here as they are used in both speeduino.ino and scheduler.ino
extern byte channelInjEnabled;
extern int ignition1EndAngle;
extern int ignition2EndAngle;
extern int ignition3EndAngle;
@ -611,7 +608,8 @@ extern volatile byte HWTest_INJ; /**< Each bit in this variable represents
extern volatile byte HWTest_INJ_50pc; /**< Each bit in this variable represents one of the injector channels and it's 50% HW test status */
extern volatile byte HWTest_IGN; /**< Each bit in this variable represents one of the ignition channels and it's HW test status */
extern volatile byte HWTest_IGN_50pc; /**< Each bit in this variable represents one of the ignition channels and it's 50% HW test status */
extern byte maxIgnOutputs; /**< Used for rolling rev limiter to indicate how many total ignition channels should currently be firing */
extern byte maxIgnOutputs; /**< Number of ignition outputs being used by the current tune configuration */
extern byte maxInjOutputs; /**< Number of injection outputs being used by the current tune configuration */
extern byte resetControl; ///< resetControl needs to be here (as global) because using the config page (4) directly can prevent burning the setting

View File

@ -106,9 +106,6 @@ volatile PINMASK_TYPE triggerSec_pin_mask;
volatile PORT_TYPE *triggerThird_pin_port;
volatile PINMASK_TYPE triggerThird_pin_mask;
/// These need to be here as they are used in both speeduino.ino and scheduler.ino
byte channelInjEnabled = 0;
int ignition1EndAngle = 0;
int ignition2EndAngle = 0;
int ignition3EndAngle = 0;
@ -153,8 +150,8 @@ volatile byte HWTest_INJ = 0; /**< Each bit in this variable represents one of t
volatile byte HWTest_INJ_50pc = 0; /**< Each bit in this variable represents one of the injector channels and it's 50% HW test status */
volatile byte HWTest_IGN = 0; /**< Each bit in this variable represents one of the ignition channels and it's HW test status */
volatile byte HWTest_IGN_50pc = 0;
byte maxIgnOutputs = 1; /**< Used for rolling rev limiter to indicate how many total ignition channels should currently be firing */
byte maxIgnOutputs = 1; /**< Number of ignition outputs being used by the current tune configuration */
byte maxInjOutputs = 1; /**< Number of injection outputs being used by the current tune configuration */
//This needs to be here because using the config page directly can prevent burning the setting
byte resetControl = RESET_CONTROL_DISABLED;

View File

@ -450,7 +450,8 @@ void initialiseAll(void)
currentLoopTime = micros_safe();
mainLoopCount = 0;
currentStatus.nSquirts = configPage2.nCylinders / configPage2.divider; //The number of squirts being requested. This is manually overridden below for sequential setups (Due to TS req_fuel calc limitations)
if(configPage2.divider == 0) { currentStatus.nSquirts = 2; } //Safety check.
else { currentStatus.nSquirts = configPage2.nCylinders / configPage2.divider; } //The number of squirts being requested. This is manually overridden below for sequential setups (Due to TS req_fuel calc limitations)
if(currentStatus.nSquirts == 0) { currentStatus.nSquirts = 1; } //Safety check. Should never happen as TS will give an error, but leave in case tune is manually altered etc.
//Calculate the number of degrees between cylinders
@ -458,8 +459,7 @@ void initialiseAll(void)
CRANK_ANGLE_MAX_IGN = 360;
CRANK_ANGLE_MAX_INJ = 360;
channelInjEnabled = 0; // Disable all injectors
BIT_SET(channelInjEnabled, INJ1_CMD_BIT);
maxInjOutputs = 1; // Disable all injectors expect channel 1
ignition1EndAngle = 0;
ignition2EndAngle = 0;
@ -478,6 +478,7 @@ void initialiseAll(void)
channel1IgnDegrees = 0;
channel1InjDegrees = 0;
maxIgnOutputs = 1;
maxInjOutputs = 1;
//Sequential ignition works identically on a 1 cylinder whether it's odd or even fire.
if( (configPage4.sparkMode == IGN_MODE_SEQUENTIAL) && (configPage2.strokes == FOUR_STROKE) ) { CRANK_ANGLE_MAX_IGN = 720; }
@ -489,12 +490,10 @@ void initialiseAll(void)
req_fuel_uS = req_fuel_uS * 2;
}
BIT_SET(channelInjEnabled, INJ1_CMD_BIT);
//Check if injector staging is enabled
if(configPage10.stagingEnabled == true)
{
BIT_SET(channelInjEnabled, INJ2_CMD_BIT);
maxInjOutputs = 2;
channel2InjDegrees = channel1InjDegrees;
}
break;
@ -503,6 +502,7 @@ void initialiseAll(void)
channel1IgnDegrees = 0;
channel1InjDegrees = 0;
maxIgnOutputs = 2;
maxInjOutputs = 2;
if (configPage2.engineType == EVEN_FIRE ) { channel2IgnDegrees = 180; }
else { channel2IgnDegrees = configPage2.oddfire2; }
@ -525,14 +525,10 @@ void initialiseAll(void)
channel2InjDegrees = 0;
}
BIT_SET(channelInjEnabled, INJ1_CMD_BIT);
BIT_SET(channelInjEnabled, INJ2_CMD_BIT);
//Check if injector staging is enabled
if(configPage10.stagingEnabled == true)
{
BIT_SET(channelInjEnabled, INJ3_CMD_BIT);
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
maxInjOutputs = 4;
channel3InjDegrees = channel1InjDegrees;
channel4InjDegrees = channel2InjDegrees;
@ -543,6 +539,7 @@ void initialiseAll(void)
case 3:
channel1IgnDegrees = 0;
maxIgnOutputs = 3;
maxInjOutputs = 3;
if (configPage2.engineType == EVEN_FIRE )
{
//Sequential and Single channel modes both run over 720 crank degrees, but only on 4 stroke engines.
@ -566,7 +563,7 @@ void initialiseAll(void)
}
//For alternating injection, the squirt occurs at different times for each channel
if( (configPage2.injLayout == INJ_SEMISEQUENTIAL) || (configPage2.injLayout == INJ_PAIRED) || (configPage2.strokes == TWO_STROKE) )
if( (configPage2.injLayout == INJ_SEMISEQUENTIAL) || (configPage2.injLayout == INJ_PAIRED) )
{
channel1InjDegrees = 0;
channel2InjDegrees = 120;
@ -589,12 +586,23 @@ void initialiseAll(void)
}
else if (configPage2.injLayout == INJ_SEQUENTIAL)
{
channel1InjDegrees = 0;
channel2InjDegrees = 240;
channel3InjDegrees = 480;
CRANK_ANGLE_MAX_INJ = 720;
currentStatus.nSquirts = 1;
req_fuel_uS = req_fuel_uS * 2;
if(configPage2.strokes == TWO_STROKE)
{
channel1InjDegrees = 0;
channel2InjDegrees = 120;
channel3InjDegrees = 240;
CRANK_ANGLE_MAX_INJ = 360;
}
else
{
req_fuel_uS = req_fuel_uS * 2;
channel1InjDegrees = 0;
channel2InjDegrees = 240;
channel3InjDegrees = 480;
CRANK_ANGLE_MAX_INJ = 720;
}
}
else
{
@ -604,24 +612,18 @@ void initialiseAll(void)
channel3InjDegrees = 240;
}
BIT_SET(channelInjEnabled, INJ1_CMD_BIT);
BIT_SET(channelInjEnabled, INJ2_CMD_BIT);
BIT_SET(channelInjEnabled, INJ3_CMD_BIT);
//Check if injector staging is enabled
if(configPage10.stagingEnabled == true)
{
#if INJ_CHANNELS >= 6
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
BIT_SET(channelInjEnabled, INJ6_CMD_BIT);
maxInjOutputs = 6;
channel4InjDegrees = channel1InjDegrees;
channel5InjDegrees = channel2InjDegrees;
channel6InjDegrees = channel3InjDegrees;
#else
//Staged output is on channel 4
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
maxInjOutputs = 4;
channel4InjDegrees = channel1InjDegrees;
#endif
}
@ -630,6 +632,7 @@ void initialiseAll(void)
channel1IgnDegrees = 0;
channel1InjDegrees = 0;
maxIgnOutputs = 2; //Default value for 4 cylinder, may be changed below
maxInjOutputs = 2;
if (configPage2.engineType == EVEN_FIRE )
{
channel2IgnDegrees = 180;
@ -684,8 +687,7 @@ void initialiseAll(void)
channel3InjDegrees = 360;
channel4InjDegrees = 540;
BIT_SET(channelInjEnabled, INJ3_CMD_BIT);
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
maxInjOutputs = 4;
CRANK_ANGLE_MAX_INJ = 720;
currentStatus.nSquirts = 1;
@ -694,28 +696,19 @@ void initialiseAll(void)
else
{
//Should never happen, but default values
BIT_CLEAR(channelInjEnabled, INJ3_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ4_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ5_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ6_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ7_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ8_CMD_BIT);
maxInjOutputs = 2;
}
//Check if injector staging is enabled
if(configPage10.stagingEnabled == true)
{
BIT_SET(channelInjEnabled, INJ3_CMD_BIT);
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
maxInjOutputs = 4;
if( (configPage2.injLayout == INJ_SEQUENTIAL) || (configPage2.injLayout == INJ_SEMISEQUENTIAL) )
{
//Staging with 4 cylinders semi/sequential requires 8 total channels
#if INJ_CHANNELS >= 8
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
BIT_SET(channelInjEnabled, INJ6_CMD_BIT);
BIT_SET(channelInjEnabled, INJ7_CMD_BIT);
BIT_SET(channelInjEnabled, INJ8_CMD_BIT);
maxInjOutputs = 8;
channel5InjDegrees = channel1InjDegrees;
channel6InjDegrees = channel2InjDegrees;
@ -724,7 +717,7 @@ void initialiseAll(void)
#else
//This is an invalid config as there are not enough outputs to support sequential + staging
//Put the staging output to the non-existant channel 5
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
maxInjOutputs = 5;
channel5InjDegrees = channel1InjDegrees;
#endif
}
@ -735,8 +728,6 @@ void initialiseAll(void)
}
}
BIT_SET(channelInjEnabled, INJ1_CMD_BIT);
BIT_SET(channelInjEnabled, INJ2_CMD_BIT);
break;
case 5:
channel1IgnDegrees = 0;
@ -745,6 +736,7 @@ void initialiseAll(void)
channel4IgnDegrees = 216;
channel5IgnDegrees = 288;
maxIgnOutputs = 5; //Only 4 actual outputs, so that's all that can be cut
maxInjOutputs = 4; //Is updated below to 5 if there are enough channels
if(configPage4.sparkMode == IGN_MODE_SEQUENTIAL)
{
@ -788,10 +780,7 @@ void initialiseAll(void)
channel4InjDegrees = 432;
channel5InjDegrees = 576;
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
#if INJ_CHANNELS >= 6
if(configPage10.stagingEnabled == true) { BIT_SET(channelInjEnabled, INJ6_CMD_BIT); }
#endif
maxInjOutputs = 5;
CRANK_ANGLE_MAX_INJ = 720;
currentStatus.nSquirts = 1;
@ -799,12 +788,8 @@ void initialiseAll(void)
}
#endif
BIT_SET(channelInjEnabled, INJ1_CMD_BIT);
BIT_SET(channelInjEnabled, INJ2_CMD_BIT);
BIT_SET(channelInjEnabled, INJ3_CMD_BIT);
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
#if INJ_CHANNELS >= 5
if(configPage10.stagingEnabled == true) { BIT_SET(channelInjEnabled, INJ5_CMD_BIT); }
#if INJ_CHANNELS >= 6
if(configPage10.stagingEnabled == true) { maxInjOutputs = 6; }
#endif
break;
case 6:
@ -812,6 +797,7 @@ void initialiseAll(void)
channel2IgnDegrees = 120;
channel3IgnDegrees = 240;
maxIgnOutputs = 3;
maxInjOutputs = 3;
#if IGN_CHANNELS >= 6
if( (configPage4.sparkMode == IGN_MODE_SEQUENTIAL))
@ -855,9 +841,7 @@ void initialiseAll(void)
channel5InjDegrees = 480;
channel6InjDegrees = 600;
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
BIT_SET(channelInjEnabled, INJ6_CMD_BIT);
maxInjOutputs = 6;
CRANK_ANGLE_MAX_INJ = 720;
currentStatus.nSquirts = 1;
@ -865,17 +849,13 @@ void initialiseAll(void)
}
else if(configPage10.stagingEnabled == true) //Check if injector staging is enabled
{
BIT_SET(channelInjEnabled, INJ3_CMD_BIT);
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
maxInjOutputs = 6;
if( (configPage2.injLayout == INJ_SEQUENTIAL) || (configPage2.injLayout == INJ_SEMISEQUENTIAL) )
{
//Staging with 4 cylinders semi/sequential requires 8 total channels
#if INJ_CHANNELS >= 8
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
BIT_SET(channelInjEnabled, INJ6_CMD_BIT);
BIT_SET(channelInjEnabled, INJ7_CMD_BIT);
BIT_SET(channelInjEnabled, INJ8_CMD_BIT);
//Staging with 6 cylinders semi/sequential requires 7 total channels
#if INJ_CHANNELS >= 7
maxInjOutputs = 7;
channel5InjDegrees = channel1InjDegrees;
channel6InjDegrees = channel2InjDegrees;
@ -883,17 +863,13 @@ void initialiseAll(void)
channel8InjDegrees = channel4InjDegrees;
#else
//This is an invalid config as there are not enough outputs to support sequential + staging
//Put the staging output to the non-existant channel 5
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
channel5InjDegrees = channel1InjDegrees;
//Put the staging output to the non-existant channel 7
maxInjOutputs = 7;
channel7InjDegrees = channel1InjDegrees;
#endif
}
}
#endif
BIT_SET(channelInjEnabled, INJ1_CMD_BIT);
BIT_SET(channelInjEnabled, INJ2_CMD_BIT);
BIT_SET(channelInjEnabled, INJ3_CMD_BIT);
break;
case 8:
channel1IgnDegrees = 0;
@ -901,6 +877,7 @@ void initialiseAll(void)
channel3IgnDegrees = 180;
channel4IgnDegrees = 270;
maxIgnOutputs = 4;
maxInjOutputs = 4;
if( (configPage4.sparkMode == IGN_MODE_SINGLE))
@ -959,10 +936,7 @@ void initialiseAll(void)
channel7InjDegrees = 540;
channel8InjDegrees = 630;
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
BIT_SET(channelInjEnabled, INJ6_CMD_BIT);
BIT_SET(channelInjEnabled, INJ7_CMD_BIT);
BIT_SET(channelInjEnabled, INJ8_CMD_BIT);
maxInjOutputs = 8;
CRANK_ANGLE_MAX_INJ = 720;
currentStatus.nSquirts = 1;
@ -970,10 +944,6 @@ void initialiseAll(void)
}
#endif
BIT_SET(channelInjEnabled, INJ1_CMD_BIT);
BIT_SET(channelInjEnabled, INJ2_CMD_BIT);
BIT_SET(channelInjEnabled, INJ3_CMD_BIT);
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
break;
default: //Handle this better!!!
channel1InjDegrees = 0;
@ -3616,21 +3586,15 @@ void changeHalfToFullSync(void)
switch (configPage2.nCylinders)
{
case 4:
BIT_SET(channelInjEnabled, INJ3_CMD_BIT);
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
maxInjOutputs = 4;
break;
case 6:
BIT_SET(channelInjEnabled, INJ4_CMD_BIT);
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
BIT_SET(channelInjEnabled, INJ6_CMD_BIT);
maxInjOutputs = 6;
break;
case 8:
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
BIT_SET(channelInjEnabled, INJ6_CMD_BIT);
BIT_SET(channelInjEnabled, INJ7_CMD_BIT);
BIT_SET(channelInjEnabled, INJ8_CMD_BIT);
maxInjOutputs = 8;
break;
default:
@ -3708,8 +3672,7 @@ void changeFullToHalfSync(void)
inj2StartFunction = openInjector2and3;
inj2EndFunction = closeInjector2and3;
}
BIT_CLEAR(channelInjEnabled, INJ3_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ4_CMD_BIT);
maxInjOutputs = 2;
break;
case 6:
@ -3719,9 +3682,7 @@ void changeFullToHalfSync(void)
inj2EndFunction = closeInjector2and5;
inj3StartFunction = openInjector3and6;
inj3EndFunction = closeInjector3and6;
BIT_CLEAR(channelInjEnabled, INJ4_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ5_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ6_CMD_BIT);
maxInjOutputs = 3;
break;
case 8:
@ -3733,10 +3694,7 @@ void changeFullToHalfSync(void)
inj3EndFunction = closeInjector3and7;
inj4StartFunction = openInjector4and8;
inj4EndFunction = closeInjector4and8;
BIT_CLEAR(channelInjEnabled, INJ5_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ6_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ7_CMD_BIT);
BIT_CLEAR(channelInjEnabled, INJ8_CMD_BIT);
maxInjOutputs = 4;
break;
}
}

View File

@ -863,27 +863,27 @@ extern void beginInjectorPriming(void)
if( (primingValue > 0) && (currentStatus.TPS < configPage4.floodClear) )
{
primingValue = primingValue * 100 * 5; //to achieve long enough priming pulses, the values in tuner studio are divided by 0.5 instead of 0.1, so multiplier of 5 is required.
if ( BIT_CHECK(channelInjEnabled, INJ1_CMD_BIT) == true ) { setFuelSchedule1(100, primingValue); }
if ( maxInjOutputs >= 1 ) { setFuelSchedule1(100, primingValue); }
#if (INJ_CHANNELS >= 2)
if ( BIT_CHECK(channelInjEnabled, INJ2_CMD_BIT) == true ) { setFuelSchedule2(100, primingValue); }
if ( maxInjOutputs >= 2 ) { setFuelSchedule2(100, primingValue); }
#endif
#if (INJ_CHANNELS >= 3)
if ( BIT_CHECK(channelInjEnabled, INJ3_CMD_BIT) == true ) { setFuelSchedule3(100, primingValue); }
if ( maxInjOutputs >= 3 ) { setFuelSchedule3(100, primingValue); }
#endif
#if (INJ_CHANNELS >= 4)
if ( BIT_CHECK(channelInjEnabled, INJ4_CMD_BIT) == true ) { setFuelSchedule4(100, primingValue); }
if ( maxInjOutputs >= 4 ) { setFuelSchedule4(100, primingValue); }
#endif
#if (INJ_CHANNELS >= 5)
if ( BIT_CHECK(channelInjEnabled, INJ5_CMD_BIT) == true ) { setFuelSchedule5(100, primingValue); }
if ( maxInjOutputs >= 5 ) { setFuelSchedule5(100, primingValue); }
#endif
#if (INJ_CHANNELS >= 6)
if ( BIT_CHECK(channelInjEnabled, INJ6_CMD_BIT) == true ) { setFuelSchedule6(100, primingValue); }
if ( maxInjOutputs >= 6 ) { setFuelSchedule6(100, primingValue); }
#endif
#if (INJ_CHANNELS >= 7)
if ( BIT_CHECK(channelInjEnabled, INJ7_CMD_BIT) == true) { setFuelSchedule7(100, primingValue); }
if ( maxInjOutputs >= 7 ) { setFuelSchedule7(100, primingValue); }
#endif
#if (INJ_CHANNELS >= 8)
if ( BIT_CHECK(channelInjEnabled, INJ8_CMD_BIT) == true ) { setFuelSchedule8(100, primingValue); }
if ( maxInjOutputs >= 8 ) { setFuelSchedule8(100, primingValue); }
#endif
}
}

View File

@ -20,6 +20,7 @@ void loop(void);
uint16_t PW(int REQ_FUEL, byte VE, long MAP, uint16_t corrections, int injOpen);
byte getVE1(void);
byte getAdvance1(void);
void calculateStaging(uint32_t);
extern uint16_t req_fuel_uS; /**< The required fuel variable (As calculated by TunerStudio) in uS */
extern uint16_t inj_opentime_uS; /**< The injector opening time. This is set within Tuner Studio, but stored here in uS rather than mS */

View File

@ -494,198 +494,14 @@ void loop(void)
doCrankSpeedCalcs(); //In crankMaths.ino
//Check that the duty cycle of the chosen pulsewidth isn't too high.
unsigned long pwLimit = percentage(configPage2.dutyLim, revolutionTime); //The pulsewidth limit is determined to be the duty cycle limit (Eg 85%) by the total time it takes to perform 1 revolution
uint32_t pwLimit = percentage(configPage2.dutyLim, revolutionTime); //The pulsewidth limit is determined to be the duty cycle limit (Eg 85%) by the total time it takes to perform 1 revolution
//Handle multiple squirts per rev
if (configPage2.strokes == FOUR_STROKE) { pwLimit = pwLimit * 2 / currentStatus.nSquirts; }
else { pwLimit = pwLimit / currentStatus.nSquirts; }
//Apply the pwLimit if staging is disabled and engine is not cranking
if( (!BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) && (configPage10.stagingEnabled == false) ) { if (currentStatus.PW1 > pwLimit) { currentStatus.PW1 = pwLimit; } }
//Calculate staging pulsewidths if used
//To run staged injection, the number of cylinders must be less than or equal to the injector channels (ie Assuming you're running paired injection, you need at least as many injector channels as you have cylinders, half for the primaries and half for the secondaries)
if( (configPage10.stagingEnabled == true) && (configPage2.nCylinders <= INJ_CHANNELS || configPage2.injType == INJ_TYPE_TBODY) && (currentStatus.PW1 > inj_opentime_uS) ) //Final check is to ensure that DFCO isn't active, which would cause an overflow below (See #267)
{
//Scale the 'full' pulsewidth by each of the injector capacities
currentStatus.PW1 -= inj_opentime_uS; //Subtract the opening time from PW1 as it needs to be multiplied out again by the pri/sec req_fuel values below. It is added on again after that calculation.
uint32_t tempPW1 = (((unsigned long)currentStatus.PW1 * staged_req_fuel_mult_pri) / 100);
if(configPage10.stagingMode == STAGING_MODE_TABLE)
{
uint32_t tempPW3 = (((unsigned long)currentStatus.PW1 * staged_req_fuel_mult_sec) / 100); //This is ONLY needed in in table mode. Auto mode only calculates the difference.
byte stagingSplit = get3DTableValue(&stagingTable, currentStatus.fuelLoad, currentStatus.RPM);
currentStatus.PW1 = ((100 - stagingSplit) * tempPW1) / 100;
currentStatus.PW1 += inj_opentime_uS;
//PW2 is used temporarily to hold the secondary injector pulsewidth. It will be assigned to the correct channel below
if(stagingSplit > 0)
{
BIT_SET(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Set the staging active flag
currentStatus.PW2 = (stagingSplit * tempPW3) / 100;
currentStatus.PW2 += inj_opentime_uS;
}
else
{
BIT_CLEAR(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Clear the staging active flag
currentStatus.PW2 = 0;
}
}
else if(configPage10.stagingMode == STAGING_MODE_AUTO)
{
currentStatus.PW1 = tempPW1;
//If automatic mode, the primary injectors are used all the way up to their limit (Configured by the pulsewidth limit setting)
//If they exceed their limit, the extra duty is passed to the secondaries
if(tempPW1 > pwLimit)
{
BIT_SET(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Set the staging active flag
uint32_t extraPW = tempPW1 - pwLimit + inj_opentime_uS; //The open time must be added here AND below because tempPW1 does not include an open time. The addition of it here takes into account the fact that pwLlimit does not contain an allowance for an open time.
currentStatus.PW1 = pwLimit;
currentStatus.PW2 = ((extraPW * staged_req_fuel_mult_sec) / staged_req_fuel_mult_pri); //Convert the 'left over' fuel amount from primary injector scaling to secondary
currentStatus.PW2 += inj_opentime_uS;
}
else
{
//If tempPW1 < pwLImit it means that the entire fuel load can be handled by the primaries and staging is inactive.
//Secondary PW is simply set to 0
BIT_CLEAR(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Clear the staging active flag
currentStatus.PW2 = 0;
}
}
//Allocate the primary and secondary pulse widths based on the fuel configuration
switch (configPage2.nCylinders)
{
case 1:
//Nothing required for 1 cylinder, channels are correct already
break;
case 2:
//Prmaary pulsewidth on channels 1 and 2, secondary on channels 3 and 4
currentStatus.PW3 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
break;
case 3:
//6 channels required for 'normal' 3 cylinder staging support
#if INJ_CHANNELS >= 6
//Primary pulsewidth on channels 1, 2 and 3, secondary on channels 4, 5 and 6
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
#else
//If there are not enough channels, then primary pulsewidth is on channels 1, 2 and 3, secondary on channel 4
currentStatus.PW4 = currentStatus.PW2;
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
break;
case 4:
if( (configPage2.injLayout == INJ_SEQUENTIAL) || (configPage2.injLayout == INJ_SEMISEQUENTIAL) )
{
//Staging with 4 cylinders semi/sequential requires 8 total channels
#if INJ_CHANNELS >= 8
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
currentStatus.PW7 = currentStatus.PW2;
currentStatus.PW8 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
currentStatus.PW4 = currentStatus.PW1;
#else
//This is an invalid config as there are not enough outputs to support sequential + staging
//Put the staging output to the non-existant channel 5
BIT_SET(channelInjEnabled, INJ5_CMD_BIT);
channel5InjDegrees = channel1InjDegrees;
#endif
}
else
{
currentStatus.PW3 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
}
break;
case 5:
//No easily supportable 5 cylinder staging option unless there are at least 5 channels
#if INJ_CHANNELS >= 5
if (configPage2.injLayout != INJ_SEQUENTIAL)
{
currentStatus.PW5 = currentStatus.PW2;
}
#if INJ_CHANNELS >= 6
currentStatus.PW6 = currentStatus.PW2;
#endif
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
currentStatus.PW4 = currentStatus.PW1;
break;
case 6:
#if INJ_CHANNELS >= 6
//8 cylinder staging only if not sequential
if (configPage2.injLayout != INJ_SEQUENTIAL)
{
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
}
#if INJ_CHANNELS >= 8
else
{
//If there are 8 channels, then the 6 cylinder sequential option is available by using channels 7 + 8 for staging
currentStatus.PW7 = currentStatus.PW2;
currentStatus.PW8 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW1;
currentStatus.PW5 = currentStatus.PW1;
currentStatus.PW6 = currentStatus.PW1;
}
#endif
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
break;
case 8:
#if INJ_CHANNELS >= 8
//8 cylinder staging only if not sequential
if (configPage2.injLayout != INJ_SEQUENTIAL)
{
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
currentStatus.PW7 = currentStatus.PW2;
currentStatus.PW8 = currentStatus.PW2;
}
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
currentStatus.PW4 = currentStatus.PW1;
break;
default:
//Assume 4 cylinder non-seq for default
currentStatus.PW3 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
break;
}
}
else { BIT_CLEAR(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); } //Clear the staging active flag
if( BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == false)
{
//If staging is off, all the pulse widths are set the same (Sequential and other adjustments may be made below)
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
currentStatus.PW4 = currentStatus.PW1;
currentStatus.PW5 = currentStatus.PW1;
currentStatus.PW6 = currentStatus.PW1;
currentStatus.PW7 = currentStatus.PW1;
currentStatus.PW8 = currentStatus.PW1;
}
calculateStaging(pwLimit);
//***********************************************************************************************
//BEGIN INJECTION TIMING
@ -1107,7 +923,7 @@ void loop(void)
|------------------------------------------------------------------------------------------
*/
#if INJ_CHANNELS >= 2
if( (BIT_CHECK(channelInjEnabled, INJ2_CMD_BIT) == true) && (currentStatus.PW2 >= inj_opentime_uS) )
if( (maxInjOutputs >= 2) && (currentStatus.PW2 >= inj_opentime_uS) )
{
uint32_t timeOut = calculateInjectorNTimeout(fuelSchedule2, channel2InjDegrees, injector2StartAngle, crankAngle);
if ( timeOut>0U )
@ -1121,7 +937,7 @@ void loop(void)
#endif
#if INJ_CHANNELS >= 3
if( (BIT_CHECK(channelInjEnabled, INJ3_CMD_BIT) == true) && (currentStatus.PW3 >= inj_opentime_uS) )
if( (maxInjOutputs >= 3) && (currentStatus.PW3 >= inj_opentime_uS) )
{
uint32_t timeOut = calculateInjectorNTimeout(fuelSchedule3, channel3InjDegrees, injector3StartAngle, crankAngle);
if ( timeOut>0U )
@ -1135,7 +951,7 @@ void loop(void)
#endif
#if INJ_CHANNELS >= 4
if( (BIT_CHECK(channelInjEnabled, INJ4_CMD_BIT) == true) && (currentStatus.PW4 >= inj_opentime_uS) )
if( (maxInjOutputs >= 4) && (currentStatus.PW4 >= inj_opentime_uS) )
{
uint32_t timeOut = calculateInjectorNTimeout(fuelSchedule4, channel4InjDegrees, injector4StartAngle, crankAngle);
if ( timeOut>0U )
@ -1149,7 +965,7 @@ void loop(void)
#endif
#if INJ_CHANNELS >= 5
if( (BIT_CHECK(channelInjEnabled, INJ5_CMD_BIT) == true) && (currentStatus.PW5 >= inj_opentime_uS) )
if( (maxInjOutputs >= 5) && (currentStatus.PW5 >= inj_opentime_uS) )
{
uint32_t timeOut = calculateInjectorNTimeout(fuelSchedule5, channel5InjDegrees, injector5StartAngle, crankAngle);
if ( timeOut>0U )
@ -1163,7 +979,7 @@ void loop(void)
#endif
#if INJ_CHANNELS >= 6
if( (BIT_CHECK(channelInjEnabled, INJ6_CMD_BIT) == true) && (currentStatus.PW6 >= inj_opentime_uS) )
if( (maxInjOutputs >= 6) && (currentStatus.PW6 >= inj_opentime_uS) )
{
uint32_t timeOut = calculateInjectorNTimeout(fuelSchedule6, channel6InjDegrees, injector6StartAngle, crankAngle);
if ( timeOut>0U )
@ -1177,7 +993,7 @@ void loop(void)
#endif
#if INJ_CHANNELS >= 7
if( (BIT_CHECK(channelInjEnabled, INJ7_CMD_BIT) == true) && (currentStatus.PW7 >= inj_opentime_uS) )
if( (maxInjOutputs >= 7) && (currentStatus.PW7 >= inj_opentime_uS) )
{
uint32_t timeOut = calculateInjectorNTimeout(fuelSchedule7, channel7InjDegrees, injector7StartAngle, crankAngle);
if ( timeOut>0U )
@ -1191,7 +1007,7 @@ void loop(void)
#endif
#if INJ_CHANNELS >= 8
if( (BIT_CHECK(channelInjEnabled, INJ8_CMD_BIT) == true) && (currentStatus.PW8 >= inj_opentime_uS) )
if( (maxInjOutputs >= 8) && (currentStatus.PW8 >= inj_opentime_uS) )
{
uint32_t timeOut = calculateInjectorNTimeout(fuelSchedule8, channel8InjDegrees, injector8StartAngle, crankAngle);
if ( timeOut>0U )
@ -1645,3 +1461,199 @@ void calculateIgnitionAngles(int dwellAngle)
break;
}
}
void calculateStaging(uint32_t pwLimit)
{
//Calculate staging pulsewidths if used
//To run staged injection, the number of cylinders must be less than or equal to the injector channels (ie Assuming you're running paired injection, you need at least as many injector channels as you have cylinders, half for the primaries and half for the secondaries)
if( (configPage10.stagingEnabled == true) && (configPage2.nCylinders <= INJ_CHANNELS || configPage2.injType == INJ_TYPE_TBODY) && (currentStatus.PW1 > inj_opentime_uS) ) //Final check is to ensure that DFCO isn't active, which would cause an overflow below (See #267)
{
//Scale the 'full' pulsewidth by each of the injector capacities
currentStatus.PW1 -= inj_opentime_uS; //Subtract the opening time from PW1 as it needs to be multiplied out again by the pri/sec req_fuel values below. It is added on again after that calculation.
uint32_t tempPW1 = (((unsigned long)currentStatus.PW1 * staged_req_fuel_mult_pri) / 100);
if(configPage10.stagingMode == STAGING_MODE_TABLE)
{
uint32_t tempPW3 = (((unsigned long)currentStatus.PW1 * staged_req_fuel_mult_sec) / 100); //This is ONLY needed in in table mode. Auto mode only calculates the difference.
byte stagingSplit = get3DTableValue(&stagingTable, currentStatus.fuelLoad, currentStatus.RPM);
currentStatus.PW1 = ((100 - stagingSplit) * tempPW1) / 100;
currentStatus.PW1 += inj_opentime_uS;
//PW2 is used temporarily to hold the secondary injector pulsewidth. It will be assigned to the correct channel below
if(stagingSplit > 0)
{
BIT_SET(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Set the staging active flag
currentStatus.PW2 = (stagingSplit * tempPW3) / 100;
currentStatus.PW2 += inj_opentime_uS;
}
else
{
BIT_CLEAR(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Clear the staging active flag
currentStatus.PW2 = 0;
}
}
else if(configPage10.stagingMode == STAGING_MODE_AUTO)
{
currentStatus.PW1 = tempPW1;
//If automatic mode, the primary injectors are used all the way up to their limit (Configured by the pulsewidth limit setting)
//If they exceed their limit, the extra duty is passed to the secondaries
if(tempPW1 > pwLimit)
{
BIT_SET(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Set the staging active flag
uint32_t extraPW = tempPW1 - pwLimit + inj_opentime_uS; //The open time must be added here AND below because tempPW1 does not include an open time. The addition of it here takes into account the fact that pwLlimit does not contain an allowance for an open time.
currentStatus.PW1 = pwLimit;
currentStatus.PW2 = ((extraPW * staged_req_fuel_mult_sec) / staged_req_fuel_mult_pri); //Convert the 'left over' fuel amount from primary injector scaling to secondary
currentStatus.PW2 += inj_opentime_uS;
}
else
{
//If tempPW1 < pwLImit it means that the entire fuel load can be handled by the primaries and staging is inactive.
//Secondary PW is simply set to 0
BIT_CLEAR(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Clear the staging active flag
currentStatus.PW2 = 0;
}
}
//Allocate the primary and secondary pulse widths based on the fuel configuration
switch (configPage2.nCylinders)
{
case 1:
//Nothing required for 1 cylinder, channels are correct already
break;
case 2:
//Primary pulsewidth on channels 1 and 2, secondary on channels 3 and 4
currentStatus.PW3 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
break;
case 3:
//6 channels required for 'normal' 3 cylinder staging support
#if INJ_CHANNELS >= 6
//Primary pulsewidth on channels 1, 2 and 3, secondary on channels 4, 5 and 6
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
#else
//If there are not enough channels, then primary pulsewidth is on channels 1, 2 and 3, secondary on channel 4
currentStatus.PW4 = currentStatus.PW2;
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
break;
case 4:
if( (configPage2.injLayout == INJ_SEQUENTIAL) || (configPage2.injLayout == INJ_SEMISEQUENTIAL) )
{
//Staging with 4 cylinders semi/sequential requires 8 total channels
#if INJ_CHANNELS >= 8
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
currentStatus.PW7 = currentStatus.PW2;
currentStatus.PW8 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
currentStatus.PW4 = currentStatus.PW1;
#else
//This is an invalid config as there are not enough outputs to support sequential + staging
//Put the staging output to the non-existant channel 5
currentStatus.PW5 = currentStatus.PW2;
#endif
}
else
{
currentStatus.PW3 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
}
break;
case 5:
//No easily supportable 5 cylinder staging option unless there are at least 5 channels
#if INJ_CHANNELS >= 5
if (configPage2.injLayout != INJ_SEQUENTIAL)
{
currentStatus.PW5 = currentStatus.PW2;
}
#if INJ_CHANNELS >= 6
currentStatus.PW6 = currentStatus.PW2;
#endif
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
currentStatus.PW4 = currentStatus.PW1;
break;
case 6:
#if INJ_CHANNELS >= 6
//8 cylinder staging only if not sequential
if (configPage2.injLayout != INJ_SEQUENTIAL)
{
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
}
#if INJ_CHANNELS >= 8
else
{
//If there are 8 channels, then the 6 cylinder sequential option is available by using channels 7 + 8 for staging
currentStatus.PW7 = currentStatus.PW2;
currentStatus.PW8 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW1;
currentStatus.PW5 = currentStatus.PW1;
currentStatus.PW6 = currentStatus.PW1;
}
#endif
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
break;
case 8:
#if INJ_CHANNELS >= 8
//8 cylinder staging only if not sequential
if (configPage2.injLayout != INJ_SEQUENTIAL)
{
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
currentStatus.PW7 = currentStatus.PW2;
currentStatus.PW8 = currentStatus.PW2;
}
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
currentStatus.PW4 = currentStatus.PW1;
break;
default:
//Assume 4 cylinder non-seq for default
currentStatus.PW3 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
break;
}
}
else
{
if(maxInjOutputs >= 2) { currentStatus.PW2 = currentStatus.PW1; }
else { currentStatus.PW2 = 0; }
if(maxInjOutputs >= 3) { currentStatus.PW3 = currentStatus.PW1; }
else { currentStatus.PW3 = 0; }
if(maxInjOutputs >= 4) { currentStatus.PW4 = currentStatus.PW1; }
else { currentStatus.PW4 = 0; }
if(maxInjOutputs >= 5) { currentStatus.PW5 = currentStatus.PW1; }
else { currentStatus.PW5 = 0; }
if(maxInjOutputs >= 6) { currentStatus.PW6 = currentStatus.PW1; }
else { currentStatus.PW6 = 0; }
if(maxInjOutputs >= 7) { currentStatus.PW7 = currentStatus.PW1; }
else { currentStatus.PW7 = 0; }
if(maxInjOutputs >= 8) { currentStatus.PW8 = currentStatus.PW1; }
else { currentStatus.PW8 = 0; }
BIT_CLEAR(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Clear the staging active flag
}
}