Teensy groundwork (Many to come)

This commit is contained in:
Josh Stewart 2016-10-07 17:34:27 +11:00
parent cb4d0b9ab6
commit 983e365dd7
7 changed files with 158 additions and 93 deletions

View File

@ -1,4 +1,9 @@
#ifndef AUX_H
#define AUX_H
void initialiseAuxPWM();
void boostControl();
void vvtControl();
volatile byte *boost_pin_port;
volatile byte boost_pin_mask;
@ -16,4 +21,4 @@ unsigned int vvt_pwm_max_count; //Used for variable PWM frequency
volatile unsigned int vvt_pwm_cur_value;
long vvt_pwm_target_value;
#endif

View File

@ -21,6 +21,7 @@ void fanControl()
else if (currentStatus.coolant <= (configPage4.fanSP - configPage4.fanHyster)) { digitalWrite(pinFan, fanLOW); }
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
void initialiseAuxPWM()
{
TCCR1B = 0x00; //Disbale Timer1 while we set it up
@ -53,9 +54,7 @@ void boostControl()
boostPID.Compute();
TIMSK1 |= (1 << OCIE1A); //Turn on the compare unit (ie turn on the interrupt)
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
else { TIMSK1 &= ~(1 << OCIE1A); } // Disable timer channel
#endif
}
void vvtControl()
@ -71,7 +70,6 @@ void vvtControl()
}
//The interrupt to control the Boost PWM
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ISR(TIMER1_COMPA_vect)
{
if (boost_pwm_state)
@ -107,6 +105,11 @@ ISR(TIMER1_COMPB_vect)
}
}
#elif defined(PROCESSOR_TEENSY_3_1) || defined(PROCESSOR_TEENSY_3_2)
#elif defined (CORE_TEENSY) && defined (__MK20DX256__)
//YET TO BE IMPLEMENTED ON TEENSY
void initialiseAuxPWM() { }
void boostControl() { }
void vvtControl() { }
#endif

View File

