Rover MEMS 4 cylinder decoder (#1032)

Decodes the 5 known Rover MEMS ECU patterns for Rover based engines. Covers A series, T series, O Series, K Series and V8. Doesn't currently cover sequential ignition for v6 or v8.

Co-authored-by: Josh Stewart <josh@noisymime.org>
Resolves #101
This commit is contained in:
mike501 2023-04-30 10:01:10 +01:00 committed by GitHub
parent e0dbb38794
commit 53d6a6a461
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 451 additions and 11 deletions

View File

@ -177,7 +177,7 @@
#define trigger_NGC = 22
#define trigger_VMAX = 23
#define trigger_renix = 24
#define trigger_Rover = 25
[Constants]
@ -497,13 +497,13 @@ page = 4
TrigEdge = bits, U08, 5,[0:0], "RISING", "FALLING"
TrigSpeed = bits, U08, 5,[1:1], "Crank Speed", "Cam Speed"
IgInv = bits, U08, 5,[2:2], "Going Low", "Going High"
TrigPattern= bits, U08, 5,[3:7], "Missing Tooth", "Basic Distributor", "Dual Wheel", "GM 7X", "4G63 / Miata / 3000GT", "GM 24X", "Jeep 2000", "Audi 135", "Honda D17", "Miata 99-05", "Mazda AU", "Non-360 Dual", "Nissan 360", "Subaru 6/7", "Daihatsu +1", "Harley EVO", "36-2-2-2", "36-2-1", "DSM 420a", "Weber-Marelli", "Ford ST170", "DRZ400", "Chrysler NGC", "Yamaha Vmax 1990+", "Renix", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
TrigPattern= bits, U08, 5,[3:7], "Missing Tooth", "Basic Distributor", "Dual Wheel", "GM 7X", "4G63 / Miata / 3000GT", "GM 24X", "Jeep 2000", "Audi 135", "Honda D17", "Miata 99-05", "Mazda AU", "Non-360 Dual", "Nissan 360", "Subaru 6/7", "Daihatsu +1", "Harley EVO", "36-2-2-2", "36-2-1", "DSM 420a", "Weber-Marelli", "Ford ST170", "DRZ400", "Chrysler NGC", "Yamaha Vmax 1990+", "Renix", "Rover MEMS", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
TrigEdgeSec= bits, U08, 6,[0:0], "RISING", "FALLING"
fuelPumpPin= bits , U08, 6,[1:6], "Board Default", "INVALID", "INVALID", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "INVALID", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15", "INVALID"
useResync = bits, U08, 6,[7:7], "No", "Yes"
sparkDur = scalar, U08, 7, "ms", 0.1, 0, 0, 25.5, 1 ; Spark duration
trigPatternSec = bits,U08, 8,[0:6], "Single tooth cam", "4-1 cam", "Poll level", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
PollLevelPol = bits, U08, 8,[7:7], "Low", "High"
trigPatternSec = bits,U08, 8,[0:6], "Single tooth cam", "4-1 cam", "Poll level", "Rover 5-3-2 cam", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
PollLevelPol = bits, U08, 8,[7:7], "Low", "High",
;Reset Control
bootloaderCaps = scalar, U08, 9, "level", 1, 0, 0, 255, 0
@ -2838,9 +2838,9 @@ menuDialog = main
field = "Note: This is the number of revolutions that will be skipped during"
field = "cranking before the injectors and coils are fired"
field = "Trigger edge", TrigEdge { TrigPattern != 4 && TrigPattern != 22 } ;4G63 uses both edges ;NGC uses both edges
field = "Secondary trigger edge", TrigEdgeSec, { (TrigPattern == 0 && TrigSpeed == 0 && trigPatternSec != 2) || TrigPattern == 2 || TrigPattern == 9 || TrigPattern == 12 || TrigPattern == 18 || TrigPattern == 19 || TrigPattern == 20 || TrigPattern == 21 || TrigPattern == 24 } ;Missing tooth, dual wheel and Miata 9905, weber-marelli, ST170, DRZ400 Renix,
field = "Secondary trigger edge", TrigEdgeSec, { (TrigPattern == 0 && TrigSpeed == 0 && trigPatternSec != 2) || TrigPattern == 2 || TrigPattern == 9 || TrigPattern == 12 || TrigPattern == 18 || TrigPattern == 19 || TrigPattern == 20 || TrigPattern == 21 || TrigPattern == 24 || TrigPattern == 25 } ;Missing tooth, dual wheel and Miata 9905, weber-marelli, ST170, DRZ400 Renix, Rover MEMS
field = "Level for 1st phase", PollLevelPol, { (TrigPattern == 0 && TrigSpeed == 0 && trigPatternSec == 2) }
field = "Missing Tooth Secondary type", trigPatternSec, { (TrigPattern == 0 && TrigSpeed == 0) }
field = "Missing Tooth Secondary type", trigPatternSec, { (TrigPattern == 0&& TrigSpeed == 0) || TrigPattern == 25 }
field = "Trigger Filter", TrigFilter, { TrigPattern != 13 }
field = "Re-sync every cycle", useResync, { TrigPattern == 2 || TrigPattern == 4 || TrigPattern == 7 || TrigPattern == 12 || TrigPattern == 9 || TrigPattern == 13 || TrigPattern == 18 || TrigPattern == 19 || TrigPattern == 21 } ;Dual wheel, 4G63, Audi 135, Nissan 360, Miata 99-05, weber-marelli. DRZ400

View File

@ -36,7 +36,7 @@
#define DECODER_NGC 22
#define DECODER_VMAX 23
#define DECODER_RENIX 24
#define DECODER_ROVERMEMS 25
#define BIT_DECODER_2ND_DERIV 0 //The use of the 2nd derivative calculation is limited to certain decoders. This is set to either true or false in each decoders setup routine
#define BIT_DECODER_IS_SEQUENTIAL 1 //Whether or not the decoder supports sequential operation
@ -223,6 +223,13 @@ void triggerSetup_Renix();
void triggerPrimary_Renix();
void triggerSetEndTeeth_Renix();
void triggerSetup_RoverMEMS(void);
void triggerPri_RoverMEMS(void);
void triggerSec_RoverMEMS(void);
uint16_t getRPM_RoverMEMS(void);
int getCrankAngle_RoverMEMS(void);
void triggerSetEndTeeth_RoverMEMS(void);
void triggerSetup_Vmax(void);
void triggerPri_Vmax(void);
void triggerSec_Vmax(void);
@ -296,4 +303,11 @@ extern int16_t toothAngles[24]; //An array for storing fixed tooth angles. Curre
#define TOOTH_CRANK 0
#define TOOTH_CAM 1
// used by the ROVER MEMS pattern
#define ID_TOOTH_PATTERN 0 // have we identified teeth to skip for calculating RPM?
#define SKIP_TOOTH1 1
#define SKIP_TOOTH2 2
#define SKIP_TOOTH3 3
#define SKIP_TOOTH4 4
#endif

View File

@ -69,8 +69,10 @@ volatile unsigned long targetGap2;
volatile unsigned long toothOneTime = 0; //The time (micros()) that tooth 1 last triggered
volatile unsigned long toothOneMinusOneTime = 0; //The 2nd to last time (micros()) that tooth 1 last triggered
volatile bool revolutionOne = 0; // For sequential operation, this tracks whether the current revolution is 1 or 2 (not 1)
volatile bool revolutionLastOne = 0; // used to identify in the rover pattern which has a non unique primary trigger something unique - has the secondary tooth changed.
volatile unsigned int secondaryToothCount; //Used for identifying the current secondary (Usually cam) tooth for patterns with multiple secondary teeth
volatile unsigned int secondaryLastToothCount = 0; // used to identify in the rover pattern which has a non unique primary trigger something unique - has the secondary tooth changed.
volatile unsigned long secondaryLastToothTime = 0; //The time (micros()) that the last tooth was registered (Cam input)
volatile unsigned long secondaryLastToothTime1 = 0; //The time (micros()) that the last tooth was registered (Cam input)
@ -4880,9 +4882,6 @@ void triggerPri_Renix()
}
}
void triggerSetEndTeeth_Renix()
{
byte toothAdder = 0;
@ -4964,5 +4963,411 @@ void triggerSetEndTeeth_Renix()
lastToothCalcAdvance = currentStatus.advance;
}
/** @} */
/*****************************************************************
* Rover MEMS decoder
* Covers multiple trigger wheels used interchanbably over the range of MEMS units
* Specifically covers teeth patterns on the primary trigger (crank)
* 3 gap 14 gap 2 gap 13 gap
* 11 gap 5 gap 12 gap 4 gap
* 2 gap 14 gap 3 gap 13 gap
* 17 gap 17 gap
*
* Support no cam, single tooth Cam (or half moon cam), and multi tooth (5-3-2 teeth)
*
* @defgroup dec_rover_mems Rover MEMS all versions including T Series, O Series, Mini and K Series
* @{
*/
volatile unsigned long roverMEMSTeethSeen = 0; // used for flywheel gap pattern matching
void triggerSetup_RoverMEMS()
{
for(toothOneTime = 0; toothOneTime < 10; toothOneTime++) // repurpose variable temporarily to help clear ToothAngles.
{ toothAngles[toothOneTime] = 0; }// Repurpose ToothAngles to store data needed for this implementation.
triggerFilterTime = (1000000 / (MAX_RPM / 60 * 36)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
triggerSecFilterTime = (1000000 / (MAX_RPM / 60)); // only 1 tooth on the wheel not 36
configPage4.triggerTeeth = 36;
triggerToothAngle = 360 / configPage4.triggerTeeth; //The number of degrees that passes from tooth to tooth 360 / 36 theortical teeth
triggerActualTeeth = 36; //The number of physical teeth on the wheel. Need to fix now so we can identify the wheel on the first rotation and not risk a type 1 wheel not being spotted
toothLastMinusOneToothTime = 0;
toothCurrentCount = 0; // current tooth
secondaryToothCount = 0;
secondaryLastToothCount = 0;
toothOneTime = 0;
toothOneMinusOneTime = 0;
revolutionOne=0;
MAX_STALL_TIME = (3333UL * triggerToothAngle * 2); //Minimum 50rpm. (3333uS is the time per degree at 50rpm)
}
void triggerPri_RoverMEMS()
{
curTime = micros();
curGap = curTime - toothLastToothTime;
if ( curGap >= triggerFilterTime ) //Pulses should never be less than triggerFilterTime, so if they are it means a false trigger. (A 36-1 wheel at 8000pm will have triggers approx. every 200uS)
{
if( (toothLastToothTime > 0) && (toothLastMinusOneToothTime > 0) ) // have we seen more than 1 tooth so we start processing
{
//Begin the missing tooth detection
targetGap = (3 * (toothLastToothTime - toothLastMinusOneToothTime)) >> 1; //Multiply by 1.5 (Checks for a gap 1.5x greater than the last one) (Uses bitshift to multiply by 3 then divide by 2. Much faster than multiplying by 1.5)
currentStatus.hasSync = true;
if ( curGap > targetGap) // we've found a gap
{
roverMEMSTeethSeen = roverMEMSTeethSeen << 2; // add the space for the gap and the tooth we've just seen so shift 2 bits
roverMEMSTeethSeen++; // add the tooth seen to the variable
toothCurrentCount++; // Increment the tooth counter on the wheel (used to spot a revolution and trigger igition timing)
// the missing tooth gap messing up timing as it appears in different parts of the cycle. Don't update setFilter as it would be wrong with the gap
toothCurrentCount++;
}
else //Regular (non-missing) tooth so update things
{
roverMEMSTeethSeen = roverMEMSTeethSeen << 1; // make a space, shift the bits 1 place to the left
roverMEMSTeethSeen++; // add the tooth seen
toothCurrentCount++; //Increment the tooth counter on the wheel (used to spot a revolution)
setFilter(curGap);
}
// reduce checks to minimise cpu load when looking for key point to identify where we are on the wheel
if( toothCurrentCount >= triggerActualTeeth )
{ //12345678901234567890123456789012
if( roverMEMSTeethSeen == 0b11111101111111011111111110111111) // Binary pattern for trigger pattern 9-7-10-6- (#5)
{
if(toothAngles[ID_TOOTH_PATTERN] != 5)
{
//teeth to skip when calculating RPM as they've just had a gap
toothAngles[SKIP_TOOTH1] = 1;
toothAngles[SKIP_TOOTH2] = 11;
toothAngles[SKIP_TOOTH3] = 19;
toothAngles[SKIP_TOOTH4] = 30;
toothAngles[ID_TOOTH_PATTERN] = 5;
configPage4.triggerMissingTeeth = 4; // this could be read in from the config file, but people could adjust it.
triggerActualTeeth = 36; // should be 32 if not hacking toothcounter
}
triggerRoverMEMSCommon();
} //123456789012345678901234567890123456
else if( roverMEMSTeethSeen == 0b11011101111111111111101101111111) // Binary pattern for trigger pattern 3-14-2-13- (#4)
{
if(toothAngles[ID_TOOTH_PATTERN] != 4)
{
//teeth to skip when calculating RPM as they've just had a gap
toothAngles[SKIP_TOOTH1] = 8;
toothAngles[SKIP_TOOTH2] = 11;
toothAngles[SKIP_TOOTH3] = 25;
toothAngles[SKIP_TOOTH4] = 27;
toothAngles[ID_TOOTH_PATTERN] = 4;
configPage4.triggerMissingTeeth = 4; // this could be read in from the config file, but people could adjust it.
triggerActualTeeth = 36; // should be 32 if not hacking toothcounter
}
triggerRoverMEMSCommon();
} //123456789012345678901234567890123456
else if(roverMEMSTeethSeen == 0b11011011111111111111011101111111) // Binary pattern for trigger pattern 2-14-3-13- (#3)
{
if(toothAngles[ID_TOOTH_PATTERN] != 3)
{
//teeth to skip when calculating RPM as they've just had a gap
toothAngles[SKIP_TOOTH1] = 8;
toothAngles[SKIP_TOOTH2] = 10;
toothAngles[SKIP_TOOTH3] = 24;
toothAngles[SKIP_TOOTH4] = 27;
toothAngles[ID_TOOTH_PATTERN] = 3;
configPage4.triggerMissingTeeth = 4; // this could be read in from the config file, but people could adjust it.
triggerActualTeeth = 36; // should be 32 if not hacking toothcounter
}
triggerRoverMEMSCommon();
} //12345678901234567890123456789012
else if(roverMEMSTeethSeen == 0b11111101111101111111111110111101) // Binary pattern for trigger pattern 11-5-12-4- (#2)
{
if(toothAngles[ID_TOOTH_PATTERN] != 2)
{
//teeth to skip when calculating RPM as they've just had a gap
toothAngles[SKIP_TOOTH1] = 1;
toothAngles[SKIP_TOOTH2] = 12;
toothAngles[SKIP_TOOTH3] = 17;
toothAngles[SKIP_TOOTH4] = 29;
toothAngles[ID_TOOTH_PATTERN] = 2;
configPage4.triggerMissingTeeth = 4; // this could be read in from the config file, but people could adjust it.
triggerActualTeeth = 36; // should be 32 if not hacking toothcounter
}
triggerRoverMEMSCommon();
} //12345678901234567890123456789012
else if(roverMEMSTeethSeen == 0b11111111111101111111111111111101) // Binary pattern for trigger pattern 17-17- (#1)
{
if(toothAngles[ID_TOOTH_PATTERN] != 1)
{
//teeth to skip when calculating RPM as they've just had a gap
toothAngles[SKIP_TOOTH1] = 1;
toothAngles[SKIP_TOOTH2] = 18;
toothAngles[ID_TOOTH_PATTERN] = 1;
configPage4.triggerMissingTeeth = 2; // this should be read in from the config file, but people could adjust it.
triggerActualTeeth = 36; // should be 34 if not hacking toothcounter
}
triggerRoverMEMSCommon();
}
else if(toothCurrentCount > triggerActualTeeth+1) // no patterns match after a rotation when we only need 32 teeth to match, we've lost sync
{
currentStatus.hasSync = false;
if(secondaryToothCount > 0)
BIT_SET(currentStatus.status3, BIT_STATUS3_HALFSYNC);
else
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_HALFSYNC);
currentStatus.syncLossCounter++;
}
}
}
toothLastMinusOneToothTime = toothLastToothTime;
toothLastToothTime = curTime;
//NEW IGNITION MODE
if( (configPage2.perToothIgn == true) && (!BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) )
{
int16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage4.triggerAngle;
crankAngle = ignitionLimits(crankAngle);
if( (configPage4.sparkMode == IGN_MODE_SEQUENTIAL) && (revolutionOne == true))
{ crankAngle += 360; checkPerToothTiming(crankAngle, (configPage4.triggerTeeth + toothCurrentCount)); }
else
{ checkPerToothTiming(crankAngle, toothCurrentCount); }
}
}
}
void triggerRoverMEMSCommon(void)
{
// pattern 1 isn't unique & if we don't have a cam we need special code to identify if we're tooth 18 or 36 - this allows batch injection but not spark to run
// as we have to be greater than 18 teeth when using the cam this code also works for that.
if( toothCurrentCount > 18)
{
toothCurrentCount = 1;
toothOneMinusOneTime = toothOneTime;
toothOneTime = curTime;
revolutionOne = !revolutionOne; //Flip sequential revolution tracker
}
//if Sequential fuel or ignition is in use, further checks are needed before determining sync
if( (configPage4.sparkMode == IGN_MODE_SEQUENTIAL) || (configPage2.injLayout == INJ_SEQUENTIAL) )
{
//If either fuel or ignition is sequential, only declare sync if the cam tooth has been seen OR if the missing wheel is on the cam
if( (secondaryToothCount > 0) || (configPage4.TrigSpeed == CAM_SPEED) )
{
currentStatus.hasSync = true;
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_HALFSYNC); //the engine is fully synced so clear the Half Sync bit
if(configPage4.trigPatternSec == SEC_TRIGGER_SINGLE) { secondaryToothCount = 0; } //Reset the secondary tooth counter to prevent it overflowing
}
else if(currentStatus.hasSync != true)
{ BIT_SET(currentStatus.status3, BIT_STATUS3_HALFSYNC); } //If there is primary trigger but no secondary we only have half sync.
}
else { currentStatus.hasSync = true; BIT_CLEAR(currentStatus.status3, BIT_STATUS3_HALFSYNC); } //If nothing is using sequential, we have sync and also clear half sync bit
if(currentStatus.hasSync == true)
{ currentStatus.startRevolutions++; }
else
{ currentStatus.startRevolutions = 0; }
}
int getCrankAngle_RoverMEMS()
{
//This is the current angle ATDC the engine is at. This is the last known position based on what tooth was last 'seen'. It is only accurate to the resolution of the trigger wheel (Eg 36-1 is 10 degrees)
unsigned long tempToothLastToothTime;
int tempToothCurrentCount;
bool tempRevolutionOne;
//Grab some variables that are used in the trigger code and assign them to temp variables.
noInterrupts();
tempToothCurrentCount = toothCurrentCount;
tempRevolutionOne = revolutionOne;
tempToothLastToothTime = toothLastToothTime;
interrupts();
int crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage4.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
//Sequential check (simply sets whether we're on the first or 2nd revoltuion of the cycle)
if ( (tempRevolutionOne == true) && (configPage4.TrigSpeed == CRANK_SPEED) ) { crankAngle += 360; }
lastCrankAngleCalc = micros();
elapsedTime = (lastCrankAngleCalc - tempToothLastToothTime);
crankAngle += timeToAngle(elapsedTime, CRANKMATH_METHOD_INTERVAL_REV);
if (crankAngle >= 720) { crankAngle -= 720; }
else if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; }
if (crankAngle < 0) { crankAngle += CRANK_ANGLE_MAX; }
return crankAngle;
}
void triggerSec_RoverMEMS()
{
curTime2 = micros();
curGap2 = curTime2 - toothLastSecToothTime;
//Safety check for initial startup
if( (toothLastSecToothTime == 0) )
{
targetGap2 = curGap * 2;
curGap2 = 0;
toothLastSecToothTime = curTime2;
}
if ( curGap2 >= triggerSecFilterTime )
{
secondaryToothCount++;
toothLastSecToothTime = curTime2;
//Record the VVT Angle
if( configPage6.vvtEnabled > 0 &&
( (configPage4.trigPatternSec == SEC_TRIGGER_SINGLE) ||
(configPage4.trigPatternSec == SEC_TRIGGER_5_3_2 && secondaryToothCount == 6 ) ) )
{
int16_t curAngle;
curAngle = getCrankAngle();
while(curAngle > 360) { curAngle -= 360; }
curAngle -= configPage4.triggerAngle; //Value at TDC
if( configPage6.vvtMode == VVT_MODE_CLOSED_LOOP ) { curAngle -= configPage10.vvtCLMinAng; }
currentStatus.vvt1Angle = curAngle;
}
if(configPage4.trigPatternSec == SEC_TRIGGER_SINGLE)
{
//Standard single tooth cam trigger
revolutionOne = true;
triggerSecFilterTime = curGap2 >> 1; //Next secondary filter is half the current gap
}
else if (configPage4.trigPatternSec == SEC_TRIGGER_5_3_2) // multi tooth cam
{
if (curGap2 < targetGap2) // ie normal tooth sized gap, not a single or double gap
{
triggerSecFilterTime = curGap2 >> 1; //Next secondary filter is half the current gap
targetGap2 = (3 * (curGap2)) >> 1; //Multiply by 1.5 (Checks for a gap 1.5x greater than the last one) (Uses bitshift to multiply by 3 then divide by 2. Much faster than multiplying by 1.5)
}
else
{
// gap either single or double - nb remember we've got the tooth after the gap, so on the 5 tooth pattern we'll see here tooth 6
if(secondaryToothCount == 6)
{
// if we've got the tooth after the gap from reading 5 teeth we're on cycle 360-720 & tooth 18-36
revolutionOne = false;
if(toothCurrentCount < 19)
{
toothCurrentCount += 18;
}
}
else if (secondaryToothCount == 4)
{
// we've got the tooth after the gap from reading 3 teeth we're on cycle 0-360 & tooth 1-18
revolutionOne = true;
if(toothCurrentCount > 17)
{
toothCurrentCount -= 18;
}
}
else if (secondaryToothCount == 3)
{
// if we've got the tooth after the gap from reading 2 teeth we're on cycle 0-360 & tooth 18-36
revolutionOne = true;
if(toothCurrentCount < 19)
{
toothCurrentCount += 18;
}
}
secondaryToothCount = 1; // as we've had a gap we need to reset to this being the first tooth after the gap
}
}
} //Trigger filter
}
uint16_t getRPM_RoverMEMS()
{
uint16_t tempRPM = 0;
if( currentStatus.RPM < currentStatus.crankRPM)
{
if( (toothCurrentCount != (unsigned int) toothAngles[SKIP_TOOTH1]) &&
(toothCurrentCount != (unsigned int) toothAngles[SKIP_TOOTH2]) &&
(toothCurrentCount != (unsigned int) toothAngles[SKIP_TOOTH3]) &&
(toothCurrentCount != (unsigned int) toothAngles[SKIP_TOOTH4]) )
{ tempRPM = crankingGetRPM(36,360); }
else
{ tempRPM = currentStatus.RPM; } //Can't do per tooth RPM as the missing tooth messes the calculation
}
else
{ tempRPM = stdGetRPM(360); }
return tempRPM;
}
void triggerSetEndTeeth_RoverMEMS()
{
//Temp variables are used here to avoid potential issues if a trigger interrupt occurs part way through this function
int16_t tempIgnitionEndTooth[5]; // cheating with the array - location 1 is spark 1, location 0 not used.
int16_t toothAdder = 0;
if( (configPage4.sparkMode == IGN_MODE_SEQUENTIAL) && (configPage4.TrigSpeed == CRANK_SPEED) ) { toothAdder = 36; }
tempIgnitionEndTooth[1] = ( (ignition1EndAngle - configPage4.triggerAngle) / (int16_t)(10) ) - 1;
if(tempIgnitionEndTooth[1] > (36 + toothAdder)) { tempIgnitionEndTooth[1] -= (36 + toothAdder); }
if(tempIgnitionEndTooth[1] <= 0) { tempIgnitionEndTooth[1] += (36 + toothAdder); }
if(tempIgnitionEndTooth[1] > (36 + toothAdder)) { tempIgnitionEndTooth[1] = (36 + toothAdder); }
tempIgnitionEndTooth[2] = ( (ignition2EndAngle - configPage4.triggerAngle) / (int16_t)(10) ) - 1;
if(tempIgnitionEndTooth[2] > (36 + toothAdder)) { tempIgnitionEndTooth[2] -= (36 + toothAdder); }
if(tempIgnitionEndTooth[2] <= 0) { tempIgnitionEndTooth[2] += (36 + toothAdder); }
if(tempIgnitionEndTooth[2] > (36 + toothAdder)) { tempIgnitionEndTooth[2] = (36 + toothAdder); }
tempIgnitionEndTooth[3] = ( (ignition3EndAngle - configPage4.triggerAngle) / (int16_t)(10) ) - 1;
if(tempIgnitionEndTooth[3] > (36 + toothAdder)) { tempIgnitionEndTooth[3] -= (36 + toothAdder); }
if(tempIgnitionEndTooth[3] <= 0) { tempIgnitionEndTooth[3] += (36 + toothAdder); }
if(tempIgnitionEndTooth[3] > (36 + toothAdder)) { tempIgnitionEndTooth[3] = (36 + toothAdder); }
tempIgnitionEndTooth[4] = ( (ignition4EndAngle - configPage4.triggerAngle) / (int16_t)(10) ) - 1;
if(tempIgnitionEndTooth[4] > (36 + toothAdder)) { tempIgnitionEndTooth[4] -= (36 + toothAdder); }
if(tempIgnitionEndTooth[4] <= 0) { tempIgnitionEndTooth[4] += (36 + toothAdder); }
if(tempIgnitionEndTooth[4] > (36 + toothAdder)) { tempIgnitionEndTooth[4] = (36 + toothAdder); }
// take into account the missing teeth on the Rover flywheels
int tempCount=0;
if(configPage4.sparkMode == IGN_MODE_SEQUENTIAL)
{
// check the calculated trigger tooth exists, if it doesn't use the previous tooth
// nb the toothAngles[x] holds the tooth after the gap, hence the '-1' to see if it matches a gap
for(tempCount=1;tempCount <5;tempCount++)
{
if(tempIgnitionEndTooth[tempCount] == (toothAngles[1]) || tempIgnitionEndTooth[tempCount] == (toothAngles[2]) ||
tempIgnitionEndTooth[tempCount] == (toothAngles[3]) || tempIgnitionEndTooth[tempCount] == (toothAngles[4]) ||
tempIgnitionEndTooth[tempCount] == (36 + toothAngles[1]) || tempIgnitionEndTooth[tempCount] == (36 + toothAngles[2]) ||
tempIgnitionEndTooth[tempCount] == (36 + toothAngles[3]) || tempIgnitionEndTooth[tempCount] == (36 + toothAngles[4]) )
{ tempIgnitionEndTooth[tempCount]--; }
}
}
else
{
for(tempCount=1;tempCount<5;tempCount++)
{
if(tempIgnitionEndTooth[tempCount] == (toothAngles[1]) || tempIgnitionEndTooth[tempCount] == (toothAngles[2]) )
{ tempIgnitionEndTooth[tempCount]--; }
}
}
ignition1EndTooth = tempIgnitionEndTooth[1];
ignition2EndTooth = tempIgnitionEndTooth[2];
ignition3EndTooth = tempIgnitionEndTooth[3];
ignition4EndTooth = tempIgnitionEndTooth[4];
lastToothCalcAdvance = currentStatus.advance;
}
/** @} */
/** @} */

