2015-05-28 16:49:44 -07:00
/*
Speeduino - Simple engine management for the Arduino Mega 2560 platform
Copyright ( C ) Josh Stewart
A full copy of the license may be found in the projects root directory
*/
2015-01-27 15:01:12 -08:00
/*
The corrections functions in this file affect the fuel pulsewidth ( Either increasing or decreasing )
based on factors other than the VE lookup .
2017-02-13 06:07:05 -08:00
These factors include temperature ( Warmup Enrichment and After Start Enrichment ) , Acceleration / Decelleration ,
2015-01-27 15:01:12 -08:00
Flood clear mode etc .
*/
//************************************************************************************************************
2014-01-07 00:02:00 -08:00
2015-02-14 09:04:00 -08:00
# include "corrections.h"
# include "globals.h"
2018-06-05 23:51:28 -07:00
# include "timers.h"
2014-01-07 00:02:00 -08:00
2016-04-08 06:52:32 -07:00
long PID_O2 , PID_output , PID_AFRTarget ;
2018-01-23 17:05:50 -08:00
PID egoPID ( & PID_O2 , & PID_output , & PID_AFRTarget , configPage6 . egoKP , configPage6 . egoKI , configPage6 . egoKD , REVERSE ) ; //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
2016-04-08 06:52:32 -07:00
void initialiseCorrections ( )
{
egoPID . SetMode ( AUTOMATIC ) ; //Turn O2 PID on
2016-12-26 01:53:37 -08:00
currentStatus . flexIgnCorrection = 0 ;
2017-11-05 01:56:04 -07:00
currentStatus . egoCorrection = 100 ; //Default value of no adjustment must be set to avoid randomness on first correction cycle after startup
2017-10-31 22:10:06 -07:00
AFRnextCycle = 0 ;
2016-04-08 06:52:32 -07:00
}
2015-01-27 15:01:12 -08:00
/*
correctionsTotal ( ) calls all the other corrections functions and combines their results .
This is the only function that should be called from anywhere outside the file
*/
2017-10-23 22:54:18 -07:00
static inline byte correctionsFuel ( )
2014-01-07 00:02:00 -08:00
{
2016-06-16 21:13:10 -07:00
unsigned long sumCorrections = 100 ;
byte activeCorrections = 0 ;
2015-01-24 23:03:52 -08:00
byte result ; //temporary variable to store the result of each corrections function
2017-02-13 06:07:05 -08:00
//The values returned by each of the correction functions are multipled together and then divided back to give a single 0-255 value.
2015-02-05 13:11:33 -08:00
currentStatus . wueCorrection = correctionWUE ( ) ;
2016-06-16 21:13:10 -07:00
if ( currentStatus . wueCorrection ! = 100 ) { sumCorrections = ( sumCorrections * currentStatus . wueCorrection ) ; activeCorrections + + ; }
2017-02-13 06:07:05 -08:00
2015-01-24 23:03:52 -08:00
result = correctionASE ( ) ;
2016-06-16 21:13:10 -07:00
if ( result ! = 100 ) { sumCorrections = ( sumCorrections * result ) ; activeCorrections + + ; }
2017-02-13 06:07:05 -08:00
2015-02-06 13:29:51 -08:00
result = correctionCranking ( ) ;
2016-06-16 21:13:10 -07:00
if ( result ! = 100 ) { sumCorrections = ( sumCorrections * result ) ; activeCorrections + + ; }
if ( activeCorrections = = 3 ) { sumCorrections = sumCorrections / powint ( 100 , activeCorrections ) ; activeCorrections = 0 ; } // Need to check this to ensure that sumCorrections doesn't overflow. Can occur when the number of corrections is greater than 3 (Which is 100^4) as 100^5 can overflow
2017-02-13 06:07:05 -08:00
2015-02-05 13:11:33 -08:00
currentStatus . TAEamount = correctionAccel ( ) ;
2016-06-16 21:13:10 -07:00
if ( currentStatus . TAEamount ! = 100 ) { sumCorrections = ( sumCorrections * currentStatus . TAEamount ) ; activeCorrections + + ; }
if ( activeCorrections = = 3 ) { sumCorrections = sumCorrections / powint ( 100 , activeCorrections ) ; activeCorrections = 0 ; }
2017-02-13 06:07:05 -08:00
2015-01-24 23:03:52 -08:00
result = correctionFloodClear ( ) ;
2016-06-16 21:13:10 -07:00
if ( result ! = 100 ) { sumCorrections = ( sumCorrections * result ) ; activeCorrections + + ; }
if ( activeCorrections = = 3 ) { sumCorrections = sumCorrections / powint ( 100 , activeCorrections ) ; activeCorrections = 0 ; }
2017-02-13 06:07:05 -08:00
2017-01-10 23:30:46 -08:00
currentStatus . egoCorrection = correctionAFRClosedLoop ( ) ;
2016-06-16 21:13:10 -07:00
if ( currentStatus . egoCorrection ! = 100 ) { sumCorrections = ( sumCorrections * currentStatus . egoCorrection ) ; activeCorrections + + ; }
if ( activeCorrections = = 3 ) { sumCorrections = sumCorrections / powint ( 100 , activeCorrections ) ; activeCorrections = 0 ; }
2017-02-13 06:07:05 -08:00
2017-01-10 23:30:46 -08:00
currentStatus . batCorrection = correctionBatVoltage ( ) ;
2016-06-16 21:13:10 -07:00
if ( currentStatus . batCorrection ! = 100 ) { sumCorrections = ( sumCorrections * currentStatus . batCorrection ) ; activeCorrections + + ; }
if ( activeCorrections = = 3 ) { sumCorrections = sumCorrections / powint ( 100 , activeCorrections ) ; activeCorrections = 0 ; }
2017-02-13 06:07:05 -08:00
2017-01-10 23:30:46 -08:00
currentStatus . iatCorrection = correctionIATDensity ( ) ;
2016-06-16 21:13:10 -07:00
if ( currentStatus . iatCorrection ! = 100 ) { sumCorrections = ( sumCorrections * currentStatus . iatCorrection ) ; activeCorrections + + ; }
if ( activeCorrections = = 3 ) { sumCorrections = sumCorrections / powint ( 100 , activeCorrections ) ; activeCorrections = 0 ; }
2016-11-28 01:37:24 -08:00
2017-01-10 23:30:46 -08:00
currentStatus . flexCorrection = correctionFlex ( ) ;
2016-11-28 01:37:24 -08:00
if ( currentStatus . flexCorrection ! = 100 ) { sumCorrections = ( sumCorrections * currentStatus . flexCorrection ) ; activeCorrections + + ; }
if ( activeCorrections = = 3 ) { sumCorrections = sumCorrections / powint ( 100 , activeCorrections ) ; activeCorrections = 0 ; }
2017-02-13 06:07:05 -08:00
2017-01-10 23:30:46 -08:00
currentStatus . launchCorrection = correctionLaunch ( ) ;
2016-06-16 21:13:10 -07:00
if ( currentStatus . launchCorrection ! = 100 ) { sumCorrections = ( sumCorrections * currentStatus . launchCorrection ) ; activeCorrections + + ; }
2017-02-13 06:07:05 -08:00
2017-10-23 22:54:18 -07:00
bitWrite ( currentStatus . status1 , BIT_STATUS1_DFCO , correctionDFCO ( ) ) ;
if ( bitRead ( currentStatus . status1 , BIT_STATUS1_DFCO ) = = 1 ) { sumCorrections = 0 ; }
2016-06-16 21:13:10 -07:00
sumCorrections = sumCorrections / powint ( 100 , activeCorrections ) ;
2017-02-13 06:07:05 -08:00
2015-02-05 18:11:39 -08:00
if ( sumCorrections > 255 ) { sumCorrections = 255 ; } //This is the maximum allowable increase
2014-09-20 15:46:04 -07:00
return ( byte ) sumCorrections ;
2014-01-07 00:02:00 -08:00
}
2015-01-27 15:01:12 -08:00
/*
Warm Up Enrichment ( WUE )
Uses a 2 D enrichment table ( WUETable ) where the X axis is engine temp and the Y axis is the amount of extra fuel to add
*/
2016-12-11 03:51:04 -08:00
static inline byte correctionWUE ( )
2014-01-07 00:02:00 -08:00
{
2017-06-03 03:45:25 -07:00
byte WUEValue ;
2014-05-08 06:01:36 -07:00
//Possibly reduce the frequency this runs at (Costs about 50 loops per second)
2017-06-03 03:45:25 -07:00
if ( currentStatus . coolant > ( WUETable . axisX [ 9 ] - CALIBRATION_TEMPERATURE_OFFSET ) )
{
//This prevents us doing the 2D lookup if we're already up to temp
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_WARMUP ) ;
2018-03-27 18:50:36 -07:00
WUEValue = WUETable . values [ 9 ] ; //Set the current value to be whatever the final value on the curve is.
2017-06-03 03:45:25 -07:00
}
else
{
BIT_SET ( currentStatus . engine , BIT_ENGINE_WARMUP ) ;
WUEValue = table2D_getValue ( & WUETable , currentStatus . coolant + CALIBRATION_TEMPERATURE_OFFSET ) ;
}
return WUEValue ;
2014-01-07 00:02:00 -08:00
}
2015-02-06 13:29:51 -08:00
/*
Cranking Enrichment
Additional fuel % to be added when the engine is cranking
*/
2016-12-11 03:51:04 -08:00
static inline byte correctionCranking ( )
2015-02-06 13:29:51 -08:00
{
2017-06-03 03:45:25 -07:00
byte crankingValue = 100 ;
2018-01-23 17:05:50 -08:00
//if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) { crankingValue = 100 + configPage2.crankingPct; }
2017-07-27 07:48:08 -07:00
if ( BIT_CHECK ( currentStatus . engine , BIT_ENGINE_CRANK ) )
2017-08-23 00:18:59 -07:00
{
2017-07-27 07:48:08 -07:00
crankingValue = table2D_getValue ( & crankingEnrichTable , currentStatus . coolant + CALIBRATION_TEMPERATURE_OFFSET ) ;
}
2017-06-03 03:45:25 -07:00
return crankingValue ;
2015-02-06 13:29:51 -08:00
}
2015-01-27 15:01:12 -08:00
/*
After Start Enrichment
This is a short period ( Usually < 20 seconds ) immediately after the engine first fires ( But not when cranking )
where an additional amount of fuel is added ( Over and above the WUE amount )
*/
2016-12-11 03:51:04 -08:00
static inline byte correctionASE ( )
2014-01-07 00:02:00 -08:00
{
2017-06-03 03:45:25 -07:00
byte ASEValue ;
2015-02-06 13:29:51 -08:00
//Two checks are requiredL:
//1) Is the negine run time less than the configured ase time
//2) Make sure we're not still cranking
2018-01-23 17:05:50 -08:00
if ( ( currentStatus . runSecs < configPage2 . aseCount ) & & ! ( BIT_CHECK ( currentStatus . engine , BIT_ENGINE_CRANK ) ) )
2014-01-29 21:28:21 -08:00
{
2014-12-23 15:25:51 -08:00
BIT_SET ( currentStatus . engine , BIT_ENGINE_ASE ) ; //Mark ASE as active.
2018-01-23 17:05:50 -08:00
ASEValue = 100 + configPage2 . asePct ;
2014-01-29 21:28:21 -08:00
}
2017-06-03 03:45:25 -07:00
else
{
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_ASE ) ; //Mark ASE as inactive.
ASEValue = 100 ;
}
return ASEValue ;
2014-01-07 00:02:00 -08:00
}
2014-02-17 02:54:28 -08:00
/*
TPS based acceleration enrichment
Calculates the % change of the throttle over time ( % / second ) and performs a lookup based on this
2015-01-27 15:01:12 -08:00
When the enrichment is turned on , it runs at that amount for a fixed period of time ( taeTime )
2017-11-08 03:51:40 -08:00
Note that as the maximum enrichment amount is + 255 % , the overall return value from this function can be 100 + 255 = 355. Hence this function returns a int16_t rather than byte
2014-02-17 02:54:28 -08:00
*/
2017-11-08 03:51:40 -08:00
static inline int16_t correctionAccel ( )
2014-01-07 00:02:00 -08:00
{
2017-11-08 03:51:40 -08:00
int16_t accelValue = 100 ;
2015-01-27 15:01:12 -08:00
//First, check whether the accel. enrichment is already running
2017-06-04 05:48:59 -07:00
if ( BIT_CHECK ( currentStatus . engine , BIT_ENGINE_ACC ) )
2015-01-27 15:01:12 -08:00
{
//If it is currently running, check whether it should still be running or whether it's reached it's end time
2018-03-09 19:07:06 -08:00
if ( micros_safe ( ) > = currentStatus . TAEEndTime )
2015-01-27 15:01:12 -08:00
{
//Time to turn enrichment off
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_ACC ) ;
currentStatus . TAEamount = 0 ;
2017-06-03 03:45:25 -07:00
accelValue = 100 ;
2017-07-17 21:05:26 -07:00
currentStatus . tpsDOT = 0 ;
2017-06-03 03:45:25 -07:00
}
else
{
//Enrichment still needs to keep running. Simply return the total TAE amount
accelValue = currentStatus . TAEamount ;
2015-01-27 15:01:12 -08:00
}
}
2017-06-03 03:45:25 -07:00
else
2014-05-06 04:07:49 -07:00
{
2017-07-02 18:52:27 -07:00
int8_t TPS_change = ( currentStatus . TPS - currentStatus . TPSlast ) ;
2017-06-03 03:45:25 -07:00
//Check for deceleration (Deceleration adjustment not yet supported)
2017-07-02 19:14:07 -07:00
//Also check for only very small movement (Movement less than or equal to 2% is ignored). This not only means we can skip the lookup, but helps reduce false triggering around 0-2% throttle openings
2017-07-02 18:52:27 -07:00
if ( TPS_change < = 2 )
2017-06-03 03:45:25 -07:00
{
accelValue = 100 ;
2017-07-17 21:05:26 -07:00
currentStatus . tpsDOT = 0 ;
2017-06-03 03:45:25 -07:00
}
else
{
//If TAE isn't currently turned on, need to check whether it needs to be turned on
2017-07-02 18:52:27 -07:00
int rateOfChange = ldiv ( 1000000 , ( currentStatus . TPS_time - currentStatus . TPSlast_time ) ) . quot * TPS_change ; //This is the % per second that the TPS has moved
2017-06-03 03:45:25 -07:00
currentStatus . tpsDOT = rateOfChange / 10 ; //The TAE bins are divided by 10 in order to allow them to be stored in a byte. Faster as this than divu10
2018-01-23 17:05:50 -08:00
if ( rateOfChange > configPage2 . tpsThresh )
2017-06-03 03:45:25 -07:00
{
BIT_SET ( currentStatus . engine , BIT_ENGINE_ACC ) ; //Mark accleration enrichment as active.
2018-03-09 19:07:06 -08:00
currentStatus . TAEEndTime = micros_safe ( ) + ( ( unsigned long ) configPage2 . taeTime * 10000 ) ; //Set the time in the future where the enrichment will be turned off. taeTime is stored as mS / 10, so multiply it by 100 to get it in uS
2017-06-03 03:45:25 -07:00
accelValue = 100 + table2D_getValue ( & taeTable , currentStatus . tpsDOT ) ;
}
}
2014-05-06 04:07:49 -07:00
}
2017-02-13 06:07:05 -08:00
2017-06-03 03:45:25 -07:00
return accelValue ;
2014-05-06 04:07:49 -07:00
}
/*
Simple check to see whether we are cranking with the TPS above the flood clear threshold
This function always returns either 100 or 0
*/
2016-12-11 03:51:04 -08:00
static inline byte correctionFloodClear ( )
2014-05-06 04:07:49 -07:00
{
2017-06-03 03:45:25 -07:00
byte floodValue = 100 ;
2017-06-04 05:48:59 -07:00
if ( BIT_CHECK ( currentStatus . engine , BIT_ENGINE_CRANK ) )
2014-05-06 04:07:49 -07:00
{
//Engine is currently cranking, check what the TPS is
2018-01-23 17:05:50 -08:00
if ( currentStatus . TPS > = configPage4 . floodClear )
2014-05-06 04:07:49 -07:00
{
//Engine is cranking and TPS is above threshold. Cut all fuel
2017-06-03 03:45:25 -07:00
floodValue = 0 ;
2014-05-06 04:07:49 -07:00
}
}
2017-06-03 03:45:25 -07:00
return floodValue ;
2014-01-07 00:02:00 -08:00
}
2015-02-05 13:11:33 -08:00
2015-04-04 03:10:13 -07:00
/*
Battery Voltage correction
Uses a 2 D enrichment table ( WUETable ) where the X axis is engine temp and the Y axis is the amount of extra fuel to add
*/
2017-01-10 23:30:46 -08:00
static inline byte correctionBatVoltage ( )
2015-04-04 03:10:13 -07:00
{
2017-06-03 03:45:25 -07:00
byte batValue = 100 ;
if ( currentStatus . battery10 > ( injectorVCorrectionTable . axisX [ 5 ] ) ) { batValue = injectorVCorrectionTable . values [ injectorVCorrectionTable . xSize - 1 ] ; } //This prevents us doing the 2D lookup if the voltage is above maximum
else { batValue = table2D_getValue ( & injectorVCorrectionTable , currentStatus . battery10 ) ; }
return batValue ;
2015-04-04 03:10:13 -07:00
}
2015-10-17 15:29:41 -07:00
/*
2017-02-13 06:07:05 -08:00
Simple temperature based corrections lookup based on the inlet air temperature .
This corrects for changes in air density from movement of the temperature
2015-10-17 15:29:41 -07:00
*/
2017-01-10 23:30:46 -08:00
static inline byte correctionIATDensity ( )
2015-10-17 15:29:41 -07:00
{
2017-06-03 03:45:25 -07:00
byte IATValue = 100 ;
if ( ( currentStatus . IAT + CALIBRATION_TEMPERATURE_OFFSET ) > ( IATDensityCorrectionTable . axisX [ 8 ] ) ) { IATValue = IATDensityCorrectionTable . values [ IATDensityCorrectionTable . xSize - 1 ] ; } //This prevents us doing the 2D lookup if the intake temp is above maximum
else { IATValue = table2D_getValue ( & IATDensityCorrectionTable , currentStatus . IAT + CALIBRATION_TEMPERATURE_OFFSET ) ; } //currentStatus.IAT is the actual temperature, values in IATDensityCorrectionTable.axisX are temp+offset
return IATValue ;
2015-10-18 05:20:16 -07:00
}
/*
Launch control has a setting to increase the fuel load to assist in bringing up boost
This simple check applies the extra fuel if we ' re currently launching
*/
2017-01-10 23:30:46 -08:00
static inline byte correctionLaunch ( )
2015-10-18 05:20:16 -07:00
{
2017-06-03 03:45:25 -07:00
byte launchValue = 100 ;
2018-01-23 17:05:50 -08:00
if ( currentStatus . launchingHard | | currentStatus . launchingSoft ) { launchValue = ( 100 + configPage6 . lnchFuelAdd ) ; }
2017-06-03 03:45:25 -07:00
return launchValue ;
2015-10-17 15:29:41 -07:00
}
2016-02-24 18:11:13 -08:00
/*
* Returns true if decelleration fuel cutoff should be on , false if its off
*/
2017-01-10 23:30:46 -08:00
static inline bool correctionDFCO ( )
2016-02-24 18:11:13 -08:00
{
2017-06-03 03:45:25 -07:00
bool DFCOValue = false ;
2018-01-23 17:05:50 -08:00
if ( configPage2 . dfcoEnabled = = 1 )
2017-06-03 03:45:25 -07:00
{
2018-01-23 17:05:50 -08:00
if ( bitRead ( currentStatus . status1 , BIT_STATUS1_DFCO ) = = 1 ) { DFCOValue = ( currentStatus . RPM > ( configPage4 . dfcoRPM * 10 ) ) & & ( currentStatus . TPS < configPage4 . dfcoTPSThresh ) ; }
else { DFCOValue = ( currentStatus . RPM > ( unsigned int ) ( ( configPage4 . dfcoRPM * 10 ) + configPage4 . dfcoHyster ) ) & & ( currentStatus . TPS < configPage4 . dfcoTPSThresh ) ; }
2017-06-03 03:45:25 -07:00
}
return DFCOValue ;
2016-02-24 18:11:13 -08:00
}
2016-11-28 01:37:24 -08:00
/*
* Flex fuel adjustment to vary fuel based on ethanol content
2017-02-13 06:07:05 -08:00
* The amount of extra fuel required is a linear relationship based on the % of ethanol .
2016-11-28 01:37:24 -08:00
*/
2017-01-10 23:30:46 -08:00
static inline byte correctionFlex ( )
2016-11-28 01:37:24 -08:00
{
2017-06-03 03:45:25 -07:00
byte flexValue = 100 ;
2018-03-09 19:07:06 -08:00
2018-01-24 22:25:11 -08:00
if ( configPage2 . flexEnabled = = 1 )
2017-06-03 03:45:25 -07:00
{
2018-01-24 22:25:11 -08:00
flexValue = table2D_getValue ( & flexFuelTable , currentStatus . ethanolPct ) ;
2017-06-03 03:45:25 -07:00
}
return flexValue ;
2016-11-28 01:37:24 -08:00
}
2015-02-05 13:11:33 -08:00
/*
Lookup the AFR target table and perform either a simple or PID adjustment based on this
Simple ( Best suited to narrowband sensors ) :
If the O2 sensor reports that the mixture is lean / rich compared to the desired AFR target , it will make a 1 % adjustment
It then waits < egoDelta > number of ignition events and compares O2 against the target table again . If it is still lean / rich then the adjustment is increased to 2 %
This continues until either :
a ) the O2 reading flips from lean to rich , at which point the adjustment cycle starts again at 1 % or
b ) the adjustment amount increases to < egoLimit > at which point it stays at this level until the O2 state ( rich / lean ) changes
2017-02-13 06:07:05 -08:00
2015-02-05 13:11:33 -08:00
PID ( Best suited to wideband sensors ) :
2017-02-13 06:07:05 -08:00
2015-02-05 13:11:33 -08:00
*/
2015-02-16 21:32:07 -08:00
2017-01-10 23:30:46 -08:00
static inline byte correctionAFRClosedLoop ( )
2015-02-05 13:11:33 -08:00
{
2017-06-03 03:45:25 -07:00
byte AFRValue = 100 ;
2018-01-23 17:05:50 -08:00
if ( configPage6 . egoType > 0 ) //egoType of 0 means no O2 sensor
2015-02-05 13:11:33 -08:00
{
2017-06-03 03:45:25 -07:00
currentStatus . afrTarget = currentStatus . O2 ; //Catch all incase the below doesn't run. This prevents the Include AFR option from doing crazy things if the AFR target conditions aren't met. This value is changed again below if all conditions are met.
2017-10-31 22:10:06 -07:00
//Determine whether the Y axis of the AFR target table tshould be MAP (Speed-Density) or TPS (Alpha-N)
2018-04-24 04:31:52 -07:00
currentStatus . afrTarget = get3DTableValue ( & afrTable , currentStatus . fuelLoad , currentStatus . RPM ) ; //Perform the target lookup
2017-10-31 22:10:06 -07:00
//Check all other requirements for closed loop adjustments
2018-01-23 17:05:50 -08:00
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 ) )
2015-02-05 13:11:33 -08:00
{
2017-11-05 01:56:04 -07:00
AFRValue = currentStatus . egoCorrection ; //Need to record this here, just to make sure the correction stays 'on' even if the nextCycle count isn't ready
2017-10-31 22:10:06 -07:00
2017-11-05 01:56:04 -07:00
if ( ignitionCount > = AFRnextCycle )
2015-02-15 02:32:38 -08:00
{
2018-01-23 17:05:50 -08:00
AFRnextCycle = ignitionCount + configPage6 . egoCount ; //Set the target ignition event for the next calculation
2017-11-05 01:56:04 -07:00
//Check which algorithm is used, simple or PID
2018-01-23 17:05:50 -08:00
if ( configPage6 . egoAlgorithm = = EGO_ALGORITHM_SIMPLE )
2015-02-15 02:32:38 -08:00
{
2017-11-05 01:56:04 -07:00
//*************************************************************************************************************************************
//Simple algorithm
if ( currentStatus . O2 > currentStatus . afrTarget )
2015-02-15 02:32:38 -08:00
{
2017-11-05 01:56:04 -07:00
//Running lean
2018-01-23 17:05:50 -08:00
if ( currentStatus . egoCorrection < ( 100 + configPage6 . egoLimit ) ) //Fueling adjustment must be at most the egoLimit amount (up or down)
2017-11-05 01:56:04 -07:00
{
2018-06-04 00:01:53 -07:00
AFRValue = ( currentStatus . egoCorrection + 1 ) ; //Increase the fueling by 1%
2017-11-05 01:56:04 -07:00
}
2018-06-04 00:01:53 -07:00
else { AFRValue = currentStatus . egoCorrection ; } //Means we're at the maximum adjustment amount, so simply return that again
2015-02-15 02:32:38 -08:00
}
2018-06-04 00:01:53 -07:00
else if ( currentStatus . O2 < currentStatus . afrTarget )
{
2017-11-05 01:56:04 -07:00
//Running Rich
2018-01-23 17:05:50 -08:00
if ( currentStatus . egoCorrection > ( 100 - configPage6 . egoLimit ) ) //Fueling adjustment must be at most the egoLimit amount (up or down)
2017-11-05 01:56:04 -07:00
{
2018-06-04 00:01:53 -07:00
AFRValue = ( currentStatus . egoCorrection - 1 ) ; //Decrease the fueling by 1%
2017-11-05 01:56:04 -07:00
}
2018-06-04 00:01:53 -07:00
else { AFRValue = currentStatus . egoCorrection ; } //Means we're at the maximum adjustment amount, so simply return that again
}
else { AFRValue = currentStatus . egoCorrection ; } //Means we're already right on target
2015-02-15 02:32:38 -08:00
}
2018-01-23 17:05:50 -08:00
else if ( configPage6 . egoAlgorithm = = EGO_ALGORITHM_PID )
2017-11-05 01:56:04 -07:00
{
//*************************************************************************************************************************************
//PID algorithm
2018-01-23 17:05:50 -08:00
egoPID . SetOutputLimits ( ( long ) ( - configPage6 . egoLimit ) , ( long ) ( configPage6 . egoLimit ) ) ; //Set the limits again, just incase the user has changed them since the last loop. Note that these are sent to the PID library as (Eg:) -15 and +15
egoPID . SetTunings ( configPage6 . egoKP , configPage6 . egoKI , configPage6 . egoKD ) ; //Set the PID values again, just incase the user has changed them since the last loop
2017-11-05 01:56:04 -07:00
PID_O2 = ( long ) ( currentStatus . O2 ) ;
PID_AFRTarget = ( long ) ( currentStatus . afrTarget ) ;
egoPID . Compute ( ) ;
//currentStatus.egoCorrection = 100 + PID_output;
AFRValue = 100 + PID_output ;
}
else { AFRValue = 100 ; } // Occurs if the egoAlgorithm is set to 0 (No Correction)
} //Ignition count check
2017-10-31 22:10:06 -07:00
} //Multi variable check
2017-06-03 03:45:25 -07:00
} //egoType
2017-02-13 06:07:05 -08:00
2017-06-03 03:45:25 -07:00
return AFRValue ; //Catch all (Includes when AFR target = current AFR
2015-02-05 13:11:33 -08:00
}
2016-12-11 03:51:04 -08:00
//******************************** IGNITION ADVANCE CORRECTIONS ********************************
2017-06-03 03:45:25 -07:00
int8_t correctionsIgn ( int8_t base_advance )
2016-12-11 03:51:04 -08:00
{
2017-06-03 03:45:25 -07:00
int8_t advance ;
advance = correctionFlexTiming ( base_advance ) ;
2017-01-10 23:30:46 -08:00
advance = correctionIATretard ( advance ) ;
advance = correctionSoftRevLimit ( advance ) ;
advance = correctionSoftLaunch ( advance ) ;
2017-01-17 18:20:04 -08:00
advance = correctionSoftFlatShift ( advance ) ;
2017-05-09 22:46:14 -07:00
2016-12-11 03:51:04 -08:00
//Fixed timing check must go last
2017-01-10 23:30:46 -08:00
advance = correctionFixedTiming ( advance ) ;
advance = correctionCrankingFixedTiming ( advance ) ; //This overrrides the regular fixed timing, must come last
2016-12-11 03:51:04 -08:00
return advance ;
}
2017-05-09 00:29:55 -07:00
static inline int8_t correctionFixedTiming ( int8_t advance )
2016-12-11 03:51:04 -08:00
{
2018-05-01 00:33:52 -07:00
int8_t ignFixValue = advance ;
2018-01-23 17:05:50 -08:00
if ( configPage4 . FixAng ! = 0 ) { ignFixValue = configPage4 . FixAng ; } //Check whether the user has set a fixed timing angle
2017-06-03 03:45:25 -07:00
return ignFixValue ;
2016-12-11 03:51:04 -08:00
}
2017-05-09 00:29:55 -07:00
static inline int8_t correctionCrankingFixedTiming ( int8_t advance )
2016-12-11 03:51:04 -08:00
{
2017-06-03 03:45:25 -07:00
byte ignCrankFixValue = advance ;
2018-01-23 17:05:50 -08:00
if ( BIT_CHECK ( currentStatus . engine , BIT_ENGINE_CRANK ) ) { ignCrankFixValue = configPage4 . CrankAng ; } //Use the fixed cranking ignition angle
2017-06-03 03:45:25 -07:00
return ignCrankFixValue ;
2016-12-11 03:51:04 -08:00
}
2017-05-09 00:29:55 -07:00
static inline int8_t correctionFlexTiming ( int8_t advance )
2016-12-11 03:51:04 -08:00
{
2017-06-03 03:45:25 -07:00
byte ignFlexValue = advance ;
2018-01-23 17:05:50 -08:00
if ( configPage2 . flexEnabled = = 1 ) //Check for flex being enabled
2017-06-03 03:45:25 -07:00
{
2018-01-24 22:25:11 -08:00
currentStatus . flexIgnCorrection = table2D_getValue ( & flexAdvTable , currentStatus . ethanolPct ) ;
2017-06-03 03:45:25 -07:00
ignFlexValue = advance + currentStatus . flexIgnCorrection ;
}
return ignFlexValue ;
2016-12-11 03:51:04 -08:00
}
2017-05-09 00:29:55 -07:00
static inline int8_t correctionIATretard ( int8_t advance )
2016-12-11 03:51:04 -08:00
{
2017-06-03 03:45:25 -07:00
byte ignIATValue = advance ;
2016-12-11 03:51:04 -08:00
//Adjust the advance based on IAT. If the adjustment amount is greater than the current advance, just set advance to 0
2017-05-09 00:29:55 -07:00
int8_t advanceIATadjust = table2D_getValue ( & IATRetardTable , currentStatus . IAT ) ;
2017-05-09 22:46:14 -07:00
int tempAdvance = ( advance - advanceIATadjust ) ;
2017-06-03 03:45:25 -07:00
if ( tempAdvance > = - OFFSET_IGNITION ) { ignIATValue = tempAdvance ; }
else { ignIATValue = - OFFSET_IGNITION ; }
return ignIATValue ;
2016-12-11 03:51:04 -08:00
}
2017-05-09 00:29:55 -07:00
static inline int8_t correctionSoftRevLimit ( int8_t advance )
2016-12-11 03:51:04 -08:00
{
2017-06-03 03:45:25 -07:00
byte ignSoftRevValue = advance ;
2016-12-11 03:51:04 -08:00
BIT_CLEAR ( currentStatus . spark , BIT_SPARK_SFTLIM ) ;
2018-01-23 17:05:50 -08:00
if ( currentStatus . RPM > ( ( unsigned int ) ( configPage4 . SoftRevLim ) * 100 ) ) { BIT_SET ( currentStatus . spark , BIT_SPARK_SFTLIM ) ; ignSoftRevValue = configPage4 . SoftLimRetard ; } //Softcut RPM limit (If we're above softcut limit, delay timing by configured number of degrees)
2017-06-03 03:45:25 -07:00
return ignSoftRevValue ;
2016-12-11 03:51:04 -08:00
}
2017-05-09 00:29:55 -07:00
static inline int8_t correctionSoftLaunch ( int8_t advance )
2016-12-11 03:51:04 -08:00
{
2017-06-03 03:45:25 -07:00
byte ignSoftLaunchValue = advance ;
2017-02-13 06:07:05 -08:00
//SoftCut rev limit for 2-step launch control.
2018-01-23 17:05:50 -08:00
if ( configPage6 . launchEnabled & & clutchTrigger & & ( currentStatus . clutchEngagedRPM < ( ( unsigned int ) ( configPage6 . flatSArm ) * 100 ) ) & & ( currentStatus . RPM > ( ( unsigned int ) ( configPage6 . lnchSoftLim ) * 100 ) ) & & ( currentStatus . TPS > = configPage10 . lnchCtrlTPS ) )
2017-01-17 18:20:04 -08:00
{
2017-02-13 06:07:05 -08:00
currentStatus . launchingSoft = true ;
2017-01-17 18:20:04 -08:00
BIT_SET ( currentStatus . spark , BIT_SPARK_SLAUNCH ) ;
2018-01-23 17:05:50 -08:00
ignSoftLaunchValue = configPage6 . lnchRetard ;
2017-06-03 03:45:25 -07:00
}
else
{
currentStatus . launchingSoft = false ;
BIT_CLEAR ( currentStatus . spark , BIT_SPARK_SLAUNCH ) ;
2017-02-13 06:07:05 -08:00
}
2017-01-17 18:20:04 -08:00
2017-06-03 03:45:25 -07:00
return ignSoftLaunchValue ;
2017-01-17 18:20:04 -08:00
}
2017-05-09 00:29:55 -07:00
static inline int8_t correctionSoftFlatShift ( int8_t advance )
2017-01-17 18:20:04 -08:00
{
2017-06-03 03:45:25 -07:00
byte ignSoftFlatValue = advance ;
2018-01-23 17:05:50 -08:00
if ( configPage6 . flatSEnable & & clutchTrigger & & ( currentStatus . clutchEngagedRPM > ( ( unsigned int ) ( configPage6 . flatSArm ) * 100 ) ) & & ( currentStatus . RPM > ( currentStatus . clutchEngagedRPM - configPage6 . flatSSoftWin ) ) )
2017-02-13 06:07:05 -08:00
{
2017-01-17 18:20:04 -08:00
BIT_SET ( currentStatus . spark2 , BIT_SPARK2_FLATSS ) ;
2018-01-23 17:05:50 -08:00
ignSoftFlatValue = configPage6 . flatSRetard ;
2017-01-17 18:20:04 -08:00
}
2017-06-03 03:45:25 -07:00
else { BIT_CLEAR ( currentStatus . spark2 , BIT_SPARK2_FLATSS ) ; }
2017-01-17 18:20:04 -08:00
2017-06-03 03:45:25 -07:00
return ignSoftFlatValue ;
2016-12-11 03:51:04 -08:00
}
2017-04-21 00:29:09 -07:00
//******************************** DWELL CORRECTIONS ********************************
uint16_t correctionsDwell ( uint16_t dwell )
{
2017-06-03 03:45:25 -07:00
uint16_t tempDwell = dwell ;
2017-04-21 00:29:09 -07:00
//Pull battery voltage based dwell correction and apply if needed
currentStatus . dwellCorrection = table2D_getValue ( & dwellVCorrectionTable , currentStatus . battery10 ) ;
2017-06-03 03:45:25 -07:00
if ( currentStatus . dwellCorrection ! = 100 ) { tempDwell = divs100 ( dwell ) * currentStatus . dwellCorrection ; }
2017-04-21 00:29:09 -07:00
//Dwell limiter
2018-01-23 17:05:50 -08:00
uint16_t dwellPerRevolution = tempDwell + ( uint16_t ) ( configPage4 . sparkDur * 100 ) ; //Spark duration is in mS*10. Multiple it by 100 to get spark duration in uS
2017-05-09 00:29:55 -07:00
int8_t pulsesPerRevolution = 1 ;
2017-04-21 00:29:09 -07:00
//Single channel spark mode is the only time there will be more than 1 pulse per revolution on any given output
2018-01-23 17:05:50 -08:00
if ( ( ( configPage4 . sparkMode = = IGN_MODE_SINGLE ) | | ( configPage4 . sparkMode = = IGN_MODE_ROTARY ) ) & & ( configPage2 . nCylinders > 1 ) ) //No point in running this for 1 cylinder engines
2017-04-21 00:29:09 -07:00
{
2018-01-23 17:05:50 -08:00
pulsesPerRevolution = ( configPage2 . nCylinders > > 1 ) ;
2017-04-21 00:29:09 -07:00
dwellPerRevolution = dwellPerRevolution * pulsesPerRevolution ;
}
if ( dwellPerRevolution > revolutionTime )
{
//Possibly need some method of reducing spark duration here as well, but this is a start
2018-01-23 17:05:50 -08:00
tempDwell = ( revolutionTime / pulsesPerRevolution ) - ( configPage4 . sparkDur * 100 ) ;
2017-04-21 00:29:09 -07:00
}
2017-06-03 03:45:25 -07:00
return tempDwell ;
2017-04-21 00:29:09 -07:00
}