Initial work on new ignition timing method (Very messy)

This commit is contained in:
Josh Stewart 2018-08-08 15:17:09 +10:00
parent 6ad046c398
commit cc6bf05a43
9 changed files with 93 additions and 44 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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;