View File

@ -283,6 +283,7 @@
#define SEC_TRIGGER_SINGLE 0
#define SEC_TRIGGER_4_1 1
#define SEC_TRIGGER_POLL 2
#define SEC_TRIGGER_5_3_2 3
#define ROTARY_IGN_FC 0
#define ROTARY_IGN_FD 1

View File

@ -3470,6 +3470,26 @@ void initialiseTriggers(void)
attachInterrupt(triggerInterrupt2, triggerSecondaryHandler, secondaryTriggerEdge);
break;
case DECODER_ROVERMEMS:
//Rover MEMs - covers multiple flywheel trigger combinations.
triggerSetup_RoverMEMS();
triggerHandler = triggerPri_RoverMEMS;
getRPM = getRPM_RoverMEMS;
triggerSetEndTeeth = triggerSetEndTeeth_RoverMEMS;
triggerSecondaryHandler = triggerSec_RoverMEMS;
getCrankAngle = getCrankAngle_missingTooth;
if(configPage4.TrigEdge == 0) { primaryTriggerEdge = RISING; } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { primaryTriggerEdge = FALLING; }
if(configPage4.TrigEdgeSec == 0) { secondaryTriggerEdge = RISING; }
else { secondaryTriggerEdge = FALLING; }
attachInterrupt(triggerInterrupt, triggerHandler, primaryTriggerEdge);
attachInterrupt(triggerInterrupt2, triggerSecondaryHandler, secondaryTriggerEdge);
break;
case DECODER_DRZ400:
triggerSetup_DRZ400();