Chrysler NGC 6 and 8 cylinder decoder (#707)

* Chrysler NGC 6 and 8 cylinder decoder

* Extra comments

* Only recalculate new ignition mode for valid teeth
This commit is contained in:
DeionSi 2021-12-23 04:56:08 +01:00 committed by GitHub
parent 0605b7f822
commit 2cd7ed327b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 171 additions and 20 deletions

View File

@ -192,6 +192,7 @@ void triggerSec_DRZ400();
void triggerSetup_NGC();
void triggerPri_NGC();
void triggerSec_NGC4();
void triggerSec_NGC68();
uint16_t getRPM_NGC();
void triggerSetEndTeeth_NGC();

View File

@ -4177,11 +4177,14 @@ void triggerSec_DRZ400()
triggerSecFilterTime = (toothOneTime - toothOneMinusOneTime) >> 1; //Set filter at 50% of the current crank speed.
}
/** Chrysler NGC - a dedicated decoder for vehicles with 4 cylinder NGC pattern.
36+2-2 trigger wheel running at crank speed
7 tooth trigger wheel running at cam speed
Both wheels use the polarity of the missing teeth to determine position
* @defgroup dec Chrysler NGC 4-cylinder
/** Chrysler NGC - a dedicated decoder for vehicles with 4, 6 and 8 cylinder NGC pattern.
4-cyl: 36+2-2 crank wheel and 7 tooth cam
6-cyl: 36-2+2 crank wheel and 12 tooth cam in 6 groups
8-cyl: 36-2+2 crank wheel and 15 tooth cam in 8 groups
The crank decoder uses the polarity of the missing teeth to determine position
The 4-cyl cam decoder uses the polarity of the missing teeth to determine position
The 6 and 8-cyl cam decoder uses the amount of teeth in the two previous groups of teeth to determine position
* @defgroup dec Chrysler NGC - 4, 6 and 8-cylinder
* @{
*/
@ -4193,20 +4196,49 @@ void triggerSetup_NGC()
//Primary trigger
configPage4.triggerTeeth = 36; //The number of teeth on the wheel incl missing teeth.
triggerToothAngle = 10; //The number of degrees that passes from tooth to tooth
triggerFilterTime = (int)(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
triggerFilterTime = 1000000 / (MAX_RPM/60) / (360/triggerToothAngle); //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
toothCurrentCount = 0;
toothOneTime = 0;
toothOneMinusOneTime = 0;
toothOneMinusOneTime = 0;
toothLastMinusOneToothTime = 0;
toothLastToothRisingTime = 0;
MAX_STALL_TIME = (3333UL * triggerToothAngle * 2 ); //Minimum 50rpm. (3333uS is the time per degree at 50rpm)
//Secondary trigger
triggerSecFilterTime = (1000000 / MAX_RPM * 60 / (360 / 36) / 2); //Two nearest edges are 36 degrees apart. Divide by 2 for cam speed.
if (configPage2.nCylinders == 4) {
triggerSecFilterTime = (1000000 / (MAX_RPM/60) / (360/36) * 2); //Two nearest edges are 36 degrees apart. Multiply by 2 for half cam speed.
} else {
triggerSecFilterTime = (1000000 / (MAX_RPM/60) / (360/21) * 2); //Two nearest edges are 21 degrees apart. Multiply by 2 for half cam speed.
}
secondaryToothCount = 0;
toothSystemCount = 0;
toothLastSecToothRisingTime = 0;
toothLastSecToothTime = 0;
toothLastMinusOneSecToothTime = 0;
//toothAngles is reused to store the cam pattern, only used for 6 and 8 cylinder pattern
if (configPage2.nCylinders == 6) {
toothAngles[0] = 1; // Pos 0 is required to be the same as group 6 for easier math
toothAngles[1] = 3; // Group 1 ...
toothAngles[2] = 1;
toothAngles[3] = 2;
toothAngles[4] = 3;
toothAngles[5] = 2;
toothAngles[6] = 1;
toothAngles[7] = 3; // Pos 7 is required to be the same as group 1 for easier math
}
else if (configPage2.nCylinders == 8) {
toothAngles[0] = 3; // Pos 0 is required to be the same as group 8 for easier math
toothAngles[1] = 1; // Group 1 ...
toothAngles[2] = 1;
toothAngles[3] = 2;
toothAngles[4] = 3;
toothAngles[5] = 2;
toothAngles[6] = 2;
toothAngles[7] = 1;
toothAngles[8] = 3;
toothAngles[9] = 1; // Pos 9 is required to be the same as group 1 for easier math
}
}
void triggerPri_NGC() {
@ -4222,11 +4254,10 @@ void triggerPri_NGC() {
{
toothCurrentCount++;
validTrigger = true;
bool isMissingTooth = false;
if ( toothLastToothTime > 0 && toothLastMinusOneToothTime > 0 ) { //Make sure we haven't enough tooth information to calculate missing tooth length
bool isMissingTooth = false;
//Only check for missing tooth if we expect this one to be it or if we haven't found one yet
if (toothCurrentCount == 17 || toothCurrentCount == 35 || ( currentStatus.hasSync == false && BIT_CHECK(currentStatus.status3, BIT_STATUS3_HALFSYNC) == false) ) {
//If the time between the current tooth and the last is greater than 2x 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
@ -4256,13 +4287,19 @@ void triggerPri_NGC() {
if( (configPage4.sparkMode == IGN_MODE_SEQUENTIAL) || (configPage2.injLayout == INJ_SEQUENTIAL) )
{
// Verify the tooth counters are valid and use this to determine current revolution
if ( (toothCurrentCount == 1 && (secondaryToothCount == 1 || secondaryToothCount == 2) ) || (toothCurrentCount == 19 && secondaryToothCount == 4) )
if (
( configPage2.nCylinders == 4 && ( (toothCurrentCount == 1 && (secondaryToothCount == 1 || secondaryToothCount == 2) ) || (toothCurrentCount == 19 && secondaryToothCount == 4) ) ) ||
( configPage2.nCylinders == 6 && ( (toothCurrentCount == 1 && (toothSystemCount == 1 || toothSystemCount == 2) ) || (toothCurrentCount == 19 && (toothSystemCount == 2 || toothSystemCount == 3) ) ) ) ||
( configPage2.nCylinders == 8 && ( (toothCurrentCount == 1 && (toothSystemCount == 1 || toothSystemCount == 2) ) || (toothCurrentCount == 19 && (toothSystemCount == 3 || toothSystemCount == 4) ) ) ) )
{
revolutionOne = false;
currentStatus.hasSync = true;
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_HALFSYNC); //the engine is fully synced so clear the Half Sync bit
}
else if ( (toothCurrentCount == 1 && secondaryToothCount == 5) || (toothCurrentCount == 19 && secondaryToothCount == 7) )
else if (
( configPage2.nCylinders == 4 && ( (toothCurrentCount == 1 && secondaryToothCount == 5) || (toothCurrentCount == 19 && secondaryToothCount == 7) ) ) ||
( configPage2.nCylinders == 6 && ( (toothCurrentCount == 1 && (toothSystemCount == 4 || toothSystemCount == 5) ) || (toothCurrentCount == 19 && (toothSystemCount == 5 || toothSystemCount == 6) ) ) ) ||
( configPage2.nCylinders == 8 && ( (toothCurrentCount == 1 && (toothSystemCount == 5 || toothSystemCount == 6) ) || (toothCurrentCount == 19 && (toothSystemCount == 7 || toothSystemCount == 8) ) ) ) )
{
revolutionOne = true;
currentStatus.hasSync = true;
@ -4272,7 +4309,8 @@ void triggerPri_NGC() {
else {
if (currentStatus.hasSync == true) { currentStatus.syncLossCounter++; }
currentStatus.hasSync = false;
BIT_SET(currentStatus.status3, BIT_STATUS3_HALFSYNC); } //If there is primary trigger but no secondary we only have half sync.
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
@ -4293,12 +4331,16 @@ void triggerPri_NGC() {
}
}
toothLastMinusOneToothTime = toothLastToothTime;
if (isMissingTooth == true) { // If we have a missing tooth, copy the gap from the previous tooth as that is the correct normal tooth length
toothLastMinusOneToothTime = curTime - (toothLastToothTime - toothLastMinusOneToothTime);
}
else {
toothLastMinusOneToothTime = toothLastToothTime;
}
toothLastToothTime = curTime;
}
//NEW IGNITION MODE
if( (configPage2.perToothIgn == true) && (BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) == false) )
//NEW IGNITION MODE
if( (configPage2.perToothIgn == true) && (BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) == false) )
{
int16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage4.triggerAngle;
crankAngle = ignitionLimits(crankAngle);
@ -4308,6 +4350,7 @@ void triggerPri_NGC() {
checkPerToothTiming(crankAngle, (configPage4.triggerTeeth + toothCurrentCount));
}
else{ checkPerToothTiming(crankAngle, toothCurrentCount); }
}
}
}
@ -4361,6 +4404,63 @@ void triggerSec_NGC4()
}
}
#define secondaryToothLastCount checkSyncToothCount
void triggerSec_NGC68()
{
//Only check the cam wheel for sequential operation
if( configPage4.sparkMode != IGN_MODE_SEQUENTIAL && configPage2.injLayout != INJ_SEQUENTIAL ) {
return;
}
curTime2 = micros();
curGap2 = curTime2 - toothLastSecToothTime;
if ( curGap2 > triggerSecFilterTime )
{
if ( toothLastSecToothTime > 0 && toothLastToothTime > 0 && toothLastMinusOneToothTime > 0 ) //Make sure we have enough tooth information to calculate tooth lengths
{
/* Cam wheel can have a single tooth in a group which can screw up the "targetgap" calculations
Instead use primary wheel tooth gap as comparison as those values are always correct. 2.1 primary teeth are the same duration as one secondary tooth. */
if (curGap2 >= (3 * (toothLastToothTime - toothLastMinusOneToothTime) ) ) // Check if we have a bigger gap, that is missing teeth
{
//toothSystemCount > 0 means we have cam sync and identifies which group we have synced with
//toothAngles is reused to store the cam pattern
if (secondaryToothCount > 0 && secondaryToothLastCount > 0) { // Only check for cam sync if we have actually detected two groups and can get cam sync
if (toothSystemCount > 0 && secondaryToothCount == (unsigned int)toothAngles[toothSystemCount+1]) { // Do a quick check if we already have cam sync
toothSystemCount++;
if (toothSystemCount > configPage2.nCylinders) { toothSystemCount = 1; }
}
else { // Check for a pair of matching groups which tells us which group we are at, this should only happen when we don't have cam sync
toothSystemCount = 0; // We either haven't got cam sync yet or we lost cam sync
for (byte group = 1; group <= configPage2.nCylinders; group++) {
if (secondaryToothCount == (unsigned int)toothAngles[group] && secondaryToothLastCount == (byte)toothAngles[group-1] ) { // Find a matching pattern/position
toothSystemCount = group;
break;
}
}
}
}
secondaryToothLastCount = secondaryToothCount;
//This is the first tooth in this group
secondaryToothCount = 1;
triggerSecFilterTime = 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 if (secondaryToothCount > 0) {
//Normal tooth
secondaryToothCount++;
triggerSecFilterTime = curGap2 >> 2; //Set filter at 25% of the current speed
}
}
toothLastSecToothTime = curTime2;
}
}
uint16_t getRPM_NGC()
{
uint16_t tempRPM = 0;
@ -4421,6 +4521,50 @@ void triggerSetEndTeeth_NGC()
else if(tempIgnition4EndTooth > 70) { tempIgnition4EndTooth = 70; } // These are missing teeth, so set the next one before instead
ignition4EndTooth = tempIgnition4EndTooth;
#if IGN_CHANNELS >= 6
int16_t tempIgnition5EndTooth;
tempIgnition5EndTooth = ( (ignition5EndAngle - configPage4.triggerAngle) / (int16_t)(triggerToothAngle) ) - 1; // Which tooth is the last tooth before ignition
if(tempIgnition5EndTooth < 1) { tempIgnition5EndTooth += (configPage4.triggerTeeth + toothAdder); } // Wrap around teeth below 1
else if(tempIgnition5EndTooth > (configPage4.triggerTeeth + toothAdder)) { tempIgnition5EndTooth -= (configPage4.triggerTeeth + toothAdder); } // Wrap around teeth above max tooth count
if(tempIgnition5EndTooth == 17 || tempIgnition5EndTooth == 18) { tempIgnition5EndTooth = 16; } // These are missing teeth, so set the next one before instead
else if(tempIgnition5EndTooth == 35 || tempIgnition5EndTooth == 36) { tempIgnition5EndTooth = 34; } // These are missing teeth, so set the next one before instead
else if(tempIgnition5EndTooth == 53 || tempIgnition5EndTooth == 54) { tempIgnition5EndTooth = 52; } // These are missing teeth, so set the next one before instead
else if(tempIgnition5EndTooth > 70) { tempIgnition5EndTooth = 70; } // These are missing teeth, so set the next one before instead
ignition5EndTooth = tempIgnition5EndTooth;
int16_t tempIgnition6EndTooth;
tempIgnition6EndTooth = ( (ignition6EndAngle - configPage4.triggerAngle) / (int16_t)(triggerToothAngle) ) - 1; // Which tooth is the last tooth before ignition
if(tempIgnition6EndTooth < 1) { tempIgnition6EndTooth += (configPage4.triggerTeeth + toothAdder); } // Wrap around teeth below 1
else if(tempIgnition6EndTooth > (configPage4.triggerTeeth + toothAdder)) { tempIgnition6EndTooth -= (configPage4.triggerTeeth + toothAdder); } // Wrap around teeth above max tooth count
if(tempIgnition6EndTooth == 17 || tempIgnition6EndTooth == 18) { tempIgnition6EndTooth = 16; } // These are missing teeth, so set the next one before instead
else if(tempIgnition6EndTooth == 35 || tempIgnition6EndTooth == 36) { tempIgnition6EndTooth = 34; } // These are missing teeth, so set the next one before instead
else if(tempIgnition6EndTooth == 53 || tempIgnition6EndTooth == 54) { tempIgnition6EndTooth = 52; } // These are missing teeth, so set the next one before instead
else if(tempIgnition6EndTooth > 70) { tempIgnition6EndTooth = 70; } // These are missing teeth, so set the next one before instead
ignition6EndTooth = tempIgnition6EndTooth;
#endif
#if IGN_CHANNELS >= 8
int16_t tempIgnition7EndTooth;
tempIgnition7EndTooth = ( (ignition7EndAngle - configPage4.triggerAngle) / (int16_t)(triggerToothAngle) ) - 1; // Which tooth is the last tooth before ignition
if(tempIgnition7EndTooth < 1) { tempIgnition7EndTooth += (configPage4.triggerTeeth + toothAdder); } // Wrap around teeth below 1
else if(tempIgnition7EndTooth > (configPage4.triggerTeeth + toothAdder)) { tempIgnition7EndTooth -= (configPage4.triggerTeeth + toothAdder); } // Wrap around teeth above max tooth count
if(tempIgnition7EndTooth == 17 || tempIgnition7EndTooth == 18) { tempIgnition7EndTooth = 16; } // These are missing teeth, so set the next one before instead
else if(tempIgnition7EndTooth == 35 || tempIgnition7EndTooth == 36) { tempIgnition7EndTooth = 34; } // These are missing teeth, so set the next one before instead
else if(tempIgnition7EndTooth == 53 || tempIgnition7EndTooth == 54) { tempIgnition7EndTooth = 52; } // These are missing teeth, so set the next one before instead
else if(tempIgnition7EndTooth > 70) { tempIgnition7EndTooth = 70; } // These are missing teeth, so set the next one before instead
ignition7EndTooth = tempIgnition7EndTooth;
int16_t tempIgnition8EndTooth;
tempIgnition8EndTooth = ( (ignition8EndAngle - configPage4.triggerAngle) / (int16_t)(triggerToothAngle) ) - 1; // Which tooth is the last tooth before ignition
if(tempIgnition8EndTooth < 1) { tempIgnition8EndTooth += (configPage4.triggerTeeth + toothAdder); } // Wrap around teeth below 1
else if(tempIgnition8EndTooth > (configPage4.triggerTeeth + toothAdder)) { tempIgnition8EndTooth -= (configPage4.triggerTeeth + toothAdder); } // Wrap around teeth above max tooth count
if(tempIgnition8EndTooth == 17 || tempIgnition8EndTooth == 18) { tempIgnition8EndTooth = 16; } // These are missing teeth, so set the next one before instead
else if(tempIgnition8EndTooth == 35 || tempIgnition8EndTooth == 36) { tempIgnition8EndTooth = 34; } // These are missing teeth, so set the next one before instead
else if(tempIgnition8EndTooth == 53 || tempIgnition8EndTooth == 54) { tempIgnition8EndTooth = 52; } // These are missing teeth, so set the next one before instead
else if(tempIgnition8EndTooth > 70) { tempIgnition8EndTooth = 70; } // These are missing teeth, so set the next one before instead
ignition8EndTooth = tempIgnition8EndTooth;
#endif
lastToothCalcAdvance = currentStatus.advance;
}
/** @} */

View File

@ -3235,17 +3235,23 @@ void initialiseTriggers()
break;
case DECODER_NGC:
//Chrysler NGC 4 cylinder
//Chrysler NGC - 4, 6 and 8 cylinder
triggerSetup_NGC();
triggerHandler = triggerPri_NGC;
triggerSecondaryHandler = triggerSec_NGC4;
decoderHasSecondary = true;
getRPM = getRPM_NGC;
getCrankAngle = getCrankAngle_missingTooth;
triggerSetEndTeeth = triggerSetEndTeeth_NGC;
primaryTriggerEdge = CHANGE;
secondaryTriggerEdge = CHANGE;
if (configPage2.nCylinders == 4) {
triggerSecondaryHandler = triggerSec_NGC4;
secondaryTriggerEdge = CHANGE;
}
else {
triggerSecondaryHandler = triggerSec_NGC68;
secondaryTriggerEdge = FALLING;
}
attachInterrupt(triggerInterrupt, triggerHandler, primaryTriggerEdge);
attachInterrupt(triggerInterrupt2, triggerSecondaryHandler, secondaryTriggerEdge);