update with josh2 13102016
This commit is contained in:
parent
501778a8fe
commit
6289f0cda2
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
//YET TO BE IMPLEMENTED ON TEENSY
|
||||
void initialiseAuxPWM() { }
|
||||
void boostControl() { }
|
||||
void vvtControl() { }
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
#define veMapPage 1
|
||||
|
||||
|
||||
uint8_t currentcanPage = 1;//Not the same as the speeduino config page numbers
|
||||
uint8_t currentCanPage = 1;//Not the same as the speeduino config page numbers
|
||||
uint8_t nCanretry = 0; //no of retrys
|
||||
uint8_t cancmdfail = 0; //command fail yes/no
|
||||
uint8_t canlisten = 0;
|
||||
uint8_t Lbuffer[8]; //8 byte buffer to store incomng can data
|
||||
|
||||
|
||||
void Cancommand();//This is the heart of the Command Line Interpeter. All that needed to be done was to make it human readable.
|
||||
void canCommand();//This is the heart of the Command Line Interpeter. All that needed to be done was to make it human readable.
|
||||
void sendCancommand(uint8_t cmdtype , uint16_t canadddress, uint8_t candata1, uint8_t candata2);
|
||||
void testCanComm();
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ sendcancommand is called when a comman d is to be sent via serial3 to the Can in
|
|||
//#include "globals.h"
|
||||
//#include "storage.h"
|
||||
|
||||
void Cancommand()
|
||||
void canCommand()
|
||||
{
|
||||
switch (Serial3.read())
|
||||
{
|
||||
|
|
128
comms.ino
128
comms.ino
|
@ -18,7 +18,7 @@ void command()
|
|||
switch (Serial.read())
|
||||
{
|
||||
case 'A': // send x bytes of realtime values
|
||||
sendValues(packetSize,0); //send values to serial0
|
||||
sendValues(packetSize, 0); //send values to serial0
|
||||
break;
|
||||
|
||||
case 'B': // Burn current values to eeprom
|
||||
|
@ -62,12 +62,12 @@ void command()
|
|||
break;
|
||||
|
||||
case 'S': // send code version
|
||||
Serial.print("Speeduino 2016.09");
|
||||
Serial.print("Speeduino 2016.10-dev");
|
||||
currentStatus.secl = 0; //This is required in TS3 due to its stricter timings
|
||||
break;
|
||||
|
||||
case 'Q': // send code version
|
||||
Serial.print("speeduino 201609-dev");
|
||||
Serial.print("speeduino 201610-dev");
|
||||
break;
|
||||
|
||||
case 'V': // send VE table and constants in binary
|
||||
|
@ -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
|
||||
|
@ -198,20 +198,21 @@ void command()
|
|||
/*
|
||||
This function returns the current values of a fixed group of variables
|
||||
*/
|
||||
void sendValues(int packetlength, byte portnum)
|
||||
void sendValues(int packetlength, byte portNum)
|
||||
{
|
||||
byte response[packetlength];
|
||||
|
||||
if (portnum == 3){ //if port number is 3
|
||||
if (portNum == 3)
|
||||
{
|
||||
//CAN serial
|
||||
Serial3.write("A"); //confirm cmd type
|
||||
Serial3.write(packetlength); //confirm no of byte to be sent
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if(requestCount == 0) { currentStatus.secl = 0; }
|
||||
requestCount++;
|
||||
}
|
||||
{
|
||||
if(requestCount == 0) { currentStatus.secl = 0; }
|
||||
requestCount++;
|
||||
}
|
||||
|
||||
currentStatus.spark ^= (-currentStatus.hasSync ^ currentStatus.spark) & (1 << BIT_SPARK_SYNC); //Set the sync bit of the Spark variable to match the hasSync variable
|
||||
|
||||
|
@ -260,14 +261,13 @@ void sendValues(int packetlength, byte portnum)
|
|||
response[34] = getNextError();
|
||||
|
||||
//cli();
|
||||
if (portnum == 0){Serial.write(response, (size_t)packetlength);}
|
||||
else if (portnum == 3){Serial3.write(response, (size_t)packetlength);}
|
||||
//Serial.flush();
|
||||
if (portNum == 0) { Serial.write(response, (size_t)packetlength); }
|
||||
else if (portNum == 3) { Serial3.write(response, (size_t)packetlength); }
|
||||
//sei();
|
||||
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:
|
||||
|
@ -777,7 +777,7 @@ This function is used to store calibration data sent by Tuner Studio.
|
|||
void receiveCalibration(byte tableID)
|
||||
{
|
||||
byte* pnt_TargetTable; //Pointer that will be used to point to the required target table
|
||||
int OFFSET, DIVISION_FACTOR, BYTES_PER_VALUE;
|
||||
int OFFSET, DIVISION_FACTOR, BYTES_PER_VALUE, EEPROM_START;
|
||||
|
||||
switch (tableID)
|
||||
{
|
||||
|
@ -787,6 +787,7 @@ void receiveCalibration(byte tableID)
|
|||
OFFSET = CALIBRATION_TEMPERATURE_OFFSET; //
|
||||
DIVISION_FACTOR = 10;
|
||||
BYTES_PER_VALUE = 2;
|
||||
EEPROM_START = EEPROM_CALIBRATION_CLT;
|
||||
break;
|
||||
case 1:
|
||||
//Inlet air temp table
|
||||
|
@ -794,6 +795,7 @@ void receiveCalibration(byte tableID)
|
|||
OFFSET = CALIBRATION_TEMPERATURE_OFFSET;
|
||||
DIVISION_FACTOR = 10;
|
||||
BYTES_PER_VALUE = 2;
|
||||
EEPROM_START = EEPROM_CALIBRATION_IAT;
|
||||
break;
|
||||
case 2:
|
||||
//O2 table
|
||||
|
@ -801,6 +803,7 @@ void receiveCalibration(byte tableID)
|
|||
OFFSET = 0;
|
||||
DIVISION_FACTOR = 1;
|
||||
BYTES_PER_VALUE = 1;
|
||||
EEPROM_START = EEPROM_CALIBRATION_O2;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -848,7 +851,10 @@ void receiveCalibration(byte tableID)
|
|||
}
|
||||
|
||||
pnt_TargetTable[(x / 2)] = (byte)tempValue;
|
||||
int y = EEPROM_CALIBRATION_O2 + counter;
|
||||
|
||||
//From TS3.x onwards, the EEPROM must be written here as TS restarts immediately after the process completes which is before the EEPROM write completes
|
||||
int y = EEPROM_START + (x / 2);
|
||||
EEPROM.update(y, (byte)tempValue);
|
||||
|
||||
every2nd = false;
|
||||
analogWrite(13, (counter % 50) );
|
||||
|
|
|
@ -15,7 +15,7 @@ volatile unsigned long toothLastSecToothTime = 0; //The time (micros()) that the
|
|||
volatile unsigned long toothLastMinusOneToothTime = 0; //The time (micros()) that the tooth before the last tooth was registered
|
||||
volatile unsigned long toothOneTime = 0; //The time (micros()) that tooth 1 last triggered
|
||||
volatile unsigned long toothOneMinusOneTime = 0; //The 2nd to last time (micros()) that tooth 1 last triggered
|
||||
volatile bool revolutionOne; // For sequential operation, this tracks whether the current revolution is 1 or 2 (not 1)
|
||||
volatile bool revolutionOne = 0; // For sequential operation, this tracks whether the current revolution is 1 or 2 (not 1)
|
||||
volatile unsigned int toothHistory[TOOTH_LOG_BUFFER];
|
||||
volatile unsigned int toothHistoryIndex = 0;
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ void triggerPri_missingTooth()
|
|||
if ( curGap > targetGap || toothCurrentCount > triggerActualTeeth)
|
||||
{
|
||||
toothCurrentCount = 1;
|
||||
revolutionOne = !revolutionOne; //Flip sequential revolution tracker
|
||||
toothOneMinusOneTime = toothOneTime;
|
||||
toothOneTime = curTime;
|
||||
currentStatus.hasSync = true;
|
||||
|
@ -123,7 +124,10 @@ void triggerPri_missingTooth()
|
|||
toothLastToothTime = curTime;
|
||||
}
|
||||
|
||||
void triggerSec_missingTooth(){ return; } //This function currently is not used
|
||||
void triggerSec_missingTooth()
|
||||
{
|
||||
if(!currentStatus.hasSync) { revolutionOne = 0; } //Sequential revolution reset
|
||||
}
|
||||
|
||||
int getRPM_missingTooth()
|
||||
{
|
||||
|
@ -147,6 +151,9 @@ int getCrankAngle_missingTooth(int timePerDegree)
|
|||
if(elapsedTime < SHRT_MAX ) { crankAngle += div((int)elapsedTime, timePerDegree).quot; } //This option is much faster, but only available for smaller values of elapsedTime
|
||||
else { crankAngle += ldiv(elapsedTime, timePerDegree).quot; }
|
||||
|
||||
//Sequential check (simply sets whether we're on the first or 2nd revoltuion of the cycle)
|
||||
if (revolutionOne) { crankAngle += 360; }
|
||||
|
||||
if (crankAngle >= 720) { crankAngle -= 720; }
|
||||
else if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; }
|
||||
if (crankAngle < 0) { crankAngle += 360; }
|
||||
|
|
14
globals.h
14
globals.h
|
@ -55,9 +55,15 @@ const byte packetSize = 35;
|
|||
#define TOOTH_LOG_SIZE 128
|
||||
#define TOOTH_LOG_BUFFER 256
|
||||
|
||||
#define INJ_SIMULTANEOUS 0
|
||||
#define INJ_PAIRED 0
|
||||
#define INJ_SEMISEQUENTIAL 1
|
||||
#define INJ_SEQUENTIAL 2
|
||||
#define INJ_BANKED 2
|
||||
#define INJ_SEQUENTIAL 3
|
||||
|
||||
#define IGN_MODE_WASTED 0
|
||||
#define IGN_MODE_SINGLE 1
|
||||
#define IGN_MODE_WASTEDCOP 2
|
||||
#define IGN_MODE_SEQUENTIAL 3
|
||||
|
||||
#define SIZE_BYTE 8
|
||||
#define SIZE_INT 16
|
||||
|
@ -141,7 +147,7 @@ struct statuses {
|
|||
unsigned int PW; //In uS
|
||||
volatile byte runSecs; //Counter of seconds since cranking commenced (overflows at 255 obviously)
|
||||
volatile byte secl; //Continous
|
||||
volatile int loopsPerSecond;
|
||||
volatile unsigned int loopsPerSecond;
|
||||
boolean launchingSoft; //True when in launch control soft limit mode
|
||||
boolean launchingHard; //True when in launch control hard limit mode
|
||||
int freeRAM;
|
||||
|
@ -215,7 +221,7 @@ struct config1 {
|
|||
byte algorithm : 1; //"Speed Density", "Alpha-N"
|
||||
byte baroCorr : 1;
|
||||
byte injLayout : 2;
|
||||
byte canenable : 1; //is can interface enabled
|
||||
byte canEnable : 1; //is can interface enabled
|
||||
|
||||
byte primePulse;
|
||||
byte dutyLim;
|
||||
|
|
3
idle.h
3
idle.h
|
@ -36,4 +36,5 @@ long idle_pwm_target_value;
|
|||
long idle_cl_target_rpm;
|
||||
|
||||
void initialiseIdle();
|
||||
|
||||
static inline void disableIdle();
|
||||
static inline void enableIdle();
|
||||
|
|
34
idle.ino
34
idle.ino
|
@ -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)
|
||||
|
@ -279,6 +293,12 @@ ISR(TIMER4_COMPC_vect)
|
|||
}
|
||||
|
||||
}
|
||||
#elif defined(PROCESSOR_TEENSY_3_1) || defined(PROCESSOR_TEENSY_3_2)
|
||||
void idle_off() { }
|
||||
#elif defined (CORE_TEENSY)
|
||||
//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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<msq xmlns="http://www.msefi.com/:msq">
|
||||
<bibliography author="TunerStudio MS(Beta) 3.0.08 - EFI Analytics, Inc." tuneComment="" writeDate="Mon Sep 26 22:13:44 BST 2016"/>
|
||||
<versionInfo fileFormat="5.0" firmwareInfo="Speeduino+2016.08" nPages="8" signature="speeduino 201609-dev"/>
|
||||
<bibliography author="TunerStudio MS(Beta) 3.0.10.04 - EFI Analytics, Inc." tuneComment="" writeDate="Fri Sep 30 22:35:03 AEST 2016"/>
|
||||
<versionInfo fileFormat="5.0" firmwareInfo="Speeduino+2016.09" nPages="8" signature="speeduino 201609"/>
|
||||
<page>
|
||||
<pcVariable name="tsCanId">"0"</pcVariable>
|
||||
</page>
|
||||
|
@ -79,7 +79,7 @@
|
|||
100.0
|
||||
</constant>
|
||||
<constant digits="0" name="crankingPct" units="%">20.0</constant>
|
||||
<constant name="pinLayout">"Speeduino v0.3"</constant>
|
||||
<constant name="pinLayout">"Speeduino v0.4"</constant>
|
||||
<constant name="tachoPin">"Board Default"</constant>
|
||||
<constant name="unused2-16f">"One"</constant>
|
||||
<constant digits="1" name="tdePct" units="ms">3.2</constant>
|
||||
|
@ -94,7 +94,7 @@
|
|||
<constant name="display5">"RPM"</constant>
|
||||
<constant name="displayB1">"RPM"</constant>
|
||||
<constant name="displayB2">"RPM"</constant>
|
||||
<constant digits="1" name="reqFuel" units="ms">14.4</constant>
|
||||
<constant digits="1" name="reqFuel" units="ms">12.8</constant>
|
||||
<constant digits="0" name="divider">2.0</constant>
|
||||
<constant name="alternate">"Alternating"</constant>
|
||||
<constant name="multiplyMAP">"No"</constant>
|
||||
|
@ -116,7 +116,6 @@
|
|||
<constant name="algorithm">"Speed Density"</constant>
|
||||
<constant name="baroCorr">"Off"</constant>
|
||||
<constant name="injLayout">"Bank"</constant>
|
||||
<constant name="canenable">"Enable"</constant>
|
||||
<constant digits="1" name="primePulse" units="ms">4.0</constant>
|
||||
<constant digits="0" name="dutyLim" units="%">85.0</constant>
|
||||
<constant digits="0" name="unused41" units="RPM">4200.0</constant>
|
||||
|
@ -128,6 +127,9 @@
|
|||
<constant digits="0" name="mapMax" units="kpa">260.0</constant>
|
||||
<constant digits="0" name="fpPrime" units="s">3.0</constant>
|
||||
<constant digits="1" name="stoich" units=":1">14.7</constant>
|
||||
<constant digits="0" name="oddfire2">0.0</constant>
|
||||
<constant digits="0" name="oddfire3">0.0</constant>
|
||||
<constant digits="0" name="oddfire4">0.0</constant>
|
||||
<constant digits="0" name="unused2-57" units="RPM">0.0</constant>
|
||||
<constant digits="0" name="unused2-58" units="RPM">0.0</constant>
|
||||
<constant digits="0" name="unused2-59" units="RPM">0.0</constant>
|
||||
|
@ -196,16 +198,14 @@
|
|||
<constant digits="0" name="TrigAng" units="Deg">0.0</constant>
|
||||
<constant digits="0" name="FixAng" units="Deg">0.0</constant>
|
||||
<constant digits="0" name="CrankAng" units="Deg">5.0</constant>
|
||||
<constant digits="0" name="IgHold">10.0</constant>
|
||||
<constant digits="0" name="TrigAngMul">4.0</constant>
|
||||
<constant name="TrigEdge">"Leading"</constant>
|
||||
<constant name="TrigSpeed">"Crank Speed"</constant>
|
||||
<constant name="IgInv">"Going Low"</constant>
|
||||
<constant name="oddfire">"Yes"</constant>
|
||||
<constant name="TrigPattern">"Missing Tooth"</constant>
|
||||
<constant digits="0" name="IdleAdv" units="Deg">-1.9008</constant>
|
||||
<constant digits="0" name="IdleAdvTPS" units="ADC">65.0</constant>
|
||||
<constant digits="0" name="IdleAdvRPM" units="RPM">3200.0</constant>
|
||||
<constant digits="0" name="IdleAdvCLT" units="F">-5.814</constant>
|
||||
<constant digits="1" name="IdleAdvCLT" units="C">-21.0</constant>
|
||||
<constant digits="0" name="IdleDelayTime" units="sec">38.0</constant>
|
||||
<constant digits="0" name="StgCycles" units="cycles">2.0</constant>
|
||||
<constant name="dwellcont">"Dwell control"</constant>
|
||||
|
@ -236,17 +236,17 @@
|
|||
17.0
|
||||
32.0
|
||||
</constant>
|
||||
<constant cols="1" digits="0" name="wueBins" rows="10" units="F">
|
||||
-40.014
|
||||
-14.814
|
||||
17.586
|
||||
48.186
|
||||
78.786
|
||||
100.386
|
||||
120.186
|
||||
139.986
|
||||
156.186
|
||||
175.986
|
||||
<constant cols="1" digits="0" name="wueBins" rows="10" units="C">
|
||||
-40.0
|
||||
-26.0
|
||||
-8.0
|
||||
9.0
|
||||
26.0
|
||||
38.0
|
||||
49.0
|
||||
60.0
|
||||
69.0
|
||||
80.0
|
||||
</constant>
|
||||
<constant digits="0" name="dwellLim" units="ms">8.0</constant>
|
||||
<constant cols="1" digits="0" name="dwellRates" rows="6" units="%">
|
||||
|
@ -257,13 +257,13 @@
|
|||
91.0
|
||||
85.0
|
||||
</constant>
|
||||
<constant cols="1" digits="0" name="iatRetBins" rows="6" units="F">
|
||||
136.386
|
||||
179.586
|
||||
199.386
|
||||
219.186
|
||||
240.786
|
||||
256.986
|
||||
<constant cols="1" digits="0" name="iatRetBins" rows="6" units="C">
|
||||
58.0
|
||||
82.0
|
||||
93.0
|
||||
104.0
|
||||
116.0
|
||||
140.0
|
||||
</constant>
|
||||
<constant cols="1" digits="0" name="iatRetRates" rows="6" units="deg">
|
||||
0.0
|
||||
|
@ -271,7 +271,7 @@
|
|||
2.0
|
||||
4.0
|
||||
6.0
|
||||
8.0
|
||||
10.0
|
||||
</constant>
|
||||
<constant digits="0" name="dfcoRPM" units="RPM">1500.0</constant>
|
||||
<constant digits="0" name="dfcoHyster" units="RPM">200.0</constant>
|
||||
|
@ -345,7 +345,7 @@
|
|||
<constant digits="0" name="egoKP" units="%">100.0</constant>
|
||||
<constant digits="0" name="egoKI" units="%">20.0</constant>
|
||||
<constant digits="0" name="egoKD" units="%">0.0</constant>
|
||||
<constant digits="0" name="egoTemp" units="°F">157.986</constant>
|
||||
<constant digits="0" name="egoTemp" units="C">70.0</constant>
|
||||
<constant digits="0" name="egoCount">16.0</constant>
|
||||
<constant digits="0" name="egoDelta" units="%">1.0</constant>
|
||||
<constant digits="0" name="egoLimit">15.0</constant>
|
||||
|
@ -372,16 +372,16 @@
|
|||
100.0
|
||||
98.0
|
||||
</constant>
|
||||
<constant cols="1" digits="0" name="airDenBins" rows="9" units="F">
|
||||
-40.014
|
||||
-4.014
|
||||
31.986
|
||||
67.986
|
||||
94.986
|
||||
121.986
|
||||
139.986
|
||||
193.986
|
||||
247.986
|
||||
<constant cols="1" digits="0" name="airDenBins" rows="9" units="C">
|
||||
-40.0
|
||||
-20.0
|
||||
0.0
|
||||
20.0
|
||||
35.0
|
||||
50.0
|
||||
60.0
|
||||
90.0
|
||||
120.0
|
||||
</constant>
|
||||
<constant cols="1" digits="0" name="airDenRates" rows="9" units="%">
|
||||
126.0
|
||||
|
@ -411,7 +411,8 @@
|
|||
<constant digits="0" name="boostKP" units="%">100.0</constant>
|
||||
<constant digits="0" name="boostKI" units="%">0.0</constant>
|
||||
<constant digits="0" name="boostKD" units="%">0.0</constant>
|
||||
<constant digits="0" name="unused6-60" units="RPM">24300.0</constant>
|
||||
<constant name="lnchPullRes">"Float"</constant>
|
||||
<constant name="unused6-60">"ONE"</constant>
|
||||
<constant digits="0" name="unused6-61" units="RPM">4500.0</constant>
|
||||
<constant digits="0" name="unused6-62" units="RPM">3000.0</constant>
|
||||
<constant digits="0" name="unused6-63" units="RPM">6000.0</constant>
|
||||
|
@ -453,17 +454,17 @@
|
|||
16.0
|
||||
9.0
|
||||
</constant>
|
||||
<constant cols="1" digits="0" name="iacBins" rows="10" units="F">
|
||||
-36.414
|
||||
-2.214
|
||||
33.786
|
||||
62.586
|
||||
93.186
|
||||
121.986
|
||||
145.386
|
||||
174.186
|
||||
208.386
|
||||
289.386
|
||||
<constant cols="1" digits="0" name="iacBins" rows="10" units="C">
|
||||
-38.0
|
||||
-19.0
|
||||
1.0
|
||||
17.0
|
||||
34.0
|
||||
50.0
|
||||
63.0
|
||||
79.0
|
||||
98.0
|
||||
143.0
|
||||
</constant>
|
||||
<constant cols="1" digits="0" name="iacCrankSteps" rows="4" units="Steps">
|
||||
123.0
|
||||
|
@ -477,17 +478,17 @@
|
|||
44.0
|
||||
60.0
|
||||
</constant>
|
||||
<constant cols="1" digits="0" name="iacCrankBins" rows="4" units="F">
|
||||
-18.414
|
||||
42.786
|
||||
111.186
|
||||
168.786
|
||||
<constant cols="1" digits="0" name="iacCrankBins" rows="4" units="C">
|
||||
-28.0
|
||||
6.0
|
||||
44.0
|
||||
76.0
|
||||
</constant>
|
||||
<constant name="iacAlgorithm">"None"</constant>
|
||||
<constant name="iacStepTime">"3"</constant>
|
||||
<constant name="iacChannels">"1"</constant>
|
||||
<constant name="iacPWMdir">"Normal"</constant>
|
||||
<constant digits="0" name="iacFastTemp" units="F">67.986</constant>
|
||||
<constant digits="0" name="iacFastTemp" units="C">20.0</constant>
|
||||
<constant digits="0" name="iacStepHome" units="Steps">240.0</constant>
|
||||
<constant digits="0" name="iacStepHyster" units="Steps">4.0</constant>
|
||||
<constant name="fanInv">"No"</constant>
|
||||
|
@ -497,14 +498,14 @@
|
|||
<constant name="unused7-55d">"No"</constant>
|
||||
<constant name="unused7-55e">"No"</constant>
|
||||
<constant name="unused7-55f">"No"</constant>
|
||||
<constant digits="0" name="fanSP" units="°F">166.986</constant>
|
||||
<constant digits="0" name="fanHyster" units="°F">35.586</constant>
|
||||
<constant digits="0" name="fanSP" units="C">75.0</constant>
|
||||
<constant digits="0" name="fanHyster" units="C">2.0</constant>
|
||||
<constant digits="0" name="fanFreq" units="Hz">6.0</constant>
|
||||
<constant cols="1" digits="0" name="fanPWMBins" rows="4" units="F">
|
||||
139.986
|
||||
-4.014
|
||||
-40.014
|
||||
316.386
|
||||
<constant cols="1" digits="0" name="fanPWMBins" rows="4" units="C">
|
||||
60.0
|
||||
-20.0
|
||||
-40.0
|
||||
158.0
|
||||
</constant>
|
||||
</page>
|
||||
<page number="7" size="160">
|
||||
|
@ -570,9 +571,9 @@
|
|||
</constant>
|
||||
</page>
|
||||
<settings Comment="These setting are only used if this msq is opened without a project.">
|
||||
<setting name="FAHRENHEIT" value="FAHRENHEIT"/>
|
||||
<setting name="SPEED_DENSITY" value="SPEED_DENSITY"/>
|
||||
<setting name="CAN_COMMANDS_OFF" value="CAN_COMMANDS_OFF"/>
|
||||
<setting name="CELSIUS" value="CELSIUS"/>
|
||||
</settings>
|
||||
<userComments Comment="These are user comments that can be related to a particular setting or dialog."/>
|
||||
</msq>
|
||||
</msq>
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
queryCommand = "Q"
|
||||
;signature = 20
|
||||
signature = "speeduino 201609-dev"
|
||||
signature = "speeduino 201610-dev"
|
||||
versionInfo = "S" ; Put this in the title bar.
|
||||
|
||||
|
||||
|
@ -160,7 +160,6 @@ page = 2
|
|||
|
||||
reqFuel = scalar, U08, 24, "ms", 0.1, 0.0, 0.0, 25.5, 1
|
||||
divider = scalar, U08, 25, "", 1.0, 0.0
|
||||
;injTiming = bits, U08, 26, [0:1], "Simultaneous", "Semi-Sequential", "Sequential"
|
||||
alternate = bits, U08, 26, [0:0], "Simultaneous", "Alternating"
|
||||
multiplyMAP= bits, U08, 26, [1:1], "No", "Yes"
|
||||
includeAFR = bits, U08, 26, [2:2], "No", "Yes"
|
||||
|
@ -186,8 +185,8 @@ page = 2
|
|||
flexEnabled= bits, U08, 38, [1:1], "Off", "On"
|
||||
algorithm = bits, U08, 38, [2:2], "Speed Density", "Alpha-N"
|
||||
baroCorr = bits, U08, 38, [3:3], "Off", "On"
|
||||
injLayout = bits, U08, 38, [4:5], "Bank", "Semi-Sequential", "INVALID", "INVALID"
|
||||
canenable = bits, U08, 38, [6:6], "Disable", "Enable"
|
||||
injLayout = bits, U08, 38, [4:5], "Paired", "Semi-Sequential", "INVALID", "Sequential"
|
||||
canEnable = bits, U08, 38, [6:6], "Disable", "Enable"
|
||||
|
||||
primePulse = scalar, U08, 39, "ms", 0.1, 0.0, 0.0, 25.5, 1
|
||||
dutyLim = scalar, U08, 40, "%", 1.0, 0.0, 0.0, 100.0, 0
|
||||
|
@ -336,9 +335,9 @@ page = 6
|
|||
egoKI = scalar, U08, 2, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte)
|
||||
egoKD = scalar, U08, 3, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte)
|
||||
#if CELSIUS
|
||||
egoTemp = scalar, U08, 4, "°C", 1.0, -40, -40, 102.0, 0
|
||||
egoTemp = scalar, U08, 4, "C", 1.0, -40, -40, 102.0, 0
|
||||
#else
|
||||
egoTemp = scalar, U08, 4, "°F", 1.8, -22.23, -40, 215.0, 0
|
||||
egoTemp = scalar, U08, 4, "F", 1.8, -22.23, -40, 215.0, 0
|
||||
#endif
|
||||
egoCount = scalar, U08, 5, "", 4.0, 0.0, 4.0, 255.0, 0 ; * ( 1 byte)
|
||||
egoDelta = scalar, U08, 6, "%", 1.0, 0.0, 0.0, 255.0, 0 ; * ( 1 byte)
|
||||
|
@ -431,11 +430,11 @@ page = 7
|
|||
unused7-55e = bits, U08, 56, [6:6], "No", "Yes"
|
||||
unused7-55f = bits, U08, 56, [7:7], "No", "Yes"
|
||||
#if CELSIUS
|
||||
fanSP = scalar, U08, 57, "°C", 1.0, -40, -40, 215.0, 0
|
||||
fanHyster = scalar, U08, 58, "°C", 1.0, -40, -40, 215.0, 0
|
||||
fanSP = scalar, U08, 57, "C", 1.0, -40, -40, 215.0, 0
|
||||
fanHyster = scalar, U08, 58, "C", 1.0, -40, -40, 215.0, 0
|
||||
#else
|
||||
fanSP = scalar, U08, 57, "°F", 1.8, -22.23, -40, 215.0, 0
|
||||
fanHyster = scalar, U08, 58, "°F", 1.8, -22.23, -40, 215.0, 0
|
||||
fanSP = scalar, U08, 57, "F", 1.8, -22.23, -40, 215.0, 0
|
||||
fanHyster = scalar, U08, 58, "F", 1.8, -22.23, -40, 215.0, 0
|
||||
#endif
|
||||
fanFreq = scalar, U08 , 59, "Hz", 2.0, 0.0, 10, 511, 0
|
||||
#if CELSIUS
|
||||
|
@ -590,8 +589,8 @@ menuDialog = main
|
|||
subMenu = vvtTbl, "VVT duty cycle", 8, { vvtEnabled }
|
||||
subMenu = std_separator
|
||||
subMenu = tacho, "Tacho Output"
|
||||
subMenu = std_separator
|
||||
subMenu = canio, "Canbus Interface"
|
||||
subMenu = std_separator
|
||||
subMenu = canIO, "Canbus Interface"
|
||||
|
||||
|
||||
|
||||
|
@ -619,11 +618,13 @@ menuDialog = main
|
|||
; tool tips tooltips
|
||||
;Ensure all settings are defined as some MS2/BG words shipped with TS are not applicable.
|
||||
nCylinders = "The number of cylinders in your engine."
|
||||
alternate = ""
|
||||
engineType = "Most engines are Even Fire. Typical odd-fire engines are V-twin, some V4, Vmax, some V6, V10."
|
||||
twoStroke = "Four-Stroke (most engines), Two-stroke."
|
||||
nInjectors = "Number of primary injectors."
|
||||
mapSample = "The method used for calculating the MAP reading\nFor 1-2 Cylinder engines, Cycle Minimum is recommended.\nFor more than 2 cylinders Cycle Average is recommended"
|
||||
stoich = "The stoichiometric ration of the fuel being used. For flex fuel, choose the primary fuel"
|
||||
injLayout = "The injector layout and timing to be used. Options are: \n 1. Paired - 2 injectors per output. Outputs active is equal to half the number of cylinders. Outputs are timed over 1 crank revolution. \n 2. Semi-sequential: Same as paired except that injector channels are mirrored (1&4, 2&3) meaning the number of outputs used are equal to the number of cylinders. Only valid for 4 cylinders or less. \n 3. Banked: 2 outputs only used. \n 4. Sequential: 1 injector per output and outputs used equals the number of cylinders. Injection is timed over full cycle.
|
||||
|
||||
TrigPattern = "The type of input trigger decoder to be used."
|
||||
numteeth = "Number of teeth on Primary Wheel."
|
||||
|
@ -716,8 +717,8 @@ menuDialog = main
|
|||
dialog = tacho, "Tacho"
|
||||
field = "Output pin", tachoPin
|
||||
|
||||
dialog = canio, "CanBus interface"
|
||||
field = "Enable/Disable", canenable
|
||||
dialog = canIO, "CanBus interface"
|
||||
field = "Enable/Disable", canEnable
|
||||
|
||||
dialog = accelEnrichments_center, ""
|
||||
field = "TPSdot Threshold", tpsThresh
|
||||
|
@ -732,12 +733,18 @@ menuDialog = main
|
|||
field = "Cutoff RPM", dfcoRPM, { dfcoEnabled }
|
||||
field = "RPM Hysteresis", dfcoHyster, { dfcoEnabled }
|
||||
|
||||
dialog = accelEnrichments_north_south, ""
|
||||
liveGraph = pump_ae_Graph, "AE Graph"
|
||||
graphLine = afr
|
||||
graphLine = TPSdot, "%", -2000, 2000, auto, auto
|
||||
|
||||
dialog = accelEnrichments_north, "", xAxis
|
||||
panel = time_accel_tpsdot_curve
|
||||
;panel = time_accel_tpsdot_tbl
|
||||
|
||||
dialog = accelEnrichments, "Acceleration Enrichment"
|
||||
panel = accelEnrichments_north, North
|
||||
panel = accelEnrichments_north_south, Center
|
||||
panel = accelEnrichments_center, Center
|
||||
panel = accelEnrichments_south, South
|
||||
|
||||
|
@ -1189,7 +1196,7 @@ menuDialog = main
|
|||
gaugeCategory = "Other"
|
||||
clockGauge = secl, "Clock", "Seconds", 0, 255, 10, 10, 245, 245, 0, 0
|
||||
deadGauge = deadValue, "---", "", 0, 1, -1, -1, 2, 2, 0, 0
|
||||
loopGauge = loopsPerSecond,"Main loop speed", "Loops/S" , 0, 20000, -1, 500,1800, 4000, 0, 0
|
||||
loopGauge = loopsPerSecond,"Main loop speed", "Loops/S" , 0, 70000, -1, 500,1800, 4000, 0, 0
|
||||
memoryGauge = freeRAM, "Free memory", "bytes" , 0, 8000, -1, 1000,8000, 1000, 0, 0
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
|
@ -1356,7 +1363,7 @@ menuDialog = main
|
|||
TPSdot = scalar, U08, 21, "%/s", 10.00, 0.000
|
||||
advance = scalar, U08, 22, "deg", 1.000, 0.000
|
||||
tps = scalar, U08, 23, "%", 1.000, 0.000
|
||||
loopsPerSecond = scalar, S16, 24, "loops", 1.000, 0.000
|
||||
loopsPerSecond = scalar, U16, 24, "loops", 1.000, 0.000
|
||||
freeRAM = scalar, S16, 26, "bytes", 1.000, 0.000
|
||||
batCorrection = scalar, U08, 28, "%", 1.000, 0.000
|
||||
spark = scalar, U08, 29, "bits", 1.000, 0.000
|
||||
|
|
136
scheduler.h
136
scheduler.h
|
@ -32,6 +32,91 @@ See page 136 of the processors datasheet: http://www.atmel.com/Images/doc2549.pd
|
|||
#include <avr/io.h>
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
|
||||
//Refer to http://svn.savannah.nongnu.org/viewvc/trunk/avr-libc/include/avr/iomxx0_1.h?root=avr-libc&view=markup
|
||||
#define FUEL1_COUNTER TCNT3
|
||||
#define FUEL2_COUNTER TCNT3
|
||||
#define FUEL3_COUNTER TCNT3
|
||||
#define FUEL4_COUNTER TCNT4
|
||||
|
||||
#define IGN1_COUNTER TCNT5
|
||||
#define IGN2_COUNTER TCNT5
|
||||
#define IGN3_COUNTER TCNT5
|
||||
#define IGN4_COUNTER TCNT4
|
||||
|
||||
#define FUEL1_COMPARE OCR3A
|
||||
#define FUEL2_COMPARE OCR3B
|
||||
#define FUEL3_COMPARE OCR3C
|
||||
#define FUEL4_COMPARE OCR4B
|
||||
|
||||
#define IGN1_COMPARE OCR5A
|
||||
#define IGN2_COMPARE OCR5B
|
||||
#define IGN3_COMPARE OCR5C
|
||||
#define IGN4_COMPARE OCR4A
|
||||
|
||||
#define FUEL1_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3A) //Turn on the A compare unit (ie turn on the interrupt)
|
||||
#define FUEL2_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3B) //Turn on the B compare unit (ie turn on the interrupt)
|
||||
#define FUEL3_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3C) //Turn on the C compare unit (ie turn on the interrupt)
|
||||
#define FUEL4_TIMER_ENABLE() TIMSK4 |= (1 << OCIE4B) //Turn on the B compare unit (ie turn on the interrupt)
|
||||
|
||||
#define FUEL1_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3A); //Turn off this output compare unit
|
||||
#define FUEL2_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3B); //Turn off this output compare unit
|
||||
#define FUEL3_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3C); //Turn off this output compare unit
|
||||
#define FUEL4_TIMER_DISABLE() TIMSK4 &= ~(1 << OCIE4B); //Turn off this output compare unit
|
||||
|
||||
#define IGN1_TIMER_ENABLE() TIMSK5 |= (1 << OCIE5A) //Turn on the A compare unit (ie turn on the interrupt)
|
||||
#define IGN2_TIMER_ENABLE() TIMSK5 |= (1 << OCIE5B) //Turn on the B compare unit (ie turn on the interrupt)
|
||||
#define IGN3_TIMER_ENABLE() TIMSK5 |= (1 << OCIE5C) //Turn on the C compare unit (ie turn on the interrupt)
|
||||
#define IGN4_TIMER_ENABLE() TIMSK4 |= (1 << OCIE4A) //Turn on the A compare unit (ie turn on the interrupt)
|
||||
|
||||
#define IGN1_TIMER_DISABLE() TIMSK5 &= ~(1 << OCIE5A) //Turn off this output compare unit
|
||||
#define IGN2_TIMER_DISABLE() TIMSK5 &= ~(1 << OCIE5B) //Turn off this output compare unit
|
||||
#define IGN3_TIMER_DISABLE() TIMSK5 &= ~(1 << OCIE5C) //Turn off this output compare unit
|
||||
#define IGN4_TIMER_DISABLE() TIMSK4 &= ~(1 << OCIE4A) //Turn off this output compare unit
|
||||
|
||||
#elif defined(CORE_TEENSY)
|
||||
//http://shawnhymel.com/661/learning-the-teensy-lc-interrupt-service-routines/
|
||||
#define FUEL1_COUNTER FTM0_CNT
|
||||
#define FUEL2_COUNTER FTM0_CNT
|
||||
#define FUEL3_COUNTER FTM0_CNT
|
||||
#define FUEL4_COUNTER FTM0_CNT
|
||||
|
||||
#define IGN1_COUNTER FTM0_CNT
|
||||
#define IGN2_COUNTER FTM0_CNT
|
||||
#define IGN3_COUNTER FTM0_CNT
|
||||
#define IGN4_COUNTER FTM0_CNT
|
||||
|
||||
#define FUEL1_COMPARE FTM0_C0V
|
||||
#define FUEL2_COMPARE FTM0_C1V
|
||||
#define FUEL3_COMPARE FTM0_C2V
|
||||
#define FUEL4_COMPARE FTM0_C3V
|
||||
|
||||
#define IGN1_COMPARE FTM0_C4V
|
||||
#define IGN2_COMPARE FTM0_C5V
|
||||
#define IGN3_COMPARE FTM0_C6V
|
||||
#define IGN4_COMPARE FTM0_C7V
|
||||
|
||||
#define FUEL1_TIMER_ENABLE() NVIC_ENABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define FUEL2_TIMER_ENABLE() NVIC_ENABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define FUEL3_TIMER_ENABLE() NVIC_ENABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define FUEL4_TIMER_ENABLE() NVIC_ENABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
|
||||
#define FUEL1_TIMER_DISABLE() NVIC_DISABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define FUEL2_TIMER_DISABLE() NVIC_DISABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define FUEL3_TIMER_DISABLE() NVIC_DISABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define FUEL4_TIMER_DISABLE() NVIC_DISABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
|
||||
#define IGN1_TIMER_ENABLE() NVIC_ENABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define IGN2_TIMER_ENABLE() NVIC_ENABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define IGN3_TIMER_ENABLE() NVIC_ENABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define IGN4_TIMER_ENABLE() NVIC_ENABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
|
||||
#define IGN1_TIMER_DISABLE() NVIC_DISABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define IGN2_TIMER_DISABLE() NVIC_DISABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define IGN3_TIMER_DISABLE() NVIC_DISABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#define IGN4_TIMER_DISABLE() NVIC_DISABLE_IRQ(IRQ_FTM1) //THIS IS NOT RIGHT! PLACEHOLDER ONLY!
|
||||
#endif
|
||||
|
||||
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)());
|
||||
|
@ -63,7 +148,7 @@ struct Schedule {
|
|||
unsigned int endCompare;
|
||||
};
|
||||
|
||||
Schedule *timer3Aqueue[4];
|
||||
volatile Schedule *timer3Aqueue[4];
|
||||
Schedule *timer3Bqueue[4];
|
||||
Schedule *timer3Cqueue[4];
|
||||
|
||||
|
@ -86,27 +171,50 @@ Schedule ignitionSchedule8;
|
|||
|
||||
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)
|
||||
static inline unsigned int setQueue(volatile 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;
|
||||
if(schedule1->Status == OFF)
|
||||
{
|
||||
queue[0] = schedule2;
|
||||
queue[1] = schedule2;
|
||||
tmpQueue[0] = schedule2->startCompare - CNT;
|
||||
tmpQueue[1] = schedule2->endCompare - CNT;
|
||||
}
|
||||
else
|
||||
{
|
||||
queue[0] = schedule1;
|
||||
queue[1] = schedule1;
|
||||
tmpQueue[0] = schedule1->startCompare - CNT;
|
||||
tmpQueue[1] = schedule1->endCompare - CNT;
|
||||
}
|
||||
|
||||
if(schedule2->Status == OFF)
|
||||
{
|
||||
queue[2] = schedule1;
|
||||
queue[3] = schedule1;
|
||||
tmpQueue[2] = schedule1->startCompare - CNT;
|
||||
tmpQueue[3] = schedule1->endCompare - CNT;
|
||||
}
|
||||
else
|
||||
{
|
||||
queue[2] = schedule2;
|
||||
queue[3] = schedule2;
|
||||
tmpQueue[2] = schedule2->startCompare - CNT;
|
||||
tmpQueue[3] = schedule2->endCompare - CNT;
|
||||
}
|
||||
|
||||
|
||||
//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; }
|
||||
//This implementes a sorting networking based on the Bose-Nelson sorting network
|
||||
//See: http://pages.ripco.net/~jgamble/nw.html
|
||||
#define SWAP(x,y) if(tmpQueue[y] < tmpQueue[x]) { unsigned int tmp = tmpQueue[x]; tmpQueue[x] = tmpQueue[y]; tmpQueue[y] = tmp; volatile Schedule *tmpS = queue[x]; queue[x] = queue[y]; queue[y] = tmpS; }
|
||||
//SWAP(0, 1); //Likely not needed
|
||||
//SWAP(2, 3); //Likely not needed
|
||||
SWAP(0, 2);
|
||||
SWAP(1, 3);
|
||||
SWAP(1, 2);
|
||||
|
||||
|
@ -119,7 +227,7 @@ static inline unsigned int setQueue(Schedule *queue[], Schedule *schedule1, Sche
|
|||
* 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[])
|
||||
static inline unsigned int popQueue(volatile Schedule *queue[])
|
||||
{
|
||||
queue[0] = queue[1];
|
||||
queue[1] = queue[2];
|
||||
|
|
264
scheduler.ino
264
scheduler.ino
|
@ -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,13 +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;
|
||||
|
||||
fuelSchedule1.schedulesSet = 0;
|
||||
fuelSchedule2.schedulesSet = 0;
|
||||
fuelSchedule3.schedulesSet = 0;
|
||||
|
||||
//Ignition Schedules, which uses timer 5
|
||||
TCCR5B = 0x00; //Disable Timer3 while we set it up
|
||||
|
@ -34,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;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -81,14 +89,14 @@ void setFuelSchedule1(void (*startCallback)(), unsigned long timeout, unsigned l
|
|||
* 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.startCompare = FUEL1_COUNTER + (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; }
|
||||
if(channel5InjEnabled) { FUEL1_COMPARE = setQueue(timer3Aqueue, &fuelSchedule1, &fuelSchedule5, FUEL1_COUNTER); } //Schedule 1 shares a timer with schedule 5
|
||||
else { timer3Aqueue[0] = &fuelSchedule1; timer3Aqueue[1] = &fuelSchedule1; timer3Aqueue[2] = &fuelSchedule1; timer3Aqueue[3] = &fuelSchedule1; FUEL1_COMPARE = fuelSchedule1.startCompare; }
|
||||
interrupts();
|
||||
TIMSK3 |= (1 << OCIE3A); //Turn on the A compare unit (ie turn on the interrupt)
|
||||
FUEL1_TIMER_ENABLE();
|
||||
}
|
||||
void setFuelSchedule2(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
|
||||
{
|
||||
|
@ -105,47 +113,59 @@ void setFuelSchedule2(void (*startCallback)(), unsigned long timeout, unsigned l
|
|||
* 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.startCompare = FUEL2_COUNTER + (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
|
||||
FUEL2_COMPARE = 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)
|
||||
FUEL2_TIMER_ENABLE();
|
||||
}
|
||||
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
|
||||
|
||||
//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
|
||||
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.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();
|
||||
fuelSchedule3.startCompare = FUEL3_COUNTER + (timeout >> 4); //As above, but with bit shift instead of / 16
|
||||
fuelSchedule3.endCompare = fuelSchedule3.startCompare + (duration >> 4);
|
||||
FUEL3_COMPARE = fuelSchedule3.startCompare; //Use the C copmare unit of timer 3
|
||||
fuelSchedule3.Status = PENDING; //Turn this schedule on
|
||||
fuelSchedule3.schedulesSet++; //Increment the number of times this schedule has been set
|
||||
TIMSK3 |= (1 << OCIE3C); //Turn on the C compare unit (ie turn on the interrupt)
|
||||
interrupts();
|
||||
FUEL3_TIMER_ENABLE();
|
||||
}
|
||||
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
|
||||
|
||||
//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
|
||||
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.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();
|
||||
fuelSchedule4.startCompare = FUEL4_COUNTER + (timeout >> 4);
|
||||
fuelSchedule4.endCompare = fuelSchedule4.startCompare + (duration >> 4);
|
||||
FUEL4_COMPARE = fuelSchedule4.startCompare; //Use the C copmare unit of timer 3
|
||||
fuelSchedule4.Status = PENDING; //Turn this schedule on
|
||||
fuelSchedule4.schedulesSet++; //Increment the number of times this schedule has been set
|
||||
TIMSK4 |= (1 << OCIE4B); //Turn on the B compare unit (ie turn on the interrupt)
|
||||
interrupts();
|
||||
FUEL4_TIMER_ENABLE();
|
||||
}
|
||||
void setFuelSchedule5(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
|
||||
{
|
||||
|
@ -161,6 +181,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);
|
||||
|
@ -169,80 +190,103 @@ 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)())
|
||||
{
|
||||
if(ignitionSchedule1.Status == RUNNING) { return; } //Check that we're not already part way through a schedule
|
||||
|
||||
ignitionSchedule1.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule1.EndCallback = endCallback; //Name the start callback function
|
||||
ignitionSchedule1.duration = duration;
|
||||
|
||||
//As the timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency))
|
||||
if (timeout > 262140) { timeout = 262100; } // 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.
|
||||
OCR5A = TCNT5 + (timeout >> 2); //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4)
|
||||
|
||||
ignitionSchedule1.duration = duration;
|
||||
ignitionSchedule1.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule1.EndCallback = endCallback; //Name the start callback function
|
||||
noInterrupts();
|
||||
ignitionSchedule1.startCompare = IGN1_COUNTER + (timeout >> 2); //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 + (duration >> 2);
|
||||
IGN1_COMPARE = ignitionSchedule1.startCompare;
|
||||
ignitionSchedule1.Status = PENDING; //Turn this schedule on
|
||||
TIMSK5 |= (1 << OCIE5A); //Turn on the A compare unit (ie turn on the interrupt)
|
||||
interrupts();
|
||||
IGN1_TIMER_ENABLE();
|
||||
}
|
||||
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
|
||||
|
||||
//As the timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency))
|
||||
if (timeout > 262140) { timeout = 262100; } // If the timeout is >4x (Each tick represents 4uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when applied causing erratic behaviour such as erroneous sparking. This must be set slightly lower than the max of 262140 to avoid strangeness
|
||||
OCR5B = TCNT5 + (timeout >> 2); //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4)
|
||||
|
||||
ignitionSchedule2.duration = duration;
|
||||
ignitionSchedule2.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule2.EndCallback = endCallback; //Name the start callback function
|
||||
ignitionSchedule2.duration = duration;
|
||||
|
||||
//As the timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency))
|
||||
if (timeout > 262140) { timeout = 262100; } // If the timeout is >4x (Each tick represents 4uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when applied causing erratic behaviour such as erroneous sparking. This must be set slightly lower than the max of 262140 to avoid strangeness
|
||||
|
||||
noInterrupts();
|
||||
ignitionSchedule2.startCompare = IGN2_COUNTER + (timeout >> 2); //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4)
|
||||
ignitionSchedule2.endCompare = ignitionSchedule2.startCompare + (duration >> 2);
|
||||
IGN2_COMPARE = ignitionSchedule2.startCompare;
|
||||
ignitionSchedule2.Status = PENDING; //Turn this schedule on
|
||||
TIMSK5 |= (1 << OCIE5B); //Turn on the B compare unit (ie turn on the interrupt)
|
||||
interrupts();
|
||||
IGN1_TIMER_ENABLE();
|
||||
}
|
||||
void setIgnitionSchedule3(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
|
||||
{
|
||||
if(ignitionSchedule3.Status == RUNNING) { return; } //Check that we're not already part way through a schedule
|
||||
|
||||
ignitionSchedule3.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule3.EndCallback = endCallback; //Name the start callback function
|
||||
ignitionSchedule3.duration = duration;
|
||||
|
||||
//The timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency))
|
||||
if (timeout > 262140) { timeout = 262100; } // If the timeout is >4x (Each tick represents 4uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when applied causing erratic behaviour such as erroneous sparking. This must be set slightly lower than the max of 262140 to avoid strangeness
|
||||
OCR5C = TCNT5 + (timeout >> 2); //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4)
|
||||
|
||||
ignitionSchedule3.duration = duration;
|
||||
ignitionSchedule3.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule3.EndCallback = endCallback; //Name the start callback function
|
||||
noInterrupts();
|
||||
ignitionSchedule3.startCompare = IGN3_COUNTER + (timeout >> 2); //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4)
|
||||
ignitionSchedule3.endCompare = ignitionSchedule3.startCompare + (duration >> 2);
|
||||
IGN3_COMPARE = ignitionSchedule3.startCompare;
|
||||
ignitionSchedule3.Status = PENDING; //Turn this schedule on
|
||||
TIMSK5 |= (1 << OCIE5C); //Turn on the C compare unit (ie turn on the interrupt)
|
||||
interrupts();
|
||||
IGN3_TIMER_ENABLE();
|
||||
}
|
||||
void setIgnitionSchedule4(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
|
||||
{
|
||||
if(ignitionSchedule4.Status == RUNNING) { return; } //Check that we're not already part way through a schedule
|
||||
|
||||
ignitionSchedule4.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule4.EndCallback = endCallback; //Name the start callback function
|
||||
ignitionSchedule4.duration = duration;
|
||||
|
||||
//We need to calculate the value to reset the timer to (preload) in order to achieve the desired overflow time
|
||||
//The timer is ticking every 16uS (Time per Tick = (Prescale)*(1/Frequency))
|
||||
//Note this is different to the other ignition timers
|
||||
unsigned int absoluteTimeout = TCNT4 + (timeout >> 4); //As above, but with bit shift instead of / 16
|
||||
|
||||
OCR4A = absoluteTimeout;
|
||||
ignitionSchedule4.duration = duration;
|
||||
ignitionSchedule4.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule4.EndCallback = endCallback; //Name the start callback function
|
||||
|
||||
noInterrupts();
|
||||
ignitionSchedule4.startCompare = IGN4_COUNTER + (timeout >> 4); //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4)
|
||||
ignitionSchedule4.endCompare = ignitionSchedule4.startCompare + (duration >> 4);
|
||||
IGN4_COMPARE = ignitionSchedule4.startCompare;
|
||||
ignitionSchedule4.Status = PENDING; //Turn this schedule on
|
||||
TIMSK4 |= (1 << OCIE4A); //Turn on the A compare unit (ie turn on the interrupt)
|
||||
interrupts();
|
||||
IGN4_TIMER_ENABLE();
|
||||
}
|
||||
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
|
||||
|
||||
ignitionSchedule5.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule5.EndCallback = endCallback; //Name the start callback function
|
||||
ignitionSchedule5.duration = duration;
|
||||
|
||||
//As the timer is ticking every 4uS (Time per Tick = (Prescale)*(1/Frequency))
|
||||
if (timeout > 262140) { timeout = 262100; } // If the timeout is >4x (Each tick represents 4uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when applied causing erratic behaviour such as erroneous sparking. This must be set slightly lower than the max of 262140 to avoid strangeness
|
||||
OCR5A = TCNT5 + (timeout >> 2); //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4)
|
||||
|
||||
ignitionSchedule5.duration = duration;
|
||||
ignitionSchedule5.StartCallback = startCallback; //Name the start callback function
|
||||
ignitionSchedule5.EndCallback = endCallback; //Name the start callback function
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
|
||||
OCR5A = TCNT5 + (timeout >> 2); //As there is a tick every 4uS, there are timeout/4 ticks until the interrupt should be triggered ( >>2 divides by 4)
|
||||
ignitionSchedule5.Status = PENDING; //Turn this schedule on
|
||||
TIMSK5 |= (1 << OCIE5A); //Turn on the A compare unit (ie turn on the interrupt)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************************************************************************************************************************************/
|
||||
|
@ -250,44 +294,52 @@ 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)
|
||||
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 == OFF) { FUEL1_TIMER_DISABLE(); 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
|
||||
{
|
||||
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);
|
||||
FUEL1_COMPARE = popQueue(timer3Aqueue);
|
||||
}
|
||||
else if (timer3Aqueue[0]->Status == RUNNING)
|
||||
{
|
||||
timer3Aqueue[0]->EndCallback();
|
||||
timer3Aqueue[0]->Status = OFF; //Turn off the schedule
|
||||
timer3Aqueue[0]->schedulesSet = 0;
|
||||
OCR3A = popQueue(timer3Aqueue);
|
||||
FUEL1_COMPARE = popQueue(timer3Aqueue);
|
||||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
void timer3compareBinterrupt() //Most ARM chips can simply call a function
|
||||
#endif
|
||||
{
|
||||
if (fuelSchedule2.Status == PENDING) //Check to see if this schedule is turn on
|
||||
{
|
||||
fuelSchedule2.StartCallback();
|
||||
fuelSchedule2.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
|
||||
OCR3B = fuelSchedule2.endCompare;
|
||||
FUEL2_COMPARE = fuelSchedule2.endCompare;
|
||||
}
|
||||
else if (fuelSchedule2.Status == RUNNING)
|
||||
{
|
||||
fuelSchedule2.EndCallback();
|
||||
fuelSchedule2.Status = OFF; //Turn off the schedule
|
||||
fuelSchedule2.schedulesSet = 0;
|
||||
TIMSK3 &= ~(1 << OCIE3B); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3)
|
||||
FUEL2_TIMER_DISABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||
ISR(TIMER3_COMPC_vect, ISR_NOBLOCK) //fuelSchedule3
|
||||
#elif defined (CORE_TEENSY) && defined (__MK20DX256__)
|
||||
#elif defined (CORE_TEENSY)
|
||||
void timer3compareCinterrupt() //Most ARM chips can simply call a function
|
||||
#endif
|
||||
{
|
||||
|
@ -295,20 +347,20 @@ void timer3compareCinterrupt() //Most ARM chips can simply call a function
|
|||
{
|
||||
fuelSchedule3.StartCallback();
|
||||
fuelSchedule3.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
|
||||
OCR3C = fuelSchedule3.endCompare;
|
||||
FUEL3_COMPARE = fuelSchedule3.endCompare;
|
||||
}
|
||||
else if (fuelSchedule3.Status == RUNNING)
|
||||
{
|
||||
fuelSchedule3.EndCallback();
|
||||
fuelSchedule3.Status = OFF; //Turn off the schedule
|
||||
fuelSchedule3.schedulesSet = 0;
|
||||
TIMSK3 &= ~(1 << OCIE3C); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3)
|
||||
FUEL3_TIMER_DISABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||
ISR(TIMER4_COMPB_vect, ISR_NOBLOCK) //fuelSchedule4
|
||||
#elif defined (CORE_TEENSY) && defined (__MK20DX256__)
|
||||
#elif defined (CORE_TEENSY)
|
||||
void timer4compareBinterrupt() //Most ARM chips can simply call a function
|
||||
#endif
|
||||
{
|
||||
|
@ -316,109 +368,105 @@ void timer4compareBinterrupt() //Most ARM chips can simply call a function
|
|||
{
|
||||
fuelSchedule4.StartCallback();
|
||||
fuelSchedule4.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
|
||||
OCR4B = fuelSchedule4.endCompare;
|
||||
FUEL4_COMPARE = fuelSchedule4.endCompare;
|
||||
}
|
||||
else if (fuelSchedule4.Status == RUNNING)
|
||||
{
|
||||
fuelSchedule4.EndCallback();
|
||||
fuelSchedule4.Status = OFF; //Turn off the schedule
|
||||
fuelSchedule4.schedulesSet = 0;
|
||||
TIMSK4 &= ~(1 << OCIE4B); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3)
|
||||
FUEL4_TIMER_DISABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||
ISR(TIMER5_COMPA_vect, ISR_NOBLOCK) //ignitionSchedule1
|
||||
#elif defined (CORE_TEENSY) && defined (__MK20DX256__)
|
||||
#elif defined (CORE_TEENSY)
|
||||
void timer5compareAinterrupt() //Most ARM chips can simply call a function
|
||||
#endif
|
||||
{
|
||||
if (ignitionSchedule1.Status == PENDING) //Check to see if this schedule is turn on
|
||||
{
|
||||
//if ( ign1LastRev == startRevolutions ) { return; }
|
||||
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();
|
||||
ignitionSchedule1.StartCallback();
|
||||
ign1LastRev = startRevolutions;
|
||||
OCR5A = TCNT5 + (ignitionSchedule1.duration >> 2); //Divide by 4
|
||||
IGN1_COMPARE = ignitionSchedule1.endCompare; //OCR5A = TCNT5 + (ignitionSchedule1.duration >> 2); //Divide by 4
|
||||
}
|
||||
else if (ignitionSchedule1.Status == RUNNING)
|
||||
{
|
||||
ignitionSchedule1.Status = OFF; //Turn off the schedule
|
||||
ignitionSchedule1.EndCallback();
|
||||
ignitionCount += 1; //Increment the igintion counter
|
||||
TIMSK5 &= ~(1 << OCIE5A); //Turn off this output compare unit
|
||||
IGN1_TIMER_DISABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||
ISR(TIMER5_COMPB_vect, ISR_NOBLOCK) //ignitionSchedule2
|
||||
#elif defined (CORE_TEENSY) && defined (__MK20DX256__)
|
||||
#elif defined (CORE_TEENSY)
|
||||
void timer5compareBinterrupt() //Most ARM chips can simply call a function
|
||||
#endif
|
||||
{
|
||||
if (ignitionSchedule2.Status == PENDING) //Check to see if this schedule is turn on
|
||||
{
|
||||
//if ( ign2LastRev == startRevolutions ) { return; }
|
||||
ignitionSchedule2.StartCallback();
|
||||
ignitionSchedule2.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
|
||||
ignitionSchedule2.startTime = micros();
|
||||
ignitionSchedule2.StartCallback();
|
||||
ign2LastRev = startRevolutions;
|
||||
OCR5B = TCNT5 + (ignitionSchedule2.duration >> 2);
|
||||
IGN2_COMPARE = ignitionSchedule2.endCompare; //OCR5B = TCNT5 + (ignitionSchedule2.duration >> 2);
|
||||
}
|
||||
else if (ignitionSchedule2.Status == RUNNING)
|
||||
{
|
||||
ignitionSchedule2.Status = OFF; //Turn off the schedule
|
||||
ignitionSchedule2.EndCallback();
|
||||
ignitionCount += 1; //Increment the igintion counter
|
||||
TIMSK5 &= ~(1 << OCIE5B); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3)
|
||||
IGN2_TIMER_DISABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||
ISR(TIMER5_COMPC_vect, ISR_NOBLOCK) //ignitionSchedule3
|
||||
#elif defined (CORE_TEENSY) && defined (__MK20DX256__)
|
||||
#elif defined (CORE_TEENSY)
|
||||
void timer5compareCinterrupt() //Most ARM chips can simply call a function
|
||||
#endif
|
||||
{
|
||||
if (ignitionSchedule3.Status == PENDING) //Check to see if this schedule is turn on
|
||||
{
|
||||
//if ( ign3LastRev == startRevolutions ) { return; }
|
||||
ignitionSchedule3.StartCallback();
|
||||
ignitionSchedule3.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
|
||||
ignitionSchedule3.startTime = micros();
|
||||
ignitionSchedule3.StartCallback();
|
||||
ign3LastRev = startRevolutions;
|
||||
OCR5C = TCNT5 + (ignitionSchedule3.duration >> 2);
|
||||
IGN3_COMPARE = ignitionSchedule3.endCompare; //OCR5C = TCNT5 + (ignitionSchedule3.duration >> 2);
|
||||
}
|
||||
else if (ignitionSchedule3.Status == RUNNING)
|
||||
{
|
||||
ignitionSchedule3.Status = OFF; //Turn off the schedule
|
||||
ignitionSchedule3.EndCallback();
|
||||
ignitionCount += 1; //Increment the igintion counter
|
||||
TIMSK5 &= ~(1 << OCIE5C); //Turn off this output compare unit (This simply writes 0 to the OCIE3A bit of TIMSK3)
|
||||
IGN3_TIMER_DISABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||
ISR(TIMER4_COMPA_vect, ISR_NOBLOCK) //ignitionSchedule4
|
||||
#elif defined (CORE_TEENSY) && defined (__MK20DX256__)
|
||||
#elif defined (CORE_TEENSY)
|
||||
void timer4compareAinterrupt() //Most ARM chips can simply call a function
|
||||
#endif
|
||||
{
|
||||
if (ignitionSchedule4.Status == PENDING) //Check to see if this schedule is turn on
|
||||
{
|
||||
//if ( ign4LastRev == startRevolutions ) { return; }
|
||||
ignitionSchedule4.StartCallback();
|
||||
ignitionSchedule4.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
|
||||
ignitionSchedule4.startTime = micros();
|
||||
ignitionSchedule4.StartCallback();
|
||||
ign4LastRev = startRevolutions;
|
||||
OCR4A = TCNT4 + (ignitionSchedule4.duration >> 4); //Divide by 16
|
||||
IGN4_COMPARE = ignitionSchedule4.endCompare; //OCR4A = TCNT4 + (ignitionSchedule4.duration >> 4); //Divide by 16
|
||||
}
|
||||
else if (ignitionSchedule4.Status == RUNNING)
|
||||
{
|
||||
ignitionSchedule4.Status = OFF; //Turn off the schedule
|
||||
ignitionSchedule4.EndCallback();
|
||||
ignitionCount += 1; //Increment the igintion counter
|
||||
TIMSK4 &= ~(1 << OCIE4A); //Turn off this output compare unit (This simply writes 0 to the OCIE4A bit of TIMSK4)
|
||||
IGN4_TIMER_DISABLE();
|
||||
}
|
||||
}
|
||||
|
|
216
speeduino.ino
216
speeduino.ino
|
@ -97,9 +97,10 @@ unsigned long MAPrunningValue; //Used for tracking either the total of all MAP r
|
|||
unsigned int MAPcount; //Number of samples taken in the current MAP cycle
|
||||
byte MAPcurRev = 0; //Tracks which revolution we're sampling on
|
||||
|
||||
int CRANK_ANGLE_MAX = 360; // The number of crank degrees that the system track over. 360 for wasted / timed batch and 720 for sequential
|
||||
bool useSequentialFuel; // Whether sequential fueling is to be used (1 squirt per cycle)
|
||||
bool useSequentialIgnition; // Whether sequential ignition is used (1 spark per cycle)
|
||||
int CRANK_ANGLE_MAX = 720;
|
||||
int CRANK_ANGLE_MAX_IGN, CRANK_ANGLE_MAX_INJ = 360; // The number of crank degrees that the system track over. 360 for wasted / timed batch and 720 for sequential
|
||||
//bool useSequentialFuel; // Whether sequential fueling is to be used (1 squirt per cycle)
|
||||
//bool useSequentialIgnition; // Whether sequential ignition is used (1 spark per cycle)
|
||||
|
||||
static byte coilHIGH = HIGH;
|
||||
static byte coilLOW = LOW;
|
||||
|
@ -149,7 +150,10 @@ volatile bool fpPrimed = false; //Tracks whether or not the fuel pump priming ha
|
|||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.begin(115200);
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //ATmega2561 does not have Serial3
|
||||
if (configPage1.canEnable) { Serial3.begin(115200); }
|
||||
#endif
|
||||
|
||||
//Setup the dummy fuel and ignition tables
|
||||
//dummyFuelTable(&fuelTable);
|
||||
|
@ -161,7 +165,6 @@ void setup()
|
|||
table3D_setSize(&vvtTable, 8);
|
||||
|
||||
loadConfig();
|
||||
if (configPage1.canenable ==1){Serial3.begin(115200);}
|
||||
|
||||
//Repoint the 2D table structs to the config pages that were just loaded
|
||||
taeTable.valueSize = SIZE_BYTE; //Set this table to use byte values
|
||||
|
@ -457,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
|
||||
|
@ -467,6 +470,7 @@ void setup()
|
|||
cbi(ADCSRA,ADPS1);
|
||||
cbi(ADCSRA,ADPS0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
mainLoopCount = 0;
|
||||
|
@ -483,11 +487,14 @@ void setup()
|
|||
case 2:
|
||||
channel1IgnDegrees = 0;
|
||||
|
||||
if (configPage1.engineType == EVEN_FIRE ) { channel2IgnDegrees = 180; }
|
||||
if (configPage1.engineType == EVEN_FIRE )
|
||||
{
|
||||
channel2IgnDegrees = 180;
|
||||
}
|
||||
else { channel2IgnDegrees = configPage1.oddfire2; }
|
||||
|
||||
//For alternatiing injection, the squirt occurs at different times for each channel
|
||||
if(configPage1.injTiming == INJ_SEMISEQUENTIAL)
|
||||
|
||||
//For alternating injection, the squirt occurs at different times for each channel
|
||||
if(configPage1.injLayout == INJ_SEMISEQUENTIAL)
|
||||
{
|
||||
channel1InjDegrees = 0;
|
||||
channel2InjDegrees = channel2IgnDegrees; //Set to the same as the ignition degrees (Means there's no need for another if to check for oddfire)
|
||||
|
@ -512,17 +519,19 @@ void setup()
|
|||
}
|
||||
|
||||
//For alternatiing injection, the squirt occurs at different times for each channel
|
||||
if(configPage1.injTiming == INJ_SEMISEQUENTIAL)
|
||||
if(configPage1.injLayout == INJ_SEMISEQUENTIAL)
|
||||
{
|
||||
channel1InjDegrees = 0;
|
||||
channel2InjDegrees = channel2IgnDegrees;
|
||||
channel3InjDegrees = channel2IgnDegrees;
|
||||
}
|
||||
else if (configPage1.injTiming == INJ_SEQUENTIAL)
|
||||
else if (configPage1.injLayout == INJ_SEQUENTIAL)
|
||||
{
|
||||
channel1InjDegrees = 0;
|
||||
channel2InjDegrees = 240;
|
||||
channel3InjDegrees = 480;
|
||||
CRANK_ANGLE_MAX_INJ = 720;
|
||||
req_fuel_uS = req_fuel_uS * 2;
|
||||
}
|
||||
else { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
|
||||
|
||||
|
@ -537,10 +546,12 @@ void setup()
|
|||
{
|
||||
channel2IgnDegrees = 180;
|
||||
|
||||
if(useSequentialIgnition)
|
||||
if(configPage2.sparkMode == IGN_MODE_SEQUENTIAL)
|
||||
{
|
||||
channel3IgnDegrees = 360;
|
||||
channel4IgnDegrees = 540;
|
||||
|
||||
CRANK_ANGLE_MAX_IGN = 720;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -551,17 +562,23 @@ void setup()
|
|||
}
|
||||
|
||||
//For alternatiing injection, the squirt occurs at different times for each channel
|
||||
if(configPage1.injTiming == INJ_SEMISEQUENTIAL)
|
||||
if(configPage1.injLayout == INJ_SEMISEQUENTIAL)
|
||||
{
|
||||
channel1InjDegrees = 0;
|
||||
channel2InjDegrees = channel2IgnDegrees;
|
||||
}
|
||||
else if (useSequentialFuel)
|
||||
else if (configPage1.injLayout == INJ_SEQUENTIAL)
|
||||
{
|
||||
channel1InjDegrees = 0;
|
||||
channel2InjDegrees = channel2IgnDegrees;
|
||||
channel3InjDegrees = channel3IgnDegrees;
|
||||
channel4InjDegrees = channel4IgnDegrees;
|
||||
channel2InjDegrees = 180;
|
||||
channel3InjDegrees = 360;
|
||||
channel4InjDegrees = 540;
|
||||
|
||||
channel3InjEnabled = true;
|
||||
channel4InjEnabled = true;
|
||||
|
||||
CRANK_ANGLE_MAX_INJ = 720;
|
||||
req_fuel_uS = req_fuel_uS * 2;
|
||||
}
|
||||
else { channel1InjDegrees = channel2InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
|
||||
|
||||
|
@ -575,16 +592,18 @@ void setup()
|
|||
channel4IgnDegrees = 216;
|
||||
channel5IgnDegrees = 288;
|
||||
|
||||
if(useSequentialIgnition)
|
||||
if(configPage2.sparkMode == IGN_MODE_SEQUENTIAL)
|
||||
{
|
||||
channel2IgnDegrees = 144;
|
||||
channel3IgnDegrees = 288;
|
||||
channel4IgnDegrees = 432;
|
||||
channel5IgnDegrees = 576;
|
||||
|
||||
CRANK_ANGLE_MAX_IGN = 720;
|
||||
}
|
||||
|
||||
//For alternatiing injection, the squirt occurs at different times for each channel
|
||||
if(configPage1.injTiming == INJ_SEMISEQUENTIAL)
|
||||
if(configPage1.injLayout == INJ_SEMISEQUENTIAL)
|
||||
{
|
||||
channel1InjDegrees = 0;
|
||||
channel2InjDegrees = 72;
|
||||
|
@ -592,13 +611,15 @@ void setup()
|
|||
channel4InjDegrees = 216;
|
||||
channel5InjDegrees = 288;
|
||||
}
|
||||
else if (useSequentialFuel)
|
||||
else if (configPage1.injLayout == INJ_SEQUENTIAL)
|
||||
{
|
||||
channel1InjDegrees = 0;
|
||||
channel2InjDegrees = 144;
|
||||
channel3InjDegrees = 288;
|
||||
channel4InjDegrees = 432;
|
||||
channel5InjDegrees = 576;
|
||||
|
||||
CRANK_ANGLE_MAX_INJ = 720;
|
||||
}
|
||||
else { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = channel4InjDegrees = channel5InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
|
||||
|
||||
|
@ -614,7 +635,7 @@ void setup()
|
|||
channel3IgnDegrees = 240;
|
||||
|
||||
//For alternatiing injection, the squirt occurs at different times for each channel
|
||||
if(configPage1.injTiming == INJ_SEMISEQUENTIAL || configPage1.injTiming == INJ_SEQUENTIAL) //No full sequential for more than 4 cylinders
|
||||
if(configPage1.injLayout == INJ_SEMISEQUENTIAL || configPage1.injLayout == INJ_SEQUENTIAL) //No full sequential for more than 4 cylinders
|
||||
{
|
||||
channel1InjDegrees = 0;
|
||||
channel2InjDegrees = 120;
|
||||
|
@ -635,7 +656,7 @@ void setup()
|
|||
channel4IgnDegrees = 270;
|
||||
|
||||
//For alternatiing injection, the squirt occurs at different times for each channel
|
||||
if(configPage1.injTiming == INJ_SEMISEQUENTIAL || configPage1.injTiming == INJ_SEQUENTIAL) //No full sequential for more than 4 cylinders
|
||||
if(configPage1.injLayout == INJ_SEMISEQUENTIAL || configPage1.injTiming == INJ_SEQUENTIAL) //No full sequential for more than 4 cylinders
|
||||
{
|
||||
channel1InjDegrees = 0;
|
||||
channel2InjDegrees = 90;
|
||||
|
@ -754,17 +775,19 @@ void loop()
|
|||
command();
|
||||
}
|
||||
}
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //ATmega2561 does not have Serial3
|
||||
//if Can interface is enabled then check for serial3 requests.
|
||||
if (configPage1.canenable == 1)
|
||||
if (configPage1.canEnable)
|
||||
{
|
||||
if ( ((mainLoopCount & 31) == 1) or (Serial3.available() > SERIAL_BUFFER_THRESHOLD) )
|
||||
{
|
||||
if (Serial3.available() > 0)
|
||||
{
|
||||
Cancommand();
|
||||
canCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// if (configPage1.displayType && (mainLoopCount & 255) == 1) { updateDisplay();} //Displays currently disabled
|
||||
|
||||
|
@ -795,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
|
||||
|
@ -989,53 +1012,66 @@ void loop()
|
|||
//Determine next firing angles
|
||||
int PWdivTimerPerDegree = div(currentStatus.PW, timePerDegree).quot; //How many crank degrees the calculated PW will take at the current speed
|
||||
injector1StartAngle = configPage1.inj1Ang - ( PWdivTimerPerDegree ); //This is a little primitive, but is based on the idea that all fuel needs to be delivered before the inlet valve opens. See http://www.extraefi.co.uk/sequential_fuel.html for more detail
|
||||
if(injector1StartAngle < 0) {injector1StartAngle += CRANK_ANGLE_MAX;}
|
||||
if(injector1StartAngle < 0) {injector1StartAngle += CRANK_ANGLE_MAX_INJ;}
|
||||
//Repeat the above for each cylinder
|
||||
switch (configPage1.nCylinders)
|
||||
{
|
||||
//2 cylinders
|
||||
case 2:
|
||||
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX) {injector2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
break;
|
||||
//3 cylinders
|
||||
case 3:
|
||||
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX) {injector2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector3StartAngle > CRANK_ANGLE_MAX) {injector3StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
break;
|
||||
//4 cylinders
|
||||
case 4:
|
||||
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX) {injector2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
|
||||
if(configPage1.injLayout == INJ_SEQUENTIAL)
|
||||
{
|
||||
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
injector4StartAngle = (configPage1.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector4StartAngle > CRANK_ANGLE_MAX_INJ) {injector4StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
|
||||
injector1StartAngle += 360;
|
||||
injector2StartAngle += 360;
|
||||
injector3StartAngle += 360;
|
||||
injector4StartAngle += 360;
|
||||
}
|
||||
break;
|
||||
//5 cylinders
|
||||
case 5:
|
||||
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX) {injector2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector3StartAngle > CRANK_ANGLE_MAX) {injector3StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
injector4StartAngle = (configPage1.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector4StartAngle > CRANK_ANGLE_MAX) {injector4StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector4StartAngle > CRANK_ANGLE_MAX_INJ) {injector4StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
injector5StartAngle = (configPage1.inj1Ang + channel5InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector5StartAngle > CRANK_ANGLE_MAX) {injector5StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector5StartAngle > CRANK_ANGLE_MAX_INJ) {injector5StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
break;
|
||||
//6 cylinders
|
||||
case 6:
|
||||
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX) {injector2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector3StartAngle > CRANK_ANGLE_MAX) {injector3StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
break;
|
||||
//8 cylinders
|
||||
case 8:
|
||||
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX) {injector2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector3StartAngle > CRANK_ANGLE_MAX) {injector3StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
injector4StartAngle = (configPage1.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree ));
|
||||
if(injector4StartAngle > CRANK_ANGLE_MAX) {injector4StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(injector4StartAngle > CRANK_ANGLE_MAX_INJ) {injector4StartAngle -= CRANK_ANGLE_MAX_INJ;}
|
||||
break;
|
||||
//Will hit the default case on 1 cylinder or >8 cylinders. Do nothing in these cases
|
||||
default:
|
||||
|
@ -1061,45 +1097,53 @@ void loop()
|
|||
|
||||
//Calculate start angle for each channel
|
||||
//1 cylinder (Everyone gets this)
|
||||
ignition1StartAngle = CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle; // 360 - desired advance angle - number of degrees the dwell will take
|
||||
if(ignition1StartAngle < 0) {ignition1StartAngle += CRANK_ANGLE_MAX;}
|
||||
ignition1StartAngle = CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle; // 360 - desired advance angle - number of degrees the dwell will take
|
||||
if(ignition1StartAngle < 0) {ignition1StartAngle += CRANK_ANGLE_MAX_IGN;}
|
||||
|
||||
//This test for more cylinders and do the same thing
|
||||
switch (configPage1.nCylinders)
|
||||
{
|
||||
//2 cylinders
|
||||
case 2:
|
||||
ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > CRANK_ANGLE_MAX) {ignition2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
break;
|
||||
//3 cylinders
|
||||
case 3:
|
||||
ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > CRANK_ANGLE_MAX) {ignition2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
ignition3StartAngle = channel3IgnDegrees + 360 - currentStatus.advance - dwellAngle;
|
||||
if(ignition3StartAngle > CRANK_ANGLE_MAX) {ignition3StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
break;
|
||||
//4 cylinders
|
||||
case 4:
|
||||
ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > CRANK_ANGLE_MAX) {ignition2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(ignition2StartAngle < 0) {ignition2StartAngle += CRANK_ANGLE_MAX;}
|
||||
ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
if(ignition2StartAngle < 0) {ignition2StartAngle += CRANK_ANGLE_MAX_IGN;}
|
||||
|
||||
if(configPage2.sparkMode == IGN_MODE_SEQUENTIAL)
|
||||
{
|
||||
ignition3StartAngle = channel3IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle;
|
||||
if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
ignition4StartAngle = channel4IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle;
|
||||
if(ignition4StartAngle > CRANK_ANGLE_MAX_IGN) {ignition4StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
}
|
||||
break;
|
||||
//6 cylinders
|
||||
case 6:
|
||||
ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > CRANK_ANGLE_MAX) {ignition2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
ignition3StartAngle = channel3IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle;
|
||||
if(ignition3StartAngle > CRANK_ANGLE_MAX) {ignition3StartAngle -= CRANK_ANGLE_MAX;}
|
||||
ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
ignition3StartAngle = channel3IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle;
|
||||
if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
break;
|
||||
//8 cylinders
|
||||
case 8:
|
||||
ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > CRANK_ANGLE_MAX) {ignition2StartAngle -= CRANK_ANGLE_MAX;}
|
||||
ignition2StartAngle = channel2IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance - dwellAngle;
|
||||
if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
ignition3StartAngle = channel3IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle;
|
||||
if(ignition3StartAngle > CRANK_ANGLE_MAX) {ignition3StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
ignition4StartAngle = channel4IgnDegrees + CRANK_ANGLE_MAX - currentStatus.advance - dwellAngle;
|
||||
if(ignition4StartAngle > CRANK_ANGLE_MAX) {ignition4StartAngle -= CRANK_ANGLE_MAX;}
|
||||
if(ignition4StartAngle > CRANK_ANGLE_MAX_IGN) {ignition4StartAngle -= CRANK_ANGLE_MAX_IGN;}
|
||||
break;
|
||||
|
||||
//Will hit the default case on 1 cylinder or >8 cylinders. Do nothing in these cases
|
||||
|
@ -1115,13 +1159,14 @@ void loop()
|
|||
|
||||
//Determine the current crank angle
|
||||
int crankAngle = getCrankAngle(timePerDegree);
|
||||
if (crankAngle > CRANK_ANGLE_MAX_INJ ) { crankAngle -= 360; }
|
||||
|
||||
if (fuelOn && currentStatus.PW > 0 && !BIT_CHECK(currentStatus.squirt, BIT_SQUIRT_BOOSTCUT))
|
||||
{
|
||||
if (injector1StartAngle <= crankAngle && fuelSchedule1.schedulesSet == 0) { injector1StartAngle += 360; }
|
||||
if (injector1StartAngle <= crankAngle && fuelSchedule1.schedulesSet == 0) { injector1StartAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
if (injector1StartAngle > crankAngle)
|
||||
{
|
||||
if (configPage1.injLayout == 1)
|
||||
if (configPage1.injLayout == INJ_SEMISEQUENTIAL)
|
||||
{
|
||||
setFuelSchedule1(openInjector1and4,
|
||||
((unsigned long)(injector1StartAngle - crankAngle) * (unsigned long)timePerDegree),
|
||||
|
@ -1153,10 +1198,10 @@ void loop()
|
|||
if(channel2InjEnabled)
|
||||
{
|
||||
tempCrankAngle = crankAngle - channel2InjDegrees;
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; }
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
tempStartAngle = injector2StartAngle - channel2InjDegrees;
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; }
|
||||
if (tempStartAngle <= tempCrankAngle && fuelSchedule2.schedulesSet == 0) { tempStartAngle += 360; }
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
if (tempStartAngle <= tempCrankAngle && fuelSchedule2.schedulesSet == 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
if ( tempStartAngle > tempCrankAngle )
|
||||
{
|
||||
if (configPage1.injLayout == 1)
|
||||
|
@ -1181,10 +1226,10 @@ void loop()
|
|||
if(channel3InjEnabled)
|
||||
{
|
||||
tempCrankAngle = crankAngle - channel3InjDegrees;
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; }
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
tempStartAngle = injector3StartAngle - channel3InjDegrees;
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; }
|
||||
if (tempStartAngle <= tempCrankAngle && fuelSchedule3.schedulesSet == 0) { tempStartAngle += 360; }
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
if (tempStartAngle <= tempCrankAngle && fuelSchedule3.schedulesSet == 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
if ( tempStartAngle > tempCrankAngle )
|
||||
{
|
||||
setFuelSchedule3(openInjector3,
|
||||
|
@ -1198,10 +1243,10 @@ void loop()
|
|||
if(channel4InjEnabled)
|
||||
{
|
||||
tempCrankAngle = crankAngle - channel4InjDegrees;
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; }
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
tempStartAngle = injector4StartAngle - channel4InjDegrees;
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; }
|
||||
if (tempStartAngle <= tempCrankAngle && fuelSchedule4.schedulesSet == 0) { tempStartAngle += 360; }
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
if (tempStartAngle <= tempCrankAngle && fuelSchedule4.schedulesSet == 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
if ( tempStartAngle > tempCrankAngle )
|
||||
{
|
||||
setFuelSchedule4(openInjector4,
|
||||
|
@ -1212,13 +1257,13 @@ void loop()
|
|||
}
|
||||
}
|
||||
|
||||
//if(channel5InjEnabled)
|
||||
if(channel5InjEnabled)
|
||||
{
|
||||
tempCrankAngle = crankAngle - channel5InjDegrees;
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; }
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
tempStartAngle = injector5StartAngle - channel5InjDegrees;
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; }
|
||||
if (tempStartAngle <= tempCrankAngle && fuelSchedule5.schedulesSet == 0) { tempStartAngle += 360; }
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
if (tempStartAngle <= tempCrankAngle && fuelSchedule5.schedulesSet == 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
|
||||
if ( tempStartAngle > tempCrankAngle )
|
||||
{
|
||||
setFuelSchedule5(openInjector5,
|
||||
|
@ -1232,14 +1277,15 @@ void loop()
|
|||
//***********************************************************************************************
|
||||
//| BEGIN IGNITION SCHEDULES
|
||||
//Likewise for the ignition
|
||||
//Perform an initial check to see if the ignition is turned on (Ignition only turns on after a preset number of cranking revolutions and:
|
||||
//Check for hard cut rev limit (If we're above the hardcut limit, we simply don't set a spark schedule)
|
||||
//crankAngle = getCrankAngle(timePerDegree); //Refresh with the latest crank angle
|
||||
crankAngle = getCrankAngle(timePerDegree); //Refresh with the latest crank angle
|
||||
if (crankAngle > CRANK_ANGLE_MAX_IGN ) { crankAngle -= 360; }
|
||||
|
||||
//fixedCrankingOverride is used to extend the dwell during cranking so that the decoder can trigger the spark upon seeing a certain tooth. Currently only available on the basic distributor and 4g63 decoders.
|
||||
if ( configPage2.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) { fixedCrankingOverride = currentStatus.dwell; }
|
||||
else { fixedCrankingOverride = 0; }
|
||||
|
||||
|
||||
//Perform an initial check to see if the ignition is turned on (Ignition only turns on after a preset number of cranking revolutions and:
|
||||
//Check for hard cut rev limit (If we're above the hardcut limit, we simply don't set a spark schedule)
|
||||
if(ignitionOn && !currentStatus.launchingHard && !BIT_CHECK(currentStatus.spark, BIT_SPARK_BOOSTCUT) && !BIT_CHECK(currentStatus.spark, BIT_SPARK_HRDLIM))
|
||||
{
|
||||
|
||||
|
@ -1262,9 +1308,9 @@ void loop()
|
|||
}
|
||||
|
||||
tempCrankAngle = crankAngle - channel2IgnDegrees;
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; }
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_IGN; }
|
||||
tempStartAngle = ignition2StartAngle - channel2IgnDegrees;
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; }
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_IGN; }
|
||||
//if ( (tempStartAngle > tempCrankAngle) && ign2LastRev != startRevolutions)
|
||||
//if ( ign2LastRev != startRevolutions )
|
||||
{
|
||||
|
@ -1283,9 +1329,9 @@ void loop()
|
|||
}
|
||||
|
||||
tempCrankAngle = crankAngle - channel3IgnDegrees;
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; }
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_IGN; }
|
||||
tempStartAngle = ignition3StartAngle - channel3IgnDegrees;
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; }
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_IGN; }
|
||||
//if (tempStartAngle > tempCrankAngle)
|
||||
{
|
||||
long ignition3StartTime = 0;
|
||||
|
@ -1303,9 +1349,9 @@ void loop()
|
|||
}
|
||||
|
||||
tempCrankAngle = crankAngle - channel4IgnDegrees;
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; }
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_IGN; }
|
||||
tempStartAngle = ignition4StartAngle - channel4IgnDegrees;
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; }
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_IGN; }
|
||||
//if (tempStartAngle > tempCrankAngle)
|
||||
{
|
||||
|
||||
|
@ -1324,9 +1370,9 @@ void loop()
|
|||
}
|
||||
|
||||
tempCrankAngle = crankAngle - channel5IgnDegrees;
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX; }
|
||||
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_IGN; }
|
||||
tempStartAngle = ignition5StartAngle - channel5IgnDegrees;
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX; }
|
||||
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_IGN; }
|
||||
//if (tempStartAngle > tempCrankAngle)
|
||||
{
|
||||
|
||||
|
|
4
timers.h
4
timers.h
|
@ -24,7 +24,9 @@ volatile int loopSec;
|
|||
volatile unsigned long targetOverdwellTime;
|
||||
volatile unsigned long targetTachoPulseTime;
|
||||
|
||||
|
||||
#if defined (CORE_TEENSY)
|
||||
IntervalTimer lowResTimer;
|
||||
#endif
|
||||
void initialiseTimers();
|
||||
|
||||
#endif // TIMERS_H
|
||||
|
|
|
@ -26,6 +26,9 @@ void initialiseTimers()
|
|||
/* Now configure the prescaler to CPU clock divided by 128 = 125Khz */
|
||||
TCCR2B |= (1<<CS22) | (1<<CS20); // Set bits
|
||||
TCCR2B &= ~(1<<CS21); // Clear bit
|
||||
#elif defined (CORE_TEENSY)
|
||||
//Uses the PIT timer on Teensy.
|
||||
lowResTimer.begin(oneMSInterval, 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -34,8 +37,8 @@ void initialiseTimers()
|
|||
//Executes every ~1ms.
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
|
||||
ISR(TIMER2_OVF_vect, ISR_NOBLOCK)
|
||||
#elif defined (CORE_TEENSY) && defined (__MK20DX256__)
|
||||
void timer2Overflowinterrupt() //Most ARM chips can simply call a function
|
||||
#elif defined (CORE_TEENSY)
|
||||
void oneMSInterval() //Most ARM chips can simply call a function
|
||||
#endif
|
||||
{
|
||||
|
||||
|
|
|
@ -12,9 +12,13 @@ Returns how much free dynamic memory exists (between heap and stack)
|
|||
|
||||
int freeRam ()
|
||||
{
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
extern int __heap_start, *__brkval;
|
||||
int v;
|
||||
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||
#elif defined(CORE_TEENSY)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setPinMapping(byte boardID)
|
||||
|
|
Loading…
Reference in New Issue