@ -75,7 +75,7 @@ void command()
break;
case 'W': // receive new VE obr constant at 'W'+<offset>+<newbyte>
int offset;
int valueOffset; //cannot use offset as a variable name, it is a reserved word for several teensy libraries
while (Serial.available() == 0) { }
if (isMap)
@ -84,15 +84,15 @@ void command()
offset1 = Serial.read();
while (Serial.available() == 0) { }
offset2 = Serial.read();
offset = word(offset2, offset1);
valueOffset = word(offset2, offset1);
}
else
{
offset = Serial.read();
valueOffset = Serial.read();
}
while (Serial.available() == 0) { }
receiveValue(offset, Serial.read());
receiveValue(valueOffset, Serial.read());
break;
case 't': // receive new Calibration info. Command structure: "t", <tble_idx> <data array>. This is an MS2/Extra command, NOT part of MS1 spec
@ -267,7 +267,7 @@ void sendValues(int packetlength, byte portNum)
return;
}
void receiveValue(int offset, byte newValue)
void receiveValue(int valueOffset, byte newValue)
{
void* pnt_configPage;//This only stores the address of the value that it's pointing to and not the max size
@ -275,24 +275,24 @@ void receiveValue(int offset, byte newValue)
switch (currentPage)
{
case veMapPage:
if (offset < 256) //New value is part of the fuel map
if (valueOffset < 256) //New value is part of the fuel map
{
fuelTable.values[15 - offset / 16][offset % 16] = newValue;
fuelTable.values[15 - valueOffset / 16][valueOffset % 16] = newValue;
return;
}
else
{
//Check whether this is on the X (RPM) or Y (MAP/TPS) axis
if (offset < 272)
if (valueOffset < 272)
{
//X Axis
fuelTable.axisX[(offset - 256)] = ((int)(newValue) * 100); //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct
fuelTable.axisX[(valueOffset - 256)] = ((int)(newValue) * 100); //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct
}
else
{
//Y Axis
offset = 15 - (offset - 272); //Need to do a translation to flip the order (Due to us using (0,0) in the top left rather than bottom right
fuelTable.axisY[offset] = (int)(newValue);
valueOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order (Due to us using (0,0) in the top left rather than bottom right
fuelTable.axisY[valueOffset] = (int)(newValue);
}
return;
}
@ -301,31 +301,31 @@ void receiveValue(int offset, byte newValue)
case veSetPage:
pnt_configPage = &configPage1; //Setup a pointer to the relevant config page
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if ( offset < page_size)
if (valueOffset < page_size)
{
*((byte *)pnt_configPage + (byte)offset) = newValue; //Need to subtract 80 because the map and bins (Which make up 80 bytes) aren't part of the config pages
*((byte *)pnt_configPage + (byte)valueOffset) = newValue; //Need to subtract 80 because the map and bins (Which make up 80 bytes) aren't part of the config pages
}
break;
case ignMapPage: //Ignition settings page (Page 2)
if (offset < 256) //New value is part of the ignition map
if (valueOffset < 256) //New value is part of the ignition map
{
ignitionTable.values[15 - offset / 16][offset % 16] = newValue;
ignitionTable.values[15 - valueOffset / 16][valueOffset % 16] = newValue;
return;
}
else
{
//Check whether this is on the X (RPM) or Y (MAP/TPS) axis
if (offset < 272)
if (valueOffset < 272)
{
//X Axis
ignitionTable.axisX[(offset - 256)] = (int)(newValue) * int(100); //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct
ignitionTable.axisX[(valueOffset - 256)] = (int)(newValue) * int(100); //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct
}
else
{
//Y Axis
offset = 15 - (offset - 272); //Need to do a translation to flip the order
ignitionTable.axisY[offset] = (int)(newValue);
valueOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order
ignitionTable.axisY[valueOffset] = (int)(newValue);
}
return;
}
@ -333,31 +333,31 @@ void receiveValue(int offset, byte newValue)
case ignSetPage:
pnt_configPage = &configPage2;
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if ( offset < page_size)
if (valueOffset < page_size)
{
*((byte *)pnt_configPage + (byte)offset) = newValue; //Need to subtract 80 because the map and bins (Which make up 80 bytes) aren't part of the config pages
*((byte *)pnt_configPage + (byte)valueOffset) = newValue; //Need to subtract 80 because the map and bins (Which make up 80 bytes) aren't part of the config pages
}
break;
case afrMapPage: //Air/Fuel ratio target settings page
if (offset < 256) //New value is part of the afr map
if (valueOffset < 256) //New value is part of the afr map
{
afrTable.values[15 - offset / 16][offset % 16] = newValue;
afrTable.values[15 - valueOffset / 16][valueOffset % 16] = newValue;
return;
}
else
{
//Check whether this is on the X (RPM) or Y (MAP/TPS) axis
if (offset < 272)
if (valueOffset < 272)
{
//X Axis
afrTable.axisX[(offset - 256)] = int(newValue) * int(100); //The RPM values sent by megasquirt are divided by 100, need to multiply it back by 100 to make it correct
afrTable.axisX[(valueOffset - 256)] = int(newValue) * int(100); //The RPM values sent by megasquirt are divided by 100, need to multiply it back by 100 to make it correct
}
else
{
//Y Axis
offset = 15 - (offset - 272); //Need to do a translation to flip the order
afrTable.axisY[offset] = int(newValue);
valueOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order
afrTable.axisY[valueOffset] = int(newValue);
}
return;
@ -366,52 +366,52 @@ void receiveValue(int offset, byte newValue)
case afrSetPage:
pnt_configPage = &configPage3;
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if ( offset < page_size)
if (valueOffset < page_size)
{
*((byte *)pnt_configPage + (byte)offset) = newValue; //Need to subtract 80 because the map and bins (Which make up 80 bytes) aren't part of the config pages
*((byte *)pnt_configPage + (byte)valueOffset) = newValue; //Need to subtract 80 because the map and bins (Which make up 80 bytes) aren't part of the config pages
}
break;
case iacPage: //Idle Air Control settings page (Page 4)
pnt_configPage = &configPage4;
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if ( offset < page_size)
if (valueOffset < page_size)
{
*((byte *)pnt_configPage + (byte)offset) = newValue;
*((byte *)pnt_configPage + (byte)valueOffset) = newValue;
}
break;
case boostvvtPage: //Boost and VVT maps (8x8)
if (offset < 64) //New value is part of the boost map
if (valueOffset < 64) //New value is part of the boost map
{
boostTable.values[7 - offset / 8][offset % 8] = newValue;
boostTable.values[7 - valueOffset / 8][valueOffset % 8] = newValue;
return;
}
else if (offset < 72) //New value is on the X (RPM) axis of the boost table
else if (valueOffset < 72) //New value is on the X (RPM) axis of the boost table
{
boostTable.axisX[(offset - 64)] = int(newValue) * int(100); //The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct
boostTable.axisX[(valueOffset - 64)] = int(newValue) * int(100); //The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct
return;
}
else if (offset < 80) //New value is on the Y (TPS) axis of the boost table
else if (valueOffset < 80) //New value is on the Y (TPS) axis of the boost table
{
boostTable.axisY[(7 - (offset - 72))] = int(newValue);
boostTable.axisY[(7 - (valueOffset - 72))] = int(newValue);
return;
}
else if (offset < 144) //New value is part of the vvt map
else if (valueOffset < 144) //New value is part of the vvt map
{
offset = offset - 80;
vvtTable.values[7 - offset / 8][offset % 8] = newValue;
valueOffset = valueOffset - 80;
vvtTable.values[7 - valueOffset / 8][valueOffset % 8] = newValue;
return;
}
else if (offset < 152) //New value is on the X (RPM) axis of the vvt table
else if (valueOffset < 152) //New value is on the X (RPM) axis of the vvt table
{
offset = offset - 144;
vvtTable.axisX[offset] = int(newValue) * int(100); //The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct
valueOffset = valueOffset - 144;
vvtTable.axisX[valueOffset] = int(newValue) * int(100); //The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct
return;
}
else //New value is on the Y (Load) axis of the vvt table
{
offset = offset - 152;
vvtTable.axisY[(7 - offset)] = int(newValue);
valueOffset = valueOffset - 152;
vvtTable.axisY[(7 - valueOffset)] = int(newValue);
return;
}
default:

3
idle.h
View File

@ -36,4 +36,5 @@ long idle_pwm_target_value;
long idle_cl_target_rpm;
void initialiseIdle();
static inline void disableIdle();
static inline void enableIdle();

View File

@ -53,7 +53,7 @@ void initialiseIdle()
idle2_pin_port = portOutputRegister(digitalPinToPort(pinIdle2));
idle2_pin_mask = digitalPinToBitMask(pinIdle2);
idle_pwm_max_count = 1000000L / (16 * configPage3.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz
TIMSK4 |= (1 << OCIE4C); //Turn on the C compare unit (ie turn on the interrupt)
enableIdle();
break;
case 3:
@ -141,8 +141,8 @@ void idleControl()
{
//Standard running
currentStatus.idleDuty = table2D_getValue(&iacPWMTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //All temps are offset by 40 degrees
if( currentStatus.idleDuty == 0 ) { TIMSK4 &= ~(1 << OCIE4C); digitalWrite(pinIdle1, LOW); break; }
TIMSK4 |= (1 << OCIE4C); //Turn on the C compare unit (ie turn on the interrupt)
if( currentStatus.idleDuty == 0 ) { disableIdle(); break; }
enableIdle();
idle_pwm_target_value = percentage(currentStatus.idleDuty, idle_pwm_max_count);
idleOn = true;
}
@ -154,8 +154,8 @@ void idleControl()
//idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD);
idlePID.Compute();
if( idle_pwm_target_value == 0 ) { TIMSK4 &= ~(1 << OCIE4C); digitalWrite(pinIdle1, LOW); }
else{ TIMSK4 |= (1 << OCIE4C); } //Turn on the C compare unit (ie turn on the interrupt)
if( idle_pwm_target_value == 0 ) { disableIdle(); }
else{ enableIdle(); } //Turn on the C compare unit (ie turn on the interrupt)
//idle_pwm_target_value = 104;
break;
@ -240,6 +240,20 @@ void homeStepper()
//The interrupt to turn off the idle pwm
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
//This function simply turns off the idle PWM and sets the pin low
static inline void disableIdle()
{
TIMSK4 &= ~(1 << OCIE4C); //Turn off interrupt
digitalWrite(pinIdle1, LOW);
}
//Any common functions associated with starting the Idle
//Typically this is enabling the PWM interrupt
static inline void enableIdle()
{
TIMSK4 |= (1 << OCIE4C); //Turn on the C compare unit (ie turn on the interrupt)
}
ISR(TIMER4_COMPC_vect)
{
if (idle_pwm_state)
@ -280,5 +294,11 @@ ISR(TIMER4_COMPC_vect)
}
#elif defined(PROCESSOR_TEENSY_3_1) || defined(PROCESSOR_TEENSY_3_2)
void idle_off() { }
//This function simply turns off the idle PWM and sets the pin low
static inline void disableIdle()
{
digitalWrite(pinIdle1, LOW);
}
static inline void enableIdle() { }
#endif

View File

@ -10,7 +10,8 @@ A full copy of the license may be found in the projects root directory
void initialiseSchedulers()
{
nullSchedule.Status = OFF;
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
// 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
@ -19,15 +20,6 @@ void initialiseSchedulers()
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
//TCCR3B = 0x03; //Timer3 Control Reg B: Timer Prescaler set to 64. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
fuelSchedule1.Status = OFF;
fuelSchedule2.Status = OFF;
fuelSchedule3.Status = OFF;
fuelSchedule5.Status = OFF;
fuelSchedule1.schedulesSet = 0;
fuelSchedule2.schedulesSet = 0;
fuelSchedule3.schedulesSet = 0;
//Ignition Schedules, which uses timer 5
TCCR5B = 0x00; //Disable Timer3 while we set it up
@ -36,26 +28,40 @@ void initialiseSchedulers()
TCCR5A = 0x00; //Timer5 Control Reg A: Wave Gen Mode normal
//TCCR5B = (1 << CS12); //Timer5 Control Reg B: Timer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
TCCR5B = 0x03; //aka Divisor = 64 = 490.1Hz
ignitionSchedule1.Status = OFF;
ignitionSchedule2.Status = OFF;
ignitionSchedule3.Status = OFF;
ignitionSchedule1.schedulesSet = 0;
ignitionSchedule2.schedulesSet = 0;
ignitionSchedule3.schedulesSet = 0;
//The remaining Schedules (Schedules 4 for fuel and ignition) use Timer4
TCCR4B = 0x00; //Disable Timer4 while we set it up
TCNT4 = 0; //Reset Timer Count
TIFR4 = 0x00; //Timer4 INT Flag Reg: Clear Timer Overflow Flag
TCCR4A = 0x00; //Timer4 Control Reg A: Wave Gen Mode normal
TCCR4B = (1 << CS12); //Timer4 Control Reg B: aka Divisor = 256 = 122.5HzTimer Prescaler set to 256. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
ignitionSchedule4.Status = OFF;
fuelSchedule4.Status = OFF;
#elif defined (CORE_TEENSY) && defined (__MK20DX256__)
//Configure ARM timers here
#endif
ignitionSchedule4.schedulesSet = 0;
fuelSchedule1.Status = OFF;
fuelSchedule2.Status = OFF;
fuelSchedule3.Status = OFF;
fuelSchedule4.Status = OFF;
fuelSchedule5.Status = OFF;
fuelSchedule1.schedulesSet = 0;
fuelSchedule2.schedulesSet = 0;
fuelSchedule3.schedulesSet = 0;
fuelSchedule4.schedulesSet = 0;
//Note that timer4 compare channel C is used by the idle control
fuelSchedule5.schedulesSet = 0;
ignitionSchedule1.Status = OFF;
ignitionSchedule2.Status = OFF;
ignitionSchedule3.Status = OFF;
ignitionSchedule4.Status = OFF;
ignitionSchedule1.schedulesSet = 0;
ignitionSchedule2.schedulesSet = 0;
ignitionSchedule3.schedulesSet = 0;
ignitionSchedule4.schedulesSet = 0;
}
/*
@ -82,6 +88,7 @@ void setFuelSchedule1(void (*startCallback)(), unsigned long timeout, unsigned l
* 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
*/
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
noInterrupts();
fuelSchedule1.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16
fuelSchedule1.endCompare = fuelSchedule1.startCompare + (duration >> 4);
@ -91,6 +98,7 @@ void setFuelSchedule1(void (*startCallback)(), unsigned long timeout, unsigned l
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)
#endif
}
void setFuelSchedule2(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
{
@ -106,6 +114,7 @@ void setFuelSchedule2(void (*startCallback)(), unsigned long timeout, unsigned l
* 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
*/
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
noInterrupts();
fuelSchedule2.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16
fuelSchedule2.endCompare = fuelSchedule2.startCompare + (duration >> 4);
@ -114,40 +123,57 @@ void setFuelSchedule2(void (*startCallback)(), unsigned long timeout, unsigned l
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)
#endif
}
void setFuelSchedule3(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
{
if(fuelSchedule3.Status == RUNNING) { return; } //Check that we're not already part way through a schedule
fuelSchedule3.StartCallback = startCallback; //Name the start callback function
fuelSchedule3.EndCallback = endCallback; //Name the end callback function
fuelSchedule3.duration = duration;
//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 require
/*
* 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
*/
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
noInterrupts();
fuelSchedule3.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16
fuelSchedule3.endCompare = fuelSchedule3.startCompare + (duration >> 4);
OCR3C = fuelSchedule3.startCompare; //Use the C copmare unit of timer 3
fuelSchedule3.duration = duration;
fuelSchedule3.StartCallback = startCallback; //Name the start callback function
fuelSchedule3.EndCallback = endCallback; //Name the end callback function
fuelSchedule3.Status = PENDING; //Turn this schedule on
fuelSchedule3.schedulesSet++; //Increment the number of times this schedule has been set
interrupts();
TIMSK3 |= (1 << OCIE3C); //Turn on the C compare unit (ie turn on the interrupt)
#endif
}
void setFuelSchedule4(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)()) //Uses timer 4 compare B
{
if(fuelSchedule4.Status == RUNNING) { return; } //Check that we're not already part way through a schedule
fuelSchedule4.StartCallback = startCallback; //Name the start callback function
fuelSchedule4.EndCallback = endCallback; //Name the end callback function
fuelSchedule4.duration = duration;
//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 = TCNT4 + (timeout / 4); //Each tick occurs every 4uS with the 128 prescaler, so divide the timeout by 4 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
/*
* 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
*/
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
noInterrupts();
fuelSchedule4.startCompare = TCNT4 + (timeout >> 4);
fuelSchedule4.endCompare = fuelSchedule4.startCompare + (duration >> 4);
OCR4B = fuelSchedule4.startCompare; //Use the C copmare unit of timer 3
fuelSchedule4.duration = duration;
fuelSchedule4.StartCallback = startCallback; //Name the start callback function
fuelSchedule4.EndCallback = endCallback; //Name the end callback function
fuelSchedule4.Status = PENDING; //Turn this schedule on
fuelSchedule4.schedulesSet++; //Increment the number of times this schedule has been set
interrupts();
TIMSK4 |= (1 << OCIE4B); //Turn on the B compare unit (ie turn on the interrupt)
#endif
}
void setFuelSchedule5(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
{
@ -163,6 +189,7 @@ void setFuelSchedule5(void (*startCallback)(), unsigned long timeout, unsigned l
/*
* The following must be enclosed in the noIntterupts block to avoid contention caused if the relevant interrupts fires before the state is fully set
*/
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
noInterrupts();
fuelSchedule5.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16
fuelSchedule5.endCompare = fuelSchedule5.startCompare + (duration >> 4);
@ -171,6 +198,7 @@ void setFuelSchedule5(void (*startCallback)(), unsigned long timeout, unsigned l
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)
#endif
}
//Ignition schedulers use Timer 5
void setIgnitionSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
@ -252,7 +280,11 @@ void setIgnitionSchedule5(void (*startCallback)(), unsigned long timeout, unsign
//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__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
ISR(TIMER3_COMPA_vect, ISR_NOBLOCK) //fuelSchedules 1 and 5
#elif defined (CORE_TEENSY) && defined (__MK20DX256__)
void timer3compareAinterrupt() //Most ARM chips can simply call a function
#endif
{
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
@ -270,7 +302,11 @@ ISR(TIMER3_COMPA_vect, ISR_NOBLOCK) //fuelSchedules 1 and 5
}
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //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
{

View File

@ -460,7 +460,7 @@ void setup()
currentLoopTime = micros();
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
//This sets the ADC (Analog to Digitial Converter) to run at 1Mhz, greatly reducing analog read times (MAP/TPS)
//1Mhz is the fastest speed permitted by the CPU without affecting accuracy
//Please see chapter 11 of 'Practical Arduino' (http://books.google.com.au/books?id=HsTxON1L6D4C&printsec=frontcover#v=onepage&q&f=false) for more details
@ -470,6 +470,7 @@ void setup()
cbi(ADCSRA,ADPS1);
cbi(ADCSRA,ADPS0);
#endif
#endif
mainLoopCount = 0;
@ -817,7 +818,7 @@ void loop()
fuelOn = false;
if (fpPrimed) { digitalWrite(pinFuelPump, LOW); } //Turn off the fuel pump, but only if the priming is complete
fuelPumpOn = false;
TIMSK4 &= ~(1 << OCIE4C); digitalWrite(pinIdle1, LOW); //Turns off the idle control PWM. This REALLY needs to be cleaned up into a general PWM controller class
disableIdle(); //Turn off the idle PWM
}
//Uncomment the following for testing
@ -1002,7 +1003,6 @@ void loop()
if( !BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
{
unsigned long pwLimit = percentage(configPage1.dutyLim, revolutionTime); //The pulsewidth limit is determined to be the duty cycle limit (Eg 85%) by the total time it takes to perform 1 revolution
if (
if (currentStatus.PW > pwLimit) { currentStatus.PW = pwLimit; }
}