From e44f4c7b5488ff7ce2b7f26421ccc02674cedc8b Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Mon, 26 Jun 2023 10:46:11 +1000 Subject: [PATCH] Fix issue where staging fuel channels would be active even when not required --- reference/speeduino.ini | 3 + speeduino/globals.h | 6 +- speeduino/globals.ino | 7 +- speeduino/init.ino | 150 ++++++--------- speeduino/scheduler.ino | 16 +- speeduino/speeduino.h | 1 + speeduino/speeduino.ino | 398 +++++++++++++++++++++------------------- 7 files changed, 275 insertions(+), 306 deletions(-) diff --git a/reference/speeduino.ini b/reference/speeduino.ini index 8157b2cc..8a8b445a 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -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 diff --git a/speeduino/globals.h b/speeduino/globals.h index 1ab379e1..dc7081c2 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -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 diff --git a/speeduino/globals.ino b/speeduino/globals.ino index 79861e01..7eef4ed0 100644 --- a/speeduino/globals.ino +++ b/speeduino/globals.ino @@ -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; diff --git a/speeduino/init.ino b/speeduino/init.ino index bbdbd4b8..290931dc 100644 --- a/speeduino/init.ino +++ b/speeduino/init.ino @@ -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; } } diff --git a/speeduino/scheduler.ino b/speeduino/scheduler.ino index 4a12d484..83982260 100644 --- a/speeduino/scheduler.ino +++ b/speeduino/scheduler.ino @@ -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 } } diff --git a/speeduino/speeduino.h b/speeduino/speeduino.h index b10c7132..9fc6e105 100644 --- a/speeduino/speeduino.h +++ b/speeduino/speeduino.h @@ -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 */ diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index 1217fac1..cc04bb50 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -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 + + } + +}