AFR protection function (#861)
* Implementing AFR protection * Update globals.h * Bug fixes and code refactoring * Moved variables to prevent ODR * Dialog for AFR protection * Data size and math corrections * Possibility to use either AFR or lambda * Updated default AFR protection values * No need to do multiplications due to existing RPMdiv100 variable * The X100 multiplier was wrongfully removed * Add defaults in updates.ino, minor formatting cleanups Co-authored-by: Josh Stewart <josh@noisymime.org>
This commit is contained in:
parent
f64d9348dc
commit
298d994ba1
|
@ -1055,7 +1055,21 @@ page = 9
|
|||
#else
|
||||
coolantProtTemp = array, U08, 173, [6], "F", 1.8, -22.23, -40, 215, 0
|
||||
#endif
|
||||
unused179_191 = array, U08, 179, [13], "", 1, 0, 0, 255, 0
|
||||
|
||||
unused179_184 = array, U08, 179, [6], "", 1, 0, 0, 255, 0
|
||||
|
||||
; AFR engine protection
|
||||
afrProtectEnabled = bits, U08, 185, [0:0], "Off", "On"
|
||||
afrProtectMAP = scalar, U08, 186, "kPa", 2.0, 0.0, 0.0, 511.0, 0 ; 8 bit value, 1 byte
|
||||
afrProtectRPM = scalar, U08, 187, "RPM", 100, 0.0, 100, 25500, 0 ; 8 bit value, 1 byte
|
||||
afrProtectTPS = scalar, U08, 188, "%", 0.5, 0.0, 0.0, 100.0, 1 ; 8 bit value, 1 byte
|
||||
#if LAMBDA
|
||||
afrProtectDeviation = scalar, U08, 189, "Lambda", {0.1 / stoich}, 0.0, 0.00, 25.5, 2 ; 8 bit value, 1 byte
|
||||
#else
|
||||
afrProtectDeviation = scalar, U08, 189, "AFR", 0.1, 0.0, 0.0, 25.5, 1 ; 8 bit value, 1 byte
|
||||
#endif
|
||||
afrProtectCutTime = scalar, U08, 190, "seconds", 0.1, 0.0, 0.0, 2.5, 1 ; 8 bit value, 1 byte
|
||||
afrProtectReactivationTPS = scalar, U08, 191, "%", 0.5, 0.0, 0.0, 100.0, 1 ; 8 bit value, 1 byte
|
||||
|
||||
page = 10
|
||||
#if CELSIUS
|
||||
|
@ -1571,6 +1585,19 @@ page = 15
|
|||
#endif
|
||||
defaultValue = vvtDelay, 60
|
||||
|
||||
; AFR protection default values
|
||||
defaultValue = afrProtectEnabled, 0
|
||||
defaultValue = afrProtectMAP, 180
|
||||
defaultValue = afrProtectRPM, 4000
|
||||
defaultValue = afrProtectTPS, 80
|
||||
#if LAMBDA
|
||||
defaultValue = afrProtectDeviation, 0.10
|
||||
#else
|
||||
defaultValue = afrProtectDeviation, 1.47
|
||||
#endif
|
||||
defaultValue = afrProtectCutTime, 0.8
|
||||
defaultValue = afrProtectReactivationTPS, 20
|
||||
|
||||
;Default pins
|
||||
defaultValue = fanPin, 0
|
||||
defaultValue = vvt1Pin, 0
|
||||
|
@ -1757,6 +1784,7 @@ menuDialog = main
|
|||
groupChildMenu = revLimiterDialog, "Rev Limiters", { engineProtectType }
|
||||
groupChildMenu = boostCut, "Boost Cut", { engineProtectType }
|
||||
groupChildMenu = oilPressureProtection, "Oil Pressure", { engineProtectType }
|
||||
groupChildMenu = afrProtect, "AFR Protection", { engineProtectType }
|
||||
subMenu = flexFuel, "Flex Fuel", 2
|
||||
subMenu = veTableDialog, "VE Table", 0
|
||||
subMenu = sparkTbl, "Spark Table", 2
|
||||
|
@ -1995,6 +2023,18 @@ menuDialog = main
|
|||
hardRevLim = "A fixed hard rev limit is a single point that the fuel or ignition (or both) will be cut completely to reduce increasing RPMs"
|
||||
engineProtectMaxRPM = "The RPM point that engine protections will engage from. Below this RPM value, engine protections will NOT be active"
|
||||
|
||||
; AFR Protection Help
|
||||
afrProtectMAP = "Minimum manifold air pressure the AFR lean protection will activate"
|
||||
afrProtectRPM = "The minimum RPM the AFR lean protection will activate"
|
||||
afrProtectTPS = "The minimum current throttle position for the AFR lean protection to activate"
|
||||
#if LAMBDA
|
||||
afrProtectDeviation = "Maximum deviation from current lambda value in which lean protection will activate"
|
||||
#else
|
||||
afrProtectDeviation = "Maximum deviation from current AFR value in which lean protection will activate"
|
||||
#endif
|
||||
afrProtectCutTime = "A time delay before activating engine protection when all conditions has been met"
|
||||
afrProtectReactivationTPS = "Going below this throttle position (%) will deactivate this protection"
|
||||
|
||||
fuel2InputPin = "The Arduino pin that is being used to trigger the second fuel table to be active"
|
||||
fuel2InputPolarity = "Whether the 2nd fuel table should be active when input is high or low. This should be LOW for a typical ground switching input"
|
||||
fuel2InputPullup = "Whether to use the built in PULLUP for the switching input. This should be Yes for a typical ground switching input"
|
||||
|
@ -2818,7 +2858,23 @@ menuDialog = main
|
|||
field = "Oil Pressure Protection", oilPressureProtEnbl, { oilPressureEnable }
|
||||
panel = oil_pressure_prot_curve, { oilPressureEnable && oilPressureProtEnbl }
|
||||
|
||||
|
||||
; AFR engine protection dialog
|
||||
dialog = afrProtect, "AFR Protection", yAxis
|
||||
field = "AFR protection is used to prevent engine from running lean"
|
||||
field = "#Note: This function requires wideband sensor and proper AFR table"
|
||||
field = ""
|
||||
field = "Enable AFR protection ", afrProtectEnabled, {egoType == 2}
|
||||
field = "Minimum manifold air pressure ", afrProtectMAP, {afrProtectEnabled}
|
||||
field = "Minimum engine RPM ", afrProtectRPM, {afrProtectEnabled}
|
||||
field = "Minimum throttle position ", afrProtectTPS, {afrProtectEnabled}
|
||||
#if LAMBDA
|
||||
field = "Maximum lambda deviation ", afrProtectDeviation, {afrProtectEnabled}
|
||||
#else
|
||||
field = "Maximum AFR deviation ", afrProtectDeviation, {afrProtectEnabled}
|
||||
#endif
|
||||
field = "Time before cut ", afrProtectCutTime, {afrProtectEnabled}
|
||||
field = ""
|
||||
field = "Reactivate below throttle ", afrProtectReactivationTPS, {afrProtectEnabled}
|
||||
|
||||
indicatorPanel = protectIndicatorPanel, 1, { 1 }
|
||||
indicator = { engineProtectStatus}, "Engine Protect OFF", "Engine Protect ON", green, black, red, black
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define HARD_REV_FIXED 1
|
||||
#define HARD_REV_COOLANT 2
|
||||
|
||||
|
||||
byte checkEngineProtect();
|
||||
byte checkRevLimit();
|
||||
byte checkBoostLimit();
|
||||
|
|
|
@ -112,7 +112,85 @@ byte checkOilPressureLimit()
|
|||
|
||||
byte checkAFRLimit()
|
||||
{
|
||||
byte checkAFRLimitActive = 0;
|
||||
static bool checkAFRLimitActive = false;
|
||||
static bool afrProtectCountEnabled = false;
|
||||
static unsigned long afrProtectCount = 0;
|
||||
static constexpr char X2_MULTIPLIER = 2;
|
||||
static constexpr char X100_MULTIPLIER = 100;
|
||||
|
||||
/*
|
||||
To use this function, a wideband sensor is required.
|
||||
|
||||
First of all, check whether engine protection is enabled,
|
||||
thereafter check whether AFR protection is enabled and at last
|
||||
if wideband sensor is used.
|
||||
|
||||
After confirmation, the following conditions has to be met:
|
||||
- MAP above x kPa
|
||||
- RPM above x
|
||||
- TPS above x %
|
||||
- AFR threshold (AFR target + defined maximum deviation)
|
||||
- Time before cut
|
||||
|
||||
See afrProtect variables in globals.h for more information.
|
||||
|
||||
If all conditions above are true, a specified time delay is starting
|
||||
to count down in which leads to the engine protection function
|
||||
to be activated using selected protection cut method (e.g. ignition,
|
||||
fuel or both).
|
||||
|
||||
For reactivation, the following condition has to be met:
|
||||
- TPS below x %
|
||||
*/
|
||||
|
||||
/*
|
||||
Do 3 checks here;
|
||||
- whether engine protection is enabled
|
||||
- whether AFR protection is enabled
|
||||
- whether wideband sensor is used
|
||||
*/
|
||||
if(configPage6.engineProtectType != PROTECT_CUT_OFF && configPage9.afrProtectEnabled && configPage6.egoType == EGO_TYPE_WIDE) {
|
||||
/* Conditions */
|
||||
bool mapCondition = (currentStatus.MAP >= (configPage9.afrProtectMinMAP * X2_MULTIPLIER)) ? true : false;
|
||||
bool rpmCondition = (currentStatus.RPMdiv100 >= configPage9.afrProtectMinRPM) ? true : false;
|
||||
bool tpsCondition = (currentStatus.TPS >= configPage9.afrProtectMinTPS) ? true : false;
|
||||
bool afrCondition = (currentStatus.O2 >= (currentStatus.afrTarget + configPage9.afrProtectDeviation)) ? true : false;
|
||||
|
||||
/* Check if conditions above are fulfilled */
|
||||
if(mapCondition && rpmCondition && tpsCondition && afrCondition)
|
||||
{
|
||||
/* All conditions fulfilled - start counter for 'protection delay' */
|
||||
if(!afrProtectCountEnabled)
|
||||
{
|
||||
afrProtectCountEnabled = true;
|
||||
afrProtectCount = millis();
|
||||
}
|
||||
|
||||
/* Check if countdown has reached its target, if so then instruct to cut */
|
||||
if(millis() >= (afrProtectCount + (configPage9.afrProtectCutTime * X100_MULTIPLIER)))
|
||||
{
|
||||
checkAFRLimitActive = true;
|
||||
BIT_SET(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_AFR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Conditions have presumably changed - deactivate and reset counter */
|
||||
if(afrProtectCountEnabled)
|
||||
{
|
||||
afrProtectCountEnabled = false;
|
||||
afrProtectCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if condition for reactivation is fulfilled */
|
||||
if(checkAFRLimitActive && (currentStatus.TPS <= configPage9.afrProtectReactivationTPS))
|
||||
{
|
||||
checkAFRLimitActive = false;
|
||||
afrProtectCountEnabled = false;
|
||||
BIT_CLEAR(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_AFR);
|
||||
}
|
||||
}
|
||||
|
||||
return checkAFRLimitActive;
|
||||
}
|
||||
|
|
|
@ -248,6 +248,10 @@
|
|||
#define COMPOSITE_LOG_TRIG 2
|
||||
#define COMPOSITE_LOG_SYNC 3
|
||||
|
||||
#define EGO_TYPE_OFF 0
|
||||
#define EGO_TYPE_NARROW 1
|
||||
#define EGO_TYPE_WIDE 2
|
||||
|
||||
#define INJ_TYPE_PORT 0
|
||||
#define INJ_TYPE_TBODY 1
|
||||
|
||||
|
@ -1180,13 +1184,13 @@ struct config9 {
|
|||
byte unused10_182;
|
||||
byte unused10_183;
|
||||
byte unused10_184;
|
||||
byte unused10_185;
|
||||
byte unused10_186;
|
||||
byte unused10_187;
|
||||
byte unused10_188;
|
||||
byte unused10_189;
|
||||
byte unused10_190;
|
||||
byte unused10_191;
|
||||
byte afrProtectEnabled : 1; /* < AFR protection enabled status. 0 = disabled, 1 = enabled */
|
||||
byte afrProtectMinMAP; /* < Minimum MAP. Stored value is divided by 2. Increments of 2 kPa, maximum 511 (?) kPa */
|
||||
byte afrProtectMinRPM; /* < Minimum RPM. Stored value is divded by 100. Increments of 100 RPM, maximum 25500 RPM */
|
||||
byte afrProtectMinTPS; /* < Minimum TPS. */
|
||||
byte afrProtectDeviation; /* < Maximum deviation from AFR target table. Stored value is multiplied by 10 */
|
||||
byte afrProtectCutTime; /* < Time in ms before cut. Stored value is divided by 100. Maximum of 2550 ms */
|
||||
byte afrProtectReactivationTPS; /* Disable engine protection cut once below this TPS percentage */
|
||||
|
||||
#if defined(CORE_AVR)
|
||||
};
|
||||
|
|
|
@ -1328,7 +1328,7 @@ uint16_t PW(int REQ_FUEL, byte VE, long MAP, uint16_t corrections, int injOpen)
|
|||
if ( configPage2.multiplyMAP == MULTIPLY_MAP_MODE_100) { iMAP = ((unsigned int)MAP << 7) / 100; }
|
||||
else if( configPage2.multiplyMAP == MULTIPLY_MAP_MODE_BARO) { iMAP = ((unsigned int)MAP << 7) / currentStatus.baro; }
|
||||
|
||||
if ( (configPage2.includeAFR == true) && (configPage6.egoType == 2) && (currentStatus.runSecs > configPage6.ego_sdelay) ) {
|
||||
if ( (configPage2.includeAFR == true) && (configPage6.egoType == EGO_TYPE_WIDE) && (currentStatus.runSecs > configPage6.ego_sdelay) ) {
|
||||
iAFR = ((unsigned int)currentStatus.O2 << 7) / currentStatus.afrTarget; //Include AFR (vs target) if enabled
|
||||
}
|
||||
if ( (configPage2.incorporateAFR == true) && (configPage2.includeAFR == false) ) {
|
||||
|
@ -1341,7 +1341,7 @@ uint16_t PW(int REQ_FUEL, byte VE, long MAP, uint16_t corrections, int injOpen)
|
|||
unsigned long intermediate = ((uint32_t)REQ_FUEL * (uint32_t)iVE) >> 7; //Need to use an intermediate value to avoid overflowing the long
|
||||
if ( configPage2.multiplyMAP > 0 ) { intermediate = (intermediate * (unsigned long)iMAP) >> 7; }
|
||||
|
||||
if ( (configPage2.includeAFR == true) && (configPage6.egoType == 2) && (currentStatus.runSecs > configPage6.ego_sdelay) ) {
|
||||
if ( (configPage2.includeAFR == true) && (configPage6.egoType == EGO_TYPE_WIDE) && (currentStatus.runSecs > configPage6.ego_sdelay) ) {
|
||||
//EGO type must be set to wideband and the AFR warmup time must've elapsed for this to be used
|
||||
intermediate = (intermediate * (unsigned long)iAFR) >> 7;
|
||||
}
|
||||
|
|
|
@ -659,6 +659,13 @@ void doUpdates()
|
|||
++table_Y;
|
||||
}
|
||||
|
||||
//AFR Protection added, add default values
|
||||
configPage9.afrProtectEnabled = 0; //Disable by default
|
||||
configPage9.afrProtectMinMAP = 90; //Is divided by 2, vlue represents 180kPa
|
||||
configPage9.afrProtectMinRPM = 40; //4000 RPM min
|
||||
configPage9.afrProtectMinTPS = 160; //80% TPS min
|
||||
configPage9.afrProtectDeviation = 14; //1.4 AFR deviation
|
||||
|
||||
writeAllConfig();
|
||||
storeEEPROMVersion(20);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue