Merge branch 'master' into Pulsed-HW-Test

This commit is contained in:
Josh Stewart 2023-10-27 09:24:38 +11:00 committed by GitHub
commit 510351fe79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 212 additions and 62 deletions

View File

@ -44,7 +44,7 @@ jobs:
env:
MISRA_GIST: ${{ secrets.MISRA_GIST }}
VIOLATIONS: ${{ env.VIOLATIONS }}
uses: schneegans/dynamic-badges-action@v1.6.0
uses: schneegans/dynamic-badges-action@v1.7.0
with:
auth: ${{ secrets.MISRA_GIST }}
gistID: d8a449a3f6d3307dab457431512502f9

View File

@ -1005,8 +1005,8 @@ page = 9
unused10_110 = scalar, U08, 110, "", 1, 0, 0, 255, 0
unused10_111 = scalar, U08, 111, "", 1, 0, 0, 255, 0
unused10_112 = scalar, U08, 112, "", 1, 0, 0, 255, 0
unused10_113 = scalar, U08, 113, "", 1, 0, 0, 255, 0
egoMAPMax = scalar, U08, 112, "kPa", 2.0, 0.0, 2.0, 511.0, 0
egoMAPMin = scalar, U08, 113, "kPa", 2.0, 0.0, 2.0, 511.0, 0
speeduino_tsCanId = bits, U08, 114, [0:3], $tsCanId_list
true_address = bits, U16, 115, [0:10], $CAN_ADDRESS_HEX
@ -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"
@ -1839,6 +1847,9 @@ page = 15
defaultValue = rollingProtRPMDelta, -300 -200 -100 -50
defaultValue = rollingProtCutPercent, 50 65 80 95
defaultValue = egoMAPMax, 100
defaultValue = egoMAPMin, 26
#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
@ -2415,6 +2426,9 @@ menuDialog = main
boostDCWhenDisabled = "When the closedloop boost controller is disabled by 'enable trigger', this is the Duty cycle set on the boost selenoid. Ususally this is 99% because it keeps the waste gate firmly closed until the threshold and builds boost as fast as possible (no wastegate leak)"
boostControlEnableThreshold = "When the 'Boost control enable trigger' is set to 'fixed', this value is used as threshold. Usually the value is set just below the wastgate pressure of the used turbo setup. For example 130kpa for a 0.3 bar wastegate actuator. Below this value the ECU has no control over the boost anyway."
egoMAPMax = "Only Correct below this MAP Value"
egoMAPMin = "Only Correct above this MAP Value"
[UserDefined]
; Enhanced TunerStudio dialogs can be defined here
@ -2610,6 +2624,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"
@ -2723,6 +2741,8 @@ menuDialog = main
field = "Active Above Coolant", egoTemp, { egoType && (egoAlgorithm < 3) }
field = "Active Above RPM", egoRPM, { egoType && (egoAlgorithm < 3) }
field = "Active Below TPS", egoTPSMax, { egoType && (egoAlgorithm < 3) }
field = "Active Below MAP", egoMAPMax, { egoType && (egoAlgorithm < 3) }
field = "Active Above MAP", egoMAPMin, { egoType && (egoAlgorithm < 3) }
field = "EGO delay after start", ego_sdelay, { (egoAlgorithm < 3) }
field = "PID Proportional Gain", egoKP, { egoType && (egoAlgorithm == 2) }
field = "PID Integral", egoKI, { egoType && (egoAlgorithm == 2) }

View File

@ -190,6 +190,10 @@ void legacySerialCommand(void)
Serial.write(highByte(currentStatus.freeRAM));
break;
case 'M':
legacySerialHandler(currentCommand, Serial, serialStatusFlag);
break;
case 'N': // Displays a new line. Like pushing enter in a text editor
Serial.println();
break;
@ -391,48 +395,6 @@ void legacySerialCommand(void)
break;
case 'M':
serialStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if(chunkPending == false)
{
//This means it's a new request
//7 bytes required:
//2 - Page identifier
//2 - offset
//2 - Length
//1 - 1st New value
if(Serial.available() >= 7)
{
byte offset1, offset2, length1, length2;
Serial.read(); // First byte of the page identifier can be ignored. It's always 0
currentPage = Serial.read();
//currentPage = 1;
offset1 = Serial.read();
offset2 = Serial.read();
valueOffset = word(offset2, offset1);
length1 = Serial.read();
length2 = Serial.read();
chunkSize = word(length2, length1);
//Regular page data
chunkPending = true;
chunkComplete = 0;
}
}
//This CANNOT be an else of the above if statement as chunkPending gets set to true above
if(chunkPending == true)
{
while( (Serial.available() > 0) && (chunkComplete < chunkSize) )
{
setPageValue(currentPage, (valueOffset + chunkComplete), Serial.read());
chunkComplete++;
}
if(chunkComplete >= chunkSize) { serialStatusFlag = SERIAL_INACTIVE; chunkPending = false; }
}
break;
case 'w':
//No w commands are supported in legacy mode. This should never be called
if(Serial.available() >= 7)
@ -586,6 +548,48 @@ void legacySerialHandler(byte cmd, Stream &targetPort, SerialStatus &targetStatu
}
break;
case 'M':
targetStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;
if(chunkPending == false)
{
//This means it's a new request
//7 bytes required:
//2 - Page identifier
//2 - offset
//2 - Length
//1 - 1st New value
if(targetPort.available() >= 7)
{
byte offset1, offset2, length1, length2;
targetPort.read(); // First byte of the page identifier can be ignored. It's always 0
currentPage = targetPort.read();
//currentPage = 1;
offset1 = targetPort.read();
offset2 = targetPort.read();
valueOffset = word(offset2, offset1);
length1 = targetPort.read();
length2 = targetPort.read();
chunkSize = word(length2, length1);
//Regular page data
chunkPending = true;
chunkComplete = 0;
}
}
//This CANNOT be an else of the above if statement as chunkPending gets set to true above
if(chunkPending == true)
{
while( (targetPort.available() > 0) && (chunkComplete < chunkSize) )
{
setPageValue(currentPage, (valueOffset + chunkComplete), targetPort.read());
chunkComplete++;
}
if(chunkComplete >= chunkSize) { targetStatusFlag = SERIAL_INACTIVE; chunkPending = false; }
}
break;
case 'p':
targetStatusFlag = SERIAL_COMMAND_INPROGRESS_LEGACY;

View File

@ -137,6 +137,10 @@ void secondserial_Command(void)
*/
break;
}
case 'M':
legacySerialHandler(currentSecondaryCommand, secondarySerial, serialSecondaryStatusFlag);
break;
case 'n': // sends the bytes of realtime values from the NEW CAN list
//sendValues(0, NEW_CAN_PACKET_SIZE, 0x32, secondarySerial, serialSecondaryStatusFlag); //send values to serial3

View File

@ -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;
@ -631,7 +655,7 @@ byte correctionAFRClosedLoop(void)
AFRnextCycle = ignitionCount + configPage6.egoCount; //Set the target ignition event for the next calculation
//Check all other requirements for closed loop adjustments
if( (currentStatus.coolant > (int)(configPage6.egoTemp - CALIBRATION_TEMPERATURE_OFFSET)) && (currentStatus.RPM > (unsigned int)(configPage6.egoRPM * 100)) && (currentStatus.TPS <= configPage6.egoTPSMax) && (currentStatus.O2 < configPage6.ego_max) && (currentStatus.O2 > configPage6.ego_min) && (currentStatus.runSecs > configPage6.ego_sdelay) && (BIT_CHECK(currentStatus.status1, BIT_STATUS1_DFCO) == 0) )
if( (currentStatus.coolant > (int)(configPage6.egoTemp - CALIBRATION_TEMPERATURE_OFFSET)) && (currentStatus.RPM > (unsigned int)(configPage6.egoRPM * 100)) && (currentStatus.TPS <= configPage6.egoTPSMax) && (currentStatus.O2 < configPage6.ego_max) && (currentStatus.O2 > configPage6.ego_min) && (currentStatus.runSecs > configPage6.ego_sdelay) && (BIT_CHECK(currentStatus.status1, BIT_STATUS1_DFCO) == 0) && ( currentStatus.MAP <= (configPage9.egoMAPMax * 2U) ) && ( currentStatus.MAP >= (configPage9.egoMAPMin * 2U) ) )
{
//Check which algorithm is used, simple or PID
@ -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)

View File

@ -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

View File

@ -1098,8 +1098,8 @@ struct config9 {
byte unused10_110;
byte unused10_111;
byte unused10_112;
byte unused10_113;
byte egoMAPMax; //needs to be multiplied by 2 to get the proper value
byte egoMAPMin; //needs to be multiplied by 2 to get the proper value
byte speeduino_tsCanId:4; //speeduino TS canid (0-14)
uint16_t true_address; //speeduino 11bit can address
uint16_t realtime_base_address; //speeduino 11 bit realtime base address
@ -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 */

View File

@ -732,6 +732,16 @@ void doUpdates(void)
configPage13.hwTestInjDuration = 8;
configPage13.hwTestIgnDuration = 4;
//DFCO taper default values (Feature disabled by default)
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
writeAllConfig();
storeEEPROMVersion(23);
}

View File

@ -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