revolutionTime=(toothOneTime-toothOneMinusOneTime);//The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that)
triggerActualTeeth=configPage2.triggerTeeth-configPage2.triggerMissingTeeth;//The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt
triggerFilterTime=(int)(1000000/(MAX_RPM/60*configPage2.triggerTeeth));//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
if(curGap<triggerFilterTime){return;}//Debounce check. 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 the time between the current tooth and the last is greater than 1.5x the time between the last tooth and the tooth before that, we make the assertion that we must be at the first tooth after the gap
if(configPage2.triggerMissingTeeth==1){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)
else{targetGap=((toothLastToothTime-toothLastMinusOneToothTime))*2;}//Multiply by 2 (Checks for a gap 2x greater than the last one)
if(toothCurrentCount<(triggerActualTeeth)&¤tStatus.hasSync){currentStatus.hasSync=false;return;}//This occurs when we're at tooth #1, but haven't seen all the other teeth. This indicates a signal issue so we flag lost sync so this will attempt to resync on the next revolution.
triggerFilterTime=0;//This is used to prevent a condition where serious intermitent signals (Eg someone furiously plugging the sensor wire in and out) can leave the filter in an unrecoverable state
}
else
{
//Filter can only be recalc'd for the regular teeth, not the missing one.
//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)
intcrankAngle=(tempToothCurrentCount-1)*triggerToothAngle+configPage2.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.
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
triggerToothAngle=360/configPage2.triggerTeeth;//The number of degrees that passes from tooth to tooth
toothCurrentCount=255;//Default value
triggerFilterTime=(int)(1000000/(MAX_RPM/60*configPage2.triggerTeeth));//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=(int)(1000000/(MAX_RPM/60*2))/2;//Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed)
//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)
intcrankAngle=(tempToothCurrentCount-1)*triggerToothAngle+configPage2.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.
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
MAX_STALL_TIME=(1851UL*triggerToothAngle);//Minimum 90rpm. (1851uS is the time per degree at 90rpm). This decoder uses 90rpm rather than 50rpm due to the potentially very high stall time on a 4 cylinder if we wait that long.
//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)
unsignedlongtempToothLastToothTime;
inttempToothCurrentCount;
//Grab some variables that are used in the trigger code and assign them to temp variables.
//int crankAngle = (tempToothCurrentCount - 1) * triggerToothAngle + configPage2.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.
//crankAngle += ldiv( (micros() - tempToothLastToothTime), timePerDegree).quot; //Estimate the number of degrees travelled since the last tooth
intcrankAngle=(tempToothCurrentCount-1)*triggerToothAngle+configPage2.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.
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
targetGap=(lastGap)>>1;//The target gap is set at half the last tooth gap
if(curGap<targetGap)//If the gap between this tooth and the last one is less than half of the previous gap, then we are very likely at the magical 3rd tooth
return;//We return here so that the tooth times below don't get set (The magical 3rd tooth should not be considered for any calculations that use those times)
//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)
crankAngle=(tempToothCurrentCount-1)*triggerToothAngle+42;//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.
crankAngle=(tempToothCurrentCount-2)*triggerToothAngle+42;//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.
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
triggerFilterTime=curGap>>2;//This only applies during non-sync conditions. If there is sync then triggerFilterTime gets changed again below with a better value.
if(toothCurrentCount==1||toothCurrentCount==3){triggerToothAngle=70;triggerFilterTime=curGap;}//Trigger filter is set to whatever time it took to do 70 degrees (Next trigger is 110 degrees away)
else{triggerToothAngle=110;triggerFilterTime=(curGap*3)>>3;}//Trigger filter is set to (110*3)/8=41.25=41 degrees (Next trigger is 70 degrees away).
revolutionTime=(toothLastToothTime-toothLastMinusOneToothTime);//Note that trigger tooth angle changes between 70 and 110 depending on the last tooth that was seen
//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)
unsignedlongtempToothLastToothTime;
inttempToothCurrentCount;
//Grab some variables that are used in the trigger code and assign them to temp variables.
intcrankAngle=toothAngles[(tempToothCurrentCount-1)]+configPage2.triggerAngle;//Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
if(toothCurrentCount==25){currentStatus.hasSync=false;return;}//Indicates sync has not been achieved (Still waiting for 1 revolution of the crank to take place)
//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)
unsignedlongtempToothLastToothTime;
inttempToothCurrentCount;
//Grab some variables that are used in the trigger code and assign them to temp variables.
if(toothCurrentCount==0){crankAngle=0+configPage2.triggerAngle;}//This is the special case to handle when the 'last tooth' seen was the cam tooth. 0 is the angle at which the crank tooth goes high (Within 360 degrees).
else{crankAngle=toothAngles[(tempToothCurrentCount-1)]+configPage2.triggerAngle;}//Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
if(toothCurrentCount==13){currentStatus.hasSync=false;return;}//Indicates sync has not been achieved (Still waiting for 1 revolution of the crank to take place)
//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)
unsignedlongtempToothLastToothTime;
inttempToothCurrentCount;
//Grab some variables that are used in the trigger code and assign them to temp variables.
noInterrupts();
tempToothCurrentCount=toothCurrentCount;
tempToothLastToothTime=toothLastToothTime;
interrupts();
intcrankAngle;
if(toothCurrentCount==0){crankAngle=146+configPage2.triggerAngle;}//This is the special case to handle when the 'last tooth' seen was the cam tooth. 146 is the angle at which the crank tooth goes high.
else{crankAngle=toothAngles[(tempToothCurrentCount-1)]+configPage2.triggerAngle;}//Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
triggerFilterTime=(unsignedlong)(1000000/(MAX_RPM/60*135UL));//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
//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)
unsignedlongtempToothLastToothTime;
inttempToothCurrentCount;
//Grab some variables that are used in the trigger code and assign them to temp variables.
noInterrupts();
tempToothCurrentCount=toothCurrentCount;
tempToothLastToothTime=toothLastToothTime;
interrupts();
//Handle case where the secondary tooth was the last one seen
intcrankAngle=(tempToothCurrentCount-1)*triggerToothAngle+configPage2.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.
//Estimate the number of degrees travelled since the last tooth}
longelapsedTime=micros()-tempToothLastToothTime;
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
targetGap=(lastGap)>>1;//The target gap is set at half the last tooth gap
if(curGap<targetGap)//If the gap between this tooth and the last one is less than half of the previous gap, then we are very likely at the magical 13th tooth
{
toothCurrentCount=0;
currentStatus.hasSync=true;
return;//We return here so that the tooth times below don't get set (The magical 13th tooth should not be considered for any calculations that use those times)
}
}
toothLastMinusOneToothTime=toothLastToothTime;
toothLastToothTime=curTime;
}
voidtriggerSec_HondaD17(){return;}//The 4+1 signal on the cam is yet to be supported
intgetRPM_HondaD17()
{
returnstdGetRPM();
}
intgetCrankAngle_HondaD17(inttimePerDegree)
{
//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)
unsignedlongtempToothLastToothTime;
inttempToothCurrentCount;
//Grab some variables that are used in the trigger code and assign them to temp variables.
noInterrupts();
tempToothCurrentCount=toothCurrentCount;
tempToothLastToothTime=toothLastToothTime;
interrupts();
//Check if the last tooth seen was the reference tooth 13 (Number 0 here). All others can be calculated, but tooth 3 has a unique angle
intcrankAngle;
if(tempToothCurrentCount==0)
{
crankAngle=11*triggerToothAngle+configPage2.triggerAngle;//if temptoothCurrentCount is 0, the last tooth seen was the 13th one. Based on this, ignore the 13th tooth and use the 12th one as the last reference.
}
else
{
crankAngle=(tempToothCurrentCount-1)*triggerToothAngle+configPage2.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.
}
//Estimate the number of degrees travelled since the last tooth}
longelapsedTime=micros()-tempToothLastToothTime;
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
triggerFilterTime=1500;//10000 rpm, assuming we're triggering on both edges off the crank tooth.
triggerSecFilterTime=(int)(1000000/(MAX_RPM/60*2))/2;//Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed)
}
voidtriggerPri_Miata9905()
{
curTime=micros();
curGap=curTime-toothLastToothTime;
if(curGap<triggerFilterTime){return;}//Debounce check. Pulses should never be less than triggerFilterTime
toothCurrentCount++;
if(toothCurrentCount==1||toothCurrentCount==5)//Trigger is on CHANGE, hence 4 pulses = 1 crank rev
{
toothCurrentCount=1;//Reset the counter
toothOneMinusOneTime=toothOneTime;
toothOneTime=curTime;
currentStatus.hasSync=true;
startRevolutions++;//Counter
//if ((startRevolutions & 15) == 1) { currentStatus.hasSync = false; } //Every 64 revolutions, force a resync with the cam
}
elseif(!currentStatus.hasSync){return;}
addToothLogEntry(curGap);
//Whilst this is an uneven tooth pattern, if the specific angle between the last 2 teeth is specified, 1st deriv prediction can be used
if(toothCurrentCount==1||toothCurrentCount==3){triggerToothAngle=70;triggerFilterTime=curGap;}//Trigger filter is set to whatever time it took to do 70 degrees (Next trigger is 110 degrees away)
else{triggerToothAngle=110;triggerFilterTime=(curGap*3)>>3;}//Trigger filter is set to (110*3)/8=41.25=41 degrees (Next trigger is 70 degrees away).
targetGap=(lastGap)>>1;//The target gap is set at half the last tooth gap
if(curGap<targetGap)//If the gap between this tooth and the last one is less than half of the previous gap, then we are very likely at the extra (3rd) tooth on the cam). This tooth is located at 421 crank degrees (aka 61 degrees) and therefore the last crank tooth seen was number 1 (At 350 degrees)
{
toothCurrentCount=1;
currentStatus.hasSync=true;
}
}
//else { triggerFilterTime = 1500; } //reset filter time (ugly)
return;
}
intgetRPM_Miata9905()
{
//During cranking, RPM is calculated 4 times per revolution, once for each tooth on the crank signal.
//Because these signals aren't even (Alternating 110 and 70 degrees), this needs a special function
if(currentStatus.RPM<configPage2.crankRPM)
{
inttempToothAngle;
noInterrupts();
tempToothAngle=triggerToothAngle;
revolutionTime=(toothLastToothTime-toothLastMinusOneToothTime);//Note that trigger tooth angle changes between 70 and 110 depending on the last tooth that was seen
interrupts();
revolutionTime=revolutionTime*36;
return(tempToothAngle*60000000L)/revolutionTime;
}
else{returnstdGetRPM();}
}
intgetCrankAngle_Miata9905(inttimePerDegree)
{
if(!currentStatus.hasSync){return0;}
//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)
unsignedlongtempToothLastToothTime;
inttempToothCurrentCount;
//Grab some variables that are used in the trigger code and assign them to temp variables.
noInterrupts();
tempToothCurrentCount=toothCurrentCount;
tempToothLastToothTime=toothLastToothTime;
interrupts();
intcrankAngle=toothAngles[(tempToothCurrentCount-1)]+configPage2.triggerAngle;//Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
//Estimate the number of degrees travelled since the last tooth}
longelapsedTime=micros()-tempToothLastToothTime;
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
//Whilst this is an uneven tooth pattern, if the specific angle between the last 2 teeth is specified, 1st deriv prediction can be used
if(toothCurrentCount==1||toothCurrentCount==3){triggerToothAngle=72;triggerFilterTime=curGap;}//Trigger filter is set to whatever time it took to do 72 degrees (Next trigger is 108 degrees away)
else{triggerToothAngle=108;triggerFilterTime=(curGap*3)>>3;}//Trigger filter is set to (108*3)/8=40 degrees (Next trigger is 70 degrees away).
if(curGap2<targetGap)//If the gap between this tooth and the last one is less than half of the previous gap, then we are very likely at the extra (3rd) tooth on the cam). This tooth is located at 421 crank degrees (aka 61 degrees) and therefore the last crank tooth seen was number 1 (At 350 degrees)
revolutionTime=(toothLastToothTime-toothLastMinusOneToothTime);//Note that trigger tooth angle changes between 72 and 108 depending on the last tooth that was seen
//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)
unsignedlongtempToothLastToothTime;
inttempToothCurrentCount;
//Grab some variables that are used in the trigger code and assign them to temp variables.
noInterrupts();
tempToothCurrentCount=toothCurrentCount;
tempToothLastToothTime=toothLastToothTime;
interrupts();
intcrankAngle=toothAngles[(tempToothCurrentCount-1)]+configPage2.triggerAngle;//Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
//Estimate the number of degrees travelled since the last tooth}
longelapsedTime=micros()-tempToothLastToothTime;
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime
triggerToothAngle=(360*configPage2.TrigAngMul)/configPage2.triggerTeeth;//The number of degrees that passes from tooth to tooth multiplied by the additional multiplier
triggerFilterTime=(int)(1000000/(MAX_RPM/60*configPage2.triggerTeeth));//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=(int)(1000000/(MAX_RPM/60*2))/2;//Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed)
secondDerivEnabled=false;
decoderIsSequential=true;
MAX_STALL_TIME=(3333UL*triggerToothAngle);//Minimum 50rpm. (3333uS is the time per degree at 50rpm)
//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)
unsignedlongtempToothLastToothTime;
inttempToothCurrentCount;
//Grab some variables that are used in the trigger code and assign them to temp variables.
noInterrupts();
tempToothCurrentCount=toothCurrentCount;
tempToothLastToothTime=toothLastToothTime;
interrupts();
//Handle case where the secondary tooth was the last one seen
//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.
//Estimate the number of degrees travelled since the last tooth}
longelapsedTime=micros()-tempToothLastToothTime;
if(elapsedTime<SHRT_MAX){crankAngle+=div((int)elapsedTime,timePerDegree).quot;}//This option is much faster, but only available for smaller values of elapsedTime