diff --git a/reference/speeduino.ini b/reference/speeduino.ini index 689a9035..f50922c8 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -189,6 +189,7 @@ #define trigger_VMAX = 23 #define trigger_renix = 24 #define trigger_Rover = 25 + #define trigger_K6A = 26 [Constants] @@ -512,7 +513,7 @@ 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", "Rover MEMS", "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", "K6A", "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" @@ -2941,7 +2942,7 @@ 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 || TrigPattern == 25 } ;Missing tooth, dual wheel and Miata 9905, weber-marelli, ST170, DRZ400 Renix, Rover MEMS + 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, K6A field = "Level for 1st phase", PollLevelPol, { (TrigPattern == 0 && TrigSpeed == 0 && trigPatternSec == 2) } field = "Missing Tooth Secondary type", trigPatternSec, { (TrigPattern == 0&& TrigSpeed == 0) || TrigPattern == 25 } field = "Trigger Filter", TrigFilter, { TrigPattern != 13 } @@ -2967,7 +2968,7 @@ menuDialog = main field = "Cranking advance Angle", CrankAng field = "Spark Outputs triggers", IgInv panel = lockSparkSettings - panel = newIgnitionMode, { 1 }, {TrigPattern == 0 || TrigPattern == 1 || TrigPattern == 2 || TrigPattern == 3 || TrigPattern == 4 || TrigPattern == 9 || TrigPattern == 12 || TrigPattern == 13 || TrigPattern == 16 || TrigPattern == 18 || TrigPattern == 19 || TrigPattern == 22 || TrigPattern == 24} ;Only works for missing tooth, distributor, dual wheel, GM 7X, 4g63, Miata 99-05, nissan 360, Subaru 6/7, 420a, weber-marelli, NGC Renix, + panel = newIgnitionMode, { 1 }, {TrigPattern == 0 || TrigPattern == 1 || TrigPattern == 2 || TrigPattern == 3 || TrigPattern == 4 || TrigPattern == 9 || TrigPattern == 12 || TrigPattern == 13 || TrigPattern == 16 || TrigPattern == 18 || TrigPattern == 19 || TrigPattern == 22 || TrigPattern == 24 || TrigPattern == 25 || TrigPattern == 26 } ;Only works for missing tooth, distributor, dual wheel, GM 7X, 4g63, Miata 99-05, nissan 360, Subaru 6/7, 420a, weber-marelli, NGC Renix, K6A dialog = dwellSettings, "Dwell Settings", 4 topicHelp = "http://wiki.speeduino.com/en/configuration/Dwell" diff --git a/speeduino/decoders.cpp b/speeduino/decoders.cpp index e272d409..019ed2d3 100644 --- a/speeduino/decoders.cpp +++ b/speeduino/decoders.cpp @@ -5403,4 +5403,405 @@ void triggerSetEndTeeth_RoverMEMS() ignition4EndTooth = tempIgnitionEndTooth[4]; } /** @} */ + +/** Suzuki K6A 3 cylinder engine + +* (See: https://www.msextra.com/forums/viewtopic.php?t=74614) +* @defgroup Suzuki_K6A Suzuki K6A +* @{ +*/ +void triggerSetup_SuzukiK6A(void) +{ + triggerToothAngle = 90; //The number of degrees that passes from tooth to tooth (primary) - set to a value, needs to be set per tooth + toothCurrentCount = 99; //Fake tooth count represents no sync + + configPage4.TrigSpeed = CAM_SPEED; + triggerActualTeeth = 7; + toothCurrentCount = 1; + curGap = curGap2 = curGap3 = 0; + + if(initialisationComplete == false) { toothLastToothTime = micros(); } //Set a startup value here to avoid filter errors when starting. This MUST have the initial check to prevent the fuel pump just staying on all the time + else { toothLastToothTime = 0; } + toothLastMinusOneToothTime = 0; + + // based on data in msextra page linked to above we can deduce, + // gap between rising and falling edge of a normal 70 degree tooth is 48 degrees, this means the gap is 70 degrees - 48 degrees = 22 degrees. + // assume this is constant for all similar sized gaps and teeth + // sync tooth is 35 degrees - eyeball looks like the tooth is 50% tooth and 50% gap so guess its 17 degrees and 18 degrees. + + // coded every tooth here in case you want to try "change" setting on the trigger setup (this is defineed in init.ino and what i've set it to, otherwise you need code to selet rising or falling in init.ino (steal it from another trigger)). + // If you don't want change then drop the 'falling' edges listed below and half the number of edges + reduce the triggerActualTeeth + // nb as you can edit the trigger offset using rising or falling edge setup below is irrelevant as you can adjust via the trigger ofset to cover the difference. + + // not using toothAngles[0] as i'm hoping it makes logic easier + + toothAngles[1] = 0; // 0 TDC cylinder 1, + toothAngles[2] = 170; // 170 - end of cylinder 1, start of cylinder 3, trigger ignition for cylinder 3 on this tooth + toothAngles[3] = 240; // 70 TDC cylinder 3 + toothAngles[4] = 410; // 170 - end of cylinder 3, start of cylinder2, trigger ignition for cylinder 2 on this tooth + toothAngles[5] = 480; // 70 TDC cylinder 2 + toothAngles[6] = 515; // 35 Additional sync tooth + toothAngles[7] = 650; // 135 end of cylinder 2, start of cylinder 1, trigger ignition for cylinder 1 on this tooth + toothAngles[8] = 720; // 70 - gap to rotation to TDC1. array item 1 and 8 are the same, code never gets here its for reference only + + + MAX_STALL_TIME = (3333UL * triggerToothAngle); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) + triggerFilterTime = 1500; //10000 rpm, assuming we're triggering on both edges off the crank tooth. + triggerSecFilterTime = 0; //Need to figure out something better for this + BIT_CLEAR(decoderState, BIT_DECODER_HAS_FIXED_CRANKING); + BIT_CLEAR(decoderState, BIT_DECODER_TOOTH_ANG_CORRECT); + BIT_CLEAR(decoderState, BIT_DECODER_HAS_SECONDARY); // never sure if we need to set this in this type of trigger + BIT_CLEAR(currentStatus.status3, BIT_STATUS3_HALFSYNC); // we can never have half sync - its either full or none. + BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); + BIT_SET(decoderState, BIT_DECODER_IS_SEQUENTIAL); +} + +void triggerPri_SuzukiK6A(void) +{ + curTime = micros(); + curGap = curTime - toothLastToothTime; + if ( (curGap >= triggerFilterTime) || (currentStatus.startRevolutions == 0) ) + { + toothCurrentCount++; + BIT_SET(decoderState, BIT_DECODER_VALID_TRIGGER); //Flag this pulse as being a valid trigger (ie that it passed filters) + + toothLastMinusOneToothTime = toothLastToothTime; + toothLastToothTime = curTime; + + + // now to figure out if its a normal tooth or the extra sync tooth + // pattern is normally small tooth, big tooth, small tooth, big tooth. The extra tooth breaks the pattern go it goes, big tooth (curGap3), small tooth(curGap2), small tooth(curGap) + // reuse curGap2 and curGap3 (from secondary and Tertiary decoders) to store previous tooth sizes as not needed in this decoder. + + if ( ( curGap <= curGap2 ) && + ( curGap2 <= curGap3 ) ) + { + // cur Gap is smaller than last gap & last gap is smaller than gap before that - means we must be on sync tooth + toothCurrentCount = 6; // set tooth counter to correct tooth + currentStatus.hasSync = true; + } + + curGap3 = curGap2; // update values for next time we're in the loop + curGap2 = curGap; + + + if( (toothCurrentCount == (triggerActualTeeth + 1)) && currentStatus.hasSync == true ) + { + // seen enough teeth to have a revolution of the crank + toothCurrentCount = 1; //Reset the counter + toothOneMinusOneTime = toothOneTime; + toothOneTime = curTime; + currentStatus.startRevolutions = currentStatus.startRevolutions + 2; // increment for 2 revs as we do 720 degrees on the the crank + } + else if (toothCurrentCount > (triggerActualTeeth + 1)) + { + // Lost sync + currentStatus.hasSync = false; + currentStatus.syncLossCounter++; + triggerFilterTime = 0; + toothCurrentCount=0; + } + + // check gaps match with tooth to check we have sync + // so if we *think* we've seen tooth 3 whos gap should be smaller than the previous tooth & it isn't, + // then we've lost sync + switch (toothCurrentCount) + { + case 1: + case 3: + case 5: + case 6: + // current tooth gap is bigger than previous tooth gap = syncloss + // eg tooth 3 should be smaller than tooth 2 gap, if its not then we've lost sync and the tooth 3 we've just seen isn't really tooth 3 + if (curGap > curGap2) + { + currentStatus.hasSync = false; + currentStatus.syncLossCounter++; + triggerFilterTime = 0; + toothCurrentCount=2; + } + break; + + case 2: + case 4: + case 7: + // current tooth gap is smaller than the previous tooth gap = syncloss + // eg tooth 2 should be bigger than tooth 1, if its not then we've got syncloss + if (curGap < curGap2) + { + currentStatus.hasSync = false; + currentStatus.syncLossCounter++; + triggerFilterTime = 0; + toothCurrentCount=1; + } + break; + } + + // Setup data to allow other areas of the system to work due to odd sized teeth - this could be merged with sync checking above, left seperate to keep code clearer as its doing only one function at once + // % of filter are not based on previous tooth size but expected next tooth size + // triggerToothAngle is the size of the prevous tooth not the future tooth + if (currentStatus.hasSync == true ) + { + switch (toothCurrentCount) // Set tooth angle based on previous gap and triggerFilterTime based on prevoius gap and next gap + { + case 2: + case 4: + // equivalent of tooth 1 except we've not done rotation code yet so its 8 + // 170 degree tooth, next tooth is 70 + switch (configPage4.triggerFilter) + { + case 1: // 25 % 17 degrees + triggerFilterTime = curGap>>3; + break; + case 2: // 50 % 35 degrees + triggerFilterTime = (curGap>>3) + (curGap>>4); + break; + case 3: // 75 % 52 degrees + triggerFilterTime = (curGap>>2) + (curGap>>4); + break; + default: + triggerFilterTime = 0; + break; + } + break; + + case 5: + // 70 degrees, next tooth is 35 + switch (configPage4.triggerFilter) + { + case 1: // 25 % 8 degrees + triggerFilterTime = curGap>>3; + break; + case 2: // 50 % 17 degrees + triggerFilterTime = curGap>>2; + break; + case 3: // 75 % 25 degrees + triggerFilterTime = (curGap>>2) + (curGap>>3); + break; + default: + triggerFilterTime = 0; + break; + } + break; + + case 6: + // sync tooth, next tooth is 135 + switch (configPage4.triggerFilter) + { + case 1: // 25 % 33 degrees + triggerFilterTime = curGap; + break; + case 2: // 50 % 67 degrees + triggerFilterTime = curGap * 2; + break; + case 3: // 75 % 100 degrees + triggerFilterTime = curGap * 3; + break; + default: + triggerFilterTime = 0; + break; + } + break; + + case 7: + // 135 degre tooth, next tooth is 70 + switch (configPage4.triggerFilter) + { + case 1: // 25 % 17 degrees + triggerFilterTime = curGap>>3; + break; + case 2: // 50 % 35 degrees + triggerFilterTime = curGap>>2; + break; + case 3: // 75 % 52 degrees + triggerFilterTime = (curGap>>2) + (curGap>>3); + break; + default: + triggerFilterTime = 0; + break; + } + break; + + case 1: + case 3: + // 70 degree tooth, next tooth is 170 + switch (configPage4.triggerFilter) + { + case 1: // 25 % 42 degrees + triggerFilterTime = (curGap>>1) + (curGap>>3); + break; + case 2: // 50 % 85 degrees + triggerFilterTime = curGap + (curGap>>2); + break; + case 3: // 75 % 127 degrees + triggerFilterTime = curGap + (curGap>>1) + (curGap>>2); + break; + default: + triggerFilterTime = 0; + break; + } + break; + + } + + //NEW IGNITION MODE + if( (configPage2.perToothIgn == true) ) + { + int16_t crankAngle = toothAngles[toothCurrentCount] + configPage4.triggerAngle; + crankAngle = ignitionLimits(crankAngle); + checkPerToothTiming(crankAngle, toothCurrentCount); + } + + } // has sync + + } //Trigger filter + +} + +void triggerSec_SuzukiK6A(void) +{ + return; +} + +uint16_t getRPM_SuzukiK6A(void) +{ + //Cranking code needs working out. + + uint16_t tempRPM; + + tempRPM = stdGetRPM(720); + MAX_STALL_TIME = revolutionTime << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this + if(MAX_STALL_TIME < 366667UL) { MAX_STALL_TIME = 366667UL; } //Check for 50rpm minimum + + return tempRPM; +} + +int getCrankAngle_SuzukiK6A(void) +{ + int crankAngle = 0; + + //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; + //Grab some variables that are used in the trigger code and assign them to temp variables. + noInterrupts(); + tempToothCurrentCount = toothCurrentCount; + tempToothLastToothTime = toothLastToothTime; + lastCrankAngleCalc = micros(); //micros() is no longer interrupt safe + interrupts(); + + crankAngle = toothAngles[(tempToothCurrentCount)] + configPage4.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} + elapsedTime = (lastCrankAngleCalc - tempToothLastToothTime); + + switch(toothCurrentCount) + { + case 2: + case 4: + // equivalent of tooth 1 except we've not done rotation code yet so its 8 + // 170 degree tooth, next tooth is 70 + triggerToothAngle = 170; + break; + + case 5: + // 70 degrees, next tooth is 35 + triggerToothAngle = 70; + break; + + case 6: + // sync tooth, next tooth is 135 + triggerToothAngle = 35; + break; + + case 7: + // 135 degre tooth, next tooth is 70 + triggerToothAngle = 135; + break; + + case 1: + case 3: + // 70 degree tooth, next tooth is 170 + triggerToothAngle = 70; + break; + } + crankAngle += timeToAngle(elapsedTime, CRANKMATH_METHOD_INTERVAL_TOOTH); + if (crankAngle >= 720) { crankAngle -= 720; } +// if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } not needed, crank angle max gets max from injection or ignition, we have to be over 720 degrees so can ignore + if (crankAngle < 0) { crankAngle += 720; } + + return crankAngle; +} + +// Assumes no advance greater than 48 degrees. Trigers on the tooth before the ignition event +void triggerSetEndTeeth_SuzukiK6A(void) +{ + byte nCount, bExit; + + //Temp variables are used here to avoid potential issues if a trigger interrupt occurs part way through this function + int16_t tempIgnitionEndTooth; + + tempIgnitionEndTooth = (ignition1EndAngle - configPage4.triggerAngle); + + tempIgnitionEndTooth = ignitionLimits(tempIgnitionEndTooth); + + for (nCount = 1, bExit = false; nCount < 8 && bExit == false; nCount++) + { + if(tempIgnitionEndTooth <= toothAngles[nCount]) + { + // The tooth we want is the tooth prior to this one. + tempIgnitionEndTooth = nCount-1; + if (tempIgnitionEndTooth <= 0) + { tempIgnitionEndTooth = 7; } + bExit = true; + } + } + if(nCount == 8) + { tempIgnitionEndTooth = 7; } // didn't find a match, use tooth 7 as it must be greater than 7 but less than 1. + ignition1EndTooth = tempIgnitionEndTooth; + + //-------------------- + + tempIgnitionEndTooth = (ignition2EndAngle - configPage4.triggerAngle); + tempIgnitionEndTooth = ignitionLimits(tempIgnitionEndTooth); + + for (nCount = 1, bExit = false; nCount < 8 && bExit == false; nCount++) + { + if(tempIgnitionEndTooth <= toothAngles[nCount]) + { + // The tooth we want is the tooth prior to this one. + tempIgnitionEndTooth = nCount-1; + if (tempIgnitionEndTooth <= 0) + { tempIgnitionEndTooth = 7; } + bExit = true; // force exit from loop + } + } + if(nCount == 8) + { tempIgnitionEndTooth = 7; } // didn't find a match, use tooth 7 as it must be greater than 7 but less than 1. + ignition2EndTooth = tempIgnitionEndTooth; + + //-------------- + + tempIgnitionEndTooth = (ignition3EndAngle - configPage4.triggerAngle); + tempIgnitionEndTooth = ignitionLimits(tempIgnitionEndTooth); + + for (nCount = 1, bExit = false; nCount < 8 && bExit == false; nCount++) + { + if(tempIgnitionEndTooth <= toothAngles[nCount]) + { + // The tooth we want is the tooth prior to this one. + tempIgnitionEndTooth = nCount-1; + if (tempIgnitionEndTooth <= 0) + { tempIgnitionEndTooth = 7; } + bExit = true; // force exit from loop + } + } + if(nCount == 8) + { tempIgnitionEndTooth = 7; } // didn't find a match, use tooth 7 as it must be greater than 7 but less than 1. + ignition3EndTooth = tempIgnitionEndTooth; + + + lastToothCalcAdvance = currentStatus.advance; +} /** @} */ + diff --git a/speeduino/decoders.h b/speeduino/decoders.h index 26c6bed5..aaff22e4 100644 --- a/speeduino/decoders.h +++ b/speeduino/decoders.h @@ -39,6 +39,7 @@ #define DECODER_VMAX 23 #define DECODER_RENIX 24 #define DECODER_ROVERMEMS 25 +#define DECODER_SUZUKI_K6A 26 #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 @@ -241,6 +242,15 @@ uint16_t getRPM_Vmax(void); int getCrankAngle_Vmax(void); void triggerSetEndTeeth_Vmax(void); +void triggerSetup_SuzukiK6A(void); +void triggerPri_SuzukiK6A(void); +void triggerSec_SuzukiK6A(void); +uint16_t getRPM_SuzukiK6A(void); +int getCrankAngle_SuzukiK6A(void); +void triggerSetEndTeeth_SuzukiK6A(void); + + + extern void (*triggerHandler)(void); //Pointer for the trigger function (Gets pointed to the relevant decoder) extern void (*triggerSecondaryHandler)(void); //Pointer for the secondary trigger function (Gets pointed to the relevant decoder) extern void (*triggerTertiaryHandler)(void); //Pointer for the tertiary trigger function (Gets pointed to the relevant decoder) diff --git a/speeduino/init.cpp b/speeduino/init.cpp index 15343bac..5bcd493e 100644 --- a/speeduino/init.cpp +++ b/speeduino/init.cpp @@ -3670,6 +3670,20 @@ void initialiseTriggers(void) attachInterrupt(triggerInterrupt2, triggerSecondaryHandler, secondaryTriggerEdge); break; + case DECODER_SUZUKI_K6A: + triggerSetup_SuzukiK6A(); + triggerHandler = triggerPri_SuzukiK6A; // only primary, no secondary, trigger pattern is over 720 degrees + getRPM = getRPM_SuzukiK6A; + getCrankAngle = getCrankAngle_SuzukiK6A; + triggerSetEndTeeth = triggerSetEndTeeth_SuzukiK6A; + + + if(configPage4.TrigEdge == 0) { primaryTriggerEdge = RISING; } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) + else { primaryTriggerEdge = FALLING; } + + attachInterrupt(triggerInterrupt, triggerHandler, primaryTriggerEdge); + break; + default: triggerHandler = triggerPri_missingTooth;