From cc6bf05a432edc3a839caa8d8babf95a4896137a Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Wed, 8 Aug 2018 15:17:09 +1000 Subject: [PATCH] Initial work on new ignition timing method (Very messy) --- speeduino/crankMaths.h | 7 +++++- speeduino/crankMaths.ino | 2 +- speeduino/decoders.h | 5 ++-- speeduino/decoders.ino | 50 ++++++++++++++++++++++------------------ speeduino/scheduledIO.h | 9 ++++++++ speeduino/scheduler.ino | 50 ++++++++++++++++++++++++++++++---------- speeduino/speeduino.h | 4 ++++ speeduino/timers.ino | 2 +- speeduino/utils.ino | 8 +++---- 9 files changed, 93 insertions(+), 44 deletions(-) diff --git a/speeduino/crankMaths.h b/speeduino/crankMaths.h index 48d1669f..48e4092e 100644 --- a/speeduino/crankMaths.h +++ b/speeduino/crankMaths.h @@ -7,12 +7,17 @@ #define CRANKMATH_METHOD_ALPHA_BETA 3 #define CRANKMATH_METHOD_2ND_DERIVATIVE 4 -#define fastDegreesToUS(degrees) (degrees * (unsigned long)timePerDegree) +//#define fastDegreesToUS(targetDegrees) ((targetDegrees) * (unsigned long)timePerDegree) +#define fastDegreesToUS(targetDegrees) (((targetDegrees) * (unsigned long)timePerDegreex16) >> 4) +#define fastTimeToAngle(time) (((unsigned long)time * degreesPeruSx2048) / 2048) //Divide by 2048 will be converted at compile time to bitshift + +#define ignitionLimits(angle) (angle >= CRANK_ANGLE_MAX_IGN ? (angle - CRANK_ANGLE_MAX_IGN) : (angle < 0 ? (angle + CRANK_ANGLE_MAX_IGN) : angle)) unsigned long angleToTime(int16_t, byte); uint16_t timeToAngle(unsigned long, byte); volatile int timePerDegree; +volatile uint16_t timePerDegreex16; volatile uint16_t degreesPeruSx2048; #endif \ No newline at end of file diff --git a/speeduino/crankMaths.ino b/speeduino/crankMaths.ino index 67b5f47c..3cf92539 100644 --- a/speeduino/crankMaths.ino +++ b/speeduino/crankMaths.ino @@ -52,7 +52,7 @@ uint16_t timeToAngle(unsigned long time, byte method) { //A last interval method of calculating angle that does not take into account any acceleration. The interval used is the time taken to complete the last full revolution //degreesPeruSx2048 is the number of degrees the crank moves per uS. This value is almost always <1uS, so it is multiplied by 2048. This allows an angle calcuation with only a multiply and a bitshift without any appreciable drop in accuracy - returnAngle = (time * degreesPeruSx2048) / 2048; //Divide by 2048 will be converted at compile time to bitshift + returnAngle = fastTimeToAngle(time); } else if (method == CRANKMATH_METHOD_INTERVAL_TOOTH) { diff --git a/speeduino/decoders.h b/speeduino/decoders.h index d764bd58..304c33ad 100644 --- a/speeduino/decoders.h +++ b/speeduino/decoders.h @@ -10,10 +10,10 @@ #endif static inline void addToothLogEntry(unsigned long); -static inline uint16_t stdGetRPM(uint16_t degreesOver); +static inline uint16_t stdGetRPM(uint16_t); static inline void setFilter(unsigned long); static inline int crankingGetRPM(byte); -static inline void doPerToothTiming(uint16_t crankAngle); +//static inline void doPerToothTiming(uint16_t); void triggerSetup_missingTooth(); void triggerPri_missingTooth(); @@ -66,6 +66,7 @@ bool decoderHasFixedCrankingTiming = false; //Whether or not the decoder support byte checkSyncToothCount; //How many teeth must've been seen on this revolution before we try to confirm sync (Useful for missing tooth type decoders) unsigned long elapsedTime; unsigned long lastCrankAngleCalc; +int16_t lastToothCalcAdvance = 99; //Invalid value here forces calculation of this on first main loop int16_t ignition1EndTooth = 0; int16_t ignition2EndTooth = 0; diff --git a/speeduino/decoders.ino b/speeduino/decoders.ino index 60d5a9d9..433cfb22 100644 --- a/speeduino/decoders.ino +++ b/speeduino/decoders.ino @@ -113,14 +113,20 @@ On decoders that are enabled for per tooth based timing adjustments, this functi For each ignition channel, a check is made whether we're at the relevant tooth and whether that ignition schedule is currently running Only if both these conditions are met will the schedule be updated with the latest timing information. */ -static inline void doPerToothTiming(uint16_t crankAngle) -{ - if ( (toothCurrentCount == ignition1EndTooth) && (ignitionSchedule1.Status == RUNNING) ) { IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE( ((ignition1EndAngle - crankAngle) * timePerDegree) ); } - else if ( (toothCurrentCount == ignition2EndTooth) && (ignitionSchedule2.Status == RUNNING) ) { IGN2_COMPARE = IGN2_COUNTER + uS_TO_TIMER_COMPARE( ((ignition2EndAngle - crankAngle) * timePerDegree) ); } - else if ( (toothCurrentCount == ignition3EndTooth) && (ignitionSchedule3.Status == RUNNING) ) { IGN3_COMPARE = IGN3_COUNTER + uS_TO_TIMER_COMPARE( ((ignition3EndAngle - crankAngle) * timePerDegree) ); } - else if ( (toothCurrentCount == ignition4EndTooth) && (ignitionSchedule4.Status == RUNNING) ) { IGN4_COMPARE = IGN4_COUNTER + uS_TO_TIMER_COMPARE_SLOW( ((ignition4EndAngle - crankAngle) * timePerDegree) ); } +//static inline void doPerToothTiming(uint16_t crankAngle) +#define doPerToothTiming(crankAngle) \ +{ \ + if ( (toothCurrentCount == ignition1EndTooth) ) \ + { if(ignitionSchedule1.Status == RUNNING) { IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE( fastDegreesToUS( ignitionLimits( (ignition1EndAngle - crankAngle) ) ) ); } \ + else { ignitionSchedule1.endCompare = IGN1_COUNTER + uS_TO_TIMER_COMPARE( fastDegreesToUS( ignitionLimits( (ignition1EndAngle - crankAngle) ) ) ); ignitionSchedule1.hasNextSchedule = true; } \ + } \ + else if ( (toothCurrentCount == ignition2EndTooth) && (ignitionSchedule2.Status == RUNNING) ) { IGN2_COMPARE = IGN2_COUNTER + uS_TO_TIMER_COMPARE( fastDegreesToUS( ignitionLimits( (ignition2EndAngle - crankAngle) ) ) ); } \ + else if ( (toothCurrentCount == ignition3EndTooth) && (ignitionSchedule3.Status == RUNNING) ) { IGN3_COMPARE = IGN3_COUNTER + uS_TO_TIMER_COMPARE( fastDegreesToUS( ignitionLimits( (ignition3EndAngle - crankAngle) ) ) ); } \ + else if ( (toothCurrentCount == ignition4EndTooth) && (ignitionSchedule4.Status == RUNNING) ) { IGN4_COMPARE = IGN4_COUNTER + uS_TO_TIMER_COMPARE_SLOW( fastDegreesToUS( ignitionLimits( (ignition4EndAngle - crankAngle) ) ) ); } \ } +// if ( (toothCurrentCount == ignition1EndTooth) ) { ignitionSchedule1.endCompare = IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE( fastDegreesToUS( ignitionLimits( (ignition1EndAngle - crankAngle) ) ) ); } \ + /* 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 @@ -164,6 +170,7 @@ void triggerPri_missingTooth() if ( (curGap > targetGap) || (toothCurrentCount > triggerActualTeeth) ) { + //Missing tooth detected if(toothCurrentCount < (triggerActualTeeth) && (currentStatus.hasSync == true) ) { //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. @@ -195,12 +202,18 @@ void triggerPri_missingTooth() toothLastToothTime = curTime; triggerToothAngleIsCorrect = true; } + } //EXPERIMENTAL! - if(configPage2.perToothIgn == true) + if(configPage2.perToothIgn == true && !BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) { - uint16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage4.triggerAngle; + //ignition1EndTooth = 11; + //ignition1EndAngle = 0; + int16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage4.triggerAngle; + //if ( (toothCurrentCount == ignition1EndTooth) && (ignitionSchedule1.Status == RUNNING) ) { IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE( fastDegreesToUS( ignitionLimits( (ignition1EndAngle - crankAngle) ) ) ); } + //if ( (toothCurrentCount == ignition1EndTooth) && (ignitionSchedule1.Status == RUNNING) ) { IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE( 9048 ); } + //else { if (toothCurrentCount == ignition1EndTooth) { ignitionSchedule1.endCompare = IGN1_COUNTER + uS_TO_TIMER_COMPARE( 9048 ); } } doPerToothTiming(crankAngle); } } @@ -292,28 +305,27 @@ int getCrankAngle_missingTooth() void triggerSetEndTeeth_missingTooth() { - ignition1EndTooth = ( (ignition1EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1; if(ignition1EndTooth > configPage4.triggerTeeth) { ignition1EndTooth -= configPage4.triggerTeeth; } - if(ignition1EndTooth <= 0) { ignition1EndTooth -= configPage4.triggerTeeth; } + if(ignition1EndTooth <= 0) { ignition1EndTooth += configPage4.triggerTeeth; } if(ignition1EndTooth > triggerActualTeeth) { ignition1EndTooth = triggerActualTeeth; } ignition2EndTooth = ( (ignition2EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1; if(ignition2EndTooth > configPage4.triggerTeeth) { ignition2EndTooth -= configPage4.triggerTeeth; } - if(ignition2EndTooth <= 0) { ignition2EndTooth -= configPage4.triggerTeeth; } + if(ignition2EndTooth <= 0) { ignition2EndTooth += configPage4.triggerTeeth; } if(ignition2EndTooth > triggerActualTeeth) { ignition2EndTooth = triggerActualTeeth; } ignition3EndTooth = ( (ignition3EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1; if(ignition3EndTooth > configPage4.triggerTeeth) { ignition3EndTooth -= configPage4.triggerTeeth; } - if(ignition3EndTooth <= 0) { ignition3EndTooth -= configPage4.triggerTeeth; } + if(ignition3EndTooth <= 0) { ignition3EndTooth += configPage4.triggerTeeth; } if(ignition3EndTooth > triggerActualTeeth) { ignition3EndTooth = triggerActualTeeth; } ignition4EndTooth = ( (ignition4EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1; if(ignition4EndTooth > configPage4.triggerTeeth) { ignition4EndTooth -= configPage4.triggerTeeth; } - if(ignition4EndTooth <= 0) { ignition4EndTooth -= configPage4.triggerTeeth; } + if(ignition4EndTooth <= 0) { ignition4EndTooth += configPage4.triggerTeeth; } if(ignition4EndTooth > triggerActualTeeth) { ignition4EndTooth = triggerActualTeeth; } - + lastToothCalcAdvance = currentStatus.advance; } /* ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -522,15 +534,7 @@ void triggerPri_BasicDistributor() if(configPage2.perToothIgn == true) { uint16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage4.triggerAngle; - if ( (toothCurrentCount == ignition1EndTooth) && (ignitionSchedule1.Status == RUNNING) ) - { - IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE( ((ignition1EndAngle - crankAngle) * timePerDegree) ); - //IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE( (ignition1EndAngle - crankAngle)*my_timePerDegree - micros_compensation ); - - } - else if ( (toothCurrentCount == ignition2EndTooth) && (ignitionSchedule2.Status == RUNNING) ) { IGN2_COMPARE = IGN2_COUNTER + uS_TO_TIMER_COMPARE( ((ignition2EndAngle - crankAngle) * timePerDegree) ); } - else if ( (toothCurrentCount == ignition3EndTooth) && (ignitionSchedule3.Status == RUNNING) ) { IGN3_COMPARE = IGN3_COUNTER + uS_TO_TIMER_COMPARE( ((ignition3EndAngle - crankAngle) * timePerDegree) ); } - else if ( (toothCurrentCount == ignition4EndTooth) && (ignitionSchedule4.Status == RUNNING) ) { IGN4_COMPARE = IGN4_COUNTER + uS_TO_TIMER_COMPARE( ((ignition4EndAngle - crankAngle) * timePerDegree) ); } + doPerToothTiming(crankAngle); } toothLastMinusOneToothTime = toothLastToothTime; diff --git a/speeduino/scheduledIO.h b/speeduino/scheduledIO.h index 648ee64c..ccc13c9c 100644 --- a/speeduino/scheduledIO.h +++ b/speeduino/scheduledIO.h @@ -67,6 +67,15 @@ void endCoil2and4Charge(); #define openInjector3and5() openInjector3(); openInjector5() #define closeInjector3and5() closeInjector3(); closeInjector5() +#define coil1Low() (*ign1_pin_port &= ~(ign1_pin_mask)) +#define coil1High() (*ign1_pin_port |= (ign1_pin_mask)) +#define coil2Low() (*ign2_pin_port &= ~(ign2_pin_mask)) +#define coil2High() (*ign2_pin_port |= (ign2_pin_mask)) +#define coil3Low() (*ign3_pin_port &= ~(ign3_pin_mask)) +#define coil3High() (*ign3_pin_port |= (ign3_pin_mask)) +#define coil4Low() (*ign4_pin_port &= ~(ign4_pin_mask)) +#define coil4High() (*ign4_pin_port |= (ign4_pin_mask)) + void nullCallback(); static byte coilHIGH = HIGH; diff --git a/speeduino/scheduler.ino b/speeduino/scheduler.ino index b6375e84..497498d9 100644 --- a/speeduino/scheduler.ino +++ b/speeduino/scheduler.ino @@ -642,13 +642,13 @@ void setIgnitionSchedule1(void (*startCallback)(), unsigned long timeout, unsign //Need to check that the timeout doesn't exceed the overflow uint16_t timeout_timer_compare; - timeout -= (micros() - lastCrankAngleCalc); + //timeout -= (micros() - lastCrankAngleCalc); if (timeout > MAX_TIMER_PERIOD) { timeout_timer_compare = uS_TO_TIMER_COMPARE( (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(timeout); } //Normal case noInterrupts(); ignitionSchedule1.startCompare = IGN1_COUNTER + timeout_timer_compare; //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4) - ignitionSchedule1.endCompare = ignitionSchedule1.startCompare + uS_TO_TIMER_COMPARE(duration); + if(ignitionSchedule1.hasNextSchedule == false) { ignitionSchedule1.endCompare = ignitionSchedule1.startCompare + uS_TO_TIMER_COMPARE(duration); } IGN1_COMPARE = ignitionSchedule1.startCompare; ignitionSchedule1.Status = PENDING; //Turn this schedule on ignitionSchedule1.schedulesSet++; @@ -663,8 +663,11 @@ static inline void refreshIgnitionSchedule1(unsigned long timeToEnd) //Must have the threshold check here otherwise it can cause a condition where the compare fires twice, once after the other, both for the end //if( (timeToEnd < ignitionSchedule1.duration) && (timeToEnd > IGNITION_REFRESH_THRESHOLD) ) { + unsigned long adjustedTimeToEnd = timeToEnd; noInterrupts(); - unsigned long adjustedTimeToEnd = timeToEnd - (micros() - lastCrankAngleCalc); //Take into account any time that has passed since the last crank angle calculation + //unsigned long timeSinceLastCrankAngleCalc = (micros() - lastCrankAngleCalc); + //Take into account any time that has passed since the last crank angle calculation + //if(timeToEnd > timeSinceLastCrankAngleCalc) { adjustedTimeToEnd = timeToEnd - timeSinceLastCrankAngleCalc; } ignitionSchedule1.endCompare = IGN1_COUNTER + uS_TO_TIMER_COMPARE(adjustedTimeToEnd); IGN1_COMPARE = ignitionSchedule1.endCompare; interrupts(); @@ -1174,29 +1177,52 @@ 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 = IGN1_COUNTER + uS_TO_TIMER_COMPARE(ignitionSchedule1.duration); //Doing this here prevents a potential overflow on restarts + if(ignitionSchedule1.hasNextSchedule == true) { IGN1_COMPARE = ignitionSchedule1.endCompare; } + else { 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; + //IGN1_COMPARE = IGN1_COMPARE - 150; //ignitionSchedule1.Status = STAGED; } else if (ignitionSchedule1.Status == STAGED) { - int16_t crankAngle = getCrankAngle(); + unsigned long timeToLast = lastCrankAngleCalc - micros(); + degreesPeruSx2048 = 46; + //crankAngle += fastTimeToAngle(timeToLast); + int crankAngle = getCrankAngle(); + if(crankAngle > CRANK_ANGLE_MAX_IGN) { crankAngle -= CRANK_ANGLE_MAX_IGN; } - if(ignition1EndAngle > crankAngle) - { - IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE( fastDegreesToUS((ignition1EndAngle - crankAngle)) ); + int degreesToTarget; + //ignition1EndAngle = 0; + if(ignition1EndAngle > crankAngle) { degreesToTarget = (ignition1EndAngle - crankAngle); } + else + { + if((crankAngle - ignition1EndAngle) < 10) + { + ignitionSchedule1.EndCallback(); + ignitionSchedule1.Status = OFF; //Turn off the schedule + ignitionSchedule1.schedulesSet = 0; + ignitionCount += 1; //Increment the igintion counter + IGN1_TIMER_DISABLE(); + return; + } + degreesToTarget = CRANK_ANGLE_MAX_IGN - crankAngle; + //degreesToTarget = 720 - crankAngle; + } - else { IGN1_COMPARE = ignitionSchedule1.endCompare; } + + //degreesToTarget = 360-crankAngle; ignitionSchedule1.Status = RUNNING; + IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE( fastDegreesToUS(degreesToTarget) ); + } else if (ignitionSchedule1.Status == RUNNING) { - ignitionSchedule1.EndCallback(); + //ignitionSchedule1.EndCallback(); + *ign1_pin_port &= ~(ign1_pin_mask); ignitionSchedule1.Status = OFF; //Turn off the schedule ignitionSchedule1.schedulesSet = 0; + ignitionSchedule1.hasNextSchedule = false; ignitionCount += 1; //Increment the igintion counter IGN1_TIMER_DISABLE(); } diff --git a/speeduino/speeduino.h b/speeduino/speeduino.h index bdd7cdcf..c5c8cc6b 100644 --- a/speeduino/speeduino.h +++ b/speeduino/speeduino.h @@ -5,4 +5,8 @@ static inline unsigned int PW(int REQ_FUEL, byte VE, long MAP, int corrections, static inline byte getVE(); static inline byte getAdvance(); +unsigned long calculateInjector2StartAngle(unsigned int); +unsigned long calculateInjector3StartAngle(unsigned int); +unsigned long calculateInjector4StartAngle(unsigned int); + #endif diff --git a/speeduino/timers.ino b/speeduino/timers.ino index fa9aa010..860da0c3 100644 --- a/speeduino/timers.ino +++ b/speeduino/timers.ino @@ -68,7 +68,7 @@ void initialiseTimers() //Timer2 Overflow Interrupt Vector, called when the timer overflows. //Executes every ~1ms. #if defined(CORE_AVR) //AVR chips use the ISR for this -ISR(TIMER2_OVF_vect) +ISR(TIMER2_OVF_vect, ISR_NOBLOCK) //This MUST be no block. Turning NO_BLOCK off messes with timing accuracy #elif defined (CORE_TEENSY) || defined(CORE_STM32) void oneMSInterval() //Most ARM chips can simply call a function #endif diff --git a/speeduino/utils.ino b/speeduino/utils.ino index a2483cbb..3a12a3f9 100644 --- a/speeduino/utils.ino +++ b/speeduino/utils.ino @@ -897,14 +897,14 @@ void initialiseTriggers() case 0: //Missing tooth decoder triggerSetup_missingTooth(); - trigger = triggerPri_missingTooth; - triggerSecondary = triggerSec_missingTooth; + //trigger = triggerPri_missingTooth; + //triggerSecondary = triggerSec_missingTooth; getRPM = getRPM_missingTooth; getCrankAngle = getCrankAngle_missingTooth; triggerSetEndTeeth = triggerSetEndTeeth_missingTooth; - if(configPage4.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(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, triggerPri_missingTooth, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) + else { attachInterrupt(triggerInterrupt, triggerPri_missingTooth, FALLING); } if(configPage4.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, RISING); } else { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, FALLING); } break;