From 23c3c8b6bfbc1bf5e5deaa0109ea2d14887e5d9a Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Mon, 30 Jan 2017 17:10:17 +1100 Subject: [PATCH] Formatting cleanup --- decoders.ino | 486 +++++++++++++++++++++++++------------------------- maths.h | 3 +- scheduler.ino | 118 ++++++------ speeduino.ino | 386 +++++++++++++++++++-------------------- 4 files changed, 498 insertions(+), 495 deletions(-) diff --git a/decoders.ino b/decoders.ino index 3bc07d6..89f3c78 100644 --- a/decoders.ino +++ b/decoders.ino @@ -17,7 +17,7 @@ Each decoder must have the following 4 functions (Where xxxx is the decoder name And each decoder must utlise at least the following variables: toothLastToothTime - The time (In uS) that the last primary tooth was 'seen' -* +* */ #include "decoders.h" @@ -27,12 +27,12 @@ static inline void addToothLogEntry(unsigned long toothTime) //High speed tooth logging history toothHistory[toothHistoryIndex] = toothTime; if(toothHistoryIndex == (TOOTH_LOG_BUFFER-1)) - { + { if (toothLogRead) { - toothHistoryIndex = 0; - BIT_CLEAR(currentStatus.squirt, BIT_SQUIRT_TOOTHLOG1READY); - toothLogRead = false; //The tooth log ready bit is cleared to ensure that we only get a set of concurrent values. + toothHistoryIndex = 0; + BIT_CLEAR(currentStatus.squirt, BIT_SQUIRT_TOOTHLOG1READY); + toothLogRead = false; //The tooth log ready bit is cleared to ensure that we only get a set of concurrent values. } } else @@ -55,7 +55,7 @@ static inline int stdGetRPM() } /* - * Sets the new filter time based on the current settings. + * Sets the new filter time based on the current settings. * This ONLY works for even spaced decoders */ static inline void setFilter(unsigned long curGap) @@ -63,7 +63,7 @@ static inline void setFilter(unsigned long curGap) if(configPage2.triggerFilter == 1) { triggerFilterTime = curGap >> 2; } //Lite filter level is 25% of previous gap else if(configPage2.triggerFilter == 2) { triggerFilterTime = curGap >> 1; } //Medium filter level is 50% of previous gap else if (configPage2.triggerFilter == 3) { triggerFilterTime = (curGap * 3) >> 2; } //Aggressive filter level is 75% of previous gap - else { triggerFilterTime = 0; } //trigger filter is turned off. + else { triggerFilterTime = 0; } //trigger filter is turned off. } /* @@ -76,11 +76,11 @@ static inline int crankingGetRPM(byte totalTeeth) { noInterrupts(); revolutionTime = (toothLastToothTime - toothLastMinusOneToothTime) * totalTeeth; - interrupts(); + interrupts(); return (US_IN_MINUTE / revolutionTime); } -/* +/* Name: Missing tooth wheel Desc: A multi-tooth wheel with one of more 'missing' teeth. The first tooth after the missing one is considered number 1 and isthe basis for the trigger angle Note: This does not currently support dual wheel (ie missing tooth + single tooth on cam) @@ -93,7 +93,7 @@ void triggerSetup_missingTooth() 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 secondDerivEnabled = false; decoderIsSequential = false; - checkSyncToothCount = (configPage2.triggerTeeth) >> 1; //50% of the total teeth. + checkSyncToothCount = (configPage2.triggerTeeth) >> 1; //50% of the total teeth. MAX_STALL_TIME = (3333UL * triggerToothAngle * (configPage2.triggerMissingTeeth + 1)); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) } @@ -106,7 +106,7 @@ void triggerPri_missingTooth() curGap = curTime - toothLastToothTime; 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) toothCurrentCount++; //Increment the tooth counter - + addToothLogEntry(curGap); //if(toothCurrentCount > checkSyncToothCount || !currentStatus.hasSync) @@ -115,16 +115,16 @@ void triggerPri_missingTooth() //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 ( curGap > targetGap || toothCurrentCount > triggerActualTeeth) - { - if(toothCurrentCount < (triggerActualTeeth) && currentStatus.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. - toothCurrentCount = 1; + { + if(toothCurrentCount < (triggerActualTeeth) && currentStatus.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. + toothCurrentCount = 1; revolutionOne = !revolutionOne; //Flip sequential revolution tracker toothOneMinusOneTime = toothOneTime; toothOneTime = curTime; currentStatus.hasSync = true; - currentStatus.startRevolutions++; //Counter + currentStatus.startRevolutions++; //Counter 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 @@ -133,13 +133,13 @@ void triggerPri_missingTooth() setFilter(curGap); } } - + toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; } void triggerSec_missingTooth() -{ +{ //TODO: This should really have filtering enabled on the secondary input. revolutionOne = 1; } @@ -156,32 +156,33 @@ int getCrankAngle_missingTooth(int timePerDegree) unsigned long tempToothLastToothTime; int tempToothCurrentCount; bool tempRevolutionOne; - //Grab some variables that are used in the trigger code and assign them to temp variables. + //Grab some variables that are used in the trigger code and assign them to temp variables. noInterrupts(); tempToothCurrentCount = toothCurrentCount; tempToothLastToothTime = toothLastToothTime; tempRevolutionOne = revolutionOne; interrupts(); - + 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. //Estimate the number of degrees travelled since the last tooth} - long elapsedTime = micros() - tempToothLastToothTime; + long elapsedTime = (micros() - tempToothLastToothTime); + //crankAngle += DIV_ROUND_CLOSEST(elapsedTime, timePerDegree); if(elapsedTime < SHRT_MAX ) { crankAngle += div((int)elapsedTime, timePerDegree).quot; } //This option is much faster, but only available for smaller values of elapsedTime else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } //Sequential check (simply sets whether we're on the first or 2nd revoltuion of the cycle) if (tempRevolutionOne) { crankAngle += 360; } - if (crankAngle >= 720) { crankAngle -= 720; } + if (crankAngle >= 720) { crankAngle -= 720; } else if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += CRANK_ANGLE_MAX; } - + return crankAngle; } -/* +/* Name: Dual wheel -Desc: 2 wheels located either both on the crank or with the primary on the crank and the secondary on the cam. +Desc: 2 wheels located either both on the crank or with the primary on the crank and the secondary on the cam. Note: There can be no missing teeth on the primary wheel */ void triggerSetup_DualWheel() @@ -197,7 +198,7 @@ void triggerSetup_DualWheel() void triggerPri_DualWheel() -{ +{ curTime = micros(); curGap = curTime - toothLastToothTime; if ( curGap < triggerFilterTime ) { return; } //Pulses should never be less than triggerFilterTime, so if they are it means a false trigger. @@ -206,11 +207,11 @@ void triggerPri_DualWheel() toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; - + if ( !currentStatus.hasSync ) { return; } - + if ( toothCurrentCount == 1 || toothCurrentCount > configPage2.triggerTeeth ) - { + { toothCurrentCount = 1; revolutionOne = !revolutionOne; //Flip sequential revolution tracker toothOneMinusOneTime = toothOneTime; @@ -219,30 +220,30 @@ void triggerPri_DualWheel() } setFilter(curGap); //Recalc the new filter value - + } void triggerSec_DualWheel() -{ +{ curTime2 = micros(); curGap2 = curTime2 - toothLastSecToothTime; - if ( curGap2 < triggerSecFilterTime ) { return; } + if ( curGap2 < triggerSecFilterTime ) { return; } toothLastSecToothTime = curTime2; triggerSecFilterTime = curGap2 >> 2; //Set filter at 25% of the current speed toothCurrentCount = configPage2.triggerTeeth; - + if(!currentStatus.hasSync) { toothLastToothTime = micros(); toothLastMinusOneToothTime = (toothOneTime - 6000000) / configPage2.triggerTeeth; //Fixes RPM at 10rpm until a full revolution has taken place - + currentStatus.hasSync = true; } revolutionOne = 1; //Sequential revolution reset -} +} int getRPM_DualWheel() { @@ -257,16 +258,16 @@ int getCrankAngle_DualWheel(int timePerDegree) unsigned long tempToothLastToothTime; int tempToothCurrentCount; bool tempRevolutionOne; - //Grab some variables that are used in the trigger code and assign them to temp variables. + //Grab some variables that are used in the trigger code and assign them to temp variables. noInterrupts(); tempToothCurrentCount = toothCurrentCount; tempToothLastToothTime = toothLastToothTime; tempRevolutionOne = revolutionOne; interrupts(); - + //Handle case where the secondary tooth was the last one seen if(tempToothCurrentCount == 0) { tempToothCurrentCount = configPage2.triggerTeeth; } - + 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. //Estimate the number of degrees travelled since the last tooth} long elapsedTime = micros() - tempToothLastToothTime; @@ -275,11 +276,11 @@ int getCrankAngle_DualWheel(int timePerDegree) //Sequential check (simply sets whether we're on the first or 2nd revoltuion of the cycle) if (tempRevolutionOne) { crankAngle += 360; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += CRANK_ANGLE_MAX; } - + return crankAngle; } @@ -299,7 +300,7 @@ void triggerSetup_BasicDistributor() triggerFilterTime = triggerFilterTime / 2; //Safety margin secondDerivEnabled = false; decoderIsSequential = false; - 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. + 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. } void triggerPri_BasicDistributor() @@ -307,20 +308,20 @@ void triggerPri_BasicDistributor() curTime = micros(); curGap = curTime - toothLastToothTime; if ( curGap < triggerFilterTime ) { return; } //Noise rejection check. Pulses should never be less than triggerFilterTime - + if(toothCurrentCount == triggerActualTeeth ) //Check if we're back to the beginning of a revolution - { + { toothCurrentCount = 1; //Reset the counter toothOneMinusOneTime = toothOneTime; toothOneTime = curTime; currentStatus.hasSync = true; - currentStatus.startRevolutions++; //Counter + currentStatus.startRevolutions++; //Counter } - else - { - toothCurrentCount++; //Increment the tooth counter + else + { + toothCurrentCount++; //Increment the tooth counter } - + setFilter(curGap); //Recalc the new filter value addToothLogEntry(curGap); @@ -331,7 +332,7 @@ void triggerPri_BasicDistributor() endCoil3Charge(); endCoil4Charge(); } - + toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; } @@ -339,9 +340,9 @@ void triggerSec_BasicDistributor() { return; } //Not required int getRPM_BasicDistributor() { uint16_t tempRPM; - if(currentStatus.RPM < configPage2.crankRPM) + if(currentStatus.RPM < configPage2.crankRPM) { tempRPM = crankingGetRPM(triggerActualTeeth); } - else + else { tempRPM = stdGetRPM(); } return tempRPM << 1; //Multiply RPM by 2 due to tracking over 720 degrees now rather than 360 @@ -351,26 +352,26 @@ int getCrankAngle_BasicDistributor(int timePerDegree) //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. + //Grab some variables that are used in the trigger code and assign them to temp variables. noInterrupts(); tempToothCurrentCount = toothCurrentCount; tempToothLastToothTime = toothLastToothTime; interrupts(); - + //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 - - + + 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. //Estimate the number of degrees travelled since the last tooth} long elapsedTime = 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 else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += CRANK_ANGLE_MAX; } - + return crankAngle; } @@ -393,28 +394,28 @@ void triggerPri_GM7X() curTime = micros(); curGap = curTime - toothLastToothTime; toothCurrentCount++; //Increment the tooth counter - + addToothLogEntry(curGap); - + // if( toothCurrentCount > 7 ) { - toothCurrentCount = 1; - toothOneMinusOneTime = toothOneTime; + toothCurrentCount = 1; + toothOneMinusOneTime = toothOneTime; toothOneTime = curTime; } else { 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 - { - toothCurrentCount = 3; + { + toothCurrentCount = 3; currentStatus.hasSync = true; - currentStatus.startRevolutions++; //Counter + currentStatus.startRevolutions++; //Counter 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) - } + } } - + toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; } @@ -428,12 +429,12 @@ int getCrankAngle_GM7X(int timePerDegree) //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. + //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 (Number 3). All others can be calculated, but tooth 3 has a unique angle int crankAngle; if( tempToothCurrentCount < 3 ) @@ -448,16 +449,16 @@ int getCrankAngle_GM7X(int timePerDegree) { 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. } - + //Estimate the number of degrees travelled since the last tooth} long elapsedTime = 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 else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += 360; } - + return crankAngle; } @@ -477,9 +478,9 @@ void triggerSetup_4G63() decoderIsSequential = true; MAX_STALL_TIME = 366667UL; //Minimum 50rpm based on the 110 degree tooth spacing toothLastToothTime = micros(); //Set a startup value here to avoid filter errors when starting - + //Note that these angles are for every rising and falling edge - + toothAngles[0] = 355; //Falling edge of tooth #1 toothAngles[1] = 105; //Rising edge of tooth #2 toothAngles[2] = 175; //Falling edge of tooth #2 @@ -500,8 +501,8 @@ void triggerSetup_4G63() toothAngles[10] = 535; //Rising edge of wide cam tooth toothAngles[11] = 645; //Rising edge of tooth #1 */ - - triggerFilterTime = 1500; //10000 rpm, assuming we're triggering on both edges off the crank tooth. + + 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) } @@ -512,14 +513,14 @@ void triggerPri_4G63() if ( curGap < triggerFilterTime ) { return; } //Filter check. Pulses should never be less than triggerFilterTime addToothLogEntry(curGap); - triggerFilterTime = curGap >> 2; //This only applies during non-sync conditions. If there is sync then triggerFilterTime gets changed again below with a better value. - + triggerFilterTime = curGap >> 2; //This only applies during non-sync conditions. If there is sync then triggerFilterTime gets changed again below with a better value. + toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; - + 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; @@ -534,40 +535,40 @@ void triggerPri_4G63() if( toothCurrentCount == 1 ) { endCoil1Charge(); } else if( toothCurrentCount == 3 ) { endCoil2Charge(); } } - + //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(configPage2.triggerFilter == 1 || currentStatus.RPM < 1800) - { + if(configPage2.triggerFilter == 1 || currentStatus.RPM < 1800) + { //Lite filter 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). } - else if(configPage2.triggerFilter == 2) + else if(configPage2.triggerFilter == 2) { //Medium filter level if(toothCurrentCount == 1 || toothCurrentCount == 3) { triggerToothAngle = 70; triggerFilterTime = (curGap * 5) >> 2 ; } //87.5 degrees with a target of 110 else { triggerToothAngle = 110; triggerFilterTime = (curGap >> 1); } //55 degrees with a target of 70 - } - else if (configPage2.triggerFilter == 3) + } + else if (configPage2.triggerFilter == 3) { //Aggressive filter level if(toothCurrentCount == 1 || toothCurrentCount == 3) { triggerToothAngle = 70; triggerFilterTime = (curGap * 11) >> 3 ; } //96.26 degrees with a target of 110 else { triggerToothAngle = 110; triggerFilterTime = (curGap * 9) >> 5; } //61.87 degrees with a target of 70 } - else { triggerFilterTime = 0; } //trigger filter is turned off. + else { triggerFilterTime = 0; } //trigger filter is turned off. } void triggerSec_4G63() -{ +{ curTime2 = micros(); curGap2 = curTime2 - toothLastSecToothTime; - if ( curGap2 < triggerSecFilterTime ) { return; } + if ( curGap2 < triggerSecFilterTime ) { return; } toothLastSecToothTime = curTime2; - + if(BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) || !currentStatus.hasSync) { - triggerFilterTime = 1500; //If this is removed, can have trouble getting sync again after the engine is turned off (but ECU not reset). - + triggerFilterTime = 1500; //If this is removed, can have trouble getting sync again after the engine is turned off (but ECU not reset). + //Check the status of the crank trigger bool crank = digitalRead(pinTrigger); if(crank == HIGH) @@ -578,29 +579,29 @@ void triggerSec_4G63() toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; */ - } + } } //else { triggerFilterTime = 1500; } //reset filter time (ugly) - return; + return; } int getRPM_4G63() { - //During cranking, RPM is calculated 4 times per revolution, once for each rising/falling of the crank signal. + //During cranking, RPM is calculated 4 times per revolution, once for each rising/falling of the crank signal. //Because these signals aren't even (Alternating 110 and 70 degrees), this needs a special function if(!currentStatus.hasSync) { return 0; } - if(currentStatus.RPM < configPage2.crankRPM) - { + if(currentStatus.RPM < configPage2.crankRPM) + { if(currentStatus.startRevolutions < 2) { return 0; } //Need at least 2 full revolutions to prevent crazy initial rpm value int tempToothAngle; noInterrupts(); tempToothAngle = triggerToothAngle; /* High-res mode - if(toothCurrentCount == 1) { tempToothAngle = 70; } + if(toothCurrentCount == 1) { tempToothAngle = 70; } else { tempToothAngle = toothAngles[toothCurrentCount-1] - toothAngles[toothCurrentCount-2]; } */ - revolutionTime = (toothLastToothTime - toothLastMinusOneToothTime); //Note that trigger tooth angle changes between 70 and 110 depending on the last tooth that was seen + 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; int tempRPM = ((unsigned long)tempToothAngle * 6000000UL) / revolutionTime; @@ -615,23 +616,23 @@ int getCrankAngle_4G63(int timePerDegree) //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. + //Grab some variables that are used in the trigger code and assign them to temp variables. noInterrupts(); tempToothCurrentCount = toothCurrentCount; tempToothLastToothTime = toothLastToothTime; interrupts(); - - int 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. + + int 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. //Estimate the number of degrees travelled since the last tooth} - + unsigned long elapsedTime = 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 else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += 360; } - + return crankAngle; } @@ -681,28 +682,28 @@ void triggerPri_24X() if(toothCurrentCount == 25) { currentStatus.hasSync = false; return; } //Indicates sync has not been achieved (Still waiting for 1 revolution of the crank to take place) curTime = micros(); curGap = curTime - toothLastToothTime; - + if(toothCurrentCount == 0) - { + { toothCurrentCount = 1; //Reset the counter toothOneMinusOneTime = toothOneTime; toothOneTime = curTime; currentStatus.hasSync = true; - currentStatus.startRevolutions++; //Counter + currentStatus.startRevolutions++; //Counter } else { toothCurrentCount++; //Increment the tooth counter } - + addToothLogEntry(curGap); - + toothLastToothTime = curTime; } void triggerSec_24X() -{ +{ toothCurrentCount = 0; //All we need to do is reset the tooth count back to zero, indicating that we're at the beginning of a new revolution - return; + return; } int getRPM_24X() @@ -714,25 +715,25 @@ int getCrankAngle_24X(int timePerDegree) //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. + //Grab some variables that are used in the trigger code and assign them to temp variables. noInterrupts(); tempToothCurrentCount = toothCurrentCount; tempToothLastToothTime = toothLastToothTime; interrupts(); - + int crankAngle; - 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 (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. + //Estimate the number of degrees travelled since the last tooth} long elapsedTime = 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 else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += 360; } - + return crankAngle; } @@ -759,7 +760,7 @@ void triggerSetup_Jeep2000() toothAngles[10] = 454; toothAngles[11] = 474; - MAX_STALL_TIME = (3333UL * 60); //Minimum 50rpm. (3333uS is the time per degree at 50rpm). Largest gap between teeth is 60 degrees. + MAX_STALL_TIME = (3333UL * 60); //Minimum 50rpm. (3333uS is the time per degree at 50rpm). Largest gap between teeth is 60 degrees. toothCurrentCount = 13; //We set the initial tooth value to be something that should never be reached. This indicates no sync secondDerivEnabled = false; decoderIsSequential = false; @@ -771,14 +772,14 @@ void triggerPri_Jeep2000() curTime = micros(); curGap = curTime - toothLastToothTime; if ( curGap < triggerFilterTime ) { return; } //Noise rejection check. Pulses should never be less than triggerFilterTime - + if(toothCurrentCount == 0) - { + { toothCurrentCount = 1; //Reset the counter toothOneMinusOneTime = toothOneTime; toothOneTime = curTime; currentStatus.hasSync = true; - currentStatus.startRevolutions++; //Counter + currentStatus.startRevolutions++; //Counter } else { @@ -786,16 +787,16 @@ void triggerPri_Jeep2000() } setFilter(curGap); //Recalc the new filter value - + addToothLogEntry(curGap); - + toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; } void triggerSec_Jeep2000() -{ +{ toothCurrentCount = 0; //All we need to do is reset the tooth count back to zero, indicating that we're at the beginning of a new revolution - return; + return; } int getRPM_Jeep2000() @@ -807,30 +808,30 @@ int getCrankAngle_Jeep2000(int timePerDegree) //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. + //Grab some variables that are used in the trigger code and assign them to temp variables. noInterrupts(); tempToothCurrentCount = toothCurrentCount; tempToothLastToothTime = toothLastToothTime; interrupts(); - + int crankAngle; - 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 (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. //Estimate the number of degrees travelled since the last tooth} long elapsedTime = 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 else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += 360; } - + return crankAngle; } -/* +/* Name: Audi 135 -Desc: 135 teeth on the crank and 1 tooth on the cam. +Desc: 135 teeth on the crank and 1 tooth on the cam. Note: This is very similar to the dual wheel decoder, however due to the 135 teeth not dividing evenly into 360, only every 3rd crank tooth is used in calculating the crank angle. This effectively makes it a 45 tooth dual wheel setup */ void triggerSetup_Audi135() @@ -846,7 +847,7 @@ void triggerSetup_Audi135() } void triggerPri_Audi135() -{ +{ curTime = micros(); curGap = curTime - toothSystemLastToothTime; if ( curGap < triggerFilterTime ) { return; } @@ -855,38 +856,38 @@ void triggerPri_Audi135() addToothLogEntry(curGap); if ( !currentStatus.hasSync ) { return; } if ( toothSystemCount < 3 ) { return; } //We only proceed for every third tooth - + toothSystemCount = 0; toothCurrentCount++; //Increment the tooth counter - + if ( toothCurrentCount == 1 || toothCurrentCount > 45 ) - { + { toothCurrentCount = 1; toothOneMinusOneTime = toothOneTime; toothOneTime = curTime; currentStatus.startRevolutions++; //Counter - } + } setFilter(curGap); //Recalc the new filter value - + toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; } void triggerSec_Audi135() -{ +{ curTime2 = micros(); curGap2 = curTime2 - toothLastSecToothTime; - if ( curGap2 < triggerSecFilterTime ) { return; } + if ( curGap2 < triggerSecFilterTime ) { return; } toothLastSecToothTime = curTime2; - + if( !currentStatus.hasSync ) { toothCurrentCount = 0; currentStatus.hasSync = true; toothSystemCount = 3; //Need to set this to 3 so that the next primary tooth is counted } -} +} int getRPM_Audi135() { @@ -894,36 +895,36 @@ int getRPM_Audi135() } int getCrankAngle_Audi135(int timePerDegree) -{ +{ //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. + //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 if(tempToothCurrentCount == 0) { tempToothCurrentCount = 45; } - + 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. //Estimate the number of degrees travelled since the last tooth} long elapsedTime = 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 else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += 360; } - + return crankAngle; } /* ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Name: Honda D17 -Desc: -Note: +Desc: +Note: */ void triggerSetup_HondaD17() { @@ -939,33 +940,33 @@ void triggerPri_HondaD17() curTime = micros(); curGap = curTime - toothLastToothTime; toothCurrentCount++; //Increment the tooth counter - + addToothLogEntry(curGap); - + // if( toothCurrentCount == 13 && currentStatus.hasSync) { - toothCurrentCount = 0; + toothCurrentCount = 0; return; } else if( toothCurrentCount == 1 && currentStatus.hasSync) { - toothOneMinusOneTime = toothOneTime; + toothOneMinusOneTime = toothOneTime; toothOneTime = curTime; - currentStatus.startRevolutions++; //Counter + currentStatus.startRevolutions++; //Counter } else { //13th tooth 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; + { + 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; } @@ -979,32 +980,32 @@ int getCrankAngle_HondaD17(int timePerDegree) //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. + //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 int crankAngle; 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. + 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} long elapsedTime = 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 else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += 360; } - + return crankAngle; } @@ -1021,16 +1022,16 @@ void triggerSetup_Miata9905() toothCurrentCount = 99; //Fake tooth count represents no sync secondDerivEnabled = false; decoderIsSequential = true; - + //Note that these angles are for every rising and falling edge - + toothAngles[0] = 350; //Falling edge of tooth #1 toothAngles[1] = 100; //Rising edge of tooth #2 toothAngles[2] = 170; //Falling edge of tooth #2 toothAngles[3] = 280; //Rising edge of tooth #1 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. + 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) } @@ -1039,10 +1040,10 @@ void triggerPri_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; @@ -1051,52 +1052,52 @@ void triggerPri_Miata9905() //if ((startRevolutions & 15) == 1) { currentStatus.hasSync = false; } //Every 64 revolutions, force a resync with the cam } else if (!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). - + curGap = curGap >> 1; - + toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; } void triggerSec_Miata9905() -{ +{ curTime2 = micros(); curGap2 = curTime2 - toothLastSecToothTime; - if ( curGap2 < triggerSecFilterTime ) { return; } + if ( curGap2 < triggerSecFilterTime ) { return; } toothLastSecToothTime = curTime2; lastGap = curGap2; - + if(BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) || !currentStatus.hasSync) { triggerFilterTime = 1500; //Check the status of the crank trigger 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; + { + toothCurrentCount = 1; currentStatus.hasSync = true; - } + } } //else { triggerFilterTime = 1500; } //reset filter time (ugly) - return; + return; } int getRPM_Miata9905() { - //During cranking, RPM is calculated 4 times per revolution, once for each tooth on the crank signal. + //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) - { + if(currentStatus.RPM < configPage2.crankRPM) + { int tempToothAngle; noInterrupts(); tempToothAngle = triggerToothAngle; - revolutionTime = (toothLastToothTime - toothLastMinusOneToothTime); //Note that trigger tooth angle changes between 70 and 110 depending on the last tooth that was seen + 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; @@ -1110,30 +1111,30 @@ int getCrankAngle_Miata9905(int timePerDegree) //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. + //Grab some variables that are used in the trigger code and assign them to temp variables. noInterrupts(); tempToothCurrentCount = toothCurrentCount; tempToothLastToothTime = toothLastToothTime; interrupts(); - - int 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. + + int 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. //Estimate the number of degrees travelled since the last tooth} - + long elapsedTime = 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 else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += 360; } - + return crankAngle; } /* ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Name: Mazda AU version -Desc: -Note: +Desc: +Note: Tooth #2 is defined as the next crank tooth after the single cam tooth Tooth number one is at 348* ATDC */ @@ -1144,14 +1145,14 @@ void triggerSetup_MazdaAU() secondaryToothCount = 0; //Needed for the cam tooth tracking secondDerivEnabled = false; decoderIsSequential = true; - + toothAngles[0] = 348; //tooth #1 toothAngles[1] = 96; //tooth #2 toothAngles[2] = 168; //tooth #3 toothAngles[3] = 276; //tooth #4 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. + 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) } @@ -1162,10 +1163,10 @@ void triggerPri_MazdaAU() if ( curGap < triggerFilterTime ) { return; } //Filter check. Pulses should never be less than triggerFilterTime addToothLogEntry(curGap); - + 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; @@ -1181,35 +1182,35 @@ void triggerPri_MazdaAU() if( toothCurrentCount == 1 ) { endCoil1Charge(); } else if( toothCurrentCount == 3 ) { endCoil2Charge(); } } - + //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). - + toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; } void triggerSec_MazdaAU() -{ +{ curTime2 = micros(); lastGap = curGap2; curGap2 = curTime2 - toothLastSecToothTime; - //if ( curGap2 < triggerSecFilterTime ) { return; } + //if ( curGap2 < triggerSecFilterTime ) { return; } toothLastSecToothTime = curTime2; - + //if(BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) || !currentStatus.hasSync) //Not sure if the cranking check is needed here if(!currentStatus.hasSync) { //we find sync by looking for the 2 teeth that are close together. The next crank tooth after that is the one we're looking for. //For the sake of this decoder, the lone cam tooth will be designated #1 if(secondaryToothCount == 2) - { - toothCurrentCount = 1; + { + toothCurrentCount = 1; currentStatus.hasSync = true; } else { - triggerFilterTime = 1500; //In case the engine has been running and then lost sync. + triggerFilterTime = 1500; //In case the engine has been running and then lost sync. targetGap = (lastGap) >> 1; //The target gap is set at half the last tooth gap 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) { @@ -1219,22 +1220,22 @@ void triggerSec_MazdaAU() secondaryToothCount++; } - return; + return; } int getRPM_MazdaAU() { if (!currentStatus.hasSync) { return 0; } - - //During cranking, RPM is calculated 4 times per revolution, once for each tooth on the crank signal. + + //During cranking, RPM is calculated 4 times per revolution, once for each tooth on the crank signal. //Because these signals aren't even (Alternating 108 and 72 degrees), this needs a special function - if(currentStatus.RPM < configPage2.crankRPM) - { + if(currentStatus.RPM < configPage2.crankRPM) + { int tempToothAngle; noInterrupts(); tempToothAngle = triggerToothAngle; - revolutionTime = (toothLastToothTime - toothLastMinusOneToothTime); //Note that trigger tooth angle changes between 72 and 108 depending on the last tooth that was seen + revolutionTime = (toothLastToothTime - toothLastMinusOneToothTime); //Note that trigger tooth angle changes between 72 and 108 depending on the last tooth that was seen interrupts(); revolutionTime = revolutionTime * 36; return (tempToothAngle * 60000000L) / revolutionTime; @@ -1248,29 +1249,29 @@ int getCrankAngle_MazdaAU(int timePerDegree) //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. + //Grab some variables that are used in the trigger code and assign them to temp variables. noInterrupts(); tempToothCurrentCount = toothCurrentCount; tempToothLastToothTime = toothLastToothTime; interrupts(); - - int 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. + + int 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. //Estimate the number of degrees travelled since the last tooth} - + long elapsedTime = 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 else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += 360; } - + return crankAngle; } -/* +/* Name: Non-360 Dual wheel -Desc: 2 wheels located either both on the crank or with the primary on the crank and the secondary on the cam. +Desc: 2 wheels located either both on the crank or with the primary on the crank and the secondary on the cam. Note: There can be no missing teeth on the primary wheel */ void triggerSetup_non360() @@ -1286,14 +1287,14 @@ void triggerSetup_non360() void triggerPri_non360() -{ +{ //This is not used, the trigger is identical to the dual wheel one, so that is used instead. } void triggerSec_non360() -{ +{ //This is not used, the trigger is identical to the dual wheel one, so that is used instead. -} +} int getRPM_non360() { @@ -1307,30 +1308,27 @@ int getCrankAngle_non360(int timePerDegree) //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. + //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 if(tempToothCurrentCount == 0) { tempToothCurrentCount = configPage2.triggerTeeth; } //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. int crankAngle = (tempToothCurrentCount - 1) * triggerToothAngle; - crankAngle = (crankAngle / configPage2.TrigAngMul) + configPage2.triggerAngle; //Have to divide by the multiplier to get back to actual crank angle. - + crankAngle = (crankAngle / configPage2.TrigAngMul) + configPage2.triggerAngle; //Have to divide by the multiplier to get back to actual crank angle. + //Estimate the number of degrees travelled since the last tooth} long elapsedTime = 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 else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; } - - if (crankAngle >= 720) { crankAngle -= 720; } + + if (crankAngle >= 720) { crankAngle -= 720; } if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += 360; } - + return crankAngle; } - - - diff --git a/maths.h b/maths.h index bf94c51..7daa0e7 100644 --- a/maths.h +++ b/maths.h @@ -1,6 +1,7 @@ #ifndef MATH_H #define MATH_H -int fastMap1023toX(unsigned long x, int out_max); +int fastMap1023toX(unsigned long, int); +unsigned long percentage(byte, unsigned long); #endif diff --git a/scheduler.ino b/scheduler.ino index a958bf1..448be32 100644 --- a/scheduler.ino +++ b/scheduler.ino @@ -34,8 +34,8 @@ void initialiseSchedulers() TCNT4 = 0; //Reset Timer Count TIFR4 = 0x00; //Timer4 INT Flag Reg: Clear Timer Overflow Flag TCCR4A = 0x00; //Timer4 Control Reg A: Wave Gen Mode normal - TCCR4B = (1 << CS12); //Timer4 Control Reg B: aka Divisor = 256 = 122.5HzTimer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg - + TCCR4B = (1 << CS12); //Timer4 Control Reg B: aka Divisor = 256 = 122.5HzTimer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg + #elif defined (CORE_TEENSY) && defined (__MK20DX256__) //FlexTimer 0 is used for 4 ignition and 4 injection schedules. There are 8 channels on this module, so no other timers are needed @@ -57,23 +57,23 @@ void initialiseSchedulers() FTM1_CNTIN = 0x0000; //Shouldn't be needed, but just in case FTM1_CNT = 0x0000; // Reset the count to zero FTM1_MOD = 0xFFFF; // max modulus = 65535 - + /* * Enable the clock for FTM0/1 * 00 No clock selected. Disables the FTM counter. * 01 System clock * 10 Fixed frequency clock * 11 External clock - */ + */ FTM0_SC |= FTM_SC_CLKS(0b1); FTM1_SC |= FTM_SC_CLKS(0b1); - /* - * Set Prescaler + /* + * Set Prescaler * This is the slowest that the timer can be clocked (Without used the slow timer, which is too slow). It results in ticks of 2.13333uS on the teensy 3.5: * 60000000 Hz = F_BUS * 128 * 1000000uS / F_BUS = 2.133uS - * + * * 000 = Divide by 1 * 001 Divide by 2 * 010 Divide by 4 @@ -86,38 +86,38 @@ void initialiseSchedulers() FTM0_SC |= FTM_SC_PS(0b111); FTM1_SC |= FTM_SC_PS(0b111); - //Setup the channels (See Pg 1014 of K64 DS). + //Setup the channels (See Pg 1014 of K64 DS). //FTM0_C0SC &= ~FTM_CSC_ELSB; //Probably not needed as power on state should be 0 //FTM0_C0SC &= ~FTM_CSC_ELSA; //Probably not needed as power on state should be 0 //FTM0_C0SC &= ~FTM_CSC_DMA; //Probably not needed as power on state should be 0 FTM0_C0SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it FTM0_C0SC |= FTM_CSC_MSA; //Enable Compare mode FTM0_C0SC |= FTM_CSC_CHIE; //Enable channel compare interrupt - + FTM0_C1SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it FTM0_C1SC |= FTM_CSC_MSA; //Enable Compare mode FTM0_C1SC |= FTM_CSC_CHIE; //Enable channel compare interrupt - + FTM0_C2SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it FTM0_C2SC |= FTM_CSC_MSA; //Enable Compare mode FTM0_C2SC |= FTM_CSC_CHIE; //Enable channel compare interrupt - + FTM0_C3SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it FTM0_C3SC |= FTM_CSC_MSA; //Enable Compare mode FTM0_C3SC |= FTM_CSC_CHIE; //Enable channel compare interrupt - + FTM0_C4SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it FTM0_C4SC |= FTM_CSC_MSA; //Enable Compare mode FTM0_C4SC |= FTM_CSC_CHIE; //Enable channel compare interrupt - + FTM0_C5SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it FTM0_C5SC |= FTM_CSC_MSA; //Enable Compare mode FTM0_C5SC |= FTM_CSC_CHIE; //Enable channel compare interrupt - + FTM0_C6SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it FTM0_C6SC |= FTM_CSC_MSA; //Enable Compare mode FTM0_C6SC |= FTM_CSC_CHIE; //Enable channel compare interrupt - + FTM0_C7SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it FTM0_C7SC |= FTM_CSC_MSA; //Enable Compare mode FTM0_C7SC |= FTM_CSC_CHIE; //Enable channel compare interrupt @@ -130,10 +130,10 @@ void initialiseSchedulers() // enable IRQ Interrupt NVIC_ENABLE_IRQ(IRQ_FTM0); NVIC_ENABLE_IRQ(IRQ_FTM1); - + #endif - fuelSchedule1.Status = OFF; + fuelSchedule1.Status = OFF; fuelSchedule2.Status = OFF; fuelSchedule3.Status = OFF; fuelSchedule4.Status = OFF; @@ -150,15 +150,15 @@ void initialiseSchedulers() ignitionSchedule3.Status = OFF; ignitionSchedule4.Status = OFF; ignitionSchedule5.Status = OFF; - + ignitionSchedule1.schedulesSet = 0; ignitionSchedule2.schedulesSet = 0; ignitionSchedule3.schedulesSet = 0; ignitionSchedule4.schedulesSet = 0; ignitionSchedule5.schedulesSet = 0; - + } - + /* These 8 function turn a schedule on, provides the time to start and the duration and gives it callback functions. All 8 functions operate the same, just on different schedules @@ -171,7 +171,7 @@ endCallback: This function is called once the duration time has been reached void setFuelSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) { if(fuelSchedule1.Status == RUNNING) { return; } //Check that we're not already part way through a schedule - + fuelSchedule1.StartCallback = startCallback; //Name the start callback function fuelSchedule1.EndCallback = endCallback; //Name the end callback function fuelSchedule1.duration = duration; @@ -179,7 +179,7 @@ void setFuelSchedule1(void (*startCallback)(), unsigned long timeout, unsigned l /* * The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupts fires before the state is fully set * We need to calculate the value to reset the timer to (preload) in order to achieve the desired overflow time - * As the timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) + * As the timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) * unsigned int absoluteTimeout = TCNT3 + (timeout / 16); //Each tick occurs every 16uS with the 256 prescaler, so divide the timeout by 16 to get ther required number of ticks. Add this to the current tick count to get the target time. This will automatically overflow as required */ noInterrupts(); @@ -196,7 +196,7 @@ void setFuelSchedule1(void (*startCallback)(), unsigned long timeout, unsigned l void setFuelSchedule2(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) { if(fuelSchedule2.Status == RUNNING) { return; } //Check that we're not already part way through a schedule - + fuelSchedule2.StartCallback = startCallback; //Name the start callback function fuelSchedule2.EndCallback = endCallback; //Name the end callback function fuelSchedule2.duration = duration; @@ -204,7 +204,7 @@ void setFuelSchedule2(void (*startCallback)(), unsigned long timeout, unsigned l /* * The following must be enclosed in the noIntterupts block to avoid contention caused if the relevant interrupts fires before the state is fully set * We need to calculate the value to reset the timer to (preload) in order to achieve the desired overflow time - * As the timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) + * As the timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) * unsigned int absoluteTimeout = TCNT3 + (timeout / 16); //Each tick occurs every 16uS with the 256 prescaler, so divide the timeout by 16 to get ther required number of ticks. Add this to the current tick count to get the target time. This will automatically overflow as required */ noInterrupts(); @@ -223,11 +223,11 @@ void setFuelSchedule3(void (*startCallback)(), unsigned long timeout, unsigned l fuelSchedule3.StartCallback = startCallback; //Name the start callback function fuelSchedule3.EndCallback = endCallback; //Name the end callback function fuelSchedule3.duration = duration; - + /* * The following must be enclosed in the noIntterupts block to avoid contention caused if the relevant interrupts fires before the state is fully set * We need to calculate the value to reset the timer to (preload) in order to achieve the desired overflow time - * As the timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) + * As the timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) * unsigned int absoluteTimeout = TCNT3 + (timeout / 16); //Each tick occurs every 16uS with the 256 prescaler, so divide the timeout by 16 to get ther required number of ticks. Add this to the current tick count to get the target time. This will automatically overflow as required */ noInterrupts(); @@ -242,15 +242,15 @@ void setFuelSchedule3(void (*startCallback)(), unsigned long timeout, unsigned l void setFuelSchedule4(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) //Uses timer 4 compare B { if(fuelSchedule4.Status == RUNNING) { return; } //Check that we're not already part way through a schedule - + fuelSchedule4.StartCallback = startCallback; //Name the start callback function fuelSchedule4.EndCallback = endCallback; //Name the end callback function fuelSchedule4.duration = duration; - + /* * The following must be enclosed in the noIntterupts block to avoid contention caused if the relevant interrupts fires before the state is fully set * We need to calculate the value to reset the timer to (preload) in order to achieve the desired overflow time - * As the timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) + * As the timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) * unsigned int absoluteTimeout = TCNT3 + (timeout / 16); //Each tick occurs every 16uS with the 256 prescaler, so divide the timeout by 16 to get ther required number of ticks. Add this to the current tick count to get the target time. This will automatically overflow as required */ noInterrupts(); @@ -265,9 +265,9 @@ void setFuelSchedule4(void (*startCallback)(), unsigned long timeout, unsigned l void setFuelSchedule5(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) { if(fuelSchedule5.Status == RUNNING) { return; } //Check that we're not already part way through a schedule - + //We need to calculate the value to reset the timer to (preload) in order to achieve the desired overflow time - //As the timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) + //As the timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) //unsigned int absoluteTimeout = TCNT3 + (timeout / 16); //Each tick occurs every 16uS with the 256 prescaler, so divide the timeout by 16 to get ther required number of ticks. Add this to the current tick count to get the target time. This will automatically overflow as required fuelSchedule5.StartCallback = startCallback; //Name the start callback function fuelSchedule5.EndCallback = endCallback; //Name the end callback function @@ -295,8 +295,8 @@ void setIgnitionSchedule1(void (*startCallback)(), unsigned long timeout, unsign ignitionSchedule1.StartCallback = startCallback; //Name the start callback function ignitionSchedule1.EndCallback = endCallback; //Name the start callback function ignitionSchedule1.duration = duration; - - //As the timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency)) + + //As the timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency)) if (timeout > MAX_TIMER_PERIOD) { timeout = MAX_TIMER_PERIOD - 1; } // If the timeout is >4x (Each tick represents 4uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking. noInterrupts(); @@ -311,14 +311,14 @@ void setIgnitionSchedule1(void (*startCallback)(), unsigned long timeout, unsign void setIgnitionSchedule2(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) { if(ignitionSchedule2.Status == RUNNING) { return; } //Check that we're not already part way through a schedule - + ignitionSchedule2.StartCallback = startCallback; //Name the start callback function ignitionSchedule2.EndCallback = endCallback; //Name the start callback function ignitionSchedule2.duration = duration; - - //As the timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency)) + + //As the timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency)) if (timeout > MAX_TIMER_PERIOD) { timeout = MAX_TIMER_PERIOD - 1; } // If the timeout is >4x (Each tick represents 4uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking. - + noInterrupts(); ignitionSchedule2.startCompare = IGN2_COUNTER + uS_TO_TIMER_COMPARE(timeout); //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4) ignitionSchedule2.endCompare = ignitionSchedule2.startCompare + uS_TO_TIMER_COMPARE(duration); @@ -335,10 +335,10 @@ void setIgnitionSchedule3(void (*startCallback)(), unsigned long timeout, unsign ignitionSchedule3.StartCallback = startCallback; //Name the start callback function ignitionSchedule3.EndCallback = endCallback; //Name the start callback function ignitionSchedule3.duration = duration; - - //The timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency)) + + //The timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency)) if (timeout > MAX_TIMER_PERIOD) { timeout = MAX_TIMER_PERIOD - 1; } // If the timeout is >4x (Each tick represents 4uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking. - + noInterrupts(); ignitionSchedule3.startCompare = IGN3_COUNTER + uS_TO_TIMER_COMPARE(timeout); //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4) ignitionSchedule3.endCompare = ignitionSchedule3.startCompare + uS_TO_TIMER_COMPARE(duration); @@ -346,7 +346,7 @@ void setIgnitionSchedule3(void (*startCallback)(), unsigned long timeout, unsign ignitionSchedule3.Status = PENDING; //Turn this schedule on ignitionSchedule3.schedulesSet++; interrupts(); - IGN3_TIMER_ENABLE(); + IGN3_TIMER_ENABLE(); } void setIgnitionSchedule4(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) { @@ -355,7 +355,7 @@ void setIgnitionSchedule4(void (*startCallback)(), unsigned long timeout, unsign ignitionSchedule4.StartCallback = startCallback; //Name the start callback function ignitionSchedule4.EndCallback = endCallback; //Name the start callback function ignitionSchedule4.duration = duration; - + //We need to calculate the value to reset the timer to (preload) in order to achieve the desired overflow time //The timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) //Note this is different to the other ignition timers @@ -368,7 +368,7 @@ void setIgnitionSchedule4(void (*startCallback)(), unsigned long timeout, unsign ignitionSchedule4.Status = PENDING; //Turn this schedule on ignitionSchedule4.schedulesSet++; interrupts(); - IGN4_TIMER_ENABLE(); + IGN4_TIMER_ENABLE(); } void setIgnitionSchedule5(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) { @@ -377,7 +377,7 @@ void setIgnitionSchedule5(void (*startCallback)(), unsigned long timeout, unsign ignitionSchedule5.StartCallback = startCallback; //Name the start callback function ignitionSchedule5.EndCallback = endCallback; //Name the start callback function ignitionSchedule5.duration = duration; - + //We need to calculate the value to reset the timer to (preload) in order to achieve the desired overflow time //The timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency)) //Note this is different to the other ignition timers @@ -390,9 +390,9 @@ void setIgnitionSchedule5(void (*startCallback)(), unsigned long timeout, unsign ignitionSchedule5.Status = PENDING; //Turn this schedule on ignitionSchedule5.schedulesSet++; interrupts(); - IGN5_TIMER_ENABLE(); + IGN5_TIMER_ENABLE(); } - + /*******************************************************************************************************************************************************************************************************/ //This function (All 8 ISR functions that are below) gets called when either the start time or the duration time are reached //This calls the relevant callback function (startCallback or endCallback) depending on the status of the schedule. @@ -461,7 +461,7 @@ static inline void fuelSchedule3Interrupt() //Most ARM chips can simply call a f FUEL3_TIMER_DISABLE(); } } - + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this ISR(TIMER4_COMPB_vect, ISR_NOBLOCK) //fuelSchedule4 #elif defined (CORE_TEENSY) @@ -479,10 +479,10 @@ static inline void fuelSchedule4Interrupt() //Most ARM chips can simply call a f fuelSchedule4.EndCallback(); fuelSchedule4.Status = OFF; //Turn off the schedule fuelSchedule4.schedulesSet = 0; - FUEL4_TIMER_DISABLE(); + FUEL4_TIMER_DISABLE(); } } - + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this ISR(TIMER5_COMPA_vect) //ignitionSchedule1 #elif defined (CORE_TEENSY) @@ -506,7 +506,7 @@ static inline void ignitionSchedule1Interrupt() //Most ARM chips can simply call IGN1_TIMER_DISABLE(); } } - + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this ISR(TIMER5_COMPB_vect) //ignitionSchedule2 #elif defined (CORE_TEENSY) @@ -530,7 +530,7 @@ static inline void ignitionSchedule2Interrupt() //Most ARM chips can simply call IGN2_TIMER_DISABLE(); } } - + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this ISR(TIMER5_COMPC_vect) //ignitionSchedule3 #elif defined (CORE_TEENSY) @@ -554,7 +554,7 @@ static inline void ignitionSchedule3Interrupt() //Most ARM chips can simply call IGN3_TIMER_DISABLE(); } } - + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this ISR(TIMER4_COMPA_vect) //ignitionSchedule4 #elif defined (CORE_TEENSY) @@ -603,16 +603,16 @@ static inline void ignitionSchedule5Interrupt() //Most ARM chips can simply call } } - + #if defined(CORE_TEENSY) -void ftm0_isr(void) +void ftm0_isr(void) { - - if(FTM0_C0SC & FTM_CSC_CHF) { FTM0_C0SC &= ~FTM_CSC_CHF; fuelSchedule1Interrupt(); } - else if(FTM0_C1SC & FTM_CSC_CHF) { FTM0_C1SC &= ~FTM_CSC_CHF; fuelSchedule2Interrupt(); } - else if(FTM0_C2SC & FTM_CSC_CHF) { FTM0_C2SC &= ~FTM_CSC_CHF; fuelSchedule3Interrupt(); } - else if(FTM0_C3SC & FTM_CSC_CHF) { FTM0_C3SC &= ~FTM_CSC_CHF; fuelSchedule4Interrupt(); } + + if(FTM0_C0SC & FTM_CSC_CHF) { FTM0_C0SC &= ~FTM_CSC_CHF; fuelSchedule1Interrupt(); } + else if(FTM0_C1SC & FTM_CSC_CHF) { FTM0_C1SC &= ~FTM_CSC_CHF; fuelSchedule2Interrupt(); } + else if(FTM0_C2SC & FTM_CSC_CHF) { FTM0_C2SC &= ~FTM_CSC_CHF; fuelSchedule3Interrupt(); } + else if(FTM0_C3SC & FTM_CSC_CHF) { FTM0_C3SC &= ~FTM_CSC_CHF; fuelSchedule4Interrupt(); } else if(FTM0_C4SC & FTM_CSC_CHF) { FTM0_C4SC &= ~FTM_CSC_CHF; ignitionSchedule1Interrupt(); } else if(FTM0_C5SC & FTM_CSC_CHF) { FTM0_C5SC &= ~FTM_CSC_CHF; ignitionSchedule2Interrupt(); } else if(FTM0_C6SC & FTM_CSC_CHF) { FTM0_C6SC &= ~FTM_CSC_CHF; ignitionSchedule3Interrupt(); } diff --git a/speeduino.ino b/speeduino.ino index 5eb253d..cf8e8f3 100644 --- a/speeduino.ino +++ b/speeduino.ino @@ -28,10 +28,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "scheduler.h" #include "comms.h" #include "cancomms.h" -#include "math.h" +#include "maths.h" #include "corrections.h" #include "timers.h" -//#include "display.h" +//#include "display.h" #include "decoders.h" #include "idle.h" #include "auxiliaries.h" @@ -78,7 +78,7 @@ unsigned long currentLoopTime; //The time the current loop started (uS) unsigned long previousLoopTime; //The time the previous loop started (uS) int CRANK_ANGLE_MAX = 720; -int CRANK_ANGLE_MAX_IGN = 360, CRANK_ANGLE_MAX_INJ = 360; // The number of crank degrees that the system track over. 360 for wasted / timed batch and 720 for sequential +int CRANK_ANGLE_MAX_IGN = 360, CRANK_ANGLE_MAX_INJ = 360; // The number of crank degrees that the system track over. 360 for wasted / timed batch and 720 for sequential //bool useSequentialFuel; // Whether sequential fueling is to be used (1 squirt per cycle) //bool useSequentialIgnition; // Whether sequential ignition is used (1 spark per cycle) @@ -129,13 +129,13 @@ int timePerDegree; byte degreesPerLoop; //The number of crank degrees that pass for each mainloop of the program volatile bool fpPrimed = false; //Tracks whether or not the fuel pump priming has been completed yet -void setup() +void setup() { Serial.begin(115200); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //ATmega2561 does not have Serial3 if (configPage1.canEnable) { Serial3.begin(115200); } #endif - + //Setup the dummy fuel and ignition tables //dummyFuelTable(&fuelTable); //dummyIgnitionTable(&ignitionTable); @@ -148,9 +148,9 @@ void setup() table3D_setSize(&trim2Table, 6); table3D_setSize(&trim3Table, 6); table3D_setSize(&trim4Table, 6); - + loadConfig(); - + //Repoint the 2D table structs to the config pages that were just loaded taeTable.valueSize = SIZE_BYTE; //Set this table to use byte values taeTable.xSize = 4; @@ -160,7 +160,7 @@ void setup() WUETable.xSize = 10; WUETable.values = configPage1.wueValues; WUETable.axisX = configPage2.wueBins; - + dwellVCorrectionTable.valueSize = SIZE_BYTE; dwellVCorrectionTable.xSize = 6; dwellVCorrectionTable.values = configPage2.dwellCorrectionValues; @@ -177,13 +177,13 @@ void setup() IATRetardTable.xSize = 6; IATRetardTable.values = configPage2.iatRetValues; IATRetardTable.axisX = configPage2.iatRetBins; - + //Setup the calibration tables loadCalibration(); //Set the pin mappings setPinMapping(configPage1.pinMapping); - //Need to check early on whether the coil charging is inverted. If this is not set straight away it can cause an unwanted spark at bootup + //Need to check early on whether the coil charging is inverted. If this is not set straight away it can cause an unwanted spark at bootup if(configPage2.IgInv == 1) { coilHIGH = LOW, coilLOW = HIGH; } else { coilHIGH = HIGH, coilLOW = LOW; } endCoil1Charge(); @@ -191,14 +191,14 @@ void setup() endCoil3Charge(); endCoil4Charge(); endCoil5Charge(); - + //Similar for injectors, make sure they're turned off closeInjector1(); closeInjector2(); closeInjector3(); closeInjector4(); closeInjector5(); - + //Set the tacho output default state digitalWrite(pinTachOut, HIGH); @@ -206,7 +206,7 @@ void setup() readMAP(); /* * The highest sea-level pressure on Earth occurs in Siberia, where the Siberian High often attains a sea-level pressure above 105 kPa; - * with record highs close to 108.5 kPa. + * with record highs close to 108.5 kPa. * The lowest measurable sea-level pressure is found at the centers of tropical cyclones and tornadoes, with a record low of 87 kPa; */ if ((currentStatus.MAP >= BARO_MIN) && (currentStatus.MAP <= BARO_MAX)) //Check if engine isn't running @@ -214,13 +214,13 @@ void setup() currentStatus.baro = currentStatus.MAP; EEPROM.update(EEPROM_LAST_BARO, currentStatus.baro); } - else + else { //Attempt to use the last known good baro reading from EEPROM if ((EEPROM.read(EEPROM_LAST_BARO) >= BARO_MIN) && (EEPROM.read(EEPROM_LAST_BARO) <= BARO_MAX)) //Make sure it's not invalid (Possible on first run etc) { currentStatus.baro = EEPROM.read(EEPROM_LAST_BARO); } //last baro correction - else { currentStatus.baro = 100; } //Final fall back position. - } + else { currentStatus.baro = 100; } //Final fall back position. + } //Perform all initialisations initialiseSchedulers(); @@ -234,30 +234,30 @@ void setup() //Check whether the flex sensor is enabled and if so, attach an interupt for it if(configPage1.flexEnabled) - { + { attachInterrupt(digitalPinToInterrupt(pinFlex), flexPulse, RISING); currentStatus.ethanolPct = 0; } - + //Once the configs have been loaded, a number of one time calculations can be completed req_fuel_uS = configPage1.reqFuel * 100; //Convert to uS and an int. This is the only variable to be used in calculations - inj_opentime_uS = configPage1.injOpen * 100; //Injector open time. Comes through as ms*10 (Eg 15.5ms = 155). - + inj_opentime_uS = configPage1.injOpen * 100; //Injector open time. Comes through as ms*10 (Eg 15.5ms = 155). + //Begin the main crank trigger interrupt pin setup //The interrupt numbering is a bit odd - See here for reference: http://arduino.cc/en/Reference/AttachInterrupt - //These assignments are based on the Arduino Mega AND VARY BETWEEN BOARDS. Please confirm the board you are using and update acordingly. + //These assignments are based on the Arduino Mega AND VARY BETWEEN BOARDS. Please confirm the board you are using and update acordingly. byte triggerInterrupt = 0; // By default, use the first interrupt byte triggerInterrupt2 = 1; currentStatus.RPM = 0; currentStatus.hasSync = false; - currentStatus.runSecs = 0; + currentStatus.runSecs = 0; currentStatus.secl = 0; currentStatus.startRevolutions = 0; currentStatus.flatShiftingHard = false; currentStatus.launchingHard = false; triggerFilterTime = 0; //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 simply a default value, the actual values are set in the setup() functinos of each decoder - - switch (pinTrigger) { + + switch (pinTrigger) { //Arduino Mega 2560 mapping case 2: triggerInterrupt = 0; break; @@ -271,9 +271,9 @@ void setup() triggerInterrupt = 3; break; case 21: triggerInterrupt = 2; break; - + } - switch (pinTrigger2) { + switch (pinTrigger2) { //Arduino Mega 2560 mapping case 2: triggerInterrupt2 = 0; break; @@ -287,14 +287,14 @@ void setup() triggerInterrupt2 = 3; break; case 21: triggerInterrupt2 = 2; break; - + } pinMode(pinTrigger, INPUT); pinMode(pinTrigger2, INPUT); pinMode(pinTrigger3, INPUT); //digitalWrite(pinTrigger, HIGH); - + //Set the trigger function based on the decoder in the config switch (configPage2.TrigPattern) { @@ -305,52 +305,52 @@ void setup() triggerSecondary = triggerSec_missingTooth; getRPM = getRPM_missingTooth; getCrankAngle = getCrankAngle_missingTooth; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) else { attachInterrupt(triggerInterrupt, trigger, FALLING); } if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, RISING); } else { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, FALLING); } break; - + case 1: // Basic distributor triggerSetup_BasicDistributor(); trigger = triggerPri_BasicDistributor; getRPM = getRPM_BasicDistributor; getCrankAngle = getCrankAngle_BasicDistributor; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) else { attachInterrupt(triggerInterrupt, trigger, FALLING); } break; - + case 2: triggerSetup_DualWheel(); trigger = triggerPri_DualWheel; getRPM = getRPM_DualWheel; getCrankAngle = getCrankAngle_DualWheel; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) else { attachInterrupt(triggerInterrupt, trigger, FALLING); } if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, RISING); } else { attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, FALLING); } break; - + case 3: triggerSetup_GM7X(); trigger = triggerPri_GM7X; getRPM = getRPM_GM7X; getCrankAngle = getCrankAngle_GM7X; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) else { attachInterrupt(triggerInterrupt, trigger, FALLING); } break; - + case 4: triggerSetup_4G63(); trigger = triggerPri_4G63; getRPM = getRPM_4G63; getCrankAngle = getCrankAngle_4G63; - + //These may both need to change, not sure if(configPage2.TrigEdge == 0) { @@ -359,39 +359,39 @@ void setup() } else { - attachInterrupt(triggerInterrupt, trigger, CHANGE); // Primary trigger connects to + attachInterrupt(triggerInterrupt, trigger, CHANGE); // Primary trigger connects to attachInterrupt(triggerInterrupt2, triggerSec_4G63, FALLING); } break; - + case 5: triggerSetup_24X(); trigger = triggerPri_24X; getRPM = getRPM_24X; getCrankAngle = getCrankAngle_24X; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) - else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to + else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to attachInterrupt(triggerInterrupt2, triggerSec_24X, CHANGE); break; - + case 6: triggerSetup_Jeep2000(); trigger = triggerPri_Jeep2000; getRPM = getRPM_Jeep2000; getCrankAngle = getCrankAngle_Jeep2000; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) - else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to + else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to attachInterrupt(triggerInterrupt2, triggerSec_Jeep2000, CHANGE); break; - + case 7: triggerSetup_Audi135(); trigger = triggerPri_Audi135; getRPM = getRPM_Audi135; getCrankAngle = getCrankAngle_Audi135; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) else { attachInterrupt(triggerInterrupt, trigger, FALLING); } attachInterrupt(triggerInterrupt2, triggerSec_Audi135, RISING); @@ -402,9 +402,9 @@ void setup() trigger = triggerPri_HondaD17; getRPM = getRPM_HondaD17; getCrankAngle = getCrankAngle_HondaD17; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) - else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to + else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to attachInterrupt(triggerInterrupt2, triggerSec_HondaD17, CHANGE); break; @@ -413,7 +413,7 @@ void setup() trigger = triggerPri_Miata9905; getRPM = getRPM_Miata9905; getCrankAngle = getCrankAngle_Miata9905; - + //These may both need to change, not sure if(configPage2.TrigEdge == 0) { @@ -422,7 +422,7 @@ void setup() } else { - attachInterrupt(triggerInterrupt, trigger, FALLING); // Primary trigger connects to + attachInterrupt(triggerInterrupt, trigger, FALLING); // Primary trigger connects to attachInterrupt(triggerInterrupt2, triggerSec_Miata9905, RISING); } break; @@ -432,9 +432,9 @@ void setup() trigger = triggerPri_MazdaAU; getRPM = getRPM_MazdaAU; getCrankAngle = getCrankAngle_MazdaAU; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) - else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to + else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to attachInterrupt(triggerInterrupt2, triggerSec_MazdaAU, FALLING); break; @@ -443,33 +443,33 @@ void setup() trigger = triggerPri_DualWheel; //Is identical to the dual wheel decoder, so that is used. Same goes for the secondary below getRPM = getRPM_non360; getCrankAngle = getCrankAngle_non360; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) - else { attachInterrupt(triggerInterrupt, trigger, FALLING); } - attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, FALLING); //Note the use of the Dual Wheel trigger function here. No point in having the same code in twice. + else { attachInterrupt(triggerInterrupt, trigger, FALLING); } + attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, FALLING); //Note the use of the Dual Wheel trigger function here. No point in having the same code in twice. break; - + default: trigger = triggerPri_missingTooth; getRPM = getRPM_missingTooth; getCrankAngle = getCrankAngle_missingTooth; - + if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) else { attachInterrupt(triggerInterrupt, trigger, FALLING); } break; } //End crank triger interrupt attachment - + req_fuel_uS = req_fuel_uS / engineSquirtsPerCycle; //The req_fuel calculation above gives the total required fuel (At VE 100%) in the full cycle. If we're doing more than 1 squirt per cycle then we need to split the amount accordingly. (Note that in a non-sequential 4-stroke setup you cannot have less than 2 squirts as you cannot determine the stroke to make the single squirt on) - + //Initial values for loop times previousLoopTime = 0; currentLoopTime = micros(); - + mainLoopCount = 0; ignitionCount = 0; - + //Calculate the number of degrees between cylinders switch (configPage1.nCylinders) { case 1: @@ -481,11 +481,11 @@ void setup() case 2: channel1IgnDegrees = 0; - if (configPage1.engineType == EVEN_FIRE ) + if (configPage1.engineType == EVEN_FIRE ) { channel2IgnDegrees = 180; } - else { channel2IgnDegrees = configPage1.oddfire2; } + else { channel2IgnDegrees = configPage1.oddfire2; } //For alternating injection, the squirt occurs at different times for each channel if(configPage1.injLayout == INJ_SEMISEQUENTIAL) @@ -501,7 +501,7 @@ void setup() case 3: channel1IgnDegrees = 0; - if (configPage1.engineType == EVEN_FIRE ) + if (configPage1.engineType == EVEN_FIRE ) { channel2IgnDegrees = 120; channel3IgnDegrees = 240; @@ -511,7 +511,7 @@ void setup() channel2IgnDegrees = configPage1.oddfire2; channel3IgnDegrees = configPage1.oddfire3; } - + //For alternatiing injection, the squirt occurs at different times for each channel if(configPage1.injLayout == INJ_SEMISEQUENTIAL || configPage1.injLayout == INJ_PAIRED) { @@ -536,7 +536,7 @@ void setup() case 4: channel1IgnDegrees = 0; - if (configPage1.engineType == EVEN_FIRE ) + if (configPage1.engineType == EVEN_FIRE ) { channel2IgnDegrees = 180; @@ -544,7 +544,7 @@ void setup() { channel3IgnDegrees = 360; channel4IgnDegrees = 540; - + CRANK_ANGLE_MAX_IGN = 720; } } @@ -570,7 +570,7 @@ void setup() channel3InjEnabled = true; channel4InjEnabled = true; - + CRANK_ANGLE_MAX_INJ = 720; req_fuel_uS = req_fuel_uS * 2; } @@ -592,7 +592,7 @@ void setup() channel3IgnDegrees = 288; channel4IgnDegrees = 432; channel5IgnDegrees = 576; - + CRANK_ANGLE_MAX_IGN = 720; } @@ -612,7 +612,7 @@ void setup() channel3InjDegrees = 288; channel4InjDegrees = 432; channel5InjDegrees = 576; - + CRANK_ANGLE_MAX_INJ = 720; } if (!configPage1.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = channel4InjDegrees = channel5InjDegrees = 0; } //For simultaneous, all squirts happen at the same time @@ -627,7 +627,7 @@ void setup() channel1IgnDegrees = 0; channel2IgnDegrees = 120; channel3IgnDegrees = 240; - + //For alternatiing injection, the squirt occurs at different times for each channel /* if(configPage1.injLayout == INJ_SEMISEQUENTIAL || configPage1.injLayout == INJ_SEQUENTIAL || configPage1.injLayout == INJ_PAIRED) //No full sequential for more than 4 cylinders @@ -638,7 +638,7 @@ void setup() } */ if (!configPage1.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = 0; } //For simultaneous, all squirts happen at the same time - + configPage1.injLayout = 0; //This is a failsafe. We can never run semi-sequential with more than 4 cylinders channel1InjEnabled = true; @@ -650,7 +650,7 @@ void setup() channel2IgnDegrees = 90; channel3IgnDegrees = 180; channel4IgnDegrees = 270; - + //For alternatiing injection, the squirt occurs at different times for each channel /* if(configPage1.injLayout == INJ_SEMISEQUENTIAL || configPage1.injTiming == INJ_SEQUENTIAL) //No full sequential for more than 4 cylinders @@ -662,7 +662,7 @@ void setup() } */ if (!configPage1.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = channel4InjDegrees = 0; } //For simultaneous, all squirts happen at the same time - + configPage1.injLayout = 0; //This is a failsafe. We can never run semi-sequential with more than 4 cylinders channel1InjEnabled = true; @@ -675,7 +675,7 @@ void setup() channel2InjDegrees = 180; break; } - + switch(configPage2.sparkMode) { case IGN_MODE_WASTED: @@ -691,7 +691,7 @@ void setup() ign5StartFunction = beginCoil5Charge; ign5EndFunction = endCoil5Charge; break; - + case IGN_MODE_SINGLE: //Single channel mode. All ignition pulses are on channel 1 ign1StartFunction = beginCoil1Charge; @@ -705,7 +705,7 @@ void setup() ign5StartFunction = beginCoil1Charge; ign5EndFunction = endCoil1Charge; break; - + case IGN_MODE_WASTEDCOP: //Wasted COP mode. Ignition channels 1&3 and 2&4 are paired together //This is not a valid mode for >4 cylinders @@ -715,7 +715,7 @@ void setup() ign1EndFunction = endCoil1and3Charge; ign2StartFunction = beginCoil2and4Charge; ign2EndFunction = endCoil2and4Charge; - + ign3StartFunction = nullCallback; ign3EndFunction = nullCallback; ign4StartFunction = nullCallback; @@ -748,8 +748,8 @@ void setup() ign4EndFunction = endCoil4Charge; ign5StartFunction = beginCoil5Charge; ign5EndFunction = endCoil5Charge; - break; - + break; + default: //Wasted spark (Shouldn't ever happen anyway) ign1StartFunction = beginCoil1Charge; @@ -764,7 +764,7 @@ void setup() ign5EndFunction = endCoil5Charge; break; } - + //Begin priming the fuel pump. This is turned off in the low resolution, 1s interrupt in timers.ino digitalWrite(pinFuelPump, HIGH); fuelPumpOn = true; @@ -773,15 +773,15 @@ void setup() setFuelSchedule2(openInjector2and3, 100, (unsigned long)(configPage1.primePulse * 100), closeInjector2and3); } -void loop() +void loop() { - mainLoopCount++; + mainLoopCount++; //Check for any requets from serial. Serial operations are checked under 2 scenarios: // 1) Every 64 loops (64 Is more than fast enough for TunerStudio). This function is equivalent to ((loopCount % 64) == 1) but is considerably faster due to not using the mod or division operations // 2) If the amount of data in the serial buffer is greater than a set threhold (See globals.h). This is to avoid serial buffer overflow when large amounts of data is being sent - if ( ((mainLoopCount & 31) == 1) or (Serial.available() > SERIAL_BUFFER_THRESHOLD) ) + if ( ((mainLoopCount & 31) == 1) or (Serial.available() > SERIAL_BUFFER_THRESHOLD) ) { - if (Serial.available() > 0) + if (Serial.available() > 0) { command(); } @@ -790,9 +790,9 @@ void loop() //if Can interface is enabled then check for serial3 requests. if (configPage1.canEnable) { - if ( ((mainLoopCount & 31) == 1) or (Serial3.available() > SERIAL_BUFFER_THRESHOLD) ) + if ( ((mainLoopCount & 31) == 1) or (Serial3.available() > SERIAL_BUFFER_THRESHOLD) ) { - if (Serial3.available() > 0) + if (Serial3.available() > 0) { canCommand(); } @@ -801,19 +801,19 @@ void loop() #endif // if (configPage1.displayType && (mainLoopCount & 255) == 1) { updateDisplay();} //Displays currently disabled - + previousLoopTime = currentLoopTime; currentLoopTime = micros(); unsigned long timeToLastTooth = (currentLoopTime - toothLastToothTime); if ( (timeToLastTooth < MAX_STALL_TIME) || (toothLastToothTime > currentLoopTime) ) //Check how long ago the last tooth was seen compared to now. If it was more than half a second ago then the engine is probably stopped. toothLastToothTime can be greater than currentLoopTime if a pulse occurs between getting the lastest time and doing the comparison { currentStatus.RPM = currentStatus.longRPM = getRPM(); //Long RPM is included here - if(fuelPumpOn == false) { digitalWrite(pinFuelPump, HIGH); fuelPumpOn = true; } //Check if the fuel pump is on and turn it on if it isn't. + if(fuelPumpOn == false) { digitalWrite(pinFuelPump, HIGH); fuelPumpOn = true; } //Check if the fuel pump is on and turn it on if it isn't. } else { //We reach here if the time between teeth is too great. This VERY likely means the engine has stopped - currentStatus.RPM = 0; + currentStatus.RPM = 0; currentStatus.PW1 = 0; currentStatus.VE = 0; toothLastToothTime = 0; @@ -829,34 +829,34 @@ void loop() fuelPumpOn = false; disableIdle(); //Turn off the idle PWM } - + //Uncomment the following for testing /* currentStatus.hasSync = true; currentStatus.RPM = 500; */ - + //***Perform sensor reads*** //----------------------------------------------------------------------------------------------------- readMAP(); - + //TPS setting to be performed every 32 loops (any faster and it can upset the TPSdot sampling time) if ((mainLoopCount & 31) == 1) { readTPS(); - + //Check for launching/flat shift (clutch) can be done around here too previousClutchTrigger = clutchTrigger; if(configPage3.launchHiLo) { clutchTrigger = digitalRead(pinLaunch); } - else { clutchTrigger = !digitalRead(pinLaunch); } + else { clutchTrigger = !digitalRead(pinLaunch); } if(previousClutchTrigger != clutchTrigger) { currentStatus.clutchEngagedRPM = currentStatus.RPM; } - - if (configPage3.launchEnabled && clutchTrigger && (currentStatus.clutchEngagedRPM < ((unsigned int)(configPage3.flatSArm) * 100)) && (currentStatus.RPM > ((unsigned int)(configPage3.lnchHardLim) * 100)) ) { currentStatus.launchingHard = true; BIT_SET(currentStatus.spark, BIT_SPARK_HLAUNCH); } //HardCut rev limit for 2-step launch control. + + if (configPage3.launchEnabled && clutchTrigger && (currentStatus.clutchEngagedRPM < ((unsigned int)(configPage3.flatSArm) * 100)) && (currentStatus.RPM > ((unsigned int)(configPage3.lnchHardLim) * 100)) ) { currentStatus.launchingHard = true; BIT_SET(currentStatus.spark, BIT_SPARK_HLAUNCH); } //HardCut rev limit for 2-step launch control. else { currentStatus.launchingHard = false; BIT_CLEAR(currentStatus.spark, BIT_SPARK_HLAUNCH); } if(configPage3.flatSEnable && clutchTrigger && (currentStatus.RPM > ((unsigned int)(configPage3.flatSArm) * 100)) && (currentStatus.RPM > currentStatus.clutchEngagedRPM) ) { currentStatus.flatShiftingHard = true; } - else { currentStatus.flatShiftingHard = false; } + else { currentStatus.flatShiftingHard = false; } //Boost cutoff is very similar to launchControl, but with a check against MAP rather than a switch if(configPage3.boostCutType && currentStatus.MAP > (configPage3.boostLimit * 2) ) //The boost limit is divided by 2 to allow a limit up to 511kPa @@ -882,7 +882,7 @@ void loop() BIT_CLEAR(currentStatus.spark, BIT_SPARK_BOOSTCUT); BIT_CLEAR(currentStatus.squirt, BIT_SQUIRT_BOOSTCUT); } - + //And check whether the tooth log buffer is ready if(toothHistoryIndex > TOOTH_LOG_SIZE) { BIT_SET(currentStatus.squirt, BIT_SQUIRT_TOOTHLOG1READY); } } @@ -894,13 +894,13 @@ void loop() readCLT(); readIAT(); readO2(); - readBat(); - + readBat(); + vvtControl(); boostControl(); //Most boost tends to run at about 30Hz, so placing it here ensures a new target time is fetched frequently enough - idleControl(); //Perform any idle related actions. Even at higher frequencies, running 4x per second is sufficient. + idleControl(); //Perform any idle related actions. Even at higher frequencies, running 4x per second is sufficient. } - if(configPage4.iacAlgorithm == 4) { idleControl(); } //Run idlecontrol every loop for stepper idle. + if(configPage4.iacAlgorithm == 4) { idleControl(); } //Run idlecontrol every loop for stepper idle. //Always check for sync //Main loop runs within this clause @@ -908,7 +908,7 @@ void loop() { if(currentStatus.startRevolutions >= configPage2.StgCycles) { ignitionOn = true; fuelOn = true;} //Enable the fuel and ignition, assuming staging revolutions are complete //If it is, check is we're running or cranking - if(currentStatus.RPM > ((unsigned int)configPage2.crankRPM * 100)) //Crank RPM stored in byte as RPM / 100 + if(currentStatus.RPM > ((unsigned int)configPage2.crankRPM * 100)) //Crank RPM stored in byte as RPM / 100 { BIT_SET(currentStatus.engine, BIT_ENGINE_RUN); //Sets the engine running bit //Only need to do anything if we're transitioning from cranking to running @@ -917,31 +917,31 @@ void loop() BIT_CLEAR(currentStatus.engine, BIT_ENGINE_CRANK); //clears the engine cranking bit if(configPage2.ignBypassEnabled) { digitalWrite(pinIgnBypass, HIGH); } } - } - else + } + else { //Sets the engine cranking bit, clears the engine running bit - BIT_SET(currentStatus.engine, BIT_ENGINE_CRANK); - BIT_CLEAR(currentStatus.engine, BIT_ENGINE_RUN); + BIT_SET(currentStatus.engine, BIT_ENGINE_CRANK); + BIT_CLEAR(currentStatus.engine, BIT_ENGINE_RUN); currentStatus.runSecs = 0; //We're cranking (hopefully), so reset the engine run time to prompt ASE. if(configPage2.ignBypassEnabled) { digitalWrite(pinIgnBypass, LOW); } - } - + } + //END SETTING STATUSES //----------------------------------------------------------------------------------------------------- - + //Begin the fuel calculation //Calculate an injector pulsewidth from the VE currentStatus.corrections = correctionsFuel(); //currentStatus.corrections = 100; if (configPage1.algorithm == 0) //Check which fuelling algorithm is being used - { + { //Speed Density currentStatus.VE = get3DTableValue(&fuelTable, currentStatus.MAP, currentStatus.RPM); //Perform lookup into fuel map for RPM vs MAP value currentStatus.PW1 = PW_SD(req_fuel_uS, currentStatus.VE, currentStatus.MAP, currentStatus.corrections, inj_opentime_uS); currentStatus.advance = get3DTableValue(&ignitionTable, currentStatus.MAP, currentStatus.RPM); //As above, but for ignition advance } else - { + { //Alpha-N currentStatus.VE = get3DTableValue(&fuelTable, currentStatus.TPS, currentStatus.RPM); //Perform lookup into fuel map for RPM vs TPS value currentStatus.PW1 = PW_AN(req_fuel_uS, currentStatus.VE, currentStatus.TPS, currentStatus.corrections, inj_opentime_uS); //Calculate pulsewidth using the Alpha-N algorithm (in uS) @@ -956,7 +956,7 @@ void loop() //Adjust the advance based on IAT. If the adjustment amount is greater than the current advance, just set advance to 0 byte advanceIATadjust = table2D_getValue(&IATRetardTable, currentStatus.IAT); if (advanceIATadjust <= currentStatus.advance) { currentStatus.advance -= advanceIATadjust; } - else { currentStatus.advance = 0; } + else { currentStatus.advance = 0; } */ int injector1StartAngle = 0; @@ -972,8 +972,8 @@ void loop() //These are used for comparisons on channels above 1 where the starting angle (for injectors or ignition) can be less than a single loop time //(Don't ask why this is needed, it will break your head) int tempCrankAngle; - int tempStartAngle; - + int tempStartAngle; + //******************************************************** //How fast are we going? Need to know how long (uS) it will take to get from one tooth to the next. We then use that to estimate how far we are between the last tooth and the next one //We use a 1st Deriv accleration prediction, but only when there is an even spacing between primary sensor teeth @@ -1001,23 +1001,25 @@ void loop() else { angle1 = angle2 = triggerToothAngle; } } else { angle1 = angle2 = triggerToothAngle; } - + long toothDeltaV = (1000000L * angle2 / toothHistory[toothHistoryIndex]) - (1000000L * angle1 / toothHistory[toothHistoryIndex-1]); long toothDeltaT = toothHistory[toothHistoryIndex]; //long timeToLastTooth = micros() - toothLastToothTime; //Cannot be unsigned - + rpmDelta = (toothDeltaV << 10) / (6 * toothDeltaT); - } - - + } + + timePerDegree = ldiv( 166666L, (currentStatus.RPM + rpmDelta)).quot; //There is a small amount of rounding in this calculation, however it is less than 0.001 of a uS (Faster as ldiv than / ) } else { long rpm_adjust = ((long)(micros() - toothOneTime) * (long)currentStatus.rpmDOT) / 1000000; //Take into account any likely accleration that has occurred since the last full revolution completed + + //timePerDegree = DIV_ROUND_CLOSEST(166666L, (currentStatus.RPM + rpm_adjust)); timePerDegree = ldiv( 166666L, currentStatus.RPM + rpm_adjust).quot; //There is a small amount of rounding in this calculation, however it is less than 0.001 of a uS (Faster as ldiv than / ) } - + //Check that the duty cycle of the chosen pulsewidth isn't too high. This is disabled at cranking if( !BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) { @@ -1025,16 +1027,16 @@ void loop() if (CRANK_ANGLE_MAX_INJ == 720) { pwLimit = pwLimit * 2; } //For sequential, the maximum pulse time is double (2 revolutions). Wouldn't work for 2 stroke... if (currentStatus.PW1 > pwLimit) { currentStatus.PW1 = pwLimit; } } - - + + //*********************************************************************************************** //BEGIN INJECTION TIMING //Determine next firing angles currentStatus.PW2 = currentStatus.PW3 = currentStatus.PW4 = currentStatus.PW1; // Initial state is for all pulsewidths to be the same (This gets changed below) int PWdivTimerPerDegree = div(currentStatus.PW1, timePerDegree).quot; //How many crank degrees the calculated PW will take at the current speed injector1StartAngle = configPage1.inj1Ang - ( PWdivTimerPerDegree ); //This is a little primitive, but is based on the idea that all fuel needs to be delivered before the inlet valve opens. See http://www.extraefi.co.uk/sequential_fuel.html for more detail - if(injector1StartAngle < 0) {injector1StartAngle += CRANK_ANGLE_MAX_INJ;} - + if(injector1StartAngle < 0) {injector1StartAngle += CRANK_ANGLE_MAX_INJ;} + //Repeat the above for each cylinder switch (configPage1.nCylinders) { @@ -1046,7 +1048,7 @@ void loop() //3 cylinders case 3: injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree )); - if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;} + if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;} injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree )); if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;} break; @@ -1068,7 +1070,7 @@ void loop() unsigned long pw2percent = 100 + (byte)get3DTableValue(&trim2Table, currentStatus.MAP, currentStatus.RPM) - OFFSET_FUELTRIM; unsigned long pw3percent = 100 + (byte)get3DTableValue(&trim3Table, currentStatus.MAP, currentStatus.RPM) - OFFSET_FUELTRIM; unsigned long pw4percent = 100 + (byte)get3DTableValue(&trim4Table, currentStatus.MAP, currentStatus.RPM) - OFFSET_FUELTRIM; - + if (pw1percent != 100) { currentStatus.PW1 = (pw1percent * currentStatus.PW1) / 100; } if (pw2percent != 100) { currentStatus.PW2 = (pw2percent * currentStatus.PW2) / 100; } if (pw3percent != 100) { currentStatus.PW3 = (pw3percent * currentStatus.PW3) / 100; } @@ -1088,16 +1090,16 @@ void loop() if(injector5StartAngle > CRANK_ANGLE_MAX_INJ) {injector5StartAngle -= CRANK_ANGLE_MAX_INJ;} break; //6 cylinders - case 6: + case 6: injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree )); - if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;} + if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;} injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree )); if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;} break; //8 cylinders - case 8: + case 8: injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree )); - if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;} + if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;} injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree )); if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;} injector4StartAngle = (configPage1.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree )); @@ -1107,13 +1109,13 @@ void loop() default: break; } - + //*********************************************************************************************** //| BEGIN IGNITION CALCULATIONS BIT_CLEAR(currentStatus.spark, BIT_SPARK_HRDLIM); if (currentStatus.RPM > ((unsigned int)(configPage2.HardRevLim) * 100) ) { BIT_SET(currentStatus.spark, BIT_SPARK_HRDLIM); } //Hardcut RPM limit - - + + //Set dwell //Dwell is stored as ms * 10. ie Dwell of 4.3ms would be 43 in configPage2. This number therefore needs to be multiplied by 100 to get dwell in uS if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) { currentStatus.dwell = (configPage2.dwellCrank * 100); } @@ -1122,12 +1124,12 @@ void loop() currentStatus.dwellCorrection = table2D_getValue(&dwellVCorrectionTable, currentStatus.battery10); if (currentStatus.dwellCorrection != 100) { currentStatus.dwell = divs100(currentStatus.dwell) * currentStatus.dwellCorrection; } int dwellAngle = (div(currentStatus.dwell, timePerDegree).quot ); //Convert the dwell time to dwell angle based on the current engine speed - + //Calculate start angle for each channel //1 cylinder (Everyone gets this) ignition1StartAngle = CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle; // 360 - desired advance angle - number of degrees the dwell will take - if(ignition1StartAngle < 0) {ignition1StartAngle += CRANK_ANGLE_MAX_IGN;} - + if(ignition1StartAngle < 0) {ignition1StartAngle += CRANK_ANGLE_MAX_IGN;} + //This test for more cylinders and do the same thing switch (configPage1.nCylinders) { @@ -1139,7 +1141,7 @@ void loop() //3 cylinders case 3: ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle; - if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} ignition3StartAngle = channel3IgnDegrees + 360 - currentStatus.advance - dwellAngle; if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;} break; @@ -1165,54 +1167,54 @@ void loop() ignition3StartAngle = channel3IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle; if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;} - + ignition4StartAngle = channel4IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle; if(ignition4StartAngle > CRANK_ANGLE_MAX_IGN) {ignition4StartAngle -= CRANK_ANGLE_MAX_IGN;} - + ignition5StartAngle = channel5IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle; if(ignition5StartAngle > CRANK_ANGLE_MAX_IGN) {ignition5StartAngle -= CRANK_ANGLE_MAX_IGN;} - + break; //6 cylinders case 6: ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle; - if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} ignition3StartAngle = channel3IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle; if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;} break; //8 cylinders case 8: ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle; - if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} ignition3StartAngle = channel3IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle; if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;} ignition4StartAngle = channel4IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle; if(ignition4StartAngle > CRANK_ANGLE_MAX_IGN) {ignition4StartAngle -= CRANK_ANGLE_MAX_IGN;} break; - + //Will hit the default case on 1 cylinder or >8 cylinders. Do nothing in these cases default: break; } - + //*********************************************************************************************** //| BEGIN FUEL SCHEDULES //Finally calculate the time (uS) until we reach the firing angles and set the schedules //We only need to set the shcedule if we're BEFORE the open angle //This may potentially be called a number of times as we get closer and closer to the opening time - + //Determine the current crank angle int crankAngle = getCrankAngle(timePerDegree); if (crankAngle > CRANK_ANGLE_MAX_INJ ) { crankAngle -= 360; } - + if (fuelOn && currentStatus.PW1 > 0 && !BIT_CHECK(currentStatus.squirt, BIT_SQUIRT_BOOSTCUT)) { if (injector1StartAngle <= crankAngle && fuelSchedule1.schedulesSet == 0) { injector1StartAngle += CRANK_ANGLE_MAX_INJ; } if (injector1StartAngle > crankAngle) - { + { if (configPage1.injLayout == INJ_SEMISEQUENTIAL) { - setFuelSchedule1(openInjector1and4, + setFuelSchedule1(openInjector1and4, ((unsigned long)(injector1StartAngle - crankAngle) * (unsigned long)timePerDegree), (unsigned long)currentStatus.PW1, closeInjector1and4 @@ -1220,14 +1222,14 @@ void loop() } else { - setFuelSchedule1(openInjector1, + setFuelSchedule1(openInjector1, ((unsigned long)(injector1StartAngle - crankAngle) * (unsigned long)timePerDegree), (unsigned long)currentStatus.PW1, closeInjector1 ); } } - + /*----------------------------------------------------------------------------------------- | A Note on tempCrankAngle and tempStartAngle: | The use of tempCrankAngle/tempStartAngle is described below. It is then used in the same way for channels 2, 3 and 4 on both injectors and ignition @@ -1235,7 +1237,7 @@ void loop() | Eg: If cylinder 2 TDC is 180 degrees after cylinder 1 (Eg a standard 4 cylidner engine), then tempCrankAngle is 180* less than the current crank angle and | tempStartAngle is the desired open time less 180*. Thus the cylinder is being treated relative to its own TDC, regardless of its offset | - | This is done to avoid problems with very short of very long times until tempStartAngle. + | This is done to avoid problems with very short of very long times until tempStartAngle. | This will very likely need to be rewritten when sequential is enabled |------------------------------------------------------------------------------------------ */ @@ -1247,10 +1249,10 @@ void loop() if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; } if (tempStartAngle <= tempCrankAngle && fuelSchedule2.schedulesSet == 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; } if ( tempStartAngle > tempCrankAngle ) - { + { if (configPage1.injLayout == 1) { - setFuelSchedule2(openInjector2and3, + setFuelSchedule2(openInjector2and3, ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), (unsigned long)currentStatus.PW2, closeInjector2and3 @@ -1258,7 +1260,7 @@ void loop() } else { - setFuelSchedule2(openInjector2, + setFuelSchedule2(openInjector2, ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), (unsigned long)currentStatus.PW2, closeInjector2 @@ -1275,8 +1277,8 @@ void loop() if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; } if (tempStartAngle <= tempCrankAngle && fuelSchedule3.schedulesSet == 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; } if ( tempStartAngle > tempCrankAngle ) - { - setFuelSchedule3(openInjector3, + { + setFuelSchedule3(openInjector3, ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), (unsigned long)currentStatus.PW3, closeInjector3 @@ -1292,8 +1294,8 @@ void loop() if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; } if (tempStartAngle <= tempCrankAngle && fuelSchedule4.schedulesSet == 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; } if ( tempStartAngle > tempCrankAngle ) - { - setFuelSchedule4(openInjector4, + { + setFuelSchedule4(openInjector4, ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), (unsigned long)currentStatus.PW4, closeInjector4 @@ -1309,9 +1311,9 @@ void loop() if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; } if (tempStartAngle <= tempCrankAngle && fuelSchedule5.schedulesSet == 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; } if ( tempStartAngle > tempCrankAngle ) - { + { //Note the hacky use of fuel schedule 3 below - setFuelSchedule3(openInjector3and5, + setFuelSchedule3(openInjector3and5, ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), (unsigned long)currentStatus.PW1, closeInjector3and5 @@ -1322,10 +1324,8 @@ void loop() //*********************************************************************************************** //| BEGIN IGNITION SCHEDULES //Likewise for the ignition - crankAngle = getCrankAngle(timePerDegree); //Refresh with the latest crank angle - if (crankAngle > CRANK_ANGLE_MAX_IGN ) { crankAngle -= 360; } - //fixedCrankingOverride is used to extend the dwell during cranking so that the decoder can trigger the spark upon seeing a certain tooth. Currently only available on the basic distributor and 4g63 decoders. + //fixedCrankingOverride is used to extend the dwell during cranking so that the decoder can trigger the spark upon seeing a certain tooth. Currently only available on the basic distributor and 4g63 decoders. if ( configPage2.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) { fixedCrankingOverride = currentStatus.dwell * 2; } else { fixedCrankingOverride = 0; } @@ -1333,7 +1333,12 @@ void loop() //Check for hard cut rev limit (If we're above the hardcut limit, we simply don't set a spark schedule) if(ignitionOn && !currentStatus.launchingHard && !BIT_CHECK(currentStatus.spark, BIT_SPARK_BOOSTCUT) && !BIT_CHECK(currentStatus.spark, BIT_SPARK_HRDLIM) && !currentStatus.flatShiftingHard) { - + + //Refresh the current crank angle info + //ignition1StartAngle = 335; + crankAngle = getCrankAngle(timePerDegree); //Refresh with the latest crank angle + if (crankAngle > CRANK_ANGLE_MAX_IGN ) { crankAngle -= 360; } + //if (ignition1StartAngle <= crankAngle && ignition1.schedulesSet == 0) { ignition1StartAngle += CRANK_ANGLE_MAX_IGN; } if (ignition1StartAngle > crankAngle) { @@ -1341,13 +1346,12 @@ void loop() long some_time = ((unsigned long)(ignition1StartAngle - crankAngle) * (unsigned long)timePerDegree); long newRPM = (long)(some_time * currentStatus.rpmDOT) / 1000000L; newRPM = currentStatus.RPM + (newRPM/2); - unsigned long timePerDegree_1 = ldiv( 166666L, newRPM).quot;*/ - - setIgnitionSchedule1(ign1StartFunction, - ((unsigned long)(ignition1StartAngle - crankAngle) * (unsigned long)timePerDegree), - //some_time -some_accel, - //((unsigned long)((unsigned long)currentStatus.dwell* currentStatus.RPM) / newRPM) + fixedCrankingOverride, - currentStatus.dwell + fixedCrankingOverride, + unsigned long timePerDegree_1 = ldiv( 166666L, newRPM).quot; + unsigned long timeout = (unsigned long)(ignition1StartAngle - crankAngle) * 282UL; + */ + setIgnitionSchedule1(ign1StartFunction, + ((unsigned long)(ignition1StartAngle - crankAngle) * (unsigned long)timePerDegree), //(timeout/10), + currentStatus.dwell + fixedCrankingOverride, //((unsigned long)((unsigned long)currentStatus.dwell* currentStatus.RPM) / newRPM) + fixedCrankingOverride, ign1EndFunction ); } @@ -1358,55 +1362,55 @@ void loop() if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_IGN; } //if ( (tempStartAngle > tempCrankAngle) && ign2LastRev != startRevolutions) //if ( ign2LastRev != startRevolutions ) - { + { unsigned long ignition2StartTime = 0; if(tempStartAngle > tempCrankAngle) { ignition2StartTime = ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree); } //else if (tempStartAngle < tempCrankAngle) { ignition2StartTime = ((long)(360 - tempCrankAngle + tempStartAngle) * (long)timePerDegree); } else { ignition2StartTime = 0; } - + if(ignition2StartTime > 0) { - setIgnitionSchedule2(ign2StartFunction, + setIgnitionSchedule2(ign2StartFunction, ignition2StartTime, currentStatus.dwell + fixedCrankingOverride, ign2EndFunction ); } } - + tempCrankAngle = crankAngle - channel3IgnDegrees; if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_IGN; } tempStartAngle = ignition3StartAngle - channel3IgnDegrees; if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_IGN; } //if (tempStartAngle > tempCrankAngle) - { + { long ignition3StartTime = 0; if(tempStartAngle > tempCrankAngle) { ignition3StartTime = ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree); } //else if (tempStartAngle < tempCrankAngle) { ignition4StartTime = ((long)(360 - tempCrankAngle + tempStartAngle) * (long)timePerDegree); } else { ignition3StartTime = 0; } - + if(ignition3StartTime > 0) { - setIgnitionSchedule3(ign3StartFunction, + setIgnitionSchedule3(ign3StartFunction, ignition3StartTime, currentStatus.dwell + fixedCrankingOverride, ign3EndFunction ); } } - + tempCrankAngle = crankAngle - channel4IgnDegrees; if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_IGN; } tempStartAngle = ignition4StartAngle - channel4IgnDegrees; if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_IGN; } //if (tempStartAngle > tempCrankAngle) - { - + { + long ignition4StartTime = 0; if(tempStartAngle > tempCrankAngle) { ignition4StartTime = ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree); } //else if (tempStartAngle < tempCrankAngle) { ignition4StartTime = ((long)(360 - tempCrankAngle + tempStartAngle) * (long)timePerDegree); } else { ignition4StartTime = 0; } - + if(ignition4StartTime > 0) { - setIgnitionSchedule4(ign4StartFunction, + setIgnitionSchedule4(ign4StartFunction, ignition4StartTime, currentStatus.dwell + fixedCrankingOverride, ign4EndFunction @@ -1419,23 +1423,23 @@ void loop() tempStartAngle = ignition5StartAngle - channel5IgnDegrees; if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_IGN; } //if (tempStartAngle > tempCrankAngle) - { - + { + long ignition5StartTime = 0; if(tempStartAngle > tempCrankAngle) { ignition5StartTime = ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree); } //else if (tempStartAngle < tempCrankAngle) { ignition4StartTime = ((long)(360 - tempCrankAngle + tempStartAngle) * (long)timePerDegree); } else { ignition5StartTime = 0; } - + if(ignition5StartTime > 0) { - setIgnitionSchedule5(ign5StartFunction, + setIgnitionSchedule5(ign5StartFunction, ignition5StartTime, currentStatus.dwell + fixedCrankingOverride, ign5EndFunction ); } } - + } - + } }