From 940a6826b52b3393bfa730c9e9ef64000bb77246 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Sat, 6 Jun 2020 10:52:27 +1000 Subject: [PATCH] Initial work on engine protection system --- reference/speeduino.ini | 44 ++++++++++++++++---- speeduino/comms.ino | 3 +- speeduino/corrections.ino | 4 +- speeduino/engineProtection.h | 8 ++++ speeduino/engineProtection.ino | 75 ++++++++++++++++++++++++++++++++++ speeduino/globals.h | 20 +++++++-- speeduino/globals.ino | 1 + speeduino/init.ino | 9 +++- speeduino/speeduino.ino | 35 ++-------------- 9 files changed, 151 insertions(+), 48 deletions(-) create mode 100644 speeduino/engineProtection.h create mode 100644 speeduino/engineProtection.ino diff --git a/reference/speeduino.ini b/reference/speeduino.ini index 10ff8dd6..08c137a2 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -500,7 +500,9 @@ page = 4 idleAdvBins = array, U08, 108, [6], "RPM", 10.0, -50, -500, 500, 0 idleAdvValues = array, U08, 114, [6], "deg", 1.0, -15, -15, 50, 0 - unused4-120 = array, U08, 120, [8], "%", 1.0, 0.0, 0.0, 255, 0 + engineProtectMaxRPM = scalar, U08, 120, "rpm", 100, 0.0, 100, 25500, 0 + + unused4-120 = array, U08, 121, [7], "%", 1.0, 0.0, 0.0, 255, 0 ;-------------------------------------------------- ;Start AFR page @@ -524,7 +526,7 @@ page = 6 egoType = bits , U08, 0, [2:3], "Disabled", "Narrow Band", "Wide Band", "INVALID" ; egoOption boostEnabled = bits, U08, 0, [4:4], "Off", "On" vvtEnabled = bits, U08, 0, [5:5], "Off", "On" - boostCutType = bits, U08, 0, [6:7], "Off", "Spark Only", "Fuel Only","Both" + engineProtectType = bits, U08, 0, [6:7], "Off", "Spark Only", "Fuel Only","Both" egoKP = scalar, U08, 1, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte) egoKI = scalar, U08, 2, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte) @@ -1031,17 +1033,20 @@ page = 10 ;Pressure transducers fuelPressureEnable = bits, U08, 135, [0:0], "Off", "On" oilPressureEnable = bits, U08, 135, [1:1], "Off", "On" + oilPressureProtEnbl = bits, U08, 135, [2:2], "Off", "On" fuelPressurePin = bits, U08, 136, [0:3], "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A8", "A10", "A11", "A12", "A13", "A14", "A15" oilPressurePin = bits, U08, 136, [4:7], "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A8", "A10", "A11", "A12", "A13", "A14", "A15" - fuelPressureMin = scalar, S08, 137, "kpa", 1.0, 0.0, -100, 127, 0 ;Note signed int - fuelPressureMax = scalar, U08, 138, "kpa", 1.0, 0.0, 0.0, 255, 0 - oilPressureMin = scalar, S08, 139, "kpa", 1.0, 0.0, -100, 127, 0 ;Note signed int - oilPressureMax = scalar, U08, 140, "kpa", 1.0, 0.0, 0.0, 255, 0 + fuelPressureMin = scalar, S08, 137, "psi", 1.0, 0.0, -100, 127, 0 ;Note signed int + fuelPressureMax = scalar, U08, 138, "psi", 1.0, 0.0, 0.0, 255, 0 + oilPressureMin = scalar, S08, 139, "psi", 1.0, 0.0, -100, 127, 0 ;Note signed int + oilPressureMax = scalar, U08, 140, "psi", 1.0, 0.0, 0.0, 255, 0 + + oilPressureProtRPM = array, U08, 141, [ 4], "RPM", 100.0, 0.0, 100.0, 25500, 0 + oilPressureProtMins = array, U08, 145, [ 4], "psi", 1.0, 0.0, 0.0, 255, 0 - unused11_135_191 = array, U08, 141, [50], "RPM", 100.0, 0.0, 100, 25500, 0 - ;unused11_135_191 = array, U08, 135, [56], "RPM", 100.0, 0.0, 100, 25500, 0 + unused11_135_191 = array, U08, 149, [42], "RPM", 100.0, 0.0, 100, 25500, 0 ;Page 11 is the fuel map and axis bins only page = 11 @@ -2477,6 +2482,8 @@ menuDialog = main settingOption = "0-150 PSI", oilPressureMin=-18, oilPressureMax=168 ; Vout = VCC x (P x 0.8 / 150 + 0.1) https://aftermarketindustries.com.au/image/cache/data/aftermarket%20industries%20fuel%20pressure%20sensor%20data%202-500x500.png field = "Pressure at 0v", oilPressureMin, { oilPressureEnable } field = "Pressure at 5v", oilPressureMax, { oilPressureEnable } + field = "Oil Pressure Protection", oilPressureProtEnbl, { oilPressureEnable } + panel = oil_pressure_prot_curve, { oilPressureEnable } dialog = oilPressureDialog, "Oil Pressure", xAxis gauge = oilPressureGauge @@ -3530,6 +3537,15 @@ cmdVSSratio6 = "E\x99\x06" yBins = knock_window_dur size = 400, 200 +; Oil Pressure protection curve + curve = oil_pressure_prot_curve, "Oil Pressure Protection" + columnLabel = "RPM", "Minimum PSI" + xAxis = 0, 8000, 9 + yAxis = 0, 150, 3 + xBins = oilPressureProtRPM, rpm + yBins = oilPressureProtMins + size = 400, 200 + ; Warmup enrichment VEAL AFR adjustment curves curve = warmup_afr_curve, "Target Adjustment" columnLabel = "Coolant", "Offset" @@ -3815,6 +3831,12 @@ cmdVSSratio6 = "E\x99\x06" indicator = { resetLockOn }, "Reset Lock OFF","Reset Lock ON", red, black, green, black indicator = { bootloaderCaps > 0 }, "Std. Boot", "Custom Boot", white, black, white, black indicator = { nitrousOn }, "Nitrous Off", "Nitrous On", white, black, red, black + ;Engine Protection status indicators + indicator = { engineProtectStatus}, "Engine Protect OFF", "Engine Protect ON", white, black, red, black + indicator = { engineProtectRPM }, "Rev Limiter Off", "Rev Limiter ON", white, black, red, black + indicator = { engineProtectMAP }, "Boost Limit OFF", "Boost Limit ON", white, black, red, black + indicator = { engineProtectOil }, "Oil Pres. Protect OFF","Oil Pres. Protect ON",white, black, red, black + indicator = { engineProtectAFR }, "AFR Protect OFF", "AFR Protect ON", white, black, red, black ;------------------------------------------------------------------------------- @@ -3920,6 +3942,12 @@ cmdVSSratio6 = "E\x99\x06" vssRefresh = bits, U08, 83, [3:3] unused81_4 = bits, U08, 83, [4:4] nSquirts = bits, U08, 83, [5:7] + engineProtectStatus = scalar, U08, 84, "bits", 1.000, 0.000 + engineProtectRPM = bits, U08, 84, [0:0] + engineProtectMAP = bits, U08, 84, [1:1] + engineProtectOil = bits, U08, 84, [2:2] + engineProtectAFR = bits, U08, 84, [3:3] + engineProtectOth = bits, U08, 84, [4:7] ; Unused for now unused1 = scalar, U08, 84, "ADC",1.000, 0.000 fuelLoad = scalar, S16, 85, { bitStringValue( algorithmUnits , algorithm ) }, 1.000, 0.000 ignLoad = scalar, S16, 87, { bitStringValue( algorithmUnits , ignAlgorithm ) }, 1.000, 0.000 diff --git a/speeduino/comms.ino b/speeduino/comms.ino index 1bf0b7d2..a9994e49 100644 --- a/speeduino/comms.ino +++ b/speeduino/comms.ino @@ -629,8 +629,7 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum) fullStatus[82] = highByte(currentStatus.PW4); //Pulsewidth 4 multiplied by 10 in ms. Have to convert from uS to mS. fullStatus[83] = currentStatus.status3; - - fullStatus[84] = currentStatus.nChannels; //THIS IS CURRENTLY UNUSED! + fullStatus[84] = currentStatus.engineProtectStatus; fullStatus[85] = lowByte(currentStatus.fuelLoad); fullStatus[86] = highByte(currentStatus.fuelLoad); fullStatus[87] = lowByte(currentStatus.ignLoad); diff --git a/speeduino/corrections.ino b/speeduino/corrections.ino index 385834fa..f91244cc 100644 --- a/speeduino/corrections.ino +++ b/speeduino/corrections.ino @@ -773,8 +773,8 @@ int8_t correctionKnock(int8_t advance) //First check is to do the window calculations (ASsuming knock is enabled) if( configPage10.knock_mode != KNOCK_MODE_OFF ) { - knockWindowMin = table2D_getValue(&knockWindowStartTable, currentStatus.RPM); - knockWindowMax = knockWindowMin + table2D_getValue(&knockWindowDurationTable, currentStatus.RPM); + knockWindowMin = table2D_getValue(&knockWindowStartTable, currentStatus.RPMdiv100); + knockWindowMax = knockWindowMin + table2D_getValue(&knockWindowDurationTable, currentStatus.RPMdiv100); } diff --git a/speeduino/engineProtection.h b/speeduino/engineProtection.h new file mode 100644 index 00000000..a39878b1 --- /dev/null +++ b/speeduino/engineProtection.h @@ -0,0 +1,8 @@ + + + + +byte checkEngineProtect(); +byte checkBoostLimit(); +byte checkOilPressureLimit(); +byte checkAFRLimit(); \ No newline at end of file diff --git a/speeduino/engineProtection.ino b/speeduino/engineProtection.ino new file mode 100644 index 00000000..874f5f57 --- /dev/null +++ b/speeduino/engineProtection.ino @@ -0,0 +1,75 @@ + +#include "globals.h" +#include "engineProtection.h" + +byte checkEngineProtect() +{ + byte protectActive = 0; + if(checkBoostLimit() || checkOilPressureLimit() || checkAFRLimit()) + { + if(currentStatus.RPM > (configPage4.engineProtectMaxRPM*100U)) { protectActive = 1; } + } + + return protectActive; +} + +byte checkBoostLimit() +{ + byte boostLimitActive = 0; + //Boost cutoff is very similar to launchControl, but with a check against MAP rather than a switch + if( (configPage6.boostCutType > 0) && (currentStatus.MAP > (configPage6.boostLimit * 2)) ) //The boost limit is divided by 2 to allow a limit up to 511kPa + { + boostLimitActive = 1; + switch(configPage6.boostCutType) + { + case 1: + BIT_SET(currentStatus.spark, BIT_SPARK_BOOSTCUT); + BIT_CLEAR(currentStatus.status1, BIT_STATUS1_BOOSTCUT); + BIT_SET(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_MAP); + break; + case 2: + BIT_SET(currentStatus.status1, BIT_STATUS1_BOOSTCUT); + BIT_CLEAR(currentStatus.spark, BIT_SPARK_BOOSTCUT); + break; + case 3: + BIT_SET(currentStatus.spark, BIT_SPARK_BOOSTCUT); + BIT_SET(currentStatus.status1, BIT_STATUS1_BOOSTCUT); + break; + default: + //Shouldn't ever happen, but just in case, disable all cuts + BIT_CLEAR(currentStatus.status1, BIT_STATUS1_BOOSTCUT); + BIT_CLEAR(currentStatus.spark, BIT_SPARK_BOOSTCUT); + } + } + else + { + BIT_CLEAR(currentStatus.spark, BIT_SPARK_BOOSTCUT); + BIT_CLEAR(currentStatus.status1, BIT_STATUS1_BOOSTCUT); + } + + return boostLimitActive; +} + +byte checkOilPressureLimit() +{ + byte oilProtectActive = 0; + BIT_CLEAR(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_OIL); //Will be set true below if required + + if(configPage10.oilPressureProtEnbl == true) + { + byte oilLimit = table2D_getValue(&oilPressureProtectTable, currentStatus.RPMdiv100); + if(currentStatus.oilPressure < oilLimit) + { + BIT_SET(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_OIL); + oilProtectActive = 1; + } + } + + return oilProtectActive; +} + +byte checkAFRLimit() +{ + +} + diff --git a/speeduino/globals.h b/speeduino/globals.h index 51b3fd50..e8f3ee1a 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -288,6 +288,11 @@ #define IGN7_CMD_BIT 6 #define IGN8_CMD_BIT 7 +#define ENGINE_PROTECT_BIT_RPM 0 +#define ENGINE_PROTECT_BIT_MAP 1 +#define ENGINE_PROTECT_BIT_OIL 2 +#define ENGINE_PROTECT_BIT_AFR 3 + //Table sizes #define CALIBRATION_TABLE_SIZE 512 #define CALIBRATION_TEMPERATURE_OFFSET 40 // All temperature measurements are stored offset by 40 degrees. This is so we can use an unsigned byte (0-255) to represent temperature ranges from -40 to 215 @@ -339,6 +344,7 @@ extern struct table2D flexAdvTable; //6 bin flex fuel correction table for tim extern struct table2D flexBoostTable; //6 bin flex fuel correction table for boost adjustments (2D) extern struct table2D knockWindowStartTable; extern struct table2D knockWindowDurationTable; +extern struct table2D oilPressureProtectTable; //These are for the direct port manipulation of the injectors, coils and aux outputs extern volatile PORT_TYPE *inj1_pin_port; @@ -460,6 +466,7 @@ extern volatile byte LOOP_TIMER; struct statuses { volatile bool hasSync; uint16_t RPM; + byte RPMdiv100; long longRPM; int mapADC; int baroADC; @@ -559,6 +566,7 @@ struct statuses { byte gear; /**< Current gear (Calculated from vss) */ byte fuelPressure; /**< Fuel pressure in PSI */ byte oilPressure; /**< Oil pressure in PSI */ + byte engineProtectStatus; }; /** @@ -791,7 +799,9 @@ struct config4 { byte idleAdvBins[6]; byte idleAdvValues[6]; - byte unused4_120[8]; + byte engineProtectMaxRPM; + + byte unused4_120[7]; #if defined(CORE_AVR) }; @@ -1088,7 +1098,8 @@ struct config10 { byte fuelPressureEnable : 1; byte oilPressureEnable : 1; - byte unused10_135 : 6; + byte oilPressureProtEnbl : 1; + byte unused10_135 : 5; byte fuelPressurePin : 4; byte oilPressurePin : 4; @@ -1098,7 +1109,10 @@ struct config10 { int8_t oilPressureMin; byte oilPressureMax; - byte unused11_135_191[51]; //Bytes 135-191 + byte oilPressureProtRPM[4]; + byte oilPressureProtMins[4]; + + byte unused11_135_191[43]; //Bytes 135-191 #if defined(CORE_AVR) }; diff --git a/speeduino/globals.ino b/speeduino/globals.ino index c190aa62..a4764493 100644 --- a/speeduino/globals.ino +++ b/speeduino/globals.ino @@ -38,6 +38,7 @@ struct table2D flexAdvTable; //6 bin flex fuel correction table for timing adv struct table2D flexBoostTable; //6 bin flex fuel correction table for boost adjustments (2D) struct table2D knockWindowStartTable; struct table2D knockWindowDurationTable; +struct table2D oilPressureProtectTable; //These are for the direct port manipulation of the injectors, coils and aux outputs volatile PORT_TYPE *inj1_pin_port; diff --git a/speeduino/init.ino b/speeduino/init.ino index 2ceecf81..0c4e3604 100644 --- a/speeduino/init.ino +++ b/speeduino/init.ino @@ -182,6 +182,12 @@ void initialiseAll() knockWindowDurationTable.values = configPage10.knock_window_dur; knockWindowDurationTable.axisX = configPage10.knock_window_rpms; + oilPressureProtectTable.valueSize = SIZE_BYTE; + oilPressureProtectTable.axisSize = SIZE_BYTE; //Set this table to use byte axis bins + oilPressureProtectTable.xSize = 4; + oilPressureProtectTable.values = configPage10.oilPressureProtMins; + oilPressureProtectTable.axisX = configPage10.oilPressureProtRPM; + //Setup the calibration tables loadCalibration(); @@ -316,6 +322,7 @@ void initialiseAll() currentStatus.launchingHard = false; currentStatus.crankRPM = ((unsigned int)configPage4.crankRPM * 10); //Crank RPM limit (Saves us calculating this over and over again. It's updated once per second in timers.ino) currentStatus.fuelPumpOn = false; + currentStatus.engineProtectStatus = 0; triggerFilterTime = 0; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise. This is simply a default value, the actual values are set in the setup() functinos of each decoder dwellLimit_uS = (1000 * configPage4.dwellLimit); currentStatus.nChannels = ((uint8_t)INJ_CHANNELS << 4) + IGN_CHANNELS; //First 4 bits store the number of injection channels, 2nd 4 store the number of ignition channels @@ -325,7 +332,7 @@ void initialiseAll() timer5_overflow_count = 0; toothHistoryIndex = 0; toothHistorySerialIndex = 0; - + noInterrupts(); initialiseTriggers(); diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index 4fb6966d..9d304d77 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "storage.h" #include "crankMaths.h" #include "init.h" +#include "engineProtection.h" #include BOARD_H //Note that this is not a real file, it is defined in globals.h. int ignition1StartAngle = 0; @@ -145,6 +146,7 @@ void loop() { currentStatus.longRPM = getRPM(); //Long RPM is included here currentStatus.RPM = currentStatus.longRPM; + currentStatus.RPMdiv100 = currentStatus.RPM / 100; FUEL_PUMP_ON(); currentStatus.fuelPumpOn = true; //Not sure if this is needed. } @@ -228,37 +230,6 @@ void loop() else { currentStatus.flatShiftingHard = false; } } - - - //Boost cutoff is very similar to launchControl, but with a check against MAP rather than a switch - if( (configPage6.boostCutType > 0) && (currentStatus.MAP > (configPage6.boostLimit * 2)) ) //The boost limit is divided by 2 to allow a limit up to 511kPa - { - switch(configPage6.boostCutType) - { - case 1: - BIT_SET(currentStatus.spark, BIT_SPARK_BOOSTCUT); - BIT_CLEAR(currentStatus.status1, BIT_STATUS1_BOOSTCUT); - break; - case 2: - BIT_SET(currentStatus.status1, BIT_STATUS1_BOOSTCUT); - BIT_CLEAR(currentStatus.spark, BIT_SPARK_BOOSTCUT); - break; - case 3: - BIT_SET(currentStatus.spark, BIT_SPARK_BOOSTCUT); - BIT_SET(currentStatus.status1, BIT_STATUS1_BOOSTCUT); - break; - default: - //Shouldn't ever happen, but just in case, disable all cuts - BIT_CLEAR(currentStatus.status1, BIT_STATUS1_BOOSTCUT); - BIT_CLEAR(currentStatus.spark, BIT_SPARK_BOOSTCUT); - } - } - else - { - BIT_CLEAR(currentStatus.spark, BIT_SPARK_BOOSTCUT); - BIT_CLEAR(currentStatus.status1, BIT_STATUS1_BOOSTCUT); - } - //And check whether the tooth log buffer is ready if(toothHistoryIndex > TOOTH_LOG_SIZE) { BIT_SET(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY); } @@ -932,7 +903,7 @@ void loop() //Perform an initial check to see if the ignition is turned on (Ignition only turns on after a preset number of cranking revolutions and: //Check for any of the hard cut rev limits being on - if(currentStatus.launchingHard || BIT_CHECK(currentStatus.spark, BIT_SPARK_BOOSTCUT) || BIT_CHECK(currentStatus.spark, BIT_SPARK_HRDLIM) || currentStatus.flatShiftingHard) + if(checkEngineProtect() || currentStatus.launchingHard || BIT_CHECK(currentStatus.spark, BIT_SPARK_HRDLIM) || currentStatus.flatShiftingHard) { if(configPage2.hardCutType == HARD_CUT_FULL) { ignitionOn = false; } else