From dfa48ed250e5e4af1105f4f7fb09f26cab3a9b9b Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Mon, 5 Feb 2018 09:39:46 +1100 Subject: [PATCH 1/8] Fix for rare overflow issue that could cause an incorrect pulse width at very low RPM (<200rpm) --- reference/speeduino.ini | 2 +- speeduino/scheduler.h | 4 ++-- speeduino/scheduler.ino | 36 +++++++++++++++++++----------------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/reference/speeduino.ini b/reference/speeduino.ini index 6a9133ed..af0c8ccf 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -1,4 +1,4 @@ -;------------------------------------------------------------------------------- +;------------------------------------------------------------------------------- #unset CAN_COMMANDS #unset enablehardware_test diff --git a/speeduino/scheduler.h b/speeduino/scheduler.h index d308f4f8..d94541ce 100644 --- a/speeduino/scheduler.h +++ b/speeduino/scheduler.h @@ -412,8 +412,8 @@ struct Schedule { void (*StartCallback)(); //Start Callback function for schedule void (*EndCallback)(); //Start Callback function for schedule volatile unsigned long startTime; //The system time (in uS) that the schedule started - volatile unsigned int startCompare; //The counter value of the timer when this will start - volatile unsigned int endCompare; + volatile uint16_t startCompare; //The counter value of the timer when this will start + volatile uint16_t endCompare; unsigned int nextStartCompare; unsigned int nextEndCompare; diff --git a/speeduino/scheduler.ino b/speeduino/scheduler.ino index 4ead737f..a6493f08 100644 --- a/speeduino/scheduler.ino +++ b/speeduino/scheduler.ino @@ -290,13 +290,13 @@ void setFuelSchedule(struct Schedule *targetSchedule, unsigned long timeout, uns //Need to check that the timeout doesn't exceed the overflow uint16_t timeout_timer_compare; - if (timeout > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (MAX_TIMER_PERIOD_SLOW - 1) ); } // If the timeout is >16x (Each tick represents 16uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking. - else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case + if (timeout > MAX_TIMER_PERIOD) { timeout_timer_compare = uS_TO_TIMER_COMPARE( (MAX_TIMER_PERIOD - 1) ); } // If the timeout is >16x (Each tick represents 16uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking. + else { timeout_timer_compare = uS_TO_TIMER_COMPARE(timeout); } //Normal case //The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set noInterrupts(); targetSchedule->startCompare = *targetSchedule->counter + timeout_timer_compare; - targetSchedule->endCompare = targetSchedule->startCompare + uS_TO_TIMER_COMPARE_SLOW(duration); + targetSchedule->endCompare = targetSchedule->startCompare + uS_TO_TIMER_COMPARE(duration); targetSchedule->Status = PENDING; //Turn this schedule on targetSchedule->schedulesSet++; //Increment the number of times this schedule has been set @@ -308,8 +308,8 @@ void setFuelSchedule(struct Schedule *targetSchedule, unsigned long timeout, uns { //If the schedule is already running, we can set the next schedule so it is ready to go //This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule - targetSchedule->nextStartCompare = *targetSchedule->counter + uS_TO_TIMER_COMPARE_SLOW(timeout); - targetSchedule->nextEndCompare = targetSchedule->nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration); + targetSchedule->nextStartCompare = *targetSchedule->counter + uS_TO_TIMER_COMPARE(timeout); + targetSchedule->nextEndCompare = targetSchedule->nextStartCompare + uS_TO_TIMER_COMPARE(duration); targetSchedule->hasNextSchedule = true; } } @@ -327,7 +327,7 @@ void setFuelSchedule1(unsigned long timeout, unsigned long duration) //Need to check that the timeout doesn't exceed the overflow uint16_t timeout_timer_compare; - if (timeout > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (MAX_TIMER_PERIOD_SLOW - 1) ); } // If the timeout is >16x (Each tick represents 16uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking. + if ((timeout+duration) > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (MAX_TIMER_PERIOD_SLOW - 1 - duration) ); } // If the timeout is >16x (Each tick represents 16uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking. else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case //The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set @@ -350,7 +350,8 @@ void setFuelSchedule1(unsigned long timeout, unsigned long duration) //This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule fuelSchedule1.nextStartCompare = FUEL1_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout); fuelSchedule1.nextEndCompare = fuelSchedule1.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration); - fuelSchedule1.hasNextSchedule = true; + fuelSchedule1.duration = duration; + fuelSchedule1.hasNextSchedule = false; } } @@ -766,7 +767,7 @@ static inline void fuelSchedule1Interrupt() //Most ARM chips can simply call a f if (configPage2.injLayout == INJ_SEMISEQUENTIAL) { openInjector1and4(); } else { openInjector1(); } fuelSchedule1.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) - FUEL1_COMPARE = fuelSchedule1.endCompare; + FUEL1_COMPARE = FUEL1_COUNTER + uS_TO_TIMER_COMPARE_SLOW(fuelSchedule1.duration); //Doing this here prevents a potential overflow on restarts } else if (fuelSchedule1.Status == RUNNING) { @@ -803,7 +804,7 @@ static inline void fuelSchedule2Interrupt() //Most ARM chips can simply call a f if (configPage2.injLayout == INJ_SEMISEQUENTIAL) { openInjector2and3(); } else { openInjector2(); } fuelSchedule2.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) - FUEL2_COMPARE = fuelSchedule2.endCompare; + FUEL2_COMPARE = FUEL2_COUNTER + uS_TO_TIMER_COMPARE_SLOW(fuelSchedule2.duration); //Doing this here prevents a potential overflow on restarts } else if (fuelSchedule2.Status == RUNNING) { @@ -839,7 +840,7 @@ static inline void fuelSchedule3Interrupt() //Most ARM chips can simply call a f if(channel5InjEnabled) { openInjector3and5(); } else { openInjector3(); } fuelSchedule3.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) - FUEL3_COMPARE = fuelSchedule3.endCompare; + FUEL3_COMPARE = FUEL3_COUNTER + uS_TO_TIMER_COMPARE_SLOW(fuelSchedule3.duration); //Doing this here prevents a potential overflow on restarts } else if (fuelSchedule3.Status == RUNNING) { @@ -874,7 +875,7 @@ static inline void fuelSchedule4Interrupt() //Most ARM chips can simply call a f //fuelSchedule4.StartCallback(); openInjector4(); fuelSchedule4.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) - FUEL4_COMPARE = fuelSchedule4.endCompare; + FUEL4_COMPARE = FUEL4_COUNTER + uS_TO_TIMER_COMPARE_SLOW(fuelSchedule4.duration); //Doing this here prevents a potential overflow on restarts } else if (fuelSchedule4.Status == RUNNING) { @@ -942,11 +943,12 @@ static inline void ignitionSchedule1Interrupt() //Most ARM chips can simply call ignitionSchedule1.StartCallback(); ignitionSchedule1.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) ignitionSchedule1.startTime = micros(); - IGN1_COMPARE = ignitionSchedule1.endCompare; + //IGN1_COMPARE = ignitionSchedule1.endCompare; + IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE(ignitionSchedule1.duration); //Doing this here prevents a potential overflow on restarts //This code is all to do with the staged ignition timing testing. That is, calling this interrupt slightly before the true ignition point and recalculating the end time for more accuracy //IGN1_COMPARE = ignitionSchedule1.endCompare - 50; //ignitionSchedule1.Status = STAGED; - } + } else if (ignitionSchedule1.Status == STAGED) { int16_t crankAngle = getCrankAngle(timePerDegree); @@ -980,7 +982,7 @@ static inline void ignitionSchedule2Interrupt() //Most ARM chips can simply call ignitionSchedule2.StartCallback(); ignitionSchedule2.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) ignitionSchedule2.startTime = micros(); - IGN2_COMPARE = ignitionSchedule2.endCompare; //OCR5B = TCNT5 + (ignitionSchedule2.duration >> 2); + IGN2_COMPARE = IGN2_COUNTER + uS_TO_TIMER_COMPARE(ignitionSchedule2.duration); //Doing this here prevents a potential overflow on restarts } else if (ignitionSchedule2.Status == RUNNING) { @@ -1003,7 +1005,7 @@ static inline void ignitionSchedule3Interrupt() //Most ARM chips can simply call ignitionSchedule3.StartCallback(); ignitionSchedule3.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) ignitionSchedule3.startTime = micros(); - IGN3_COMPARE = ignitionSchedule3.endCompare; //OCR5C = TCNT5 + (ignitionSchedule3.duration >> 2); + IGN3_COMPARE = IGN3_COUNTER + uS_TO_TIMER_COMPARE(ignitionSchedule3.duration); //Doing this here prevents a potential overflow on restarts } else if (ignitionSchedule3.Status == RUNNING) { @@ -1036,7 +1038,7 @@ static inline void ignitionSchedule4Interrupt() //Most ARM chips can simply call ignitionSchedule4.StartCallback(); ignitionSchedule4.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) ignitionSchedule4.startTime = micros(); - IGN4_COMPARE = ignitionSchedule4.endCompare; + IGN4_COMPARE = IGN4_COUNTER + uS_TO_TIMER_COMPARE_SLOW(ignitionSchedule4.duration); //Doing this here prevents a potential overflow on restarts } else if (ignitionSchedule4.Status == RUNNING) { @@ -1069,7 +1071,7 @@ static inline void ignitionSchedule5Interrupt() //Most ARM chips can simply call ignitionSchedule5.StartCallback(); ignitionSchedule5.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) ignitionSchedule5.startTime = micros(); - IGN5_COMPARE = ignitionSchedule5.endCompare; + IGN5_COMPARE = IGN5_COUNTER + uS_TO_TIMER_COMPARE_SLOW(ignitionSchedule5.duration); //Doing this here prevents a potential overflow on restarts } else if (ignitionSchedule5.Status == RUNNING) { From 725b93e0835039f6e0c10a4baffa58eaa4cb1a3f Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Mon, 5 Feb 2018 12:44:24 +1100 Subject: [PATCH 2/8] Add additional caching on 2D table lookups --- speeduino/table.ino | 194 +++++++++++++++++++++++--------------------- 1 file changed, 101 insertions(+), 93 deletions(-) diff --git a/speeduino/table.ino b/speeduino/table.ino index 95964b03..eb1f6479 100644 --- a/speeduino/table.ino +++ b/speeduino/table.ino @@ -59,111 +59,119 @@ int table2D_getValue(struct table2D *fromTable, int X_in) bool valueFound = false; int X = X_in; - int xMinValue, xMaxValue; - if (fromTable->valueSize == SIZE_BYTE) - { - //Byte version - xMinValue = fromTable->axisX[0]; - xMaxValue = fromTable->axisX[fromTable->xSize-1]; - } - else - { - //int version - xMinValue = fromTable->axisX16[0]; - xMaxValue = fromTable->axisX16[fromTable->xSize-1]; - } int xMin = 0; int xMax = 0; - //If the requested X value is greater/small than the maximum/minimum bin, reset X to be that value - if(X > xMaxValue) { X = xMaxValue; } - if(X < xMinValue) { X = xMinValue; } - - - if (fromTable->valueSize == SIZE_BYTE) + //Check whether the X input is the same as last time this ran + if(X_in == fromTable->lastInput) { - //**** Byte version **** - - //1st check is whether we're still in the same X bin as last time - if ( (X <= fromTable->axisX[fromTable->lastXMax]) && (X > fromTable->axisX[fromTable->lastXMin]) ) - { - xMaxValue = fromTable->axisX[fromTable->lastXMax]; - xMinValue = fromTable->axisX[fromTable->lastXMin]; - xMax = fromTable->lastXMax; - xMin = fromTable->lastXMin; - } - else - { - //If we're not in the same bin, loop through to find where we are - for (int x = fromTable->xSize-1; x >= 0; x--) - { - //Checks the case where the X value is exactly what was requested - if ( (X == fromTable->axisX[x]) || (x == 0) ) - { - returnValue = fromTable->values[x]; //Simply return the coresponding value - valueFound = true; - break; - } - else - { - //Normal case - if ( (X <= fromTable->axisX[x]) && (X > fromTable->axisX[x-1]) ) - { - xMaxValue = fromTable->axisX[x]; - xMinValue = fromTable->axisX[x-1]; - xMax = x; - fromTable->lastXMax = xMax; - xMin = x-1; - fromTable->lastXMin = xMin; - break; - } - } - } - } + returnValue = fromTable->lastOutput; + valueFound = true; } else { - // **** INT VERSION **** + if (fromTable->valueSize == SIZE_BYTE) + { + //Byte version + xMinValue = fromTable->axisX[0]; + xMaxValue = fromTable->axisX[fromTable->xSize-1]; + } + else + { + //int version + xMinValue = fromTable->axisX16[0]; + xMaxValue = fromTable->axisX16[fromTable->xSize-1]; + } - //1st check is whether we're still in the same X bin as last time - if ( (X <= fromTable->axisX16[fromTable->lastXMax]) && (X > fromTable->axisX16[fromTable->lastXMin]) ) - { - xMaxValue = fromTable->axisX16[fromTable->lastXMax]; - xMinValue = fromTable->axisX16[fromTable->lastXMin]; - xMax = fromTable->lastXMax; - xMin = fromTable->lastXMin; - } - else - { - //If we're not in the same bin, loop through to find where we are - for (int x = fromTable->xSize-1; x >= 0; x--) - { - //Checks the case where the X value is exactly what was requested - if ( (X == fromTable->axisX16[x]) || (x == 0) ) - { - returnValue = fromTable->values16[x]; //Simply return the coresponding value - valueFound = true; - break; - } - else - { - //Normal case - if ( (X <= fromTable->axisX16[x]) && (X > fromTable->axisX16[x-1]) ) + //If the requested X value is greater/small than the maximum/minimum bin, reset X to be that value + if(X > xMaxValue) { X = xMaxValue; } + if(X < xMinValue) { X = xMinValue; } + + + if (fromTable->valueSize == SIZE_BYTE) + { + //**** Byte version **** + + //1st check is whether we're still in the same X bin as last time + if ( (X <= fromTable->axisX[fromTable->lastXMax]) && (X > fromTable->axisX[fromTable->lastXMin]) ) + { + xMaxValue = fromTable->axisX[fromTable->lastXMax]; + xMinValue = fromTable->axisX[fromTable->lastXMin]; + xMax = fromTable->lastXMax; + xMin = fromTable->lastXMin; + } + else + { + //If we're not in the same bin, loop through to find where we are + for (int x = fromTable->xSize-1; x >= 0; x--) + { + //Checks the case where the X value is exactly what was requested + if ( (X == fromTable->axisX[x]) || (x == 0) ) { - xMaxValue = fromTable->axisX16[x]; - xMinValue = fromTable->axisX16[x-1]; - xMax = x; - fromTable->lastXMax = xMax; - xMin = x-1; - fromTable->lastXMin = xMin; + returnValue = fromTable->values[x]; //Simply return the coresponding value + valueFound = true; break; - } //Found in loop - } //Exact hit - } //For loop - } + } + else + { + //Normal case + if ( (X <= fromTable->axisX[x]) && (X > fromTable->axisX[x-1]) ) + { + xMaxValue = fromTable->axisX[x]; + xMinValue = fromTable->axisX[x-1]; + xMax = x; + fromTable->lastXMax = xMax; + xMin = x-1; + fromTable->lastXMin = xMin; + break; + } + } + } + } + } + else + { + // **** INT VERSION **** - } + //1st check is whether we're still in the same X bin as last time + if ( (X <= fromTable->axisX16[fromTable->lastXMax]) && (X > fromTable->axisX16[fromTable->lastXMin]) ) + { + xMaxValue = fromTable->axisX16[fromTable->lastXMax]; + xMinValue = fromTable->axisX16[fromTable->lastXMin]; + xMax = fromTable->lastXMax; + xMin = fromTable->lastXMin; + } + else + { + //If we're not in the same bin, loop through to find where we are + for (int x = fromTable->xSize-1; x >= 0; x--) + { + //Checks the case where the X value is exactly what was requested + if ( (X == fromTable->axisX16[x]) || (x == 0) ) + { + returnValue = fromTable->values16[x]; //Simply return the coresponding value + valueFound = true; + break; + } + else + { + //Normal case + if ( (X <= fromTable->axisX16[x]) && (X > fromTable->axisX16[x-1]) ) + { + xMaxValue = fromTable->axisX16[x]; + xMinValue = fromTable->axisX16[x-1]; + xMax = x; + fromTable->lastXMax = xMax; + xMin = x-1; + fromTable->lastXMin = xMin; + break; + } //Found in loop + } //Exact hit + } //For loop + } //In cache or not + } //byte or int values + } //X_in same as last time if (valueFound == false) { From 8b7f0c345b071b9b726bb1cc47b8e703f1045f95 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Mon, 5 Feb 2018 12:44:38 +1100 Subject: [PATCH 3/8] Add a loops/rev counter in TS --- reference/speeduino.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/reference/speeduino.ini b/reference/speeduino.ini index af0c8ccf..ba910b7c 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -2393,6 +2393,7 @@ cmdtestspk450dc = "E\x03\x0C" boostCutOut = { boostCutFuel || boostCutSpark } lambda = { afr / stoich } MAPxRPM = { rpm * map } + loopsPerRev = { loopsPerSecond / (rpm / 60) } ;Manifold pressure in weirdo units map_bar = { (map - baro) / 101.33 } From c038ebb1d7317221508c1984d0ec37367081b9b7 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Mon, 5 Feb 2018 16:13:26 +1100 Subject: [PATCH 4/8] Fix bug that prevents the per tooth based timing from functioning --- speeduino/speeduino.ino | 68 +++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index aaa36d03..cf47f2bd 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -1248,6 +1248,7 @@ void loop() //Calculate start angle for each channel //1 cylinder (Everyone gets this) ignition1EndAngle = CRANK_ANGLE_MAX_IGN - currentStatus.advance; + if(ignition1EndAngle > CRANK_ANGLE_MAX_IGN) {ignition1EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition1StartAngle = ignition1EndAngle - dwellAngle; // 360 - desired advance angle - number of degrees the dwell will take if(ignition1StartAngle < 0) {ignition1StartAngle += CRANK_ANGLE_MAX_IGN;} @@ -1256,35 +1257,41 @@ void loop() { //2 cylinders case 2: - ignition2EndAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition2EndAngle = channel2IgnDegrees - currentStatus.advance; + if(ignition2EndAngle > CRANK_ANGLE_MAX_IGN) {ignition2EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition2StartAngle = ignition2EndAngle - dwellAngle; - if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition2StartAngle < 0) {ignition2StartAngle += CRANK_ANGLE_MAX_IGN;} break; //3 cylinders case 3: - ignition2EndAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition2EndAngle = channel2IgnDegrees - currentStatus.advance; + if(ignition2EndAngle > CRANK_ANGLE_MAX_IGN) {ignition2EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition2StartAngle = ignition2EndAngle - dwellAngle; - if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} - ignition3EndAngle = channel3IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + if(ignition2StartAngle < 0) {ignition2StartAngle += CRANK_ANGLE_MAX_IGN;} + + ignition3EndAngle = channel3IgnDegrees - currentStatus.advance; + if(ignition3EndAngle > CRANK_ANGLE_MAX_IGN) {ignition3EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition3StartAngle = channel3IgnDegrees + 360 - currentStatus.advance - dwellAngle; - if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition3StartAngle < 0) {ignition3StartAngle += CRANK_ANGLE_MAX_IGN;} break; //4 cylinders case 4: - ignition2EndAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition2EndAngle = channel2IgnDegrees - currentStatus.advance; + if(ignition2EndAngle > CRANK_ANGLE_MAX_IGN) {ignition2EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition2StartAngle = ignition2EndAngle - dwellAngle; - if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} if(ignition2StartAngle < 0) {ignition2StartAngle += CRANK_ANGLE_MAX_IGN;} if(configPage4.sparkMode == IGN_MODE_SEQUENTIAL) { - ignition3EndAngle = channel3IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition3EndAngle = channel3IgnDegrees - currentStatus.advance; + if(ignition3EndAngle > CRANK_ANGLE_MAX_IGN) {ignition3EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition3StartAngle = ignition3EndAngle - dwellAngle; - if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition3StartAngle < 0) {ignition3StartAngle += CRANK_ANGLE_MAX_IGN;} - ignition4EndAngle = channel4IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition4EndAngle = channel4IgnDegrees - currentStatus.advance; + if(ignition4EndAngle > CRANK_ANGLE_MAX_IGN) {ignition4EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition4StartAngle = ignition4EndAngle - dwellAngle; - if(ignition4StartAngle > CRANK_ANGLE_MAX_IGN) {ignition4StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition4StartAngle < 0) {ignition4StartAngle += CRANK_ANGLE_MAX_IGN;} } else if(configPage4.sparkMode == IGN_MODE_ROTARY) { @@ -1309,18 +1316,20 @@ void loop() break; //5 cylinders case 5: - ignition2EndAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition2EndAngle = channel2IgnDegrees - currentStatus.advance; + if(ignition2EndAngle > CRANK_ANGLE_MAX_IGN) {ignition2EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition2StartAngle = ignition2EndAngle - dwellAngle; - if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} if(ignition2StartAngle < 0) {ignition2StartAngle += CRANK_ANGLE_MAX_IGN;} - ignition3EndAngle = channel3IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition3EndAngle = channel3IgnDegrees - currentStatus.advance; + if(ignition3EndAngle > CRANK_ANGLE_MAX_IGN) {ignition3EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition3StartAngle = ignition3EndAngle - dwellAngle; - if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition3StartAngle < 0) {ignition3StartAngle += CRANK_ANGLE_MAX_IGN;} ignition4EndAngle = channel4IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + if(ignition4EndAngle > CRANK_ANGLE_MAX_IGN) {ignition4EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition4StartAngle = ignition4EndAngle - dwellAngle; - if(ignition4StartAngle > CRANK_ANGLE_MAX_IGN) {ignition4StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition4StartAngle < 0) {ignition4StartAngle += CRANK_ANGLE_MAX_IGN;} ignition5StartAngle = channel5IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle; if(ignition5StartAngle > CRANK_ANGLE_MAX_IGN) {ignition5StartAngle -= CRANK_ANGLE_MAX_IGN;} @@ -1328,27 +1337,32 @@ void loop() break; //6 cylinders case 6: - ignition2EndAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition2EndAngle = channel2IgnDegrees - currentStatus.advance; + if(ignition2EndAngle > CRANK_ANGLE_MAX_IGN) {ignition2EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition2StartAngle = ignition2EndAngle - dwellAngle; - if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition2StartAngle < 0) {ignition2StartAngle += CRANK_ANGLE_MAX_IGN;} - ignition3EndAngle = channel3IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition3EndAngle = channel3IgnDegrees - currentStatus.advance; + if(ignition3EndAngle > CRANK_ANGLE_MAX_IGN) {ignition3EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition3StartAngle = ignition3EndAngle - dwellAngle; - if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition3StartAngle < 0) {ignition3StartAngle += CRANK_ANGLE_MAX_IGN;} break; //8 cylinders case 8: - ignition2EndAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition2EndAngle = channel2IgnDegrees - currentStatus.advance; + if(ignition2EndAngle > CRANK_ANGLE_MAX_IGN) {ignition2EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition2StartAngle = ignition2EndAngle - dwellAngle; - if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition2StartAngle < 0) {ignition2StartAngle += CRANK_ANGLE_MAX_IGN;} - ignition3EndAngle = channel3IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition3EndAngle = channel3IgnDegrees - currentStatus.advance; + if(ignition3EndAngle > CRANK_ANGLE_MAX_IGN) {ignition3EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition3StartAngle = ignition3EndAngle - dwellAngle; - if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition3StartAngle < 0) {ignition3StartAngle += CRANK_ANGLE_MAX_IGN;} - ignition4EndAngle = channel4IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance; + ignition4EndAngle = channel4IgnDegrees - currentStatus.advance; + if(ignition4EndAngle > CRANK_ANGLE_MAX_IGN) {ignition4EndAngle -= CRANK_ANGLE_MAX_IGN;} ignition4StartAngle = ignition4EndAngle - dwellAngle; - if(ignition4StartAngle > CRANK_ANGLE_MAX_IGN) {ignition4StartAngle -= CRANK_ANGLE_MAX_IGN;} + if(ignition4StartAngle < 0) {ignition4StartAngle += CRANK_ANGLE_MAX_IGN;} break; //Will hit the default case on 1 cylinder or >8 cylinders. Do nothing in these cases From 0c5b3ef00654d78af0f051e561c4071a10759bcb Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Mon, 5 Feb 2018 17:31:22 +1100 Subject: [PATCH 5/8] Add a 1s cache timeout for the 2D table caches --- speeduino/table.h | 1 + speeduino/table.ino | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/speeduino/table.h b/speeduino/table.h index a178a489..1202bea4 100644 --- a/speeduino/table.h +++ b/speeduino/table.h @@ -29,6 +29,7 @@ struct table2D { //Store the last input and output for caching int16_t lastInput; int16_t lastOutput; + byte cacheTime; //TRacks when the last cache value was set so it can expire after x seconds }; void table2D_setSize(struct table2D targetTable, byte newSize); diff --git a/speeduino/table.ino b/speeduino/table.ino index eb1f6479..ce6a5427 100644 --- a/speeduino/table.ino +++ b/speeduino/table.ino @@ -64,13 +64,15 @@ int table2D_getValue(struct table2D *fromTable, int X_in) int xMax = 0; //Check whether the X input is the same as last time this ran - if(X_in == fromTable->lastInput) + if(X_in == fromTable->lastInput && fromTable->cacheTime == currentStatus.secl) { returnValue = fromTable->lastOutput; valueFound = true; } else { + fromTable->cacheTime = currentStatus.secl; //As we're not using the cache value, set the current secl value to track when this new value was calc'd + if (fromTable->valueSize == SIZE_BYTE) { //Byte version From 0c374cf081bd5f9ac1fdefc785879463e350c4f6 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Mon, 5 Feb 2018 18:05:36 +1100 Subject: [PATCH 6/8] Prevent overflow of fuel when RPM < 115 and sequential is selected --- speeduino/scheduler.ino | 238 +++++++++++++++++++++------------------- speeduino/table.h | 2 +- 2 files changed, 129 insertions(+), 111 deletions(-) diff --git a/speeduino/scheduler.ino b/speeduino/scheduler.ino index a6493f08..f5a5772d 100644 --- a/speeduino/scheduler.ino +++ b/speeduino/scheduler.ino @@ -318,142 +318,160 @@ void setFuelSchedule(struct Schedule *targetSchedule, unsigned long timeout, uns //void setFuelSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) void setFuelSchedule1(unsigned long timeout, unsigned long duration) { - if(fuelSchedule1.Status != RUNNING) //Check that we're not already part way through a schedule + //Check whether timeout exceeds the maximum future time. This can potentially occur on sequential setups when below ~115rpm + if(timeout < MAX_TIMER_PERIOD_SLOW) { - //Callbacks no longer used, but retained for now: - //fuelSchedule1.StartCallback = startCallback; - //fuelSchedule1.EndCallback = endCallback; - fuelSchedule1.duration = duration; + if(fuelSchedule1.Status != RUNNING) //Check that we're not already part way through a schedule + { + //Callbacks no longer used, but retained for now: + //fuelSchedule1.StartCallback = startCallback; + //fuelSchedule1.EndCallback = endCallback; + fuelSchedule1.duration = duration; - //Need to check that the timeout doesn't exceed the overflow - uint16_t timeout_timer_compare; - if ((timeout+duration) > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (MAX_TIMER_PERIOD_SLOW - 1 - duration) ); } // If the timeout is >16x (Each tick represents 16uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking. - else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case + //Need to check that the timeout doesn't exceed the overflow + uint16_t timeout_timer_compare; + if ((timeout+duration) > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (MAX_TIMER_PERIOD_SLOW - 1 - duration) ); } // If the timeout is >16x (Each tick represents 16uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking. + else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case - //The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set - noInterrupts(); - fuelSchedule1.startCompare = FUEL1_COUNTER + timeout_timer_compare; - fuelSchedule1.endCompare = fuelSchedule1.startCompare + uS_TO_TIMER_COMPARE_SLOW(duration); - fuelSchedule1.Status = PENDING; //Turn this schedule on - fuelSchedule1.schedulesSet++; //Increment the number of times this schedule has been set - //Schedule 1 shares a timer with schedule 5 - //if(channel5InjEnabled) { FUEL1_COMPARE = setQueue(timer3Aqueue, &fuelSchedule1, &fuelSchedule5, FUEL1_COUNTER); } - //else { timer3Aqueue[0] = &fuelSchedule1; timer3Aqueue[1] = &fuelSchedule1; timer3Aqueue[2] = &fuelSchedule1; timer3Aqueue[3] = &fuelSchedule1; FUEL1_COMPARE = fuelSchedule1.startCompare; } - //timer3Aqueue[0] = &fuelSchedule1; timer3Aqueue[1] = &fuelSchedule1; timer3Aqueue[2] = &fuelSchedule1; timer3Aqueue[3] = &fuelSchedule1; - FUEL1_COMPARE = fuelSchedule1.startCompare; - interrupts(); - FUEL1_TIMER_ENABLE(); - } - else - { - //If the schedule is already running, we can set the next schedule so it is ready to go - //This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule - fuelSchedule1.nextStartCompare = FUEL1_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout); - fuelSchedule1.nextEndCompare = fuelSchedule1.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration); - fuelSchedule1.duration = duration; - fuelSchedule1.hasNextSchedule = false; - } + //The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set + noInterrupts(); + fuelSchedule1.startCompare = FUEL1_COUNTER + timeout_timer_compare; + fuelSchedule1.endCompare = fuelSchedule1.startCompare + uS_TO_TIMER_COMPARE_SLOW(duration); + fuelSchedule1.Status = PENDING; //Turn this schedule on + fuelSchedule1.schedulesSet++; //Increment the number of times this schedule has been set + //Schedule 1 shares a timer with schedule 5 + //if(channel5InjEnabled) { FUEL1_COMPARE = setQueue(timer3Aqueue, &fuelSchedule1, &fuelSchedule5, FUEL1_COUNTER); } + //else { timer3Aqueue[0] = &fuelSchedule1; timer3Aqueue[1] = &fuelSchedule1; timer3Aqueue[2] = &fuelSchedule1; timer3Aqueue[3] = &fuelSchedule1; FUEL1_COMPARE = fuelSchedule1.startCompare; } + //timer3Aqueue[0] = &fuelSchedule1; timer3Aqueue[1] = &fuelSchedule1; timer3Aqueue[2] = &fuelSchedule1; timer3Aqueue[3] = &fuelSchedule1; + FUEL1_COMPARE = fuelSchedule1.startCompare; + interrupts(); + FUEL1_TIMER_ENABLE(); + } + else + { + //If the schedule is already running, we can set the next schedule so it is ready to go + //This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule + noInterrupts(); + fuelSchedule1.nextStartCompare = FUEL1_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout); + fuelSchedule1.nextEndCompare = fuelSchedule1.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration); + fuelSchedule1.duration = duration; + fuelSchedule1.hasNextSchedule = true; + interrupts(); + } //Schedule is RUNNING + } //Timeout less than threshold } void setFuelSchedule2(unsigned long timeout, unsigned long duration) { - if(fuelSchedule2.Status != RUNNING) //Check that we're not already part way through a schedule + //Check whether timeout exceeds the maximum future time. This can potentially occur on sequential setups when below ~115rpm + if(timeout < MAX_TIMER_PERIOD_SLOW) { - //Callbacks no longer used, but retained for now: - //fuelSchedule2.StartCallback = startCallback; - //fuelSchedule2.EndCallback = endCallback; - fuelSchedule2.duration = duration; + if(fuelSchedule2.Status != RUNNING) //Check that we're not already part way through a schedule + { + //Callbacks no longer used, but retained for now: + //fuelSchedule2.StartCallback = startCallback; + //fuelSchedule2.EndCallback = endCallback; + fuelSchedule2.duration = duration; - //Need to check that the timeout doesn't exceed the overflow - uint16_t timeout_timer_compare; - if (timeout > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (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. - else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case + //Need to check that the timeout doesn't exceed the overflow + uint16_t timeout_timer_compare; + if (timeout > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (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. + else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case - //The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set - noInterrupts(); - fuelSchedule2.startCompare = FUEL2_COUNTER + timeout_timer_compare; - fuelSchedule2.endCompare = fuelSchedule2.startCompare + uS_TO_TIMER_COMPARE_SLOW(duration); - FUEL2_COMPARE = fuelSchedule2.startCompare; //Use the B compare unit of timer 3 - fuelSchedule2.Status = PENDING; //Turn this schedule on - fuelSchedule2.schedulesSet++; //Increment the number of times this schedule has been set - interrupts(); - FUEL2_TIMER_ENABLE(); - } - else - { - //If the schedule is already running, we can set the next schedule so it is ready to go - //This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule - fuelSchedule2.nextStartCompare = FUEL2_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout); - fuelSchedule2.nextEndCompare = fuelSchedule2.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration); - fuelSchedule2.hasNextSchedule = true; + //The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set + noInterrupts(); + fuelSchedule2.startCompare = FUEL2_COUNTER + timeout_timer_compare; + fuelSchedule2.endCompare = fuelSchedule2.startCompare + uS_TO_TIMER_COMPARE_SLOW(duration); + FUEL2_COMPARE = fuelSchedule2.startCompare; //Use the B compare unit of timer 3 + fuelSchedule2.Status = PENDING; //Turn this schedule on + fuelSchedule2.schedulesSet++; //Increment the number of times this schedule has been set + interrupts(); + FUEL2_TIMER_ENABLE(); + } + else + { + //If the schedule is already running, we can set the next schedule so it is ready to go + //This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule + fuelSchedule2.nextStartCompare = FUEL2_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout); + fuelSchedule2.nextEndCompare = fuelSchedule2.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration); + fuelSchedule2.hasNextSchedule = true; + } } } //void setFuelSchedule3(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) void setFuelSchedule3(unsigned long timeout, unsigned long duration) { - if(fuelSchedule3.Status != RUNNING)//Check that we're not already part way through a schedule + //Check whether timeout exceeds the maximum future time. This can potentially occur on sequential setups when below ~115rpm + if(timeout < MAX_TIMER_PERIOD_SLOW) { - //Callbacks no longer used, but retained for now: - //fuelSchedule3.StartCallback = startCallback; - //fuelSchedule3.EndCallback = endCallback; - fuelSchedule3.duration = duration; + if(fuelSchedule3.Status != RUNNING)//Check that we're not already part way through a schedule + { + //Callbacks no longer used, but retained for now: + //fuelSchedule3.StartCallback = startCallback; + //fuelSchedule3.EndCallback = endCallback; + fuelSchedule3.duration = duration; - //Need to check that the timeout doesn't exceed the overflow - uint16_t timeout_timer_compare; - if (timeout > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (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. - else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case + //Need to check that the timeout doesn't exceed the overflow + uint16_t timeout_timer_compare; + if (timeout > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (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. + else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case - //The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set - noInterrupts(); - fuelSchedule3.startCompare = FUEL3_COUNTER + timeout_timer_compare; - fuelSchedule3.endCompare = fuelSchedule3.startCompare + uS_TO_TIMER_COMPARE_SLOW(duration); - FUEL3_COMPARE = fuelSchedule3.startCompare; //Use the C copmare unit of timer 3 - fuelSchedule3.Status = PENDING; //Turn this schedule on - fuelSchedule3.schedulesSet++; //Increment the number of times this schedule has been set - interrupts(); - FUEL3_TIMER_ENABLE(); - } - else - { - //If the schedule is already running, we can set the next schedule so it is ready to go - //This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule - fuelSchedule3.nextStartCompare = FUEL3_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout); - fuelSchedule3.nextEndCompare = fuelSchedule3.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration); - fuelSchedule3.hasNextSchedule = true; + //The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set + noInterrupts(); + fuelSchedule3.startCompare = FUEL3_COUNTER + timeout_timer_compare; + fuelSchedule3.endCompare = fuelSchedule3.startCompare + uS_TO_TIMER_COMPARE_SLOW(duration); + FUEL3_COMPARE = fuelSchedule3.startCompare; //Use the C copmare unit of timer 3 + fuelSchedule3.Status = PENDING; //Turn this schedule on + fuelSchedule3.schedulesSet++; //Increment the number of times this schedule has been set + interrupts(); + FUEL3_TIMER_ENABLE(); + } + else + { + //If the schedule is already running, we can set the next schedule so it is ready to go + //This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule + fuelSchedule3.nextStartCompare = FUEL3_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout); + fuelSchedule3.nextEndCompare = fuelSchedule3.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration); + fuelSchedule3.hasNextSchedule = true; + } } } //void setFuelSchedule4(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) void setFuelSchedule4(unsigned long timeout, unsigned long duration) //Uses timer 4 compare B { - if(fuelSchedule4.Status != RUNNING) //Check that we're not already part way through a schedule + //Check whether timeout exceeds the maximum future time. This can potentially occur on sequential setups when below ~115rpm + if(timeout < MAX_TIMER_PERIOD_SLOW) { - //Callbacks no longer used, but retained for now: - //fuelSchedule4.StartCallback = startCallback; - //fuelSchedule4.EndCallback = endCallback; - fuelSchedule4.duration = duration; + if(fuelSchedule4.Status != RUNNING) //Check that we're not already part way through a schedule + { + //Callbacks no longer used, but retained for now: + //fuelSchedule4.StartCallback = startCallback; + //fuelSchedule4.EndCallback = endCallback; + fuelSchedule4.duration = duration; - //Need to check that the timeout doesn't exceed the overflow - uint16_t timeout_timer_compare; - if (timeout > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (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. - else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case + //Need to check that the timeout doesn't exceed the overflow + uint16_t timeout_timer_compare; + if (timeout > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (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. + else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case - //The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set - noInterrupts(); - fuelSchedule4.startCompare = FUEL4_COUNTER + timeout_timer_compare; - fuelSchedule4.endCompare = fuelSchedule4.startCompare + uS_TO_TIMER_COMPARE_SLOW(duration); - FUEL4_COMPARE = fuelSchedule4.startCompare; //Use the C copmare unit of timer 3 - fuelSchedule4.Status = PENDING; //Turn this schedule on - fuelSchedule4.schedulesSet++; //Increment the number of times this schedule has been set - interrupts(); - FUEL4_TIMER_ENABLE(); - } - else - { - //If the schedule is already running, we can set the next schedule so it is ready to go - //This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule - fuelSchedule4.nextStartCompare = FUEL4_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout); - fuelSchedule4.nextEndCompare = fuelSchedule4.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration); - fuelSchedule4.hasNextSchedule = true; + //The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set + noInterrupts(); + fuelSchedule4.startCompare = FUEL4_COUNTER + timeout_timer_compare; + fuelSchedule4.endCompare = fuelSchedule4.startCompare + uS_TO_TIMER_COMPARE_SLOW(duration); + FUEL4_COMPARE = fuelSchedule4.startCompare; //Use the C copmare unit of timer 3 + fuelSchedule4.Status = PENDING; //Turn this schedule on + fuelSchedule4.schedulesSet++; //Increment the number of times this schedule has been set + interrupts(); + FUEL4_TIMER_ENABLE(); + } + else + { + //If the schedule is already running, we can set the next schedule so it is ready to go + //This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule + fuelSchedule4.nextStartCompare = FUEL4_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout); + fuelSchedule4.nextEndCompare = fuelSchedule4.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration); + fuelSchedule4.hasNextSchedule = true; + } } } diff --git a/speeduino/table.h b/speeduino/table.h index 1202bea4..7dee642f 100644 --- a/speeduino/table.h +++ b/speeduino/table.h @@ -29,7 +29,7 @@ struct table2D { //Store the last input and output for caching int16_t lastInput; int16_t lastOutput; - byte cacheTime; //TRacks when the last cache value was set so it can expire after x seconds + byte cacheTime; //TRacks when the last cache value was set so it can expire after x seconds. A timeout is required to pickup when a tuning value is changed, otherwise the old cached value will continue to be returned as the X value isn't changing. }; void table2D_setSize(struct table2D targetTable, byte newSize); From 11a0c8069e7209637caa62209e3ec029514ba228 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Mon, 5 Feb 2018 18:05:58 +1100 Subject: [PATCH 7/8] Fix initial state of the dual wheel decoder on first rev after sync --- speeduino/decoders.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/speeduino/decoders.ino b/speeduino/decoders.ino index 5dae5ba2..a803eab7 100644 --- a/speeduino/decoders.ino +++ b/speeduino/decoders.ino @@ -377,7 +377,8 @@ void triggerSec_DualWheel() { toothLastToothTime = micros(); //CONFIRM THE BELOW! IT DOESN'T LOOK RIGHT (toothOneTime??) - toothLastMinusOneToothTime = (toothOneTime - 6000000) / configPage4.triggerTeeth; //Fixes RPM at 10rpm until a full revolution has taken place + //toothLastMinusOneToothTime = (toothOneTime - 6000000) / configPage4.triggerTeeth; //Fixes RPM at 10rpm until a full revolution has taken place + toothLastMinusOneToothTime = micros() - (6000000 / configPage4.triggerTeeth); //Fixes RPM at 10rpm until a full revolution has taken place toothCurrentCount = configPage4.triggerTeeth; currentStatus.hasSync = true; From d646553b6fbe5c1fcb67af4cbe36a22051b9fad9 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Tue, 6 Feb 2018 21:47:02 +1100 Subject: [PATCH 8/8] Fix for 24x decoder not syncing after startup --- speeduino/decoders.ino | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/speeduino/decoders.ino b/speeduino/decoders.ino index a803eab7..b67a048f 100644 --- a/speeduino/decoders.ino +++ b/speeduino/decoders.ino @@ -1026,7 +1026,8 @@ void triggerSetup_24X() toothAngles[23] = 357; MAX_STALL_TIME = (3333UL * triggerToothAngle); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) - toothCurrentCount = 25; //We set the initial tooth value to be something that should never be reached. This indicates no sync + if(initialisationComplete == false) { toothCurrentCount = 25; toothLastToothTime = micros(); } //Set a startup value here to avoid filter errors when starting. This MUST have the initi check to prevent the fuel pump just staying on all the time + //We set the initial tooth value to be something that should never be reached. This indicates no sync secondDerivEnabled = false; decoderIsSequential = true; } @@ -1044,24 +1045,29 @@ void triggerPri_24X() toothCurrentCount = 1; //Reset the counter toothOneMinusOneTime = toothOneTime; toothOneTime = curTime; + revolutionOne = !revolutionOne; //Sequential revolution flip currentStatus.hasSync = true; currentStatus.startRevolutions++; //Counter + triggerToothAngle = 15; //Always 15 degrees for tooth #15 } else { toothCurrentCount++; //Increment the tooth counter + triggerToothAngle = toothAngles[(toothCurrentCount-1)] - toothAngles[(toothCurrentCount-2)]; //Calculate the last tooth gap in degrees } 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; + revolutionOne = 1; //Sequential revolution reset } uint16_t getRPM_24X() @@ -1072,11 +1078,12 @@ 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; + int tempToothCurrentCount, tempRevolutionOne; //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; @@ -1088,6 +1095,9 @@ int getCrankAngle_24X(int 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 > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; } if (crankAngle < 0) { crankAngle += 360; }