From 9111c5ec86007109c3f5ac74df91166d45b727b1 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Wed, 27 Jul 2016 19:31:38 +1000 Subject: [PATCH] Mostly complete 5 cylinder scheduling --- scheduler.h | 56 +++++++++++++++++++--- scheduler.ino | 123 ++++++++++++++++++++++++++---------------------- speeduino.ino | 128 ++++++++++++++++++++++++++++++++------------------ 3 files changed, 200 insertions(+), 107 deletions(-) diff --git a/scheduler.h b/scheduler.h index dccb37fb..8a9d86bb 100644 --- a/scheduler.h +++ b/scheduler.h @@ -63,10 +63,9 @@ struct Schedule { unsigned int endCompare; }; -struct timerCompareManager { - volatile Schedule *currentSchedule; - volatile Schedule *nextSchedule; -}; +Schedule *timer3Aqueue[4]; +Schedule *timer3Bqueue[4]; +Schedule *timer3Cqueue[4]; Schedule fuelSchedule1; Schedule fuelSchedule2; @@ -85,8 +84,51 @@ Schedule ignitionSchedule6; Schedule ignitionSchedule7; Schedule ignitionSchedule8; -timerCompareManager timer3compareA; -timerCompareManager timer3compareB; -timerCompareManager timer3compareC; +Schedule nullSchedule; //This is placed at the end of the queue. It's status will always be set to OFF and hence will never perform any action within an ISR + +static inline unsigned int setQueue(Schedule *queue[], Schedule *schedule1, Schedule *schedule2, unsigned int CNT) +{ + //Create an array of all the upcoming targets, relative to the current count on the timer + unsigned int tmpQueue[4]; + tmpQueue[0] = schedule1->startCompare - CNT; + tmpQueue[1] = schedule1->endCompare - CNT; + tmpQueue[2] = schedule2->startCompare - CNT; + tmpQueue[3] = schedule2->endCompare - CNT; + + //Set the initial queue state. This order matches the tmpQueue order + queue[0] = schedule1; + queue[1] = schedule1; + queue[2] = schedule2; + queue[3] = schedule2; + + //Sort the queues. Both queues are kept in sync. + //This implementes a sorting networking based on the Bose-Nelson swap algorithm + //See: + #define SWAP(x,y) if(tmpQueue[y] < tmpQueue[x]) { unsigned int tmp = tmpQueue[x]; tmpQueue[x] = tmpQueue[y]; tmpQueue[y] = tmp; Schedule *tmpS = queue[x]; queue[x] = queue[y]; queue[y] = tmpS; } + //SWAP(0, 1); //Likely not needed + //SWAP(2, 3); //Likely not needed + SWAP(1, 3); + SWAP(1, 2); + + //Return the next compare time in the queue + return tmpQueue[0] + CNT; //Return the +} + +/* + * Moves all the Schedules in a queue forward one position. + * The current item (0) is discarded + * The final queue slot is set to nullSchedule to indicate that no action should be taken + */ +static inline unsigned int popQueue(Schedule *queue[]) +{ + queue[0] = queue[1]; + queue[1] = queue[2]; + queue[2] = queue[3]; + queue[3] = &nullSchedule; + + if( queue[0]->Status == PENDING ) { return queue[0]->startCompare; } + else { return queue[0]->endCompare; } +} + #endif // SCHEDULER_H diff --git a/scheduler.ino b/scheduler.ino index a32a8a6f..cf1f5a25 100644 --- a/scheduler.ino +++ b/scheduler.ino @@ -9,6 +9,8 @@ A full copy of the license may be found in the projects root directory void initialiseSchedulers() { + nullSchedule.Status = OFF; + // Much help in this from http://arduinomega.blogspot.com.au/2011/05/timer2-and-overflow-interrupt-lets-get.html //Fuel Schedules, which uses timer 3 TCCR3B = 0x00; //Disable Timer3 while we set it up @@ -63,40 +65,53 @@ timeout: The number of uS in the future that the startCallback should be trigger duration: The number of uS after startCallback is called before endCallback is called endCallback: This function is called once the duration time has been reached */ +volatile bool flip = 0; 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 - //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)) - //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 - fuelSchedule1.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16 - fuelSchedule1.endCompare = fuelSchedule1.startCompare + (duration >> 4); - OCR3A = fuelSchedule1.startCompare; - fuelSchedule1.duration = duration; fuelSchedule1.StartCallback = startCallback; //Name the start callback function fuelSchedule1.EndCallback = endCallback; //Name the end callback function - fuelSchedule1.Status = PENDING; //Turn this schedule on - timer3compareA.currentSchedule = &fuelSchedule1; - fuelSchedule1.schedulesSet++; //Increment the number of times this schedule has been set - TIMSK3 |= (1 << OCIE3A); //Turn on the C compare unit (ie turn on the interrupt) + fuelSchedule1.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)) + * 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(); + fuelSchedule1.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16 + fuelSchedule1.endCompare = fuelSchedule1.startCompare + (duration >> 4); + fuelSchedule1.Status = PENDING; //Turn this schedule on + fuelSchedule1.schedulesSet++; //Increment the number of times this schedule has been set + if(channel5InjEnabled) { OCR3A = setQueue(timer3Aqueue, &fuelSchedule1, &fuelSchedule5, TCNT3); } //Schedule 1 shares a timer with schedule 5 + else { timer3Aqueue[0] = &fuelSchedule1; timer3Aqueue[1] = &fuelSchedule1; timer3Aqueue[2] = &fuelSchedule1; timer3Aqueue[3] = &fuelSchedule1; OCR3A = fuelSchedule1.startCompare; } + interrupts(); + TIMSK3 |= (1 << OCIE3A); //Turn on the A compare unit (ie turn on the interrupt) } 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 - //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)) - //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 - fuelSchedule2.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16 - fuelSchedule2.endCompare = fuelSchedule2.startCompare + (duration >> 4); - OCR3B = fuelSchedule2.startCompare; //Use the B copmare unit of timer 3 - fuelSchedule2.duration = duration; fuelSchedule2.StartCallback = startCallback; //Name the start callback function fuelSchedule2.EndCallback = endCallback; //Name the end callback function - fuelSchedule2.Status = PENDING; //Turn this schedule on - fuelSchedule2.schedulesSet++; //Increment the number of times this schedule has been set - TIMSK3 |= (1 << OCIE3B); //Turn on the B compare unit (ie turn on the interrupt) + fuelSchedule2.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)) + * 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(); + fuelSchedule2.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16 + fuelSchedule2.endCompare = fuelSchedule2.startCompare + (duration >> 4); + OCR3B = fuelSchedule2.startCompare; //Use the B copmare unit of timer 3 + fuelSchedule2.Status = PENDING; //Turn this schedule on + fuelSchedule2.schedulesSet++; //Increment the number of times this schedule has been set + interrupts(); + TIMSK3 |= (1 << OCIE3B); //Turn on the B compare unit (ie turn on the interrupt) } void setFuelSchedule3(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) { @@ -138,20 +153,22 @@ void setFuelSchedule5(void (*startCallback)(), unsigned long timeout, unsigned l //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)) - fuelSchedule5.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16 - fuelSchedule5.endCompare = fuelSchedule5.startCompare + (duration >> 4); - - if(fuelSchedule5.startCompare < OCR3A) - { - OCR3A = fuelSchedule5.startCompare; - timer3compareA.currentSchedule = &fuelSchedule5; - } - - fuelSchedule5.duration = duration; + //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 + fuelSchedule5.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 + */ + noInterrupts(); + fuelSchedule5.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16 + fuelSchedule5.endCompare = fuelSchedule5.startCompare + (duration >> 4); fuelSchedule5.Status = PENDING; //Turn this schedule on - TIMSK3 |= (1 << OCIE3A); //Turn on the C compare unit (ie turn on the interrupt) + fuelSchedule5.schedulesSet++; //Increment the number of times this schedule has been set + OCR3A = setQueue(timer3Aqueue, &fuelSchedule1, &fuelSchedule5, TCNT3); //Schedule 1 shares a timer with schedule 5 + interrupts(); + TIMSK3 |= (1 << OCIE3A); //Turn on the A compare unit (ie turn on the interrupt) } //Ignition schedulers use Timer 5 void setIgnitionSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) @@ -214,6 +231,7 @@ void setIgnitionSchedule4(void (*startCallback)(), unsigned long timeout, unsign } void setIgnitionSchedule5(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) { + return; if(ignitionSchedule1.Status == RUNNING) { return; } //Check that we're not already part way through a schedule //As the timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency)) @@ -227,41 +245,30 @@ void setIgnitionSchedule5(void (*startCallback)(), unsigned long timeout, unsign TIMSK5 |= (1 << OCIE5A); //Turn on the A compare unit (ie turn on the interrupt) } - - +/*******************************************************************************************************************************************************************************************************/ //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. //If the startCallback function is called, we put the scheduler into RUNNING state //Timer3A (fuel schedule 1) Compare Vector -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this ISR(TIMER3_COMPA_vect, ISR_NOBLOCK) //fuelSchedules 1 and 5 -#else -void timer3compareAinterrupt() //Most ARM chips can simply call a function -#endif { - if (timer3compareA.currentSchedule == 0) { return; } //Safety check - if (timer3compareA.currentSchedule->Status == PENDING) //Check to see if this schedule is turn on + if (timer3Aqueue[0]->Status == OFF) { TIMSK3 &= ~(1 << OCIE3A); return; } //Safety check. Turn off this output compare unit and return without performing any action + if (timer3Aqueue[0]->Status == PENDING) //Check to see if this schedule is turn on { - timer3compareA.currentSchedule->StartCallback(); - timer3compareA.currentSchedule->Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) - OCR3A = timer3compareA.currentSchedule->endCompare; - //timer3compareA.currentSchedule = timer3compareA.nextSchedule; - //timer3compareA.nextSchedule = 0; + timer3Aqueue[0]->StartCallback(); + timer3Aqueue[0]->Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback) + OCR3A = popQueue(timer3Aqueue); } - else if (fuelSchedule1.Status == RUNNING) + else if (timer3Aqueue[0]->Status == RUNNING) { - fuelSchedule1.EndCallback(); - fuelSchedule1.Status = OFF; //Turn off the schedule - fuelSchedule1.schedulesSet = 0; - TIMSK3 &= ~(1 << OCIE3A); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3) + timer3Aqueue[0]->EndCallback(); + timer3Aqueue[0]->Status = OFF; //Turn off the schedule + timer3Aqueue[0]->schedulesSet = 0; + OCR3A = popQueue(timer3Aqueue); } } - -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this + ISR(TIMER3_COMPB_vect, ISR_NOBLOCK) //fuelSchedule2 -#elif defined (CORE_TEENSY) && defined (__MK20DX256__) -void timer3compareBinterrupt() //Most ARM chips can simply call a function -#endif { if (fuelSchedule2.Status == PENDING) //Check to see if this schedule is turn on { @@ -277,6 +284,7 @@ void timer3compareBinterrupt() //Most ARM chips can simply call a function TIMSK3 &= ~(1 << OCIE3B); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3) } } + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this ISR(TIMER3_COMPC_vect, ISR_NOBLOCK) //fuelSchedule3 #elif defined (CORE_TEENSY) && defined (__MK20DX256__) @@ -297,6 +305,7 @@ void timer3compareCinterrupt() //Most ARM chips can simply call a function TIMSK3 &= ~(1 << OCIE3C); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3) } } + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this ISR(TIMER4_COMPB_vect, ISR_NOBLOCK) //fuelSchedule4 #elif defined (CORE_TEENSY) && defined (__MK20DX256__) @@ -317,6 +326,7 @@ void timer4compareBinterrupt() //Most ARM chips can simply call a function TIMSK4 &= ~(1 << OCIE4B); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3) } } + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this ISR(TIMER5_COMPA_vect, ISR_NOBLOCK) //ignitionSchedule1 #elif defined (CORE_TEENSY) && defined (__MK20DX256__) @@ -340,6 +350,7 @@ void timer5compareAinterrupt() //Most ARM chips can simply call a function TIMSK5 &= ~(1 << OCIE5A); //Turn off this output compare unit } } + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this ISR(TIMER5_COMPB_vect, ISR_NOBLOCK) //ignitionSchedule2 #elif defined (CORE_TEENSY) && defined (__MK20DX256__) @@ -363,6 +374,7 @@ void timer5compareBinterrupt() //Most ARM chips can simply call a function TIMSK5 &= ~(1 << OCIE5B); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3) } } + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this ISR(TIMER5_COMPC_vect, ISR_NOBLOCK) //ignitionSchedule3 #elif defined (CORE_TEENSY) && defined (__MK20DX256__) @@ -386,6 +398,7 @@ void timer5compareCinterrupt() //Most ARM chips can simply call a function TIMSK5 &= ~(1 << OCIE5C); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3) } } + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this ISR(TIMER4_COMPA_vect, ISR_NOBLOCK) //ignitionSchedule4 #elif defined (CORE_TEENSY) && defined (__MK20DX256__) diff --git a/speeduino.ino b/speeduino.ino index 0bef03d1..d28d214b 100644 --- a/speeduino.ino +++ b/speeduino.ino @@ -825,7 +825,7 @@ void loop() readIAT(); readO2(); 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. @@ -976,6 +976,17 @@ void loop() injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree )); if(injector2StartAngle > CRANK_ANGLE_MAX) {injector2StartAngle -= CRANK_ANGLE_MAX;} break; + //5 cylinders + case 5: + injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree )); + if(injector2StartAngle > CRANK_ANGLE_MAX) {injector2StartAngle -= CRANK_ANGLE_MAX;} + injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree )); + if(injector3StartAngle > CRANK_ANGLE_MAX) {injector3StartAngle -= CRANK_ANGLE_MAX;} + injector4StartAngle = (configPage1.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree )); + if(injector4StartAngle > CRANK_ANGLE_MAX) {injector4StartAngle -= CRANK_ANGLE_MAX;} + injector5StartAngle = (configPage1.inj1Ang + channel5InjDegrees - ( PWdivTimerPerDegree )); + if(injector5StartAngle > CRANK_ANGLE_MAX) {injector5StartAngle -= CRANK_ANGLE_MAX;} + break; //6 cylinders case 6: injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree )); @@ -1105,57 +1116,83 @@ void loop() | This will very likely need to be rewritten when sequential is enabled |------------------------------------------------------------------------------------------ */ - tempCrankAngle = crankAngle - channel2InjDegrees; - if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; } - tempStartAngle = injector2StartAngle - channel2InjDegrees; - if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; } - if (tempStartAngle <= tempCrankAngle && fuelSchedule2.schedulesSet == 0) { tempStartAngle += 360; } - if ( (tempStartAngle > tempCrankAngle) && channel2InjEnabled) - { - if (configPage1.injLayout == 1) - { - setFuelSchedule2(openInjector2and3, - ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), - (unsigned long)currentStatus.PW, - closeInjector2and3 - ); + if(channel2InjEnabled) + { + tempCrankAngle = crankAngle - channel2InjDegrees; + if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; } + tempStartAngle = injector2StartAngle - channel2InjDegrees; + if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; } + if (tempStartAngle <= tempCrankAngle && fuelSchedule2.schedulesSet == 0) { tempStartAngle += 360; } + if ( tempStartAngle > tempCrankAngle ) + { + if (configPage1.injLayout == 1) + { + setFuelSchedule2(openInjector2and3, + ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), + (unsigned long)currentStatus.PW, + closeInjector2and3 + ); + } + else + { + setFuelSchedule2(openInjector2, + ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), + (unsigned long)currentStatus.PW, + closeInjector2 + ); + } } - else - { - setFuelSchedule2(openInjector2, + } + + if(channel3InjEnabled) + { + tempCrankAngle = crankAngle - channel3InjDegrees; + if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; } + tempStartAngle = injector3StartAngle - channel3InjDegrees; + if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; } + if (tempStartAngle <= tempCrankAngle && fuelSchedule3.schedulesSet == 0) { tempStartAngle += 360; } + if ( tempStartAngle > tempCrankAngle ) + { + setFuelSchedule3(openInjector3, ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), (unsigned long)currentStatus.PW, - closeInjector2 + closeInjector3 ); } } - - tempCrankAngle = crankAngle - channel3InjDegrees; - if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; } - tempStartAngle = injector3StartAngle - channel3InjDegrees; - if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; } - if (tempStartAngle <= tempCrankAngle && fuelSchedule3.schedulesSet == 0) { tempStartAngle += 360; } - if ( (tempStartAngle > tempCrankAngle) && channel3InjEnabled) - { - setFuelSchedule3(openInjector3, - ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), - (unsigned long)currentStatus.PW, - closeInjector3 - ); + + if(channel4InjEnabled) + { + tempCrankAngle = crankAngle - channel4InjDegrees; + if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; } + tempStartAngle = injector4StartAngle - channel4InjDegrees; + if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; } + if (tempStartAngle <= tempCrankAngle && fuelSchedule4.schedulesSet == 0) { tempStartAngle += 360; } + if ( tempStartAngle > tempCrankAngle ) + { + setFuelSchedule4(openInjector4, + ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), + (unsigned long)currentStatus.PW, + closeInjector4 + ); + } } - - tempCrankAngle = crankAngle - channel4InjDegrees; - if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; } - tempStartAngle = injector4StartAngle - channel4InjDegrees; - if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; } - if (tempStartAngle <= tempCrankAngle && fuelSchedule4.schedulesSet == 0) { tempStartAngle += 360; } - if ( (tempStartAngle > tempCrankAngle) && channel4InjEnabled) - { - setFuelSchedule4(openInjector4, - ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), - (unsigned long)currentStatus.PW, - closeInjector4 - ); + + //if(channel5InjEnabled) + { + tempCrankAngle = crankAngle - channel5InjDegrees; + if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; } + tempStartAngle = injector5StartAngle - channel5InjDegrees; + if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; } + if (tempStartAngle <= tempCrankAngle && fuelSchedule5.schedulesSet == 0) { tempStartAngle += 360; } + if ( tempStartAngle > tempCrankAngle ) + { + setFuelSchedule5(openInjector5, + ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree), + (unsigned long)currentStatus.PW, + closeInjector5 + ); + } } } //*********************************************************************************************** @@ -1171,6 +1208,7 @@ void loop() if(ignitionOn && !currentStatus.launchingHard && !BIT_CHECK(currentStatus.spark, BIT_SPARK_BOOSTCUT) && !BIT_CHECK(currentStatus.spark, BIT_SPARK_HRDLIM)) { + //if ( (ignition1StartAngle > crankAngle))// && ign1LastRev != startRevolutions) //if ((ignition1StartAngle > crankAngle) == 0) //if ((ignition1StartAngle < crankAngle))