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
*/
2021-06-21 22:30:52 -07:00
/** @file
Corrections to injection pulsewidth .
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 .
2021-06-21 22:30:52 -07:00
These factors include :
- Temperature ( Warmup Enrichment and After Start Enrichment )
2022-04-10 17:49:58 -07:00
- Acceleration / Deceleration
2021-06-21 22:30:52 -07:00
- Flood clear mode
- etc .
Most correction functions return value 100 ( like 100 % = = 1 ) for no need for correction .
There are 2 top level functions that call more detailed corrections for Fuel and Ignition respectively :
- @ ref correctionsFuel ( ) - All fuel related corrections
- @ ref correctionsIgn ( ) - All ignition related corrections
2015-01-27 15:01:12 -08:00
*/
//************************************************************************************************************
2014-01-07 00:02:00 -08:00
2015-02-14 09:04:00 -08:00
# include "globals.h"
2018-08-15 00:44:30 -07:00
# include "corrections.h"
2020-02-22 14:54:13 -08:00
# include "speeduino.h"
2018-06-05 23:51:28 -07:00
# include "timers.h"
2018-07-19 00:33:40 -07:00
# include "maths.h"
2018-08-13 19:47:15 -07:00
# include "sensors.h"
2018-07-19 00:33:40 -07:00
# include "src/PID_v1/PID_v1.h"
2014-01-07 00:02:00 -08:00
2016-04-08 06:52:32 -07:00
long PID_O2 , PID_output , PID_AFRTarget ;
2021-06-21 22:30:52 -07:00
/** Instance of the PID object in case that algorithm is used (Always instantiated).
* Needs to be global as it maintains state outside of each function call .
* Comes from Arduino ( ? ) PID library .
*/
PID egoPID ( & PID_O2 , & PID_output , & PID_AFRTarget , configPage6 . egoKP , configPage6 . egoKI , configPage6 . egoKD , REVERSE ) ;
2016-04-08 06:52:32 -07:00
2021-01-22 20:28:20 -08:00
byte activateMAPDOT ; //The mapDOT value seen when the MAE was activated.
byte activateTPSDOT ; //The tpsDOT value seen when the MAE was activated.
2022-04-10 20:38:23 -07:00
bool idleAdvActive = false ;
2020-01-23 19:18:57 -08:00
uint16_t AFRnextCycle ;
unsigned long knockStartTime ;
2024-07-10 23:14:09 -07:00
uint8_t knockLastRecoveryStep ;
//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
2022-04-04 14:27:54 -07:00
uint8_t aseTaper ;
2023-10-24 16:09:57 -07:00
uint8_t dfcoDelay ;
2022-04-04 14:27:54 -07:00
uint8_t idleAdvTaper ;
uint8_t crankingEnrichTaper ;
2023-10-24 16:09:57 -07:00
uint8_t dfcoTaper ;
2020-01-23 19:18:57 -08:00
2022-04-10 17:49:58 -07:00
/** Initialise instances and vars related to corrections (at ECU boot-up).
2021-06-21 22:30:52 -07:00
*/
2022-11-05 15:43:29 -07:00
void initialiseCorrections ( void )
2016-04-08 06:52:32 -07:00
{
2024-07-29 21:35:20 -07:00
PID_output = 0L ;
PID_O2 = 0L ;
PID_AFRTarget = 0L ;
// Toggling between modes resets the PID internal state
// This is required by the unit tests
// TODO: modify PID code to provide a method to reset it.
egoPID . SetMode ( AUTOMATIC ) ;
egoPID . SetMode ( MANUAL ) ;
egoPID . SetMode ( AUTOMATIC ) ;
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 ;
2024-07-10 23:14:09 -07:00
BIT_CLEAR ( currentStatus . status5 , BIT_STATUS5_KNOCK_ACTIVE ) ;
BIT_CLEAR ( currentStatus . status5 , BIT_STATUS5_KNOCK_PULSE ) ;
currentStatus . knockCount = 1 ;
knockLastRecoveryStep = 0 ;
knockStartTime = 0 ;
2022-04-10 17:49:58 -07:00
currentStatus . battery10 = 125 ; //Set battery voltage to sensible value for dwell correction for "flying start" (else ignition gets spurious pulses after boot)
2016-04-08 06:52:32 -07:00
}
2021-06-21 22:30:52 -07:00
/** Dispatch calculations for all fuel related corrections.
Calls all the other corrections functions and combines their results .
2015-01-27 15:01:12 -08:00
This is the only function that should be called from anywhere outside the file
*/
2022-11-05 15:43:29 -07:00
uint16_t correctionsFuel ( void )
2022-04-10 22:32:49 -07:00
{
uint32_t sumCorrections = 100 ;
uint16_t result ; //temporary variable to store the result of each corrections function
//The values returned by each of the correction functions are multiplied together and then divided back to give a single 0-255 value.
currentStatus . wueCorrection = correctionWUE ( ) ;
if ( currentStatus . wueCorrection ! = 100 ) { sumCorrections = div100 ( sumCorrections * currentStatus . wueCorrection ) ; }
2022-06-26 19:18:17 -07:00
currentStatus . ASEValue = correctionASE ( ) ;
if ( currentStatus . ASEValue ! = 100 ) { sumCorrections = div100 ( sumCorrections * currentStatus . ASEValue ) ; }
2022-04-10 22:32:49 -07:00
result = correctionCranking ( ) ;
if ( result ! = 100 ) { sumCorrections = div100 ( sumCorrections * result ) ; }
currentStatus . AEamount = correctionAccel ( ) ;
2023-01-09 15:46:34 -08:00
if ( ( configPage2 . aeApplyMode = = AE_MODE_MULTIPLIER ) | | BIT_CHECK ( currentStatus . engine , BIT_ENGINE_DCC ) ) // multiply by the AE amount in case of multiplier AE mode or Decel
2022-04-10 22:32:49 -07:00
{
2023-01-09 15:46:34 -08:00
if ( currentStatus . AEamount ! = 100 ) { sumCorrections = div100 ( sumCorrections * currentStatus . AEamount ) ; }
2022-04-10 22:32:49 -07:00
}
result = correctionFloodClear ( ) ;
if ( result ! = 100 ) { sumCorrections = div100 ( sumCorrections * result ) ; }
currentStatus . egoCorrection = correctionAFRClosedLoop ( ) ;
if ( currentStatus . egoCorrection ! = 100 ) { sumCorrections = div100 ( sumCorrections * currentStatus . egoCorrection ) ; }
currentStatus . batCorrection = correctionBatVoltage ( ) ;
if ( configPage2 . battVCorMode = = BATTV_COR_MODE_OPENTIME )
{
inj_opentime_uS = configPage2 . injOpen * currentStatus . batCorrection ; // Apply voltage correction to injector open time.
2024-02-19 20:36:45 -08:00
//currentStatus.batCorrection = 100; // This is to ensure that the correction is not applied twice. There is no battery correction fator as we have instead changed the open time
2022-04-10 22:32:49 -07:00
}
if ( configPage2 . battVCorMode = = BATTV_COR_MODE_WHOLE )
{
if ( currentStatus . batCorrection ! = 100 ) { sumCorrections = div100 ( sumCorrections * currentStatus . batCorrection ) ; }
}
currentStatus . iatCorrection = correctionIATDensity ( ) ;
if ( currentStatus . iatCorrection ! = 100 ) { sumCorrections = div100 ( sumCorrections * currentStatus . iatCorrection ) ; }
currentStatus . baroCorrection = correctionBaro ( ) ;
if ( currentStatus . baroCorrection ! = 100 ) { sumCorrections = div100 ( sumCorrections * currentStatus . baroCorrection ) ; }
currentStatus . flexCorrection = correctionFlex ( ) ;
if ( currentStatus . flexCorrection ! = 100 ) { sumCorrections = div100 ( sumCorrections * currentStatus . flexCorrection ) ; }
currentStatus . fuelTempCorrection = correctionFuelTemp ( ) ;
if ( currentStatus . fuelTempCorrection ! = 100 ) { sumCorrections = div100 ( sumCorrections * currentStatus . fuelTempCorrection ) ; }
currentStatus . launchCorrection = correctionLaunch ( ) ;
if ( currentStatus . launchCorrection ! = 100 ) { sumCorrections = div100 ( sumCorrections * currentStatus . launchCorrection ) ; }
bitWrite ( currentStatus . status1 , BIT_STATUS1_DFCO , correctionDFCO ( ) ) ;
2023-10-24 16:09:57 -07:00
byte dfcoTaperCorrection = correctionDFCOfuel ( ) ;
if ( dfcoTaperCorrection = = 0 ) { sumCorrections = 0 ; }
else if ( dfcoTaperCorrection ! = 100 ) { sumCorrections = div100 ( sumCorrections * dfcoTaperCorrection ) ; }
2022-04-10 22:32:49 -07:00
if ( sumCorrections > 1500 ) { sumCorrections = 1500 ; } //This is the maximum allowable increase during cranking
return ( uint16_t ) sumCorrections ;
}
2021-06-21 22:30:52 -07:00
/** Warm Up Enrichment (WUE) corrections.
2015-01-27 15:01:12 -08:00
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
*/
2022-11-05 15:43:29 -07:00
byte correctionWUE ( void )
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)
2019-10-29 04:50:46 -07:00
//if (currentStatus.coolant > (WUETable.axisX[9] - CALIBRATION_TEMPERATURE_OFFSET))
if ( currentStatus . coolant > ( table2D_getAxisValue ( & WUETable , 9 ) - CALIBRATION_TEMPERATURE_OFFSET ) )
2017-06-03 03:45:25 -07:00
{
//This prevents us doing the 2D lookup if we're already up to temp
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_WARMUP ) ;
2019-11-10 00:04:32 -08:00
WUEValue = table2D_getRawValue ( & WUETable , 9 ) ;
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
}
2021-06-21 22:30:52 -07:00
/** Cranking Enrichment corrections.
2015-02-06 13:29:51 -08:00
Additional fuel % to be added when the engine is cranking
*/
2022-11-05 15:43:29 -07:00
uint16_t correctionCranking ( void )
2015-02-06 13:29:51 -08:00
{
2020-03-16 16:38:03 -07:00
uint16_t crankingValue = 100 ;
2020-05-18 22:22:43 -07:00
//Check if we are actually cranking
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 ) ;
2020-03-16 16:38:03 -07:00
crankingValue = ( uint16_t ) crankingValue * 5 ; //multiplied by 5 to get range from 0% to 1275%
2022-04-04 14:27:54 -07:00
crankingEnrichTaper = 0 ;
2017-07-27 07:48:08 -07:00
}
2020-05-18 22:22:43 -07:00
//If we're not cranking, check if if cranking enrichment tapering to ASE should be done
2022-04-04 14:27:54 -07:00
else if ( crankingEnrichTaper < configPage10 . crankingEnrichTaper )
2020-05-18 22:22:43 -07:00
{
crankingValue = table2D_getValue ( & crankingEnrichTable , currentStatus . coolant + CALIBRATION_TEMPERATURE_OFFSET ) ;
crankingValue = ( uint16_t ) crankingValue * 5 ; //multiplied by 5 to get range from 0% to 1275%
//Taper start value needs to account for ASE that is now running, so total correction does not increase when taper begins
unsigned long taperStart = ( unsigned long ) crankingValue * 100 / currentStatus . ASEValue ;
2022-04-04 14:27:54 -07:00
crankingValue = ( uint16_t ) map ( crankingEnrichTaper , 0 , configPage10 . crankingEnrichTaper , taperStart , 100 ) ; //Taper from start value to 100%
2020-05-18 22:22:43 -07:00
if ( crankingValue < 100 ) { crankingValue = 100 ; } //Sanity check
2022-06-19 22:03:31 -07:00
if ( BIT_CHECK ( LOOP_TIMER , BIT_TIMER_10HZ ) ) { crankingEnrichTaper + + ; }
2020-05-18 22:22:43 -07:00
}
2017-06-03 03:45:25 -07:00
return crankingValue ;
2015-02-06 13:29:51 -08:00
}
2022-06-26 17:39:14 -07:00
/** After Start Enrichment calculation.
2020-01-23 19:18:57 -08:00
* This is a short period ( Usually < 20 seconds ) immediately after the engine first fires ( But not when cranking )
2021-06-21 22:30:52 -07:00
* where an additional amount of fuel is added ( Over and above the WUE amount ) .
2020-01-23 19:18:57 -08:00
*
* @ return uint8_t The After Start Enrichment modifier as a % . 100 % = No modification .
2022-06-19 22:03:31 -07:00
*/
2022-11-05 15:43:29 -07:00
byte correctionASE ( void )
2014-01-07 00:02:00 -08:00
{
2022-06-26 19:18:17 -07:00
int16_t ASEValue = currentStatus . ASEValue ;
2022-04-10 17:49:58 -07:00
//Two checks are required:
2019-10-31 20:25:51 -07:00
//1) Is the engine run time less than the configured ase time
2015-02-06 13:29:51 -08:00
//2) Make sure we're not still cranking
2022-06-19 22:03:31 -07:00
if ( BIT_CHECK ( currentStatus . engine , BIT_ENGINE_CRANK ) ! = true )
2014-01-29 21:28:21 -08:00
{
2022-06-26 19:18:17 -07:00
if ( BIT_CHECK ( LOOP_TIMER , BIT_TIMER_10HZ ) | | ( currentStatus . ASEValue = = 0 ) )
2020-03-23 18:36:24 -07:00
{
2022-06-19 22:03:31 -07:00
if ( ( currentStatus . runSecs < ( table2D_getValue ( & ASECountTable , currentStatus . coolant + CALIBRATION_TEMPERATURE_OFFSET ) ) ) & & ! ( BIT_CHECK ( currentStatus . engine , BIT_ENGINE_CRANK ) ) )
2020-03-23 18:36:24 -07:00
{
BIT_SET ( currentStatus . engine , BIT_ENGINE_ASE ) ; //Mark ASE as active.
2022-06-19 22:03:31 -07:00
ASEValue = 100 + table2D_getValue ( & ASETable , currentStatus . coolant + CALIBRATION_TEMPERATURE_OFFSET ) ;
aseTaper = 0 ;
2020-03-23 18:36:24 -07:00
}
else
{
2022-06-19 22:03:31 -07:00
if ( aseTaper < configPage2 . aseTaperTime ) //Check if we've reached the end of the taper time
{
BIT_SET ( currentStatus . engine , BIT_ENGINE_ASE ) ; //Mark ASE as active.
ASEValue = 100 + map ( aseTaper , 0 , configPage2 . aseTaperTime , table2D_getValue ( & ASETable , currentStatus . coolant + CALIBRATION_TEMPERATURE_OFFSET ) , 0 ) ;
aseTaper + + ;
}
else
{
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_ASE ) ; //Mark ASE as inactive.
ASEValue = 100 ;
}
2020-03-23 18:36:24 -07:00
}
2022-06-19 22:03:31 -07:00
//Safety checks
2024-08-22 14:19:52 -07:00
if ( ASEValue > UINT8_MAX ) { ASEValue = UINT8_MAX ; }
2022-06-19 22:03:31 -07:00
if ( ASEValue < 0 ) { ASEValue = 0 ; }
2022-06-26 19:18:17 -07:00
ASEValue = ( byte ) ASEValue ;
2020-03-23 18:36:24 -07:00
}
2022-06-19 22:03:31 -07:00
}
else
{
2022-06-26 19:18:17 -07:00
//Engine is cranking, ASE disabled
2022-06-19 22:03:31 -07:00
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_ASE ) ; //Mark ASE as inactive.
ASEValue = 100 ;
2014-01-29 21:28:21 -08:00
}
2022-06-26 19:18:17 -07:00
return ASEValue ;
2014-01-07 00:02:00 -08:00
}
2021-06-21 22:30:52 -07:00
/** Acceleration enrichment correction calculation.
2019-05-30 01:02:18 -07:00
*
* Calculates the % change of the throttle over time ( % / second ) and performs a lookup based on this
2020-04-18 15:21:52 -07:00
* Coolant - based modifier is applied on the top of this .
2019-05-30 01:02:18 -07:00
* When the enrichment is turned on , it runs at that amount for a fixed period of time ( taeTime )
*
2021-06-21 22:30:52 -07:00
* @ return uint16_t The Acceleration enrichment modifier as a % . 100 % = No modification .
*
2020-04-18 15:21:52 -07:00
* As the maximum enrichment amount is + 255 % and maximum cold adjustment for this is 255 % , the overall return value
2021-06-21 22:30:52 -07:00
* from this function can be 100 + ( 255 * 255 / 100 ) = 750. Hence this function returns a uint16_t rather than byte .
2019-05-30 01:02:18 -07:00
*/
2022-11-05 15:43:29 -07:00
uint16_t correctionAccel ( void )
2014-01-07 00:02:00 -08:00
{
2017-11-08 03:51:40 -08:00
int16_t accelValue = 100 ;
2021-01-21 21:31:14 -08:00
int16_t MAP_change = 0 ;
2022-04-15 19:51:54 -07:00
int16_t TPS_change = 0 ;
2021-01-21 21:31:14 -08:00
if ( configPage2 . aeMode = = AE_MODE_MAP )
{
//Get the MAP rate change
MAP_change = ( currentStatus . MAP - MAPlast ) ;
2023-11-05 14:10:08 -08:00
currentStatus . mapDOT = ( MICROS_PER_SEC / ( MAP_time - MAPlast_time ) ) * MAP_change ; //This is the % per second that the MAP has moved
2022-12-13 16:17:47 -08:00
//currentStatus.mapDOT = 15 * MAP_change; //This is the kpa per second that the MAP has moved
2021-01-21 21:31:14 -08:00
}
else if ( configPage2 . aeMode = = AE_MODE_TPS )
{
//Get the TPS rate change
2022-05-24 18:02:55 -07:00
TPS_change = ( currentStatus . TPS - currentStatus . TPSlast ) ;
2023-11-05 14:10:08 -08:00
//currentStatus.tpsDOT = ldiv(MICROS_PER_SEC, (TPS_time - TPSlast_time)).quot * TPS_change; //This is the % per second that the TPS has moved
2022-12-13 16:17:47 -08:00
currentStatus . tpsDOT = ( TPS_READ_FREQUENCY * TPS_change ) / 2 ; //This is the % per second that the TPS has moved, adjusted for the 0.5% resolution of the TPS
2021-01-21 21:31:14 -08:00
}
2015-01-27 15:01:12 -08:00
//First, check whether the accel. enrichment is already running
2022-12-13 16:17:47 -08:00
if ( BIT_CHECK ( currentStatus . engine , BIT_ENGINE_ACC ) | | BIT_CHECK ( currentStatus . engine , BIT_ENGINE_DCC ) )
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
2019-05-21 14:47:09 -07:00
if ( micros_safe ( ) > = currentStatus . AEEndTime )
2015-01-27 15:01:12 -08:00
{
//Time to turn enrichment off
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_ACC ) ;
2022-12-13 16:17:47 -08:00
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_DCC ) ;
2019-05-21 14:47:09 -07:00
currentStatus . AEamount = 0 ;
2017-06-03 03:45:25 -07:00
accelValue = 100 ;
2019-05-30 01:02:18 -07:00
//Reset the relevant DOT value to 0
if ( configPage2 . aeMode = = AE_MODE_MAP ) { currentStatus . mapDOT = 0 ; }
else if ( configPage2 . aeMode = = AE_MODE_TPS ) { currentStatus . tpsDOT = 0 ; }
2017-06-03 03:45:25 -07:00
}
else
{
2021-01-21 21:31:14 -08:00
//Enrichment still needs to keep running.
//Simply return the total TAE amount
2019-05-21 14:47:09 -07:00
accelValue = currentStatus . AEamount ;
2021-01-21 21:31:14 -08:00
//Need to check whether the accel amount has increased from when AE was turned on
//If the accel amount HAS increased, we clear the current enrich phase and a new one will be started below
2022-12-13 16:17:47 -08:00
if ( ( configPage2 . aeMode = = AE_MODE_MAP ) & & ( abs ( currentStatus . mapDOT ) > activateMAPDOT ) )
{
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_ACC ) ;
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_DCC ) ;
}
else if ( ( configPage2 . aeMode = = AE_MODE_TPS ) & & ( abs ( currentStatus . tpsDOT ) > activateTPSDOT ) )
{
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_ACC ) ;
BIT_CLEAR ( currentStatus . engine , BIT_ENGINE_DCC ) ;
}
2015-01-27 15:01:12 -08:00
}
}
2021-01-21 21:31:14 -08:00
2022-12-13 16:17:47 -08:00
if ( ! BIT_CHECK ( currentStatus . engine , BIT_ENGINE_ACC ) & & ! BIT_CHECK ( currentStatus . engine , BIT_ENGINE_DCC ) ) //Need to check this again as it may have been changed in the above section (Both ACC and DCC are off if this has changed)
2014-05-06 04:07:49 -07:00
{
2019-05-30 01:02:18 -07:00
if ( configPage2 . aeMode = = AE_MODE_MAP )
2017-06-03 03:45:25 -07:00
{
2022-12-13 16:17:47 -08:00
if ( abs ( MAP_change ) < = configPage2 . maeMinChange )
2017-06-03 03:45:25 -07:00
{
2019-06-04 01:27:38 -07:00
accelValue = 100 ;
currentStatus . mapDOT = 0 ;
}
else
{
//If MAE isn't currently turned on, need to check whether it needs to be turned on
2022-12-13 16:17:47 -08:00
if ( abs ( currentStatus . mapDOT ) > configPage2 . maeThresh )
2018-06-09 21:57:52 -07:00
{
2022-12-13 16:17:47 -08:00
activateMAPDOT = abs ( currentStatus . mapDOT ) ;
2019-06-04 01:27:38 -07:00
currentStatus . AEEndTime = micros_safe ( ) + ( ( unsigned long ) configPage2 . aeTime * 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
2022-12-13 16:17:47 -08:00
//Check if the MAP rate of change is negative or positive. Negative means decelarion.
if ( currentStatus . mapDOT < 0 )
2018-06-09 21:57:52 -07:00
{
2022-12-13 16:17:47 -08:00
BIT_SET ( currentStatus . engine , BIT_ENGINE_DCC ) ; //Mark deceleration enleanment as active.
accelValue = configPage2 . decelAmount ; //In decel, use the decel fuel amount as accelValue
} //Deceleration
//Positive MAP rate of change is acceleration.
else
2020-04-18 15:21:52 -07:00
{
2022-12-13 16:17:47 -08:00
BIT_SET ( currentStatus . engine , BIT_ENGINE_ACC ) ; //Mark acceleration enrichment as active.
accelValue = table2D_getValue ( & maeTable , currentStatus . mapDOT / 10 ) ; //The x-axis of mae table is divided by 10 to fit values in byte.
//Apply the RPM taper to the above
//The RPM settings are stored divided by 100:
uint16_t trueTaperMin = configPage2 . aeTaperMin * 100 ;
uint16_t trueTaperMax = configPage2 . aeTaperMax * 100 ;
if ( currentStatus . RPM > trueTaperMin )
2020-04-18 15:21:52 -07:00
{
2022-12-13 16:17:47 -08:00
if ( currentStatus . RPM > trueTaperMax ) { accelValue = 0 ; } //RPM is beyond taper max limit, so accel enrich is turned off
else
{
int16_t taperRange = trueTaperMax - trueTaperMin ;
int16_t taperPercent = ( ( currentStatus . RPM - trueTaperMin ) * 100UL ) / taperRange ; //The percentage of the way through the RPM taper range
accelValue = percentage ( ( 100 - taperPercent ) , accelValue ) ; //Calculate the above percentage of the calculated accel amount.
}
2020-04-18 15:21:52 -07:00
}
2022-12-13 16:17:47 -08:00
//Apply AE cold coolant modifier, if CLT is less than taper end temperature
if ( currentStatus . coolant < ( int ) ( configPage2 . aeColdTaperMax - CALIBRATION_TEMPERATURE_OFFSET ) )
2020-04-18 15:21:52 -07:00
{
2022-12-13 16:17:47 -08:00
//If CLT is less than taper min temp, apply full modifier on top of accelValue
if ( currentStatus . coolant < = ( int ) ( configPage2 . aeColdTaperMin - CALIBRATION_TEMPERATURE_OFFSET ) )
{
uint16_t accelValue_uint = percentage ( configPage2 . aeColdPct , accelValue ) ;
accelValue = ( int16_t ) accelValue_uint ;
}
//If CLT is between taper min and max, taper the modifier value and apply it on top of accelValue
else
{
int16_t taperRange = ( int16_t ) configPage2 . aeColdTaperMax - configPage2 . aeColdTaperMin ;
int16_t taperPercent = ( int ) ( ( currentStatus . coolant + CALIBRATION_TEMPERATURE_OFFSET - configPage2 . aeColdTaperMin ) * 100 ) / taperRange ;
int16_t coldPct = ( int16_t ) 100 + percentage ( ( 100 - taperPercent ) , ( configPage2 . aeColdPct - 100 ) ) ;
uint16_t accelValue_uint = ( uint16_t ) accelValue * coldPct / 100 ; //Potential overflow (if AE is large) without using uint16_t (percentage() may overflow)
accelValue = ( int16_t ) accelValue_uint ;
}
2020-04-18 15:21:52 -07:00
}
2022-12-13 16:17:47 -08:00
accelValue = 100 + accelValue ; //In case of AE, add the 100 normalisation to the calculated amount
2020-04-18 15:21:52 -07:00
}
2019-06-04 01:27:38 -07:00
} //MAE Threshold
2022-12-13 16:17:47 -08:00
} //MAP change threshold
} //AE Mode
2019-05-30 01:02:18 -07:00
else if ( configPage2 . aeMode = = AE_MODE_TPS )
{
2022-12-13 16:17:47 -08:00
//Check for only very small movement. This not only means we can skip the lookup, but helps reduce false triggering around 0-2% throttle openings
if ( abs ( TPS_change ) < = configPage2 . taeMinChange )
2019-05-30 01:02:18 -07:00
{
accelValue = 100 ;
currentStatus . tpsDOT = 0 ;
}
else
{
//If TAE isn't currently turned on, need to check whether it needs to be turned on
2022-12-13 16:17:47 -08:00
if ( abs ( currentStatus . tpsDOT ) > configPage2 . taeThresh )
2019-05-30 01:02:18 -07:00
{
2022-12-13 16:17:47 -08:00
activateTPSDOT = abs ( currentStatus . tpsDOT ) ;
2019-05-30 01:02:18 -07:00
currentStatus . AEEndTime = micros_safe ( ) + ( ( unsigned long ) configPage2 . aeTime * 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
2022-12-13 16:17:47 -08:00
//Check if the TPS rate of change is negative or positive. Negative means decelarion.
if ( currentStatus . tpsDOT < 0 )
2019-05-30 01:02:18 -07:00
{
2022-12-13 16:17:47 -08:00
BIT_SET ( currentStatus . engine , BIT_ENGINE_DCC ) ; //Mark deceleration enleanment as active.
accelValue = configPage2 . decelAmount ; //In decel, use the decel fuel amount as accelValue
} //Deceleration
//Positive TPS rate of change is Acceleration.
else
2020-04-18 15:21:52 -07:00
{
2022-12-13 16:17:47 -08:00
BIT_SET ( currentStatus . engine , BIT_ENGINE_ACC ) ; //Mark acceleration enrichment as active.
accelValue = table2D_getValue ( & taeTable , currentStatus . tpsDOT / 10 ) ; //The x-axis of tae table is divided by 10 to fit values in byte.
//Apply the RPM taper to the above
//The RPM settings are stored divided by 100:
uint16_t trueTaperMin = configPage2 . aeTaperMin * 100 ;
uint16_t trueTaperMax = configPage2 . aeTaperMax * 100 ;
if ( currentStatus . RPM > trueTaperMin )
2020-04-18 15:21:52 -07:00
{
2022-12-13 16:17:47 -08:00
if ( currentStatus . RPM > trueTaperMax ) { accelValue = 0 ; } //RPM is beyond taper max limit, so accel enrich is turned off
else
{
int16_t taperRange = trueTaperMax - trueTaperMin ;
int16_t taperPercent = ( ( currentStatus . RPM - trueTaperMin ) * 100UL ) / taperRange ; //The percentage of the way through the RPM taper range
accelValue = percentage ( ( 100 - taperPercent ) , accelValue ) ; //Calculate the above percentage of the calculated accel amount.
}
2020-04-18 15:21:52 -07:00
}
2022-12-13 16:17:47 -08:00
//Apply AE cold coolant modifier, if CLT is less than taper end temperature
if ( currentStatus . coolant < ( int ) ( configPage2 . aeColdTaperMax - CALIBRATION_TEMPERATURE_OFFSET ) )
2020-04-18 15:21:52 -07:00
{
2022-12-13 16:17:47 -08:00
//If CLT is less than taper min temp, apply full modifier on top of accelValue
if ( currentStatus . coolant < = ( int ) ( configPage2 . aeColdTaperMin - CALIBRATION_TEMPERATURE_OFFSET ) )
{
uint16_t accelValue_uint = percentage ( configPage2 . aeColdPct , accelValue ) ;
accelValue = ( int16_t ) accelValue_uint ;
}
//If CLT is between taper min and max, taper the modifier value and apply it on top of accelValue
else
{
int16_t taperRange = ( int16_t ) configPage2 . aeColdTaperMax - configPage2 . aeColdTaperMin ;
int16_t taperPercent = ( int ) ( ( currentStatus . coolant + CALIBRATION_TEMPERATURE_OFFSET - configPage2 . aeColdTaperMin ) * 100 ) / taperRange ;
int16_t coldPct = ( int16_t ) 100 + percentage ( ( 100 - taperPercent ) , ( configPage2 . aeColdPct - 100 ) ) ;
uint16_t accelValue_uint = ( uint16_t ) accelValue * coldPct / 100 ; //Potential overflow (if AE is large) without using uint16_t
accelValue = ( int16_t ) accelValue_uint ;
}
2020-04-18 15:21:52 -07:00
}
2022-12-13 16:17:47 -08:00
accelValue = 100 + accelValue ; //In case of AE, add the 100 normalisation to the calculated amount
} //Acceleration
2019-05-30 01:02:18 -07:00
} //TAE Threshold
2022-12-13 16:17:47 -08:00
} //TPS change threshold
2019-05-30 01:02:18 -07:00
} //AE Mode
} //AE active
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
}
2021-06-21 22:30:52 -07:00
/** Simple check to see whether we are cranking with the TPS above the flood clear threshold.
@ return 100 ( not cranking and thus no need for flood - clear ) or 0 ( Engine cranking and TPS above @ ref config4 . floodClear limit ) .
2014-05-06 04:07:49 -07:00
*/
2022-11-05 15:43:29 -07:00
byte correctionFloodClear ( void )
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
2021-06-21 22:30:52 -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 .
2015-04-04 03:10:13 -07:00
*/
2022-11-05 15:43:29 -07:00
byte correctionBatVoltage ( void )
2015-04-04 03:10:13 -07:00
{
2017-06-03 03:45:25 -07:00
byte batValue = 100 ;
2020-02-06 20:57:40 -08:00
batValue = table2D_getValue ( & injectorVCorrectionTable , currentStatus . battery10 ) ;
2017-06-03 03:45:25 -07:00
return batValue ;
2015-04-04 03:10:13 -07:00
}
2021-06-21 22:30:52 -07:00
/** Simple temperature based corrections lookup based on the inlet air temperature (IAT).
This corrects for changes in air density from movement of the temperature .
2015-10-17 15:29:41 -07:00
*/
2022-11-05 15:43:29 -07:00
byte correctionIATDensity ( void )
2015-10-17 15:29:41 -07:00
{
2017-06-03 03:45:25 -07:00
byte IATValue = 100 ;
2019-10-29 04:50:46 -07:00
IATValue = table2D_getValue ( & IATDensityCorrectionTable , currentStatus . IAT + CALIBRATION_TEMPERATURE_OFFSET ) ; //currentStatus.IAT is the actual temperature, values in IATDensityCorrectionTable.axisX are temp+offset
2017-06-03 03:45:25 -07:00
return IATValue ;
2015-10-18 05:20:16 -07:00
}
2022-04-10 17:49:58 -07:00
/** Correction for current barometric / ambient pressure.
* @ returns A percentage value indicating the amount the fuelling should be changed based on the barometric reading . 100 = No change . 110 = 10 % increase . 90 = 10 % decrease
2019-11-03 15:14:11 -08:00
*/
2022-11-05 15:43:29 -07:00
byte correctionBaro ( void )
2019-11-03 15:14:11 -08:00
{
byte baroValue = 100 ;
baroValue = table2D_getValue ( & baroFuelTable , currentStatus . baro ) ;
return baroValue ;
}
2021-06-21 22:30:52 -07:00
/** Launch control has a setting to increase the fuel load to assist in bringing up boost.
2015-10-18 05:20:16 -07:00
This simple check applies the extra fuel if we ' re currently launching
*/
2022-11-05 15:43:29 -07:00
byte correctionLaunch ( void )
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
}
2023-10-24 16:09:57 -07:00
/**
*/
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 ;
}
2016-02-24 18:11:13 -08:00
/*
2022-04-10 17:49:58 -07:00
* Returns true if deceleration fuel cutoff should be on , false if its off
2016-02-24 18:11:13 -08:00
*/
2022-11-05 15:43:29 -07:00
bool correctionDFCO ( void )
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
{
2020-05-28 19:25:33 -07:00
if ( BIT_CHECK ( currentStatus . status1 , BIT_STATUS1_DFCO ) = = 1 )
2020-04-07 18:25:53 -07:00
{
2020-04-02 20:46:11 -07:00
DFCOValue = ( currentStatus . RPM > ( configPage4 . dfcoRPM * 10 ) ) & & ( currentStatus . TPS < configPage4 . dfcoTPSThresh ) ;
2023-10-24 16:09:57 -07:00
if ( DFCOValue = = false ) { dfcoDelay = 0 ; }
2020-04-02 20:46:11 -07:00
}
2020-04-07 18:25:53 -07:00
else
{
2023-10-05 05:02:15 -07:00
if ( ( currentStatus . TPS < configPage4 . dfcoTPSThresh ) & & ( currentStatus . coolant > = ( int ) ( configPage2 . dfcoMinCLT - CALIBRATION_TEMPERATURE_OFFSET ) ) & & ( currentStatus . RPM > ( unsigned int ) ( ( configPage4 . dfcoRPM * 10 ) + ( configPage4 . dfcoHyster * 2 ) ) ) )
2020-04-07 18:25:53 -07:00
{
2023-10-24 16:09:57 -07:00
if ( dfcoDelay < configPage2 . dfcoDelay )
2022-04-04 14:27:54 -07:00
{
2023-10-24 16:09:57 -07:00
if ( BIT_CHECK ( LOOP_TIMER , BIT_TIMER_10HZ ) ) { dfcoDelay + + ; }
2022-04-04 14:27:54 -07:00
}
else { DFCOValue = true ; }
2020-04-02 20:46:11 -07:00
}
2023-10-24 16:09:57 -07:00
else { dfcoDelay = 0 ; } //Prevent future activation right away if previous time wasn't activated
2020-04-07 18:25:53 -07:00
} // DFCO active check
} // DFCO enabled check
2017-06-03 03:45:25 -07:00
return DFCOValue ;
2016-02-24 18:11:13 -08:00
}
2021-06-21 22:30:52 -07: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
*/
2022-11-05 15:43:29 -07:00
byte correctionFlex ( void )
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
}
2020-08-17 19:34:56 -07:00
/*
* Fuel temperature adjustment to vary fuel based on fuel temperature reading
*/
2022-11-05 15:43:29 -07:00
byte correctionFuelTemp ( void )
2020-08-17 19:34:56 -07:00
{
byte fuelTempValue = 100 ;
if ( configPage2 . flexEnabled = = 1 )
{
fuelTempValue = table2D_getValue ( & fuelTempTable , currentStatus . fuelTemp + CALIBRATION_TEMPERATURE_OFFSET ) ;
}
return fuelTempValue ;
}
2024-07-29 21:35:20 -07:00
// ============================= Air Fuel Ratio (AFR) correction =============================
uint8_t calculateAfrTarget ( table3d16RpmLoad & afrLookUpTable , const statuses & current , const config2 & page2 , const config6 & page6 ) {
//afrTarget value lookup must be done if O2 sensor is enabled, and always if incorporateAFR is enabled
if ( page2 . incorporateAFR = = true ) {
return get3DTableValue ( & afrLookUpTable , current . fuelLoad , current . RPM ) ;
}
if ( page6 . egoType ! = EGO_TYPE_OFF )
{
//Determine whether the Y axis of the AFR target table tshould be MAP (Speed-Density) or TPS (Alpha-N)
//Note that this should only run after the sensor warmup delay when using Include AFR option,
if ( current . runSecs > page6 . ego_sdelay ) {
return get3DTableValue ( & afrLookUpTable , current . fuelLoad , current . RPM ) ;
}
return current . O2 ; //Catch all
}
return current . afrTarget ;
}
2021-06-21 22:30:52 -07:00
/** Lookup the AFR target table and perform either a simple or PID adjustment based on this.
2015-02-05 13:11:33 -08:00
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
2021-10-20 14:03:29 -07:00
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 % .
2021-06-21 22:30:52 -07:00
2015-02-05 13:11:33 -08:00
This continues until either :
2021-06-21 22:30:52 -07:00
- the O2 reading flips from lean to rich , at which point the adjustment cycle starts again at 1 % or
2021-10-20 14:03:29 -07:00
- 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
*/
2022-11-05 15:43:29 -07:00
byte correctionAFRClosedLoop ( void )
2015-02-05 13:11:33 -08:00
{
2024-07-29 21:35:20 -07:00
byte AFRValue = 100U ;
2017-06-03 03:45:25 -07:00
2024-03-20 17:37:45 -07:00
if ( ( configPage6 . egoType > 0 ) & & ( BIT_CHECK ( currentStatus . status1 , BIT_STATUS1_DFCO ) ! = 1 ) ) //egoType of 0 means no O2 sensor. If DFCO is active do not run the ego controllers to prevent iterator wind-up.
2021-01-19 18:01:04 -08:00
{
2020-04-23 18:17:42 -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
2022-12-13 17:03:53 -08:00
if ( ( ignitionCount > = AFRnextCycle ) | | ( ignitionCount < ( AFRnextCycle - configPage6 . egoCount ) ) )
2015-02-05 13:11:33 -08:00
{
2020-04-06 22:03:15 -07:00
AFRnextCycle = ignitionCount + configPage6 . egoCount ; //Set the target ignition event for the next calculation
//Check all other requirements for closed loop adjustments
2024-05-28 23:29:25 -07: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 ) & & ( BIT_CHECK ( currentStatus . status1 , BIT_STATUS1_DFCO ) = = 0 ) & & ( currentStatus . MAP < = ( configPage9 . egoMAPMax * 2 ) ) & & ( currentStatus . MAP > = ( configPage9 . egoMAPMin * 2 ) ) )
2015-02-15 02:32:38 -08:00
{
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
2022-04-10 17:49:58 -07:00
if ( currentStatus . egoCorrection < ( 100 + configPage6 . egoLimit ) ) //Fuelling adjustment must be at most the egoLimit amount (up or down)
2017-11-05 01:56:04 -07:00
{
2022-04-10 17:49:58 -07:00
AFRValue = ( currentStatus . egoCorrection + 1 ) ; //Increase the fuelling 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
2022-04-10 17:49:58 -07:00
if ( currentStatus . egoCorrection > ( 100 - configPage6 . egoLimit ) ) //Fuelling adjustment must be at most the egoLimit amount (up or down)
2017-11-05 01:56:04 -07:00
{
2022-04-10 17:49:58 -07:00
AFRValue = ( currentStatus . egoCorrection - 1 ) ; //Decrease the fuelling 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
2022-04-10 17:49:58 -07:00
egoPID . SetOutputLimits ( ( long ) ( - configPage6 . egoLimit ) , ( long ) ( configPage6 . egoLimit ) ) ; //Set the limits again, just in case 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 in case 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 ) ;
2019-12-01 19:47:30 -08:00
bool PID_compute = egoPID . Compute ( ) ;
2017-11-05 01:56:04 -07:00
//currentStatus.egoCorrection = 100 + PID_output;
2019-12-01 19:47:30 -08:00
if ( PID_compute = = true ) { AFRValue = 100 + PID_output ; }
2017-11-05 01:56:04 -07:00
}
else { AFRValue = 100 ; } // Occurs if the egoAlgorithm is set to 0 (No Correction)
2020-04-06 22:03:15 -07:00
} //Multi variable check
2020-04-23 18:17:42 -07:00
else { AFRValue = 100 ; } // If multivariable check fails disable correction
2020-04-06 22:03:15 -07:00
} //Ignition count 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 ********************************
2021-06-21 22:30:52 -07:00
/** Dispatch calculations for all ignition related corrections.
* @ param base_advance - Base ignition advance ( deg . ? )
* @ return Advance considering all ( ~ 12 ) individual 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 ) ;
2020-07-21 18:27:21 -07:00
advance = correctionWMITiming ( advance ) ;
2017-01-10 23:30:46 -08:00
advance = correctionIATretard ( advance ) ;
2019-04-11 05:31:24 -07:00
advance = correctionCLTadvance ( advance ) ;
2019-11-07 21:40:53 -08:00
advance = correctionIdleAdvance ( advance ) ;
2017-01-10 23:30:46 -08:00
advance = correctionSoftRevLimit ( advance ) ;
2018-06-29 08:19:51 -07:00
advance = correctionNitrous ( advance ) ;
2017-01-10 23:30:46 -08:00
advance = correctionSoftLaunch ( advance ) ;
2017-01-17 18:20:04 -08:00
advance = correctionSoftFlatShift ( advance ) ;
2024-07-10 23:14:09 -07:00
advance = correctionKnockTiming ( advance ) ;
2017-05-09 22:46:14 -07:00
2023-10-24 16:09:57 -07:00
advance = correctionDFCOignition ( advance ) ;
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 ) ;
2019-11-07 21:40:53 -08:00
advance = correctionCrankingFixedTiming ( advance ) ; //This overrides the regular fixed timing, must come last
2016-12-11 03:51:04 -08:00
return advance ;
}
2021-06-21 22:30:52 -07:00
/** Correct ignition timing to configured fixed value.
* Must be called near end to override all other corrections .
*/
2020-02-02 22:35:29 -08:00
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-06-29 01:07:39 -07:00
if ( configPage2 . fixAngEnable = = 1 ) { 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
}
2021-06-21 22:30:52 -07:00
/** Correct ignition timing to configured fixed value to use during craning.
* Must be called near end to override all other corrections .
*/
2020-02-02 22:35:29 -08:00
int8_t correctionCrankingFixedTiming ( int8_t advance )
2016-12-11 03:51:04 -08:00
{
2021-11-08 12:57:15 -08:00
int8_t ignCrankFixValue = advance ;
2023-05-09 17:32:11 -07:00
if ( BIT_CHECK ( currentStatus . engine , BIT_ENGINE_CRANK ) )
{
if ( configPage2 . crkngAddCLTAdv = = 0 ) { ignCrankFixValue = configPage4 . CrankAng ; } //Use the fixed cranking ignition angle
else { ignCrankFixValue = correctionCLTadvance ( configPage4 . CrankAng ) ; } //Use the CLT compensated cranking ignition angle
}
2017-06-03 03:45:25 -07:00
return ignCrankFixValue ;
2016-12-11 03:51:04 -08:00
}
2020-02-02 22:35:29 -08:00
int8_t correctionFlexTiming ( int8_t advance )
2016-12-11 03:51:04 -08:00
{
2020-04-15 23:31:54 -07:00
int16_t 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
{
2020-04-15 23:31:54 -07:00
ignFlexValue = ( int16_t ) table2D_getValue ( & flexAdvTable , currentStatus . ethanolPct ) - OFFSET_IGNITION ; //Negative values are achieved with offset
currentStatus . flexIgnCorrection = ( int8_t ) ignFlexValue ; //This gets cast to a signed 8 bit value to allows for negative advance (ie retard) values here.
ignFlexValue = ( int8_t ) advance + currentStatus . flexIgnCorrection ;
2017-06-03 03:45:25 -07:00
}
2020-04-15 23:31:54 -07:00
return ( int8_t ) ignFlexValue ;
2016-12-11 03:51:04 -08:00
}
2020-07-21 18:27:21 -07:00
int8_t correctionWMITiming ( int8_t advance )
{
2022-01-01 00:30:21 -08:00
if ( ( configPage10 . wmiEnabled > = 1 ) & & ( configPage10 . wmiAdvEnabled = = 1 ) & & ! BIT_CHECK ( currentStatus . status4 , BIT_STATUS4_WMI_EMPTY ) ) //Check for wmi being enabled
2020-07-21 18:27:21 -07:00
{
2022-01-01 00:30:21 -08:00
if ( ( currentStatus . TPS > = configPage10 . wmiTPS ) & & ( currentStatus . RPM > = configPage10 . wmiRPM ) & & ( currentStatus . MAP / 2 > = configPage10 . wmiMAP ) & & ( ( currentStatus . IAT + CALIBRATION_TEMPERATURE_OFFSET ) > = configPage10 . wmiIAT ) )
2020-07-21 18:27:21 -07:00
{
return ( int16_t ) advance + table2D_getValue ( & wmiAdvTable , currentStatus . MAP / 2 ) - OFFSET_IGNITION ; //Negative values are achieved with offset
}
}
return advance ;
}
2021-06-21 22:30:52 -07:00
/** Ignition correction for inlet air temperature (IAT).
*/
2020-02-02 22:35:29 -08:00
int8_t correctionIATretard ( int8_t advance )
2016-12-11 03:51:04 -08:00
{
2017-05-09 00:29:55 -07:00
int8_t advanceIATadjust = table2D_getValue ( & IATRetardTable , currentStatus . IAT ) ;
2017-06-03 03:45:25 -07:00
2021-11-08 12:57:15 -08:00
return advance - advanceIATadjust ;
2016-12-11 03:51:04 -08:00
}
2021-06-21 22:30:52 -07:00
/** Ignition correction for coolant temperature (CLT).
*/
2020-02-02 22:35:29 -08:00
int8_t correctionCLTadvance ( int8_t advance )
2019-04-11 05:31:24 -07:00
{
2019-06-23 21:46:11 -07:00
int8_t ignCLTValue = advance ;
2019-04-11 05:31:24 -07:00
//Adjust the advance based on CLT.
2019-06-23 21:46:11 -07:00
int8_t advanceCLTadjust = ( int16_t ) ( table2D_getValue ( & CLTAdvanceTable , currentStatus . coolant + CALIBRATION_TEMPERATURE_OFFSET ) ) - 15 ;
ignCLTValue = ( advance + advanceCLTadjust ) ;
2019-04-11 05:31:24 -07:00
return ignCLTValue ;
}
2021-06-21 22:30:52 -07:00
/** Ignition Idle advance correction.
*/
2020-02-02 22:35:29 -08:00
int8_t correctionIdleAdvance ( int8_t advance )
2019-11-07 21:40:53 -08:00
{
int8_t ignIdleValue = advance ;
//Adjust the advance based on idle target rpm.
2022-04-10 20:38:23 -07:00
if ( ( configPage2 . idleAdvEnabled > = 1 ) & & ( runSecsX10 > = ( configPage2 . idleAdvDelay * 5 ) ) & & idleAdvActive )
2019-11-07 21:40:53 -08:00
{
2022-04-15 19:18:58 -07:00
//currentStatus.CLIdleTarget = (byte)table2D_getValue(&idleTargetTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //All temps are offset by 40 degrees
2019-12-01 19:47:30 -08:00
int idleRPMdelta = ( currentStatus . CLIdleTarget - ( currentStatus . RPM / 10 ) ) + 50 ;
2019-11-07 21:40:53 -08:00
// Limit idle rpm delta between -500rpm - 500rpm
if ( idleRPMdelta > 100 ) { idleRPMdelta = 100 ; }
if ( idleRPMdelta < 0 ) { idleRPMdelta = 0 ; }
2022-04-04 14:27:54 -07:00
if ( ( currentStatus . RPM < ( configPage2 . idleAdvRPM * 100 ) ) & & ( ( configPage2 . vssMode = = 0 ) | | ( currentStatus . vss < configPage2 . idleAdvVss ) )
2021-07-19 01:03:07 -07:00
& & ( ( ( configPage2 . idleAdvAlgorithm = = 0 ) & & ( currentStatus . TPS < configPage2 . idleAdvTPS ) ) | | ( ( configPage2 . idleAdvAlgorithm = = 1 ) & & ( currentStatus . CTPSActive = = 1 ) ) ) ) // closed throttle position sensor (CTPS) based idle state
2019-11-07 21:40:53 -08:00
{
2022-04-04 14:27:54 -07:00
if ( idleAdvTaper < configPage9 . idleAdvStartDelay )
{
if ( BIT_CHECK ( LOOP_TIMER , BIT_TIMER_10HZ ) ) { idleAdvTaper + + ; }
}
else
2021-07-19 01:03:07 -07:00
{
int8_t advanceIdleAdjust = ( int16_t ) ( table2D_getValue ( & idleAdvanceTable , idleRPMdelta ) ) - 15 ;
if ( configPage2 . idleAdvEnabled = = 1 ) { ignIdleValue = ( advance + advanceIdleAdjust ) ; }
else if ( configPage2 . idleAdvEnabled = = 2 ) { ignIdleValue = advanceIdleAdjust ; }
}
2019-11-07 21:40:53 -08:00
}
2022-04-04 14:27:54 -07:00
else { idleAdvTaper = 0 ; }
2019-11-07 21:40:53 -08:00
}
2022-04-10 20:38:23 -07:00
2023-05-03 07:24:45 -07:00
/* When Idle advance is the only idle speed control mechanism, activate as soon as not cranking.
When some other mechanism is also present , wait until the engine is no more than 200 RPM below idle target speed on first time
*/
if ( ( ! idleAdvActive & & BIT_CHECK ( currentStatus . engine , BIT_ENGINE_RUN ) ) & &
( ( configPage6 . iacAlgorithm = = 0 ) | | ( currentStatus . RPM > ( ( ( uint16_t ) currentStatus . CLIdleTarget * 10 ) - ( uint16_t ) IGN_IDLE_THRESHOLD ) ) ) )
{
idleAdvActive = true ;
}
else
if ( idleAdvActive & & ! BIT_CHECK ( currentStatus . engine , BIT_ENGINE_RUN ) ) { idleAdvActive = false ; } //Clear flag if engine isn't running anymore
2022-04-10 20:38:23 -07:00
2019-11-07 21:40:53 -08:00
return ignIdleValue ;
}
2021-06-21 22:30:52 -07:00
/** Ignition soft revlimit correction.
*/
2020-02-02 22:35:29 -08:00
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 ;
2024-07-10 23:14:09 -07:00
BIT_CLEAR ( currentStatus . status2 , BIT_STATUS2_SFTLIM ) ;
2021-12-21 18:29:13 -08:00
if ( configPage6 . engineProtectType = = PROTECT_CUT_IGN | | configPage6 . engineProtectType = = PROTECT_CUT_BOTH )
{
2022-03-27 14:31:58 -07:00
if ( currentStatus . RPMdiv100 > = configPage4 . SoftRevLim ) //Softcut RPM limit
2021-10-11 16:25:14 -07:00
{
2024-07-10 23:14:09 -07:00
BIT_SET ( currentStatus . status2 , BIT_STATUS2_SFTLIM ) ;
2022-04-04 14:27:54 -07:00
if ( softLimitTime < configPage4 . SoftLimMax )
2021-12-21 18:29:13 -08:00
{
if ( configPage2 . SoftLimitMode = = SOFT_LIMIT_RELATIVE ) { ignSoftRevValue = ignSoftRevValue - configPage4 . SoftLimRetard ; } //delay timing by configured number of degrees in relative mode
else if ( configPage2 . SoftLimitMode = = SOFT_LIMIT_FIXED ) { ignSoftRevValue = configPage4 . SoftLimRetard ; } //delay timing to configured number of degrees in fixed mode
2022-04-04 14:27:54 -07:00
if ( BIT_CHECK ( LOOP_TIMER , BIT_TIMER_10HZ ) ) { softLimitTime + + ; }
2021-12-21 18:29:13 -08:00
}
2022-04-04 14:27:54 -07:00
}
else if ( BIT_CHECK ( LOOP_TIMER , BIT_TIMER_10HZ ) ) { softLimitTime = 0 ; } //Only reset time at runSecsX10 update rate
2020-05-08 15:39:13 -07:00
}
2017-06-03 03:45:25 -07:00
return ignSoftRevValue ;
2016-12-11 03:51:04 -08:00
}
2021-06-21 22:30:52 -07:00
/** Ignition Nitrous oxide correction.
*/
2020-02-02 22:35:29 -08:00
int8_t correctionNitrous ( int8_t advance )
2018-06-29 08:19:51 -07:00
{
byte ignNitrous = advance ;
//Check if nitrous is currently active
if ( configPage10 . n2o_enable > 0 )
{
//Check which stage is running (if any)
2020-03-18 20:18:54 -07:00
if ( ( currentStatus . nitrous_status = = NITROUS_STAGE1 ) | | ( currentStatus . nitrous_status = = NITROUS_BOTH ) )
2018-06-29 08:19:51 -07:00
{
ignNitrous - = configPage10 . n2o_stage1_retard ;
}
2020-03-18 20:18:54 -07:00
if ( ( currentStatus . nitrous_status = = NITROUS_STAGE2 ) | | ( currentStatus . nitrous_status = = NITROUS_BOTH ) )
2018-06-29 08:19:51 -07:00
{
ignNitrous - = configPage10 . n2o_stage2_retard ;
}
}
return ignNitrous ;
}
2021-06-21 22:30:52 -07:00
/** Ignition soft launch correction.
*/
2020-02-02 22:35:29 -08:00
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.
2024-08-13 17:50:47 -07:00
if ( configPage6 . launchEnabled & & currentStatus . clutchTrigger & & \
( currentStatus . clutchEngagedRPM < ( ( unsigned int ) ( configPage6 . flatSArm ) * 100 ) ) & & \
( currentStatus . RPM > ( ( unsigned int ) ( configPage6 . lnchSoftLim ) * 100 ) ) & & \
( currentStatus . TPS > = configPage10 . lnchCtrlTPS ) & & \
( ( configPage2 . vssMode = = 0 ) | | ( ( configPage2 . vssMode > 0 ) & & ( currentStatus . vss < = configPage10 . lnchCtrlVss ) ) ) \
)
2017-01-17 18:20:04 -08:00
{
2017-02-13 06:07:05 -08:00
currentStatus . launchingSoft = true ;
2024-07-10 23:14:09 -07:00
BIT_SET ( currentStatus . status2 , BIT_STATUS2_SLAUNCH ) ;
2018-01-23 17:05:50 -08:00
ignSoftLaunchValue = configPage6 . lnchRetard ;
2017-06-03 03:45:25 -07:00
}
else
{
currentStatus . launchingSoft = false ;
2024-07-10 23:14:09 -07:00
BIT_CLEAR ( currentStatus . status2 , BIT_STATUS2_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
}
2021-06-21 22:30:52 -07:00
/** Ignition correction for soft flat shift.
*/
2020-02-02 22:35:29 -08:00
int8_t correctionSoftFlatShift ( int8_t advance )
2017-01-17 18:20:04 -08:00
{
2021-07-18 16:35:42 -07:00
int8_t ignSoftFlatValue = advance ;
2017-06-03 03:45:25 -07:00
2023-12-05 19:47:13 -08:00
if ( configPage6 . flatSEnable & & currentStatus . clutchTrigger & & ( currentStatus . clutchEngagedRPM > ( ( unsigned int ) ( configPage6 . flatSArm ) * 100 ) ) & & ( currentStatus . RPM > ( currentStatus . clutchEngagedRPM - ( configPage6 . flatSSoftWin * 100 ) ) ) )
2017-02-13 06:07:05 -08:00
{
2024-07-10 23:14:09 -07:00
BIT_SET ( currentStatus . status5 , BIT_STATUS5_FLATSS ) ;
2018-01-23 17:05:50 -08:00
ignSoftFlatValue = configPage6 . flatSRetard ;
2017-01-17 18:20:04 -08:00
}
2024-07-10 23:14:09 -07:00
else { BIT_CLEAR ( currentStatus . status5 , BIT_STATUS5_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
}
2024-07-11 15:16:37 -07:00
uint8_t _calculateKnockRecovery ( uint8_t curKnockRetard )
{
uint8_t tmpKnockRetard = curKnockRetard ;
//Check whether we are in knock recovery
if ( ( micros ( ) - knockStartTime ) > ( configPage10 . knock_duration * 100000UL ) ) //knock_duration is in seconds*10
{
2024-08-13 00:16:33 -07:00
//Calculate how many recovery steps have occurred since the
2024-07-11 15:16:37 -07:00
uint32_t timeInRecovery = ( micros ( ) - knockStartTime ) - ( configPage10 . knock_duration * 100000UL ) ;
uint8_t recoverySteps = timeInRecovery / ( configPage10 . knock_recoveryStepTime * 100000UL ) ;
int8_t recoveryTimingAdj = 0 ;
if ( recoverySteps > knockLastRecoveryStep )
{
recoveryTimingAdj = ( recoverySteps - knockLastRecoveryStep ) * configPage10 . knock_recoveryStep ;
knockLastRecoveryStep = recoverySteps ;
}
if ( recoveryTimingAdj < currentStatus . knockRetard )
{
//Add the timing back in provided we haven't reached the end of the recovery period
tmpKnockRetard = currentStatus . knockRetard - recoveryTimingAdj ;
}
else
{
//Recovery is complete. Knock adjustment is set to 0 and we reset the knock status
tmpKnockRetard = 0 ;
BIT_CLEAR ( currentStatus . status5 , BIT_STATUS5_KNOCK_ACTIVE ) ;
knockStartTime = 0 ;
currentStatus . knockCount = 0 ;
}
}
return tmpKnockRetard ;
}
2021-06-21 22:30:52 -07:00
/** Ignition knock (retard) correction.
*/
2024-07-10 23:14:09 -07:00
int8_t correctionKnockTiming ( int8_t advance )
2018-07-26 05:09:48 -07:00
{
2024-07-10 23:14:09 -07:00
byte tmpKnockRetard = 0 ;
2018-08-31 00:36:09 -07:00
if ( ( configPage10 . knock_mode = = KNOCK_MODE_DIGITAL ) )
{
//
2024-07-10 23:14:09 -07:00
if ( currentStatus . knockCount > = configPage10 . knock_count )
2018-08-31 00:36:09 -07:00
{
2024-07-10 23:14:09 -07:00
if ( BIT_CHECK ( currentStatus . status5 , BIT_STATUS5_KNOCK_ACTIVE ) )
2018-08-31 00:36:09 -07:00
{
2024-07-10 23:14:09 -07:00
//Knock retard is currently active already.
tmpKnockRetard = currentStatus . knockRetard ;
2024-08-13 00:16:33 -07:00
//Check if additional knock events occurred
2024-07-10 23:14:09 -07:00
if ( BIT_CHECK ( currentStatus . status5 , BIT_STATUS5_KNOCK_PULSE ) )
{
//Check if the latest event was far enough after the initial knock event to pull further timing
if ( ( micros ( ) - knockStartTime ) > ( configPage10 . knock_stepTime * 1000UL ) )
{
//Recalculate the amount timing being pulled
currentStatus . knockCount + + ;
tmpKnockRetard = configPage10 . knock_firstStep + ( ( currentStatus . knockCount - configPage10 . knock_count ) * configPage10 . knock_stepSize ) ;
knockStartTime = micros ( ) ;
knockLastRecoveryStep = 0 ;
}
}
2024-07-11 15:16:37 -07:00
tmpKnockRetard = _calculateKnockRecovery ( tmpKnockRetard ) ;
2018-08-31 00:36:09 -07:00
}
else
{
2024-07-10 23:14:09 -07:00
//Knock currently inactive but needs to be active now
2018-08-31 00:36:09 -07:00
knockStartTime = micros ( ) ;
2024-07-10 23:14:09 -07:00
tmpKnockRetard = configPage10 . knock_firstStep + ( ( currentStatus . knockCount - configPage10 . knock_count ) * configPage10 . knock_stepSize ) ; //
BIT_SET ( currentStatus . status5 , BIT_STATUS5_KNOCK_ACTIVE ) ;
knockLastRecoveryStep = 0 ;
2018-08-31 00:36:09 -07:00
}
}
2024-07-10 23:14:09 -07:00
BIT_CLEAR ( currentStatus . status5 , BIT_STATUS5_KNOCK_PULSE ) ; //Reset the knock pulse indicator
2018-08-13 19:47:15 -07:00
}
2024-07-11 15:16:37 -07:00
else if ( ( configPage10 . knock_mode = = KNOCK_MODE_ANALOG ) )
{
if ( BIT_CHECK ( currentStatus . status5 , BIT_STATUS5_KNOCK_ACTIVE ) )
{
2024-08-13 00:16:33 -07:00
//Check if additional knock events occurred
2024-07-11 15:16:37 -07:00
//Additional knock events are when the step time has passed and the voltage remains above the threshold
if ( ( micros ( ) - knockStartTime ) > ( configPage10 . knock_stepTime * 1000UL ) )
{
//Sufficient time has passed, check the current knock value
uint16_t tmpKnockReading = getAnalogKnock ( ) ;
if ( tmpKnockReading > configPage10 . knock_threshold )
{
currentStatus . knockCount + + ;
tmpKnockRetard = configPage10 . knock_firstStep + ( ( currentStatus . knockCount - configPage10 . knock_count ) * configPage10 . knock_stepSize ) ;
knockStartTime = micros ( ) ;
knockLastRecoveryStep = 0 ;
}
}
tmpKnockRetard = _calculateKnockRecovery ( tmpKnockRetard ) ;
}
else
{
//If not is not currently active, we read the analog pin every 30Hz
if ( BIT_CHECK ( LOOP_TIMER , BIT_TIMER_30HZ ) )
{
uint16_t tmpKnockReading = getAnalogKnock ( ) ;
if ( tmpKnockReading > configPage10 . knock_threshold )
{
//Knock detected
knockStartTime = micros ( ) ;
tmpKnockRetard = configPage10 . knock_firstStep ; //
BIT_SET ( currentStatus . status5 , BIT_STATUS5_KNOCK_ACTIVE ) ;
knockLastRecoveryStep = 0 ;
}
}
}
}
2024-07-10 23:14:09 -07:00
2018-08-13 19:47:15 -07:00
2024-07-10 23:14:09 -07:00
tmpKnockRetard = min ( tmpKnockRetard , configPage10 . knock_maxRetard ) ; //Ensure the commanded retard is not higher than the maximum allowed.
currentStatus . knockRetard = tmpKnockRetard ;
return advance - tmpKnockRetard ;
2018-07-26 05:09:48 -07:00
}
2023-10-24 16:09:57 -07:00
/** 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 ;
}
2021-06-21 22:30:52 -07:00
/** Ignition Dwell Correction.
*/
2017-04-21 00:29:09 -07:00
uint16_t correctionsDwell ( uint16_t dwell )
{
2017-06-03 03:45:25 -07:00
uint16_t tempDwell = dwell ;
2022-09-26 18:55:42 -07:00
uint16_t sparkDur_uS = ( configPage4 . sparkDur * 100 ) ; //Spark duration is in mS*10. Multiple it by 100 to get spark duration in uS
2023-05-21 20:37:40 -07:00
if ( currentStatus . actualDwell = = 0 ) { currentStatus . actualDwell = tempDwell ; } //Initialise the actualDwell value if this is the first time being called
//**************************************************************************************************************************
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 ) ;
2022-02-17 19:55:43 -08:00
if ( currentStatus . dwellCorrection ! = 100 ) { tempDwell = div100 ( dwell ) * currentStatus . dwellCorrection ; }
2017-04-21 00:29:09 -07:00
2023-05-21 20:37:40 -07:00
//**************************************************************************************************************************
//Dwell error correction is a basic closed loop to keep the dwell time consistent even when adjusting its end time for the per tooth timing.
//This is mostly of benefit to low resolution triggers at low rpm (<1500)
if ( ( configPage2 . perToothIgn = = true ) & & ( configPage4 . dwellErrCorrect = = 1 ) )
{
int16_t error = tempDwell - currentStatus . actualDwell ;
if ( tempDwell > INT16_MAX ) { tempDwell = INT16_MAX ; } //Prevent overflow when casting to signed int
if ( error > ( ( int16_t ) tempDwell / 2 ) ) { error + = error ; } //Double correction amount if actual dwell is less than 50% of the requested dwell
if ( error > 0 ) { tempDwell + = error ; }
}
//**************************************************************************************************************************
/*
Dwell limiter - If the total required dwell time per revolution is longer than the maximum time available at the current RPM , reduce dwell . This can occur if there are multiple sparks per revolution
This only times this can occur are :
1. Single channel spark mode where there will be nCylinders / 2 sparks per revolution
2. Rotary ignition in wasted spark configuration ( FC / FD ) , results in 2 pulses per rev . RX - 8 is fully sequential resulting in 1 pulse , so not required
*/
2022-09-26 18:55:42 -07:00
uint16_t dwellPerRevolution = tempDwell + sparkDur_uS ;
2017-05-09 00:29:55 -07:00
int8_t pulsesPerRevolution = 1 ;
2022-04-03 03:09:55 -07:00
if ( ( ( configPage4 . sparkMode = = IGN_MODE_SINGLE ) | | ( ( configPage4 . sparkMode = = IGN_MODE_ROTARY ) & & ( configPage10 . rotaryType ! = ROTARY_IGN_RX8 ) ) ) & & ( 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
2023-11-05 14:10:08 -08:00
uint16_t adjustedSparkDur = udiv_32_16 ( sparkDur_uS * revolutionTime , dwellPerRevolution ) ;
tempDwell = udiv_32_16 ( revolutionTime , ( uint16_t ) pulsesPerRevolution ) - adjustedSparkDur ;
2017-04-21 00:29:09 -07:00
}
2023-05-21 20:37:40 -07:00
2017-06-03 03:45:25 -07:00
return tempDwell ;
2017-04-21 00:29:09 -07:00
}