From 9c3e993b53feb71fca2a5ea813b82fe695596031 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Fri, 9 Jun 2023 16:10:43 +1000 Subject: [PATCH] Initial commit of new rolling rev limiter --- reference/speeduino.ini | 30 ++++-- speeduino/engineProtection.ino | 2 +- speeduino/globals.h | 11 ++- speeduino/globals.ino | 2 +- speeduino/init.ino | 40 ++++---- speeduino/maths.h | 1 + speeduino/maths.ino | 27 ++++++ speeduino/speeduino.h | 7 -- speeduino/speeduino.ino | 166 ++++++++++++++++++++------------- speeduino/table2d.h | 1 + speeduino/table2d.ino | 3 + speeduino/updates.ino | 10 ++ 12 files changed, 200 insertions(+), 100 deletions(-) diff --git a/reference/speeduino.ini b/reference/speeduino.ini index 85beab46..8157b2cc 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -1449,7 +1449,11 @@ page = 15 airConUnused4 = bits, U08, 95, [6:7], "0", "1", "2", "3" airConIdleUpRPMAdder = scalar, U08, 96, "Added Target RPM", 10.0, 0.0, 0.0, 250.0, 0 airConPwmFanMinDuty = scalar, U08, 97, "%", 0.5, 0.0, 0.0, 100.0, 1 - Unused15_98_255 = array, U08, 98, [158], "%", 1.0, 0.0, 0.0, 255, 0 + + rollingProtRPMDelta = array, S08, 98, [4], "RPM", 10.0, 0, -1000, 0, 0 + rollingProtCutPercent = array, U08, 102, [4], "%", 1.0, 0, 0, 100, 0 + + Unused15_98_255 = array, U08, 98, [150], "%", 1.0, 0.0, 0.0, 255, 0 ;------------------------------------------------------------------------------- @@ -1810,6 +1814,9 @@ page = 15 defaultValue = batlow, 11.8 defaultValue = bathigh, 15 + defaultValue = rollingProtRPMDelta, -300 -200 -100 -50 + defaultValue = rollingProtCutPercent, 50 65 80 95 + #if LAMBDA defaultValue = wueAFR, -0.136 -0.102 -0.082 -0.068 -0.054 -0.041 -0.027 -0.014 -0.007 0.000 #else @@ -2986,14 +2993,16 @@ menuDialog = main indicator = { engineProtectAFR }, "AFR Protect OFF", "AFR Protect ON", green, black, red, black indicator = { engineProtectCoolant }, "Coolant Protect OFF", "Coolant Protect ON", green, black, red, black - dialog = engineProtectionWest, "" - field = "Protection Cut", engineProtectType - field = "Engine Protection RPM min", engineProtectMaxRPM, { engineProtectType } - field = "Cut method", hardCutType, { engineProtectType == 1 || engineProtectType == 3 } ;Only available for the protection modes that include ignition. + dialog = engineProtectionWest, "Engine Protection" + field = "Protection RPM Limit ('Limp Home')", engineProtectMaxRPM, { engineProtectType } panel = protectIndicatorPanel, { engineProtectType } - dialog = engineProtection, "Engine Protection and Limiters", xAxis + dialog = engineProtection, "Hard Limit Configuration", yAxis topicHelp = "http://wiki.speeduino.com/en/configuration/Rev_Limits" + field = "Protection Cut", engineProtectType + field = "!It is recommended to use Spark Cut on non-sequential fuel configurations", {}, {}, { engineProtectType > 1 && injLayout != 3 } + field = "Cut method", hardCutType, { engineProtectType > 0 } ;Only available for the protection modes that include ignition. + panel = rolling_prot_curve, { hardCutType == 1 } panel = engineProtectionWest dialog = clutchInput, "Clutch input" @@ -4668,6 +4677,15 @@ cmdVSSratio6 = "E\x99\x06" yBins = coolantProtRPM size = 200, 200 + ; Rolling engine protection curve + curve = rolling_prot_curve, "Rolling Cut Percent" + columnLabel = "RPM Delta", "Event Cut" + xAxis = -300, 0, 6 + yAxis = 0, 125, 6 + xBins = rollingProtRPMDelta + yBins = rollingProtCutPercent + size = 200, 200 + ; Warmup enrichment VEAL AFR adjustment curves curve = warmup_afr_curve, "Target Adjustment" columnLabel = "Coolant", "Offset" diff --git a/speeduino/engineProtection.ino b/speeduino/engineProtection.ino index 6c9deb98..454f77a8 100644 --- a/speeduino/engineProtection.ino +++ b/speeduino/engineProtection.ino @@ -7,7 +7,7 @@ byte oilProtStartTime = 0; byte checkEngineProtect(void) { byte protectActive = 0; - if(checkRevLimit() || checkBoostLimit() || checkOilPressureLimit() || checkAFRLimit() ) + if(checkBoostLimit() || checkOilPressureLimit() || checkAFRLimit() ) { if( currentStatus.RPMdiv100 > configPage4.engineProtectMaxRPM ) { protectActive = 1; } } diff --git a/speeduino/globals.h b/speeduino/globals.h index eb03ee91..1ab379e1 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -156,6 +156,8 @@ #define BIT_TOGGLE(var,pos) ((var)^= 1UL << (pos)) #define BIT_WRITE(var, pos, bitvalue) ((bitvalue) ? BIT_SET((var), (pos)) : bitClear((var), (pos))) +#define CRANK_ANGLE_MAX (max(CRANK_ANGLE_MAX_IGN, CRANK_ANGLE_MAX_INJ)) + #define interruptSafe(c) (noInterrupts(); {c} interrupts();) //Wraps any code between nointerrupt and interrupt calls #define MS_IN_MINUTE 60000 @@ -497,6 +499,7 @@ extern struct table2D oilPressureProtectTable; extern struct table2D wmiAdvTable; //6 bin wmi correction table for timing advance (2D) extern struct table2D coolantProtectTable; //6 bin coolant temperature protection table for engine protection (2D) extern struct table2D fanPWMTable; +extern struct table2D rollingCutTable; //These are for the direct port manipulation of the injectors, coils and aux outputs extern volatile PORT_TYPE *inj1_pin_port; @@ -600,7 +603,6 @@ extern volatile uint16_t ignitionCount; /**< The count of ignition events that h extern byte secondaryTriggerEdge; extern byte tertiaryTriggerEdge; #endif -extern int CRANK_ANGLE_MAX; extern int CRANK_ANGLE_MAX_IGN; extern int CRANK_ANGLE_MAX_INJ; ///< The number of crank degrees that the system track over. 360 for wasted / timed batch and 720 for sequential extern volatile uint32_t runSecsX10; /**< Counter of seconds since cranking commenced (similar to runSecs) but in increments of 0.1 seconds */ @@ -1374,7 +1376,7 @@ struct config10 { byte oilPressureProtTime; - byte unused11_191_191; //Bytes 187-191 + byte unused11_191_191; #if defined(CORE_AVR) }; @@ -1480,9 +1482,12 @@ struct config15 { byte airConUnused4 : 2; byte airConIdleUpRPMAdder; byte airConPwmFanMinDuty; + + int8_t rollingProtRPMDelta[4]; // Signed RPM value representing how much below the RPM limit. Divided by 10 + byte rollingProtCutPercent[4]; //Bytes 98-255 - byte Unused15_98_255[158]; + byte Unused15_98_255[150]; #if defined(CORE_AVR) }; diff --git a/speeduino/globals.ino b/speeduino/globals.ino index d8d27998..79861e01 100644 --- a/speeduino/globals.ino +++ b/speeduino/globals.ino @@ -54,6 +54,7 @@ struct table2D oilPressureProtectTable; struct table2D wmiAdvTable; //6 bin wmi correction table for timing advance (2D) struct table2D coolantProtectTable; struct table2D fanPWMTable; +struct table2D rollingCutTable; /// volatile inj*_pin_port and inj*_pin_mask vars are for the direct port manipulation of the injectors, coils and aux outputs. volatile PORT_TYPE *inj1_pin_port; @@ -144,7 +145,6 @@ volatile uint16_t ignitionCount; /**< The count of ignition events that have tak byte secondaryTriggerEdge; byte tertiaryTriggerEdge; #endif -int CRANK_ANGLE_MAX = 720; int CRANK_ANGLE_MAX_IGN = 360; int CRANK_ANGLE_MAX_INJ = 360; ///< The number of crank degrees that the system track over. 360 for wasted / timed batch and 720 for sequential volatile uint32_t runSecsX10; diff --git a/speeduino/init.ino b/speeduino/init.ino index c256845e..bbdbd4b8 100644 --- a/speeduino/init.ino +++ b/speeduino/init.ino @@ -259,6 +259,12 @@ void initialiseAll(void) fanPWMTable.values = configPage9.PWMFanDuty; fanPWMTable.axisX = configPage6.fanPWMBins; + rollingCutTable.valueSize = SIZE_BYTE; + rollingCutTable.axisSize = SIZE_SIGNED_BYTE; //X axis is SIGNED for this table. + rollingCutTable.xSize = 4; + rollingCutTable.values = configPage15.rollingProtCutPercent; + rollingCutTable.axisX = configPage15.rollingProtRPMDelta; + wmiAdvTable.valueSize = SIZE_BYTE; wmiAdvTable.axisSize = SIZE_BYTE; //Set this table to use byte axis bins wmiAdvTable.xSize = 6; @@ -449,7 +455,6 @@ void initialiseAll(void) //Calculate the number of degrees between cylinders //Set some default values. These will be updated below if required. - CRANK_ANGLE_MAX = 720; CRANK_ANGLE_MAX_IGN = 360; CRANK_ANGLE_MAX_INJ = 360; @@ -540,24 +545,24 @@ void initialiseAll(void) maxIgnOutputs = 3; if (configPage2.engineType == EVEN_FIRE ) { - //Sequential and Single channel modes both run over 720 crank degrees, but only on 4 stroke engines. - if( ( (configPage4.sparkMode == IGN_MODE_SEQUENTIAL) || (configPage4.sparkMode == IGN_MODE_SINGLE) ) && (configPage2.strokes == FOUR_STROKE) ) - { - channel2IgnDegrees = 240; - channel3IgnDegrees = 480; + //Sequential and Single channel modes both run over 720 crank degrees, but only on 4 stroke engines. + if( ( (configPage4.sparkMode == IGN_MODE_SEQUENTIAL) || (configPage4.sparkMode == IGN_MODE_SINGLE) ) && (configPage2.strokes == FOUR_STROKE) ) + { + channel2IgnDegrees = 240; + channel3IgnDegrees = 480; - CRANK_ANGLE_MAX_IGN = 720; + CRANK_ANGLE_MAX_IGN = 720; + } + else + { + channel2IgnDegrees = 120; + channel3IgnDegrees = 240; + } } else { - channel2IgnDegrees = 120; - channel3IgnDegrees = 240; - } - } - else - { - channel2IgnDegrees = configPage2.oddfire2; - channel3IgnDegrees = configPage2.oddfire3; + channel2IgnDegrees = configPage2.oddfire2; + channel3IgnDegrees = configPage2.oddfire3; } //For alternating injection, the squirt occurs at different times for each channel @@ -976,9 +981,6 @@ void initialiseAll(void) break; } - if(CRANK_ANGLE_MAX_IGN == CRANK_ANGLE_MAX_INJ) { CRANK_ANGLE_MAX = CRANK_ANGLE_MAX_IGN; } //If both the injector max and ignition max angles are the same, make the overall system max this value - else if (CRANK_ANGLE_MAX_IGN > CRANK_ANGLE_MAX_INJ) { CRANK_ANGLE_MAX = CRANK_ANGLE_MAX_IGN; } - else { CRANK_ANGLE_MAX = CRANK_ANGLE_MAX_INJ; } currentStatus.status3 |= currentStatus.nSquirts << BIT_STATUS3_NSQUIRTS1; //Top 3 bits of the status3 variable are the number of squirts. This must be done after the above section due to nSquirts being forced to 1 for sequential //Special case: @@ -986,7 +988,7 @@ void initialiseAll(void) //This is ONLY the case on 4 stroke systems if( (currentStatus.nSquirts == 3) || (currentStatus.nSquirts == 5) ) { - if(configPage2.strokes == FOUR_STROKE) { CRANK_ANGLE_MAX = 720; } + if(configPage2.strokes == FOUR_STROKE) { CRANK_ANGLE_MAX_INJ = 720; } } switch(configPage2.injLayout) diff --git a/speeduino/maths.h b/speeduino/maths.h index 6ad85873..2f8b4326 100644 --- a/speeduino/maths.h +++ b/speeduino/maths.h @@ -4,6 +4,7 @@ unsigned long percentage(uint8_t x, unsigned long y); unsigned long halfPercentage(uint8_t x, unsigned long y); inline long powint(int factor, unsigned int exponent); +uint8_t random1to100(); #ifdef USE_LIBDIVIDE #include "src/libdivide/libdivide.h" diff --git a/speeduino/maths.ino b/speeduino/maths.ino index 186d6df9..a57d77e6 100644 --- a/speeduino/maths.ino +++ b/speeduino/maths.ino @@ -54,3 +54,30 @@ inline long powint(int factor, unsigned int exponent) while ( (counter--) > 0) { product *= factor; } return product; } + +//Generates a random number from 1 to 100 (inclusive). +//The initial seed used is always based on micros(), though this is unlikely to cause an issue as the first run is nearly random itself +//Function requires 4 bytes to store state and seed, but operates very quickly (around 4uS per call) +uint8_t a, x, y, z; +uint8_t random1to100() +{ + //Check if this is the first time being run. If so, seed the random number generator with micros() + if( (a == 0) && (x == 0) && (y == 0) && (z == 0) ) + { + x = micros() >> 24; + y = micros() >> 16; + z = micros() >> 8; + a = micros(); + } + + do + { + unsigned char t = x ^ (x << 4); + x=y; + y=z; + z=a; + a = z ^ t ^ ( z >> 1) ^ (t << 1); + } + while(a >= 100); + return (a+1); +} diff --git a/speeduino/speeduino.h b/speeduino/speeduino.h index 31e3a81a..b10c7132 100644 --- a/speeduino/speeduino.h +++ b/speeduino/speeduino.h @@ -24,13 +24,6 @@ byte getAdvance1(void); 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 */ -extern bool ignitionOn; /**< The current state of the ignition system (on or off) */ -extern bool fuelOn; /**< The current state of the fuel system (on or off) */ - -extern byte curRollingCut; /**< Rolling rev limiter, current ignition channel being cut */ -extern byte rollingCutCounter; /**< how many times (revolutions) the ignition has been cut in a row */ -extern uint32_t rollingCutLastRev; /**< Tracks whether we're on the same or a different rev for the rolling cut */ - /** @name Staging * These values are a percentage of the total (Combined) req_fuel value that would be required for each injector channel to deliver that much fuel. * diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index d4de4266..1217fac1 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -52,11 +52,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. uint16_t req_fuel_uS = 0; /**< The required fuel variable (As calculated by TunerStudio) in uS */ uint16_t inj_opentime_uS = 0; -bool ignitionOn = false; /**< The current state of the ignition system (on or off) */ -bool fuelOn = false; /**< The current state of the fuel system (on or off) */ +uint8_t ignitionChannelsOn; /**< The current state of the ignition system (on or off) */ +uint8_t fuelChannelsOn; /**< The current state of the fuel system (on or off) */ -byte curRollingCut = 0; /**< Rolling rev limiter, current ignition channel being cut */ -byte rollingCutCounter = 0; /**< how many times (revolutions) the ignition has been cut in a row */ +//byte curRollingCut = 0; /**< Rolling rev limiter, current ignition channel being cut */ +//byte rollingCutCounter = 0; /**< how many times (revolutions) the ignition has been cut in a row */ uint32_t rollingCutLastRev = 0; /**< Tracks whether we're on the same or a different rev for the rolling cut */ uint16_t staged_req_fuel_mult_pri = 0; @@ -175,8 +175,8 @@ void loop(void) currentStatus.rpmDOT = 0; AFRnextCycle = 0; ignitionCount = 0; - ignitionOn = false; - fuelOn = false; + ignitionChannelsOn = 0; + fuelChannelsOn = 0; if (fpPrimed == true) { FUEL_PUMP_OFF(); currentStatus.fuelPumpOn = false; } //Turn off the fuel pump, but only if the priming is complete if (configPage6.iacPWMrun == false) { disableIdle(); } //Turn off the idle PWM BIT_CLEAR(currentStatus.engine, BIT_ENGINE_CRANK); //Clear cranking bit (Can otherwise get stuck 'on' even with 0 rpm) @@ -423,7 +423,6 @@ void loop(void) //Main loop runs within this clause if ((currentStatus.hasSync || BIT_CHECK(currentStatus.status3, BIT_STATUS3_HALFSYNC)) && (currentStatus.RPM > 0)) { - if(currentStatus.startRevolutions >= configPage4.StgCycles) { ignitionOn = true; fuelOn = true; } //Enable the fuel and ignition, assuming staging revolutions are complete //Check whether running or cranking if(currentStatus.RPM > currentStatus.crankRPM) //Crank RPM in the config is stored as a x10. currentStatus.crankRPM is set in timers.ino and represents the true value { @@ -987,61 +986,102 @@ void loop(void) // } //Check for any of the engine protections or rev limiters being turned on - if(checkEngineProtect() || currentStatus.launchingHard || currentStatus.flatShiftingHard) + int16_t maxAllowedRPM = configPage4.HardRevLim; //The maximum RPM allowed by all the potential limiters (Engine protection, 2-step, flat shift etc). Divided by 100. Use RPM hard limit as the default as it's the highest that is ever permitted + //Check each of the functions that has an RPM limit. Update the max allowed RPM if the function is active and has a lower RPM than already set + checkRevLimit(); + if( checkEngineProtect() && (configPage4.engineProtectMaxRPM < maxAllowedRPM)) { maxAllowedRPM = configPage4.engineProtectMaxRPM; } + if ( (currentStatus.launchingHard == true) && (configPage6.lnchHardLim < maxAllowedRPM) ) { maxAllowedRPM = configPage6.lnchHardLim; } + if ( (currentStatus.flatShiftingHard == true) && (configPage6.flatSArm < maxAllowedRPM) ) { maxAllowedRPM = configPage6.flatSArm; } + maxAllowedRPM = maxAllowedRPM * 100; //All of the above limits are divided by 100, convert back to RPM + + if( (configPage2.hardCutType == HARD_CUT_FULL) && (currentStatus.RPM > maxAllowedRPM) ) { - if( (currentStatus.RPMdiv100 > configPage4.engineProtectMaxRPM) || currentStatus.launchingHard || currentStatus.flatShiftingHard) //Ugly, but the launch/flat shift check needs to be here as well to prevent these limiters not happening when under the the Engine Protection min rpm + //Full hard cut turns outputs off completely. + switch(configPage6.engineProtectType) { - if( (configPage2.hardCutType == HARD_CUT_FULL) || (configPage6.engineProtectType == PROTECT_CUT_FUEL) ) - { - //Full hard cut turns outputs off completely. Note that hard cut is ALWAYS used on fuel cut only. - switch(configPage6.engineProtectType) + case PROTECT_CUT_OFF: + //Make sure all channels are turned on + ignitionChannelsOn = 0xFF; + fuelChannelsOn = 0xFF; + currentStatus.engineProtectStatus = 0; + break; + case PROTECT_CUT_IGN: + ignitionChannelsOn = 0; + break; + case PROTECT_CUT_FUEL: + fuelChannelsOn = 0; + break; + case PROTECT_CUT_BOTH: + ignitionChannelsOn = 0; + fuelChannelsOn = 0; + break; + default: + ignitionChannelsOn = 0; + fuelChannelsOn = 0; + break; + } + } //Hard cut check + else if( (configPage2.hardCutType == HARD_CUT_ROLLING) && (currentStatus.RPM > (maxAllowedRPM + (configPage15.rollingProtRPMDelta[0] * 10))) ) //Limit for rolling is the max allowed RPM minus the lowest value in the delta table (Delta values are negative!) + { + uint8_t revolutionsToCut = 1; + if(configPage2.strokes == FOUR_STROKE) { revolutionsToCut *= 2; } //4 stroke needs to cut for at least 2 revolutions + //if( (configPage4.sparkMode != IGN_MODE_SEQUENTIAL) || (configPage2.injLayout != INJ_SEQUENTIAL) ) { revolutionsToCut *= 2; } //4 stroke and non-sequential will cut for 4 revolutions minimum. This is to ensure no half fuel ignition cycles take place + + if(rollingCutLastRev == 0) { rollingCutLastRev = currentStatus.startRevolutions; } //First time check + if (currentStatus.startRevolutions > (rollingCutLastRev + revolutionsToCut) ) + { + uint8_t cutPercent = 0; + int16_t rpmDelta = currentStatus.RPM - maxAllowedRPM; + if(rpmDelta >= 0) { cutPercent = 100; } //If the current RPM is over the max allowed RPM then cut is full (100%) + else { cutPercent = table2D_getValue(&rollingCutTable, (rpmDelta / 10) ); } // + + //max(maxIgnOutputs, maxInjOutputs) + for(uint8_t x=0; x<8; x++) + { + if( (configPage6.engineProtectType != PROTECT_CUT_OFF) && ( (cutPercent == 100) || (random1to100() < cutPercent) ) ) { - case PROTECT_CUT_OFF: - ignitionOn = true; - fuelOn = true; - currentStatus.engineProtectStatus = 0; - break; - case PROTECT_CUT_IGN: - ignitionOn = false; - break; - case PROTECT_CUT_FUEL: - fuelOn = false; - break; - case PROTECT_CUT_BOTH: - ignitionOn = false; - fuelOn = false; - break; - default: - ignitionOn = false; - fuelOn = false; - break; + switch(configPage6.engineProtectType) + { + case PROTECT_CUT_IGN: + BIT_CLEAR(ignitionChannelsOn, x); //Turn off this ignition channel + break; + case PROTECT_CUT_FUEL: + BIT_CLEAR(fuelChannelsOn, x); //Turn off this fuel channel + break; + case PROTECT_CUT_BOTH: + BIT_CLEAR(ignitionChannelsOn, x); //Turn off this ignition channel + BIT_CLEAR(fuelChannelsOn, x); //Turn off this fuel channel + break; + default: + BIT_CLEAR(ignitionChannelsOn, x); //Turn off this ignition channel + BIT_CLEAR(fuelChannelsOn, x); //Turn off this fuel channel + break; + } + } + else + { + BIT_SET(ignitionChannelsOn, x); //Turn on this ignition channel + BIT_SET(fuelChannelsOn, x); //Turn on this fuel channel } } - else - { - //if(rollingCutCounter >= 2) //Vary this number to change the intensity of the roll. The higher the number, the closer is it to full cut - if(rollingCutLastRev == 0) { rollingCutLastRev = currentStatus.startRevolutions; } // - if (currentStatus.startRevolutions > (rollingCutLastRev+1) ) - { - //Rolls through each of the active ignition channels based on how many revolutions have taken place - //curRollingCut = ( (currentStatus.startRevolutions / 2) % maxIgnOutputs) + 1; - curRollingCut = 0; - rollingCutCounter += 1; - if(rollingCutCounter > (maxIgnOutputs-1)) { rollingCutCounter = 0; } - BIT_SET(curRollingCut, rollingCutCounter); + rollingCutLastRev = currentStatus.startRevolutions; + } + } //Rolling cut check + else + { + currentStatus.engineProtectStatus = 0; + //No engine protection active, so turn all the channels on + if(currentStatus.startRevolutions >= configPage4.StgCycles) + { + //Enable the fuel and ignition, assuming staging revolutions are complete + ignitionChannelsOn = 0xff; + fuelChannelsOn = 0xff; + } + } - ignitionOn = true; - rollingCutLastRev = currentStatus.startRevolutions; - //curRollingCut = 0; - } - } //Hard/Rolling cut check - } //RPM Check - else { currentStatus.engineProtectStatus = 0; } //Force all engine protection flags to be off as we're below the minimum RPM - } //Protection active check - else { curRollingCut = 0; } //Disables the rolling hard cut #if INJ_CHANNELS >= 1 - if (fuelOn && !BIT_CHECK(currentStatus.status1, BIT_STATUS1_BOOSTCUT)) + if( (BIT_CHECK(fuelChannelsOn, INJ1_CMD_BIT)) && !BIT_CHECK(currentStatus.status1, BIT_STATUS1_BOOSTCUT)) { if(currentStatus.PW1 >= inj_opentime_uS) { @@ -1187,7 +1227,7 @@ void loop(void) } else { fixedCrankingOverride = 0; } - if(ignitionOn) + if(ignitionChannelsOn > 0) { //Refresh the current crank angle info //ignition1StartAngle = 335; @@ -1196,7 +1236,7 @@ void loop(void) #if IGN_CHANNELS >= 1 uint32_t timeOut = calculateIgnition1Timeout(crankAngle); - if ( (timeOut > 0U) && (!BIT_CHECK(curRollingCut, IGN1_CMD_BIT)) ) + if ( (timeOut > 0U) && (BIT_CHECK(ignitionChannelsOn, IGN1_CMD_BIT)) ) { setIgnitionSchedule1(ign1StartFunction, @@ -1233,7 +1273,7 @@ void loop(void) { unsigned long ignition2StartTime = calculateIgnitionNTimeout(ignitionSchedule2, ignition2StartAngle, channel2IgnDegrees, crankAngle); - if ( (ignition2StartTime > 0) && (!BIT_CHECK(curRollingCut, IGN2_CMD_BIT)) ) + if ( (ignition2StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN2_CMD_BIT)) ) { setIgnitionSchedule2(ign2StartFunction, ignition2StartTime, @@ -1249,7 +1289,7 @@ void loop(void) { unsigned long ignition3StartTime = calculateIgnitionNTimeout(ignitionSchedule3, ignition3StartAngle, channel3IgnDegrees, crankAngle); - if ( (ignition3StartTime > 0) && (!BIT_CHECK(curRollingCut, IGN3_CMD_BIT)) ) + if ( (ignition3StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN3_CMD_BIT)) ) { setIgnitionSchedule3(ign3StartFunction, ignition3StartTime, @@ -1265,7 +1305,7 @@ void loop(void) { unsigned long ignition4StartTime = calculateIgnitionNTimeout(ignitionSchedule4, ignition4StartAngle, channel4IgnDegrees, crankAngle); - if ( (ignition4StartTime > 0) && (!BIT_CHECK(curRollingCut, IGN4_CMD_BIT)) ) + if ( (ignition4StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN4_CMD_BIT)) ) { setIgnitionSchedule4(ign4StartFunction, ignition4StartTime, @@ -1281,7 +1321,7 @@ void loop(void) { unsigned long ignition5StartTime = calculateIgnitionNTimeout(ignitionSchedule5, ignition5StartAngle, channel5IgnDegrees, crankAngle); - if ( (ignition5StartTime > 0) && (!BIT_CHECK(curRollingCut, IGN5_CMD_BIT)) ) + if ( (ignition5StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN5_CMD_BIT)) ) { setIgnitionSchedule5(ign5StartFunction, ignition5StartTime, @@ -1297,7 +1337,7 @@ void loop(void) { unsigned long ignition6StartTime = calculateIgnitionNTimeout(ignitionSchedule6, ignition6StartAngle, channel6IgnDegrees, crankAngle); - if ( (ignition6StartTime > 0) && (!BIT_CHECK(curRollingCut, IGN6_CMD_BIT)) ) + if ( (ignition6StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN6_CMD_BIT)) ) { setIgnitionSchedule6(ign6StartFunction, ignition6StartTime, @@ -1313,7 +1353,7 @@ void loop(void) { unsigned long ignition7StartTime = calculateIgnitionNTimeout(ignitionSchedule7, ignition7StartAngle, channel7IgnDegrees, crankAngle); - if ( (ignition7StartTime > 0) && (!BIT_CHECK(curRollingCut, IGN7_CMD_BIT)) ) + if ( (ignition7StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN7_CMD_BIT)) ) { setIgnitionSchedule7(ign7StartFunction, ignition7StartTime, @@ -1329,7 +1369,7 @@ void loop(void) { unsigned long ignition8StartTime = calculateIgnitionNTimeout(ignitionSchedule8, ignition8StartAngle, channel8IgnDegrees, crankAngle); - if ( (ignition8StartTime > 0) && (!BIT_CHECK(curRollingCut, IGN8_CMD_BIT)) ) + if ( (ignition8StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN8_CMD_BIT)) ) { setIgnitionSchedule8(ign8StartFunction, ignition8StartTime, diff --git a/speeduino/table2d.h b/speeduino/table2d.h index b6de26f3..455484ce 100644 --- a/speeduino/table2d.h +++ b/speeduino/table2d.h @@ -4,6 +4,7 @@ This file is used for everything related to maps/tables including their definiti #ifndef TABLE_H #define TABLE_H +#define SIZE_SIGNED_BYTE 4 #define SIZE_BYTE 8 #define SIZE_INT 16 diff --git a/speeduino/table2d.ino b/speeduino/table2d.ino index b24ac08d..3f874656 100644 --- a/speeduino/table2d.ino +++ b/speeduino/table2d.ino @@ -136,6 +136,8 @@ int16_t table2D_getAxisValue(struct table2D *fromTable, byte X_in) if(fromTable->axisSize == SIZE_INT) { returnValue = ((int16_t*)fromTable->axisX)[X_in]; } else if(fromTable->axisSize == SIZE_BYTE) { returnValue = ((uint8_t*)fromTable->axisX)[X_in]; } + else if(fromTable->axisSize == SIZE_SIGNED_BYTE) { returnValue = ((int8_t*)fromTable->axisX)[X_in]; } + return returnValue; } @@ -153,6 +155,7 @@ int16_t table2D_getRawValue(struct table2D *fromTable, byte X_index) if(fromTable->valueSize == SIZE_INT) { returnValue = ((int16_t*)fromTable->values)[X_index]; } else if(fromTable->valueSize == SIZE_BYTE) { returnValue = ((uint8_t*)fromTable->values)[X_index]; } + else if(fromTable->valueSize == SIZE_SIGNED_BYTE) { returnValue = ((int8_t*)fromTable->values)[X_index]; } return returnValue; } diff --git a/speeduino/updates.ino b/speeduino/updates.ino index 96222d2a..3d13d777 100644 --- a/speeduino/updates.ino +++ b/speeduino/updates.ino @@ -707,6 +707,16 @@ void doUpdates(void) { //202306 + //Rolling cut curve added. Default values + configPage15.rollingProtRPMDelta[0] = -30; + configPage15.rollingProtRPMDelta[1] = -20; + configPage15.rollingProtRPMDelta[2] = -10; + configPage15.rollingProtRPMDelta[3] = -5; + configPage15.rollingProtCutPercent[0] = 50; + configPage15.rollingProtCutPercent[1] = 65; + configPage15.rollingProtCutPercent[2] = 80; + configPage15.rollingProtCutPercent[3] = 95; + writeAllConfig(); storeEEPROMVersion(22); }