From f8ffbb13da2e6e1f261b294ca23b8865d720d29d Mon Sep 17 00:00:00 2001 From: "Vitor Moreno B. Sales" Date: Tue, 24 Oct 2023 20:09:57 -0300 Subject: [PATCH] Added taper entering DFCO (#1118) * Added taper for DFCO for ignition and fuel Used 1 byte of RAM and 4 on page 9 * Moved data to be compatible with DFCO map thres * Added taper for DFCO for ignition and fuel Used 1 byte of RAM and 4 on page 9 * Moved data to be compatible with DFCO map thres * Fixed potential overflow and DFCO tests * Moved math into functions and added tests --------- Co-authored-by: Josh Stewart --- reference/speeduino.ini | 14 +++++- speeduino/corrections.cpp | 55 +++++++++++++++++++++--- speeduino/corrections.h | 5 ++- speeduino/globals.h | 12 ++++-- speeduino/updates.cpp | 6 ++- test/test_fuel/test_corrections.cpp | 66 ++++++++++++++++++++++++++++- 6 files changed, 143 insertions(+), 15 deletions(-) diff --git a/reference/speeduino.ini b/reference/speeduino.ini index ad54524b..6404adfe 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -1075,7 +1075,15 @@ page = 9 coolantProtTemp = array, U08, 173, [6], "F", 1.8, -22.23, -40, 419, 0 #endif - unused179_184 = array, U08, 179, [6], "", 1, 0, 0, 255, 0 + unused10_179 = scalar, U08, 179, "", 1, 0, 0, 255, 0 + + dfcoTaperTime = scalar, U08, 180, "S", 0.1, 0.0, 0.0, 25.5, 1 + dfcoTaperFuel = scalar, U08, 181, "%", 1.0, 0.0, 0, 255, 0 + dfcoTaperAdvance = scalar, U08, 182, "deg", 1.0, 0.0, 0, 40, 0 + dfcoTaperEnable = bits, U08, 183, [0:0], "Off", "On" + unused10_182 = bits, U08, 183, [1:7], "" + + unused10_184 = scalar, U08, 184, "", 1, 0, 0, 255, 0 ; AFR engine protection afrProtectEnabled = bits, U08, 185, [0:1], "Off", "Fixed mode", "Table mode", "INVALID" @@ -2594,6 +2602,10 @@ menuDialog = main field = "Cutoff delay", dfcoDelay, { dfcoEnabled } field = "Cutoff RPM", dfcoRPM, { dfcoEnabled } field = "RPM Hysteresis", dfcoHyster, { dfcoEnabled } + field = "Enable cutoff taper", dfcoTaperEnable, { dfcoEnabled } + field = "Cutoff taper time", dfcoTaperTime, { dfcoEnabled && dfcoTaperEnable } + field = "Taper end fuel amount", dfcoTaperFuel, { dfcoEnabled && dfcoTaperEnable } + field = "Taper advance remove", dfcoTaperAdvance, { dfcoEnabled && dfcoTaperEnable } dialog = accelEnrichments_north_south, "" liveGraph = pump_ae_Graph, "AE Graph" diff --git a/speeduino/corrections.cpp b/speeduino/corrections.cpp index 4cce67a6..77caa3e7 100644 --- a/speeduino/corrections.cpp +++ b/speeduino/corrections.cpp @@ -48,9 +48,10 @@ byte lastKnockCount; int16_t knockWindowMin; //The current minimum crank angle for a knock pulse to be valid int16_t knockWindowMax;//The current maximum crank angle for a knock pulse to be valid uint8_t aseTaper; -uint8_t dfcoTaper; +uint8_t dfcoDelay; uint8_t idleAdvTaper; uint8_t crankingEnrichTaper; +uint8_t dfcoTaper; /** Initialise instances and vars related to corrections (at ECU boot-up). */ @@ -122,7 +123,9 @@ uint16_t correctionsFuel(void) if (currentStatus.launchCorrection != 100) { sumCorrections = div100(sumCorrections * currentStatus.launchCorrection); } bitWrite(currentStatus.status1, BIT_STATUS1_DFCO, correctionDFCO()); - if ( BIT_CHECK(currentStatus.status1, BIT_STATUS1_DFCO) == 1 ) { sumCorrections = 0; } + byte dfcoTaperCorrection = correctionDFCOfuel(); + if (dfcoTaperCorrection == 0) { sumCorrections = 0; } + else if (dfcoTaperCorrection != 100) { sumCorrections = div100(sumCorrections * dfcoTaperCorrection); } if(sumCorrections > 1500) { sumCorrections = 1500; } //This is the maximum allowable increase during cranking return (uint16_t)sumCorrections; @@ -539,6 +542,27 @@ byte correctionLaunch(void) return launchValue; } +/** +*/ +byte correctionDFCOfuel(void) +{ + byte scaleValue = 100; + if ( BIT_CHECK(currentStatus.status1, BIT_STATUS1_DFCO) ) + { + if ( (configPage9.dfcoTaperEnable == 1) && (dfcoTaper != 0) ) + { + //Do a check if the user reduced the duration while active to avoid overflow + if (dfcoTaper > configPage9.dfcoTaperTime) { dfcoTaper = configPage9.dfcoTaperTime; } + scaleValue = map(dfcoTaper, configPage9.dfcoTaperTime, 0, 100, configPage9.dfcoTaperFuel); + if( BIT_CHECK(LOOP_TIMER, BIT_TIMER_10HZ) ) { dfcoTaper--; } + } + else { scaleValue = 0; } //Taper ended or disabled, disable fuel + } + else { dfcoTaper = configPage9.dfcoTaperTime; } //Keep updating the duration until DFCO is active + + return scaleValue; +} + /* * Returns true if deceleration fuel cutoff should be on, false if its off */ @@ -550,19 +574,19 @@ bool correctionDFCO(void) if ( BIT_CHECK(currentStatus.status1, BIT_STATUS1_DFCO) == 1 ) { DFCOValue = ( currentStatus.RPM > ( configPage4.dfcoRPM * 10) ) && ( currentStatus.TPS < configPage4.dfcoTPSThresh ); - if ( DFCOValue == false) { dfcoTaper = 0; } + if ( DFCOValue == false) { dfcoDelay = 0; } } else { if ( (currentStatus.TPS < configPage4.dfcoTPSThresh) && (currentStatus.coolant >= (int)(configPage2.dfcoMinCLT - CALIBRATION_TEMPERATURE_OFFSET)) && ( currentStatus.RPM > (unsigned int)( (configPage4.dfcoRPM * 10) + (configPage4.dfcoHyster * 2)) ) ) { - if( dfcoTaper < configPage2.dfcoDelay ) + if( dfcoDelay < configPage2.dfcoDelay ) { - if( BIT_CHECK(LOOP_TIMER, BIT_TIMER_10HZ) ) { dfcoTaper++; } + if( BIT_CHECK(LOOP_TIMER, BIT_TIMER_10HZ) ) { dfcoDelay++; } } else { DFCOValue = true; } } - else { dfcoTaper = 0; } //Prevent future activation right away if previous time wasn't activated + else { dfcoDelay = 0; } //Prevent future activation right away if previous time wasn't activated } // DFCO active check } // DFCO enabled check return DFCOValue; @@ -702,6 +726,8 @@ int8_t correctionsIgn(int8_t base_advance) advance = correctionSoftFlatShift(advance); advance = correctionKnock(advance); + advance = correctionDFCOignition(advance); + //Fixed timing check must go last advance = correctionFixedTiming(advance); advance = correctionCrankingFixedTiming(advance); //This overrides the regular fixed timing, must come last @@ -936,6 +962,23 @@ int8_t correctionKnock(int8_t advance) return advance - knockRetard; } +/** Ignition DFCO taper correction. + */ +int8_t correctionDFCOignition(int8_t advance) +{ + int8_t dfcoRetard = advance; + if ( (configPage9.dfcoTaperEnable == 1) && BIT_CHECK(currentStatus.status1, BIT_STATUS1_DFCO) ) + { + if ( dfcoTaper != 0 ) + { + dfcoRetard -= map(dfcoTaper, configPage9.dfcoTaperTime, 0, 0, configPage9.dfcoTaperAdvance); + } + else { dfcoRetard -= configPage9.dfcoTaperAdvance; } //Taper ended, use full value + } + else { dfcoTaper = configPage9.dfcoTaperTime; } //Keep updating the duration until DFCO is active + return dfcoRetard; +} + /** Ignition Dwell Correction. */ uint16_t correctionsDwell(uint16_t dwell) diff --git a/speeduino/corrections.h b/speeduino/corrections.h index f87d2aab..e2f6e0c5 100644 --- a/speeduino/corrections.h +++ b/speeduino/corrections.h @@ -21,6 +21,7 @@ byte correctionBatVoltage(void); //Battery voltage correction byte correctionIATDensity(void); //Inlet temp density correction byte correctionBaro(void); //Barometric pressure correction byte correctionLaunch(void); //Launch control correction +byte correctionDFCOfuel(void); //DFCO taper correction bool correctionDFCO(void); //Decelleration fuel cutoff @@ -37,6 +38,7 @@ int8_t correctionNitrous(int8_t advance); int8_t correctionSoftLaunch(int8_t advance); int8_t correctionSoftFlatShift(int8_t advance); int8_t correctionKnock(int8_t advance); +int8_t correctionDFCOignition(int8_t advance); uint16_t correctionsDwell(uint16_t dwell); @@ -49,8 +51,9 @@ extern byte lastKnockCount; extern int16_t knockWindowMin; //The current minimum crank angle for a knock pulse to be valid extern int16_t knockWindowMax;//The current maximum crank angle for a knock pulse to be valid extern uint8_t aseTaper; -extern uint8_t dfcoTaper; +extern uint8_t dfcoDelay; extern uint8_t idleAdvTaper; extern uint8_t crankingEnrichTaper; +extern uint8_t dfcoTaper; #endif // CORRECTIONS_H diff --git a/speeduino/globals.h b/speeduino/globals.h index 41422806..c8bbfe2d 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -1128,12 +1128,16 @@ struct config9 { byte hardRevMode : 2; byte coolantProtRPM[6]; byte coolantProtTemp[6]; + byte unused10_179; - byte unused10_180; - byte unused10_181; - byte unused10_182; - byte unused10_183; + byte dfcoTaperTime; + byte dfcoTaperFuel; + byte dfcoTaperAdvance; + byte dfcoTaperEnable : 1; + byte unused10_183 : 6; + byte unused10_184; + byte afrProtectEnabled : 2; /* < AFR protection enabled status. 0 = disabled, 1 = fixed mode, 2 = table mode */ 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 */ diff --git a/speeduino/updates.cpp b/speeduino/updates.cpp index 5197a6cd..94d5f52d 100644 --- a/speeduino/updates.cpp +++ b/speeduino/updates.cpp @@ -727,7 +727,11 @@ void doUpdates(void) if(readEEPROMVersion() == 22) { //202311-dev - + configPage9.dfcoTaperEnable = 0; //Disable + configPage9.dfcoTaperTime = 10; //1 second + configPage9.dfcoTaperFuel = 100; //Don't scale fuel + configPage9.dfcoTaperAdvance = 20; //Reduce 20deg until full fuel cut + //EGO MAP Limits configPage9.egoMAPMax = 255, // 255 will be 510 kpa configPage9.egoMAPMin = 0, // 0 will be 0 kpa diff --git a/test/test_fuel/test_corrections.cpp b/test/test_fuel/test_corrections.cpp index b8810bf2..1205c973 100644 --- a/test/test_fuel/test_corrections.cpp +++ b/test/test_fuel/test_corrections.cpp @@ -137,9 +137,9 @@ void setup_DFCO_on() configPage2.dfcoMinCLT = 40; //Actually 0 with offset configPage2.dfcoDelay = 10; - dfcoTaper = 1; + dfcoDelay = 1; correctionDFCO(); - dfcoTaper = 20; + dfcoDelay = 20; } //********************************************************************************************************************** void test_corrections_dfco_on(void) @@ -178,6 +178,65 @@ void test_corrections_dfco_off_delay() TEST_ASSERT_FALSE(correctionDFCO()); //Make sure DFCO does not come on } +void setup_DFCO_taper_on() +{ + //Test that DFCO comes will not activate if there has not been a long enough delay + //The steup function below simulates a 2 second delay + setup_DFCO_on(); + + configPage9.dfcoTaperEnable = 1; //Enable + configPage9.dfcoTaperTime = 20; //2.0 second + configPage9.dfcoTaperFuel = 0; //Scale fuel to 0% + configPage9.dfcoTaperAdvance = 20; //Reduce 20deg until full fuel cut + + BIT_CLEAR(currentStatus.status1, BIT_STATUS1_DFCO); + //Set the threshold to be 2.5 seconds, above the simulated delay of 2s + configPage2.dfcoDelay = 250; +} +void test_corrections_dfco_taper() +{ + setup_DFCO_taper_on(); + + TEST_ASSERT_FALSE(correctionDFCO()); //Make sure DFCO does not come on + correctionDFCOfuel(); + TEST_ASSERT_EQUAL(20, dfcoTaper); //Check if value was reset to setting +} +void test_corrections_dfco_taper_fuel() +{ + setup_DFCO_taper_on(); + + correctionDFCOfuel(); + TEST_ASSERT_EQUAL(20, dfcoTaper); //Check if value was reset to setting + + BIT_SET(currentStatus.status1, BIT_STATUS1_DFCO); + dfcoTaper = 10; + TEST_ASSERT_EQUAL(50, correctionDFCOfuel()); + dfcoTaper = 5; + TEST_ASSERT_EQUAL(25, correctionDFCOfuel()); + + configPage9.dfcoTaperTime = 10; //1.0 second + dfcoTaper = 15; //Check for overflow + TEST_ASSERT_EQUAL(100, correctionDFCOfuel()); + configPage9.dfcoTaperEnable = 0; //Disable + TEST_ASSERT_EQUAL(0, correctionDFCOfuel()); +} +void test_corrections_dfco_taper_ign() +{ + setup_DFCO_taper_on(); + + dfcoTaper = 20; + BIT_SET(currentStatus.status1, BIT_STATUS1_DFCO); + + TEST_ASSERT_EQUAL(20, correctionDFCOignition(20)); + dfcoTaper = 15; + TEST_ASSERT_EQUAL(15, correctionDFCOignition(20)); + dfcoTaper = 10; + TEST_ASSERT_EQUAL(10, correctionDFCOignition(20)); + dfcoTaper = 5; + TEST_ASSERT_EQUAL(5, correctionDFCOignition(20)); + configPage9.dfcoTaperEnable = 0; //Disable + TEST_ASSERT_EQUAL(20, correctionDFCOignition(20)); +} void test_corrections_dfco() { @@ -185,6 +244,9 @@ void test_corrections_dfco() RUN_TEST(test_corrections_dfco_off_RPM); RUN_TEST(test_corrections_dfco_off_TPS); RUN_TEST(test_corrections_dfco_off_delay); + RUN_TEST(test_corrections_dfco_taper); + RUN_TEST(test_corrections_dfco_taper_fuel); + RUN_TEST(test_corrections_dfco_taper_ign); } //********************************************************************************************************************** //Setup a basic TAE enrichment curve, threshold etc that are common to all tests. Specifica values maybe updated in each individual test