Huge rewrite of the schedule code to add all 4 required schedules
This commit is contained in:
parent
251886d8aa
commit
d86597d700
|
@ -17,7 +17,6 @@ Need to calculate the req_fuel figure here, preferably in pre-processor macro
|
|||
#define pinTPS 8 //TPS input pin
|
||||
#define pinTrigger 2 //The CAS pin
|
||||
#define pinMAP 0 //MAP sensor pin
|
||||
#define triggerFilterTime 100 // The shortest time (in uS) that pulses will be accepted (Used for debounce filtering)
|
||||
//**************************************************************************************************
|
||||
|
||||
#include "globals.h"
|
||||
|
@ -42,6 +41,7 @@ int req_fuel_uS = configPage1.reqFuel * 1000; //Convert to uS and an int. This i
|
|||
// These aren't really configuration options, more so a description of how the hardware is setup. These are things that will be defined in the recommended hardware setup
|
||||
int triggerActualTeeth = configPage2.triggerTeeth - configPage2.triggerMissingTeeth; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt
|
||||
int triggerToothAngle = 360 / configPage2.triggerTeeth; //The number of degrees that passes from tooth to tooth
|
||||
int triggerFilterTime = 100; // The shortest time (in uS) that pulses will be accepted (Used for debounce filtering)
|
||||
|
||||
volatile int toothCurrentCount = 0; //The current number of teeth (Onec sync has been achieved, this can never actually be 0
|
||||
volatile unsigned long toothLastToothTime = 0; //The time (micros()) that the last tooth was registered
|
||||
|
@ -123,7 +123,7 @@ void setup() {
|
|||
//Setup the dummy fuel and ignition tables
|
||||
dummyFuelTable(&fuelTable);
|
||||
dummyIgnitionTable(&ignitionTable);
|
||||
initialiseScheduler();
|
||||
initialiseSchedulers();
|
||||
counter = 0;
|
||||
|
||||
configPage2.triggerTeeth = 12; //TESTING ONLY!
|
||||
|
@ -214,7 +214,7 @@ void loop()
|
|||
//This may potentially be called a number of times as we get closer and closer to the opening time
|
||||
if (injectorStartAngle > crankAngle)
|
||||
{
|
||||
setSchedule1(openInjector,
|
||||
setFuelSchedule1(openInjector,
|
||||
(injectorStartAngle - crankAngle) * timePerDegree,
|
||||
currentStatus.PW,
|
||||
closeInjector
|
||||
|
@ -223,7 +223,7 @@ void loop()
|
|||
//Likewise for the ignition
|
||||
if (ignitionStartAngle > crankAngle)
|
||||
{
|
||||
setSchedule2(beginCoilCharge,
|
||||
setIgnitionSchedule1(beginCoilCharge,
|
||||
(ignitionStartAngle - crankAngle) * timePerDegree,
|
||||
configPage2.dwellRun,
|
||||
endCoilCharge
|
||||
|
@ -278,17 +278,24 @@ void trigger()
|
|||
if ( (curTime - toothLastToothTime) < triggerFilterTime) { interrupts(); return; } //Debounce check. Pulses should never be less than 100uS, so if they are it means a false trigger. (A 36-1 wheel at 8000pm will have triggers approx. every 200uS)
|
||||
toothCurrentCount++; //Increment the tooth counter
|
||||
|
||||
//Serial.println("Got trigger");
|
||||
//Begin the missing tooth detection
|
||||
//If the time between the current tooth and the last is greater than 1.5x the time between the last tooth and the tooth before that, we make the assertion that we must be at the first tooth after the gap
|
||||
//if ( (curTime - toothLastToothTime) > (1.5 * (toothLastToothTime - toothLastMinusOneToothTime))) { toothCurrentCount = 1; }
|
||||
//if ( (curTime - toothLastToothTime) > ((3 * (toothLastToothTime - toothLastMinusOneToothTime))>>1)) { toothCurrentCount = 1; } //Same as above, but uses bitshift instead of multiplying by 1.5
|
||||
if (toothCurrentCount > triggerActualTeeth)
|
||||
if ( (curTime - toothLastToothTime) > ((3 * (toothLastToothTime - toothLastMinusOneToothTime))>>1)) //Same as above, but uses bitshift instead of multiplying by 1.5
|
||||
{
|
||||
toothCurrentCount = 1;
|
||||
toothOneMinusOneTime = toothOneTime;
|
||||
toothOneTime = curTime;
|
||||
}
|
||||
//TESTING METHOD
|
||||
/*
|
||||
if (toothCurrentCount > triggerActualTeeth) }
|
||||
{
|
||||
toothCurrentCount = 1;
|
||||
toothOneMinusOneTime = toothOneTime;
|
||||
toothOneTime = curTime;
|
||||
} //For testing ONLY
|
||||
}
|
||||
*/
|
||||
|
||||
toothLastMinusOneToothTime = toothLastToothTime;
|
||||
toothLastToothTime = curTime;
|
||||
|
|
28
scheduler.h
28
scheduler.h
|
@ -26,18 +26,22 @@ See page 136 of the processors datasheet: http://www.atmel.com/Images/doc2549.pd
|
|||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
//#define clockspeed 16000000
|
||||
void initialiseSchedulers();
|
||||
void setFuelSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)());
|
||||
void setFuelSchedule2(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)());
|
||||
void setIgnitionSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)());
|
||||
void setIgnitionSchedule2(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)());
|
||||
|
||||
int schedule1Status; //Value=0 means do nothing, value=1 means call the startCallback, value=2 means call the endCallback
|
||||
int schedule2Status; //As above, for 2nd scheduler
|
||||
unsigned long schedule1Duration; //How long (uS) after calling the start callback to we call the end callback
|
||||
unsigned long schedule2Duration;
|
||||
void (*schedule1StartCallback)(); //Start Callback function for schedule1
|
||||
void (*schedule2StartCallback)();
|
||||
void (*schedule1EndCallback)(); //End Callback function for schedule1
|
||||
void (*schedule2EndCallback)();
|
||||
enum ScheduleStatus {OFF, PENDING, RUNNING}; //The 3 statuses that a schedule can have
|
||||
|
||||
struct Schedule {
|
||||
unsigned long duration;
|
||||
ScheduleStatus Status;
|
||||
void (*StartCallback)(); //Start Callback function for schedule
|
||||
void (*EndCallback)(); //Start Callback function for schedule
|
||||
};
|
||||
|
||||
void initialiseScheduler();
|
||||
void setSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)());
|
||||
void setSchedule2(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)());
|
||||
Schedule fuelSchedule1;
|
||||
Schedule fuelSchedule2;
|
||||
Schedule ignitionSchedule1;
|
||||
Schedule ignitionSchedule2;
|
||||
|
|
199
scheduler.ino
199
scheduler.ino
|
@ -1,98 +1,165 @@
|
|||
|
||||
|
||||
|
||||
void initialiseScheduler()
|
||||
void initialiseSchedulers()
|
||||
{
|
||||
|
||||
// Much help in this from http://arduinomega.blogspot.com.au/2011/05/timer2-and-overflow-interrupt-lets-get.html
|
||||
//Schedule 1, which is uses timer 3
|
||||
TCCR3B = 0x00; //Disbale Timer2 while we set it up
|
||||
//Fuel Schedules, which uses timer 3
|
||||
TCCR3B = 0x00; //Disbale Timer3 while we set it up
|
||||
TCNT3 = 0; //Reset Timer Count
|
||||
TIFR3 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
|
||||
TIMSK3 = 0x01; //Timer2 INT Reg: Timer2 Overflow Interrupt Enable
|
||||
TCCR3A = 0x00; //Timer2 Control Reg A: Wave Gen Mode normal
|
||||
TCCR3B = (1 << CS12); //Timer2 Control Reg B: Timer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
|
||||
|
||||
//Schedule 2, which is uses timer 4
|
||||
TCCR4B = 0x00; //Disbale Timer2 while we set it up
|
||||
TCNT4 = 0; //Reset Timer Count
|
||||
TIFR4 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
|
||||
TIMSK4 = 0x01; //Timer2 INT Reg: Timer2 Overflow Interrupt Enable
|
||||
TCCR4A = 0x00; //Timer2 Control Reg A: Wave Gen Mode normal
|
||||
TCCR4B = (1 << CS12); //Timer2 Control Reg B: Timer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
|
||||
|
||||
schedule1Status = 0;
|
||||
schedule2Status = 0;
|
||||
TIFR3 = 0x00; //Timer3 INT Flag Reg: Clear Timer Overflow Flag
|
||||
TCCR3A = 0x00; //Timer3 Control Reg A: Wave Gen Mode normal
|
||||
TCCR3B = (1 << CS12); //Timer3 Control Reg B: Timer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
|
||||
fuelSchedule1.Status = OFF;
|
||||
fuelSchedule2.Status = OFF;
|
||||
|
||||
//Ignition Schedules, which uses timer 5
|
||||
TCCR5B = 0x00; //Disbale Timer3 while we set it up
|
||||
TCNT5 = 0; //Reset Timer Count
|
||||
TIFR5 = 0x00; //Timer3 INT Flag Reg: Clear Timer Overflow Flag
|
||||
TCCR5A = 0x00; //Timer3 Control Reg A: Wave Gen Mode normal
|
||||
TCCR5B = (1 << CS12); //Timer3 Control Reg B: Timer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
|
||||
ignitionSchedule1.Status = OFF;
|
||||
ignitionSchedule2.Status = OFF;
|
||||
}
|
||||
|
||||
/*
|
||||
This turns schedule 1 on, gives it callback functions and resets the relevant timer based on the time in the future that this should be triggered
|
||||
These 4 function turn a schedule on, provides the time to start and the duration and gives it callback functions.
|
||||
All 4 functions operate the same, just on different schedules
|
||||
Args:
|
||||
startCallback: The function to be called once the timeout1 is reached
|
||||
timeout1: The number of uS in the future that the callback should be triggered
|
||||
duration: The number of uS before endCallback is called
|
||||
startCallback: The function to be called once the timeout is reached
|
||||
timeout: The number of uS in the future that the callback should be triggered
|
||||
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
|
||||
*/
|
||||
void setSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
|
||||
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))
|
||||
//TODO: Need to add check for timeout > 1048576 ????
|
||||
if(schedule1Status == 2) { return; } //Check that we're note already part way through a schedule
|
||||
TCNT3 = 65536 - (timeout / 16); //Each tick occurs every 16uS with a 256 prescaler so divide the timeout by 16 to get ther required number of ticks. Subtract this from the total number of tick (65536 for 16-bit timer)
|
||||
schedule1Duration = duration;
|
||||
schedule1StartCallback = startCallback; //Name the start callback function
|
||||
schedule1EndCallback = endCallback; //Name the start callback function
|
||||
schedule1Status = 1; //Turn this schedule on and set it
|
||||
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
|
||||
OCR3A = absoluteTimeout;
|
||||
fuelSchedule1.duration = duration;
|
||||
fuelSchedule1.StartCallback = startCallback; //Name the start callback function
|
||||
fuelSchedule1.EndCallback = endCallback; //Name the start callback function
|
||||
fuelSchedule1.Status = PENDING; //Turn this schedule on
|
||||
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
|
||||
OCR3B = absoluteTimeout; //Use the B copmare unit of timer 3
|
||||
fuelSchedule2.duration = duration;
|
||||
fuelSchedule2.StartCallback = startCallback; //Name the start callback function
|
||||
fuelSchedule2.EndCallback = endCallback; //Name the start callback function
|
||||
fuelSchedule2.Status = PENDING; //Turn this schedule on
|
||||
TIMSK3 |= (1 << OCIE3B); //Turn on the B compare unit (ie turn on the interrupt)
|
||||
}
|
||||
//Ignition schedulers use Timer 5
|
||||
void setIgnitionSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
|
||||
{
|
||||
if(ignitionSchedule1.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 = TCNT5 + (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
|
||||
OCR5A = absoluteTimeout;
|
||||
ignitionSchedule1.duration = duration;
|
||||
ignitionSchedule1.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule1.EndCallback = endCallback; //Name the start callback function
|
||||
ignitionSchedule1.Status = PENDING; //Turn this schedule on
|
||||
TIMSK5 |= (1 << OCIE5A); //Turn on the A compare unit (ie turn on the interrupt)
|
||||
}
|
||||
void setIgnitionSchedule2(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
|
||||
{
|
||||
if(ignitionSchedule2.Status == RUNNING) { return; } //Check that we're not already part way through a schedule
|
||||
|
||||
//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 = TCNT5 + (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
|
||||
OCR5B = absoluteTimeout;
|
||||
ignitionSchedule2.duration = duration;
|
||||
ignitionSchedule2.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule2.EndCallback = endCallback; //Name the start callback function
|
||||
ignitionSchedule2.Status = PENDING; //Turn this schedule on
|
||||
TIMSK5 |= (1 << OCIE5B); //Turn on the A compare unit (ie turn on the interrupt)
|
||||
}
|
||||
|
||||
//As above, but for schedule2
|
||||
void setSchedule2(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
|
||||
//Timer3A (fuel schedule 1) Compare Vector
|
||||
//This function 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
|
||||
ISR(TIMER3_COMPA_vect) //fuelSchedule1
|
||||
{
|
||||
//TODO: Need to add check for timeout > 1048576 ????
|
||||
if(schedule2Status == 2) { return; } //Check that we're note already part way through a schedule
|
||||
TCNT4 = 65536 - (timeout / 16); //Each tick occurs every 16uS with a 256 prescaler so divide the timeout by 16 to get ther required number of ticks. Subtract this from the total number of tick (65536 for 16-bit timer)
|
||||
schedule2Duration = duration;
|
||||
schedule2StartCallback = startCallback; //Name the callback function
|
||||
schedule2EndCallback = endCallback; //Name the callback function
|
||||
schedule2Status = 1; //Turn this schedule on
|
||||
if (fuelSchedule1.Status == PENDING) //Check to see if this schedule is turn on
|
||||
{
|
||||
fuelSchedule1.StartCallback();
|
||||
fuelSchedule1.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
|
||||
unsigned int absoluteTimeout = TCNT3 + (fuelSchedule1.duration / 16);
|
||||
OCR3A = absoluteTimeout;
|
||||
}
|
||||
else if (fuelSchedule1.Status == RUNNING)
|
||||
{
|
||||
fuelSchedule1.EndCallback();
|
||||
fuelSchedule1.Status = OFF; //Turn off the schedule
|
||||
TIMSK3 &= ~(1 << OCIE3A); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3)
|
||||
}
|
||||
//TIFR3 = 0x00; //Timer3 INT Flag Reg: Clear Timer Overflow Flag. I'm not 100% sure this is necessary, but better to be safe
|
||||
}
|
||||
|
||||
//Timer3 (schedule 1) Overflow Interrupt Vector
|
||||
//This needs to call the callback function if one has been provided and rest the timer
|
||||
ISR(TIMER3_OVF_vect)
|
||||
ISR(TIMER3_COMPB_vect) //fuelSchedule2
|
||||
{
|
||||
if (schedule1Status == 1) //Check to see if this schedule is turn on
|
||||
if (fuelSchedule2.Status == PENDING) //Check to see if this schedule is turn on
|
||||
{
|
||||
schedule1StartCallback(); //Replace with user provided callback
|
||||
schedule1Status = 2; //Turn off the callback
|
||||
TCNT3 = 65536 - (schedule1Duration / 16);
|
||||
fuelSchedule2.StartCallback();
|
||||
fuelSchedule2.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
|
||||
unsigned int absoluteTimeout = TCNT3 + (fuelSchedule2.duration / 16);
|
||||
OCR3B = absoluteTimeout;
|
||||
}
|
||||
else if (schedule1Status == 2)
|
||||
else if (fuelSchedule2.Status == RUNNING)
|
||||
{
|
||||
schedule1EndCallback();
|
||||
schedule1Status = 0; //Turn off the callback
|
||||
TCNT3 = 0; //Reset Timer to 0 out of 255
|
||||
fuelSchedule2.EndCallback();
|
||||
fuelSchedule2.Status = OFF; //Turn off the schedule
|
||||
TIMSK3 &= ~(1 << OCIE3B); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3)
|
||||
}
|
||||
|
||||
TIFR3 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
|
||||
//TIFR3 = 0x00; //Timer3 INT Flag Reg: Clear Timer Overflow Flag. I'm not 100% sure this is necessary, but better to be safe
|
||||
}
|
||||
|
||||
//AS above for schedule2
|
||||
ISR(TIMER4_OVF_vect)
|
||||
ISR(TIMER5_COMPA_vect) //ignitionSchedule1
|
||||
{
|
||||
if (schedule2Status == 1) //A value of 1 means call the start callback
|
||||
if (ignitionSchedule1.Status == PENDING) //Check to see if this schedule is turn on
|
||||
{
|
||||
schedule2StartCallback();
|
||||
schedule2Status = 2; //Set to call the end callback on the next run
|
||||
TCNT4 = 65536 - (schedule2Duration / 16);
|
||||
ignitionSchedule1.StartCallback();
|
||||
ignitionSchedule1.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
|
||||
unsigned int absoluteTimeout = TCNT5 + (ignitionSchedule1.duration / 16);
|
||||
OCR5A = absoluteTimeout;
|
||||
}
|
||||
else if (schedule2Status == 2)
|
||||
else if (ignitionSchedule1.Status == RUNNING)
|
||||
{
|
||||
schedule2EndCallback();
|
||||
schedule2Status = 0; //Turn off the callback
|
||||
TCNT4 = 0; //Reset Timer to 0 out of 255
|
||||
ignitionSchedule1.EndCallback();
|
||||
ignitionSchedule1.Status = OFF; //Turn off the schedule
|
||||
TIMSK5 &= ~(1 << OCIE5A); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3)
|
||||
}
|
||||
|
||||
TIFR4 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
|
||||
//TIFR3 = 0x00; //Timer3 INT Flag Reg: Clear Timer Overflow Flag. I'm not 100% sure this is necessary, but better to be safe
|
||||
}
|
||||
ISR(TIMER5_COMPB_vect) //ignitionSchedule2
|
||||
{
|
||||
if (ignitionSchedule2.Status == PENDING) //Check to see if this schedule is turn on
|
||||
{
|
||||
ignitionSchedule2.StartCallback();
|
||||
ignitionSchedule2.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
|
||||
unsigned int absoluteTimeout = TCNT5 + (ignitionSchedule2.duration / 16);
|
||||
OCR5B = absoluteTimeout;
|
||||
}
|
||||
else if (ignitionSchedule2.Status == RUNNING)
|
||||
{
|
||||
ignitionSchedule2.EndCallback();
|
||||
ignitionSchedule2.Status = OFF; //Turn off the schedule
|
||||
TIMSK5 &= ~(1 << OCIE5B); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3)
|
||||
}
|
||||
//TIFR3 = 0x00; //Timer3 INT Flag Reg: Clear Timer Overflow Flag. I'm not 100% sure this is necessary, but better to be safe
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue