Initial proposed clang-format

This commit is contained in:
Josh Stewart 2023-09-15 12:35:56 +10:00
parent a92ca8d191
commit 0e49e268f4
37 changed files with 13848 additions and 13377 deletions

223
.clang-format Normal file
View File

@ -0,0 +1,223 @@
---
BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: "true"
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: "false"
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Always
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAfterAttributes: Never
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeConceptDeclarations: Always
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ColumnLimit: 300
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: ^"(llvm|llvm-c|clang|clang-c)/
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: ^(<|"(gtest|gmock|isl|json)/)
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: .*
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: (Test)?$
IncludeIsMainSourceRegex: ""
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: BeforeHash
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: true
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
Language: Cpp
LineEnding: DeriveLF
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PPIndentWidth: -1
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: false
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: "false"
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: "true"
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: Never
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDeclarationName: false
AfterFunctionDefinitionName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: "false"
SpacesBeforeTrailingComments: 1
SpacesInAngles: "false"
SpacesInCStyleCastParentheses: "false"
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: "2"
UseTab: Never
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE

View File

@ -2,52 +2,52 @@
#include BOARD_H
#ifdef SD_LOGGING
#include <SPI.h>
#ifdef __SD_H__
#include <SD.h>
#else
#include "SdFat.h"
#endif
#include "SD_logger.h"
#include "logger.h"
#include "rtc_common.h"
#include "maths.h"
#include <SPI.h>
#ifdef __SD_H__
#include <SD.h>
#else
#include "SdFat.h"
#endif
#include "SD_logger.h"
#include "logger.h"
#include "rtc_common.h"
#include "maths.h"
SdExFat sd;
ExFile logFile;
SdExFat sd;
ExFile logFile;
RingBuf<ExFile, RING_BUF_CAPACITY> rb;
uint8_t SD_status = SD_STATUS_OFF;
uint16_t currentLogFileNumber;
bool manualLogActive = false;
uint32_t logStartTime = 0; //In ms
uint8_t SD_status = SD_STATUS_OFF;
uint16_t currentLogFileNumber;
bool manualLogActive = false;
uint32_t logStartTime = 0; // In ms
void initSD()
{
//Set default state to ready. If any stage of the init fails, this will be changed
SD_status = SD_STATUS_READY;
// Set default state to ready. If any stage of the init fails, this will be changed
SD_status = SD_STATUS_READY;
//Set the RTC callback. This is used to set the correct timestamp on file creation and sync operations
// Set the RTC callback. This is used to set the correct timestamp on file creation and sync operations
FsDateTime::setCallback(dateTime);
// Initialise the SD.
if (!sd.begin(SD_CONFIG))
if(!sd.begin(SD_CONFIG))
{
//sd.initErrorHalt(&Serial);
//if (sdErrorCode() == SD_CARD_ERROR_CMD0) { SD_status = SD_STATUS_ERROR_NO_CARD;
// sd.initErrorHalt(&Serial);
// if (sdErrorCode() == SD_CARD_ERROR_CMD0) { SD_status = SD_STATUS_ERROR_NO_CARD;
SD_status = SD_STATUS_ERROR_NO_CARD;
}
//Set the TunerStudio status variable
// Set the TunerStudio status variable
setTS_SD_status();
}
bool createLogFile()
{
//TunerStudio only supports 8.3 filename format.
char filenameBuffer[13]; //8 + 1 + 3 + 1
// TunerStudio only supports 8.3 filename format.
char filenameBuffer[13]; // 8 + 1 + 3 + 1
bool returnValue = false;
//Saving this in case we ever go back to the datestamped filename
// Saving this in case we ever go back to the datestamped filename
/*
//Filename format is: YYYY-MM-DD_HH.MM.SS.csv
char intBuffer[5];
@ -71,17 +71,14 @@ bool createLogFile()
strcat(filenameBuffer, ".csv");
*/
//Lookup the next available file number
// Lookup the next available file number
currentLogFileNumber = getNextSDLogFileNumber();
//Create the filename
// Create the filename
sprintf(filenameBuffer, "%s%04d.%s", LOG_FILE_PREFIX, currentLogFileNumber, LOG_FILE_EXTENSION);
logFile.close();
if (logFile.open(filenameBuffer, O_RDWR | O_CREAT | O_TRUNC))
{
returnValue = true;
}
if(logFile.open(filenameBuffer, O_RDWR | O_CREAT | O_TRUNC)) { returnValue = true; }
return returnValue;
}
@ -89,11 +86,11 @@ bool createLogFile()
uint16_t getNextSDLogFileNumber()
{
uint16_t nextFileNumber = 1;
char filenameBuffer[13]; //8 + 1 + 3 + 1
char filenameBuffer[13]; // 8 + 1 + 3 + 1
sprintf(filenameBuffer, "%s%04d.%s", LOG_FILE_PREFIX, nextFileNumber, LOG_FILE_EXTENSION);
//Lookup the next available file number
while( (nextFileNumber < MAX_LOG_FILES) && (sd.exists(filenameBuffer)) )
// Lookup the next available file number
while((nextFileNumber < MAX_LOG_FILES) && (sd.exists(filenameBuffer)))
{
nextFileNumber++;
sprintf(filenameBuffer, "%s%04d.%s", LOG_FILE_PREFIX, nextFileNumber, LOG_FILE_EXTENSION);
@ -102,57 +99,57 @@ uint16_t getNextSDLogFileNumber()
return nextFileNumber;
}
bool getSDLogFileDetails(uint8_t* buffer, uint16_t logNumber)
bool getSDLogFileDetails(uint8_t *buffer, uint16_t logNumber)
{
bool fileFound = false;
if(logFile.isOpen()) { endSDLogging(); }
char filenameBuffer[13]; //8 + 1 + 3 + 1
char filenameBuffer[13]; // 8 + 1 + 3 + 1
sprintf(filenameBuffer, "%s%04d.%s", LOG_FILE_PREFIX, logNumber, LOG_FILE_EXTENSION);
if(sd.exists(filenameBuffer))
{
fileFound = true;
logFile = sd.open(filenameBuffer, O_RDONLY);
//Copy the filename into the buffer. Note we do not copy the termination character or the fullstop
for(byte i=0; i<12; i++)
// Copy the filename into the buffer. Note we do not copy the termination character or the fullstop
for(byte i = 0; i < 12; i++)
{
//We don't copy the fullstop to the buffer
//As TS requires 8.3 filenames, it's always in the same spot
if(i < 8) { buffer[i] = filenameBuffer[i]; } //Everything before the fullstop
else if(i > 8) { buffer[i-1] = filenameBuffer[i]; } //Everything after the fullstop
// We don't copy the fullstop to the buffer
// As TS requires 8.3 filenames, it's always in the same spot
if(i < 8) { buffer[i] = filenameBuffer[i]; } // Everything before the fullstop
else if(i > 8) { buffer[i - 1] = filenameBuffer[i]; } // Everything after the fullstop
}
//Maintenance check, truncate the file. This will usually do nothing, but in the case where a prior log was interrupted, this will truncate the file
//Due to overhead, only bother doing this if the engine isn't running
// Maintenance check, truncate the file. This will usually do nothing, but in the case where a prior log was interrupted, this will truncate the file
// Due to overhead, only bother doing this if the engine isn't running
if(currentStatus.RPM == 0) { logFile.truncate(); }
//Is File or ignore
// Is File or ignore
buffer[11] = 1;
//No idea
// No idea
buffer[12] = 0;
//5 bytes for FAT creation date/time
// 5 bytes for FAT creation date/time
uint16_t pDate = 0;
uint16_t pTime = 0;
logFile.getCreateDateTime(&pDate, &pTime);
buffer[13] = 0; //Not sure what this byte is for yet
buffer[13] = 0; // Not sure what this byte is for yet
buffer[14] = lowByte(pTime);
buffer[15] = highByte(pTime);
buffer[16] = lowByte(pDate);
buffer[17] = highByte(pDate);
//Sector number (4 bytes) - This byte order might be backwards
// Sector number (4 bytes) - This byte order might be backwards
uint32_t sector = logFile.firstSector();
buffer[18] = ((sector) & 255);
buffer[19] = ((sector >> 8) & 255);
buffer[20] = ((sector >> 16) & 255);
buffer[21] = ((sector >> 24) & 255);
buffer[18] = ((sector)&255);
buffer[19] = ((sector >> 8) & 255);
buffer[20] = ((sector >> 16) & 255);
buffer[21] = ((sector >> 24) & 255);
//Unsure on the below 6 bytes, possibly last accessed or modified date/time?
// Unsure on the below 6 bytes, possibly last accessed or modified date/time?
buffer[22] = 0;
buffer[23] = 0;
buffer[24] = 0;
@ -160,22 +157,18 @@ bool getSDLogFileDetails(uint8_t* buffer, uint16_t logNumber)
buffer[26] = 0;
buffer[27] = 0;
//File size (4 bytes). Little endian
// File size (4 bytes). Little endian
uint32_t size = logFile.fileSize();
buffer[28] = ((size) & 255);
buffer[29] = ((size >> 8) & 255);
buffer[30] = ((size >> 16) & 255);
buffer[31] = ((size >> 24) & 255);
buffer[28] = ((size)&255);
buffer[29] = ((size >> 8) & 255);
buffer[30] = ((size >> 16) & 255);
buffer[31] = ((size >> 24) & 255);
}
return fileFound;
}
void readSDSectors(uint8_t* buffer, uint32_t sectorNumber, uint16_t sectorCount)
{
sd.card()->readSectors(sectorNumber, buffer, sectorCount);
}
void readSDSectors(uint8_t *buffer, uint32_t sectorNumber, uint16_t sectorCount) { sd.card()->readSectors(sectorNumber, buffer, sectorCount); }
// Forward declare
void writeSDLogHeader();
@ -184,31 +177,31 @@ void beginSDLogging()
{
if(SD_status == SD_STATUS_READY)
{
SD_status = SD_STATUS_ACTIVE; //Set the status as being active so that entries will begin to be written. This will be updated below if there is an error
SD_status = SD_STATUS_ACTIVE; // Set the status as being active so that entries will begin to be written. This will be updated below if there is an error
// Open or create file - truncate existing file.
if (!createLogFile())
if(!createLogFile())
{
SD_status = SD_STATUS_ERROR_NO_WRITE;
setTS_SD_status();
return;
}
//Perform pre-allocation on card. This dramatically improves write speed
if (!logFile.preAllocate(SD_LOG_FILE_SIZE))
// Perform pre-allocation on card. This dramatically improves write speed
if(!logFile.preAllocate(SD_LOG_FILE_SIZE))
{
SD_status = SD_STATUS_ERROR_NO_SPACE;
setTS_SD_status();
return;
}
//initialise the RingBuf.
// initialise the RingBuf.
rb.begin(&logFile);
//Write a header row
// Write a header row
writeSDLogHeader();
//Note the start time
// Note the start time
logStartTime = millis();
}
}
@ -222,7 +215,7 @@ void endSDLogging()
logFile.truncate();
logFile.rewind();
logFile.close();
logFile.sync(); //This is required to update the sd object. Without this any subsequent logfiles will overwrite this one
logFile.sync(); // This is required to update the sd object. Without this any subsequent logfiles will overwrite this one
SD_status = SD_STATUS_READY;
setTS_SD_status();
@ -235,59 +228,56 @@ void checkForSDStop();
void writeSDLogEntry()
{
//Check if we're already running a log
// Check if we're already running a log
if(SD_status == SD_STATUS_READY)
{
//Log not currently running, check if it should be
// Log not currently running, check if it should be
checkForSDStart();
}
if(SD_status == SD_STATUS_ACTIVE)
{
//Write the timestamp (x.yyy seconds format)
uint32_t duration = millis() - logStartTime;
uint32_t seconds = duration / 1000;
// Write the timestamp (x.yyy seconds format)
uint32_t duration = millis() - logStartTime;
uint32_t seconds = duration / 1000;
uint32_t milliseconds = duration % 1000;
rb.print(seconds);
rb.print('.');
if (milliseconds < 100) { rb.print("0"); }
if (milliseconds < 10) { rb.print("0"); }
if(milliseconds < 100) { rb.print("0"); }
if(milliseconds < 10) { rb.print("0"); }
rb.print(milliseconds);
rb.print(',');
//Write the line to the ring buffer
for(byte x=0; x<SD_LOG_NUM_FIELDS; x++)
// Write the line to the ring buffer
for(byte x = 0; x < SD_LOG_NUM_FIELDS; x++)
{
#if FPU_MAX_SIZE >= 32
float entryValue = getReadableFloatLogEntry(x);
if(IS_INTEGER(entryValue)) { rb.print((uint16_t)entryValue); }
else { rb.print(entryValue); }
#else
rb.print(getReadableLogEntry(x));
#endif
#if FPU_MAX_SIZE >= 32
float entryValue = getReadableFloatLogEntry(x);
if(IS_INTEGER(entryValue)) { rb.print((uint16_t)entryValue); }
else { rb.print(entryValue); }
#else
rb.print(getReadableLogEntry(x));
#endif
if(x < (SD_LOG_NUM_FIELDS - 1)) { rb.print(","); }
}
rb.println("");
//Check if write to SD from ringbuffer is needed
//We write to SD when there is more than 1 sector worth of data in the ringbuffer and there is not already a write being performed
if( (rb.bytesUsed() >= SD_SECTOR_SIZE) && !logFile.isBusy() )
// Check if write to SD from ringbuffer is needed
// We write to SD when there is more than 1 sector worth of data in the ringbuffer and there is not already a write being performed
if((rb.bytesUsed() >= SD_SECTOR_SIZE) && !logFile.isBusy())
{
uint16_t bytesWritten = rb.writeOut(SD_SECTOR_SIZE);
//Make sure that the entire sector was written successfully
if (SD_SECTOR_SIZE != bytesWritten)
{
SD_status = SD_STATUS_ERROR_WRITE_FAIL;
}
uint16_t bytesWritten = rb.writeOut(SD_SECTOR_SIZE);
// Make sure that the entire sector was written successfully
if(SD_SECTOR_SIZE != bytesWritten) { SD_status = SD_STATUS_ERROR_WRITE_FAIL; }
}
//Check whether we should stop logging
// Check whether we should stop logging
checkForSDStop();
//Check whether the file is full (IE When there is not enough room to write 1 more sector)
if( (logFile.dataLength() - logFile.curPosition()) < SD_SECTOR_SIZE)
// Check whether the file is full (IE When there is not enough room to write 1 more sector)
if((logFile.dataLength() - logFile.curPosition()) < SD_SECTOR_SIZE)
{
//Provided the conditions for logging are still met, a new file will be created the next time writeSDLogEntry is called
// Provided the conditions for logging are still met, a new file will be created the next time writeSDLogEntry is called
endSDLogging();
beginSDLogging();
}
@ -297,172 +287,146 @@ void writeSDLogEntry()
void writeSDLogHeader()
{
//Write header for Time field
// Write header for Time field
rb.print("Time,");
//WRite remaining fields based on log definitions
for(byte x=0; x<SD_LOG_NUM_FIELDS; x++)
// WRite remaining fields based on log definitions
for(byte x = 0; x < SD_LOG_NUM_FIELDS; x++)
{
#ifdef CORE_AVR
//This will probably never be used
char buffer[30];
strcpy_P(buffer, (char *)pgm_read_word(&(header_table[x])));
rb.print(buffer);
#else
rb.print(header_table[x]);
#endif
#ifdef CORE_AVR
// This will probably never be used
char buffer[30];
strcpy_P(buffer, (char *)pgm_read_word(&(header_table[x])));
rb.print(buffer);
#else
rb.print(header_table[x]);
#endif
if(x < (SD_LOG_NUM_FIELDS - 1)) { rb.print(","); }
}
rb.println("");
}
//Sets the status variable for TunerStudio
// Sets the status variable for TunerStudio
void setTS_SD_status()
{
if( SD_status == SD_STATUS_ERROR_NO_CARD ) { BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_PRESENT); } // CARD is not present
else { BIT_SET(currentStatus.TS_SD_Status, SD_STATUS_CARD_PRESENT); } // CARD present
if(SD_status == SD_STATUS_ERROR_NO_CARD) { BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_PRESENT); } // CARD is not present
else { BIT_SET(currentStatus.TS_SD_Status, SD_STATUS_CARD_PRESENT); } // CARD present
BIT_SET(currentStatus.TS_SD_Status, SD_STATUS_CARD_TYPE); // CARD is SDHC
BIT_SET(currentStatus.TS_SD_Status, SD_STATUS_CARD_READY); // CARD is ready
if( SD_status == SD_STATUS_ACTIVE ) { BIT_SET(currentStatus.TS_SD_Status, SD_STATUS_CARD_LOGGING); }// CARD is logging
else { BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_LOGGING); }// CARD is not logging
if( (SD_status >= SD_STATUS_ERROR_NO_FS) ) { BIT_SET(currentStatus.TS_SD_Status, SD_STATUS_CARD_ERROR); }// CARD has an error
else { BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_ERROR); }// CARD has no error
if(SD_status == SD_STATUS_ACTIVE) { BIT_SET(currentStatus.TS_SD_Status, SD_STATUS_CARD_LOGGING); } // CARD is logging
else { BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_LOGGING); } // CARD is not logging
BIT_SET(currentStatus.TS_SD_Status, SD_STATUS_CARD_FS); // CARD has a FAT32 filesystem (Though this will be exFAT)
BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_UNUSED); //Unused bit is always 0
if((SD_status >= SD_STATUS_ERROR_NO_FS)) { BIT_SET(currentStatus.TS_SD_Status, SD_STATUS_CARD_ERROR); } // CARD has an error
else { BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_ERROR); } // CARD has no error
BIT_SET(currentStatus.TS_SD_Status, SD_STATUS_CARD_FS); // CARD has a FAT32 filesystem (Though this will be exFAT)
BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_UNUSED); // Unused bit is always 0
}
/**
/**
* Checks whether the SD logging should be started based on the logging trigger conditions
*/
void checkForSDStart()
{
//Logging can only start if we're in the ready state
//We must check the SD_status each time to prevent trying to init a new log file multiple times
// Logging can only start if we're in the ready state
// We must check the SD_status each time to prevent trying to init a new log file multiple times
if(configPage13.onboard_log_file_style > 0)
{
//Check for enable at boot
if( (configPage13.onboard_log_trigger_boot) && (SD_status == SD_STATUS_READY) )
// Check for enable at boot
if((configPage13.onboard_log_trigger_boot) && (SD_status == SD_STATUS_READY))
{
//Check that we're not already finished the logging
// Check that we're not already finished the logging
if((millis() / 1000) <= configPage13.onboard_log_tr1_duration)
{
beginSDLogging(); //Setup the log file, preallocation, header row
}
}
//Check for RPM based Enable
if( (configPage13.onboard_log_trigger_RPM) && (SD_status == SD_STATUS_READY) )
{
if( (currentStatus.RPMdiv100 >= configPage13.onboard_log_tr2_thr_on) && (currentStatus.RPMdiv100 <= configPage13.onboard_log_tr2_thr_off) ) //Need to check both on and off conditions to prevent logging starting and stopping continually
{
beginSDLogging(); //Setup the log file, preallocation, header row
beginSDLogging(); // Setup the log file, preallocation, header row
}
}
//Check for engine protection based enable
if((configPage13.onboard_log_trigger_prot) && (SD_status == SD_STATUS_READY) )
// Check for RPM based Enable
if((configPage13.onboard_log_trigger_RPM) && (SD_status == SD_STATUS_READY))
{
if((currentStatus.RPMdiv100 >= configPage13.onboard_log_tr2_thr_on) && (currentStatus.RPMdiv100 <= configPage13.onboard_log_tr2_thr_off)) // Need to check both on and off conditions to prevent logging starting and stopping continually
{
beginSDLogging(); // Setup the log file, preallocation, header row
}
}
// Check for engine protection based enable
if((configPage13.onboard_log_trigger_prot) && (SD_status == SD_STATUS_READY))
{
if(currentStatus.engineProtectStatus > 0)
{
beginSDLogging(); //Setup the log file, preallocation, header row
beginSDLogging(); // Setup the log file, preallocation, header row
}
}
if( (configPage13.onboard_log_trigger_Vbat) && (SD_status == SD_STATUS_READY) )
{
if((configPage13.onboard_log_trigger_Vbat) && (SD_status == SD_STATUS_READY)) {}
}
if((configPage13.onboard_log_trigger_Epin) && (SD_status == SD_STATUS_READY) )
if((configPage13.onboard_log_trigger_Epin) && (SD_status == SD_STATUS_READY))
{
if(digitalRead(pinSDEnable) == LOW)
{
beginSDLogging(); //Setup the log file, preallocation, header row
beginSDLogging(); // Setup the log file, preallocation, header row
}
}
}
}
/**
/**
* Checks whether the SD logging should be stopped, based on the logging trigger conditions
*/
void checkForSDStop()
{
//Check the various conditions to see if we should stop logging
// Check the various conditions to see if we should stop logging
bool log_boot = false;
bool log_RPM = false;
bool log_RPM = false;
bool log_prot = false;
bool log_Vbat = false;
bool log_Epin = false;
//Logging only needs to be stopped if already active
// Logging only needs to be stopped if already active
if(SD_status == SD_STATUS_ACTIVE)
{
//Check for enable at boot
// Check for enable at boot
if(configPage13.onboard_log_trigger_boot)
{
//Check if we're past the logging duration
if((millis() / 1000) <= configPage13.onboard_log_tr1_duration)
{
log_boot = true;
}
// Check if we're past the logging duration
if((millis() / 1000) <= configPage13.onboard_log_tr1_duration) { log_boot = true; }
}
if(configPage13.onboard_log_trigger_RPM)
{
if( (currentStatus.RPMdiv100 >= configPage13.onboard_log_tr2_thr_on) && (currentStatus.RPMdiv100 <= configPage13.onboard_log_tr2_thr_off) )
{
log_RPM = true;
}
if((currentStatus.RPMdiv100 >= configPage13.onboard_log_tr2_thr_on) && (currentStatus.RPMdiv100 <= configPage13.onboard_log_tr2_thr_off)) { log_RPM = true; }
}
if(configPage13.onboard_log_trigger_prot)
{
if(currentStatus.engineProtectStatus > 0)
{
log_prot = true;
}
if(currentStatus.engineProtectStatus > 0) { log_prot = true; }
}
if(configPage13.onboard_log_trigger_Vbat)
{
if(configPage13.onboard_log_trigger_Vbat) {}
}
//External Pin
// External Pin
if(configPage13.onboard_log_trigger_Epin)
{
if(digitalRead(pinSDEnable) == LOW)
{
log_Epin = true;
}
if(digitalRead(pinSDEnable) == LOW) { log_Epin = true; }
}
//Check all conditions to see if we should stop logging
if( (log_boot == false) && (log_RPM == false) && (log_prot == false) && (log_Vbat == false) && (log_Epin == false) && (manualLogActive == false) )
{
endSDLogging();
}
//ALso check whether logging has been disabled entirely
// Check all conditions to see if we should stop logging
if((log_boot == false) && (log_RPM == false) && (log_prot == false) && (log_Vbat == false) && (log_Epin == false) && (manualLogActive == false)) { endSDLogging(); }
// ALso check whether logging has been disabled entirely
if(configPage13.onboard_log_file_style == 0) { endSDLogging(); }
}
}
void syncSDLog()
{
if( (SD_status == SD_STATUS_ACTIVE) && (!logFile.isBusy()) && (!sd.isBusy()) )
{
logFile.sync();
}
{
if((SD_status == SD_STATUS_ACTIVE) && (!logFile.isBusy()) && (!sd.isBusy())) { logFile.sync(); }
}
/**
* Will perform a complete format of the SD card to ExFAT.
/**
* Will perform a complete format of the SD card to ExFAT.
* This will delete all files and create a new empty file system.
* The SD status will be set to busy when this happens to prevent any other operations
*/
@ -470,19 +434,16 @@ void formatExFat()
{
bool result = false;
//Set the SD status to busy
// Set the SD status to busy
BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_READY);
logFile.close();
if (sd.cardBegin(SD_CONFIG))
if(sd.cardBegin(SD_CONFIG))
{
if(sd.format())
if(sd.format())
{
if (sd.volumeBegin())
{
result = true;
}
if(sd.volumeBegin()) { result = true; }
}
}
@ -492,13 +453,13 @@ void formatExFat()
/**
* @brief Deletes a log file from the SD card
*
*
* Log files all have the same name with a 4 digit number at the end (Eg SPD_0001.csv). TS sends the 4 digits as ASCII characters and they are combined here with the logfile prefix
*
* @param log1
* @param log2
* @param log3
* @param log4
*
* @param log1
* @param log2
* @param log3
* @param log4
*/
void deleteLogFile(char log1, char log2, char log3, char log4)
{
@ -510,31 +471,26 @@ void deleteLogFile(char log1, char log2, char log3, char log4)
logFileName[7] = log4;
logFileName[8] = '.';
strcpy(logFileName + 9, LOG_FILE_EXTENSION);
//logFileName[8] = '\0';
// logFileName[8] = '\0';
if(sd.exists(logFileName))
{
sd.remove(logFileName);
}
if(sd.exists(logFileName)) { sd.remove(logFileName); }
}
// Call back for file timestamps. Only called for file create and sync().
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
void dateTime(uint16_t *date, uint16_t *time, uint8_t *ms10)
{
// Return date using FS_DATE macro to format fields.
//*date = FS_DATE(year(), month(), day());
*date = FS_DATE(rtc_getYear(), rtc_getMonth(), rtc_getDay());
// Return time using FS_TIME macro to format fields.
*time = FS_TIME(rtc_getHour(), rtc_getMinute(), rtc_getSecond());
// Return low time bits in units of 10 ms.
*ms10 = rtc_getSecond() & 1 ? 100 : 0;
}
uint32_t sectorCount()
{
return sd.card()->sectorCount();
}
uint32_t sectorCount() { return sd.card()->sectorCount(); }
#endif

View File

@ -15,25 +15,18 @@
#include "acc_mc33810.h"
#endif
static bool commandRequiresStoppedEngine(uint16_t buttonCommand)
{
return ((buttonCommand >= TS_CMD_INJ1_ON) && (buttonCommand <= TS_CMD_IGN8_50PC))
|| ((buttonCommand == TS_CMD_TEST_ENBL) || (buttonCommand == TS_CMD_TEST_DSBL));
}
static bool commandRequiresStoppedEngine(uint16_t buttonCommand) { return ((buttonCommand >= TS_CMD_INJ1_ON) && (buttonCommand <= TS_CMD_IGN8_50PC)) || ((buttonCommand == TS_CMD_TEST_ENBL) || (buttonCommand == TS_CMD_TEST_DSBL)); }
/**
* @brief
*
* @brief
*
* @param buttonCommand The command number of the button that was clicked. See TS_CommendButtonHandler.h for a list of button IDs
*/
bool TS_CommandButtonsHandler(uint16_t buttonCommand)
{
if (commandRequiresStoppedEngine(buttonCommand) && currentStatus.RPM != 0)
{
return false;
}
switch (buttonCommand)
if(commandRequiresStoppedEngine(buttonCommand) && currentStatus.RPM != 0) { return false; }
switch(buttonCommand)
{
case TS_CMD_TEST_DSBL: // cmd is stop
BIT_CLEAR(currentStatus.testOutputs, 1);
@ -41,36 +34,35 @@ bool TS_CommandButtonsHandler(uint16_t buttonCommand)
endCoil2Charge();
endCoil3Charge();
endCoil4Charge();
#if IGN_CHANNELS >= 5
#if IGN_CHANNELS >= 5
endCoil5Charge();
#endif
#if IGN_CHANNELS >= 6
#endif
#if IGN_CHANNELS >= 6
endCoil6Charge();
#endif
#if IGN_CHANNELS >= 7
#endif
#if IGN_CHANNELS >= 7
endCoil7Charge();
#endif
#if IGN_CHANNELS >= 8
#endif
#if IGN_CHANNELS >= 8
endCoil8Charge();
#endif
#endif
closeInjector1();
closeInjector2();
closeInjector3();
closeInjector4();
#if INJ_CHANNELS >= 5
#if INJ_CHANNELS >= 5
closeInjector5();
#endif
#if INJ_CHANNELS >= 6
#endif
#if INJ_CHANNELS >= 6
closeInjector6();
#endif
#if INJ_CHANNELS >= 7
#endif
#if INJ_CHANNELS >= 7
closeInjector7();
#endif
#if INJ_CHANNELS >= 8
#endif
#if INJ_CHANNELS >= 8
closeInjector8();
#endif
#endif
HWTest_INJ_50pc = 0;
HWTest_IGN_50pc = 0;
@ -82,244 +74,307 @@ bool TS_CommandButtonsHandler(uint16_t buttonCommand)
break;
case TS_CMD_INJ1_ON: // cmd group is for injector1 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ openInjector1(); }
if(BIT_CHECK(currentStatus.testOutputs, 1)) { openInjector1(); }
break;
case TS_CMD_INJ1_OFF: // cmd group is for injector1 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ closeInjector1(); BIT_CLEAR(HWTest_INJ_50pc, INJ1_CMD_BIT); }
break;
case TS_CMD_INJ1_50PC: // cmd group is for injector1 50% dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_INJ_50pc, INJ1_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ1_CMD_BIT)) { closeInjector1(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ2_ON: // cmd group is for injector2 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ openInjector2(); }
break;
case TS_CMD_INJ2_OFF: // cmd group is for injector2 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ closeInjector2(); BIT_CLEAR(HWTest_INJ_50pc, INJ2_CMD_BIT); }
break;
case TS_CMD_INJ2_50PC: // cmd group is for injector2 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_INJ_50pc, INJ2_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ2_CMD_BIT)) { closeInjector2(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ3_ON: // cmd group is for injector3 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ openInjector3(); }
break;
case TS_CMD_INJ3_OFF: // cmd group is for injector3 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ closeInjector3(); BIT_CLEAR(HWTest_INJ_50pc, INJ3_CMD_BIT); }
break;
case TS_CMD_INJ3_50PC: // cmd group is for injector3 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_INJ_50pc, INJ3_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ3_CMD_BIT)) { closeInjector3(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ4_ON: // cmd group is for injector4 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ openInjector4(); }
break;
case TS_CMD_INJ4_OFF: // cmd group is for injector4 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ closeInjector4(); BIT_CLEAR(HWTest_INJ_50pc, INJ4_CMD_BIT); }
break;
case TS_CMD_INJ4_50PC: // cmd group is for injector4 50% dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_INJ_50pc, INJ4_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ4_CMD_BIT)) { closeInjector4(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ5_ON: // cmd group is for injector5 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ openInjector5(); }
break;
case TS_CMD_INJ5_OFF: // cmd group is for injector5 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ closeInjector5(); BIT_CLEAR(HWTest_INJ_50pc, INJ5_CMD_BIT); }
break;
case TS_CMD_INJ5_50PC: // cmd group is for injector5 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_INJ_50pc, INJ5_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ5_CMD_BIT)) { closeInjector5(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ6_ON: // cmd group is for injector6 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ openInjector6(); }
break;
case TS_CMD_INJ6_OFF: // cmd group is for injector6 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ closeInjector6(); BIT_CLEAR(HWTest_INJ_50pc, INJ6_CMD_BIT); }
break;
case TS_CMD_INJ6_50PC: // cmd group is for injector6 50% dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_INJ_50pc, INJ6_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ6_CMD_BIT)) { closeInjector6(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ7_ON: // cmd group is for injector7 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ openInjector7(); }
break;
case TS_CMD_INJ7_OFF: // cmd group is for injector7 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ closeInjector7(); BIT_CLEAR(HWTest_INJ_50pc, INJ7_CMD_BIT); }
break;
case TS_CMD_INJ7_50PC: // cmd group is for injector7 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_INJ_50pc, INJ7_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ7_CMD_BIT)) { closeInjector7(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ8_ON: // cmd group is for injector8 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ openInjector8(); }
break;
case TS_CMD_INJ8_OFF: // cmd group is for injector8 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ closeInjector8(); BIT_CLEAR(HWTest_INJ_50pc, INJ8_CMD_BIT); }
break;
case TS_CMD_INJ8_50PC: // cmd group is for injector8 50% dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_INJ_50pc, INJ8_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ8_CMD_BIT)) { closeInjector8(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN1_ON: // cmd group is for spark1 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ){ beginCoil1Charge(); }
break;
case TS_CMD_IGN1_OFF: // cmd group is for spark1 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { endCoil1Charge(); BIT_CLEAR(HWTest_IGN_50pc, IGN1_CMD_BIT); }
break;
case TS_CMD_IGN1_50PC: // cmd group is for spark1 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_IGN_50pc, IGN1_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN1_CMD_BIT)) { endCoil1Charge(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN2_ON: // cmd group is for spark2 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { beginCoil2Charge(); }
break;
case TS_CMD_IGN2_OFF: // cmd group is for spark2 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { endCoil2Charge(); BIT_CLEAR(HWTest_IGN_50pc, IGN2_CMD_BIT); }
break;
case TS_CMD_IGN2_50PC: // cmd group is for spark2 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_IGN_50pc, IGN2_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN2_CMD_BIT)) { endCoil2Charge(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN3_ON: // cmd group is for spark3 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { beginCoil3Charge(); }
break;
case TS_CMD_IGN3_OFF: // cmd group is for spark3 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { endCoil3Charge(); BIT_CLEAR(HWTest_IGN_50pc, IGN3_CMD_BIT); }
break;
case TS_CMD_IGN3_50PC: // cmd group is for spark3 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_IGN_50pc, IGN3_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN3_CMD_BIT)) { endCoil3Charge(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN4_ON: // cmd group is for spark4 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { beginCoil4Charge(); }
break;
case TS_CMD_IGN4_OFF: // cmd group is for spark4 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { endCoil4Charge(); BIT_CLEAR(HWTest_IGN_50pc, IGN4_CMD_BIT); }
break;
case TS_CMD_IGN4_50PC: // cmd group is for spark4 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_IGN_50pc, IGN4_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN4_CMD_BIT)) { endCoil4Charge(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN5_ON: // cmd group is for spark5 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { beginCoil5Charge(); }
break;
case TS_CMD_IGN5_OFF: // cmd group is for spark5 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { endCoil5Charge(); BIT_CLEAR(HWTest_IGN_50pc, IGN5_CMD_BIT); }
break;
case TS_CMD_IGN5_50PC: // cmd group is for spark4 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_IGN_50pc, IGN5_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN5_CMD_BIT)) { endCoil5Charge(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN6_ON: // cmd group is for spark6 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { beginCoil6Charge(); }
break;
case TS_CMD_IGN6_OFF: // cmd group is for spark6 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { endCoil6Charge(); BIT_CLEAR(HWTest_IGN_50pc, IGN6_CMD_BIT); }
break;
case TS_CMD_IGN6_50PC: // cmd group is for spark6 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_IGN_50pc, IGN6_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN6_CMD_BIT)) { endCoil6Charge(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN7_ON: // cmd group is for spark7 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { beginCoil7Charge(); }
break;
case TS_CMD_IGN7_OFF: // cmd group is for spark7 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { endCoil7Charge(); BIT_CLEAR(HWTest_IGN_50pc, IGN7_CMD_BIT); }
break;
case TS_CMD_IGN7_50PC: // cmd group is for spark7 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_IGN_50pc, IGN7_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN7_CMD_BIT)) { endCoil7Charge(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN8_ON: // cmd group is for spark8 on actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { beginCoil8Charge(); }
break;
case TS_CMD_IGN8_OFF: // cmd group is for spark8 off actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { endCoil8Charge(); BIT_CLEAR(HWTest_IGN_50pc, IGN8_CMD_BIT); }
break;
case TS_CMD_IGN8_50PC: // cmd group is for spark8 50%dc actions
if( BIT_CHECK(currentStatus.testOutputs, 1) ) { BIT_TOGGLE(HWTest_IGN_50pc, IGN8_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN8_CMD_BIT)) { endCoil8Charge(); } //Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
//VSS Calibration routines
case TS_CMD_VSS_60KMH:
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
if(configPage2.vssMode == 1)
{
//Calculate the ratio of VSS reading from Aux input and actual VSS (assuming that actual VSS is really 60km/h).
configPage2.vssPulsesPerKm = (currentStatus.canin[configPage2.vssAuxCh] / 60);
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); //Set the flag to trigger the UI reset
}
else
{
//Calibrate the actual pulses per distance
uint32_t calibrationGap = vssGetPulseGap(0);
if( calibrationGap > 0 )
{
configPage2.vssPulsesPerKm = 60000000UL / calibrationGap;
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); //Set the flag to trigger the UI reset
}
}
closeInjector1();
BIT_CLEAR(HWTest_INJ_50pc, INJ1_CMD_BIT);
}
break;
//Calculate the RPM to speed ratio for each gear
case TS_CMD_INJ1_50PC: // cmd group is for injector1 50% dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_INJ_50pc, INJ1_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ1_CMD_BIT)) { closeInjector1(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ2_ON: // cmd group is for injector2 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { openInjector2(); }
break;
case TS_CMD_INJ2_OFF: // cmd group is for injector2 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
closeInjector2();
BIT_CLEAR(HWTest_INJ_50pc, INJ2_CMD_BIT);
}
break;
case TS_CMD_INJ2_50PC: // cmd group is for injector2 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_INJ_50pc, INJ2_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ2_CMD_BIT)) { closeInjector2(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ3_ON: // cmd group is for injector3 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { openInjector3(); }
break;
case TS_CMD_INJ3_OFF: // cmd group is for injector3 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
closeInjector3();
BIT_CLEAR(HWTest_INJ_50pc, INJ3_CMD_BIT);
}
break;
case TS_CMD_INJ3_50PC: // cmd group is for injector3 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_INJ_50pc, INJ3_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ3_CMD_BIT)) { closeInjector3(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ4_ON: // cmd group is for injector4 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { openInjector4(); }
break;
case TS_CMD_INJ4_OFF: // cmd group is for injector4 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
closeInjector4();
BIT_CLEAR(HWTest_INJ_50pc, INJ4_CMD_BIT);
}
break;
case TS_CMD_INJ4_50PC: // cmd group is for injector4 50% dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_INJ_50pc, INJ4_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ4_CMD_BIT)) { closeInjector4(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ5_ON: // cmd group is for injector5 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { openInjector5(); }
break;
case TS_CMD_INJ5_OFF: // cmd group is for injector5 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
closeInjector5();
BIT_CLEAR(HWTest_INJ_50pc, INJ5_CMD_BIT);
}
break;
case TS_CMD_INJ5_50PC: // cmd group is for injector5 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_INJ_50pc, INJ5_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ5_CMD_BIT)) { closeInjector5(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ6_ON: // cmd group is for injector6 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { openInjector6(); }
break;
case TS_CMD_INJ6_OFF: // cmd group is for injector6 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
closeInjector6();
BIT_CLEAR(HWTest_INJ_50pc, INJ6_CMD_BIT);
}
break;
case TS_CMD_INJ6_50PC: // cmd group is for injector6 50% dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_INJ_50pc, INJ6_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ6_CMD_BIT)) { closeInjector6(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ7_ON: // cmd group is for injector7 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { openInjector7(); }
break;
case TS_CMD_INJ7_OFF: // cmd group is for injector7 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
closeInjector7();
BIT_CLEAR(HWTest_INJ_50pc, INJ7_CMD_BIT);
}
break;
case TS_CMD_INJ7_50PC: // cmd group is for injector7 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_INJ_50pc, INJ7_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ7_CMD_BIT)) { closeInjector7(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_INJ8_ON: // cmd group is for injector8 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { openInjector8(); }
break;
case TS_CMD_INJ8_OFF: // cmd group is for injector8 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
closeInjector8();
BIT_CLEAR(HWTest_INJ_50pc, INJ8_CMD_BIT);
}
break;
case TS_CMD_INJ8_50PC: // cmd group is for injector8 50% dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_INJ_50pc, INJ8_CMD_BIT); }
if(!BIT_CHECK(HWTest_INJ_50pc, INJ8_CMD_BIT)) { closeInjector8(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN1_ON: // cmd group is for spark1 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { beginCoil1Charge(); }
break;
case TS_CMD_IGN1_OFF: // cmd group is for spark1 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
endCoil1Charge();
BIT_CLEAR(HWTest_IGN_50pc, IGN1_CMD_BIT);
}
break;
case TS_CMD_IGN1_50PC: // cmd group is for spark1 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_IGN_50pc, IGN1_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN1_CMD_BIT)) { endCoil1Charge(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN2_ON: // cmd group is for spark2 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { beginCoil2Charge(); }
break;
case TS_CMD_IGN2_OFF: // cmd group is for spark2 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
endCoil2Charge();
BIT_CLEAR(HWTest_IGN_50pc, IGN2_CMD_BIT);
}
break;
case TS_CMD_IGN2_50PC: // cmd group is for spark2 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_IGN_50pc, IGN2_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN2_CMD_BIT)) { endCoil2Charge(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN3_ON: // cmd group is for spark3 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { beginCoil3Charge(); }
break;
case TS_CMD_IGN3_OFF: // cmd group is for spark3 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
endCoil3Charge();
BIT_CLEAR(HWTest_IGN_50pc, IGN3_CMD_BIT);
}
break;
case TS_CMD_IGN3_50PC: // cmd group is for spark3 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_IGN_50pc, IGN3_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN3_CMD_BIT)) { endCoil3Charge(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN4_ON: // cmd group is for spark4 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { beginCoil4Charge(); }
break;
case TS_CMD_IGN4_OFF: // cmd group is for spark4 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
endCoil4Charge();
BIT_CLEAR(HWTest_IGN_50pc, IGN4_CMD_BIT);
}
break;
case TS_CMD_IGN4_50PC: // cmd group is for spark4 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_IGN_50pc, IGN4_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN4_CMD_BIT)) { endCoil4Charge(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN5_ON: // cmd group is for spark5 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { beginCoil5Charge(); }
break;
case TS_CMD_IGN5_OFF: // cmd group is for spark5 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
endCoil5Charge();
BIT_CLEAR(HWTest_IGN_50pc, IGN5_CMD_BIT);
}
break;
case TS_CMD_IGN5_50PC: // cmd group is for spark4 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_IGN_50pc, IGN5_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN5_CMD_BIT)) { endCoil5Charge(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN6_ON: // cmd group is for spark6 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { beginCoil6Charge(); }
break;
case TS_CMD_IGN6_OFF: // cmd group is for spark6 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
endCoil6Charge();
BIT_CLEAR(HWTest_IGN_50pc, IGN6_CMD_BIT);
}
break;
case TS_CMD_IGN6_50PC: // cmd group is for spark6 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_IGN_50pc, IGN6_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN6_CMD_BIT)) { endCoil6Charge(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN7_ON: // cmd group is for spark7 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { beginCoil7Charge(); }
break;
case TS_CMD_IGN7_OFF: // cmd group is for spark7 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
endCoil7Charge();
BIT_CLEAR(HWTest_IGN_50pc, IGN7_CMD_BIT);
}
break;
case TS_CMD_IGN7_50PC: // cmd group is for spark7 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_IGN_50pc, IGN7_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN7_CMD_BIT)) { endCoil7Charge(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
case TS_CMD_IGN8_ON: // cmd group is for spark8 on actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { beginCoil8Charge(); }
break;
case TS_CMD_IGN8_OFF: // cmd group is for spark8 off actions
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
endCoil8Charge();
BIT_CLEAR(HWTest_IGN_50pc, IGN8_CMD_BIT);
}
break;
case TS_CMD_IGN8_50PC: // cmd group is for spark8 50%dc actions
if(BIT_CHECK(currentStatus.testOutputs, 1)) { BIT_TOGGLE(HWTest_IGN_50pc, IGN8_CMD_BIT); }
if(!BIT_CHECK(HWTest_IGN_50pc, IGN8_CMD_BIT)) { endCoil8Charge(); } // Ensure this output is turned off (Otherwise the output may stay on permanently)
break;
// VSS Calibration routines
case TS_CMD_VSS_60KMH: {
if(configPage2.vssMode == 1)
{
// Calculate the ratio of VSS reading from Aux input and actual VSS (assuming that actual VSS is really 60km/h).
configPage2.vssPulsesPerKm = (currentStatus.canin[configPage2.vssAuxCh] / 60);
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); // Set the flag to trigger the UI reset
}
else
{
// Calibrate the actual pulses per distance
uint32_t calibrationGap = vssGetPulseGap(0);
if(calibrationGap > 0)
{
configPage2.vssPulsesPerKm = 60000000UL / calibrationGap;
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); // Set the flag to trigger the UI reset
}
}
}
break;
// Calculate the RPM to speed ratio for each gear
case TS_CMD_VSS_RATIO1:
if(currentStatus.vss > 0)
{
configPage2.vssRatio1 = (currentStatus.vss * 10000UL) / currentStatus.RPM;
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); //Set the flag to trigger the UI reset
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); // Set the flag to trigger the UI reset
}
break;
@ -327,8 +382,8 @@ bool TS_CommandButtonsHandler(uint16_t buttonCommand)
if(currentStatus.vss > 0)
{
configPage2.vssRatio2 = (currentStatus.vss * 10000UL) / currentStatus.RPM;
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); //Set the flag to trigger the UI reset
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); // Set the flag to trigger the UI reset
}
break;
@ -336,17 +391,17 @@ bool TS_CommandButtonsHandler(uint16_t buttonCommand)
if(currentStatus.vss > 0)
{
configPage2.vssRatio3 = (currentStatus.vss * 10000UL) / currentStatus.RPM;
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); //Set the flag to trigger the UI reset
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); // Set the flag to trigger the UI reset
}
break;
case TS_CMD_VSS_RATIO4:
case TS_CMD_VSS_RATIO4:
if(currentStatus.vss > 0)
{
configPage2.vssRatio4 = (currentStatus.vss * 10000UL) / currentStatus.RPM;
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); //Set the flag to trigger the UI reset
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); // Set the flag to trigger the UI reset
}
break;
@ -354,8 +409,8 @@ bool TS_CommandButtonsHandler(uint16_t buttonCommand)
if(currentStatus.vss > 0)
{
configPage2.vssRatio5 = (currentStatus.vss * 10000UL) / currentStatus.RPM;
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); //Set the flag to trigger the UI reset
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); // Set the flag to trigger the UI reset
}
break;
@ -363,12 +418,12 @@ bool TS_CommandButtonsHandler(uint16_t buttonCommand)
if(currentStatus.vss > 0)
{
configPage2.vssRatio6 = (currentStatus.vss * 10000UL) / currentStatus.RPM;
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); //Set the flag to trigger the UI reset
writeConfig(1); // Need to manually save the new config value as it will not trigger a burn in tunerStudio due to use of ControllerPriority
BIT_SET(currentStatus.status3, BIT_STATUS3_VSS_REFRESH); // Set the flag to trigger the UI reset
}
break;
//STM32 Commands
// STM32 Commands
case TS_CMD_STM32_REBOOT: //
doSystemReset();
break;
@ -378,14 +433,12 @@ bool TS_CommandButtonsHandler(uint16_t buttonCommand)
break;
#ifdef SD_LOGGING
case TS_CMD_SD_FORMAT: //Format SD card
case TS_CMD_SD_FORMAT: // Format SD card
formatExFat();
break;
#endif
default:
return false;
break;
default: return false; break;
}
return true;

View File

@ -4,34 +4,33 @@
void initMC33810(void)
{
//Set the output states of both ICs to be off to fuel and ignition
mc33810_1_requestedState = 0;
mc33810_2_requestedState = 0;
mc33810_1_returnState = 0;
mc33810_2_returnState = 0;
// Set the output states of both ICs to be off to fuel and ignition
mc33810_1_requestedState = 0;
mc33810_2_requestedState = 0;
mc33810_1_returnState = 0;
mc33810_2_returnState = 0;
pinMode(pinMC33810_1_CS, OUTPUT);
pinMode(pinMC33810_2_CS, OUTPUT);
pinMode(pinMC33810_1_CS, OUTPUT);
pinMode(pinMC33810_2_CS, OUTPUT);
SPI.begin();
//These are the SPI settings per the datasheet
SPI.beginTransaction(SPISettings(6000000, MSBFIRST, SPI_MODE0));
SPI.begin();
// These are the SPI settings per the datasheet
SPI.beginTransaction(SPISettings(6000000, MSBFIRST, SPI_MODE0));
//Set the ignition outputs to GPGD mode
/*
0001 = Mode select command
1111 = Set all 1 GD[0...3] outputs to use GPGD mode
00000000 = All remaining values are unused (For us)
*/
//uint16_t cmd = 0b000111110000;
uint16_t cmd = 0b0001111100000000;
//IC1
MC33810_1_ACTIVE();
SPI.transfer16(cmd);
MC33810_1_INACTIVE();
//IC2
MC33810_2_ACTIVE();
SPI.transfer16(cmd);
MC33810_2_INACTIVE();
// Set the ignition outputs to GPGD mode
/*
0001 = Mode select command
1111 = Set all 1 GD[0...3] outputs to use GPGD mode
00000000 = All remaining values are unused (For us)
*/
// uint16_t cmd = 0b000111110000;
uint16_t cmd = 0b0001111100000000;
// IC1
MC33810_1_ACTIVE();
SPI.transfer16(cmd);
MC33810_1_INACTIVE();
// IC2
MC33810_2_ACTIVE();
SPI.transfer16(cmd);
MC33810_2_INACTIVE();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,92 +1,91 @@
#if defined(CORE_AVR)
#include "globals.h"
#include "auxiliaries.h"
#include "globals.h"
#include "auxiliaries.h"
// Prescaler values for timers 1-3-4-5. Refer to www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
#define TIMER_PRESCALER_OFF ((0<<CS12)|(0<<CS11)|(0<<CS10))
#define TIMER_PRESCALER_1 ((0<<CS12)|(0<<CS11)|(1<<CS10))
#define TIMER_PRESCALER_8 ((0<<CS12)|(1<<CS11)|(0<<CS10))
#define TIMER_PRESCALER_64 ((0<<CS12)|(1<<CS11)|(1<<CS10))
#define TIMER_PRESCALER_256 ((1<<CS12)|(0<<CS11)|(0<<CS10))
#define TIMER_PRESCALER_1024 ((1<<CS12)|(0<<CS11)|(1<<CS10))
// Prescaler values for timers 1-3-4-5. Refer to www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
#define TIMER_PRESCALER_OFF ((0 << CS12) | (0 << CS11) | (0 << CS10))
#define TIMER_PRESCALER_1 ((0 << CS12) | (0 << CS11) | (1 << CS10))
#define TIMER_PRESCALER_8 ((0 << CS12) | (1 << CS11) | (0 << CS10))
#define TIMER_PRESCALER_64 ((0 << CS12) | (1 << CS11) | (1 << CS10))
#define TIMER_PRESCALER_256 ((1 << CS12) | (0 << CS11) | (0 << CS10))
#define TIMER_PRESCALER_1024 ((1 << CS12) | (0 << CS11) | (1 << CS10))
#define TIMER_MODE_NORMAL ((0<<WGM01)|(0<<WGM00))
#define TIMER_MODE_PWM ((0<<WGM01)|(1<<WGM00))
#define TIMER_MODE_CTC ((1<<WGM01)|(0<<WGM00))
#define TIMER_MODE_FASTPWM ((1<<WGM01)|(1<<WGM00))
#define TIMER_MODE_NORMAL ((0 << WGM01) | (0 << WGM00))
#define TIMER_MODE_PWM ((0 << WGM01) | (1 << WGM00))
#define TIMER_MODE_CTC ((1 << WGM01) | (0 << WGM00))
#define TIMER_MODE_FASTPWM ((1 << WGM01) | (1 << WGM00))
void initBoard(void)
{
/*
***********************************************************************************************************
* General
*/
configPage9.intcan_available = 0; // AVR devices do NOT have internal canbus
/*
***********************************************************************************************************
* General
*/
configPage9.intcan_available = 0; // AVR devices do NOT have internal canbus
/*
***********************************************************************************************************
* Auxiliaries
*/
//PWM used by the Boost and VVT outputs. C Channel is used by ign5
TCCR1B = TIMER_PRESCALER_OFF; //Disable Timer1 while we set it up
TCNT1 = 0; //Reset Timer Count
TCCR1A = TIMER_MODE_NORMAL; //Timer1 Control Reg A: Wave Gen Mode normal (Simply counts up from 0 to 65535 (16-bit int)
TCCR1B = TIMER_PRESCALER_256; //Timer1 Control Reg B: Timer Prescaler set to 256. 1 tick = 16uS.
TIFR1 = (1 << OCF1A) | (1<<OCF1B) | (1<<OCF1C) | (1<<TOV1) | (1<<ICF1); //Clear the compare flags, overflow flag and external input flag bits
/*
***********************************************************************************************************
* Auxiliaries
*/
// PWM used by the Boost and VVT outputs. C Channel is used by ign5
TCCR1B = TIMER_PRESCALER_OFF; // Disable Timer1 while we set it up
TCNT1 = 0; // Reset Timer Count
TCCR1A = TIMER_MODE_NORMAL; // Timer1 Control Reg A: Wave Gen Mode normal (Simply counts up from 0 to 65535 (16-bit int)
TCCR1B = TIMER_PRESCALER_256; // Timer1 Control Reg B: Timer Prescaler set to 256. 1 tick = 16uS.
TIFR1 = (1 << OCF1A) | (1 << OCF1B) | (1 << OCF1C) | (1 << TOV1) | (1 << ICF1); // Clear the compare flags, overflow flag and external input flag bits
boost_pwm_max_count = 1000000L / (16 * configPage6.boostFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow frequencies up to 511Hz
vvt_pwm_max_count = 1000000L / (16 * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle
// put idle_pwm_max_count calculation here?
boost_pwm_max_count = 1000000L / (16 * configPage6.boostFreq * 2); // Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow frequencies up to 511Hz
vvt_pwm_max_count = 1000000L / (16 * configPage6.vvtFreq * 2); // Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle
// put idle_pwm_max_count calculation here?
/*
***********************************************************************************************************
* Timers
*/
//Configure Timer2 for our low-freq interrupt code.
TCCR2B = TIMER_PRESCALER_OFF; //Disable Timer2 while we set it up
TCNT2 = 131; //Preload timer2 with 131 cycles, leaving 125 till overflow. As the timer runs at 125Khz, this causes overflow to occur at 1Khz = 1ms
TIMSK2 = (1<<TOIE2); //Timer2 Set Overflow Interrupt enabled.
TCCR2A = TIMER_MODE_NORMAL; //Timer2 Control Reg A: Wave Gen Mode normal
/* Now configure the prescaler to CPU clock divided by 128 = 125Khz */
TCCR2B = (1<<CS22) | (1<<CS20); // Set bits. This timer uses different prescaler values, thus we cannot use the defines above.
TIFR2 = (1 << OCF2A) | (1<<OCF2B) | (1<<TOV2); //Clear the compare flag bits and overflow flag bit
/*
***********************************************************************************************************
* Timers
*/
// Configure Timer2 for our low-freq interrupt code.
TCCR2B = TIMER_PRESCALER_OFF; // Disable Timer2 while we set it up
TCNT2 = 131; // Preload timer2 with 131 cycles, leaving 125 till overflow. As the timer runs at 125Khz, this causes overflow to occur at 1Khz = 1ms
TIMSK2 = (1 << TOIE2); // Timer2 Set Overflow Interrupt enabled.
TCCR2A = TIMER_MODE_NORMAL; // Timer2 Control Reg A: Wave Gen Mode normal
/* Now configure the prescaler to CPU clock divided by 128 = 125Khz */
TCCR2B = (1 << CS22) | (1 << CS20); // Set bits. This timer uses different prescaler values, thus we cannot use the defines above.
TIFR2 = (1 << OCF2A) | (1 << OCF2B) | (1 << TOV2); // Clear the compare flag bits and overflow flag bit
//Enable the watchdog timer for 2 second resets (Good reference: www.tushev.org/articles/arduino/5/arduino-and-watchdog-timer)
//Boooooooooo WDT is currently broken on Mega 2560 bootloaders :(
//wdt_enable(WDTO_2S);
// Enable the watchdog timer for 2 second resets (Good reference: www.tushev.org/articles/arduino/5/arduino-and-watchdog-timer)
// Boooooooooo WDT is currently broken on Mega 2560 bootloaders :(
// wdt_enable(WDTO_2S);
/*
***********************************************************************************************************
* Schedules
* */
//Much help in this from www.arduinomega.blogspot.com.au/2011/05/timer2-and-overflow-interrupt-lets-get.html
//Fuel Schedules, which uses timer 3
TCCR3B = TIMER_PRESCALER_OFF; //Disable Timer3 while we set it up
TCNT3 = 0; //Reset Timer Count
TCCR3A = TIMER_MODE_NORMAL; //Timer3 Control Reg A: Wave Gen Mode normal
TCCR3B = TIMER_PRESCALER_64; //Timer3 Control Reg B: Timer Prescaler set to 64.
TIFR3 = (1 << OCF3A) | (1<<OCF3B) | (1<<OCF3C) | (1<<TOV3) | (1<<ICF3); //Clear the compare flags, overflow flag and external input flag bits
/*
***********************************************************************************************************
* Schedules
* */
// Much help in this from www.arduinomega.blogspot.com.au/2011/05/timer2-and-overflow-interrupt-lets-get.html
// Fuel Schedules, which uses timer 3
TCCR3B = TIMER_PRESCALER_OFF; // Disable Timer3 while we set it up
TCNT3 = 0; // Reset Timer Count
TCCR3A = TIMER_MODE_NORMAL; // Timer3 Control Reg A: Wave Gen Mode normal
TCCR3B = TIMER_PRESCALER_64; // Timer3 Control Reg B: Timer Prescaler set to 64.
TIFR3 = (1 << OCF3A) | (1 << OCF3B) | (1 << OCF3C) | (1 << TOV3) | (1 << ICF3); // Clear the compare flags, overflow flag and external input flag bits
//Ignition Schedules, which uses timer 5. This is also used by the fast version of micros(). If the speed of this timer is changed from 4uS ticks, that MUST be changed as well. See globals.h and timers.ino
TCCR5B = TIMER_PRESCALER_OFF; //Disable Timer5 while we set it up
TCNT5 = 0; //Reset Timer Count
TCCR5A = TIMER_MODE_NORMAL; //Timer5 Control Reg A: Wave Gen Mode normal
TCCR5B = TIMER_PRESCALER_64; //Timer5 Control Reg B: Timer Prescaler set to 64.
TIFR5 = (1 << OCF5A) | (1<<OCF5B) | (1<<OCF5C) | (1<<TOV5) | (1<<ICF5); //Clear the compare flags, overflow flag and external input flag bits
#if defined(TIMER5_MICROS)
TIMSK5 |= (1 << TOIE5); //Enable the timer5 overflow interrupt (See timers.ino for ISR)
TIMSK0 &= ~_BV(TOIE0); // disable timer0 overflow interrupt
#endif
// Ignition Schedules, which uses timer 5. This is also used by the fast version of micros(). If the speed of this timer is changed from 4uS ticks, that MUST be changed as well. See globals.h and timers.ino
TCCR5B = TIMER_PRESCALER_OFF; // Disable Timer5 while we set it up
TCNT5 = 0; // Reset Timer Count
TCCR5A = TIMER_MODE_NORMAL; // Timer5 Control Reg A: Wave Gen Mode normal
TCCR5B = TIMER_PRESCALER_64; // Timer5 Control Reg B: Timer Prescaler set to 64.
TIFR5 = (1 << OCF5A) | (1 << OCF5B) | (1 << OCF5C) | (1 << TOV5) | (1 << ICF5); // Clear the compare flags, overflow flag and external input flag bits
//The remaining Schedules (Fuel schedule 4 and ignition schedules 4 and 5) use Timer4
TCCR4B = TIMER_PRESCALER_OFF; //Disable Timer4 while we set it up
TCNT4 = 0; //Reset Timer Count
TCCR4A = TIMER_MODE_NORMAL; //Timer4 Control Reg A: Wave Gen Mode normal
TCCR4B = TIMER_PRESCALER_64; //Timer4 Control Reg B: Timer Prescaler set to 64.
TIFR4 = (1 << OCF4A) | (1<<OCF4B) | (1<<OCF4C) | (1<<TOV4) | (1<<ICF4); //Clear the compare flags, overflow flag and external input flag bits
#if defined(TIMER5_MICROS)
TIMSK5 |= (1 << TOIE5); // Enable the timer5 overflow interrupt (See timers.ino for ISR)
TIMSK0 &= ~_BV(TOIE0); // disable timer0 overflow interrupt
#endif
// The remaining Schedules (Fuel schedule 4 and ignition schedules 4 and 5) use Timer4
TCCR4B = TIMER_PRESCALER_OFF; // Disable Timer4 while we set it up
TCNT4 = 0; // Reset Timer Count
TCCR4A = TIMER_MODE_NORMAL; // Timer4 Control Reg A: Wave Gen Mode normal
TCCR4B = TIMER_PRESCALER_64; // Timer4 Control Reg B: Timer Prescaler set to 64.
TIFR4 = (1 << OCF4A) | (1 << OCF4B) | (1 << OCF4C) | (1 << TOV4) | (1 << ICF4); // Clear the compare flags, overflow flag and external input flag bits
}
/*
@ -95,27 +94,24 @@ void initBoard(void)
*/
uint16_t freeRam(void)
{
extern int __heap_start, *__brkval;
int currentVal;
uint16_t v;
extern int __heap_start, *__brkval;
int currentVal;
uint16_t v;
if(__brkval == 0) { currentVal = (int) &__heap_start; }
else { currentVal = (int) __brkval; }
if(__brkval == 0) { currentVal = (int)&__heap_start; }
else { currentVal = (int)__brkval; }
//Old version:
//return (uint16_t) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
/* cppcheck-suppress misra-c2012-11.4 ; DEVIATION(D3) */
return (uint16_t) &v - currentVal; //cppcheck-suppress misra-c2012-11.4
// Old version:
// return (uint16_t) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
/* cppcheck-suppress misra-c2012-11.4 ; DEVIATION(D3) */
return (uint16_t)&v - currentVal; // cppcheck-suppress misra-c2012-11.4
}
void doSystemReset(void) { return; }
void jumpToBootloader(void) { return; }
#if defined(TIMER5_MICROS)
//This is used by the fast version of micros(). We just need to increment the timer overflow counter
ISR(TIMER5_OVF_vect)
{
++timer5_overflow_count;
}
#if defined(TIMER5_MICROS)
// This is used by the fast version of micros(). We just need to increment the timer overflow counter
ISR(TIMER5_OVF_vect) { ++timer5_overflow_count; }
static inline unsigned long micros_safe(void)
{
@ -125,7 +121,7 @@ static inline unsigned long micros_safe(void)
interrupts();
return newMicros;
}
#endif //TIMER5_MICROS
}
#endif // TIMER5_MICROS
#endif //CORE_AVR
#endif // CORE_AVR

View File

@ -1,39 +1,36 @@
#if defined(CORE_SAME51)
#include "globals.h"
#include "auxiliaries.h"
#include "globals.h"
#include "auxiliaries.h"
void initBoard()
{
/*
***********************************************************************************************************
* General
*/
/*
***********************************************************************************************************
* General
*/
/*
***********************************************************************************************************
* Timers
*/
/*
***********************************************************************************************************
* Timers
*/
/*
***********************************************************************************************************
* Auxiliaries
*/
/*
***********************************************************************************************************
* Auxiliaries
*/
/*
***********************************************************************************************************
* Idle
*/
/*
***********************************************************************************************************
* Idle
*/
/*
***********************************************************************************************************
* Schedules
*/
/*
***********************************************************************************************************
* Schedules
*/
}
uint16_t freeRam()
{
return 0;
}
uint16_t freeRam() { return 0; }
void doSystemReset() { return; }
void jumpToBootloader() { return; }

View File

@ -1,205 +1,204 @@
#if defined(CORE_STM32_GENERIC)
#include "board_stm32_generic.h"
#include "globals.h"
#include "auxiliaries.h"
#include "idle.h"
#include "scheduler.h"
#include "HardwareTimer.h"
#include "board_stm32_generic.h"
#include "globals.h"
#include "auxiliaries.h"
#include "idle.h"
#include "scheduler.h"
#include "HardwareTimer.h"
#if defined(FRAM_AS_EEPROM)
#if defined(STM32F407xx)
FramClass EEPROM(PB5, PB4, PB3, PB0); /*(mosi, miso, sclk, ssel, clockspeed) 31/01/2020*/
FramClass EEPROM(PB5, PB4, PB3, PB0); /*(mosi, miso, sclk, ssel, clockspeed) 31/01/2020*/
#else
FramClass EEPROM(PB15, PB14, PB13, PB12); //Blue/Black Pills
FramClass EEPROM(PB15, PB14, PB13, PB12); // Blue/Black Pills
#endif
#endif
void initBoard()
{
/*
***********************************************************************************************************
* General
*/
#ifndef FLASH_LENGTH
#define FLASH_LENGTH 8192
#endif
delay(10);
/*
***********************************************************************************************************
* Idle
*/
if( (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL) )
{
idle_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 5KHz
}
/*
***********************************************************************************************************
* General
*/
#ifndef FLASH_LENGTH
#define FLASH_LENGTH 8192
#endif
delay(10);
/*
***********************************************************************************************************
* Idle
*/
if((configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL))
{
idle_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.idleFreq * 2); // Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 5KHz
}
//This must happen at the end of the idle init
Timer1.setMode(4, TIMER_OUTPUT_COMPARE);
Timer1.attachInterrupt(4, idleInterrupt); //on first flash the configPage4.iacAlgorithm is invalid
// This must happen at the end of the idle init
Timer1.setMode(4, TIMER_OUTPUT_COMPARE);
Timer1.attachInterrupt(4, idleInterrupt); // on first flash the configPage4.iacAlgorithm is invalid
/*
***********************************************************************************************************
* Timers
*/
#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_BLUEPILL_F103CB)
Timer4.setPeriod(1000); // Set up period
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(1, oneMSInterval);
Timer4.resume(); // Start Timer
#else
Timer11.setPeriod(1000); // Set up period
Timer11.setMode(1, TIMER_OUTPUT_COMPARE);
Timer11.attachInterrupt(1, oneMSInterval);
Timer11.resume(); // Start Timer
#endif
pinMode(LED_BUILTIN, OUTPUT); // Visual WDT
/*
***********************************************************************************************************
* Timers
*/
#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_BLUEPILL_F103CB)
Timer4.setPeriod(1000); // Set up period
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(1, oneMSInterval);
Timer4.resume(); //Start Timer
#else
Timer11.setPeriod(1000); // Set up period
Timer11.setMode(1, TIMER_OUTPUT_COMPARE);
Timer11.attachInterrupt(1, oneMSInterval);
Timer11.resume(); //Start Timer
#endif
pinMode(LED_BUILTIN, OUTPUT); //Visual WDT
/*
***********************************************************************************************************
* Auxiliaries
*/
// 2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.boostFreq * 2); // Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow frequencies up to 511Hz
vvt_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.vvtFreq * 2); // Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle
fan_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.fanFreq * 2); // Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
/*
***********************************************************************************************************
* Auxiliaries
*/
//2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.boostFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow frequencies up to 511Hz
vvt_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle
fan_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.fanFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
// Need to be initialised last due to instant interrupt
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
Timer1.setMode(2, TIMER_OUTPUT_COMPARE);
Timer1.setMode(3, TIMER_OUTPUT_COMPARE);
Timer1.attachInterrupt(1, fanInterrupt);
Timer1.attachInterrupt(2, boostInterrupt);
Timer1.attachInterrupt(3, vvtInterrupt);
//Need to be initialised last due to instant interrupt
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
Timer1.setMode(2, TIMER_OUTPUT_COMPARE);
Timer1.setMode(3, TIMER_OUTPUT_COMPARE);
Timer1.attachInterrupt(1, fanInterrupt);
Timer1.attachInterrupt(2, boostInterrupt);
Timer1.attachInterrupt(3, vvtInterrupt);
/*
***********************************************************************************************************
* Schedules
*/
#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_BLUEPILL_F103CB)
//(CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz).
// Timer2 to 4 is on APB1, Timer1 on APB2. www.st.com/resource/en/datasheet/stm32f103cb.pdf sheet 12
Timer1.setPrescaleFactor(((Timer1.getBaseFrequency() / 1000000) * TIMER_RESOLUTION) - 1); // 2us resolution
Timer2.setPrescaleFactor(((Timer2.getBaseFrequency() / 1000000) * TIMER_RESOLUTION) - 1); // 2us resolution
Timer3.setPrescaleFactor(((Timer3.getBaseFrequency() / 1000000) * TIMER_RESOLUTION) - 1); // 2us resolution
#else
//(CYCLES_PER_MICROSECOND == 168, APB2 at 84MHz, APB1 at 42MHz).
// Timer2 to 14 is on APB1, Timers 1, 8, 9 and 10 on APB2. www.st.com/resource/en/datasheet/stm32f407vg.pdf sheet 120
Timer1.setPrescaleFactor(((Timer1.getBaseFrequency() / 1000000) * TIMER_RESOLUTION) - 1); // 2us resolution
Timer2.setPrescaleFactor(((Timer2.getBaseFrequency() / 1000000) * TIMER_RESOLUTION) - 1); // 2us resolution
Timer3.setPrescaleFactor(((Timer3.getBaseFrequency() / 1000000) * TIMER_RESOLUTION) - 1); // 2us resolution
Timer4.setPrescaleFactor(((Timer4.getBaseFrequency() / 1000000) * TIMER_RESOLUTION) - 1); // 2us resolution
Timer5.setPrescaleFactor(((Timer5.getBaseFrequency() / 1000000) * TIMER_RESOLUTION) - 1); // 2us resolution
#endif
Timer2.setMode(1, TIMER_OUTPUT_COMPARE);
Timer2.setMode(2, TIMER_OUTPUT_COMPARE);
Timer2.setMode(3, TIMER_OUTPUT_COMPARE);
Timer2.setMode(4, TIMER_OUTPUT_COMPARE);
/*
***********************************************************************************************************
* Schedules
*/
#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_BLUEPILL_F103CB)
//(CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz).
//Timer2 to 4 is on APB1, Timer1 on APB2. www.st.com/resource/en/datasheet/stm32f103cb.pdf sheet 12
Timer1.setPrescaleFactor(((Timer1.getBaseFrequency()/1000000) * TIMER_RESOLUTION)-1); //2us resolution
Timer2.setPrescaleFactor(((Timer2.getBaseFrequency()/1000000) * TIMER_RESOLUTION)-1); //2us resolution
Timer3.setPrescaleFactor(((Timer3.getBaseFrequency()/1000000) * TIMER_RESOLUTION)-1); //2us resolution
#else
//(CYCLES_PER_MICROSECOND == 168, APB2 at 84MHz, APB1 at 42MHz).
//Timer2 to 14 is on APB1, Timers 1, 8, 9 and 10 on APB2. www.st.com/resource/en/datasheet/stm32f407vg.pdf sheet 120
Timer1.setPrescaleFactor(((Timer1.getBaseFrequency()/1000000) * TIMER_RESOLUTION)-1); //2us resolution
Timer2.setPrescaleFactor(((Timer2.getBaseFrequency()/1000000) * TIMER_RESOLUTION)-1); //2us resolution
Timer3.setPrescaleFactor(((Timer3.getBaseFrequency()/1000000) * TIMER_RESOLUTION)-1); //2us resolution
Timer4.setPrescaleFactor(((Timer4.getBaseFrequency()/1000000) * TIMER_RESOLUTION)-1); //2us resolution
Timer5.setPrescaleFactor(((Timer5.getBaseFrequency()/1000000) * TIMER_RESOLUTION)-1); //2us resolution
#endif
Timer2.setMode(1, TIMER_OUTPUT_COMPARE);
Timer2.setMode(2, TIMER_OUTPUT_COMPARE);
Timer2.setMode(3, TIMER_OUTPUT_COMPARE);
Timer2.setMode(4, TIMER_OUTPUT_COMPARE);
Timer3.setMode(1, TIMER_OUTPUT_COMPARE);
Timer3.setMode(2, TIMER_OUTPUT_COMPARE);
Timer3.setMode(3, TIMER_OUTPUT_COMPARE);
Timer3.setMode(4, TIMER_OUTPUT_COMPARE);
Timer3.setMode(1, TIMER_OUTPUT_COMPARE);
Timer3.setMode(2, TIMER_OUTPUT_COMPARE);
Timer3.setMode(3, TIMER_OUTPUT_COMPARE);
Timer3.setMode(4, TIMER_OUTPUT_COMPARE);
// Attach interrupt functions
// Injection
Timer2.attachInterrupt(1, fuelSchedule1Interrupt);
Timer2.attachInterrupt(2, fuelSchedule2Interrupt);
Timer2.attachInterrupt(3, fuelSchedule3Interrupt);
Timer2.attachInterrupt(4, fuelSchedule4Interrupt);
#if(INJ_CHANNELS >= 5)
Timer5.setMode(1, TIMER_OUTPUT_COMPARE);
Timer5.attachInterrupt(1, fuelSchedule5Interrupt);
#endif
#if(INJ_CHANNELS >= 6)
Timer5.setMode(2, TIMER_OUTPUT_COMPARE);
Timer5.attachInterrupt(2, fuelSchedule6Interrupt);
#endif
#if(INJ_CHANNELS >= 7)
Timer5.setMode(3, TIMER_OUTPUT_COMPARE);
Timer5.attachInterrupt(3, fuelSchedule7Interrupt);
#endif
#if(INJ_CHANNELS >= 8)
Timer5.setMode(4, TIMER_OUTPUT_COMPARE);
Timer5.attachInterrupt(4, fuelSchedule8Interrupt);
#endif
//Attach interrupt functions
//Injection
Timer2.attachInterrupt(1, fuelSchedule1Interrupt);
Timer2.attachInterrupt(2, fuelSchedule2Interrupt);
Timer2.attachInterrupt(3, fuelSchedule3Interrupt);
Timer2.attachInterrupt(4, fuelSchedule4Interrupt);
#if (INJ_CHANNELS >= 5)
Timer5.setMode(1, TIMER_OUTPUT_COMPARE);
Timer5.attachInterrupt(1, fuelSchedule5Interrupt);
#endif
#if (INJ_CHANNELS >= 6)
Timer5.setMode(2, TIMER_OUTPUT_COMPARE);
Timer5.attachInterrupt(2, fuelSchedule6Interrupt);
#endif
#if (INJ_CHANNELS >= 7)
Timer5.setMode(3, TIMER_OUTPUT_COMPARE);
Timer5.attachInterrupt(3, fuelSchedule7Interrupt);
#endif
#if (INJ_CHANNELS >= 8)
Timer5.setMode(4, TIMER_OUTPUT_COMPARE);
Timer5.attachInterrupt(4, fuelSchedule8Interrupt);
#endif
// Ignition
Timer3.attachInterrupt(1, ignitionSchedule1Interrupt);
Timer3.attachInterrupt(2, ignitionSchedule2Interrupt);
Timer3.attachInterrupt(3, ignitionSchedule3Interrupt);
Timer3.attachInterrupt(4, ignitionSchedule4Interrupt);
#if(IGN_CHANNELS >= 5)
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(1, ignitionSchedule5Interrupt);
#endif
#if(IGN_CHANNELS >= 6)
Timer4.setMode(2, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(2, ignitionSchedule6Interrupt);
#endif
#if(IGN_CHANNELS >= 7)
Timer4.setMode(3, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(3, ignitionSchedule7Interrupt);
#endif
#if(IGN_CHANNELS >= 8)
Timer4.setMode(4, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(4, ignitionSchedule8Interrupt);
#endif
//Ignition
Timer3.attachInterrupt(1, ignitionSchedule1Interrupt);
Timer3.attachInterrupt(2, ignitionSchedule2Interrupt);
Timer3.attachInterrupt(3, ignitionSchedule3Interrupt);
Timer3.attachInterrupt(4, ignitionSchedule4Interrupt);
#if (IGN_CHANNELS >= 5)
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(1, ignitionSchedule5Interrupt);
#endif
#if (IGN_CHANNELS >= 6)
Timer4.setMode(2, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(2, ignitionSchedule6Interrupt);
#endif
#if (IGN_CHANNELS >= 7)
Timer4.setMode(3, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(3, ignitionSchedule7Interrupt);
#endif
#if (IGN_CHANNELS >= 8)
Timer4.setMode(4, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(4, ignitionSchedule8Interrupt);
#endif
Timer1.setOverflow(0xFFFF);
Timer1.resume();
Timer2.setOverflow(0xFFFF);
Timer2.resume();
Timer3.setOverflow(0xFFFF);
Timer3.resume();
#if (IGN_CHANNELS >= 5)
Timer4.setOverflow(0xFFFF);
Timer4.resume();
#endif
#if (INJ_CHANNELS >= 5)
Timer5.setOverflow(0xFFFF);
Timer5.resume();
#endif
Timer1.setOverflow(0xFFFF);
Timer1.resume();
Timer2.setOverflow(0xFFFF);
Timer2.resume();
Timer3.setOverflow(0xFFFF);
Timer3.resume();
#if(IGN_CHANNELS >= 5)
Timer4.setOverflow(0xFFFF);
Timer4.resume();
#endif
#if(INJ_CHANNELS >= 5)
Timer5.setOverflow(0xFFFF);
Timer5.resume();
#endif
}
uint16_t freeRam()
{
char top = 't';
return &top - reinterpret_cast<char*>(sbrk(0));
char top = 't';
return &top - reinterpret_cast<char *>(sbrk(0));
}
void doSystemReset( void )
void doSystemReset(void)
{
__disable_irq();
NVIC_SystemReset();
__disable_irq();
NVIC_SystemReset();
}
void jumpToBootloader( void ) // https://github.com/3devo/Arduino_Core_STM32/blob/jumpSysBL/libraries/SrcWrapper/src/stm32/bootloader.c
{ // https://github.com/markusgritsch/SilF4ware/blob/master/SilF4ware/drv_reset.c
HAL_RCC_DeInit();
HAL_DeInit();
SysTick->VAL = SysTick->LOAD = SysTick->CTRL = 0;
SYSCFG->MEMRMP = 0x01;
void jumpToBootloader(void) // https://github.com/3devo/Arduino_Core_STM32/blob/jumpSysBL/libraries/SrcWrapper/src/stm32/bootloader.c
{ // https://github.com/markusgritsch/SilF4ware/blob/master/SilF4ware/drv_reset.c
HAL_RCC_DeInit();
HAL_DeInit();
SysTick->VAL = SysTick->LOAD = SysTick->CTRL = 0;
SYSCFG->MEMRMP = 0x01;
#if defined(STM32F7xx) || defined(STM32H7xx)
const uint32_t DFU_addr = 0x1FF00000; // From AN2606
#else
const uint32_t DFU_addr = 0x1FFF0000; // Default for STM32F10xxx and STM32F40xxx/STM32F41xxx from AN2606
#endif
// This is assembly to prevent modifying the stack pointer after
// loading it, and to ensure a jump (not call) to the bootloader.
// Not sure if the barriers are really needed, they were taken from
// https://github.com/GrumpyOldPizza/arduino-STM32L4/blob/ac659033eadd50cfe001ba1590a1362b2d87bb76/system/STM32L4xx/Source/boot_stm32l4xx.c#L159-L165
asm volatile (
"ldr r0, [%[DFU_addr], #0] \n\t" // get address of stack pointer
"msr msp, r0 \n\t" // set stack pointer
"ldr r0, [%[DFU_addr], #4] \n\t" // get address of reset handler
"dsb \n\t" // data sync barrier
"isb \n\t" // instruction sync barrier
"bx r0 \n\t" // branch to bootloader
: : [DFU_addr] "l" (DFU_addr) : "r0"
);
__builtin_unreachable();
#if defined(STM32F7xx) || defined(STM32H7xx)
const uint32_t DFU_addr = 0x1FF00000; // From AN2606
#else
const uint32_t DFU_addr = 0x1FFF0000; // Default for STM32F10xxx and STM32F40xxx/STM32F41xxx from AN2606
#endif
// This is assembly to prevent modifying the stack pointer after
// loading it, and to ensure a jump (not call) to the bootloader.
// Not sure if the barriers are really needed, they were taken from
// https://github.com/GrumpyOldPizza/arduino-STM32L4/blob/ac659033eadd50cfe001ba1590a1362b2d87bb76/system/STM32L4xx/Source/boot_stm32l4xx.c#L159-L165
asm volatile("ldr r0, [%[DFU_addr], #0] \n\t" // get address of stack pointer
"msr msp, r0 \n\t" // set stack pointer
"ldr r0, [%[DFU_addr], #4] \n\t" // get address of reset handler
"dsb \n\t" // data sync barrier
"isb \n\t" // instruction sync barrier
"bx r0 \n\t" // branch to bootloader
:
: [DFU_addr] "l"(DFU_addr)
: "r0");
__builtin_unreachable();
}
#endif

View File

@ -0,0 +1,382 @@
#include "board_stm32_official.h"
#if defined(STM32_CORE_VERSION_MAJOR)
#include "globals.h"
#include "auxiliaries.h"
#include "idle.h"
#include "scheduler.h"
#include "HardwareTimer.h"
#if HAL_CAN_MODULE_ENABLED
// This activates CAN1 interface on STM32, but it's named as Can0, because that's how Teensy implementation is done
STM32_CAN Can0(CAN1, ALT_2, RX_SIZE_256, TX_SIZE_16);
/*
These CAN interfaces and pins are available for use, depending on the chip/package:
Default CAN1 pins are PA11 and PA12. Alternative (ALT) pins are PB8 & PB9 and ALT_2 pins are PD0 & PD1.
Default CAN2 pins are PB12 & PB13. Alternative (ALT) pins are PB5 & PB6.
Default CAN3 pins are PA8 & PA15. Alternative (ALT) pins are PB3 & PB4.
*/
#endif
#if defined SD_LOGGING
SPIClass SD_SPI(PC12, PC11, PC10); // SPI3_MOSI, SPI3_MISO, SPI3_SCK
#endif
#if defined(SRAM_AS_EEPROM)
BackupSramAsEEPROM EEPROM;
#elif defined(USE_SPI_EEPROM)
#if defined(STM32F407xx)
SPIClass SPI_for_flash(PB5, PB4, PB3); // SPI1_MOSI, SPI1_MISO, SPI1_SCK
#else // Blue/Black Pills
SPIClass SPI_for_flash(PB15, PB14, PB13);
#endif
// winbond W25Q16 SPI flash EEPROM emulation
EEPROM_Emulation_Config EmulatedEEPROMMconfig{255UL, 4096UL, 31, 0x00100000UL};
Flash_SPI_Config SPIconfig{USE_SPI_EEPROM, SPI_for_flash};
SPI_EEPROM_Class EEPROM(EmulatedEEPROMMconfig, SPIconfig);
#elif defined(FRAM_AS_EEPROM) // https://github.com/VitorBoss/FRAM
#if defined(STM32F407xx)
SPIClass SPI_for_FRAM(PB5, PB4, PB3); // SPI1_MOSI, SPI1_MISO, SPI1_SCK
FramClass EEPROM(PB0, SPI_for_FRAM);
#else // Blue/Black Pills
SPIClass SPI_for_FRAM(PB15, PB14, PB13);
FramClass EEPROM(PB12, SPI_for_FRAM);
#endif
#elif defined(STM32F7xx)
#if defined(DUAL_BANK)
EEPROM_Emulation_Config EmulatedEEPROMMconfig{4UL, 131072UL, 2047UL, 0x08120000UL};
#else
EEPROM_Emulation_Config EmulatedEEPROMMconfig{2UL, 262144UL, 4095UL, 0x08180000UL};
#endif
InternalSTM32F7_EEPROM_Class EEPROM(EmulatedEEPROMMconfig);
#elif defined(STM32F401xC)
EEPROM_Emulation_Config EmulatedEEPROMMconfig{1UL, 131072UL, 4095UL, 0x08020000UL};
InternalSTM32F4_EEPROM_Class EEPROM(EmulatedEEPROMMconfig);
#elif defined(STM32F411xE)
EEPROM_Emulation_Config EmulatedEEPROMMconfig{2UL, 131072UL, 4095UL, 0x08040000UL};
InternalSTM32F4_EEPROM_Class EEPROM(EmulatedEEPROMMconfig);
#else // default case, internal flash as EEPROM for STM32F4
EEPROM_Emulation_Config EmulatedEEPROMMconfig{4UL, 131072UL, 2047UL, 0x08080000UL};
InternalSTM32F4_EEPROM_Class EEPROM(EmulatedEEPROMMconfig);
#endif
HardwareTimer Timer1(TIM1);
HardwareTimer Timer2(TIM2);
HardwareTimer Timer3(TIM3);
HardwareTimer Timer4(TIM4);
#if !defined(ARDUINO_BLUEPILL_F103C8) && !defined(ARDUINO_BLUEPILL_F103CB) // F103 just have 4 timers
HardwareTimer Timer5(TIM5);
#if defined(TIM11)
HardwareTimer Timer11(TIM11);
#elif defined(TIM7)
HardwareTimer Timer11(TIM7);
#endif
#endif
#ifdef RTC_ENABLED
STM32RTC &rtc = STM32RTC::getInstance();
#endif
void initBoard()
{
/*
***********************************************************************************************************
* General
*/
#ifndef FLASH_LENGTH
#define FLASH_LENGTH 8192
#endif
delay(10);
/*
***********************************************************************************************************
* Real Time clock for datalogging/time stamping
*/
#ifdef RTC_ENABLED
// Check if RTC time has been set earlier. If yes, RTC will use LSE_CLOCK. If not, default LSI_CLOCK is used, to prevent hanging on boot.
if(rtc.isTimeSet())
{
rtc.setClockSource(STM32RTC::LSE_CLOCK); // Initialise external clock for RTC if clock is set. That is the only clock running of VBAT
}
rtc.begin(); // initialise RTC 24H format
#endif
/*
***********************************************************************************************************
* Idle
*/
if((configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OLCL))
{
idle_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.idleFreq * 2); // Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 5KHz
}
// This must happen at the end of the idle init
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer1.setMode(4, TIMER_OUTPUT_COMPARE);
#else
Timer1.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer1.attachInterrupt(4, idleInterrupt); // on first flash the configPage4.iacAlgorithm is invalid
/*
***********************************************************************************************************
* Timers
*/
#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_BLUEPILL_F103CB)
Timer4.setOverflow(1000, MICROSEC_FORMAT); // Set up period
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(1, oneMSInterval);
#else // 2.0 forward
Timer4.attachInterrupt(oneMSInterval);
#endif
Timer4.resume(); // Start Timer
#else
Timer11.setOverflow(1000, MICROSEC_FORMAT); // Set up period
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer11.setMode(1, TIMER_OUTPUT_COMPARE);
Timer11.attachInterrupt(1, oneMSInterval);
#else
Timer11.attachInterrupt(oneMSInterval);
#endif
Timer11.resume(); // Start Timer
#endif
pinMode(LED_BUILTIN, OUTPUT); // Visual WDT
/*
***********************************************************************************************************
* Auxiliaries
*/
// 2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.boostFreq * 2); // Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow frequencies up to 511Hz
vvt_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.vvtFreq * 2); // Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
fan_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.fanFreq * 2); // Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
// Need to be initialised last due to instant interrupt
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
Timer1.setMode(2, TIMER_OUTPUT_COMPARE);
Timer1.setMode(3, TIMER_OUTPUT_COMPARE);
#else // 2.0 forward
Timer1.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer1.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer1.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer1.attachInterrupt(1, fanInterrupt);
Timer1.attachInterrupt(2, boostInterrupt);
Timer1.attachInterrupt(3, vvtInterrupt);
/*
***********************************************************************************************************
* Schedules
*/
Timer1.setOverflow(0xFFFF, TICK_FORMAT);
Timer2.setOverflow(0xFFFF, TICK_FORMAT);
Timer3.setOverflow(0xFFFF, TICK_FORMAT);
Timer1.setPrescaleFactor(((Timer1.getTimerClkFreq() / 1000000) * TIMER_RESOLUTION) - 1); // 4us resolution
Timer2.setPrescaleFactor(((Timer2.getTimerClkFreq() / 1000000) * TIMER_RESOLUTION) - 1); // 4us resolution
Timer3.setPrescaleFactor(((Timer3.getTimerClkFreq() / 1000000) * TIMER_RESOLUTION) - 1); // 4us resolution
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer2.setMode(1, TIMER_OUTPUT_COMPARE);
Timer2.setMode(2, TIMER_OUTPUT_COMPARE);
Timer2.setMode(3, TIMER_OUTPUT_COMPARE);
Timer2.setMode(4, TIMER_OUTPUT_COMPARE);
Timer3.setMode(1, TIMER_OUTPUT_COMPARE);
Timer3.setMode(2, TIMER_OUTPUT_COMPARE);
Timer3.setMode(3, TIMER_OUTPUT_COMPARE);
Timer3.setMode(4, TIMER_OUTPUT_COMPARE);
#else // 2.0 forward
Timer2.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer2.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer2.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer2.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer3.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer3.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer3.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer3.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
// Attach interrupt functions
// Injection
Timer3.attachInterrupt(1, fuelSchedule1Interrupt);
Timer3.attachInterrupt(2, fuelSchedule2Interrupt);
Timer3.attachInterrupt(3, fuelSchedule3Interrupt);
Timer3.attachInterrupt(4, fuelSchedule4Interrupt);
#if(INJ_CHANNELS >= 5)
Timer5.setOverflow(0xFFFF, TICK_FORMAT);
Timer5.setPrescaleFactor(((Timer5.getTimerClkFreq() / 1000000) * TIMER_RESOLUTION) - 1); // 4us resolution
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer5.setMode(1, TIMER_OUTPUT_COMPARE);
#else // 2.0 forward
Timer5.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer5.attachInterrupt(1, fuelSchedule5Interrupt);
#endif
#if(INJ_CHANNELS >= 6)
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer5.setMode(2, TIMER_OUTPUT_COMPARE);
#else // 2.0 forward
Timer5.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer5.attachInterrupt(2, fuelSchedule6Interrupt);
#endif
#if(INJ_CHANNELS >= 7)
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer5.setMode(3, TIMER_OUTPUT_COMPARE);
#else // 2.0 forward
Timer5.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer5.attachInterrupt(3, fuelSchedule7Interrupt);
#endif
#if(INJ_CHANNELS >= 8)
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer5.setMode(4, TIMER_OUTPUT_COMPARE);
#else // 2.0 forward
Timer5.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer5.attachInterrupt(4, fuelSchedule8Interrupt);
#endif
// Ignition
Timer2.attachInterrupt(1, ignitionSchedule1Interrupt);
Timer2.attachInterrupt(2, ignitionSchedule2Interrupt);
Timer2.attachInterrupt(3, ignitionSchedule3Interrupt);
Timer2.attachInterrupt(4, ignitionSchedule4Interrupt);
#if(IGN_CHANNELS >= 5)
Timer4.setOverflow(0xFFFF, TICK_FORMAT);
Timer4.setPrescaleFactor(((Timer4.getTimerClkFreq() / 1000000) * TIMER_RESOLUTION) - 1); // 4us resolution
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
#else // 2.0 forward
Timer4.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer4.attachInterrupt(1, ignitionSchedule5Interrupt);
#endif
#if(IGN_CHANNELS >= 6)
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer4.setMode(2, TIMER_OUTPUT_COMPARE);
#else // 2.0 forward
Timer4.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer4.attachInterrupt(2, ignitionSchedule6Interrupt);
#endif
#if(IGN_CHANNELS >= 7)
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer4.setMode(3, TIMER_OUTPUT_COMPARE);
#else // 2.0 forward
Timer4.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer4.attachInterrupt(3, ignitionSchedule7Interrupt);
#endif
#if(IGN_CHANNELS >= 8)
#if(STM32_CORE_VERSION_MAJOR < 2)
Timer4.setMode(4, TIMER_OUTPUT_COMPARE);
#else // 2.0 forward
Timer4.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer4.attachInterrupt(4, ignitionSchedule8Interrupt);
#endif
}
uint16_t freeRam()
{
uint32_t freeRam;
uint32_t stackTop;
uint32_t heapTop;
// current position of the stack.
stackTop = (uint32_t)&stackTop;
// current position of heap.
void *hTop = malloc(1);
heapTop = (uint32_t)hTop;
free(hTop);
freeRam = stackTop - heapTop;
if(freeRam > 0xFFFF) { return 0xFFFF; }
else { return freeRam; }
}
void doSystemReset(void)
{
__disable_irq();
NVIC_SystemReset();
}
void jumpToBootloader(void) // https://github.com/3devo/Arduino_Core_STM32/blob/jumpSysBL/libraries/SrcWrapper/src/stm32/bootloader.c
{ // https://github.com/markusgritsch/SilF4ware/blob/master/SilF4ware/drv_reset.c
#if !defined(STM32F103xB)
HAL_RCC_DeInit();
HAL_DeInit();
SysTick->VAL = SysTick->LOAD = SysTick->CTRL = 0;
SYSCFG->MEMRMP = 0x01;
#if defined(STM32F7xx) || defined(STM32H7xx)
const uint32_t DFU_addr = 0x1FF00000; // From AN2606
#else
const uint32_t DFU_addr = 0x1FFF0000; // Default for STM32F10xxx and STM32F40xxx/STM32F41xxx from AN2606
#endif
// This is assembly to prevent modifying the stack pointer after
// loading it, and to ensure a jump (not call) to the bootloader.
// Not sure if the barriers are really needed, they were taken from
// https://github.com/GrumpyOldPizza/arduino-STM32L4/blob/ac659033eadd50cfe001ba1590a1362b2d87bb76/system/STM32L4xx/Source/boot_stm32l4xx.c#L159-L165
asm volatile("ldr r0, [%[DFU_addr], #0] \n\t" // get address of stack pointer
"msr msp, r0 \n\t" // set stack pointer
"ldr r0, [%[DFU_addr], #4] \n\t" // get address of reset handler
"dsb \n\t" // data sync barrier
"isb \n\t" // instruction sync barrier
"bx r0 \n\t" // branch to bootloader
:
: [DFU_addr] "l"(DFU_addr)
: "r0");
__builtin_unreachable();
#endif
}
/*
***********************************************************************************************************
* Interrupt callback functions
*/
#if((STM32_CORE_VERSION_MINOR <= 8) & (STM32_CORE_VERSION_MAJOR == 1))
void oneMSInterval(HardwareTimer *) { oneMSInterval(); }
void boostInterrupt(HardwareTimer *) { boostInterrupt(); }
void fuelSchedule1Interrupt(HardwareTimer *) { fuelSchedule1Interrupt(); }
void fuelSchedule2Interrupt(HardwareTimer *) { fuelSchedule2Interrupt(); }
void fuelSchedule3Interrupt(HardwareTimer *) { fuelSchedule3Interrupt(); }
void fuelSchedule4Interrupt(HardwareTimer *) { fuelSchedule4Interrupt(); }
#if(INJ_CHANNELS >= 5)
void fuelSchedule5Interrupt(HardwareTimer *) { fuelSchedule5Interrupt(); }
#endif
#if(INJ_CHANNELS >= 6)
void fuelSchedule6Interrupt(HardwareTimer *) { fuelSchedule6Interrupt(); }
#endif
#if(INJ_CHANNELS >= 7)
void fuelSchedule7Interrupt(HardwareTimer *) { fuelSchedule7Interrupt(); }
#endif
#if(INJ_CHANNELS >= 8)
void fuelSchedule8Interrupt(HardwareTimer *) { fuelSchedule8Interrupt(); }
#endif
void idleInterrupt(HardwareTimer *) { idleInterrupt(); }
void vvtInterrupt(HardwareTimer *) { vvtInterrupt(); }
void fanInterrupt(HardwareTimer *) { fanInterrupt(); }
void ignitionSchedule1Interrupt(HardwareTimer *) { ignitionSchedule1Interrupt(); }
void ignitionSchedule2Interrupt(HardwareTimer *) { ignitionSchedule2Interrupt(); }
void ignitionSchedule3Interrupt(HardwareTimer *) { ignitionSchedule3Interrupt(); }
void ignitionSchedule4Interrupt(HardwareTimer *) { ignitionSchedule4Interrupt(); }
#if(IGN_CHANNELS >= 5)
void ignitionSchedule5Interrupt(HardwareTimer *) { ignitionSchedule5Interrupt(); }
#endif
#if(IGN_CHANNELS >= 6)
void ignitionSchedule6Interrupt(HardwareTimer *) { ignitionSchedule6Interrupt(); }
#endif
#if(IGN_CHANNELS >= 7)
void ignitionSchedule7Interrupt(HardwareTimer *) { ignitionSchedule7Interrupt(); }
#endif
#if(IGN_CHANNELS >= 8)
void ignitionSchedule8Interrupt(HardwareTimer *) { ignitionSchedule8Interrupt(); }
#endif
#endif // End core<=1.8
#endif

View File

@ -288,7 +288,7 @@ extern HardwareTimer Timer11;
#endif
#endif
#if ((STM32_CORE_VERSION_MINOR<=8) & (STM32_CORE_VERSION_MAJOR==1))
#if ((STM32_CORE_VERSION_MINOR<=8) && (STM32_CORE_VERSION_MAJOR==1))
void oneMSInterval(HardwareTimer*);
void boostInterrupt(HardwareTimer*);
void fuelSchedule1Interrupt(HardwareTimer*);

View File

@ -1,385 +0,0 @@
#include "board_stm32_official.h"
#if defined(STM32_CORE_VERSION_MAJOR)
#include "globals.h"
#include "auxiliaries.h"
#include "idle.h"
#include "scheduler.h"
#include "HardwareTimer.h"
#if HAL_CAN_MODULE_ENABLED
//This activates CAN1 interface on STM32, but it's named as Can0, because that's how Teensy implementation is done
STM32_CAN Can0 (CAN1, ALT_2, RX_SIZE_256, TX_SIZE_16);
/*
These CAN interfaces and pins are available for use, depending on the chip/package:
Default CAN1 pins are PA11 and PA12. Alternative (ALT) pins are PB8 & PB9 and ALT_2 pins are PD0 & PD1.
Default CAN2 pins are PB12 & PB13. Alternative (ALT) pins are PB5 & PB6.
Default CAN3 pins are PA8 & PA15. Alternative (ALT) pins are PB3 & PB4.
*/
#endif
#if defined SD_LOGGING
SPIClass SD_SPI(PC12, PC11, PC10); //SPI3_MOSI, SPI3_MISO, SPI3_SCK
#endif
#if defined(SRAM_AS_EEPROM)
BackupSramAsEEPROM EEPROM;
#elif defined(USE_SPI_EEPROM)
#if defined(STM32F407xx)
SPIClass SPI_for_flash(PB5, PB4, PB3); //SPI1_MOSI, SPI1_MISO, SPI1_SCK
#else //Blue/Black Pills
SPIClass SPI_for_flash(PB15, PB14, PB13);
#endif
//winbond W25Q16 SPI flash EEPROM emulation
EEPROM_Emulation_Config EmulatedEEPROMMconfig{255UL, 4096UL, 31, 0x00100000UL};
Flash_SPI_Config SPIconfig{USE_SPI_EEPROM, SPI_for_flash};
SPI_EEPROM_Class EEPROM(EmulatedEEPROMMconfig, SPIconfig);
#elif defined(FRAM_AS_EEPROM) //https://github.com/VitorBoss/FRAM
#if defined(STM32F407xx)
SPIClass SPI_for_FRAM(PB5, PB4, PB3); //SPI1_MOSI, SPI1_MISO, SPI1_SCK
FramClass EEPROM(PB0, SPI_for_FRAM);
#else //Blue/Black Pills
SPIClass SPI_for_FRAM(PB15, PB14, PB13);
FramClass EEPROM(PB12, SPI_for_FRAM);
#endif
#elif defined(STM32F7xx)
#if defined(DUAL_BANK)
EEPROM_Emulation_Config EmulatedEEPROMMconfig{4UL, 131072UL, 2047UL, 0x08120000UL};
#else
EEPROM_Emulation_Config EmulatedEEPROMMconfig{2UL, 262144UL, 4095UL, 0x08180000UL};
#endif
InternalSTM32F7_EEPROM_Class EEPROM(EmulatedEEPROMMconfig);
#elif defined(STM32F401xC)
EEPROM_Emulation_Config EmulatedEEPROMMconfig{1UL, 131072UL, 4095UL, 0x08020000UL};
InternalSTM32F4_EEPROM_Class EEPROM(EmulatedEEPROMMconfig);
#elif defined(STM32F411xE)
EEPROM_Emulation_Config EmulatedEEPROMMconfig{2UL, 131072UL, 4095UL, 0x08040000UL};
InternalSTM32F4_EEPROM_Class EEPROM(EmulatedEEPROMMconfig);
#else //default case, internal flash as EEPROM for STM32F4
EEPROM_Emulation_Config EmulatedEEPROMMconfig{4UL, 131072UL, 2047UL, 0x08080000UL};
InternalSTM32F4_EEPROM_Class EEPROM(EmulatedEEPROMMconfig);
#endif
HardwareTimer Timer1(TIM1);
HardwareTimer Timer2(TIM2);
HardwareTimer Timer3(TIM3);
HardwareTimer Timer4(TIM4);
#if !defined(ARDUINO_BLUEPILL_F103C8) && !defined(ARDUINO_BLUEPILL_F103CB) //F103 just have 4 timers
HardwareTimer Timer5(TIM5);
#if defined(TIM11)
HardwareTimer Timer11(TIM11);
#elif defined(TIM7)
HardwareTimer Timer11(TIM7);
#endif
#endif
#ifdef RTC_ENABLED
STM32RTC& rtc = STM32RTC::getInstance();
#endif
void initBoard()
{
/*
***********************************************************************************************************
* General
*/
#ifndef FLASH_LENGTH
#define FLASH_LENGTH 8192
#endif
delay(10);
/*
***********************************************************************************************************
* Real Time clock for datalogging/time stamping
*/
#ifdef RTC_ENABLED
//Check if RTC time has been set earlier. If yes, RTC will use LSE_CLOCK. If not, default LSI_CLOCK is used, to prevent hanging on boot.
if (rtc.isTimeSet()) {
rtc.setClockSource(STM32RTC::LSE_CLOCK); //Initialise external clock for RTC if clock is set. That is the only clock running of VBAT
}
rtc.begin(); // initialise RTC 24H format
#endif
/*
***********************************************************************************************************
* Idle
*/
if( (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OLCL))
{
idle_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 5KHz
}
//This must happen at the end of the idle init
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer1.setMode(4, TIMER_OUTPUT_COMPARE);
#else
Timer1.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer1.attachInterrupt(4, idleInterrupt); //on first flash the configPage4.iacAlgorithm is invalid
/*
***********************************************************************************************************
* Timers
*/
#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_BLUEPILL_F103CB)
Timer4.setOverflow(1000, MICROSEC_FORMAT); // Set up period
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(1, oneMSInterval);
#else //2.0 forward
Timer4.attachInterrupt(oneMSInterval);
#endif
Timer4.resume(); //Start Timer
#else
Timer11.setOverflow(1000, MICROSEC_FORMAT); // Set up period
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer11.setMode(1, TIMER_OUTPUT_COMPARE);
Timer11.attachInterrupt(1, oneMSInterval);
#else
Timer11.attachInterrupt(oneMSInterval);
#endif
Timer11.resume(); //Start Timer
#endif
pinMode(LED_BUILTIN, OUTPUT); //Visual WDT
/*
***********************************************************************************************************
* Auxiliaries
*/
//2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.boostFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow frequencies up to 511Hz
vvt_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
fan_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.fanFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
//Need to be initialised last due to instant interrupt
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
Timer1.setMode(2, TIMER_OUTPUT_COMPARE);
Timer1.setMode(3, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer1.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer1.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer1.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer1.attachInterrupt(1, fanInterrupt);
Timer1.attachInterrupt(2, boostInterrupt);
Timer1.attachInterrupt(3, vvtInterrupt);
/*
***********************************************************************************************************
* Schedules
*/
Timer1.setOverflow(0xFFFF, TICK_FORMAT);
Timer2.setOverflow(0xFFFF, TICK_FORMAT);
Timer3.setOverflow(0xFFFF, TICK_FORMAT);
Timer1.setPrescaleFactor(((Timer1.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
Timer2.setPrescaleFactor(((Timer2.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
Timer3.setPrescaleFactor(((Timer3.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer2.setMode(1, TIMER_OUTPUT_COMPARE);
Timer2.setMode(2, TIMER_OUTPUT_COMPARE);
Timer2.setMode(3, TIMER_OUTPUT_COMPARE);
Timer2.setMode(4, TIMER_OUTPUT_COMPARE);
Timer3.setMode(1, TIMER_OUTPUT_COMPARE);
Timer3.setMode(2, TIMER_OUTPUT_COMPARE);
Timer3.setMode(3, TIMER_OUTPUT_COMPARE);
Timer3.setMode(4, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer2.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer2.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer2.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer2.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer3.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer3.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer3.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer3.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
//Attach interrupt functions
//Injection
Timer3.attachInterrupt(1, fuelSchedule1Interrupt);
Timer3.attachInterrupt(2, fuelSchedule2Interrupt);
Timer3.attachInterrupt(3, fuelSchedule3Interrupt);
Timer3.attachInterrupt(4, fuelSchedule4Interrupt);
#if (INJ_CHANNELS >= 5)
Timer5.setOverflow(0xFFFF, TICK_FORMAT);
Timer5.setPrescaleFactor(((Timer5.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer5.setMode(1, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer5.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer5.attachInterrupt(1, fuelSchedule5Interrupt);
#endif
#if (INJ_CHANNELS >= 6)
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer5.setMode(2, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer5.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer5.attachInterrupt(2, fuelSchedule6Interrupt);
#endif
#if (INJ_CHANNELS >= 7)
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer5.setMode(3, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer5.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer5.attachInterrupt(3, fuelSchedule7Interrupt);
#endif
#if (INJ_CHANNELS >= 8)
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer5.setMode(4, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer5.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer5.attachInterrupt(4, fuelSchedule8Interrupt);
#endif
//Ignition
Timer2.attachInterrupt(1, ignitionSchedule1Interrupt);
Timer2.attachInterrupt(2, ignitionSchedule2Interrupt);
Timer2.attachInterrupt(3, ignitionSchedule3Interrupt);
Timer2.attachInterrupt(4, ignitionSchedule4Interrupt);
#if (IGN_CHANNELS >= 5)
Timer4.setOverflow(0xFFFF, TICK_FORMAT);
Timer4.setPrescaleFactor(((Timer4.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer4.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer4.attachInterrupt(1, ignitionSchedule5Interrupt);
#endif
#if (IGN_CHANNELS >= 6)
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer4.setMode(2, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer4.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer4.attachInterrupt(2, ignitionSchedule6Interrupt);
#endif
#if (IGN_CHANNELS >= 7)
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer4.setMode(3, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer4.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer4.attachInterrupt(3, ignitionSchedule7Interrupt);
#endif
#if (IGN_CHANNELS >= 8)
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer4.setMode(4, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer4.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer4.attachInterrupt(4, ignitionSchedule8Interrupt);
#endif
}
uint16_t freeRam()
{
uint32_t freeRam;
uint32_t stackTop;
uint32_t heapTop;
// current position of the stack.
stackTop = (uint32_t)&stackTop;
// current position of heap.
void *hTop = malloc(1);
heapTop = (uint32_t)hTop;
free(hTop);
freeRam = stackTop - heapTop;
if(freeRam>0xFFFF){return 0xFFFF;}
else{return freeRam;}
}
void doSystemReset( void )
{
__disable_irq();
NVIC_SystemReset();
}
void jumpToBootloader( void ) // https://github.com/3devo/Arduino_Core_STM32/blob/jumpSysBL/libraries/SrcWrapper/src/stm32/bootloader.c
{ // https://github.com/markusgritsch/SilF4ware/blob/master/SilF4ware/drv_reset.c
#if !defined(STM32F103xB)
HAL_RCC_DeInit();
HAL_DeInit();
SysTick->VAL = SysTick->LOAD = SysTick->CTRL = 0;
SYSCFG->MEMRMP = 0x01;
#if defined(STM32F7xx) || defined(STM32H7xx)
const uint32_t DFU_addr = 0x1FF00000; // From AN2606
#else
const uint32_t DFU_addr = 0x1FFF0000; // Default for STM32F10xxx and STM32F40xxx/STM32F41xxx from AN2606
#endif
// This is assembly to prevent modifying the stack pointer after
// loading it, and to ensure a jump (not call) to the bootloader.
// Not sure if the barriers are really needed, they were taken from
// https://github.com/GrumpyOldPizza/arduino-STM32L4/blob/ac659033eadd50cfe001ba1590a1362b2d87bb76/system/STM32L4xx/Source/boot_stm32l4xx.c#L159-L165
asm volatile (
"ldr r0, [%[DFU_addr], #0] \n\t" // get address of stack pointer
"msr msp, r0 \n\t" // set stack pointer
"ldr r0, [%[DFU_addr], #4] \n\t" // get address of reset handler
"dsb \n\t" // data sync barrier
"isb \n\t" // instruction sync barrier
"bx r0 \n\t" // branch to bootloader
: : [DFU_addr] "l" (DFU_addr) : "r0"
);
__builtin_unreachable();
#endif
}
/*
***********************************************************************************************************
* Interrupt callback functions
*/
#if ((STM32_CORE_VERSION_MINOR<=8) & (STM32_CORE_VERSION_MAJOR==1))
void oneMSInterval(HardwareTimer*){oneMSInterval();}
void boostInterrupt(HardwareTimer*){boostInterrupt();}
void fuelSchedule1Interrupt(HardwareTimer*){fuelSchedule1Interrupt();}
void fuelSchedule2Interrupt(HardwareTimer*){fuelSchedule2Interrupt();}
void fuelSchedule3Interrupt(HardwareTimer*){fuelSchedule3Interrupt();}
void fuelSchedule4Interrupt(HardwareTimer*){fuelSchedule4Interrupt();}
#if (INJ_CHANNELS >= 5)
void fuelSchedule5Interrupt(HardwareTimer*){fuelSchedule5Interrupt();}
#endif
#if (INJ_CHANNELS >= 6)
void fuelSchedule6Interrupt(HardwareTimer*){fuelSchedule6Interrupt();}
#endif
#if (INJ_CHANNELS >= 7)
void fuelSchedule7Interrupt(HardwareTimer*){fuelSchedule7Interrupt();}
#endif
#if (INJ_CHANNELS >= 8)
void fuelSchedule8Interrupt(HardwareTimer*){fuelSchedule8Interrupt();}
#endif
void idleInterrupt(HardwareTimer*){idleInterrupt();}
void vvtInterrupt(HardwareTimer*){vvtInterrupt();}
void fanInterrupt(HardwareTimer*){fanInterrupt();}
void ignitionSchedule1Interrupt(HardwareTimer*){ignitionSchedule1Interrupt();}
void ignitionSchedule2Interrupt(HardwareTimer*){ignitionSchedule2Interrupt();}
void ignitionSchedule3Interrupt(HardwareTimer*){ignitionSchedule3Interrupt();}
void ignitionSchedule4Interrupt(HardwareTimer*){ignitionSchedule4Interrupt();}
#if (IGN_CHANNELS >= 5)
void ignitionSchedule5Interrupt(HardwareTimer*){ignitionSchedule5Interrupt();}
#endif
#if (IGN_CHANNELS >= 6)
void ignitionSchedule6Interrupt(HardwareTimer*){ignitionSchedule6Interrupt();}
#endif
#if (IGN_CHANNELS >= 7)
void ignitionSchedule7Interrupt(HardwareTimer*){ignitionSchedule7Interrupt();}
#endif
#if (IGN_CHANNELS >= 8)
void ignitionSchedule8Interrupt(HardwareTimer*){ignitionSchedule8Interrupt();}
#endif
#endif //End core<=1.8
#endif

View File

@ -1,306 +1,304 @@
#if defined(CORE_TEENSY) && defined(CORE_TEENSY35)
#include "board_teensy35.h"
#include "globals.h"
#include "auxiliaries.h"
#include "idle.h"
#include "scheduler.h"
#include "board_teensy35.h"
#include "globals.h"
#include "auxiliaries.h"
#include "idle.h"
#include "scheduler.h"
#if defined(__MK64FX512__) // use for Teensy 3.5 only
FlexCAN_T4<CAN0, RX_SIZE_256, TX_SIZE_16> Can0;
#elif defined(__MK66FX1M0__) // use for Teensy 3.6 only
FlexCAN_T4<CAN0, RX_SIZE_256, TX_SIZE_16> Can0;
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can1;
#endif
#if defined(__MK64FX512__) // use for Teensy 3.5 only
FlexCAN_T4<CAN0, RX_SIZE_256, TX_SIZE_16> Can0;
#elif defined(__MK66FX1M0__) // use for Teensy 3.6 only
FlexCAN_T4<CAN0, RX_SIZE_256, TX_SIZE_16> Can0;
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can1;
#endif
void initBoard()
{
/*
***********************************************************************************************************
* General
*/
/*
***********************************************************************************************************
* General
*/
/*
***********************************************************************************************************
* Idle
*/
if((configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OLCL))
{
// FlexTimer 2, compare channel 0 is used for idle
FTM2_MODE |= FTM_MODE_WPDIS; // Write Protection Disable
FTM2_MODE |= FTM_MODE_FTMEN; // Flex Timer module enable
FTM2_MODE |= FTM_MODE_INIT;
FTM2_SC = 0x00; // Set this to zero before changing the modulus
FTM2_CNTIN = 0x0000; // Shouldn't be needed, but just in case
FTM2_CNT = 0x0000; // Reset the count to zero
FTM2_MOD = 0xFFFF; // max modulus = 65535
/*
***********************************************************************************************************
* Idle
*/
if ((configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OLCL))
{
//FlexTimer 2, compare channel 0 is used for idle
FTM2_MODE |= FTM_MODE_WPDIS; // Write Protection Disable
FTM2_MODE |= FTM_MODE_FTMEN; //Flex Timer module enable
FTM2_MODE |= FTM_MODE_INIT;
FTM2_SC = 0x00; // Set this to zero before changing the modulus
FTM2_CNTIN = 0x0000; //Shouldn't be needed, but just in case
FTM2_CNT = 0x0000; // Reset the count to zero
FTM2_MOD = 0xFFFF; // max modulus = 65535
/*
* Enable the clock for FTM0/1
* 00 No clock selected. Disables the FTM counter.
* 01 System clock
* 10 Fixed frequency clock (32kHz)
* 11 External clock
*/
FTM2_SC |= FTM_SC_CLKS(0b10);
/*
* Trim the slow clock from 32kHz down to 31.25kHz (The slowest it will go)
* This is somewhat imprecise and documentation is not good.
* I poked the chip until I figured out the values associated with 31.25kHz
*/
MCG_C3 = 0x9B;
/*
* Set Prescaler
* This is the slowest that the timer can be clocked . It results in ticks of 32uS on the teensy 3.5:
* 31250 Hz = Slow_clock
* 1 * 1000000uS / Slow_clock = 32uS
*
* 000 = Divide by 1
* 001 Divide by 2
* 010 Divide by 4
* 011 Divide by 8
* 100 Divide by 16
* 101 Divide by 32
* 110 Divide by 64
* 111 Divide by 128
*/
FTM2_SC |= FTM_SC_PS(0b0); //No prescaler
//Setup the channels (See Pg 1014 of K64 DS).
FTM2_C0SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM2_C0SC |= FTM_CSC_MSA; //Enable Compare mode
//The below enables channel compare interrupt, but this is done in idleControl()
//FTM2_C0SC |= FTM_CSC_CHIE;
FTM2_C1SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM2_C1SC |= FTM_CSC_MSA; //Enable Compare mode
//Enable channel compare interrupt (This is currently disabled as not in use)
//FTM2_C1SC |= FTM_CSC_CHIE;
//Enable IRQ Interrupt
NVIC_ENABLE_IRQ(IRQ_FTM2);
}
* Enable the clock for FTM0/1
* 00 No clock selected. Disables the FTM counter.
* 01 System clock
* 10 Fixed frequency clock (32kHz)
* 11 External clock
*/
FTM2_SC |= FTM_SC_CLKS(0b10);
/*
***********************************************************************************************************
* Auxiliaries
*/
* Trim the slow clock from 32kHz down to 31.25kHz (The slowest it will go)
* This is somewhat imprecise and documentation is not good.
* I poked the chip until I figured out the values associated with 31.25kHz
*/
MCG_C3 = 0x9B;
/*
***********************************************************************************************************
* BOOST and VVT
*/
if (configPage6.boostEnabled == 1 || configPage6.vvtEnabled == 1)
{
//FlexTimer 2, compare channel 0 is used for idle
FTM1_MODE |= FTM_MODE_WPDIS; // Write Protection Disable
FTM1_MODE |= FTM_MODE_FTMEN; //Flex Timer module enable
FTM1_MODE |= FTM_MODE_INIT;
* Set Prescaler
* This is the slowest that the timer can be clocked . It results in ticks of 32uS on the teensy 3.5:
* 31250 Hz = Slow_clock
* 1 * 1000000uS / Slow_clock = 32uS
*
* 000 = Divide by 1
* 001 Divide by 2
* 010 Divide by 4
* 011 Divide by 8
* 100 Divide by 16
* 101 Divide by 32
* 110 Divide by 64
* 111 Divide by 128
*/
FTM2_SC |= FTM_SC_PS(0b0); // No prescaler
FTM1_SC = 0x00; // Set this to zero before changing the modulus
FTM1_CNTIN = 0x0000; //Shouldn't be needed, but just in case
FTM1_CNT = 0x0000; // Reset the count to zero
FTM1_MOD = 0xFFFF; // max modulus = 65535
// Setup the channels (See Pg 1014 of K64 DS).
FTM2_C0SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM2_C0SC |= FTM_CSC_MSA; // Enable Compare mode
// The below enables channel compare interrupt, but this is done in idleControl()
// FTM2_C0SC |= FTM_CSC_CHIE;
/*
* Enable the clock for FTM0/1
* 00 No clock selected. Disables the FTM counter.
* 01 System clock
* 10 Fixed frequency clock (32kHz)
* 11 External clock
*/
FTM1_SC |= FTM_SC_CLKS(0b10);
FTM2_C1SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM2_C1SC |= FTM_CSC_MSA; // Enable Compare mode
// Enable channel compare interrupt (This is currently disabled as not in use)
// FTM2_C1SC |= FTM_CSC_CHIE;
/*
* Trim the slow clock from 32kHz down to 31.25kHz (The slowest it will go)
* This is somewhat imprecise and documentation is not good.
* I poked the chip until I figured out the values associated with 31.25kHz
*/
MCG_C3 = 0x9B;
// Enable IRQ Interrupt
NVIC_ENABLE_IRQ(IRQ_FTM2);
}
/*
* Set Prescaler
* This is the slowest that the timer can be clocked . It results in ticks of 32uS on the teensy 3.5:
* 31250 Hz = Slow_clock
* 1 * 1000000uS / Slow_clock = 32uS
*
* 000 = Divide by 1
* 001 Divide by 2
* 010 Divide by 4
* 011 Divide by 8
* 100 Divide by 16
* 101 Divide by 32
* 110 Divide by 64
* 111 Divide by 128
*/
FTM1_SC |= FTM_SC_PS(0b0); //No prescaler
/*
***********************************************************************************************************
* Auxiliaries
*/
//Setup the channels (See Pg 1014 of K64 DS).
FTM1_C0SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM1_C0SC |= FTM_CSC_MSA; //Enable Compare mode
//The below enables channel compare interrupt, but this is done in idleControl()
//FTM1_C0SC |= FTM_CSC_CHIE;
/*
***********************************************************************************************************
* BOOST and VVT
*/
if(configPage6.boostEnabled == 1 || configPage6.vvtEnabled == 1)
{
// FlexTimer 2, compare channel 0 is used for idle
FTM1_MODE |= FTM_MODE_WPDIS; // Write Protection Disable
FTM1_MODE |= FTM_MODE_FTMEN; // Flex Timer module enable
FTM1_MODE |= FTM_MODE_INIT;
FTM1_C1SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM1_C1SC |= FTM_CSC_MSA; //Enable Compare mode
//Enable channel compare interrupt (This is currently disabled as not in use)
//FTM1_C1SC |= FTM_CSC_CHIE;
FTM2_C1SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM2_C1SC |= FTM_CSC_MSA; //Enable Compare mode
//Enable channel compare interrupt (This is currently disabled as not in use)
//FTM1_C2SC |= FTM_CSC_CHIE;
//Enable IRQ Interrupt
NVIC_ENABLE_IRQ(IRQ_FTM1);
boost_pwm_max_count = 1000000L / (32 * configPage6.boostFreq * 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
vvt_pwm_max_count = 1000000L / (32 * configPage6.vvtFreq * 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
fan_pwm_max_count = 1000000L / (32 * configPage6.fanFreq * 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
}
FTM1_SC = 0x00; // Set this to zero before changing the modulus
FTM1_CNTIN = 0x0000; // Shouldn't be needed, but just in case
FTM1_CNT = 0x0000; // Reset the count to zero
FTM1_MOD = 0xFFFF; // max modulus = 65535
/*
***********************************************************************************************************
* Timers
*/
//Uses the PIT timer on Teensy.
lowResTimer.begin(oneMSInterval, 1000);
* Enable the clock for FTM0/1
* 00 No clock selected. Disables the FTM counter.
* 01 System clock
* 10 Fixed frequency clock (32kHz)
* 11 External clock
*/
FTM1_SC |= FTM_SC_CLKS(0b10);
/*
***********************************************************************************************************
* Schedules
*/
//FlexTimer 0 is used for 4 ignition and 4 injection schedules. There are 8 channels on this module, so no other timers are needed
FTM0_MODE |= FTM_MODE_WPDIS; //Write Protection Disable
FTM0_MODE |= FTM_MODE_FTMEN; //Flex Timer module enable
FTM0_MODE |= FTM_MODE_INIT;
FTM0_SC = 0x00; // Set this to zero before changing the modulus
FTM0_CNTIN = 0x0000; //Shouldn't be needed, but just in case
FTM0_CNT = 0x0000; //Reset the count to zero
FTM0_MOD = 0xFFFF; //max modulus = 65535
//FlexTimer 3 is used for schedules on channel 5+. Currently only channel 5 is used, but will likely be expanded later
FTM3_MODE |= FTM_MODE_WPDIS; //Write Protection Disable
FTM3_MODE |= FTM_MODE_FTMEN; //Flex Timer module enable
FTM3_MODE |= FTM_MODE_INIT;
FTM3_SC = 0x00; // Set this to zero before changing the modulus
FTM3_CNTIN = 0x0000; //Shouldn't be needed, but just in case
FTM3_CNT = 0x0000; //Reset the count to zero
FTM3_MOD = 0xFFFF; //max modulus = 65535
* Trim the slow clock from 32kHz down to 31.25kHz (The slowest it will go)
* This is somewhat imprecise and documentation is not good.
* I poked the chip until I figured out the values associated with 31.25kHz
*/
MCG_C3 = 0x9B;
/*
* Enable the clock for FTM0/1
* 00 No clock selected. Disables the FTM counter.
* 01 System clock
* 10 Fixed frequency clock
* 11 External clock
*/
FTM0_SC |= FTM_SC_CLKS(0b1);
FTM3_SC |= FTM_SC_CLKS(0b1);
* Set Prescaler
* This is the slowest that the timer can be clocked . It results in ticks of 32uS on the teensy 3.5:
* 31250 Hz = Slow_clock
* 1 * 1000000uS / Slow_clock = 32uS
*
* 000 = Divide by 1
* 001 Divide by 2
* 010 Divide by 4
* 011 Divide by 8
* 100 Divide by 16
* 101 Divide by 32
* 110 Divide by 64
* 111 Divide by 128
*/
FTM1_SC |= FTM_SC_PS(0b0); // No prescaler
/*
* Set Prescaler
* This is the slowest that the timer can be clocked (Without used the slow timer, which is too slow). It results in ticks of 2.13333uS on the teensy 3.5:
* 60000000 Hz = F_BUS
* 128 * 1000000uS / F_BUS = 2.133uS
*
* 000 = Divide by 1
* 001 Divide by 2
* 010 Divide by 4
* 011 Divide by 8
* 100 Divide by 16
* 101 Divide by 32
* 110 Divide by 64
* 111 Divide by 128
*/
FTM0_SC |= FTM_SC_PS(0b111);
FTM3_SC |= FTM_SC_PS(0b111);
// Setup the channels (See Pg 1014 of K64 DS).
FTM1_C0SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM1_C0SC |= FTM_CSC_MSA; // Enable Compare mode
// The below enables channel compare interrupt, but this is done in idleControl()
// FTM1_C0SC |= FTM_CSC_CHIE;
//Setup the channels (See Pg 1014 of K64 DS).
//The are probably not needed as power on state should be 0
//FTM0_C0SC &= ~FTM_CSC_ELSB;
//FTM0_C0SC &= ~FTM_CSC_ELSA;
//FTM0_C0SC &= ~FTM_CSC_DMA;
FTM0_C0SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C0SC |= FTM_CSC_MSA; //Enable Compare mode
FTM0_C0SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
FTM1_C1SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM1_C1SC |= FTM_CSC_MSA; // Enable Compare mode
// Enable channel compare interrupt (This is currently disabled as not in use)
// FTM1_C1SC |= FTM_CSC_CHIE;
FTM0_C1SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C1SC |= FTM_CSC_MSA; //Enable Compare mode
FTM0_C1SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
FTM2_C1SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM2_C1SC |= FTM_CSC_MSA; // Enable Compare mode
// Enable channel compare interrupt (This is currently disabled as not in use)
// FTM1_C2SC |= FTM_CSC_CHIE;
FTM0_C2SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C2SC |= FTM_CSC_MSA; //Enable Compare mode
FTM0_C2SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
// Enable IRQ Interrupt
NVIC_ENABLE_IRQ(IRQ_FTM1);
FTM0_C3SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C3SC |= FTM_CSC_MSA; //Enable Compare mode
FTM0_C3SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
boost_pwm_max_count = 1000000L / (32 * configPage6.boostFreq * 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
vvt_pwm_max_count = 1000000L / (32 * configPage6.vvtFreq * 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
fan_pwm_max_count = 1000000L / (32 * configPage6.fanFreq * 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
}
FTM0_C4SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C4SC |= FTM_CSC_MSA; //Enable Compare mode
FTM0_C4SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
/*
***********************************************************************************************************
* Timers
*/
// Uses the PIT timer on Teensy.
lowResTimer.begin(oneMSInterval, 1000);
FTM0_C5SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C5SC |= FTM_CSC_MSA; //Enable Compare mode
FTM0_C5SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
/*
***********************************************************************************************************
* Schedules
*/
FTM0_C6SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C6SC |= FTM_CSC_MSA; //Enable Compare mode
FTM0_C6SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
// FlexTimer 0 is used for 4 ignition and 4 injection schedules. There are 8 channels on this module, so no other timers are needed
FTM0_MODE |= FTM_MODE_WPDIS; // Write Protection Disable
FTM0_MODE |= FTM_MODE_FTMEN; // Flex Timer module enable
FTM0_MODE |= FTM_MODE_INIT;
FTM0_C7SC &= ~FTM_CSC_MSB; //According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C7SC |= FTM_CSC_MSA; //Enable Compare mode
FTM0_C7SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
FTM0_SC = 0x00; // Set this to zero before changing the modulus
FTM0_CNTIN = 0x0000; // Shouldn't be needed, but just in case
FTM0_CNT = 0x0000; // Reset the count to zero
FTM0_MOD = 0xFFFF; // max modulus = 65535
//Do the same, but on flex timer 3 (Used for channels 5-8)
FTM3_C0SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C0SC |= FTM_CSC_MSA; //Enable Compare mode
FTM3_C0SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
// FlexTimer 3 is used for schedules on channel 5+. Currently only channel 5 is used, but will likely be expanded later
FTM3_MODE |= FTM_MODE_WPDIS; // Write Protection Disable
FTM3_MODE |= FTM_MODE_FTMEN; // Flex Timer module enable
FTM3_MODE |= FTM_MODE_INIT;
FTM3_C1SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C1SC |= FTM_CSC_MSA; //Enable Compare mode
FTM3_C1SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
FTM3_SC = 0x00; // Set this to zero before changing the modulus
FTM3_CNTIN = 0x0000; // Shouldn't be needed, but just in case
FTM3_CNT = 0x0000; // Reset the count to zero
FTM3_MOD = 0xFFFF; // max modulus = 65535
FTM3_C2SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C2SC |= FTM_CSC_MSA; //Enable Compare mode
FTM3_C2SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
/*
* Enable the clock for FTM0/1
* 00 No clock selected. Disables the FTM counter.
* 01 System clock
* 10 Fixed frequency clock
* 11 External clock
*/
FTM0_SC |= FTM_SC_CLKS(0b1);
FTM3_SC |= FTM_SC_CLKS(0b1);
FTM3_C3SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C3SC |= FTM_CSC_MSA; //Enable Compare mode
FTM3_C3SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
/*
* Set Prescaler
* This is the slowest that the timer can be clocked (Without used the slow timer, which is too slow). It results in ticks of 2.13333uS on the teensy 3.5:
* 60000000 Hz = F_BUS
* 128 * 1000000uS / F_BUS = 2.133uS
*
* 000 = Divide by 1
* 001 Divide by 2
* 010 Divide by 4
* 011 Divide by 8
* 100 Divide by 16
* 101 Divide by 32
* 110 Divide by 64
* 111 Divide by 128
*/
FTM0_SC |= FTM_SC_PS(0b111);
FTM3_SC |= FTM_SC_PS(0b111);
FTM3_C4SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C4SC |= FTM_CSC_MSA; //Enable Compare mode
FTM3_C4SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
// Setup the channels (See Pg 1014 of K64 DS).
// The are probably not needed as power on state should be 0
// FTM0_C0SC &= ~FTM_CSC_ELSB;
// FTM0_C0SC &= ~FTM_CSC_ELSA;
// FTM0_C0SC &= ~FTM_CSC_DMA;
FTM0_C0SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C0SC |= FTM_CSC_MSA; // Enable Compare mode
FTM0_C0SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM3_C5SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C5SC |= FTM_CSC_MSA; //Enable Compare mode
FTM3_C5SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
FTM0_C1SC &= ~FTM_CSC_MSB; // According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C1SC |= FTM_CSC_MSA; // Enable Compare mode
FTM0_C1SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM3_C6SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C6SC |= FTM_CSC_MSA; //Enable Compare mode
FTM3_C6SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
FTM0_C2SC &= ~FTM_CSC_MSB; // According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C2SC |= FTM_CSC_MSA; // Enable Compare mode
FTM0_C2SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM3_C7SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C7SC |= FTM_CSC_MSA; //Enable Compare mode
FTM3_C7SC |= FTM_CSC_CHIE; //Enable channel compare interrupt
FTM0_C3SC &= ~FTM_CSC_MSB; // According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C3SC |= FTM_CSC_MSA; // Enable Compare mode
FTM0_C3SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
// enable IRQ Interrupt
NVIC_ENABLE_IRQ(IRQ_FTM0);
NVIC_ENABLE_IRQ(IRQ_FTM3);
FTM0_C4SC &= ~FTM_CSC_MSB; // According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C4SC |= FTM_CSC_MSA; // Enable Compare mode
FTM0_C4SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM0_C5SC &= ~FTM_CSC_MSB; // According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C5SC |= FTM_CSC_MSA; // Enable Compare mode
FTM0_C5SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM0_C6SC &= ~FTM_CSC_MSB; // According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C6SC |= FTM_CSC_MSA; // Enable Compare mode
FTM0_C6SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM0_C7SC &= ~FTM_CSC_MSB; // According to Pg 965 of the datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM0_C7SC |= FTM_CSC_MSA; // Enable Compare mode
FTM0_C7SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
// Do the same, but on flex timer 3 (Used for channels 5-8)
FTM3_C0SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C0SC |= FTM_CSC_MSA; // Enable Compare mode
FTM3_C0SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM3_C1SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C1SC |= FTM_CSC_MSA; // Enable Compare mode
FTM3_C1SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM3_C2SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C2SC |= FTM_CSC_MSA; // Enable Compare mode
FTM3_C2SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM3_C3SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C3SC |= FTM_CSC_MSA; // Enable Compare mode
FTM3_C3SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM3_C4SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C4SC |= FTM_CSC_MSA; // Enable Compare mode
FTM3_C4SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM3_C5SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C5SC |= FTM_CSC_MSA; // Enable Compare mode
FTM3_C5SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM3_C6SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C6SC |= FTM_CSC_MSA; // Enable Compare mode
FTM3_C6SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
FTM3_C7SC &= ~FTM_CSC_MSB; // According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM3_C7SC |= FTM_CSC_MSA; // Enable Compare mode
FTM3_C7SC |= FTM_CSC_CHIE; // Enable channel compare interrupt
// enable IRQ Interrupt
NVIC_ENABLE_IRQ(IRQ_FTM0);
NVIC_ENABLE_IRQ(IRQ_FTM3);
}
void ftm0_isr(void)
{
//Use separate variables for each test to ensure conversion to bool
// Use separate variables for each test to ensure conversion to bool
bool interrupt1 = (FTM0_C0SC & FTM_CSC_CHF);
bool interrupt2 = (FTM0_C1SC & FTM_CSC_CHF);
bool interrupt3 = (FTM0_C2SC & FTM_CSC_CHF);
@ -310,103 +308,177 @@ void ftm0_isr(void)
bool interrupt7 = (FTM0_C6SC & FTM_CSC_CHF);
bool interrupt8 = (FTM0_C7SC & FTM_CSC_CHF);
if(interrupt1) { FTM0_C0SC &= ~FTM_CSC_CHF; fuelSchedule1Interrupt(); }
else if(interrupt2) { FTM0_C1SC &= ~FTM_CSC_CHF; fuelSchedule2Interrupt(); }
else if(interrupt3) { FTM0_C2SC &= ~FTM_CSC_CHF; fuelSchedule3Interrupt(); }
else if(interrupt4) { FTM0_C3SC &= ~FTM_CSC_CHF; fuelSchedule4Interrupt(); }
else if(interrupt5) { FTM0_C4SC &= ~FTM_CSC_CHF; ignitionSchedule1Interrupt(); }
else if(interrupt6) { FTM0_C5SC &= ~FTM_CSC_CHF; ignitionSchedule2Interrupt(); }
else if(interrupt7) { FTM0_C6SC &= ~FTM_CSC_CHF; ignitionSchedule3Interrupt(); }
else if(interrupt8) { FTM0_C7SC &= ~FTM_CSC_CHF; ignitionSchedule4Interrupt(); }
if(interrupt1)
{
FTM0_C0SC &= ~FTM_CSC_CHF;
fuelSchedule1Interrupt();
}
else if(interrupt2)
{
FTM0_C1SC &= ~FTM_CSC_CHF;
fuelSchedule2Interrupt();
}
else if(interrupt3)
{
FTM0_C2SC &= ~FTM_CSC_CHF;
fuelSchedule3Interrupt();
}
else if(interrupt4)
{
FTM0_C3SC &= ~FTM_CSC_CHF;
fuelSchedule4Interrupt();
}
else if(interrupt5)
{
FTM0_C4SC &= ~FTM_CSC_CHF;
ignitionSchedule1Interrupt();
}
else if(interrupt6)
{
FTM0_C5SC &= ~FTM_CSC_CHF;
ignitionSchedule2Interrupt();
}
else if(interrupt7)
{
FTM0_C6SC &= ~FTM_CSC_CHF;
ignitionSchedule3Interrupt();
}
else if(interrupt8)
{
FTM0_C7SC &= ~FTM_CSC_CHF;
ignitionSchedule4Interrupt();
}
}
void ftm3_isr(void)
{
#if (INJ_CHANNELS >= 5)
#if(INJ_CHANNELS >= 5)
bool interrupt1 = (FTM3_C0SC & FTM_CSC_CHF);
if(interrupt1) { FTM3_C0SC &= ~FTM_CSC_CHF; fuelSchedule5Interrupt(); }
#endif
#if (INJ_CHANNELS >= 6)
if(interrupt1)
{
FTM3_C0SC &= ~FTM_CSC_CHF;
fuelSchedule5Interrupt();
}
#endif
#if(INJ_CHANNELS >= 6)
bool interrupt2 = (FTM3_C1SC & FTM_CSC_CHF);
if(interrupt2) { FTM3_C1SC &= ~FTM_CSC_CHF; fuelSchedule6Interrupt(); }
#endif
#if (INJ_CHANNELS >= 7)
if(interrupt2)
{
FTM3_C1SC &= ~FTM_CSC_CHF;
fuelSchedule6Interrupt();
}
#endif
#if(INJ_CHANNELS >= 7)
bool interrupt3 = (FTM3_C2SC & FTM_CSC_CHF);
if(interrupt3) { FTM3_C2SC &= ~FTM_CSC_CHF; fuelSchedule7Interrupt(); }
#endif
#if (INJ_CHANNELS >= 8)
if(interrupt3)
{
FTM3_C2SC &= ~FTM_CSC_CHF;
fuelSchedule7Interrupt();
}
#endif
#if(INJ_CHANNELS >= 8)
bool interrupt4 = (FTM3_C3SC & FTM_CSC_CHF);
if(interrupt4) { FTM3_C3SC &= ~FTM_CSC_CHF; fuelSchedule8Interrupt(); }
#endif
#if (IGN_CHANNELS >= 5)
if(interrupt4)
{
FTM3_C3SC &= ~FTM_CSC_CHF;
fuelSchedule8Interrupt();
}
#endif
#if(IGN_CHANNELS >= 5)
bool interrupt5 = (FTM3_C4SC & FTM_CSC_CHF);
if(interrupt5) { FTM3_C4SC &= ~FTM_CSC_CHF; ignitionSchedule5Interrupt(); }
#endif
#if (IGN_CHANNELS >= 6)
if(interrupt5)
{
FTM3_C4SC &= ~FTM_CSC_CHF;
ignitionSchedule5Interrupt();
}
#endif
#if(IGN_CHANNELS >= 6)
bool interrupt6 = (FTM3_C5SC & FTM_CSC_CHF);
if(interrupt6) { FTM3_C5SC &= ~FTM_CSC_CHF; ignitionSchedule6Interrupt(); }
#endif
#if (IGN_CHANNELS >= 7)
if(interrupt6)
{
FTM3_C5SC &= ~FTM_CSC_CHF;
ignitionSchedule6Interrupt();
}
#endif
#if(IGN_CHANNELS >= 7)
bool interrupt7 = (FTM3_C6SC & FTM_CSC_CHF);
if(interrupt7) { FTM3_C6SC &= ~FTM_CSC_CHF; ignitionSchedule7Interrupt(); }
#endif
#if (IGN_CHANNELS >= 8)
if(interrupt7)
{
FTM3_C6SC &= ~FTM_CSC_CHF;
ignitionSchedule7Interrupt();
}
#endif
#if(IGN_CHANNELS >= 8)
bool interrupt8 = (FTM3_C7SC & FTM_CSC_CHF);
if(interrupt8) { FTM3_C7SC &= ~FTM_CSC_CHF; ignitionSchedule8Interrupt(); }
#endif
if(interrupt8)
{
FTM3_C7SC &= ~FTM_CSC_CHF;
ignitionSchedule8Interrupt();
}
#endif
}
//Boost and VVT handler
// Boost and VVT handler
void ftm1_isr(void)
{
//FTM1 only has 2 compare channels (Is this correct?)
//Use separate variables for each test to ensure conversion to bool
// FTM1 only has 2 compare channels (Is this correct?)
// Use separate variables for each test to ensure conversion to bool
bool interrupt1 = (FTM1_C0SC & FTM_CSC_CHF);
bool interrupt2 = (FTM1_C1SC & FTM_CSC_CHF);
if(interrupt1) { FTM1_C0SC &= ~FTM_CSC_CHF; boostInterrupt(); }
else if(interrupt2) { FTM1_C1SC &= ~FTM_CSC_CHF; vvtInterrupt(); }
if(interrupt1)
{
FTM1_C0SC &= ~FTM_CSC_CHF;
boostInterrupt();
}
else if(interrupt2)
{
FTM1_C1SC &= ~FTM_CSC_CHF;
vvtInterrupt();
}
}
//Idle and spare handler
// Idle and spare handler
void ftm2_isr(void)
{
//FTM2 only has 2 compare channels
//Use separate variables for each test to ensure conversion to bool
{
// FTM2 only has 2 compare channels
// Use separate variables for each test to ensure conversion to bool
bool interrupt1 = (FTM2_C0SC & FTM_CSC_CHF);
bool interrupt2 = (FTM2_C1SC & FTM_CSC_CHF); //For PWM Fan
bool interrupt2 = (FTM2_C1SC & FTM_CSC_CHF); // For PWM Fan
if(interrupt1) { FTM2_C0SC &= ~FTM_CSC_CHF; idleInterrupt(); }
else if(interrupt2) { FTM2_C1SC &= ~FTM_CSC_CHF; fanInterrupt(); } //For PWM Fan
if(interrupt1)
{
FTM2_C0SC &= ~FTM_CSC_CHF;
idleInterrupt();
}
else if(interrupt2)
{
FTM2_C1SC &= ~FTM_CSC_CHF;
fanInterrupt();
} // For PWM Fan
}
uint16_t freeRam()
{
uint32_t freeRam;
uint32_t stackTop;
uint32_t heapTop;
uint32_t freeRam;
uint32_t stackTop;
uint32_t heapTop;
// current position of the stack.
stackTop = (uint32_t)&stackTop;
// current position of the stack.
stackTop = (uint32_t)&stackTop;
// current position of heap.
void *hTop = malloc(1);
heapTop = (uint32_t)hTop;
free(hTop);
freeRam = stackTop - heapTop;
// current position of heap.
void *hTop = malloc(1);
heapTop = (uint32_t)hTop;
free(hTop);
freeRam = stackTop - heapTop;
if(freeRam>0xFFFF){return 0xFFFF;}
else{return freeRam;}
if(freeRam > 0xFFFF) { return 0xFFFF; }
else { return freeRam; }
}
//This function is used for attempting to set the RTC time during compile
time_t getTeensy3Time()
{
return Teensy3Clock.get();
}
// This function is used for attempting to set the RTC time during compile
time_t getTeensy3Time() { return Teensy3Clock.get(); }
void doSystemReset() { return; }
void jumpToBootloader() { return; }

View File

@ -1,9 +1,9 @@
#if defined(CORE_TEENSY) && defined(__IMXRT1062__)
#include "board_teensy41.h"
#include "globals.h"
#include "auxiliaries.h"
#include "idle.h"
#include "scheduler.h"
#include "board_teensy41.h"
#include "globals.h"
#include "auxiliaries.h"
#include "idle.h"
#include "scheduler.h"
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can0;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> Can1;
@ -11,194 +11,194 @@ FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_16> Can2;
void initBoard()
{
/*
***********************************************************************************************************
* General
*/
/*
***********************************************************************************************************
* General
*/
/*
Idle + Boost + VVT use the PIT timer. THIS IS ALSO USED BY THE INTERVAL TIMER THAT CALLS THE 1MS LOW RES TIMER!
This has 4 channels that don't have compare registers, but will run for a period of time and then fire an interrupt
The clock for these is set to 24Mhz and a prescale of 48 is used to give a 2uS tick time
Set Prescaler
* This is ideally too fast, but appears to be the slowest that the PIT can be set
* 24Mhz = PER_clock
* 48 * 1000000uS / PER_clock = 2uS
*/
CCM_CSCMR1 |= CCM_CSCMR1_PERCLK_CLK_SEL; // 24MHz
CCM_CSCMR1 |= CCM_CSCMR1_PERCLK_PODF(0b101111); //Prescale to 48
/*
Idle + Boost + VVT use the PIT timer. THIS IS ALSO USED BY THE INTERVAL TIMER THAT CALLS THE 1MS LOW RES TIMER!
This has 4 channels that don't have compare registers, but will run for a period of time and then fire an interrupt
The clock for these is set to 24Mhz and a prescale of 48 is used to give a 2uS tick time
Set Prescaler
* This is ideally too fast, but appears to be the slowest that the PIT can be set
* 24Mhz = PER_clock
* 48 * 1000000uS / PER_clock = 2uS
*/
CCM_CSCMR1 |= CCM_CSCMR1_PERCLK_CLK_SEL; // 24MHz
CCM_CSCMR1 |= CCM_CSCMR1_PERCLK_PODF(0b101111); // Prescale to 48
attachInterruptVector(IRQ_PIT, PIT_isr);
NVIC_ENABLE_IRQ(IRQ_PIT);
attachInterruptVector(IRQ_PIT, PIT_isr);
NVIC_ENABLE_IRQ(IRQ_PIT);
/*
***********************************************************************************************************
* Idle
*/
if( (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OLCL))
{
PIT_TCTRL0 = 0;
PIT_TCTRL0 |= PIT_TCTRL_TIE; // enable Timer 1 interrupts
PIT_TCTRL0 |= PIT_TCTRL_TEN; // start Timer 1
PIT_LDVAL0 = 1; //1 * 2uS = 2uS
}
/*
***********************************************************************************************************
* Idle
*/
if((configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OLCL))
{
PIT_TCTRL0 = 0;
PIT_TCTRL0 |= PIT_TCTRL_TIE; // enable Timer 1 interrupts
PIT_TCTRL0 |= PIT_TCTRL_TEN; // start Timer 1
PIT_LDVAL0 = 1; // 1 * 2uS = 2uS
}
/*
***********************************************************************************************************
* Timers
*/
//Uses the PIT timer channel 4 on Teensy 4.1.
//lowResTimer.begin(oneMSInterval, 1000);
PIT_TCTRL3 = 0;
PIT_TCTRL3 |= PIT_TCTRL_TIE; // enable Timer 2 interrupts
PIT_TCTRL3 |= PIT_TCTRL_TEN; // start Timer 2
PIT_LDVAL3 = 500; //500 * 2uS = 1ms
/*
***********************************************************************************************************
* Timers
*/
// Uses the PIT timer channel 4 on Teensy 4.1.
// lowResTimer.begin(oneMSInterval, 1000);
PIT_TCTRL3 = 0;
PIT_TCTRL3 |= PIT_TCTRL_TIE; // enable Timer 2 interrupts
PIT_TCTRL3 |= PIT_TCTRL_TEN; // start Timer 2
PIT_LDVAL3 = 500; // 500 * 2uS = 1ms
//TODO: Configure timers here
// TODO: Configure timers here
/*
***********************************************************************************************************
* Auxiliaries
*/
if (configPage6.boostEnabled == 1)
{
PIT_TCTRL1 = 0;
PIT_TCTRL1 |= PIT_TCTRL_TIE; // enable Timer 2 interrupts
PIT_TCTRL1 |= PIT_TCTRL_TEN; // start Timer 2
PIT_LDVAL1 = 1; //1 * 2uS = 2uS
}
if (configPage6.vvtEnabled == 1)
{
PIT_TCTRL2 = 0;
PIT_TCTRL2 |= PIT_TCTRL_TIE; // enable Timer 3 interrupts
PIT_TCTRL2 |= PIT_TCTRL_TEN; // start Timer 3
PIT_LDVAL2 = 1; //1 * 2uS = 2uS
}
/*
***********************************************************************************************************
* Auxiliaries
*/
if(configPage6.boostEnabled == 1)
{
PIT_TCTRL1 = 0;
PIT_TCTRL1 |= PIT_TCTRL_TIE; // enable Timer 2 interrupts
PIT_TCTRL1 |= PIT_TCTRL_TEN; // start Timer 2
PIT_LDVAL1 = 1; // 1 * 2uS = 2uS
}
if(configPage6.vvtEnabled == 1)
{
PIT_TCTRL2 = 0;
PIT_TCTRL2 |= PIT_TCTRL_TIE; // enable Timer 3 interrupts
PIT_TCTRL2 |= PIT_TCTRL_TEN; // start Timer 3
PIT_LDVAL2 = 1; // 1 * 2uS = 2uS
}
//2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / (2 * configPage6.boostFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow frequencies up to 511Hz
vvt_pwm_max_count = 1000000L / (2 * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle
#if defined(PWM_FAN_AVAILABLE)
fan_pwm_max_count = 1000000L / (2 * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle
#endif
// 2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / (2 * configPage6.boostFreq * 2); // Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow frequencies up to 511Hz
vvt_pwm_max_count = 1000000L / (2 * configPage6.vvtFreq * 2); // Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle
#if defined(PWM_FAN_AVAILABLE)
fan_pwm_max_count = 1000000L / (2 * configPage6.vvtFreq * 2); // Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle
#endif
//TODO: Configure timers here
// TODO: Configure timers here
/*
***********************************************************************************************************
* Schedules
*/
//Use the Quad timer
//Uses the BUS clock speed, which is 1/4 of the CPU clock. Maximum prescaler of 128 is used to give a 0.853333uS tick time @ 600Mhz
//TMR1 - Fuel 1-4
//0
TMR1_CTRL0 = 0;
TMR1_CSCTRL0 = 0;
TMR1_LOAD0 = 0; /* Reset load register */
TMR1_CTRL0 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR1_CTRL0 |= TMR_CTRL_CM(1); //Start the timer
//1
TMR1_CTRL1 = 0;
TMR1_CSCTRL1 = 0;
TMR1_LOAD1 = 0; /* Reset load register */
TMR1_CTRL1 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR1_CTRL1 |= TMR_CTRL_CM(1); //Start the timer
//2
TMR1_CTRL2 = 0;
TMR1_CSCTRL2 = 0;
TMR1_LOAD2 = 0; /* Reset load register */
TMR1_CTRL2 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR1_CTRL2 |= TMR_CTRL_CM(1); //Start the timer
//3
TMR1_CTRL3 = 0;
TMR1_CSCTRL3 = 0;
TMR1_LOAD3 = 0; /* Reset load register */
TMR1_CTRL3 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR1_CTRL3 |= TMR_CTRL_CM(1); //Start the timer
//TMR2 - Ign 1-4
//0
TMR2_CTRL0 = 0;
TMR2_CSCTRL0 = 0;
TMR2_LOAD0 = 0; /* Reset load register */
TMR2_CTRL0 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR2_CTRL0 |= TMR_CTRL_CM(1); //Start the timer
//1
TMR2_CTRL1 = 0;
TMR2_CSCTRL1 = 0;
TMR2_LOAD1 = 0; /* Reset load register */
TMR2_CTRL1 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR2_CTRL1 |= TMR_CTRL_CM(1); //Start the timer
//2
TMR2_CTRL2 = 0;
TMR2_CSCTRL2 = 0;
TMR2_LOAD2 = 0; /* Reset load register */
TMR2_CTRL2 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR2_CTRL2 |= TMR_CTRL_CM(1); //Start the timer
//3
TMR2_CTRL3 = 0;
TMR2_CSCTRL3 = 0;
TMR2_LOAD3 = 0; /* Reset load register */
TMR2_CTRL3 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR2_CTRL3 |= TMR_CTRL_CM(1); //Start the timer
//TMR3 - Fuel 5-8
//0
TMR3_CTRL0 = 0;
TMR3_CSCTRL0 = 0;
TMR3_LOAD0 = 0; /* Reset load register */
TMR3_CTRL0 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR3_CTRL0 |= TMR_CTRL_CM(1); //Start the timer
//1
TMR3_CTRL1 = 0;
TMR3_CSCTRL1 = 0;
TMR3_LOAD1 = 0; /* Reset load register */
TMR3_CTRL1 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR3_CTRL1 |= TMR_CTRL_CM(1); //Start the timer
//2
TMR3_CTRL2 = 0;
TMR3_CSCTRL2 = 0;
TMR3_LOAD2 = 0; /* Reset load register */
TMR3_CTRL2 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR3_CTRL2 |= TMR_CTRL_CM(1); //Start the timer
//3
TMR3_CTRL3 = 0;
TMR3_CSCTRL3 = 0;
TMR3_LOAD3 = 0; /* Reset load register */
TMR3_CTRL3 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR3_CTRL3 |= TMR_CTRL_CM(1); //Start the timer
//TMR4 - IGN 5-8
//0
TMR4_CTRL0 = 0;
TMR4_CSCTRL0 = 0;
TMR4_LOAD0 = 0; /* Reset load register */
TMR4_CTRL0 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR4_CTRL0 |= TMR_CTRL_CM(1); //Start the timer
//1
TMR4_CTRL1 = 0;
TMR4_CSCTRL1 = 0;
TMR4_LOAD1 = 0; /* Reset load register */
TMR4_CTRL1 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR4_CTRL1 |= TMR_CTRL_CM(1); //Start the timer
//2
TMR4_CTRL2 = 0;
TMR4_CSCTRL2 = 0;
TMR4_LOAD2 = 0; /* Reset load register */
TMR4_CTRL2 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR4_CTRL2 |= TMR_CTRL_CM(1); //Start the timer
//3
TMR4_CTRL3 = 0;
TMR4_CSCTRL3 = 0;
TMR4_LOAD3 = 0; /* Reset load register */
TMR4_CTRL3 |= TMR_CTRL_PCS(0b1111); //Set the prescaler to 128
TMR4_CTRL3 |= TMR_CTRL_CM(1); //Start the timer
/*
***********************************************************************************************************
* Schedules
*/
// Use the Quad timer
// Uses the BUS clock speed, which is 1/4 of the CPU clock. Maximum prescaler of 128 is used to give a 0.853333uS tick time @ 600Mhz
// TMR1 - Fuel 1-4
// 0
TMR1_CTRL0 = 0;
TMR1_CSCTRL0 = 0;
TMR1_LOAD0 = 0; /* Reset load register */
TMR1_CTRL0 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR1_CTRL0 |= TMR_CTRL_CM(1); // Start the timer
// 1
TMR1_CTRL1 = 0;
TMR1_CSCTRL1 = 0;
TMR1_LOAD1 = 0; /* Reset load register */
TMR1_CTRL1 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR1_CTRL1 |= TMR_CTRL_CM(1); // Start the timer
// 2
TMR1_CTRL2 = 0;
TMR1_CSCTRL2 = 0;
TMR1_LOAD2 = 0; /* Reset load register */
TMR1_CTRL2 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR1_CTRL2 |= TMR_CTRL_CM(1); // Start the timer
// 3
TMR1_CTRL3 = 0;
TMR1_CSCTRL3 = 0;
TMR1_LOAD3 = 0; /* Reset load register */
TMR1_CTRL3 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR1_CTRL3 |= TMR_CTRL_CM(1); // Start the timer
// TMR2 - Ign 1-4
// 0
TMR2_CTRL0 = 0;
TMR2_CSCTRL0 = 0;
TMR2_LOAD0 = 0; /* Reset load register */
TMR2_CTRL0 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR2_CTRL0 |= TMR_CTRL_CM(1); // Start the timer
// 1
TMR2_CTRL1 = 0;
TMR2_CSCTRL1 = 0;
TMR2_LOAD1 = 0; /* Reset load register */
TMR2_CTRL1 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR2_CTRL1 |= TMR_CTRL_CM(1); // Start the timer
// 2
TMR2_CTRL2 = 0;
TMR2_CSCTRL2 = 0;
TMR2_LOAD2 = 0; /* Reset load register */
TMR2_CTRL2 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR2_CTRL2 |= TMR_CTRL_CM(1); // Start the timer
// 3
TMR2_CTRL3 = 0;
TMR2_CSCTRL3 = 0;
TMR2_LOAD3 = 0; /* Reset load register */
TMR2_CTRL3 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR2_CTRL3 |= TMR_CTRL_CM(1); // Start the timer
// TMR3 - Fuel 5-8
// 0
TMR3_CTRL0 = 0;
TMR3_CSCTRL0 = 0;
TMR3_LOAD0 = 0; /* Reset load register */
TMR3_CTRL0 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR3_CTRL0 |= TMR_CTRL_CM(1); // Start the timer
// 1
TMR3_CTRL1 = 0;
TMR3_CSCTRL1 = 0;
TMR3_LOAD1 = 0; /* Reset load register */
TMR3_CTRL1 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR3_CTRL1 |= TMR_CTRL_CM(1); // Start the timer
// 2
TMR3_CTRL2 = 0;
TMR3_CSCTRL2 = 0;
TMR3_LOAD2 = 0; /* Reset load register */
TMR3_CTRL2 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR3_CTRL2 |= TMR_CTRL_CM(1); // Start the timer
// 3
TMR3_CTRL3 = 0;
TMR3_CSCTRL3 = 0;
TMR3_LOAD3 = 0; /* Reset load register */
TMR3_CTRL3 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR3_CTRL3 |= TMR_CTRL_CM(1); // Start the timer
// TMR4 - IGN 5-8
// 0
TMR4_CTRL0 = 0;
TMR4_CSCTRL0 = 0;
TMR4_LOAD0 = 0; /* Reset load register */
TMR4_CTRL0 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR4_CTRL0 |= TMR_CTRL_CM(1); // Start the timer
// 1
TMR4_CTRL1 = 0;
TMR4_CSCTRL1 = 0;
TMR4_LOAD1 = 0; /* Reset load register */
TMR4_CTRL1 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR4_CTRL1 |= TMR_CTRL_CM(1); // Start the timer
// 2
TMR4_CTRL2 = 0;
TMR4_CSCTRL2 = 0;
TMR4_LOAD2 = 0; /* Reset load register */
TMR4_CTRL2 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR4_CTRL2 |= TMR_CTRL_CM(1); // Start the timer
// 3
TMR4_CTRL3 = 0;
TMR4_CSCTRL3 = 0;
TMR4_LOAD3 = 0; /* Reset load register */
TMR4_CTRL3 |= TMR_CTRL_PCS(0b1111); // Set the prescaler to 128
TMR4_CTRL3 |= TMR_CTRL_CM(1); // Start the timer
attachInterruptVector(IRQ_QTIMER1, TMR1_isr);
NVIC_ENABLE_IRQ(IRQ_QTIMER1);
attachInterruptVector(IRQ_QTIMER2, TMR2_isr);
NVIC_ENABLE_IRQ(IRQ_QTIMER2);
attachInterruptVector(IRQ_QTIMER3, TMR3_isr);
NVIC_ENABLE_IRQ(IRQ_QTIMER3);
attachInterruptVector(IRQ_QTIMER4, TMR4_isr);
NVIC_ENABLE_IRQ(IRQ_QTIMER4);
attachInterruptVector(IRQ_QTIMER1, TMR1_isr);
NVIC_ENABLE_IRQ(IRQ_QTIMER1);
attachInterruptVector(IRQ_QTIMER2, TMR2_isr);
NVIC_ENABLE_IRQ(IRQ_QTIMER2);
attachInterruptVector(IRQ_QTIMER3, TMR3_isr);
NVIC_ENABLE_IRQ(IRQ_QTIMER3);
attachInterruptVector(IRQ_QTIMER4, TMR4_isr);
NVIC_ENABLE_IRQ(IRQ_QTIMER4);
}
void PIT_isr()
@ -208,105 +208,182 @@ void PIT_isr()
bool interrupt3 = (PIT_TFLG2 & PIT_TFLG_TIF);
bool interrupt4 = (PIT_TFLG3 & PIT_TFLG_TIF);
if(interrupt1) { PIT_TFLG0 = 1; idleInterrupt(); }
else if(interrupt2) { PIT_TFLG1 = 1; boostInterrupt(); }
else if(interrupt3) { PIT_TFLG2 = 1; vvtInterrupt(); }
else if(interrupt4) { PIT_TFLG3 = 1; oneMSInterval(); }
if(interrupt1)
{
PIT_TFLG0 = 1;
idleInterrupt();
}
else if(interrupt2)
{
PIT_TFLG1 = 1;
boostInterrupt();
}
else if(interrupt3)
{
PIT_TFLG2 = 1;
vvtInterrupt();
}
else if(interrupt4)
{
PIT_TFLG3 = 1;
oneMSInterval();
}
}
void TMR1_isr(void)
{
//TMR1 is fuel channels 1-4
// TMR1 is fuel channels 1-4
bool interrupt1 = (TMR1_CSCTRL0 & TMR_CSCTRL_TCF1);
bool interrupt2 = (TMR1_CSCTRL1 & TMR_CSCTRL_TCF1);
bool interrupt3 = (TMR1_CSCTRL2 & TMR_CSCTRL_TCF1);
bool interrupt4 = (TMR1_CSCTRL3 & TMR_CSCTRL_TCF1);
if(interrupt1) { TMR1_CSCTRL0 &= ~TMR_CSCTRL_TCF1; fuelSchedule1Interrupt(); }
else if(interrupt2) { TMR1_CSCTRL1 &= ~TMR_CSCTRL_TCF1; fuelSchedule2Interrupt(); }
else if(interrupt3) { TMR1_CSCTRL2 &= ~TMR_CSCTRL_TCF1; fuelSchedule3Interrupt(); }
else if(interrupt4) { TMR1_CSCTRL3 &= ~TMR_CSCTRL_TCF1; fuelSchedule4Interrupt(); }
if(interrupt1)
{
TMR1_CSCTRL0 &= ~TMR_CSCTRL_TCF1;
fuelSchedule1Interrupt();
}
else if(interrupt2)
{
TMR1_CSCTRL1 &= ~TMR_CSCTRL_TCF1;
fuelSchedule2Interrupt();
}
else if(interrupt3)
{
TMR1_CSCTRL2 &= ~TMR_CSCTRL_TCF1;
fuelSchedule3Interrupt();
}
else if(interrupt4)
{
TMR1_CSCTRL3 &= ~TMR_CSCTRL_TCF1;
fuelSchedule4Interrupt();
}
}
void TMR2_isr(void)
{
//TMR2 is IGN channels 1-4
// TMR2 is IGN channels 1-4
bool interrupt1 = (TMR2_CSCTRL0 & TMR_CSCTRL_TCF1);
bool interrupt2 = (TMR2_CSCTRL1 & TMR_CSCTRL_TCF1);
bool interrupt3 = (TMR2_CSCTRL2 & TMR_CSCTRL_TCF1);
bool interrupt4 = (TMR2_CSCTRL3 & TMR_CSCTRL_TCF1);
if(interrupt1) { TMR2_CSCTRL0 &= ~TMR_CSCTRL_TCF1; ignitionSchedule1Interrupt(); }
else if(interrupt2) { TMR2_CSCTRL1 &= ~TMR_CSCTRL_TCF1; ignitionSchedule2Interrupt(); }
else if(interrupt3) { TMR2_CSCTRL2 &= ~TMR_CSCTRL_TCF1; ignitionSchedule3Interrupt(); }
else if(interrupt4) { TMR2_CSCTRL3 &= ~TMR_CSCTRL_TCF1; ignitionSchedule4Interrupt(); }
if(interrupt1)
{
TMR2_CSCTRL0 &= ~TMR_CSCTRL_TCF1;
ignitionSchedule1Interrupt();
}
else if(interrupt2)
{
TMR2_CSCTRL1 &= ~TMR_CSCTRL_TCF1;
ignitionSchedule2Interrupt();
}
else if(interrupt3)
{
TMR2_CSCTRL2 &= ~TMR_CSCTRL_TCF1;
ignitionSchedule3Interrupt();
}
else if(interrupt4)
{
TMR2_CSCTRL3 &= ~TMR_CSCTRL_TCF1;
ignitionSchedule4Interrupt();
}
}
void TMR3_isr(void)
{
//TMR3 is Fuel channels 5-8
// TMR3 is Fuel channels 5-8
bool interrupt1 = (TMR3_CSCTRL0 & TMR_CSCTRL_TCF1);
bool interrupt2 = (TMR3_CSCTRL1 & TMR_CSCTRL_TCF1);
bool interrupt3 = (TMR3_CSCTRL2 & TMR_CSCTRL_TCF1);
bool interrupt4 = (TMR3_CSCTRL3 & TMR_CSCTRL_TCF1);
if(interrupt1) { TMR3_CSCTRL0 &= ~TMR_CSCTRL_TCF1; fuelSchedule5Interrupt(); }
else if(interrupt2) { TMR3_CSCTRL1 &= ~TMR_CSCTRL_TCF1; fuelSchedule6Interrupt(); }
else if(interrupt3) { TMR3_CSCTRL2 &= ~TMR_CSCTRL_TCF1; fuelSchedule7Interrupt(); }
else if(interrupt4) { TMR3_CSCTRL3 &= ~TMR_CSCTRL_TCF1; fuelSchedule8Interrupt(); }
if(interrupt1)
{
TMR3_CSCTRL0 &= ~TMR_CSCTRL_TCF1;
fuelSchedule5Interrupt();
}
else if(interrupt2)
{
TMR3_CSCTRL1 &= ~TMR_CSCTRL_TCF1;
fuelSchedule6Interrupt();
}
else if(interrupt3)
{
TMR3_CSCTRL2 &= ~TMR_CSCTRL_TCF1;
fuelSchedule7Interrupt();
}
else if(interrupt4)
{
TMR3_CSCTRL3 &= ~TMR_CSCTRL_TCF1;
fuelSchedule8Interrupt();
}
}
void TMR4_isr(void)
{
//TMR4 is IGN channels 5-8
// TMR4 is IGN channels 5-8
bool interrupt1 = (TMR4_CSCTRL0 & TMR_CSCTRL_TCF1);
bool interrupt2 = (TMR4_CSCTRL1 & TMR_CSCTRL_TCF1);
bool interrupt3 = (TMR4_CSCTRL2 & TMR_CSCTRL_TCF1);
bool interrupt4 = (TMR4_CSCTRL3 & TMR_CSCTRL_TCF1);
if(interrupt1) { TMR4_CSCTRL0 &= ~TMR_CSCTRL_TCF1; ignitionSchedule5Interrupt(); }
else if(interrupt2) { TMR4_CSCTRL1 &= ~TMR_CSCTRL_TCF1; ignitionSchedule6Interrupt(); }
else if(interrupt3) { TMR4_CSCTRL2 &= ~TMR_CSCTRL_TCF1; ignitionSchedule7Interrupt(); }
else if(interrupt4) { TMR4_CSCTRL3 &= ~TMR_CSCTRL_TCF1; ignitionSchedule8Interrupt(); }
if(interrupt1)
{
TMR4_CSCTRL0 &= ~TMR_CSCTRL_TCF1;
ignitionSchedule5Interrupt();
}
else if(interrupt2)
{
TMR4_CSCTRL1 &= ~TMR_CSCTRL_TCF1;
ignitionSchedule6Interrupt();
}
else if(interrupt3)
{
TMR4_CSCTRL2 &= ~TMR_CSCTRL_TCF1;
ignitionSchedule7Interrupt();
}
else if(interrupt4)
{
TMR4_CSCTRL3 &= ~TMR_CSCTRL_TCF1;
ignitionSchedule8Interrupt();
}
}
uint16_t freeRam()
{
uint32_t stackTop;
uint32_t heapTop;
uint32_t stackTop;
uint32_t heapTop;
// current position of the stack.
stackTop = (uint32_t) &stackTop;
// current position of the stack.
stackTop = (uint32_t)&stackTop;
// current position of heap.
void* hTop = malloc(1);
heapTop = (uint32_t) hTop;
free(hTop);
// current position of heap.
void *hTop = malloc(1);
heapTop = (uint32_t)hTop;
free(hTop);
// The difference is the free, available ram.
return (uint16_t)stackTop - heapTop;
// The difference is the free, available ram.
return (uint16_t)stackTop - heapTop;
}
//This function is used for attempting to set the RTC time during compile
time_t getTeensy3Time()
{
return Teensy3Clock.get();
}
// This function is used for attempting to set the RTC time during compile
time_t getTeensy3Time() { return Teensy3Clock.get(); }
void doSystemReset() { return; }
void jumpToBootloader() { return; }
void setTriggerHysteresis()
{
//Refer to digital.c in the Teensyduino core for the following code
//Refer also to Pgs 382 and 950 of the iMXRT1060 Reference Manual
// Refer to digital.c in the Teensyduino core for the following code
// Refer also to Pgs 382 and 950 of the iMXRT1060 Reference Manual
const struct digital_pin_bitband_and_config_table_struct *p;
const uint32_t padConfig = IOMUXC_PAD_DSE(1) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_SPEED(0) | IOMUXC_PAD_HYS;
const uint32_t padConfig = IOMUXC_PAD_DSE(1) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_SPEED(0) | IOMUXC_PAD_HYS;
//Primary trigger
// Primary trigger
p = digital_pin_to_info_PGM + pinTrigger;
*(p->reg + 1) &= ~(p->mask); // TODO: atomic
*(p->pad) = padConfig;
*(p->mux) = 5 | 0x10;
//Secondary trigger
// Secondary trigger
p = digital_pin_to_info_PGM + pinTrigger2;
*(p->reg + 1) &= ~(p->mask); // TODO: atomic
*(p->pad) = padConfig;

View File

@ -1,38 +1,35 @@
#if defined(CORE_TEMPLATE)
#include "globals.h"
#include "globals.h"
void initBoard()
{
/*
***********************************************************************************************************
* General
*/
/*
***********************************************************************************************************
* General
*/
/*
***********************************************************************************************************
* Timers
*/
/*
***********************************************************************************************************
* Timers
*/
/*
***********************************************************************************************************
* Auxiliaries
*/
/*
***********************************************************************************************************
* Auxiliaries
*/
/*
***********************************************************************************************************
* Idle
*/
/*
***********************************************************************************************************
* Idle
*/
/*
***********************************************************************************************************
* Schedules
*/
/*
***********************************************************************************************************
* Schedules
*/
}
uint16_t freeRam()
{
}
uint16_t freeRam() {}
void doSystemReset() { return; }
void jumpToBootloader() { return; }

View File

@ -8,7 +8,7 @@ A full copy of the license may be found in the projects root directory
This is for handling the data broadcasted to various CAN dashes and instrument clusters.
*/
#if defined(NATIVE_CAN_AVAILABLE)
#include "globals.h"
#include "globals.h"
// Forward declare
void DashMessage(uint16_t DashMessageID);
@ -34,76 +34,76 @@ void sendVAGCluster()
// switch case for gathering all data to message based on CAN Id.
void DashMessage(uint16_t DashMessageID)
{
switch (DashMessageID)
switch(DashMessageID)
{
case CAN_BMW_DME1:
uint32_t temp_RPM;
temp_RPM = currentStatus.RPM * 64; //RPM conversion is currentStatus.RPM * 6.4, but this does it without floats.
temp_RPM = temp_RPM / 10;
outMsg.id = DashMessageID;
outMsg.len = 8;
outMsg.buf[0] = 0x05; //bitfield, Bit0 = 1 = terminal 15 on detected, Bit2 = 1 = the ASC message ASC1 was received within the last 500 ms and contains no plausibility errors
outMsg.buf[1] = 0x0C; //Indexed Engine Torque in % of C_TQ_STND TBD do torque calculation.
outMsg.buf[2] = lowByte(uint16_t(temp_RPM)); //lsb RPM
outMsg.buf[3] = highByte(uint16_t(temp_RPM)); //msb RPM
outMsg.buf[4] = 0x0C; //Indicated Engine Torque in % of C_TQ_STND TBD do torque calculation!! Use same as for byte 1
outMsg.buf[5] = 0x15; //Engine Torque Loss (due to engine friction, AC compressor and electrical power consumption)
outMsg.buf[6] = 0x00; //not used
outMsg.buf[7] = 0x35; //Theorethical Engine Torque in % of C_TQ_STND after charge intervention
break;
temp_RPM = currentStatus.RPM * 64; // RPM conversion is currentStatus.RPM * 6.4, but this does it without floats.
temp_RPM = temp_RPM / 10;
outMsg.id = DashMessageID;
outMsg.len = 8;
outMsg.buf[0] = 0x05; // bitfield, Bit0 = 1 = terminal 15 on detected, Bit2 = 1 = the ASC message ASC1 was received within the last 500 ms and contains no plausibility errors
outMsg.buf[1] = 0x0C; // Indexed Engine Torque in % of C_TQ_STND TBD do torque calculation.
outMsg.buf[2] = lowByte(uint16_t(temp_RPM)); // lsb RPM
outMsg.buf[3] = highByte(uint16_t(temp_RPM)); // msb RPM
outMsg.buf[4] = 0x0C; // Indicated Engine Torque in % of C_TQ_STND TBD do torque calculation!! Use same as for byte 1
outMsg.buf[5] = 0x15; // Engine Torque Loss (due to engine friction, AC compressor and electrical power consumption)
outMsg.buf[6] = 0x00; // not used
outMsg.buf[7] = 0x35; // Theorethical Engine Torque in % of C_TQ_STND after charge intervention
break;
case CAN_BMW_DME2:
uint8_t temp_TPS;
uint8_t temp_BARO;
uint8_t temp_TPS;
uint8_t temp_BARO;
uint16_t temp_CLT;
temp_TPS = map(currentStatus.TPS, 0, 100, 0, 254);//TPS value conversion (from 0x00 to 0xFE)
temp_CLT = (((currentStatus.coolant - CALIBRATION_TEMPERATURE_OFFSET) + 48)*4/3); //CLT conversion (actual value to add is 48.373, but close enough)
if (temp_CLT > 255) { temp_CLT = 255; } //CLT conversion can yield to higher values than what fits to byte, so limit the maximum value to 255.
temp_TPS = map(currentStatus.TPS, 0, 100, 0, 254); // TPS value conversion (from 0x00 to 0xFE)
temp_CLT = (((currentStatus.coolant - CALIBRATION_TEMPERATURE_OFFSET) + 48) * 4 / 3); // CLT conversion (actual value to add is 48.373, but close enough)
if(temp_CLT > 255) { temp_CLT = 255; } // CLT conversion can yield to higher values than what fits to byte, so limit the maximum value to 255.
temp_BARO = currentStatus.baro;
outMsg.id = DashMessageID;
outMsg.len = 7;
outMsg.buf[0] = 0x11; //Multiplexed Information
outMsg.id = DashMessageID;
outMsg.len = 7;
outMsg.buf[0] = 0x11; // Multiplexed Information
outMsg.buf[1] = temp_CLT;
outMsg.buf[2] = temp_BARO;
outMsg.buf[3] = 0x08; //bitfield, Bit0 = 0 = Clutch released, Bit 3 = 1 = engine running
outMsg.buf[4] = 0x00; //TPS_VIRT_CRU_CAN (Not used)
outMsg.buf[3] = 0x08; // bitfield, Bit0 = 0 = Clutch released, Bit 3 = 1 = engine running
outMsg.buf[4] = 0x00; // TPS_VIRT_CRU_CAN (Not used)
outMsg.buf[5] = temp_TPS;
outMsg.buf[6] = 0x00; //bitfield, Bit0 = 0 = brake not actuated, Bit1 = 0 = brake switch system OK etc...
outMsg.buf[7] = 0x00; //not used, but set to zero just in case.
break;
outMsg.buf[6] = 0x00; // bitfield, Bit0 = 0 = brake not actuated, Bit1 = 0 = brake switch system OK etc...
outMsg.buf[7] = 0x00; // not used, but set to zero just in case.
break;
case 0x545: //fuel consumption and CEl light for BMW e46/e39/e38 instrument cluster
//fuel consumption calculation not implemented yet. But this still needs to be sent to get rid of the CEL and EML fault lights on the dash.
outMsg.id = DashMessageID;
outMsg.len = 5;
outMsg.buf[0] = 0x00; //Check engine light (binary 10), Cruise light (binary 1000), EML (binary 10000).
outMsg.buf[1] = 0x00; //LSB Fuel consumption
outMsg.buf[2] = 0x00; //MSB Fuel Consumption
if (currentStatus.coolant > 159) { outMsg.buf[3] = 0x08; } //Turn on overheat light if coolant temp hits 120 degrees celsius.
else { outMsg.buf[3] = 0x00; } //Overheat light off at normal engine temps.
outMsg.buf[4] = 0x7E; //this is oil temp
break;
case 0x545: // fuel consumption and CEl light for BMW e46/e39/e38 instrument cluster
// fuel consumption calculation not implemented yet. But this still needs to be sent to get rid of the CEL and EML fault lights on the dash.
outMsg.id = DashMessageID;
outMsg.len = 5;
outMsg.buf[0] = 0x00; // Check engine light (binary 10), Cruise light (binary 1000), EML (binary 10000).
outMsg.buf[1] = 0x00; // LSB Fuel consumption
outMsg.buf[2] = 0x00; // MSB Fuel Consumption
if(currentStatus.coolant > 159) { outMsg.buf[3] = 0x08; } // Turn on overheat light if coolant temp hits 120 degrees celsius.
else { outMsg.buf[3] = 0x00; } // Overheat light off at normal engine temps.
outMsg.buf[4] = 0x7E; // this is oil temp
break;
case 0x280: //RPM for VW instrument cluster
temp_RPM = currentStatus.RPM * 4; //RPM conversion
outMsg.id = DashMessageID;
outMsg.len = 8;
case 0x280: // RPM for VW instrument cluster
temp_RPM = currentStatus.RPM * 4; // RPM conversion
outMsg.id = DashMessageID;
outMsg.len = 8;
outMsg.buf[0] = 0x49;
outMsg.buf[1] = 0x0E;
outMsg.buf[2] = lowByte(uint16_t(temp_RPM)); //lsb RPM
outMsg.buf[3] = highByte(uint16_t(temp_RPM)); //msb RPM
outMsg.buf[2] = lowByte(uint16_t(temp_RPM)); // lsb RPM
outMsg.buf[3] = highByte(uint16_t(temp_RPM)); // msb RPM
outMsg.buf[4] = 0x0E;
outMsg.buf[5] = 0x00;
outMsg.buf[6] = 0x1B;
outMsg.buf[7] = 0x0E;
break;
break;
case 0x5A0: //VSS for VW instrument cluster
case 0x5A0: // VSS for VW instrument cluster
uint16_t temp_VSS;
temp_VSS = currentStatus.vss * 133; //VSS conversion
outMsg.id = DashMessageID;
outMsg.len = 8;
temp_VSS = currentStatus.vss * 133; // VSS conversion
outMsg.id = DashMessageID;
outMsg.len = 8;
outMsg.buf[0] = 0xFF;
outMsg.buf[1] = lowByte(temp_VSS);
outMsg.buf[2] = highByte(temp_VSS);
@ -112,10 +112,9 @@ void DashMessage(uint16_t DashMessageID)
outMsg.buf[5] = 0x00;
outMsg.buf[6] = 0x00;
outMsg.buf[7] = 0xAD;
break;
break;
default:
break;
default: break;
}
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,166 +4,181 @@
#include "timers.h"
#include "maths.h"
volatile uint16_t timePerDegree;
volatile uint16_t timePerDegreex16;
volatile uint16_t degreesPeruSx2048;
volatile uint16_t timePerDegree;
volatile uint16_t timePerDegreex16;
volatile uint16_t degreesPeruSx2048;
volatile unsigned long degreesPeruSx32768;
//These are only part of the experimental 2nd deriv calcs
byte deltaToothCount = 0; //The last tooth that was used with the deltaV calc
int rpmDelta;
// These are only part of the experimental 2nd deriv calcs
byte deltaToothCount = 0; // The last tooth that was used with the deltaV calc
int rpmDelta;
/*
* Converts a crank angle into a time from or since that angle occurred.
* Positive angles are assumed to be in the future, negative angles in the past:
* * Future angle calculations will use a predicted speed/acceleration
* * Past angle calculations will use the known speed
*
* Currently 4 methods are planned and/or available:
* 1) Last interval based on a full revolution
* 2) Last interval based on the time between the last 2 teeth (Crank Pattern dependent)
* 3) Closed loop error correction (Alpha-beta filter)
* 4) 2nd derivative prediction (Speed + acceleration)
*/
* Converts a crank angle into a time from or since that angle occurred.
* Positive angles are assumed to be in the future, negative angles in the past:
* * Future angle calculations will use a predicted speed/acceleration
* * Past angle calculations will use the known speed
*
* Currently 4 methods are planned and/or available:
* 1) Last interval based on a full revolution
* 2) Last interval based on the time between the last 2 teeth (Crank Pattern dependent)
* 3) Closed loop error correction (Alpha-beta filter)
* 4) 2nd derivative prediction (Speed + acceleration)
*/
unsigned long angleToTime(uint16_t angle, byte method)
{
unsigned long returnTime = 0;
unsigned long returnTime = 0;
if( (method == CRANKMATH_METHOD_INTERVAL_REV) || (method == CRANKMATH_METHOD_INTERVAL_DEFAULT) )
if((method == CRANKMATH_METHOD_INTERVAL_REV) || (method == CRANKMATH_METHOD_INTERVAL_DEFAULT))
{
returnTime = angleToTimeIntervalRev(angle);
// returnTime = angle * (unsigned long)timePerDegree;
}
else if(method == CRANKMATH_METHOD_INTERVAL_TOOTH)
{
// Still uses a last interval method (ie retrospective), but bases the interval on the gap between the 2 most recent teeth rather than the last full revolution
if(BIT_CHECK(decoderState, BIT_DECODER_TOOTH_ANG_CORRECT))
{
returnTime = angleToTimeIntervalRev(angle);
//returnTime = angle * (unsigned long)timePerDegree;
}
else if (method == CRANKMATH_METHOD_INTERVAL_TOOTH)
{
//Still uses a last interval method (ie retrospective), but bases the interval on the gap between the 2 most recent teeth rather than the last full revolution
if(BIT_CHECK(decoderState, BIT_DECODER_TOOTH_ANG_CORRECT))
{
noInterrupts();
unsigned long toothTime = (toothLastToothTime - toothLastMinusOneToothTime);
uint16_t tempTriggerToothAngle = triggerToothAngle; // triggerToothAngle is set by interrupts
interrupts();
returnTime = ( (toothTime * angle) / tempTriggerToothAngle );
}
else { returnTime = angleToTime(angle, CRANKMATH_METHOD_INTERVAL_REV); } //Safety check. This can occur if the last tooth seen was outside the normal pattern etc
}
noInterrupts();
unsigned long toothTime = (toothLastToothTime - toothLastMinusOneToothTime);
uint16_t tempTriggerToothAngle = triggerToothAngle; // triggerToothAngle is set by interrupts
interrupts();
return returnTime;
returnTime = ((toothTime * angle) / tempTriggerToothAngle);
}
else { returnTime = angleToTime(angle, CRANKMATH_METHOD_INTERVAL_REV); } // Safety check. This can occur if the last tooth seen was outside the normal pattern etc
}
return returnTime;
}
/*
* Convert a time (uS) into an angle at current speed
* Currently 4 methods are planned and/or available:
* 1) Last interval based on a full revolution
* 2) Last interval based on the time between the last 2 teeth (Crank Pattern dependent)
* 3) Closed loop error correction (Alpha-beta filter)
* 4) 2nd derivative prediction (Speed + acceleration)
*/
* Convert a time (uS) into an angle at current speed
* Currently 4 methods are planned and/or available:
* 1) Last interval based on a full revolution
* 2) Last interval based on the time between the last 2 teeth (Crank Pattern dependent)
* 3) Closed loop error correction (Alpha-beta filter)
* 4) 2nd derivative prediction (Speed + acceleration)
*/
uint16_t timeToAngle(unsigned long time, byte method)
{
uint16_t returnAngle = 0;
uint16_t returnAngle = 0;
if( (method == CRANKMATH_METHOD_INTERVAL_REV) || (method == CRANKMATH_METHOD_INTERVAL_DEFAULT) )
if((method == CRANKMATH_METHOD_INTERVAL_REV) || (method == CRANKMATH_METHOD_INTERVAL_DEFAULT))
{
// A last interval method of calculating angle that does not take into account any acceleration. The interval used is the time taken to complete the last full revolution
// degreesPeruSx2048 is the number of degrees the crank moves per uS. This value is almost always <1uS, so it is multiplied by 2048. This allows an angle calculation with only a multiply and a bitshift without any appreciable drop in accuracy
returnAngle = fastTimeToAngle(time);
}
else if(method == CRANKMATH_METHOD_INTERVAL_TOOTH)
{
// Still uses a last interval method (ie retrospective), but bases the interval on the gap between the 2 most recent teeth rather than the last full revolution
if(BIT_CHECK(decoderState, BIT_DECODER_TOOTH_ANG_CORRECT))
{
//A last interval method of calculating angle that does not take into account any acceleration. The interval used is the time taken to complete the last full revolution
//degreesPeruSx2048 is the number of degrees the crank moves per uS. This value is almost always <1uS, so it is multiplied by 2048. This allows an angle calculation with only a multiply and a bitshift without any appreciable drop in accuracy
returnAngle = fastTimeToAngle(time);
}
else if (method == CRANKMATH_METHOD_INTERVAL_TOOTH)
{
//Still uses a last interval method (ie retrospective), but bases the interval on the gap between the 2 most recent teeth rather than the last full revolution
if(BIT_CHECK(decoderState, BIT_DECODER_TOOTH_ANG_CORRECT))
{
noInterrupts();
unsigned long toothTime = (toothLastToothTime - toothLastMinusOneToothTime);
uint16_t tempTriggerToothAngle = triggerToothAngle; // triggerToothAngle is set by interrupts
interrupts();
noInterrupts();
unsigned long toothTime = (toothLastToothTime - toothLastMinusOneToothTime);
uint16_t tempTriggerToothAngle = triggerToothAngle; // triggerToothAngle is set by interrupts
interrupts();
returnAngle = ( (unsigned long)(time * tempTriggerToothAngle) / toothTime );
}
else { returnAngle = timeToAngle(time, CRANKMATH_METHOD_INTERVAL_REV); } //Safety check. This can occur if the last tooth seen was outside the normal pattern etc
}
else if (method == CRANKMATH_METHOD_ALPHA_BETA)
{
//Not yet implemented. Default to Rev
returnAngle = timeToAngle(time, CRANKMATH_METHOD_INTERVAL_REV);
}
else if (method == CRANKMATH_METHOD_2ND_DERIVATIVE)
{
//Not yet implemented. Default to Rev
returnAngle = timeToAngle(time, CRANKMATH_METHOD_INTERVAL_REV);
returnAngle = ((unsigned long)(time * tempTriggerToothAngle) / toothTime);
}
else { returnAngle = timeToAngle(time, CRANKMATH_METHOD_INTERVAL_REV); } // Safety check. This can occur if the last tooth seen was outside the normal pattern etc
}
else if(method == CRANKMATH_METHOD_ALPHA_BETA)
{
// Not yet implemented. Default to Rev
returnAngle = timeToAngle(time, CRANKMATH_METHOD_INTERVAL_REV);
}
else if(method == CRANKMATH_METHOD_2ND_DERIVATIVE)
{
// Not yet implemented. Default to Rev
returnAngle = timeToAngle(time, CRANKMATH_METHOD_INTERVAL_REV);
}
return returnAngle;
return returnAngle;
}
void doCrankSpeedCalcs(void)
{
//********************************************************
//How fast are we going? Need to know how long (uS) it will take to get from one tooth to the next. We then use that to estimate how far we are between the last tooth and the next one
//We use a 1st Deriv acceleration prediction, but only when there is an even spacing between primary sensor teeth
//Any decoder that has uneven spacing has its triggerToothAngle set to 0
//THIS IS CURRENTLY DISABLED FOR ALL DECODERS! It needs more work.
if( SECOND_DERIV_ENABLED && (BIT_CHECK(decoderState, BIT_DECODER_2ND_DERIV)) && (toothHistoryIndex >= 3) && (currentStatus.RPM < 2000) ) //toothHistoryIndex must be greater than or equal to 3 as we need the last 3 entries. Currently this mode only runs below 3000 rpm
//********************************************************
// How fast are we going? Need to know how long (uS) it will take to get from one tooth to the next. We then use that to estimate how far we are between the last tooth and the next one
// We use a 1st Deriv acceleration prediction, but only when there is an even spacing between primary sensor teeth
// Any decoder that has uneven spacing has its triggerToothAngle set to 0
// THIS IS CURRENTLY DISABLED FOR ALL DECODERS! It needs more work.
if(SECOND_DERIV_ENABLED && (BIT_CHECK(decoderState, BIT_DECODER_2ND_DERIV)) && (toothHistoryIndex >= 3) && (currentStatus.RPM < 2000)) // toothHistoryIndex must be greater than or equal to 3 as we need the last 3 entries. Currently this mode only runs below 3000 rpm
{
// Only recalculate deltaV if the tooth has changed since last time (DeltaV stays the same until the next tooth)
// if (deltaToothCount != toothCurrentCount)
{
deltaToothCount = toothCurrentCount;
int angle1, angle2; // These represent the crank angles that are travelled for the last 2 pulses
if(configPage4.TrigPattern == 4)
{
//Only recalculate deltaV if the tooth has changed since last time (DeltaV stays the same until the next tooth)
//if (deltaToothCount != toothCurrentCount)
{
deltaToothCount = toothCurrentCount;
int angle1, angle2; //These represent the crank angles that are travelled for the last 2 pulses
if(configPage4.TrigPattern == 4)
{
//Special case for 70/110 pattern on 4g63
angle2 = triggerToothAngle; //Angle 2 is the most recent
if (angle2 == 70) { angle1 = 110; }
else { angle1 = 70; }
}
else if(configPage4.TrigPattern == 0)
{
//Special case for missing tooth decoder where the missing tooth was one of the last 2 seen
if(toothCurrentCount == 1) { angle2 = 2*triggerToothAngle; angle1 = triggerToothAngle; }
else if(toothCurrentCount == 2) { angle1 = 2*triggerToothAngle; angle2 = triggerToothAngle; }
else { angle1 = triggerToothAngle; angle2 = triggerToothAngle; }
}
else { angle1 = triggerToothAngle; angle2 = triggerToothAngle; }
uint32_t toothDeltaV = (1000000L * angle2 / toothHistory[toothHistoryIndex]) - (1000000L * angle1 / toothHistory[toothHistoryIndex-1]);
uint32_t toothDeltaT = toothHistory[toothHistoryIndex];
//long timeToLastTooth = micros() - toothLastToothTime;
rpmDelta = (toothDeltaV << 10) / (6 * toothDeltaT);
}
timePerDegreex16 = ldiv( 2666656L, currentStatus.RPM + rpmDelta).quot; //This gives accuracy down to 0.1 of a degree and can provide noticeably better timing results on low resolution triggers
timePerDegree = timePerDegreex16 / 16;
// Special case for 70/110 pattern on 4g63
angle2 = triggerToothAngle; // Angle 2 is the most recent
if(angle2 == 70) { angle1 = 110; }
else { angle1 = 70; }
}
else
else if(configPage4.TrigPattern == 0)
{
//If we can, attempt to get the timePerDegree by comparing the times of the last two teeth seen. This is only possible for evenly spaced teeth
noInterrupts();
if( (BIT_CHECK(decoderState, BIT_DECODER_TOOTH_ANG_CORRECT)) && (toothLastToothTime > toothLastMinusOneToothTime) && (abs(currentStatus.rpmDOT) > 30) )
// Special case for missing tooth decoder where the missing tooth was one of the last 2 seen
if(toothCurrentCount == 1)
{
//noInterrupts();
unsigned long tempToothLastToothTime = toothLastToothTime;
unsigned long tempToothLastMinusOneToothTime = toothLastMinusOneToothTime;
uint16_t tempTriggerToothAngle = triggerToothAngle;
interrupts();
timePerDegreex16 = (unsigned long)( (tempToothLastToothTime - tempToothLastMinusOneToothTime)*16) / tempTriggerToothAngle;
timePerDegree = timePerDegreex16 / 16;
angle2 = 2 * triggerToothAngle;
angle1 = triggerToothAngle;
}
else if(toothCurrentCount == 2)
{
angle1 = 2 * triggerToothAngle;
angle2 = triggerToothAngle;
}
else
{
//long timeThisRevolution = (micros_safe() - toothOneTime);
interrupts();
//Take into account any likely acceleration that has occurred since the last full revolution completed:
//long rpm_adjust = (timeThisRevolution * (long)currentStatus.rpmDOT) / 1000000;
long rpm_adjust = 0;
timePerDegreex16 = ldiv( 2666656L, currentStatus.RPM + rpm_adjust).quot; //The use of a x16 value gives accuracy down to 0.1 of a degree and can provide noticeably better timing results on low resolution triggers
timePerDegree = timePerDegreex16 / 16;
angle1 = triggerToothAngle;
angle2 = triggerToothAngle;
}
}
degreesPeruSx2048 = 2048 / timePerDegree;
degreesPeruSx32768 = 524288 / timePerDegreex16;
else
{
angle1 = triggerToothAngle;
angle2 = triggerToothAngle;
}
uint32_t toothDeltaV = (1000000L * angle2 / toothHistory[toothHistoryIndex]) - (1000000L * angle1 / toothHistory[toothHistoryIndex - 1]);
uint32_t toothDeltaT = toothHistory[toothHistoryIndex];
// long timeToLastTooth = micros() - toothLastToothTime;
rpmDelta = (toothDeltaV << 10) / (6 * toothDeltaT);
}
timePerDegreex16 = ldiv(2666656L, currentStatus.RPM + rpmDelta).quot; // This gives accuracy down to 0.1 of a degree and can provide noticeably better timing results on low resolution triggers
timePerDegree = timePerDegreex16 / 16;
}
else
{
// If we can, attempt to get the timePerDegree by comparing the times of the last two teeth seen. This is only possible for evenly spaced teeth
noInterrupts();
if((BIT_CHECK(decoderState, BIT_DECODER_TOOTH_ANG_CORRECT)) && (toothLastToothTime > toothLastMinusOneToothTime) && (abs(currentStatus.rpmDOT) > 30))
{
// noInterrupts();
unsigned long tempToothLastToothTime = toothLastToothTime;
unsigned long tempToothLastMinusOneToothTime = toothLastMinusOneToothTime;
uint16_t tempTriggerToothAngle = triggerToothAngle;
interrupts();
timePerDegreex16 = (unsigned long)((tempToothLastToothTime - tempToothLastMinusOneToothTime) * 16) / tempTriggerToothAngle;
timePerDegree = timePerDegreex16 / 16;
}
else
{
// long timeThisRevolution = (micros_safe() - toothOneTime);
interrupts();
// Take into account any likely acceleration that has occurred since the last full revolution completed:
// long rpm_adjust = (timeThisRevolution * (long)currentStatus.rpmDOT) / 1000000;
long rpm_adjust = 0;
timePerDegreex16 = ldiv(2666656L, currentStatus.RPM + rpm_adjust).quot; // The use of a x16 value gives accuracy down to 0.1 of a degree and can provide noticeably better timing results on low resolution triggers
timePerDegree = timePerDegreex16 / 16;
}
}
degreesPeruSx2048 = 2048 / timePerDegree;
degreesPeruSx32768 = 524288 / timePerDegreex16;
}

File diff suppressed because it is too large Load Diff

View File

@ -6,189 +6,181 @@ A full copy of the license may be found in the projects root directory
#ifdef USE_DISPLAY
#include <SPI.h>
#include <Wire.h>
#include "src/Adafruit_SSD1306/Adafruit_GFX.h"
#include "src/Adafruit_SSD1306/Adafruit_SSD1306.h"
#include <SPI.h>
#include <Wire.h>
#include "src/Adafruit_SSD1306/Adafruit_GFX.h"
#include "src/Adafruit_SSD1306/Adafruit_SSD1306.h"
Adafruit_SSD1306 display(pinDisplayReset);
void initialiseDisplay()
{
//Protection against older pin mappings where the crank/cam signals were on the SDA and SCL pins. This will cause the Arduino to lock hard if you try to initialise i2c devices when a crank signal is coming in
// Protection against older pin mappings where the crank/cam signals were on the SDA and SCL pins. This will cause the Arduino to lock hard if you try to initialise i2c devices when a crank signal is coming in
if(pinTrigger == 20 || pinTrigger == 21 || pinTrigger2 == 20 || pinTrigger2 == 21) { return; }
switch(configPage1.displayType)
{
case 1:
display.SSD1306_SETCOMPINS_V = 0x02;
break;
case 2:
display.SSD1306_SETCOMPINS_V = 0x12;
break;
case 3:
display.SSD1306_SETCOMPINS_V = 0x12;
break;
case 4:
display.SSD1306_SETCOMPINS_V = 0x12;
break;
}
switch(configPage1.displayType)
{
case 1: display.SSD1306_SETCOMPINS_V = 0x02; break;
case 2: display.SSD1306_SETCOMPINS_V = 0x12; break;
case 3: display.SSD1306_SETCOMPINS_V = 0x12; break;
case 4: display.SSD1306_SETCOMPINS_V = 0x12; break;
}
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialise with the I2C addr 0x3C (for the 128x32)
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.print("RPM: ");
display.setCursor(0,16);
display.print("CPU: ");
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialise with the I2C addr 0x3C (for the 128x32)
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.print("RPM: ");
display.setCursor(0, 16);
display.print("CPU: ");
}
void updateDisplay()
{
display.clearDisplay();
display.setCursor(0,0);
display.setCursor(0, 0);
switch(configPage1.display1)
{
case 0:
display.print("RPM: ");
display.setCursor(28,0);
display.setCursor(28, 0);
display.print(currentStatus.RPM);
break;
case 1:
display.print("PW: ");
display.setCursor(28,0);
display.setCursor(28, 0);
display.print(currentStatus.PW1);
break;
case 2:
display.print("Adv: ");
display.setCursor(28,0);
display.setCursor(28, 0);
display.print(currentStatus.advance);
break;
case 3:
display.print("VE: ");
display.setCursor(28,0);
display.setCursor(28, 0);
display.print(currentStatus.VE);
break;
case 4:
display.print("GamE: ");
display.setCursor(28,0);
display.setCursor(28, 0);
display.print(currentStatus.corrections);
break;
case 5:
display.print("TPS: ");
display.setCursor(28,0);
display.setCursor(28, 0);
display.print(currentStatus.TPS);
break;
case 6:
display.print("IAT: ");
display.setCursor(28,0);
display.setCursor(28, 0);
display.print(currentStatus.IAT);
break;
case 7:
display.print("CLT: ");
display.setCursor(28,0);
display.setCursor(28, 0);
display.print(currentStatus.coolant);
break;
}
display.setCursor(0,11);
display.setCursor(0, 11);
switch(configPage1.display3)
{
case 0:
display.print("RPM: ");
display.setCursor(28,11);
display.setCursor(28, 11);
display.print(currentStatus.RPM);
break;
case 1:
display.print("PW: ");
display.setCursor(28,11);
display.setCursor(28, 11);
display.print(currentStatus.PW1);
break;
case 2:
display.print("Adv: ");
display.setCursor(28,11);
display.setCursor(28, 11);
display.print(currentStatus.advance);
break;
case 3:
display.print("VE: ");
display.setCursor(28,11);
display.setCursor(28, 11);
display.print(currentStatus.VE);
break;
case 4:
display.print("GamE: ");
display.setCursor(28,11);
display.setCursor(28, 11);
display.print(currentStatus.corrections);
break;
case 5:
display.print("TPS: ");
display.setCursor(28,11);
display.setCursor(28, 11);
display.print(currentStatus.TPS);
break;
case 6:
display.print("IAT: ");
display.setCursor(28,11);
display.setCursor(28, 11);
display.print(currentStatus.IAT);
break;
case 7:
display.print("CLT: ");
display.setCursor(28,11);
display.setCursor(28, 11);
display.print(currentStatus.coolant);
break;
}
display.setCursor(64,0);
display.setCursor(64, 0);
switch(configPage1.display2)
{
case 0:
display.print("O2: ");
display.setCursor(92,0);
display.setCursor(92, 0);
display.print(currentStatus.O2);
break;
case 1:
display.print("Vdc: ");
display.setCursor(92,0);
display.setCursor(92, 0);
display.print(currentStatus.battery10);
break;
case 2:
display.print("CPU: ");
display.setCursor(92,0);
display.setCursor(92, 0);
display.print(currentStatus.loopsPerSecond);
break;
case 3:
display.print("Mem: ");
display.setCursor(92,0);
display.setCursor(92, 0);
display.print(currentStatus.freeRAM);
break;
}
display.setCursor(64,11);
display.setCursor(64, 11);
switch(configPage1.display4)
{
case 0:
display.print("O2: ");
display.setCursor(92,11);
display.setCursor(92, 11);
display.print(currentStatus.O2);
break;
case 1:
display.print("Vdc: ");
display.setCursor(92,11);
display.setCursor(92, 11);
display.print(currentStatus.battery10);
break;
case 2:
display.print("CPU: ");
display.setCursor(92,11);
display.setCursor(92, 11);
display.print(currentStatus.loopsPerSecond);
break;
case 3:
display.print("Mem: ");
display.setCursor(92,11);
display.setCursor(92, 11);
display.print(currentStatus.freeRAM);
break;
}
int barWidth = ldiv(((unsigned long)currentStatus.RPM * 128), 9000).quot;
//int barWidth = map(currentStatus.RPM, 0, 9000, 0, 128);
// int barWidth = map(currentStatus.RPM, 0, 9000, 0, 128);
display.fillRect(0, 20, barWidth, 10, 1);
display.display();

View File

@ -7,9 +7,9 @@ byte oilProtStartTime = 0;
byte checkEngineProtect(void)
{
byte protectActive = 0;
if(checkBoostLimit() || checkOilPressureLimit() || checkAFRLimit() )
if(checkBoostLimit() || checkOilPressureLimit() || checkAFRLimit())
{
if( currentStatus.RPMdiv100 > configPage4.engineProtectMaxRPM ) { protectActive = 1; }
if(currentStatus.RPMdiv100 > configPage4.engineProtectMaxRPM) { protectActive = 1; }
}
return protectActive;
@ -17,33 +17,33 @@ byte checkEngineProtect(void)
byte checkRevLimit(void)
{
//Hardcut RPM limit
byte currentLimitRPM = 255; //Default to no limit (In case PROTECT_CUT_OFF is selected)
// Hardcut RPM limit
byte currentLimitRPM = 255; // Default to no limit (In case PROTECT_CUT_OFF is selected)
BIT_CLEAR(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_RPM);
BIT_CLEAR(currentStatus.spark, BIT_SPARK_HRDLIM);
BIT_CLEAR(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_COOLANT);
if (configPage6.engineProtectType != PROTECT_CUT_OFF)
if(configPage6.engineProtectType != PROTECT_CUT_OFF)
{
if(configPage9.hardRevMode == HARD_REV_FIXED)
{
currentLimitRPM = configPage4.HardRevLim;
if ( (currentStatus.RPMdiv100 >= configPage4.HardRevLim) || ((softLimitTime > configPage4.SoftLimMax) && (currentStatus.RPMdiv100 >= configPage4.SoftRevLim)) )
{
BIT_SET(currentStatus.spark, BIT_SPARK_HRDLIM); //Legacy and likely to be removed at some point
if((currentStatus.RPMdiv100 >= configPage4.HardRevLim) || ((softLimitTime > configPage4.SoftLimMax) && (currentStatus.RPMdiv100 >= configPage4.SoftRevLim)))
{
BIT_SET(currentStatus.spark, BIT_SPARK_HRDLIM); // Legacy and likely to be removed at some point
BIT_SET(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_RPM);
}
}
else { BIT_CLEAR(currentStatus.spark, BIT_SPARK_HRDLIM); }
}
else if(configPage9.hardRevMode == HARD_REV_COOLANT )
else if(configPage9.hardRevMode == HARD_REV_COOLANT)
{
currentLimitRPM = (int16_t)(table2D_getValue(&coolantProtectTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET));
if(currentStatus.RPMdiv100 > currentLimitRPM)
{
BIT_SET(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_COOLANT);
BIT_SET(currentStatus.spark, BIT_SPARK_HRDLIM); //Legacy and likely to be removed at some point
BIT_SET(currentStatus.spark, BIT_SPARK_HRDLIM); // Legacy and likely to be removed at some point
BIT_SET(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_RPM);
}
}
}
}
@ -57,9 +57,10 @@ byte checkBoostLimit(void)
BIT_CLEAR(currentStatus.spark, BIT_SPARK_BOOSTCUT);
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_BOOSTCUT);
if (configPage6.engineProtectType != PROTECT_CUT_OFF) {
//Boost cutoff is very similar to launchControl, but with a check against MAP rather than a switch
if( (configPage6.boostCutEnabled > 0) && (currentStatus.MAP > (configPage6.boostLimit * 2)) ) //The boost limit is divided by 2 to allow a limit up to 511kPa
if(configPage6.engineProtectType != PROTECT_CUT_OFF)
{
// Boost cutoff is very similar to launchControl, but with a check against MAP rather than a switch
if((configPage6.boostCutEnabled > 0) && (currentStatus.MAP > (configPage6.boostLimit * 2))) // The boost limit is divided by 2 to allow a limit up to 511kPa
{
boostLimitActive = 1;
BIT_SET(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_MAP);
@ -94,28 +95,27 @@ byte checkBoostLimit(void)
byte checkOilPressureLimit(void)
{
byte oilProtectActive = 0;
bool alreadyActive = BIT_CHECK(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_OIL);
BIT_CLEAR(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_OIL); //Will be set true below if required
bool alreadyActive = BIT_CHECK(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_OIL);
BIT_CLEAR(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_OIL); // Will be set true below if required
if (configPage6.engineProtectType != PROTECT_CUT_OFF)
if(configPage6.engineProtectType != PROTECT_CUT_OFF)
{
if( (configPage10.oilPressureProtEnbl == true) && (configPage10.oilPressureEnable == true) )
if((configPage10.oilPressureProtEnbl == true) && (configPage10.oilPressureEnable == true))
{
byte oilLimit = table2D_getValue(&oilPressureProtectTable, currentStatus.RPMdiv100);
if(currentStatus.oilPressure < oilLimit)
{
//Check if this is the first time we've been below the limit
// Check if this is the first time we've been below the limit
if(oilProtStartTime == 0) { oilProtStartTime = (millis() / 100); }
/* Check if countdown has reached its target, if so then instruct to cut */
if( (uint8_t(millis()/100) >= (uint16_t(oilProtStartTime + configPage10.oilPressureProtTime)) ) || (alreadyActive > 0) )
if((uint8_t(millis() / 100) >= (uint16_t(oilProtStartTime + configPage10.oilPressureProtTime))) || (alreadyActive > 0))
{
BIT_SET(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_OIL);
oilProtectActive = 1;
}
}
else { oilProtStartTime = 0; } //Reset the timer
else { oilProtStartTime = 0; } // Reset the timer
}
}
@ -124,11 +124,11 @@ byte checkOilPressureLimit(void)
byte checkAFRLimit(void)
{
static bool checkAFRLimitActive = false;
static bool afrProtectCountEnabled = false;
static unsigned long afrProtectCount = 0;
static constexpr char X2_MULTIPLIER = 2;
static constexpr char X100_MULTIPLIER = 100;
static bool checkAFRLimitActive = false;
static bool afrProtectCountEnabled = false;
static unsigned long afrProtectCount = 0;
static constexpr char X2_MULTIPLIER = 2;
static constexpr char X100_MULTIPLIER = 100;
/*
To use this function, a wideband sensor is required.
@ -136,7 +136,7 @@ byte checkAFRLimit(void)
First of all, check whether engine protection is enabled,
thereafter check whether AFR protection is enabled and at last
if wideband sensor is used.
After confirmation, the following conditions has to be met:
- MAP above x kPa
- RPM above x
@ -161,7 +161,8 @@ byte checkAFRLimit(void)
- whether AFR protection is enabled
- whether wideband sensor is used
*/
if(configPage6.engineProtectType != PROTECT_CUT_OFF && configPage9.afrProtectEnabled && configPage6.egoType == EGO_TYPE_WIDE) {
if(configPage6.engineProtectType != PROTECT_CUT_OFF && configPage9.afrProtectEnabled && configPage6.egoType == EGO_TYPE_WIDE)
{
/* Conditions */
bool mapCondition = (currentStatus.MAP >= (configPage9.afrProtectMinMAP * X2_MULTIPLIER)) ? true : false;
bool rpmCondition = (currentStatus.RPMdiv100 >= configPage9.afrProtectMinRPM) ? true : false;
@ -176,42 +177,42 @@ byte checkAFRLimit(void)
bool afrCondition;
switch(configPage9.afrProtectEnabled)
{
case 1: afrCondition = (currentStatus.O2 >= configPage9.afrProtectDeviation) ? true : false; break; /* Fixed value */
case 1: afrCondition = (currentStatus.O2 >= configPage9.afrProtectDeviation) ? true : false; break; /* Fixed value */
case 2: afrCondition = (currentStatus.O2 >= (currentStatus.afrTarget + configPage9.afrProtectDeviation)) ? true : false; break; /* Deviation from target table */
default: afrCondition = false; /* Unknown mode. Shouldn't even get here */
default: afrCondition = false; /* Unknown mode. Shouldn't even get here */
}
/* Check if conditions above are fulfilled */
if(mapCondition && rpmCondition && tpsCondition && afrCondition)
if(mapCondition && rpmCondition && tpsCondition && afrCondition)
{
/* All conditions fulfilled - start counter for 'protection delay' */
if(!afrProtectCountEnabled)
if(!afrProtectCountEnabled)
{
afrProtectCountEnabled = true;
afrProtectCount = millis();
afrProtectCount = millis();
}
/* Check if countdown has reached its target, if so then instruct to cut */
if(millis() >= (afrProtectCount + (configPage9.afrProtectCutTime * X100_MULTIPLIER)))
if(millis() >= (afrProtectCount + (configPage9.afrProtectCutTime * X100_MULTIPLIER)))
{
checkAFRLimitActive = true;
BIT_SET(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_AFR);
}
}
else
}
else
{
/* Conditions have presumably changed - deactivate and reset counter */
if(afrProtectCountEnabled)
if(afrProtectCountEnabled)
{
afrProtectCountEnabled = false;
afrProtectCount = 0;
afrProtectCount = 0;
}
}
/* Check if condition for reactivation is fulfilled */
if(checkAFRLimitActive && (currentStatus.TPS <= configPage9.afrProtectReactivationTPS))
if(checkAFRLimitActive && (currentStatus.TPS <= configPage9.afrProtectReactivationTPS))
{
checkAFRLimitActive = false;
checkAFRLimitActive = false;
afrProtectCountEnabled = false;
BIT_CLEAR(currentStatus.engineProtectStatus, ENGINE_PROTECT_BIT_AFR);
}
@ -219,4 +220,3 @@ byte checkAFRLimit(void)
return checkAFRLimitActive;
}

View File

@ -20,7 +20,7 @@ byte setError(byte errorID)
{
errorCodes[errorCount] = errorID;
errorCount++;
if(errorCount == 1) { BIT_SET(currentStatus.spark, BIT_SPARK_ERROR); } //Enable the error indicator
if(errorCount == 1) { BIT_SET(currentStatus.spark, BIT_SPARK_ERROR); } // Enable the error indicator
}
return errorCount;
}
@ -29,7 +29,7 @@ void clearError(byte errorID)
{
byte clearedError = 255;
if (errorID == errorCodes[0]) { clearedError = 0; }
if(errorID == errorCodes[0]) { clearedError = 0; }
else if(errorID == errorCodes[1]) { clearedError = 1; }
else if(errorID == errorCodes[2]) { clearedError = 2; }
else if(errorID == errorCodes[3]) { clearedError = 3; }
@ -37,37 +37,36 @@ void clearError(byte errorID)
if(clearedError < MAX_ERRORS)
{
errorCodes[clearedError] = ERR_NONE;
//Clear the required error and move any from above it 'down' in the error array
for (byte x=clearedError; x < (errorCount-1); x++)
// Clear the required error and move any from above it 'down' in the error array
for(byte x = clearedError; x < (errorCount - 1); x++)
{
errorCodes[x] = errorCodes[x+1];
errorCodes[x+1] = ERR_NONE;
errorCodes[x] = errorCodes[x + 1];
errorCodes[x + 1] = ERR_NONE;
}
errorCount--;
if(errorCount == 0) { BIT_CLEAR(currentStatus.spark, BIT_SPARK_ERROR); } //Enable the error indicator
if(errorCount == 0) { BIT_CLEAR(currentStatus.spark, BIT_SPARK_ERROR); } // Enable the error indicator
}
}
byte getNextError(void)
{
packedError currentError;
byte currentErrorNum = 0;
byte currentErrorNum = 0;
if(errorCount > 0)
{
//We alternate through the errors once per second
currentErrorNum = currentStatus.secl % errorCount; //Which error number will be returned. This changes once per second.
// We alternate through the errors once per second
currentErrorNum = currentStatus.secl % errorCount; // Which error number will be returned. This changes once per second.
currentError.errorNum = currentErrorNum;
currentError.errorID = errorCodes[currentErrorNum];
currentError.errorID = errorCodes[currentErrorNum];
}
else
{
currentError.errorNum = 0;
currentError.errorID = 0;
currentError.errorID = 0;
}
return *(byte*)&currentError; //Ugly, but this forces the cast of the currentError struct to a byte.
return *(byte *)&currentError; // Ugly, but this forces the cast of the currentError struct to a byte.
}

View File

@ -5,310 +5,287 @@
const char TSfirmwareVersion[] PROGMEM = "Speeduino";
const byte data_structure_version = 2; //This identifies the data structure when reading / writing. (outdated ?)
const byte data_structure_version = 2; // This identifies the data structure when reading / writing. (outdated ?)
struct table3d16RpmLoad fuelTable; ///< 16x16 fuel map
struct table3d16RpmLoad fuelTable2; ///< 16x16 fuel map
struct table3d16RpmLoad ignitionTable; ///< 16x16 ignition map
struct table3d16RpmLoad ignitionTable2; ///< 16x16 ignition map
struct table3d16RpmLoad afrTable; ///< 16x16 afr target map
struct table3d8RpmLoad stagingTable; ///< 8x8 fuel staging table
struct table3d8RpmLoad boostTable; ///< 8x8 boost map
struct table3d8RpmLoad boostTableLookupDuty; ///< 8x8 boost map lookup table
struct table3d8RpmLoad vvtTable; ///< 8x8 vvt map
struct table3d8RpmLoad vvt2Table; ///< 8x8 vvt2 map
struct table3d8RpmLoad wmiTable; ///< 8x8 wmi map
trimTable3d trim1Table; ///< 6x6 Fuel trim 1 map
trimTable3d trim2Table; ///< 6x6 Fuel trim 2 map
trimTable3d trim3Table; ///< 6x6 Fuel trim 3 map
trimTable3d trim4Table; ///< 6x6 Fuel trim 4 map
trimTable3d trim5Table; ///< 6x6 Fuel trim 5 map
trimTable3d trim6Table; ///< 6x6 Fuel trim 6 map
trimTable3d trim7Table; ///< 6x6 Fuel trim 7 map
trimTable3d trim8Table; ///< 6x6 Fuel trim 8 map
struct table3d4RpmLoad dwellTable; ///< 4x4 Dwell map
struct table2D taeTable; ///< 4 bin TPS Acceleration Enrichment map (2D)
struct table2D maeTable;
struct table2D WUETable; ///< 10 bin Warm Up Enrichment map (2D)
struct table2D ASETable; ///< 4 bin After Start Enrichment map (2D)
struct table2D ASECountTable; ///< 4 bin After Start duration map (2D)
struct table2D PrimingPulseTable; ///< 4 bin Priming pulsewidth map (2D)
struct table2D crankingEnrichTable; ///< 4 bin cranking Enrichment map (2D)
struct table2D dwellVCorrectionTable; ///< 6 bin dwell voltage correction (2D)
struct table2D injectorVCorrectionTable; ///< 6 bin injector voltage correction (2D)
struct table2D injectorAngleTable; ///< 4 bin injector angle curve (2D)
struct table2D IATDensityCorrectionTable; ///< 9 bin inlet air temperature density correction (2D)
struct table2D baroFuelTable; ///< 8 bin baro correction curve (2D)
struct table2D IATRetardTable; ///< 6 bin ignition adjustment based on inlet air temperature (2D)
struct table2D idleTargetTable; ///< 10 bin idle target table for idle timing (2D)
struct table2D idleAdvanceTable; ///< 6 bin idle advance adjustment table based on RPM difference (2D)
struct table2D CLTAdvanceTable; ///< 6 bin ignition adjustment based on coolant temperature (2D)
struct table2D rotarySplitTable; ///< 8 bin ignition split curve for rotary leading/trailing (2D)
struct table2D flexFuelTable; ///< 6 bin flex fuel correction table for fuel adjustments (2D)
struct table2D flexAdvTable; ///< 6 bin flex fuel correction table for timing advance (2D)
struct table2D flexBoostTable; ///< 6 bin flex fuel correction table for boost adjustments (2D)
struct table2D fuelTempTable; ///< 6 bin flex fuel correction table for fuel adjustments (2D)
struct table2D knockWindowStartTable;
struct table2D knockWindowDurationTable;
struct table2D oilPressureProtectTable;
struct table2D wmiAdvTable; //6 bin wmi correction table for timing advance (2D)
struct table2D coolantProtectTable;
struct table2D fanPWMTable;
struct table2D rollingCutTable;
struct table3d16RpmLoad fuelTable; ///< 16x16 fuel map
struct table3d16RpmLoad fuelTable2; ///< 16x16 fuel map
struct table3d16RpmLoad ignitionTable; ///< 16x16 ignition map
struct table3d16RpmLoad ignitionTable2; ///< 16x16 ignition map
struct table3d16RpmLoad afrTable; ///< 16x16 afr target map
struct table3d8RpmLoad stagingTable; ///< 8x8 fuel staging table
struct table3d8RpmLoad boostTable; ///< 8x8 boost map
struct table3d8RpmLoad boostTableLookupDuty; ///< 8x8 boost map lookup table
struct table3d8RpmLoad vvtTable; ///< 8x8 vvt map
struct table3d8RpmLoad vvt2Table; ///< 8x8 vvt2 map
struct table3d8RpmLoad wmiTable; ///< 8x8 wmi map
trimTable3d trim1Table; ///< 6x6 Fuel trim 1 map
trimTable3d trim2Table; ///< 6x6 Fuel trim 2 map
trimTable3d trim3Table; ///< 6x6 Fuel trim 3 map
trimTable3d trim4Table; ///< 6x6 Fuel trim 4 map
trimTable3d trim5Table; ///< 6x6 Fuel trim 5 map
trimTable3d trim6Table; ///< 6x6 Fuel trim 6 map
trimTable3d trim7Table; ///< 6x6 Fuel trim 7 map
trimTable3d trim8Table; ///< 6x6 Fuel trim 8 map
struct table3d4RpmLoad dwellTable; ///< 4x4 Dwell map
struct table2D taeTable; ///< 4 bin TPS Acceleration Enrichment map (2D)
struct table2D maeTable;
struct table2D WUETable; ///< 10 bin Warm Up Enrichment map (2D)
struct table2D ASETable; ///< 4 bin After Start Enrichment map (2D)
struct table2D ASECountTable; ///< 4 bin After Start duration map (2D)
struct table2D PrimingPulseTable; ///< 4 bin Priming pulsewidth map (2D)
struct table2D crankingEnrichTable; ///< 4 bin cranking Enrichment map (2D)
struct table2D dwellVCorrectionTable; ///< 6 bin dwell voltage correction (2D)
struct table2D injectorVCorrectionTable; ///< 6 bin injector voltage correction (2D)
struct table2D injectorAngleTable; ///< 4 bin injector angle curve (2D)
struct table2D IATDensityCorrectionTable; ///< 9 bin inlet air temperature density correction (2D)
struct table2D baroFuelTable; ///< 8 bin baro correction curve (2D)
struct table2D IATRetardTable; ///< 6 bin ignition adjustment based on inlet air temperature (2D)
struct table2D idleTargetTable; ///< 10 bin idle target table for idle timing (2D)
struct table2D idleAdvanceTable; ///< 6 bin idle advance adjustment table based on RPM difference (2D)
struct table2D CLTAdvanceTable; ///< 6 bin ignition adjustment based on coolant temperature (2D)
struct table2D rotarySplitTable; ///< 8 bin ignition split curve for rotary leading/trailing (2D)
struct table2D flexFuelTable; ///< 6 bin flex fuel correction table for fuel adjustments (2D)
struct table2D flexAdvTable; ///< 6 bin flex fuel correction table for timing advance (2D)
struct table2D flexBoostTable; ///< 6 bin flex fuel correction table for boost adjustments (2D)
struct table2D fuelTempTable; ///< 6 bin flex fuel correction table for fuel adjustments (2D)
struct table2D knockWindowStartTable;
struct table2D knockWindowDurationTable;
struct table2D oilPressureProtectTable;
struct table2D wmiAdvTable; // 6 bin wmi correction table for timing advance (2D)
struct table2D coolantProtectTable;
struct table2D fanPWMTable;
struct table2D rollingCutTable;
/// volatile inj*_pin_port and inj*_pin_mask vars are for the direct port manipulation of the injectors, coils and aux outputs.
volatile PORT_TYPE *inj1_pin_port;
volatile PORT_TYPE *inj1_pin_port;
volatile PINMASK_TYPE inj1_pin_mask;
volatile PORT_TYPE *inj2_pin_port;
volatile PORT_TYPE *inj2_pin_port;
volatile PINMASK_TYPE inj2_pin_mask;
volatile PORT_TYPE *inj3_pin_port;
volatile PORT_TYPE *inj3_pin_port;
volatile PINMASK_TYPE inj3_pin_mask;
volatile PORT_TYPE *inj4_pin_port;
volatile PORT_TYPE *inj4_pin_port;
volatile PINMASK_TYPE inj4_pin_mask;
volatile PORT_TYPE *inj5_pin_port;
volatile PORT_TYPE *inj5_pin_port;
volatile PINMASK_TYPE inj5_pin_mask;
volatile PORT_TYPE *inj6_pin_port;
volatile PORT_TYPE *inj6_pin_port;
volatile PINMASK_TYPE inj6_pin_mask;
volatile PORT_TYPE *inj7_pin_port;
volatile PORT_TYPE *inj7_pin_port;
volatile PINMASK_TYPE inj7_pin_mask;
volatile PORT_TYPE *inj8_pin_port;
volatile PORT_TYPE *inj8_pin_port;
volatile PINMASK_TYPE inj8_pin_mask;
volatile PORT_TYPE *ign1_pin_port;
volatile PORT_TYPE *ign1_pin_port;
volatile PINMASK_TYPE ign1_pin_mask;
volatile PORT_TYPE *ign2_pin_port;
volatile PORT_TYPE *ign2_pin_port;
volatile PINMASK_TYPE ign2_pin_mask;
volatile PORT_TYPE *ign3_pin_port;
volatile PORT_TYPE *ign3_pin_port;
volatile PINMASK_TYPE ign3_pin_mask;
volatile PORT_TYPE *ign4_pin_port;
volatile PORT_TYPE *ign4_pin_port;
volatile PINMASK_TYPE ign4_pin_mask;
volatile PORT_TYPE *ign5_pin_port;
volatile PORT_TYPE *ign5_pin_port;
volatile PINMASK_TYPE ign5_pin_mask;
volatile PORT_TYPE *ign6_pin_port;
volatile PORT_TYPE *ign6_pin_port;
volatile PINMASK_TYPE ign6_pin_mask;
volatile PORT_TYPE *ign7_pin_port;
volatile PORT_TYPE *ign7_pin_port;
volatile PINMASK_TYPE ign7_pin_mask;
volatile PORT_TYPE *ign8_pin_port;
volatile PORT_TYPE *ign8_pin_port;
volatile PINMASK_TYPE ign8_pin_mask;
volatile PORT_TYPE *tach_pin_port;
volatile PORT_TYPE *tach_pin_port;
volatile PINMASK_TYPE tach_pin_mask;
volatile PORT_TYPE *pump_pin_port;
volatile PORT_TYPE *pump_pin_port;
volatile PINMASK_TYPE pump_pin_mask;
volatile PORT_TYPE *flex_pin_port;
volatile PORT_TYPE *flex_pin_port;
volatile PINMASK_TYPE flex_pin_mask;
volatile PORT_TYPE *triggerPri_pin_port;
volatile PORT_TYPE *triggerPri_pin_port;
volatile PINMASK_TYPE triggerPri_pin_mask;
volatile PORT_TYPE *triggerSec_pin_port;
volatile PORT_TYPE *triggerSec_pin_port;
volatile PINMASK_TYPE triggerSec_pin_mask;
volatile PORT_TYPE *triggerThird_pin_port;
volatile PORT_TYPE *triggerThird_pin_port;
volatile PINMASK_TYPE triggerThird_pin_mask;
//These are variables used across multiple files
bool initialisationComplete = false; ///< Tracks whether the setup() function has run completely (true = has run)
byte fpPrimeTime = 0; ///< The time (in seconds, based on @ref statuses.secl) that the fuel pump started priming
uint8_t softLimitTime = 0; //The time (in 0.1 seconds, based on seclx10) that the soft limiter started
volatile uint16_t mainLoopCount; //Main loop counter (incremented at each main loop rev., used for maintaining currentStatus.loopsPerSecond)
unsigned long revolutionTime; //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that)
volatile unsigned long timer5_overflow_count = 0; //Increments every time counter 5 overflows. Used for the fast version of micros()
volatile unsigned long ms_counter = 0; //A counter that increments once per ms
uint16_t fixedCrankingOverride = 0;
bool clutchTrigger;
bool previousClutchTrigger;
volatile uint32_t toothHistory[TOOTH_LOG_SIZE]; ///< Tooth trigger history - delta time (in uS) from last tooth (Indexed by @ref toothHistoryIndex)
volatile uint8_t compositeLogHistory[TOOTH_LOG_SIZE];
volatile bool fpPrimed = false; ///< Tracks whether or not the fuel pump priming has been completed yet
volatile bool injPrimed = false; ///< Tracks whether or not the injectors priming has been completed yet
volatile unsigned int toothHistoryIndex = 0; ///< Current index to @ref toothHistory array
unsigned long currentLoopTime; /**< The time (in uS) that the current mainloop started */
volatile uint16_t ignitionCount; /**< The count of ignition events that have taken place since the engine started */
// These are variables used across multiple files
bool initialisationComplete = false; ///< Tracks whether the setup() function has run completely (true = has run)
byte fpPrimeTime = 0; ///< The time (in seconds, based on @ref statuses.secl) that the fuel pump started priming
uint8_t softLimitTime = 0; // The time (in 0.1 seconds, based on seclx10) that the soft limiter started
volatile uint16_t mainLoopCount; // Main loop counter (incremented at each main loop rev., used for maintaining currentStatus.loopsPerSecond)
unsigned long revolutionTime; // The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that)
volatile unsigned long timer5_overflow_count = 0; // Increments every time counter 5 overflows. Used for the fast version of micros()
volatile unsigned long ms_counter = 0; // A counter that increments once per ms
uint16_t fixedCrankingOverride = 0;
bool clutchTrigger;
bool previousClutchTrigger;
volatile uint32_t toothHistory[TOOTH_LOG_SIZE]; ///< Tooth trigger history - delta time (in uS) from last tooth (Indexed by @ref toothHistoryIndex)
volatile uint8_t compositeLogHistory[TOOTH_LOG_SIZE];
volatile bool fpPrimed = false; ///< Tracks whether or not the fuel pump priming has been completed yet
volatile bool injPrimed = false; ///< Tracks whether or not the injectors priming has been completed yet
volatile unsigned int toothHistoryIndex = 0; ///< Current index to @ref toothHistory array
unsigned long currentLoopTime; /**< The time (in uS) that the current mainloop started */
volatile uint16_t ignitionCount; /**< The count of ignition events that have taken place since the engine started */
#if defined(CORE_SAMD21)
PinStatus primaryTriggerEdge;
PinStatus secondaryTriggerEdge;
PinStatus tertiaryTriggerEdge;
PinStatus primaryTriggerEdge;
PinStatus secondaryTriggerEdge;
PinStatus tertiaryTriggerEdge;
#else
byte primaryTriggerEdge;
byte secondaryTriggerEdge;
byte tertiaryTriggerEdge;
byte primaryTriggerEdge;
byte secondaryTriggerEdge;
byte tertiaryTriggerEdge;
#endif
int CRANK_ANGLE_MAX_IGN = 360;
int CRANK_ANGLE_MAX_INJ = 360; ///< The number of crank degrees that the system track over. 360 for wasted / timed batch and 720 for sequential
int CRANK_ANGLE_MAX_IGN = 360;
int CRANK_ANGLE_MAX_INJ = 360; ///< The number of crank degrees that the system track over. 360 for wasted / timed batch and 720 for sequential
volatile uint32_t runSecsX10;
volatile uint32_t seclx10;
volatile byte HWTest_INJ = 0; /**< Each bit in this variable represents one of the injector channels and it's HW test status */
volatile byte HWTest_INJ_50pc = 0; /**< Each bit in this variable represents one of the injector channels and it's 50% HW test status */
volatile byte HWTest_IGN = 0; /**< Each bit in this variable represents one of the ignition channels and it's HW test status */
volatile byte HWTest_IGN_50pc = 0;
byte maxIgnOutputs = 1; /**< Number of ignition outputs being used by the current tune configuration */
byte maxInjOutputs = 1; /**< Number of injection outputs being used by the current tune configuration */
volatile byte HWTest_INJ = 0; /**< Each bit in this variable represents one of the injector channels and it's HW test status */
volatile byte HWTest_INJ_50pc = 0; /**< Each bit in this variable represents one of the injector channels and it's 50% HW test status */
volatile byte HWTest_IGN = 0; /**< Each bit in this variable represents one of the ignition channels and it's HW test status */
volatile byte HWTest_IGN_50pc = 0;
byte maxIgnOutputs = 1; /**< Number of ignition outputs being used by the current tune configuration */
byte maxInjOutputs = 1; /**< Number of injection outputs being used by the current tune configuration */
//This needs to be here because using the config page directly can prevent burning the setting
// This needs to be here because using the config page directly can prevent burning the setting
byte resetControl = RESET_CONTROL_DISABLED;
volatile byte TIMER_mask;
volatile byte LOOP_TIMER;
/// Various pin numbering (Injectors, Ign outputs, CAS, Cam, Sensors. etc.) assignments
byte pinInjector1; ///< Output pin injector 1
byte pinInjector2; ///< Output pin injector 2
byte pinInjector3; ///< Output pin injector 3
byte pinInjector4; ///< Output pin injector 4
byte pinInjector5; ///< Output pin injector 5
byte pinInjector6; ///< Output pin injector 6
byte pinInjector7; ///< Output pin injector 7
byte pinInjector8; ///< Output pin injector 8
byte pinInjector1; ///< Output pin injector 1
byte pinInjector2; ///< Output pin injector 2
byte pinInjector3; ///< Output pin injector 3
byte pinInjector4; ///< Output pin injector 4
byte pinInjector5; ///< Output pin injector 5
byte pinInjector6; ///< Output pin injector 6
byte pinInjector7; ///< Output pin injector 7
byte pinInjector8; ///< Output pin injector 8
byte injectorOutputControl = OUTPUT_CONTROL_DIRECT; /**< Specifies whether the injectors are controlled directly (Via an IO pin)
or using something like the MC33810. 0 = Direct (OUTPUT_CONTROL_DIRECT), 10 = MC33810 (OUTPUT_CONTROL_MC33810) */
byte pinCoil1; ///< Pin for coil 1
byte pinCoil2; ///< Pin for coil 2
byte pinCoil3; ///< Pin for coil 3
byte pinCoil4; ///< Pin for coil 4
byte pinCoil5; ///< Pin for coil 5
byte pinCoil6; ///< Pin for coil 6
byte pinCoil7; ///< Pin for coil 7
byte pinCoil8; ///< Pin for coil 8
byte pinCoil1; ///< Pin for coil 1
byte pinCoil2; ///< Pin for coil 2
byte pinCoil3; ///< Pin for coil 3
byte pinCoil4; ///< Pin for coil 4
byte pinCoil5; ///< Pin for coil 5
byte pinCoil6; ///< Pin for coil 6
byte pinCoil7; ///< Pin for coil 7
byte pinCoil8; ///< Pin for coil 8
byte ignitionOutputControl = OUTPUT_CONTROL_DIRECT; /**< Specifies whether the coils are controlled directly (Via an IO pin)
or using something like the MC33810. 0 = Direct (OUTPUT_CONTROL_DIRECT), 10 = MC33810 (OUTPUT_CONTROL_MC33810) */
byte pinTrigger; ///< RPM1 (Typically CAS=crankshaft angle sensor) pin
byte pinTrigger2; ///< RPM2 (Typically the Cam Sensor) pin
byte pinTrigger3; ///< the 2nd cam sensor pin
byte pinTPS; //TPS input pin
byte pinMAP; //MAP sensor pin
byte pinEMAP; //EMAP sensor pin
byte pinMAP2; //2nd MAP sensor (Currently unused)
byte pinIAT; //IAT sensor pin
byte pinCLT; //CLS sensor pin
byte pinO2; //O2 Sensor pin
byte pinO2_2; //second O2 pin
byte pinBat; //Battery voltage pin
byte pinDisplayReset; // OLED reset pin
byte pinTachOut; //Tacho output
byte pinFuelPump; //Fuel pump on/off
byte pinIdle1; //Single wire idle control
byte pinIdle2; //2 wire idle control (Not currently used)
byte pinIdleUp; //Input for triggering Idle Up
byte pinIdleUpOutput; //Output that follows (normal or inverted) the idle up pin
byte pinCTPS; //Input for triggering closed throttle state
byte pinFuel2Input; //Input for switching to the 2nd fuel table
byte pinSpark2Input; //Input for switching to the 2nd ignition table
byte pinSpareTemp1; // Future use only
byte pinSpareTemp2; // Future use only
byte pinSpareOut1; //Generic output
byte pinSpareOut2; //Generic output
byte pinSpareOut3; //Generic output
byte pinSpareOut4; //Generic output
byte pinSpareOut5; //Generic output
byte pinSpareOut6; //Generic output
byte pinSpareHOut1; //spare high current output
byte pinSpareHOut2; // spare high current output
byte pinSpareLOut1; // spare low current output
byte pinSpareLOut2; // spare low current output
byte pinTrigger; ///< RPM1 (Typically CAS=crankshaft angle sensor) pin
byte pinTrigger2; ///< RPM2 (Typically the Cam Sensor) pin
byte pinTrigger3; ///< the 2nd cam sensor pin
byte pinTPS; // TPS input pin
byte pinMAP; // MAP sensor pin
byte pinEMAP; // EMAP sensor pin
byte pinMAP2; // 2nd MAP sensor (Currently unused)
byte pinIAT; // IAT sensor pin
byte pinCLT; // CLS sensor pin
byte pinO2; // O2 Sensor pin
byte pinO2_2; // second O2 pin
byte pinBat; // Battery voltage pin
byte pinDisplayReset; // OLED reset pin
byte pinTachOut; // Tacho output
byte pinFuelPump; // Fuel pump on/off
byte pinIdle1; // Single wire idle control
byte pinIdle2; // 2 wire idle control (Not currently used)
byte pinIdleUp; // Input for triggering Idle Up
byte pinIdleUpOutput; // Output that follows (normal or inverted) the idle up pin
byte pinCTPS; // Input for triggering closed throttle state
byte pinFuel2Input; // Input for switching to the 2nd fuel table
byte pinSpark2Input; // Input for switching to the 2nd ignition table
byte pinSpareTemp1; // Future use only
byte pinSpareTemp2; // Future use only
byte pinSpareOut1; // Generic output
byte pinSpareOut2; // Generic output
byte pinSpareOut3; // Generic output
byte pinSpareOut4; // Generic output
byte pinSpareOut5; // Generic output
byte pinSpareOut6; // Generic output
byte pinSpareHOut1; // spare high current output
byte pinSpareHOut2; // spare high current output
byte pinSpareLOut1; // spare low current output
byte pinSpareLOut2; // spare low current output
byte pinSpareLOut3;
byte pinSpareLOut4;
byte pinSpareLOut5;
byte pinBoost;
byte pinVVT_1; ///< vvt (variable valve timing) output 1
byte pinVVT_2; ///< vvt (variable valve timing) output 2
byte pinFan; ///< Cooling fan output (on/off? See: auxiliaries.ino)
byte pinStepperDir; //Direction pin for the stepper motor driver
byte pinStepperStep; //Step pin for the stepper motor driver
byte pinStepperEnable; //Turning the DRV8825 driver on/off
byte pinVVT_1; ///< vvt (variable valve timing) output 1
byte pinVVT_2; ///< vvt (variable valve timing) output 2
byte pinFan; ///< Cooling fan output (on/off? See: auxiliaries.ino)
byte pinStepperDir; // Direction pin for the stepper motor driver
byte pinStepperStep; // Step pin for the stepper motor driver
byte pinStepperEnable; // Turning the DRV8825 driver on/off
byte pinLaunch;
byte pinIgnBypass; //The pin used for an ignition bypass (Optional)
byte pinFlex; //Pin with the flex sensor attached
byte pinVSS; // VSS (Vehicle speed sensor) Pin
byte pinBaro; //Pin that an al barometric pressure sensor is attached to (If used)
byte pinIgnBypass; // The pin used for an ignition bypass (Optional)
byte pinFlex; // Pin with the flex sensor attached
byte pinVSS; // VSS (Vehicle speed sensor) Pin
byte pinBaro; // Pin that an al barometric pressure sensor is attached to (If used)
byte pinResetControl; // Output pin used control resetting the Arduino
byte pinFuelPressure;
byte pinOilPressure;
byte pinWMIEmpty; // Water tank empty sensor
byte pinWMIEmpty; // Water tank empty sensor
byte pinWMIIndicator; // No water indicator bulb
byte pinWMIEnabled; // ON-OFF output to relay/pump/solenoid
byte pinWMIEnabled; // ON-OFF output to relay/pump/solenoid
byte pinMC33810_1_CS;
byte pinMC33810_2_CS;
byte pinSDEnable;
#ifdef USE_SPI_EEPROM
byte pinSPIFlash_CS;
byte pinSPIFlash_CS;
#endif
byte pinAirConComp; // Air conditioning compressor output (See: auxiliaries.ino)
byte pinAirConFan; // Stand-alone air conditioning fan output (See: auxiliaries.ino)
byte pinAirConRequest; // Air conditioning request input (See: auxiliaries.ino)
byte pinAirConComp; // Air conditioning compressor output (See: auxiliaries.ino)
byte pinAirConFan; // Stand-alone air conditioning fan output (See: auxiliaries.ino)
byte pinAirConRequest; // Air conditioning request input (See: auxiliaries.ino)
struct statuses currentStatus; /**< The master global "live" status struct. Contains all values that are updated frequently and used across modules */
struct config2 configPage2;
struct config4 configPage4;
struct config6 configPage6;
struct config9 configPage9;
struct config2 configPage2;
struct config4 configPage4;
struct config6 configPage6;
struct config9 configPage9;
struct config10 configPage10;
struct config13 configPage13;
struct config15 configPage15;
//byte cltCalibrationTable[CALIBRATION_TABLE_SIZE]; /**< An array containing the coolant sensor calibration values */
//byte iatCalibrationTable[CALIBRATION_TABLE_SIZE]; /**< An array containing the inlet air temperature sensor calibration values */
//byte o2CalibrationTable[CALIBRATION_TABLE_SIZE]; /**< An array containing the O2 sensor calibration values */
// byte cltCalibrationTable[CALIBRATION_TABLE_SIZE]; /**< An array containing the coolant sensor calibration values */
// byte iatCalibrationTable[CALIBRATION_TABLE_SIZE]; /**< An array containing the inlet air temperature sensor calibration values */
// byte o2CalibrationTable[CALIBRATION_TABLE_SIZE]; /**< An array containing the O2 sensor calibration values */
uint16_t cltCalibration_bins[32];
uint16_t cltCalibration_values[32];
uint16_t cltCalibration_bins[32];
uint16_t cltCalibration_values[32];
struct table2D cltCalibrationTable;
uint16_t iatCalibration_bins[32];
uint16_t iatCalibration_values[32];
uint16_t iatCalibration_bins[32];
uint16_t iatCalibration_values[32];
struct table2D iatCalibrationTable;
uint16_t o2Calibration_bins[32];
uint8_t o2Calibration_values[32];
struct table2D o2CalibrationTable;
uint16_t o2Calibration_bins[32];
uint8_t o2Calibration_values[32];
struct table2D o2CalibrationTable;
//These function do checks on a pin to determine if it is already in use by another (higher importance) active function
// These function do checks on a pin to determine if it is already in use by another (higher importance) active function
inline bool pinIsOutput(byte pin)
{
bool used = false;
bool isIdlePWM = (configPage6.iacAlgorithm > 0) && ((configPage6.iacAlgorithm <= 3) || (configPage6.iacAlgorithm == 6));
bool used = false;
bool isIdlePWM = (configPage6.iacAlgorithm > 0) && ((configPage6.iacAlgorithm <= 3) || (configPage6.iacAlgorithm == 6));
bool isIdleSteper = (configPage6.iacAlgorithm > 3) && (configPage6.iacAlgorithm != 6);
//Injector?
if ((pin == pinInjector1)
|| ((pin == pinInjector2) && (configPage2.nInjectors > 1))
|| ((pin == pinInjector3) && (configPage2.nInjectors > 2))
|| ((pin == pinInjector4) && (configPage2.nInjectors > 3))
|| ((pin == pinInjector5) && (configPage2.nInjectors > 4))
|| ((pin == pinInjector6) && (configPage2.nInjectors > 5))
|| ((pin == pinInjector7) && (configPage2.nInjectors > 6))
|| ((pin == pinInjector8) && (configPage2.nInjectors > 7)))
// Injector?
if((pin == pinInjector1) || ((pin == pinInjector2) && (configPage2.nInjectors > 1)) || ((pin == pinInjector3) && (configPage2.nInjectors > 2)) || ((pin == pinInjector4) && (configPage2.nInjectors > 3)) || ((pin == pinInjector5) && (configPage2.nInjectors > 4)) ||
((pin == pinInjector6) && (configPage2.nInjectors > 5)) || ((pin == pinInjector7) && (configPage2.nInjectors > 6)) || ((pin == pinInjector8) && (configPage2.nInjectors > 7)))
{
used = true;
}
//Ignition?
if ((pin == pinCoil1)
|| ((pin == pinCoil2) && (maxIgnOutputs > 1))
|| ((pin == pinCoil3) && (maxIgnOutputs > 2))
|| ((pin == pinCoil4) && (maxIgnOutputs > 3))
|| ((pin == pinCoil5) && (maxIgnOutputs > 4))
|| ((pin == pinCoil6) && (maxIgnOutputs > 5))
|| ((pin == pinCoil7) && (maxIgnOutputs > 6))
|| ((pin == pinCoil8) && (maxIgnOutputs > 7)))
// Ignition?
if((pin == pinCoil1) || ((pin == pinCoil2) && (maxIgnOutputs > 1)) || ((pin == pinCoil3) && (maxIgnOutputs > 2)) || ((pin == pinCoil4) && (maxIgnOutputs > 3)) || ((pin == pinCoil5) && (maxIgnOutputs > 4)) || ((pin == pinCoil6) && (maxIgnOutputs > 5)) ||
((pin == pinCoil7) && (maxIgnOutputs > 6)) || ((pin == pinCoil8) && (maxIgnOutputs > 7)))
{
used = true;
}
//Functions?
if ((pin == pinFuelPump)
|| ((pin == pinFan) && (configPage2.fanEnable == 1))
|| ((pin == pinVVT_1) && (configPage6.vvtEnabled > 0))
|| ((pin == pinVVT_1) && (configPage10.wmiEnabled > 0))
|| ((pin == pinVVT_2) && (configPage10.vvt2Enabled > 0))
|| ((pin == pinBoost) && (configPage6.boostEnabled == 1))
|| ((pin == pinIdle1) && isIdlePWM)
|| ((pin == pinIdle2) && isIdlePWM && (configPage6.iacChannels == 1))
|| ((pin == pinStepperEnable) && isIdleSteper)
|| ((pin == pinStepperStep) && isIdleSteper)
|| ((pin == pinStepperDir) && isIdleSteper)
|| (pin == pinTachOut)
|| ((pin == pinAirConComp) && (configPage15.airConEnable > 0))
|| ((pin == pinAirConFan) && (configPage15.airConEnable > 0) && (configPage15.airConFanEnabled > 0)) )
// Functions?
if((pin == pinFuelPump) || ((pin == pinFan) && (configPage2.fanEnable == 1)) || ((pin == pinVVT_1) && (configPage6.vvtEnabled > 0)) || ((pin == pinVVT_1) && (configPage10.wmiEnabled > 0)) || ((pin == pinVVT_2) && (configPage10.vvt2Enabled > 0)) ||
((pin == pinBoost) && (configPage6.boostEnabled == 1)) || ((pin == pinIdle1) && isIdlePWM) || ((pin == pinIdle2) && isIdlePWM && (configPage6.iacChannels == 1)) || ((pin == pinStepperEnable) && isIdleSteper) || ((pin == pinStepperStep) && isIdleSteper) ||
((pin == pinStepperDir) && isIdleSteper) || (pin == pinTachOut) || ((pin == pinAirConComp) && (configPage15.airConEnable > 0)) || ((pin == pinAirConFan) && (configPage15.airConEnable > 0) && (configPage15.airConFanEnabled > 0)))
{
used = true;
}
//Forbiden or hardware reserved? (Defined at board_xyz.h file)
if ( pinIsReserved(pin) ) { used = true; }
// Forbiden or hardware reserved? (Defined at board_xyz.h file)
if(pinIsReserved(pin)) { used = true; }
return used;
}
@ -317,16 +294,10 @@ inline bool pinIsUsed(byte pin)
{
bool used = false;
//Analog input?
if ( pinIsSensor(pin) )
{
used = true;
}
//Functions?
if ( pinIsOutput(pin) )
{
used = true;
}
// Analog input?
if(pinIsSensor(pin)) { used = true; }
// Functions?
if(pinIsOutput(pin)) { used = true; }
return used;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
#include "decoders.h"
#include "init.h"
/**
/**
* Returns a numbered byte-field (partial field in case of multi-byte fields) from "current status" structure in the format expected by TunerStudio
* Notes on fields:
* - Numbered field will be fields from @ref currentStatus, but not at all in the internal order of strct (e.g. field RPM value, number 14 will be
@ -20,68 +20,70 @@ byte getTSLogEntry(uint16_t byteNum)
switch(byteNum)
{
case 0: statusValue = currentStatus.secl; break; //secl is simply a counter that increments each second. Used to track unexpected resets (Which will reset this count to 0)
case 1: statusValue = currentStatus.status1; break; //status1 Bitfield
case 2: statusValue = currentStatus.engine; break; //Engine Status Bitfield
case 0: statusValue = currentStatus.secl; break; // secl is simply a counter that increments each second. Used to track unexpected resets (Which will reset this count to 0)
case 1: statusValue = currentStatus.status1; break; // status1 Bitfield
case 2: statusValue = currentStatus.engine; break; // Engine Status Bitfield
case 3: statusValue = currentStatus.syncLossCounter; break;
case 4: statusValue = lowByte(currentStatus.MAP); break; //2 bytes for MAP
case 4: statusValue = lowByte(currentStatus.MAP); break; // 2 bytes for MAP
case 5: statusValue = highByte(currentStatus.MAP); break;
case 6: statusValue = (byte)(currentStatus.IAT + CALIBRATION_TEMPERATURE_OFFSET); break; //mat
case 7: statusValue = (byte)(currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); break; //Coolant ADC
case 8: statusValue = currentStatus.batCorrection; break; //Battery voltage correction (%)
case 9: statusValue = currentStatus.battery10; break; //battery voltage
case 10: statusValue = currentStatus.O2; break; //O2
case 11: statusValue = currentStatus.egoCorrection; break; //Exhaust gas correction (%)
case 12: statusValue = currentStatus.iatCorrection; break; //Air temperature Correction (%)
case 13: statusValue = currentStatus.wueCorrection; break; //Warmup enrichment (%)
case 14: statusValue = lowByte(currentStatus.RPM); break; //rpm HB
case 15: statusValue = highByte(currentStatus.RPM); break; //rpm LB
case 16: statusValue = (byte)(currentStatus.AEamount >> 1); break; //TPS acceleration enrichment (%) divided by 2 (Can exceed 255)
case 17: statusValue = lowByte(currentStatus.corrections); break; //Total GammaE (%)
case 18: statusValue = highByte(currentStatus.corrections); break; //Total GammaE (%)
case 19: statusValue = currentStatus.VE1; break; //VE 1 (%)
case 20: statusValue = currentStatus.VE2; break; //VE 2 (%)
case 6: statusValue = (byte)(currentStatus.IAT + CALIBRATION_TEMPERATURE_OFFSET); break; // mat
case 7: statusValue = (byte)(currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); break; // Coolant ADC
case 8: statusValue = currentStatus.batCorrection; break; // Battery voltage correction (%)
case 9: statusValue = currentStatus.battery10; break; // battery voltage
case 10: statusValue = currentStatus.O2; break; // O2
case 11: statusValue = currentStatus.egoCorrection; break; // Exhaust gas correction (%)
case 12: statusValue = currentStatus.iatCorrection; break; // Air temperature Correction (%)
case 13: statusValue = currentStatus.wueCorrection; break; // Warmup enrichment (%)
case 14: statusValue = lowByte(currentStatus.RPM); break; // rpm HB
case 15: statusValue = highByte(currentStatus.RPM); break; // rpm LB
case 16: statusValue = (byte)(currentStatus.AEamount >> 1); break; // TPS acceleration enrichment (%) divided by 2 (Can exceed 255)
case 17: statusValue = lowByte(currentStatus.corrections); break; // Total GammaE (%)
case 18: statusValue = highByte(currentStatus.corrections); break; // Total GammaE (%)
case 19: statusValue = currentStatus.VE1; break; // VE 1 (%)
case 20: statusValue = currentStatus.VE2; break; // VE 2 (%)
case 21: statusValue = currentStatus.afrTarget; break;
case 22: statusValue = lowByte(currentStatus.tpsDOT); break; //TPS DOT
case 23: statusValue = highByte(currentStatus.tpsDOT); break; //TPS DOT
case 22: statusValue = lowByte(currentStatus.tpsDOT); break; // TPS DOT
case 23: statusValue = highByte(currentStatus.tpsDOT); break; // TPS DOT
case 24: statusValue = currentStatus.advance; break;
case 25: statusValue = currentStatus.TPS; break; // TPS (0% to 100%)
case 26:
if(currentStatus.loopsPerSecond > 60000) { currentStatus.loopsPerSecond = 60000;}
statusValue = lowByte(currentStatus.loopsPerSecond);
case 26:
if(currentStatus.loopsPerSecond > 60000) { currentStatus.loopsPerSecond = 60000; }
statusValue = lowByte(currentStatus.loopsPerSecond);
break;
case 27:
if(currentStatus.loopsPerSecond > 60000) { currentStatus.loopsPerSecond = 60000;}
statusValue = highByte(currentStatus.loopsPerSecond);
break;
case 28:
currentStatus.freeRAM = freeRam();
statusValue = lowByte(currentStatus.freeRAM); //(byte)((currentStatus.loopsPerSecond >> 8) & 0xFF);
break;
case 29:
currentStatus.freeRAM = freeRam();
statusValue = highByte(currentStatus.freeRAM);
case 27:
if(currentStatus.loopsPerSecond > 60000) { currentStatus.loopsPerSecond = 60000; }
statusValue = highByte(currentStatus.loopsPerSecond);
break;
case 30: statusValue = (byte)(currentStatus.boostTarget >> 1); break; //Divide boost target by 2 to fit in a byte
case 28:
currentStatus.freeRAM = freeRam();
statusValue = lowByte(currentStatus.freeRAM); //(byte)((currentStatus.loopsPerSecond >> 8) & 0xFF);
break;
case 29:
currentStatus.freeRAM = freeRam();
statusValue = highByte(currentStatus.freeRAM);
break;
case 30: statusValue = (byte)(currentStatus.boostTarget >> 1); break; // Divide boost target by 2 to fit in a byte
case 31: statusValue = (byte)(currentStatus.boostDuty / 100); break;
case 32: statusValue = currentStatus.spark; break; //Spark related bitfield
case 32:
statusValue = currentStatus.spark;
break; // Spark related bitfield
//rpmDOT must be sent as a signed integer
// rpmDOT must be sent as a signed integer
case 33: statusValue = lowByte(currentStatus.rpmDOT); break;
case 34: statusValue = highByte(currentStatus.rpmDOT); break;
case 35: statusValue = currentStatus.ethanolPct; break; //Flex sensor value (or 0 if not used)
case 36: statusValue = currentStatus.flexCorrection; break; //Flex fuel correction (% above or below 100)
case 37: statusValue = currentStatus.flexIgnCorrection; break; //Ignition correction (Increased degrees of advance) for flex fuel
case 35: statusValue = currentStatus.ethanolPct; break; // Flex sensor value (or 0 if not used)
case 36: statusValue = currentStatus.flexCorrection; break; // Flex fuel correction (% above or below 100)
case 37: statusValue = currentStatus.flexIgnCorrection; break; // Ignition correction (Increased degrees of advance) for flex fuel
case 38: statusValue = currentStatus.idleLoad; break;
case 39: statusValue = currentStatus.testOutputs; break;
case 40: statusValue = currentStatus.O2_2; break; //O2
case 41: statusValue = currentStatus.baro; break; //Barometer value
case 40: statusValue = currentStatus.O2_2; break; // O2
case 41: statusValue = currentStatus.baro; break; // Barometer value
case 42: statusValue = lowByte(currentStatus.canin[0]); break;
case 43: statusValue = highByte(currentStatus.canin[0]); break;
@ -119,14 +121,14 @@ byte getTSLogEntry(uint16_t byteNum)
case 74: statusValue = currentStatus.tpsADC; break;
case 75: statusValue = getNextError(); break;
case 76: statusValue = lowByte(currentStatus.PW1); break; //Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
case 77: statusValue = highByte(currentStatus.PW1); break; //Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
case 78: statusValue = lowByte(currentStatus.PW2); break; //Pulsewidth 2 multiplied by 10 in ms. Have to convert from uS to mS.
case 79: statusValue = highByte(currentStatus.PW2); break; //Pulsewidth 2 multiplied by 10 in ms. Have to convert from uS to mS.
case 80: statusValue = lowByte(currentStatus.PW3); break; //Pulsewidth 3 multiplied by 10 in ms. Have to convert from uS to mS.
case 81: statusValue = highByte(currentStatus.PW3); break; //Pulsewidth 3 multiplied by 10 in ms. Have to convert from uS to mS.
case 82: statusValue = lowByte(currentStatus.PW4); break; //Pulsewidth 4 multiplied by 10 in ms. Have to convert from uS to mS.
case 83: statusValue = highByte(currentStatus.PW4); break; //Pulsewidth 4 multiplied by 10 in ms. Have to convert from uS to mS.
case 76: statusValue = lowByte(currentStatus.PW1); break; // Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
case 77: statusValue = highByte(currentStatus.PW1); break; // Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
case 78: statusValue = lowByte(currentStatus.PW2); break; // Pulsewidth 2 multiplied by 10 in ms. Have to convert from uS to mS.
case 79: statusValue = highByte(currentStatus.PW2); break; // Pulsewidth 2 multiplied by 10 in ms. Have to convert from uS to mS.
case 80: statusValue = lowByte(currentStatus.PW3); break; // Pulsewidth 3 multiplied by 10 in ms. Have to convert from uS to mS.
case 81: statusValue = highByte(currentStatus.PW3); break; // Pulsewidth 3 multiplied by 10 in ms. Have to convert from uS to mS.
case 82: statusValue = lowByte(currentStatus.PW4); break; // Pulsewidth 4 multiplied by 10 in ms. Have to convert from uS to mS.
case 83: statusValue = highByte(currentStatus.PW4); break; // Pulsewidth 4 multiplied by 10 in ms. Have to convert from uS to mS.
case 84: statusValue = currentStatus.status3; break;
case 85: statusValue = currentStatus.engineProtectStatus; break;
@ -139,15 +141,15 @@ byte getTSLogEntry(uint16_t byteNum)
case 92: statusValue = currentStatus.CLIdleTarget; break;
case 93: statusValue = lowByte(currentStatus.mapDOT); break;
case 94: statusValue = highByte(currentStatus.mapDOT); break;
case 95: statusValue = lowByte(currentStatus.vvt1Angle); break; //2 bytes for vvt1Angle
case 95: statusValue = lowByte(currentStatus.vvt1Angle); break; // 2 bytes for vvt1Angle
case 96: statusValue = highByte(currentStatus.vvt1Angle); break;
case 97: statusValue = currentStatus.vvt1TargetAngle; break;
case 98: statusValue = (byte)(currentStatus.vvt1Duty); break;
case 99: statusValue = lowByte(currentStatus.flexBoostCorrection); break;
case 100: statusValue = highByte(currentStatus.flexBoostCorrection); break;
case 101: statusValue = currentStatus.baroCorrection; break;
case 102: statusValue = currentStatus.VE; break; //Current VE (%). Can be equal to VE1 or VE2 or a calculated value from both of them
case 103: statusValue = currentStatus.ASEValue; break; //Current ASE (%)
case 102: statusValue = currentStatus.VE; break; // Current VE (%). Can be equal to VE1 or VE2 or a calculated value from both of them
case 103: statusValue = currentStatus.ASEValue; break; // Current ASE (%)
case 104: statusValue = lowByte(currentStatus.vss); break;
case 105: statusValue = highByte(currentStatus.vss); break;
case 106: statusValue = currentStatus.gear; break;
@ -155,17 +157,17 @@ byte getTSLogEntry(uint16_t byteNum)
case 108: statusValue = currentStatus.oilPressure; break;
case 109: statusValue = currentStatus.wmiPW; break;
case 110: statusValue = currentStatus.status4; break;
case 111: statusValue = lowByte(currentStatus.vvt2Angle); break; //2 bytes for vvt2Angle
case 111: statusValue = lowByte(currentStatus.vvt2Angle); break; // 2 bytes for vvt2Angle
case 112: statusValue = highByte(currentStatus.vvt2Angle); break;
case 113: statusValue = currentStatus.vvt2TargetAngle; break;
case 114: statusValue = (byte)(currentStatus.vvt2Duty); break;
case 115: statusValue = currentStatus.outputsStatus; break;
case 116: statusValue = (byte)(currentStatus.fuelTemp + CALIBRATION_TEMPERATURE_OFFSET); break; //Fuel temperature from flex sensor
case 117: statusValue = currentStatus.fuelTempCorrection; break; //Fuel temperature Correction (%)
case 118: statusValue = currentStatus.advance1; break; //advance 1 (%)
case 119: statusValue = currentStatus.advance2; break; //advance 2 (%)
case 120: statusValue = currentStatus.TS_SD_Status; break; //SD card status
case 121: statusValue = lowByte(currentStatus.EMAP); break; //2 bytes for EMAP
case 116: statusValue = (byte)(currentStatus.fuelTemp + CALIBRATION_TEMPERATURE_OFFSET); break; // Fuel temperature from flex sensor
case 117: statusValue = currentStatus.fuelTempCorrection; break; // Fuel temperature Correction (%)
case 118: statusValue = currentStatus.advance1; break; // advance 1 (%)
case 119: statusValue = currentStatus.advance2; break; // advance 2 (%)
case 120: statusValue = currentStatus.TS_SD_Status; break; // SD card status
case 121: statusValue = lowByte(currentStatus.EMAP); break; // 2 bytes for EMAP
case 122: statusValue = highByte(currentStatus.EMAP); break;
case 123: statusValue = currentStatus.fanDuty; break;
case 124: statusValue = currentStatus.airConStatus; break;
@ -176,7 +178,7 @@ byte getTSLogEntry(uint16_t byteNum)
return statusValue;
}
/**
/**
* Similar to the @ref getTSLogEntry function, however this returns a full, unadjusted (ie human readable) log entry value.
* See logger.h for the field names and order
* @param logIndex - The log index required. Note that this is NOT the byte number, but the index in the log
@ -188,50 +190,50 @@ int16_t getReadableLogEntry(uint16_t logIndex)
switch(logIndex)
{
case 0: statusValue = currentStatus.secl; break; //secl is simply a counter that increments each second. Used to track unexpected resets (Which will reset this count to 0)
case 1: statusValue = currentStatus.status1; break; //status1 Bitfield
case 2: statusValue = currentStatus.engine; break; //Engine Status Bitfield
case 0: statusValue = currentStatus.secl; break; // secl is simply a counter that increments each second. Used to track unexpected resets (Which will reset this count to 0)
case 1: statusValue = currentStatus.status1; break; // status1 Bitfield
case 2: statusValue = currentStatus.engine; break; // Engine Status Bitfield
case 3: statusValue = currentStatus.syncLossCounter; break;
case 4: statusValue = currentStatus.MAP; break; //2 bytes for MAP
case 5: statusValue = currentStatus.IAT; break; //mat
case 6: statusValue = currentStatus.coolant; break; //Coolant ADC
case 7: statusValue = currentStatus.batCorrection; break; //Battery voltage correction (%)
case 8: statusValue = currentStatus.battery10; break; //battery voltage
case 9: statusValue = currentStatus.O2; break; //O2
case 10: statusValue = currentStatus.egoCorrection; break; //Exhaust gas correction (%)
case 11: statusValue = currentStatus.iatCorrection; break; //Air temperature Correction (%)
case 12: statusValue = currentStatus.wueCorrection; break; //Warmup enrichment (%)
case 13: statusValue = currentStatus.RPM; break; //rpm HB
case 14: statusValue = currentStatus.AEamount; break; //TPS acceleration enrichment (%)
case 15: statusValue = currentStatus.corrections; break; //Total GammaE (%)
case 16: statusValue = currentStatus.VE1; break; //VE 1 (%)
case 17: statusValue = currentStatus.VE2; break; //VE 2 (%)
case 4: statusValue = currentStatus.MAP; break; // 2 bytes for MAP
case 5: statusValue = currentStatus.IAT; break; // mat
case 6: statusValue = currentStatus.coolant; break; // Coolant ADC
case 7: statusValue = currentStatus.batCorrection; break; // Battery voltage correction (%)
case 8: statusValue = currentStatus.battery10; break; // battery voltage
case 9: statusValue = currentStatus.O2; break; // O2
case 10: statusValue = currentStatus.egoCorrection; break; // Exhaust gas correction (%)
case 11: statusValue = currentStatus.iatCorrection; break; // Air temperature Correction (%)
case 12: statusValue = currentStatus.wueCorrection; break; // Warmup enrichment (%)
case 13: statusValue = currentStatus.RPM; break; // rpm HB
case 14: statusValue = currentStatus.AEamount; break; // TPS acceleration enrichment (%)
case 15: statusValue = currentStatus.corrections; break; // Total GammaE (%)
case 16: statusValue = currentStatus.VE1; break; // VE 1 (%)
case 17: statusValue = currentStatus.VE2; break; // VE 2 (%)
case 18: statusValue = currentStatus.afrTarget; break;
case 19: statusValue = currentStatus.tpsDOT; break; //TPS DOT
case 19: statusValue = currentStatus.tpsDOT; break; // TPS DOT
case 20: statusValue = currentStatus.advance; break;
case 21: statusValue = currentStatus.TPS; break; // TPS (0% to 100%)
case 22:
if(currentStatus.loopsPerSecond > 60000) { currentStatus.loopsPerSecond = 60000;}
statusValue = currentStatus.loopsPerSecond;
case 22:
if(currentStatus.loopsPerSecond > 60000) { currentStatus.loopsPerSecond = 60000; }
statusValue = currentStatus.loopsPerSecond;
break;
case 23:
case 23:
currentStatus.freeRAM = freeRam();
statusValue = currentStatus.freeRAM;
break;
statusValue = currentStatus.freeRAM;
break;
case 24: statusValue = currentStatus.boostTarget; break;
case 25: statusValue = currentStatus.boostDuty; break;
case 26: statusValue = currentStatus.spark; break; //Spark related bitfield
case 26: statusValue = currentStatus.spark; break; // Spark related bitfield
case 27: statusValue = currentStatus.rpmDOT; break;
case 28: statusValue = currentStatus.ethanolPct; break; //Flex sensor value (or 0 if not used)
case 29: statusValue = currentStatus.flexCorrection; break; //Flex fuel correction (% above or below 100)
case 30: statusValue = currentStatus.flexIgnCorrection; break; //Ignition correction (Increased degrees of advance) for flex fuel
case 28: statusValue = currentStatus.ethanolPct; break; // Flex sensor value (or 0 if not used)
case 29: statusValue = currentStatus.flexCorrection; break; // Flex fuel correction (% above or below 100)
case 30: statusValue = currentStatus.flexIgnCorrection; break; // Ignition correction (Increased degrees of advance) for flex fuel
case 31: statusValue = currentStatus.idleLoad; break;
case 32: statusValue = currentStatus.testOutputs; break;
case 33: statusValue = currentStatus.O2_2; break; //O2
case 34: statusValue = currentStatus.baro; break; //Barometer value
case 33: statusValue = currentStatus.O2_2; break; // O2
case 34: statusValue = currentStatus.baro; break; // Barometer value
case 35: statusValue = currentStatus.canin[0]; break;
case 36: statusValue = currentStatus.canin[1]; break;
@ -249,19 +251,19 @@ int16_t getReadableLogEntry(uint16_t logIndex)
case 48: statusValue = currentStatus.canin[13]; break;
case 49: statusValue = currentStatus.canin[14]; break;
case 50: statusValue = currentStatus.canin[15]; break;
case 51: statusValue = currentStatus.tpsADC; break;
case 52: statusValue = getNextError(); break;
case 53: statusValue = currentStatus.PW1; break; //Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
case 54: statusValue = currentStatus.PW2; break; //Pulsewidth 2 multiplied by 10 in ms. Have to convert from uS to mS.
case 55: statusValue = currentStatus.PW3; break; //Pulsewidth 3 multiplied by 10 in ms. Have to convert from uS to mS.
case 56: statusValue = currentStatus.PW4; break; //Pulsewidth 4 multiplied by 10 in ms. Have to convert from uS to mS.
case 53: statusValue = currentStatus.PW1; break; // Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
case 54: statusValue = currentStatus.PW2; break; // Pulsewidth 2 multiplied by 10 in ms. Have to convert from uS to mS.
case 55: statusValue = currentStatus.PW3; break; // Pulsewidth 3 multiplied by 10 in ms. Have to convert from uS to mS.
case 56: statusValue = currentStatus.PW4; break; // Pulsewidth 4 multiplied by 10 in ms. Have to convert from uS to mS.
case 57: statusValue = currentStatus.status3; break;
case 58: statusValue = currentStatus.engineProtectStatus; break;
case 59: break; //UNUSED!!
case 59: break; // UNUSED!!
case 60: statusValue = currentStatus.fuelLoad; break;
case 61: statusValue = currentStatus.ignLoad; break;
@ -273,23 +275,23 @@ int16_t getReadableLogEntry(uint16_t logIndex)
case 67: statusValue = currentStatus.vvt1Duty; break;
case 68: statusValue = currentStatus.flexBoostCorrection; break;
case 69: statusValue = currentStatus.baroCorrection; break;
case 70: statusValue = currentStatus.VE; break; //Current VE (%). Can be equal to VE1 or VE2 or a calculated value from both of them
case 71: statusValue = currentStatus.ASEValue; break; //Current ASE (%)
case 70: statusValue = currentStatus.VE; break; // Current VE (%). Can be equal to VE1 or VE2 or a calculated value from both of them
case 71: statusValue = currentStatus.ASEValue; break; // Current ASE (%)
case 72: statusValue = currentStatus.vss; break;
case 73: statusValue = currentStatus.gear; break;
case 74: statusValue = currentStatus.fuelPressure; break;
case 75: statusValue = currentStatus.oilPressure; break;
case 76: statusValue = currentStatus.wmiPW; break;
case 77: statusValue = currentStatus.status4; break;
case 78: statusValue = currentStatus.vvt2Angle; break; //2 bytes for vvt2Angle
case 78: statusValue = currentStatus.vvt2Angle; break; // 2 bytes for vvt2Angle
case 79: statusValue = currentStatus.vvt2TargetAngle; break;
case 80: statusValue = currentStatus.vvt2Duty; break;
case 81: statusValue = currentStatus.outputsStatus; break;
case 82: statusValue = currentStatus.fuelTemp; break; //Fuel temperature from flex sensor
case 83: statusValue = currentStatus.fuelTempCorrection; break; //Fuel temperature Correction (%)
case 84: statusValue = currentStatus.advance1; break; //advance 1 (%)
case 85: statusValue = currentStatus.advance2; break; //advance 2 (%)
case 86: statusValue = currentStatus.TS_SD_Status; break; //SD card status
case 82: statusValue = currentStatus.fuelTemp; break; // Fuel temperature from flex sensor
case 83: statusValue = currentStatus.fuelTempCorrection; break; // Fuel temperature Correction (%)
case 84: statusValue = currentStatus.advance1; break; // advance 1 (%)
case 85: statusValue = currentStatus.advance2; break; // advance 2 (%)
case 86: statusValue = currentStatus.TS_SD_Status; break; // SD card status
case 87: statusValue = currentStatus.EMAP; break;
case 88: statusValue = currentStatus.fanDuty; break;
case 89: statusValue = currentStatus.airConStatus; break;
@ -299,11 +301,11 @@ int16_t getReadableLogEntry(uint16_t logIndex)
return statusValue;
}
/**
/**
* An expansion to the @ref getReadableLogEntry function for systems that have an FPU. It will provide a floating point value for any parameter that this is appropriate for, otherwise will return the result of @ref getReadableLogEntry.
* See logger.h for the field names and order
* @param logIndex - The log index required. Note that this is NOT the byte number, but the index in the log
* @return float value of the requested log entry.
* @return float value of the requested log entry.
*/
#if FPU_MAX_SIZE >= 32
float getReadableFloatLogEntry(uint16_t logIndex)
@ -312,56 +314,50 @@ float getReadableFloatLogEntry(uint16_t logIndex)
switch(logIndex)
{
case 8: statusValue = currentStatus.battery10 / 10.0; break; //battery voltage
case 8: statusValue = currentStatus.battery10 / 10.0; break; // battery voltage
case 9: statusValue = currentStatus.O2 / 10.0; break;
case 18: statusValue = currentStatus.afrTarget / 10.0; break;
case 21: statusValue = currentStatus.TPS / 2.0; break; // TPS (0% to 100% = 0 to 200)
case 33: statusValue = currentStatus.O2_2 / 10.0; break; //O2
case 21: statusValue = currentStatus.TPS / 2.0; break; // TPS (0% to 100% = 0 to 200)
case 33: statusValue = currentStatus.O2_2 / 10.0; break; // O2
case 53: statusValue = currentStatus.PW1 / 1000.0; break; //Pulsewidth 1 Have to convert from uS to mS.
case 54: statusValue = currentStatus.PW2 / 1000.0; break; //Pulsewidth 2 Have to convert from uS to mS.
case 55: statusValue = currentStatus.PW3 / 1000.0; break; //Pulsewidth 3 Have to convert from uS to mS.
case 56: statusValue = currentStatus.PW4 / 1000.0; break; //Pulsewidth 4 Have to convert from uS to mS.
case 53: statusValue = currentStatus.PW1 / 1000.0; break; // Pulsewidth 1 Have to convert from uS to mS.
case 54: statusValue = currentStatus.PW2 / 1000.0; break; // Pulsewidth 2 Have to convert from uS to mS.
case 55: statusValue = currentStatus.PW3 / 1000.0; break; // Pulsewidth 3 Have to convert from uS to mS.
case 56: statusValue = currentStatus.PW4 / 1000.0; break; // Pulsewidth 4 Have to convert from uS to mS.
default: statusValue = getReadableLogEntry(logIndex); break; //If logIndex value is NOT a float based one, use the regular function
default: statusValue = getReadableLogEntry(logIndex); break; // If logIndex value is NOT a float based one, use the regular function
}
return statusValue;
}
#endif
/**
/**
* Searches the log 2 byte array to determine whether a given index is a regular single byte or a 2 byte field
* Uses a boundless binary search for improved performance, but requires the fsIntIndex to remain in order
* Refer: https://github.com/scandum/binary_search
*
*
* @param key - Index in the log array to check
* @return True if the index is a 2 byte log field. False if it is a single byte
*/
bool is2ByteEntry(uint8_t key)
{
bool isFound = false;
bool isFound = false;
unsigned int mid, bot;
uint16_t array_size = sizeof(fsIntIndex);
uint16_t array_size = sizeof(fsIntIndex);
if (array_size > 0)
if(array_size > 0)
{
bot = 0;
mid = array_size;
while (mid > 1)
{
if (key >= pgm_read_byte( &fsIntIndex[bot + mid / 2]) )
{
bot += mid++ / 2;
}
while(mid > 1)
{
if(key >= pgm_read_byte(&fsIntIndex[bot + mid / 2])) { bot += mid++ / 2; }
mid /= 2;
}
if (key == pgm_read_byte(&fsIntIndex[bot]) )
{
isFound = true;
}
if(key == pgm_read_byte(&fsIntIndex[bot])) { isFound = true; }
}
return isFound;
@ -369,53 +365,52 @@ bool is2ByteEntry(uint8_t key)
void startToothLogger(void)
{
currentStatus.toothLogEnabled = true;
currentStatus.compositeTriggerUsed = 0; //Safety first (Should never be required)
currentStatus.toothLogEnabled = true;
currentStatus.compositeTriggerUsed = 0; // Safety first (Should never be required)
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY);
toothHistoryIndex = 0;
//Disconnect the standard interrupt and add the logger version
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), loggerPrimaryISR, CHANGE );
// Disconnect the standard interrupt and add the logger version
detachInterrupt(digitalPinToInterrupt(pinTrigger));
attachInterrupt(digitalPinToInterrupt(pinTrigger), loggerPrimaryISR, CHANGE);
if(VSS_USES_RPM2() != true)
{
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), loggerSecondaryISR, CHANGE );
detachInterrupt(digitalPinToInterrupt(pinTrigger2));
attachInterrupt(digitalPinToInterrupt(pinTrigger2), loggerSecondaryISR, CHANGE);
}
}
void stopToothLogger(void)
{
currentStatus.toothLogEnabled = false;
//Disconnect the logger interrupts and attach the normal ones
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), triggerHandler, primaryTriggerEdge );
// Disconnect the logger interrupts and attach the normal ones
detachInterrupt(digitalPinToInterrupt(pinTrigger));
attachInterrupt(digitalPinToInterrupt(pinTrigger), triggerHandler, primaryTriggerEdge);
if(VSS_USES_RPM2() != true)
{
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), triggerSecondaryHandler, secondaryTriggerEdge );
detachInterrupt(digitalPinToInterrupt(pinTrigger2));
attachInterrupt(digitalPinToInterrupt(pinTrigger2), triggerSecondaryHandler, secondaryTriggerEdge);
}
}
void startCompositeLogger(void)
{
currentStatus.compositeTriggerUsed = 2;
currentStatus.toothLogEnabled = false; //Safety first (Should never be required)
currentStatus.toothLogEnabled = false; // Safety first (Should never be required)
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY);
toothHistoryIndex = 0;
//Disconnect the standard interrupt and add the logger version
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), loggerPrimaryISR, CHANGE );
// Disconnect the standard interrupt and add the logger version
detachInterrupt(digitalPinToInterrupt(pinTrigger));
attachInterrupt(digitalPinToInterrupt(pinTrigger), loggerPrimaryISR, CHANGE);
if( (VSS_USES_RPM2() != true) && (FLEX_USES_RPM2() != true) )
if((VSS_USES_RPM2() != true) && (FLEX_USES_RPM2() != true))
{
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), loggerSecondaryISR, CHANGE );
detachInterrupt(digitalPinToInterrupt(pinTrigger2));
attachInterrupt(digitalPinToInterrupt(pinTrigger2), loggerSecondaryISR, CHANGE);
}
}
@ -423,74 +418,73 @@ void stopCompositeLogger(void)
{
currentStatus.compositeTriggerUsed = 0;
//Disconnect the logger interrupts and attach the normal ones
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), triggerHandler, primaryTriggerEdge );
// Disconnect the logger interrupts and attach the normal ones
detachInterrupt(digitalPinToInterrupt(pinTrigger));
attachInterrupt(digitalPinToInterrupt(pinTrigger), triggerHandler, primaryTriggerEdge);
if( (VSS_USES_RPM2() != true) && (FLEX_USES_RPM2() != true) )
if((VSS_USES_RPM2() != true) && (FLEX_USES_RPM2() != true))
{
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), triggerSecondaryHandler, secondaryTriggerEdge );
detachInterrupt(digitalPinToInterrupt(pinTrigger2));
attachInterrupt(digitalPinToInterrupt(pinTrigger2), triggerSecondaryHandler, secondaryTriggerEdge);
}
}
void startCompositeLoggerTertiary(void)
{
currentStatus.compositeTriggerUsed = 3;
currentStatus.toothLogEnabled = false; //Safety first (Should never be required)
currentStatus.toothLogEnabled = false; // Safety first (Should never be required)
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY);
toothHistoryIndex = 0;
//Disconnect the standard interrupt and add the logger version
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), loggerPrimaryISR, CHANGE );
// Disconnect the standard interrupt and add the logger version
detachInterrupt(digitalPinToInterrupt(pinTrigger));
attachInterrupt(digitalPinToInterrupt(pinTrigger), loggerPrimaryISR, CHANGE);
detachInterrupt( digitalPinToInterrupt(pinTrigger3) );
attachInterrupt( digitalPinToInterrupt(pinTrigger3), loggerTertiaryISR, CHANGE );
detachInterrupt(digitalPinToInterrupt(pinTrigger3));
attachInterrupt(digitalPinToInterrupt(pinTrigger3), loggerTertiaryISR, CHANGE);
}
void stopCompositeLoggerTertiary(void)
{
currentStatus.compositeTriggerUsed = 0;
//Disconnect the logger interrupts and attach the normal ones
detachInterrupt( digitalPinToInterrupt(pinTrigger) );
attachInterrupt( digitalPinToInterrupt(pinTrigger), triggerHandler, primaryTriggerEdge );
// Disconnect the logger interrupts and attach the normal ones
detachInterrupt(digitalPinToInterrupt(pinTrigger));
attachInterrupt(digitalPinToInterrupt(pinTrigger), triggerHandler, primaryTriggerEdge);
detachInterrupt( digitalPinToInterrupt(pinTrigger3) );
attachInterrupt( digitalPinToInterrupt(pinTrigger3), triggerTertiaryHandler, tertiaryTriggerEdge );
detachInterrupt(digitalPinToInterrupt(pinTrigger3));
attachInterrupt(digitalPinToInterrupt(pinTrigger3), triggerTertiaryHandler, tertiaryTriggerEdge);
}
void startCompositeLoggerCams(void)
{
currentStatus.compositeTriggerUsed = 4;
currentStatus.toothLogEnabled = false; //Safety first (Should never be required)
currentStatus.toothLogEnabled = false; // Safety first (Should never be required)
BIT_CLEAR(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY);
toothHistoryIndex = 0;
//Disconnect the standard interrupt and add the logger version
if( (VSS_USES_RPM2() != true) && (FLEX_USES_RPM2() != true) )
// Disconnect the standard interrupt and add the logger version
if((VSS_USES_RPM2() != true) && (FLEX_USES_RPM2() != true))
{
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), loggerSecondaryISR, CHANGE );
detachInterrupt(digitalPinToInterrupt(pinTrigger2));
attachInterrupt(digitalPinToInterrupt(pinTrigger2), loggerSecondaryISR, CHANGE);
}
detachInterrupt( digitalPinToInterrupt(pinTrigger3) );
attachInterrupt( digitalPinToInterrupt(pinTrigger3), loggerTertiaryISR, CHANGE );
detachInterrupt(digitalPinToInterrupt(pinTrigger3));
attachInterrupt(digitalPinToInterrupt(pinTrigger3), loggerTertiaryISR, CHANGE);
}
void stopCompositeLoggerCams(void)
{
currentStatus.compositeTriggerUsed = false;
//Disconnect the logger interrupts and attach the normal ones
if( (VSS_USES_RPM2() != true) && (FLEX_USES_RPM2() != true) )
// Disconnect the logger interrupts and attach the normal ones
if((VSS_USES_RPM2() != true) && (FLEX_USES_RPM2() != true))
{
detachInterrupt( digitalPinToInterrupt(pinTrigger2) );
attachInterrupt( digitalPinToInterrupt(pinTrigger2), triggerSecondaryHandler, secondaryTriggerEdge );
detachInterrupt(digitalPinToInterrupt(pinTrigger2));
attachInterrupt(digitalPinToInterrupt(pinTrigger2), triggerSecondaryHandler, secondaryTriggerEdge);
}
detachInterrupt( digitalPinToInterrupt(pinTrigger3) );
attachInterrupt( digitalPinToInterrupt(pinTrigger3), triggerTertiaryHandler, tertiaryTriggerEdge );
detachInterrupt(digitalPinToInterrupt(pinTrigger3));
attachInterrupt(digitalPinToInterrupt(pinTrigger3), triggerTertiaryHandler, tertiaryTriggerEdge);
}

View File

@ -2,46 +2,43 @@
#include <stdlib.h>
#ifdef USE_LIBDIVIDE
#include "src/libdivide/constant_fast_div.h"
#include "src/libdivide/constant_fast_div.h"
// Constants used for libdivide. Using predefined constants saves flash and RAM (.bss)
// versus calling the libdivide generator functions (E.g. libdivide_s32_gen)
const libdivide::libdivide_s16_t libdiv_s16_100 = { .magic = S16_MAGIC(100), .more = S16_MORE(100) };
const libdivide::libdivide_u16_t libdiv_u16_100 = { .magic = U16_MAGIC(100), .more = U16_MORE(100) };
const libdivide::libdivide_s16_t libdiv_s16_100 = {.magic = S16_MAGIC(100), .more = S16_MORE(100)};
const libdivide::libdivide_u16_t libdiv_u16_100 = {.magic = U16_MAGIC(100), .more = U16_MORE(100)};
// 32-bit constants generated here: https://godbolt.org/z/vP8Kfejo9
const libdivide::libdivide_u32_t libdiv_u32_100 = { .magic = 2748779070, .more = 6 };
const libdivide::libdivide_s32_t libdiv_s32_100 = { .magic = 1374389535, .more = 5 };
const libdivide::libdivide_u32_t libdiv_u32_200 = { .magic = 2748779070, .more = 7 };
const libdivide::libdivide_u32_t libdiv_u32_360 = { .magic = 1813430637, .more = 72 };
const libdivide::libdivide_u32_t libdiv_u32_100 = {.magic = 2748779070, .more = 6};
const libdivide::libdivide_s32_t libdiv_s32_100 = {.magic = 1374389535, .more = 5};
const libdivide::libdivide_u32_t libdiv_u32_200 = {.magic = 2748779070, .more = 7};
const libdivide::libdivide_u32_t libdiv_u32_360 = {.magic = 1813430637, .more = 72};
#endif
//Replace the standard arduino map() function to use the div function instead
// Replace the standard arduino map() function to use the div function instead
int fastMap(unsigned long x, int in_min, int in_max, int out_min, int out_max)
{
unsigned long a = (x - (unsigned long)in_min);
int b = (out_max - out_min);
int c = (in_max - in_min);
int d = (ldiv( (a * (long)b) , (long)c ).quot);
int b = (out_max - out_min);
int c = (in_max - in_min);
int d = (ldiv((a * (long)b), (long)c).quot);
return d + out_min;
//return ldiv( ((x - in_min) * (out_max - out_min)) , (in_max - in_min) ).quot + out_min;
//return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
// return ldiv( ((x - in_min) * (out_max - out_min)) , (in_max - in_min) ).quot + out_min;
// return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
//Return x percent of y
//This is a relatively fast approximation of a percentage value.
unsigned long percentage(uint8_t x, unsigned long y)
{
return div100(y * x);
}
// Return x percent of y
// This is a relatively fast approximation of a percentage value.
unsigned long percentage(uint8_t x, unsigned long y) { return div100(y * x); }
//Same as above, but 0.5% accuracy
// Same as above, but 0.5% accuracy
unsigned long halfPercentage(uint8_t x, unsigned long y)
{
#ifdef USE_LIBDIVIDE
return libdivide::libdivide_u32_do(y * x, &libdiv_u32_200);
#ifdef USE_LIBDIVIDE
return libdivide::libdivide_u32_do(y * x, &libdiv_u32_200);
#else
return (y * x) / 200;
#endif
return (y * x) / 200;
#endif
}
/*
@ -49,20 +46,23 @@ unsigned long halfPercentage(uint8_t x, unsigned long y)
*/
inline long powint(int factor, unsigned int exponent)
{
long product = 1;
long product = 1;
unsigned int counter = exponent;
while ( (counter--) > 0) { product *= factor; }
while((counter--) > 0)
{
product *= factor;
}
return product;
}
//Generates a random number from 1 to 100 (inclusive).
//The initial seed used is always based on micros(), though this is unlikely to cause an issue as the first run is nearly random itself
//Function requires 4 bytes to store state and seed, but operates very quickly (around 4uS per call)
// Generates a random number from 1 to 100 (inclusive).
// The initial seed used is always based on micros(), though this is unlikely to cause an issue as the first run is nearly random itself
// Function requires 4 bytes to store state and seed, but operates very quickly (around 4uS per call)
uint8_t a, x, y, z;
uint8_t random1to100()
{
//Check if this is the first time being run. If so, seed the random number generator with micros()
if( (a == 0) && (x == 0) && (y == 0) && (z == 0) )
// Check if this is the first time being run. If so, seed the random number generator with micros()
if((a == 0) && (x == 0) && (y == 0) && (z == 0))
{
x = micros() >> 24;
y = micros() >> 16;
@ -73,11 +73,10 @@ uint8_t random1to100()
do
{
unsigned char t = x ^ (x << 4);
x=y;
y=z;
z=a;
a = z ^ t ^ ( z >> 1) ^ (t << 1);
}
while(a >= 100);
return (a+1);
x = y;
y = z;
z = a;
a = z ^ t ^ (z >> 1) ^ (t << 1);
} while(a >= 100);
return (a + 1);
}

View File

@ -1,129 +1,128 @@
#include "globals.h"
#include RTC_LIB_H //Defined in each boards .h file
#ifdef RTC_ENABLED
#include "rtc_common.h"
#include "rtc_common.h"
void initRTC()
{
#if defined(CORE_TEENSY35) || defined(CORE_TEENSY36)|| defined(CORE_TEENSY41)
setSyncProvider(getTeensy3Time);
#if defined(CORE_TEENSY35) || defined(CORE_TEENSY36) || defined(CORE_TEENSY41)
setSyncProvider(getTeensy3Time);
#elif defined(CORE_STM32)
#endif
#endif
}
uint8_t rtc_getSecond()
{
uint8_t tempSecond = 0;
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempSecond = second();
#elif defined(CORE_STM32)
tempSecond = rtc.getSeconds();
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempSecond = second();
#elif defined(CORE_STM32)
tempSecond = rtc.getSeconds();
#endif
#endif
#endif
return tempSecond;
}
uint8_t rtc_getMinute()
{
uint8_t tempMinute = 0;
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempMinute = minute();
#elif defined(CORE_STM32)
tempMinute = rtc.getMinutes();
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempMinute = minute();
#elif defined(CORE_STM32)
tempMinute = rtc.getMinutes();
#endif
#endif
#endif
return tempMinute;
}
uint8_t rtc_getHour()
{
uint8_t tempHour = 0;
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempHour = hour();
#elif defined(CORE_STM32)
tempHour = rtc.getHours();
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempHour = hour();
#elif defined(CORE_STM32)
tempHour = rtc.getHours();
#endif
#endif
#endif
return tempHour;
}
uint8_t rtc_getDay()
{
uint8_t tempDay = 0;
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempDay = day();
#elif defined(CORE_STM32)
tempDay = rtc.getDay();
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempDay = day();
#elif defined(CORE_STM32)
tempDay = rtc.getDay();
#endif
#endif
#endif
return tempDay;
}
uint8_t rtc_getDOW()
{
uint8_t dow = 0;
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
dow = weekday();
#elif defined(CORE_STM32)
dow = rtc.getWeekDay();
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
dow = weekday();
#elif defined(CORE_STM32)
dow = rtc.getWeekDay();
#endif
#endif
#endif
return dow;
}
uint8_t rtc_getMonth()
{
uint8_t tempMonth = 0;
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempMonth = month();
#elif defined(CORE_STM32)
tempMonth = rtc.getMonth();
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempMonth = month();
#elif defined(CORE_STM32)
tempMonth = rtc.getMonth();
#endif
#endif
#endif
return tempMonth;
}
uint16_t rtc_getYear()
{
uint16_t tempYear = 0;
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempYear = year();
#elif defined(CORE_STM32)
//year in stm32 rtc is a byte. So add year 2000 to make it correct
tempYear = (2000+rtc.getYear());
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
tempYear = year();
#elif defined(CORE_STM32)
// year in stm32 rtc is a byte. So add year 2000 to make it correct
tempYear = (2000 + rtc.getYear());
#endif
#endif
#endif
return tempYear;
}
void rtc_setTime(byte second, byte minute, byte hour, byte day, byte month, uint16_t year)
{
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
setTime(hour, minute, second, day, month, year);
Teensy3Clock.set(now());
#elif defined(CORE_STM32)
//If RTC time has not been set earlier (no battery etc.) we need to stop the RTC and restart it with LSE_CLOCK to have accurate RTC.
if (!rtc.isTimeSet()) {
rtc.end();
rtc.setClockSource(STM32RTC::LSE_CLOCK);
rtc.begin();
}
rtc.setTime(hour, minute, second);
//year in stm32 rtc is a byte. so subtract year 2000 to fit
rtc.setDate(day, month, (year-2000));
#ifdef RTC_ENABLED
#if defined(CORE_TEENSY)
setTime(hour, minute, second, day, month, year);
Teensy3Clock.set(now());
#elif defined(CORE_STM32)
// If RTC time has not been set earlier (no battery etc.) we need to stop the RTC and restart it with LSE_CLOCK to have accurate RTC.
if(!rtc.isTimeSet())
{
rtc.end();
rtc.setClockSource(STM32RTC::LSE_CLOCK);
rtc.begin();
}
rtc.setTime(hour, minute, second);
// year in stm32 rtc is a byte. so subtract year 2000 to fit
rtc.setDate(day, month, (year - 2000));
#endif
#endif
#endif
}
#endif

View File

@ -6,127 +6,510 @@
/** @file
* Injector and Coil (toggle/open/close) control (under various situations, eg with particular cylinder count, rotary engine type or wasted spark ign, etc.).
* Also accounts for presence of MC33810 injector/ignition (dwell, etc.) control circuit.
* Functions here are typically assigned (at initialisation) to callback function variables (e.g. inj1StartFunction or inj1EndFunction)
* Functions here are typically assigned (at initialisation) to callback function variables (e.g. inj1StartFunction or inj1EndFunction)
* form where they are called (by scheduler.ino).
*/
inline void openInjector1(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector1_DIRECT(); } else { openInjector1_MC33810(); } }
inline void closeInjector1(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector1_DIRECT(); } else { closeInjector1_MC33810(); } }
inline void openInjector2(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector2_DIRECT(); } else { openInjector2_MC33810(); } }
inline void closeInjector2(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector2_DIRECT(); } else { closeInjector2_MC33810(); } }
inline void openInjector3(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector3_DIRECT(); } else { openInjector3_MC33810(); } }
inline void closeInjector3(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector3_DIRECT(); } else { closeInjector3_MC33810(); } }
inline void openInjector4(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector4_DIRECT(); } else { openInjector4_MC33810(); } }
inline void closeInjector4(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector4_DIRECT(); } else { closeInjector4_MC33810(); } }
inline void openInjector5(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector5_DIRECT(); } else { openInjector5_MC33810(); } }
inline void closeInjector5(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector5_DIRECT(); } else { closeInjector5_MC33810(); } }
inline void openInjector6(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector6_DIRECT(); } else { openInjector6_MC33810(); } }
inline void closeInjector6(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector6_DIRECT(); } else { closeInjector6_MC33810(); } }
inline void openInjector7(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector7_DIRECT(); } else { openInjector7_MC33810(); } }
inline void closeInjector7(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector7_DIRECT(); } else { closeInjector7_MC33810(); } }
inline void openInjector8(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector8_DIRECT(); } else { openInjector8_MC33810(); } }
inline void closeInjector8(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector8_DIRECT(); } else { closeInjector8_MC33810(); } }
inline void openInjector1(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector1_DIRECT(); }
else { openInjector1_MC33810(); }
}
inline void closeInjector1(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector1_DIRECT(); }
else { closeInjector1_MC33810(); }
}
inline void openInjector2(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector2_DIRECT(); }
else { openInjector2_MC33810(); }
}
inline void closeInjector2(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector2_DIRECT(); }
else { closeInjector2_MC33810(); }
}
inline void openInjector3(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector3_DIRECT(); }
else { openInjector3_MC33810(); }
}
inline void closeInjector3(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector3_DIRECT(); }
else { closeInjector3_MC33810(); }
}
inline void openInjector4(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector4_DIRECT(); }
else { openInjector4_MC33810(); }
}
inline void closeInjector4(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector4_DIRECT(); }
else { closeInjector4_MC33810(); }
}
inline void openInjector5(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector5_DIRECT(); }
else { openInjector5_MC33810(); }
}
inline void closeInjector5(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector5_DIRECT(); }
else { closeInjector5_MC33810(); }
}
inline void openInjector6(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector6_DIRECT(); }
else { openInjector6_MC33810(); }
}
inline void closeInjector6(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector6_DIRECT(); }
else { closeInjector6_MC33810(); }
}
inline void openInjector7(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector7_DIRECT(); }
else { openInjector7_MC33810(); }
}
inline void closeInjector7(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector7_DIRECT(); }
else { closeInjector7_MC33810(); }
}
inline void openInjector8(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { openInjector8_DIRECT(); }
else { openInjector8_MC33810(); }
}
inline void closeInjector8(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { closeInjector8_DIRECT(); }
else { closeInjector8_MC33810(); }
}
inline void injector1Toggle(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector1Toggle_DIRECT(); } else { injector1Toggle_MC33810(); } }
inline void injector2Toggle(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector2Toggle_DIRECT(); } else { injector2Toggle_MC33810(); } }
inline void injector3Toggle(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector3Toggle_DIRECT(); } else { injector3Toggle_MC33810(); } }
inline void injector4Toggle(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector4Toggle_DIRECT(); } else { injector4Toggle_MC33810(); } }
inline void injector5Toggle(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector5Toggle_DIRECT(); } else { injector5Toggle_MC33810(); } }
inline void injector6Toggle(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector6Toggle_DIRECT(); } else { injector6Toggle_MC33810(); } }
inline void injector7Toggle(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector7Toggle_DIRECT(); } else { injector7Toggle_MC33810(); } }
inline void injector8Toggle(void) { if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector8Toggle_DIRECT(); } else { injector8Toggle_MC33810(); } }
inline void injector1Toggle(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector1Toggle_DIRECT(); }
else { injector1Toggle_MC33810(); }
}
inline void injector2Toggle(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector2Toggle_DIRECT(); }
else { injector2Toggle_MC33810(); }
}
inline void injector3Toggle(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector3Toggle_DIRECT(); }
else { injector3Toggle_MC33810(); }
}
inline void injector4Toggle(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector4Toggle_DIRECT(); }
else { injector4Toggle_MC33810(); }
}
inline void injector5Toggle(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector5Toggle_DIRECT(); }
else { injector5Toggle_MC33810(); }
}
inline void injector6Toggle(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector6Toggle_DIRECT(); }
else { injector6Toggle_MC33810(); }
}
inline void injector7Toggle(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector7Toggle_DIRECT(); }
else { injector7Toggle_MC33810(); }
}
inline void injector8Toggle(void)
{
if(injectorOutputControl != OUTPUT_CONTROL_MC33810) { injector8Toggle_DIRECT(); }
else { injector8Toggle_MC33810(); }
}
inline void coil1Toggle(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil1Toggle_DIRECT(); } else { coil1Toggle_MC33810(); } }
inline void coil2Toggle(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil2Toggle_DIRECT(); } else { coil2Toggle_MC33810(); } }
inline void coil3Toggle(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil3Toggle_DIRECT(); } else { coil3Toggle_MC33810(); } }
inline void coil4Toggle(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil4Toggle_DIRECT(); } else { coil4Toggle_MC33810(); } }
inline void coil5Toggle(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil5Toggle_DIRECT(); } else { coil5Toggle_MC33810(); } }
inline void coil6Toggle(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil6Toggle_DIRECT(); } else { coil6Toggle_MC33810(); } }
inline void coil7Toggle(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil7Toggle_DIRECT(); } else { coil7Toggle_MC33810(); } }
inline void coil8Toggle(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil8Toggle_DIRECT(); } else { coil8Toggle_MC33810(); } }
inline void coil1Toggle(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil1Toggle_DIRECT(); }
else { coil1Toggle_MC33810(); }
}
inline void coil2Toggle(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil2Toggle_DIRECT(); }
else { coil2Toggle_MC33810(); }
}
inline void coil3Toggle(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil3Toggle_DIRECT(); }
else { coil3Toggle_MC33810(); }
}
inline void coil4Toggle(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil4Toggle_DIRECT(); }
else { coil4Toggle_MC33810(); }
}
inline void coil5Toggle(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil5Toggle_DIRECT(); }
else { coil5Toggle_MC33810(); }
}
inline void coil6Toggle(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil6Toggle_DIRECT(); }
else { coil6Toggle_MC33810(); }
}
inline void coil7Toggle(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil7Toggle_DIRECT(); }
else { coil7Toggle_MC33810(); }
}
inline void coil8Toggle(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil8Toggle_DIRECT(); }
else { coil8Toggle_MC33810(); }
}
// These are for Semi-Sequential and 5 Cylinder injection
//Standard 4 cylinder pairings
void openInjector1and3(void) { openInjector1(); openInjector3(); }
void closeInjector1and3(void) { closeInjector1(); closeInjector3(); }
void openInjector2and4(void) { openInjector2(); openInjector4(); }
void closeInjector2and4(void) { closeInjector2(); closeInjector4(); }
//Alternative output pairings
void openInjector1and4(void) { openInjector1(); openInjector4(); }
void closeInjector1and4(void) { closeInjector1(); closeInjector4(); }
void openInjector2and3(void) { openInjector2(); openInjector3(); }
void closeInjector2and3(void) { closeInjector2(); closeInjector3(); }
// Standard 4 cylinder pairings
void openInjector1and3(void)
{
openInjector1();
openInjector3();
}
void closeInjector1and3(void)
{
closeInjector1();
closeInjector3();
}
void openInjector2and4(void)
{
openInjector2();
openInjector4();
}
void closeInjector2and4(void)
{
closeInjector2();
closeInjector4();
}
// Alternative output pairings
void openInjector1and4(void)
{
openInjector1();
openInjector4();
}
void closeInjector1and4(void)
{
closeInjector1();
closeInjector4();
}
void openInjector2and3(void)
{
openInjector2();
openInjector3();
}
void closeInjector2and3(void)
{
closeInjector2();
closeInjector3();
}
void openInjector3and5(void) { openInjector3(); openInjector5(); }
void closeInjector3and5(void) { closeInjector3(); closeInjector5(); }
void openInjector3and5(void)
{
openInjector3();
openInjector5();
}
void closeInjector3and5(void)
{
closeInjector3();
closeInjector5();
}
void openInjector2and5(void) { openInjector2(); openInjector5(); }
void closeInjector2and5(void) { closeInjector2(); closeInjector5(); }
void openInjector3and6(void) { openInjector3(); openInjector6(); }
void closeInjector3and6(void) { closeInjector3(); closeInjector6(); }
void openInjector2and5(void)
{
openInjector2();
openInjector5();
}
void closeInjector2and5(void)
{
closeInjector2();
closeInjector5();
}
void openInjector3and6(void)
{
openInjector3();
openInjector6();
}
void closeInjector3and6(void)
{
closeInjector3();
closeInjector6();
}
void openInjector1and5(void) { openInjector1(); openInjector5(); }
void closeInjector1and5(void) { closeInjector1(); closeInjector5(); }
void openInjector2and6(void) { openInjector2(); openInjector6(); }
void closeInjector2and6(void) { closeInjector2(); closeInjector6(); }
void openInjector3and7(void) { openInjector3(); openInjector7(); }
void closeInjector3and7(void) { closeInjector3(); closeInjector7(); }
void openInjector4and8(void) { openInjector4(); openInjector8(); }
void closeInjector4and8(void) { closeInjector4(); closeInjector8(); }
void openInjector1and5(void)
{
openInjector1();
openInjector5();
}
void closeInjector1and5(void)
{
closeInjector1();
closeInjector5();
}
void openInjector2and6(void)
{
openInjector2();
openInjector6();
}
void closeInjector2and6(void)
{
closeInjector2();
closeInjector6();
}
void openInjector3and7(void)
{
openInjector3();
openInjector7();
}
void closeInjector3and7(void)
{
closeInjector3();
closeInjector7();
}
void openInjector4and8(void)
{
openInjector4();
openInjector8();
}
void closeInjector4and8(void)
{
closeInjector4();
closeInjector8();
}
inline void beginCoil1Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil1Charging_DIRECT(); } else { coil1Charging_MC33810(); } tachoOutputOn(); }
inline void endCoil1Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil1StopCharging_DIRECT(); } else { coil1StopCharging_MC33810(); } tachoOutputOff(); }
inline void beginCoil1Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil1Charging_DIRECT(); }
else { coil1Charging_MC33810(); }
tachoOutputOn();
}
inline void endCoil1Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil1StopCharging_DIRECT(); }
else { coil1StopCharging_MC33810(); }
tachoOutputOff();
}
inline void beginCoil2Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil2Charging_DIRECT(); } else { coil2Charging_MC33810(); } tachoOutputOn(); }
inline void endCoil2Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil2StopCharging_DIRECT(); } else { coil2StopCharging_MC33810(); } tachoOutputOff(); }
inline void beginCoil2Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil2Charging_DIRECT(); }
else { coil2Charging_MC33810(); }
tachoOutputOn();
}
inline void endCoil2Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil2StopCharging_DIRECT(); }
else { coil2StopCharging_MC33810(); }
tachoOutputOff();
}
inline void beginCoil3Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil3Charging_DIRECT(); } else { coil3Charging_MC33810(); } tachoOutputOn(); }
inline void endCoil3Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil3StopCharging_DIRECT(); } else { coil3StopCharging_MC33810(); } tachoOutputOff(); }
inline void beginCoil3Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil3Charging_DIRECT(); }
else { coil3Charging_MC33810(); }
tachoOutputOn();
}
inline void endCoil3Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil3StopCharging_DIRECT(); }
else { coil3StopCharging_MC33810(); }
tachoOutputOff();
}
inline void beginCoil4Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil4Charging_DIRECT(); } else { coil4Charging_MC33810(); } tachoOutputOn(); }
inline void endCoil4Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil4StopCharging_DIRECT(); } else { coil4StopCharging_MC33810(); } tachoOutputOff(); }
inline void beginCoil4Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil4Charging_DIRECT(); }
else { coil4Charging_MC33810(); }
tachoOutputOn();
}
inline void endCoil4Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil4StopCharging_DIRECT(); }
else { coil4StopCharging_MC33810(); }
tachoOutputOff();
}
inline void beginCoil5Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil5Charging_DIRECT(); } else { coil5Charging_MC33810(); } tachoOutputOn(); }
inline void endCoil5Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil5StopCharging_DIRECT(); } else { coil5StopCharging_MC33810(); } tachoOutputOff(); }
inline void beginCoil5Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil5Charging_DIRECT(); }
else { coil5Charging_MC33810(); }
tachoOutputOn();
}
inline void endCoil5Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil5StopCharging_DIRECT(); }
else { coil5StopCharging_MC33810(); }
tachoOutputOff();
}
inline void beginCoil6Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil6Charging_DIRECT(); } else { coil6Charging_MC33810(); } tachoOutputOn(); }
inline void endCoil6Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil6StopCharging_DIRECT(); } else { coil6StopCharging_MC33810(); } tachoOutputOff(); }
inline void beginCoil6Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil6Charging_DIRECT(); }
else { coil6Charging_MC33810(); }
tachoOutputOn();
}
inline void endCoil6Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil6StopCharging_DIRECT(); }
else { coil6StopCharging_MC33810(); }
tachoOutputOff();
}
inline void beginCoil7Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil7Charging_DIRECT(); } else { coil7Charging_MC33810(); } tachoOutputOn(); }
inline void endCoil7Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil7StopCharging_DIRECT(); } else { coil7StopCharging_MC33810(); } tachoOutputOff(); }
inline void beginCoil7Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil7Charging_DIRECT(); }
else { coil7Charging_MC33810(); }
tachoOutputOn();
}
inline void endCoil7Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil7StopCharging_DIRECT(); }
else { coil7StopCharging_MC33810(); }
tachoOutputOff();
}
inline void beginCoil8Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil8Charging_DIRECT(); } else { coil8Charging_MC33810(); } tachoOutputOn(); }
inline void endCoil8Charge(void) { if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil8StopCharging_DIRECT(); } else { coil8StopCharging_MC33810(); } tachoOutputOff(); }
inline void beginCoil8Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil8Charging_DIRECT(); }
else { coil8Charging_MC33810(); }
tachoOutputOn();
}
inline void endCoil8Charge(void)
{
if(ignitionOutputControl != OUTPUT_CONTROL_MC33810) { coil8StopCharging_DIRECT(); }
else { coil8StopCharging_MC33810(); }
tachoOutputOff();
}
//The below 3 calls are all part of the rotary ignition mode
// The below 3 calls are all part of the rotary ignition mode
inline void beginTrailingCoilCharge(void) { beginCoil2Charge(); }
inline void endTrailingCoilCharge1(void) { endCoil2Charge(); beginCoil3Charge(); } //Sets ign3 (Trailing select) high
inline void endTrailingCoilCharge2(void) { endCoil2Charge(); endCoil3Charge(); } //sets ign3 (Trailing select) low
inline void endTrailingCoilCharge1(void)
{
endCoil2Charge();
beginCoil3Charge();
} // Sets ign3 (Trailing select) high
inline void endTrailingCoilCharge2(void)
{
endCoil2Charge();
endCoil3Charge();
} // sets ign3 (Trailing select) low
//As above but for ignition (Wasted COP mode)
void beginCoil1and3Charge(void) { beginCoil1Charge(); beginCoil3Charge(); }
void endCoil1and3Charge(void) { endCoil1Charge(); endCoil3Charge(); }
void beginCoil2and4Charge(void) { beginCoil2Charge(); beginCoil4Charge(); }
void endCoil2and4Charge(void) { endCoil2Charge(); endCoil4Charge(); }
// As above but for ignition (Wasted COP mode)
void beginCoil1and3Charge(void)
{
beginCoil1Charge();
beginCoil3Charge();
}
void endCoil1and3Charge(void)
{
endCoil1Charge();
endCoil3Charge();
}
void beginCoil2and4Charge(void)
{
beginCoil2Charge();
beginCoil4Charge();
}
void endCoil2and4Charge(void)
{
endCoil2Charge();
endCoil4Charge();
}
//For 6cyl wasted COP mode)
void beginCoil1and4Charge(void) { beginCoil1Charge(); beginCoil4Charge(); }
void endCoil1and4Charge(void) { endCoil1Charge(); endCoil4Charge(); }
void beginCoil2and5Charge(void) { beginCoil2Charge(); beginCoil5Charge(); }
void endCoil2and5Charge(void) { endCoil2Charge(); endCoil5Charge(); }
void beginCoil3and6Charge(void) { beginCoil3Charge(); beginCoil6Charge(); }
void endCoil3and6Charge(void) { endCoil3Charge(); endCoil6Charge(); }
// For 6cyl wasted COP mode)
void beginCoil1and4Charge(void)
{
beginCoil1Charge();
beginCoil4Charge();
}
void endCoil1and4Charge(void)
{
endCoil1Charge();
endCoil4Charge();
}
void beginCoil2and5Charge(void)
{
beginCoil2Charge();
beginCoil5Charge();
}
void endCoil2and5Charge(void)
{
endCoil2Charge();
endCoil5Charge();
}
void beginCoil3and6Charge(void)
{
beginCoil3Charge();
beginCoil6Charge();
}
void endCoil3and6Charge(void)
{
endCoil3Charge();
endCoil6Charge();
}
//For 8cyl wasted COP mode)
void beginCoil1and5Charge(void) { beginCoil1Charge(); beginCoil5Charge(); }
void endCoil1and5Charge(void) { endCoil1Charge(); endCoil5Charge(); }
void beginCoil2and6Charge(void) { beginCoil2Charge(); beginCoil6Charge(); }
void endCoil2and6Charge(void) { endCoil2Charge(); endCoil6Charge(); }
void beginCoil3and7Charge(void) { beginCoil3Charge(); beginCoil7Charge(); }
void endCoil3and7Charge(void) { endCoil3Charge(); endCoil7Charge(); }
void beginCoil4and8Charge(void) { beginCoil4Charge(); beginCoil8Charge(); }
void endCoil4and8Charge(void) { endCoil4Charge(); endCoil8Charge(); }
// For 8cyl wasted COP mode)
void beginCoil1and5Charge(void)
{
beginCoil1Charge();
beginCoil5Charge();
}
void endCoil1and5Charge(void)
{
endCoil1Charge();
endCoil5Charge();
}
void beginCoil2and6Charge(void)
{
beginCoil2Charge();
beginCoil6Charge();
}
void endCoil2and6Charge(void)
{
endCoil2Charge();
endCoil6Charge();
}
void beginCoil3and7Charge(void)
{
beginCoil3Charge();
beginCoil7Charge();
}
void endCoil3and7Charge(void)
{
endCoil3Charge();
endCoil7Charge();
}
void beginCoil4and8Charge(void)
{
beginCoil4Charge();
beginCoil8Charge();
}
void endCoil4and8Charge(void)
{
endCoil4Charge();
endCoil8Charge();
}
void tachoOutputOn(void) { if(configPage6.tachoMode) { TACHO_PULSE_LOW(); } else { tachoOutputFlag = READY; } }
void tachoOutputOff(void) { if(configPage6.tachoMode) { TACHO_PULSE_HIGH(); } }
void tachoOutputOn(void)
{
if(configPage6.tachoMode) { TACHO_PULSE_LOW(); }
else { tachoOutputFlag = READY; }
}
void tachoOutputOff(void)
{
if(configPage6.tachoMode) { TACHO_PULSE_HIGH(); }
}
void nullCallback(void) { return; }

File diff suppressed because it is too large Load Diff

View File

@ -4,14 +4,14 @@
void calculateSecondaryFuel(void)
{
//If the secondary fuel table is in use, also get the VE value from there
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Clear the bit indicating that the 2nd fuel table is in use.
// If the secondary fuel table is in use, also get the VE value from there
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); // Clear the bit indicating that the 2nd fuel table is in use.
if(configPage10.fuel2Mode > 0)
{
{
if(configPage10.fuel2Mode == FUEL2_MODE_MULTIPLY)
{
currentStatus.VE2 = getVE2();
//Fuel 2 table is treated as a % value. Table 1 and 2 are multiplied together and divided by 100
// Fuel 2 table is treated as a % value. Table 1 and 2 are multiplied together and divided by 100
uint16_t combinedVE = ((uint16_t)currentStatus.VE1 * (uint16_t)currentStatus.VE2) / 100;
if(combinedVE <= 255) { currentStatus.VE = combinedVE; }
else { currentStatus.VE = 255; }
@ -19,47 +19,47 @@ void calculateSecondaryFuel(void)
else if(configPage10.fuel2Mode == FUEL2_MODE_ADD)
{
currentStatus.VE2 = getVE2();
//Fuel tables are added together, but a check is made to make sure this won't overflow the 8-bit VE value
// Fuel tables are added together, but a check is made to make sure this won't overflow the 8-bit VE value
uint16_t combinedVE = (uint16_t)currentStatus.VE1 + (uint16_t)currentStatus.VE2;
if(combinedVE <= 255) { currentStatus.VE = combinedVE; }
else { currentStatus.VE = 255; }
}
else if(configPage10.fuel2Mode == FUEL2_MODE_CONDITIONAL_SWITCH )
else if(configPage10.fuel2Mode == FUEL2_MODE_CONDITIONAL_SWITCH)
{
if(configPage10.fuel2SwitchVariable == FUEL2_CONDITION_RPM)
{
if(currentStatus.RPM > configPage10.fuel2SwitchValue)
{
BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Set the bit indicating that the 2nd fuel table is in use.
BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); // Set the bit indicating that the 2nd fuel table is in use.
currentStatus.VE2 = getVE2();
currentStatus.VE = currentStatus.VE2;
currentStatus.VE = currentStatus.VE2;
}
}
else if(configPage10.fuel2SwitchVariable == FUEL2_CONDITION_MAP)
{
if(currentStatus.MAP > configPage10.fuel2SwitchValue)
{
BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Set the bit indicating that the 2nd fuel table is in use.
BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); // Set the bit indicating that the 2nd fuel table is in use.
currentStatus.VE2 = getVE2();
currentStatus.VE = currentStatus.VE2;
currentStatus.VE = currentStatus.VE2;
}
}
else if(configPage10.fuel2SwitchVariable == FUEL2_CONDITION_TPS)
{
if(currentStatus.TPS > configPage10.fuel2SwitchValue)
{
BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Set the bit indicating that the 2nd fuel table is in use.
BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); // Set the bit indicating that the 2nd fuel table is in use.
currentStatus.VE2 = getVE2();
currentStatus.VE = currentStatus.VE2;
currentStatus.VE = currentStatus.VE2;
}
}
else if(configPage10.fuel2SwitchVariable == FUEL2_CONDITION_ETH)
{
if(currentStatus.ethanolPct > configPage10.fuel2SwitchValue)
{
BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Set the bit indicating that the 2nd fuel table is in use.
BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); // Set the bit indicating that the 2nd fuel table is in use.
currentStatus.VE2 = getVE2();
currentStatus.VE = currentStatus.VE2;
currentStatus.VE = currentStatus.VE2;
}
}
}
@ -67,79 +67,78 @@ void calculateSecondaryFuel(void)
{
if(digitalRead(pinFuel2Input) == configPage10.fuel2InputPolarity)
{
BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Set the bit indicating that the 2nd fuel table is in use.
BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); // Set the bit indicating that the 2nd fuel table is in use.
currentStatus.VE2 = getVE2();
currentStatus.VE = currentStatus.VE2;
currentStatus.VE = currentStatus.VE2;
}
}
}
}
void calculateSecondarySpark(void)
{
//Same as above but for the secondary ignition table
BIT_CLEAR(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); //Clear the bit indicating that the 2nd spark table is in use.
// Same as above but for the secondary ignition table
BIT_CLEAR(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); // Clear the bit indicating that the 2nd spark table is in use.
if(configPage10.spark2Mode > 0)
{
{
if(configPage10.spark2Mode == SPARK2_MODE_MULTIPLY)
{
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE);
currentStatus.advance2 = getAdvance2();
//make sure we don't have a negative value in the multiplier table (sharing a signed 8 bit table)
// make sure we don't have a negative value in the multiplier table (sharing a signed 8 bit table)
if(currentStatus.advance2 < 0) { currentStatus.advance2 = 0; }
//Spark 2 table is treated as a % value. Table 1 and 2 are multiplied together and divided by 100
// Spark 2 table is treated as a % value. Table 1 and 2 are multiplied together and divided by 100
int16_t combinedAdvance = ((int16_t)currentStatus.advance1 * (int16_t)currentStatus.advance2) / 100;
//make sure we don't overflow and accidentally set negative timing, currentStatus.advance can only hold a signed 8 bit value
// make sure we don't overflow and accidentally set negative timing, currentStatus.advance can only hold a signed 8 bit value
if(combinedAdvance <= 127) { currentStatus.advance = combinedAdvance; }
else { currentStatus.advance = 127; }
}
else if(configPage10.spark2Mode == SPARK2_MODE_ADD)
{
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); //Set the bit indicating that the 2nd spark table is in use.
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); // Set the bit indicating that the 2nd spark table is in use.
currentStatus.advance2 = getAdvance2();
//Spark tables are added together, but a check is made to make sure this won't overflow the 8-bit VE value
// Spark tables are added together, but a check is made to make sure this won't overflow the 8-bit VE value
int16_t combinedAdvance = (int16_t)currentStatus.advance1 + (int16_t)currentStatus.advance2;
//make sure we don't overflow and accidentally set negative timing, currentStatus.advance can only hold a signed 8 bit value
// make sure we don't overflow and accidentally set negative timing, currentStatus.advance can only hold a signed 8 bit value
if(combinedAdvance <= 127) { currentStatus.advance = combinedAdvance; }
else { currentStatus.advance = 127; }
}
else if(configPage10.spark2Mode == SPARK2_MODE_CONDITIONAL_SWITCH )
else if(configPage10.spark2Mode == SPARK2_MODE_CONDITIONAL_SWITCH)
{
if(configPage10.spark2SwitchVariable == SPARK2_CONDITION_RPM)
{
if(currentStatus.RPM > configPage10.spark2SwitchValue)
{
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); //Set the bit indicating that the 2nd spark table is in use.
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); // Set the bit indicating that the 2nd spark table is in use.
currentStatus.advance2 = getAdvance2();
currentStatus.advance = currentStatus.advance2;
currentStatus.advance = currentStatus.advance2;
}
}
else if(configPage10.spark2SwitchVariable == SPARK2_CONDITION_MAP)
{
if(currentStatus.MAP > configPage10.spark2SwitchValue)
{
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); //Set the bit indicating that the 2nd spark table is in use.
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); // Set the bit indicating that the 2nd spark table is in use.
currentStatus.advance2 = getAdvance2();
currentStatus.advance = currentStatus.advance2;
currentStatus.advance = currentStatus.advance2;
}
}
else if(configPage10.spark2SwitchVariable == SPARK2_CONDITION_TPS)
{
if(currentStatus.TPS > configPage10.spark2SwitchValue)
{
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); //Set the bit indicating that the 2nd spark table is in use.
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); // Set the bit indicating that the 2nd spark table is in use.
currentStatus.advance2 = getAdvance2();
currentStatus.advance = currentStatus.advance2;
currentStatus.advance = currentStatus.advance2;
}
}
else if(configPage10.spark2SwitchVariable == SPARK2_CONDITION_ETH)
{
if(currentStatus.ethanolPct > configPage10.spark2SwitchValue)
{
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); //Set the bit indicating that the 2nd spark table is in use.
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); // Set the bit indicating that the 2nd spark table is in use.
currentStatus.advance2 = getAdvance2();
currentStatus.advance = currentStatus.advance2;
currentStatus.advance = currentStatus.advance2;
}
}
}
@ -147,74 +146,73 @@ void calculateSecondarySpark(void)
{
if(digitalRead(pinSpark2Input) == configPage10.spark2InputPolarity)
{
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); //Set the bit indicating that the 2nd spark table is in use.
BIT_SET(currentStatus.spark2, BIT_SPARK2_SPARK2_ACTIVE); // Set the bit indicating that the 2nd spark table is in use.
currentStatus.advance2 = getAdvance2();
currentStatus.advance = currentStatus.advance2;
currentStatus.advance = currentStatus.advance2;
}
}
//Apply the fixed timing correction manually. This has to be done again here if any of the above conditions are met to prevent any of the seconadary calculations applying instead of fixec timing
// Apply the fixed timing correction manually. This has to be done again here if any of the above conditions are met to prevent any of the seconadary calculations applying instead of fixec timing
currentStatus.advance = correctionFixedTiming(currentStatus.advance);
currentStatus.advance = correctionCrankingFixedTiming(currentStatus.advance); //This overrides the regular fixed timing, must come last
currentStatus.advance = correctionCrankingFixedTiming(currentStatus.advance); // This overrides the regular fixed timing, must come last
}
}
/**
* @brief Looks up and returns the VE value from the secondary fuel table
*
*
* This performs largely the same operations as getVE() however the lookup is of the secondary fuel table and uses the secondary load source
* @return byte
* @return byte
*/
byte getVE2(void)
{
byte tempVE = 100;
if( configPage10.fuel2Algorithm == LOAD_SOURCE_MAP)
if(configPage10.fuel2Algorithm == LOAD_SOURCE_MAP)
{
//Speed Density
// Speed Density
currentStatus.fuelLoad2 = currentStatus.MAP;
}
else if (configPage10.fuel2Algorithm == LOAD_SOURCE_TPS)
else if(configPage10.fuel2Algorithm == LOAD_SOURCE_TPS)
{
//Alpha-N
// Alpha-N
currentStatus.fuelLoad2 = currentStatus.TPS * 2;
}
else if (configPage10.fuel2Algorithm == LOAD_SOURCE_IMAPEMAP)
else if(configPage10.fuel2Algorithm == LOAD_SOURCE_IMAPEMAP)
{
//IMAP / EMAP
// IMAP / EMAP
currentStatus.fuelLoad2 = (currentStatus.MAP * 100) / currentStatus.EMAP;
}
else { currentStatus.fuelLoad2 = currentStatus.MAP; } //Fallback position
tempVE = get3DTableValue(&fuelTable2, currentStatus.fuelLoad2, currentStatus.RPM); //Perform lookup into fuel map for RPM vs MAP value
else { currentStatus.fuelLoad2 = currentStatus.MAP; } // Fallback position
tempVE = get3DTableValue(&fuelTable2, currentStatus.fuelLoad2, currentStatus.RPM); // Perform lookup into fuel map for RPM vs MAP value
return tempVE;
}
/**
* @brief Performs a lookup of the second ignition advance table. The values used to look this up will be RPM and whatever load source the user has configured
*
*
* @return byte The current target advance value in degrees
*/
byte getAdvance2(void)
{
byte tempAdvance = 0;
if (configPage10.spark2Algorithm == LOAD_SOURCE_MAP) //Check which fuelling algorithm is being used
if(configPage10.spark2Algorithm == LOAD_SOURCE_MAP) // Check which fuelling algorithm is being used
{
//Speed Density
// Speed Density
currentStatus.ignLoad2 = currentStatus.MAP;
}
else if(configPage10.spark2Algorithm == LOAD_SOURCE_TPS)
{
//Alpha-N
// Alpha-N
currentStatus.ignLoad2 = currentStatus.TPS * 2;
}
else if (configPage10.spark2Algorithm == LOAD_SOURCE_IMAPEMAP)
else if(configPage10.spark2Algorithm == LOAD_SOURCE_IMAPEMAP)
{
//IMAP / EMAP
// IMAP / EMAP
currentStatus.ignLoad2 = (currentStatus.MAP * 100) / currentStatus.EMAP;
}
else { currentStatus.ignLoad2 = currentStatus.MAP; }
tempAdvance = get3DTableValue(&ignitionTable2, currentStatus.ignLoad2, currentStatus.RPM) - OFFSET_IGNITION; //As above, but for ignition advance
tempAdvance = get3DTableValue(&ignitionTable2, currentStatus.ignLoad2, currentStatus.RPM) - OFFSET_IGNITION; // As above, but for ignition advance
tempAdvance = correctionsIgn(tempAdvance);
return tempAdvance;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,11 +10,11 @@ Note that this may clear some of the existing values of the table
*/
#include "table2d.h"
#if !defined(UNIT_TEST)
#include "globals.h"
#include "globals.h"
#endif
static inline uint8_t getCacheTime(void) {
static inline uint8_t getCacheTime(void)
{
#if !defined(UNIT_TEST)
return currentStatus.secl;
#else
@ -31,66 +31,66 @@ Unfortunately this means many of the lines are duplicated depending on this
*/
int table2D_getValue(struct table2D *fromTable, int X_in)
{
//Orig memory usage = 5414
int returnValue = 0;
bool valueFound = false;
// Orig memory usage = 5414
int returnValue = 0;
bool valueFound = false;
int X = X_in;
int xMinValue, xMaxValue;
int xMin = 0;
int xMax = fromTable->xSize-1;
int xMax = fromTable->xSize - 1;
//Check whether the X input is the same as last time this ran
if( (X_in == fromTable->lastInput) && (fromTable->cacheTime == getCacheTime()) )
// Check whether the X input is the same as last time this ran
if((X_in == fromTable->lastInput) && (fromTable->cacheTime == getCacheTime()))
{
returnValue = fromTable->lastOutput;
valueFound = true;
valueFound = true;
}
//If the requested X value is greater/small than the maximum/minimum bin, simply return that value
// If the requested X value is greater/small than the maximum/minimum bin, simply return that value
else if(X >= table2D_getAxisValue(fromTable, xMax))
{
returnValue = table2D_getRawValue(fromTable, xMax);
valueFound = true;
valueFound = true;
}
else if(X <= table2D_getAxisValue(fromTable, xMin))
{
returnValue = table2D_getRawValue(fromTable, xMin);
valueFound = true;
valueFound = true;
}
//Finally if none of that is found
// Finally if none of that is found
else
{
fromTable->cacheTime = getCacheTime(); //As we're not using the cache value, set the current secl value to track when this new value was calculated
fromTable->cacheTime = getCacheTime(); // As we're not using the cache value, set the current secl value to track when this new value was calculated
//1st check is whether we're still in the same X bin as last time
// 1st check is whether we're still in the same X bin as last time
xMaxValue = table2D_getAxisValue(fromTable, fromTable->lastXMax);
xMinValue = table2D_getAxisValue(fromTable, fromTable->lastXMin);
if ( (X <= xMaxValue) && (X > xMinValue) )
if((X <= xMaxValue) && (X > xMinValue))
{
xMax = fromTable->lastXMax;
xMin = fromTable->lastXMin;
}
else
{
//If we're not in the same bin, loop through to find where we are
xMaxValue = table2D_getAxisValue(fromTable, fromTable->xSize-1); // init xMaxValue in preparation for loop.
for (int x = fromTable->xSize-1; x > 0; x--)
// If we're not in the same bin, loop through to find where we are
xMaxValue = table2D_getAxisValue(fromTable, fromTable->xSize - 1); // init xMaxValue in preparation for loop.
for(int x = fromTable->xSize - 1; x > 0; x--)
{
xMinValue = table2D_getAxisValue(fromTable, x-1); // fetch next Min
xMinValue = table2D_getAxisValue(fromTable, x - 1); // fetch next Min
//Checks the case where the X value is exactly what was requested
if (X == xMaxValue)
// Checks the case where the X value is exactly what was requested
if(X == xMaxValue)
{
returnValue = table2D_getRawValue(fromTable, x); //Simply return the corresponding value
valueFound = true;
returnValue = table2D_getRawValue(fromTable, x); // Simply return the corresponding value
valueFound = true;
break;
}
else if (X > xMinValue)
else if(X > xMinValue)
{
// Value is in the current bin
xMax = x;
xMax = x;
fromTable->lastXMax = xMax;
xMin = x-1;
xMin = x - 1;
fromTable->lastXMin = xMin;
break;
}
@ -98,9 +98,9 @@ int table2D_getValue(struct table2D *fromTable, int X_in)
xMaxValue = xMinValue; // for the next bin, our Min is their Max
}
}
} //X_in same as last time
} // X_in same as last time
if (valueFound == false)
if(valueFound == false)
{
int16_t m = X - xMinValue;
int16_t n = xMaxValue - xMinValue;
@ -111,13 +111,13 @@ int table2D_getValue(struct table2D *fromTable, int X_in)
/* Float version (if m, yMax, yMin and n were float's)
int yVal = (m * (yMax - yMin)) / n;
*/
//Non-Float version
int16_t yVal = ( ((int32_t) m) * (yMax-yMin) ) / n;
returnValue = yMin + yVal;
// Non-Float version
int16_t yVal = (((int32_t)m) * (yMax - yMin)) / n;
returnValue = yMin + yVal;
}
fromTable->lastInput = X_in;
fromTable->lastInput = X_in;
fromTable->lastOutput = returnValue;
return returnValue;
@ -125,37 +125,36 @@ int table2D_getValue(struct table2D *fromTable, int X_in)
/**
* @brief Returns an axis (bin) value from the 2D table. This works regardless of whether that axis is bytes or int16_ts
*
* @param fromTable
* @param X_in
* @return int16_t
*
* @param fromTable
* @param X_in
* @return int16_t
*/
int16_t table2D_getAxisValue(struct table2D *fromTable, byte X_in)
{
int returnValue = 0;
if(fromTable->axisSize == SIZE_INT) { returnValue = ((int16_t*)fromTable->axisX)[X_in]; }
else if(fromTable->axisSize == SIZE_BYTE) { returnValue = ((uint8_t*)fromTable->axisX)[X_in]; }
else if(fromTable->axisSize == SIZE_SIGNED_BYTE) { returnValue = ((int8_t*)fromTable->axisX)[X_in]; }
if(fromTable->axisSize == SIZE_INT) { returnValue = ((int16_t *)fromTable->axisX)[X_in]; }
else if(fromTable->axisSize == SIZE_BYTE) { returnValue = ((uint8_t *)fromTable->axisX)[X_in]; }
else if(fromTable->axisSize == SIZE_SIGNED_BYTE) { returnValue = ((int8_t *)fromTable->axisX)[X_in]; }
return returnValue;
}
/**
* @brief Returns an value from the 2D table given an index value. No interpolation is performed
*
* @param fromTable
* @param X_index
* @return int16_t
*
* @param fromTable
* @param X_index
* @return int16_t
*/
int16_t table2D_getRawValue(struct table2D *fromTable, byte X_index)
{
int returnValue = 0;
if(fromTable->valueSize == SIZE_INT) { returnValue = ((int16_t*)fromTable->values)[X_index]; }
else if(fromTable->valueSize == SIZE_BYTE) { returnValue = ((uint8_t*)fromTable->values)[X_index]; }
else if(fromTable->valueSize == SIZE_SIGNED_BYTE) { returnValue = ((int8_t*)fromTable->values)[X_index]; }
if(fromTable->valueSize == SIZE_INT) { returnValue = ((int16_t *)fromTable->values)[X_index]; }
else if(fromTable->valueSize == SIZE_BYTE) { returnValue = ((uint8_t *)fromTable->values)[X_index]; }
else if(fromTable->valueSize == SIZE_SIGNED_BYTE) { returnValue = ((int8_t *)fromTable->values)[X_index]; }
return returnValue;
}

View File

@ -27,29 +27,28 @@ Timers are typically low resolution (Compared to Schedulers), with maximum frequ
void initialiseTimers(void)
{
lastRPM_100ms = 0;
loop33ms = 0;
loop66ms = 0;
loop100ms = 0;
loop250ms = 0;
loopSec = 0;
lastRPM_100ms = 0;
loop33ms = 0;
loop66ms = 0;
loop100ms = 0;
loop250ms = 0;
loopSec = 0;
tachoOutputFlag = TACHO_INACTIVE;
}
//Timer2 Overflow Interrupt Vector, called when the timer overflows.
//Executes every ~1ms.
#if defined(CORE_AVR) //AVR chips use the ISR for this
//This MUST be no block. Turning NO_BLOCK off messes with timing accuracy.
ISR(TIMER2_OVF_vect, ISR_NOBLOCK) //cppcheck-suppress misra-c2012-8.2
// Timer2 Overflow Interrupt Vector, called when the timer overflows.
// Executes every ~1ms.
#if defined(CORE_AVR) // AVR chips use the ISR for this
// This MUST be no block. Turning NO_BLOCK off messes with timing accuracy.
ISR(TIMER2_OVF_vect, ISR_NOBLOCK) // cppcheck-suppress misra-c2012-8.2
#else
void oneMSInterval(void) //Most ARM chips can simply call a function
void oneMSInterval(void) // Most ARM chips can simply call a function
#endif
{
BIT_SET(TIMER_mask, BIT_TIMER_1KHZ);
ms_counter++;
//Increment Loop Counters
// Increment Loop Counters
loop33ms++;
loop66ms++;
loop100ms++;
@ -58,213 +57,275 @@ void oneMSInterval(void) //Most ARM chips can simply call a function
unsigned long targetOverdwellTime;
//Overdwell check
targetOverdwellTime = micros() - dwellLimit_uS; //Set a target time in the past that all coil charging must have begun after. If the coil charge began before this time, it's been running too long
bool isCrankLocked = configPage4.ignCranklock && (currentStatus.RPM < currentStatus.crankRPM); //Dwell limiter is disabled during cranking on setups using the locked cranking timing. WE HAVE to do the RPM check here as relying on the engine cranking bit can be potentially too slow in updating
//Check first whether each spark output is currently on. Only check it's dwell time if it is
// Overdwell check
targetOverdwellTime = micros() - dwellLimit_uS; // Set a target time in the past that all coil charging must have begun after. If the coil charge began before this time, it's been running too long
bool isCrankLocked = configPage4.ignCranklock && (currentStatus.RPM < currentStatus.crankRPM); // Dwell limiter is disabled during cranking on setups using the locked cranking timing. WE HAVE to do the RPM check here as relying on the engine cranking bit can be potentially too slow in updating
// Check first whether each spark output is currently on. Only check it's dwell time if it is
if(ignitionSchedule1.Status == RUNNING) { if( (ignitionSchedule1.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { ign1EndFunction(); ignitionSchedule1.Status = OFF; } }
if(ignitionSchedule2.Status == RUNNING) { if( (ignitionSchedule2.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { ign2EndFunction(); ignitionSchedule2.Status = OFF; } }
if(ignitionSchedule3.Status == RUNNING) { if( (ignitionSchedule3.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { ign3EndFunction(); ignitionSchedule3.Status = OFF; } }
if(ignitionSchedule4.Status == RUNNING) { if( (ignitionSchedule4.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { ign4EndFunction(); ignitionSchedule4.Status = OFF; } }
if(ignitionSchedule5.Status == RUNNING) { if( (ignitionSchedule5.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { ign5EndFunction(); ignitionSchedule5.Status = OFF; } }
if(ignitionSchedule6.Status == RUNNING) { if( (ignitionSchedule6.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { ign6EndFunction(); ignitionSchedule6.Status = OFF; } }
if(ignitionSchedule7.Status == RUNNING) { if( (ignitionSchedule7.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { ign7EndFunction(); ignitionSchedule7.Status = OFF; } }
if(ignitionSchedule8.Status == RUNNING) { if( (ignitionSchedule8.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { ign8EndFunction(); ignitionSchedule8.Status = OFF; } }
if(ignitionSchedule1.Status == RUNNING)
{
if((ignitionSchedule1.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true))
{
ign1EndFunction();
ignitionSchedule1.Status = OFF;
}
}
if(ignitionSchedule2.Status == RUNNING)
{
if((ignitionSchedule2.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true))
{
ign2EndFunction();
ignitionSchedule2.Status = OFF;
}
}
if(ignitionSchedule3.Status == RUNNING)
{
if((ignitionSchedule3.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true))
{
ign3EndFunction();
ignitionSchedule3.Status = OFF;
}
}
if(ignitionSchedule4.Status == RUNNING)
{
if((ignitionSchedule4.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true))
{
ign4EndFunction();
ignitionSchedule4.Status = OFF;
}
}
if(ignitionSchedule5.Status == RUNNING)
{
if((ignitionSchedule5.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true))
{
ign5EndFunction();
ignitionSchedule5.Status = OFF;
}
}
if(ignitionSchedule6.Status == RUNNING)
{
if((ignitionSchedule6.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true))
{
ign6EndFunction();
ignitionSchedule6.Status = OFF;
}
}
if(ignitionSchedule7.Status == RUNNING)
{
if((ignitionSchedule7.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true))
{
ign7EndFunction();
ignitionSchedule7.Status = OFF;
}
}
if(ignitionSchedule8.Status == RUNNING)
{
if((ignitionSchedule8.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true))
{
ign8EndFunction();
ignitionSchedule8.Status = OFF;
}
}
//Tacho is flagged as being ready for a pulse by the ignition outputs, or the sweep interval upon startup
// Tacho is flagged as being ready for a pulse by the ignition outputs, or the sweep interval upon startup
// See if we're in power-on sweep mode
if( tachoSweepEnabled )
if(tachoSweepEnabled)
{
if( (currentStatus.engine != 0) || (ms_counter >= TACHO_SWEEP_TIME_MS) ) { tachoSweepEnabled = false; } // Stop the sweep after SWEEP_TIME, or if real tach signals have started
else
if((currentStatus.engine != 0) || (ms_counter >= TACHO_SWEEP_TIME_MS)) { tachoSweepEnabled = false; } // Stop the sweep after SWEEP_TIME, or if real tach signals have started
else
{
// Ramp the needle smoothly to the max over the SWEEP_RAMP time
if( ms_counter < TACHO_SWEEP_RAMP_MS ) { tachoSweepAccum += map(ms_counter, 0, TACHO_SWEEP_RAMP_MS, 0, tachoSweepIncr); }
else { tachoSweepAccum += tachoSweepIncr; }
if(ms_counter < TACHO_SWEEP_RAMP_MS) { tachoSweepAccum += map(ms_counter, 0, TACHO_SWEEP_RAMP_MS, 0, tachoSweepIncr); }
else { tachoSweepAccum += tachoSweepIncr; }
// Each time it rolls over, it's time to pulse the Tach
if( tachoSweepAccum >= MS_PER_SEC )
{
if(tachoSweepAccum >= MS_PER_SEC)
{
tachoOutputFlag = READY;
tachoSweepAccum -= MS_PER_SEC;
}
}
}
//Tacho output check. This code will not do anything if tacho pulse duration is fixed to coil dwell.
// Tacho output check. This code will not do anything if tacho pulse duration is fixed to coil dwell.
if(tachoOutputFlag == READY)
{
//Check for half speed tacho
if( (configPage2.tachoDiv == 0) || (tachoAlt == true) )
{
// Check for half speed tacho
if((configPage2.tachoDiv == 0) || (tachoAlt == true))
{
TACHO_PULSE_LOW();
//ms_counter is cast down to a byte as the tacho duration can only be in the range of 1-6, so no extra resolution above that is required
tachoEndTime = (uint8_t)ms_counter + configPage2.tachoDuration;
// ms_counter is cast down to a byte as the tacho duration can only be in the range of 1-6, so no extra resolution above that is required
tachoEndTime = (uint8_t)ms_counter + configPage2.tachoDuration;
tachoOutputFlag = ACTIVE;
}
else
{
//Don't run on this pulse (Half speed tacho)
// Don't run on this pulse (Half speed tacho)
tachoOutputFlag = TACHO_INACTIVE;
}
tachoAlt = !tachoAlt; //Flip the alternating value in case half speed tacho is in use.
tachoAlt = !tachoAlt; // Flip the alternating value in case half speed tacho is in use.
}
else if(tachoOutputFlag == ACTIVE)
{
//If the tacho output is already active, check whether it's reached it's end time
// If the tacho output is already active, check whether it's reached it's end time
if((uint8_t)ms_counter == tachoEndTime)
{
TACHO_PULSE_HIGH();
tachoOutputFlag = TACHO_INACTIVE;
}
}
}
//30Hz loop
if (loop33ms == 33)
// 30Hz loop
if(loop33ms == 33)
{
loop33ms = 0;
BIT_SET(TIMER_mask, BIT_TIMER_30HZ);
}
//15Hz loop
if (loop66ms == 66)
// 15Hz loop
if(loop66ms == 66)
{
loop66ms = 0;
BIT_SET(TIMER_mask, BIT_TIMER_15HZ);
}
//10Hz loop
if (loop100ms == 100)
// 10Hz loop
if(loop100ms == 100)
{
loop100ms = 0; //Reset counter
loop100ms = 0; // Reset counter
BIT_SET(TIMER_mask, BIT_TIMER_10HZ);
currentStatus.rpmDOT = (currentStatus.RPM - lastRPM_100ms) * 10; //This is the RPM per second that the engine has accelerated/decelerated in the last loop
lastRPM_100ms = currentStatus.RPM; //Record the current RPM for next calc
currentStatus.rpmDOT = (currentStatus.RPM - lastRPM_100ms) * 10; // This is the RPM per second that the engine has accelerated/decelerated in the last loop
lastRPM_100ms = currentStatus.RPM; // Record the current RPM for next calc
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN) ) { runSecsX10++; }
if(BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN)) { runSecsX10++; }
else { runSecsX10 = 0; }
if ( (injPrimed == false) && (seclx10 == configPage2.primingDelay) && (currentStatus.RPM == 0) ) { beginInjectorPriming(); injPrimed = true; }
if((injPrimed == false) && (seclx10 == configPage2.primingDelay) && (currentStatus.RPM == 0))
{
beginInjectorPriming();
injPrimed = true;
}
seclx10++;
}
//4Hz loop
if (loop250ms == 250)
// 4Hz loop
if(loop250ms == 250)
{
loop250ms = 0; //Reset Counter
loop250ms = 0; // Reset Counter
BIT_SET(TIMER_mask, BIT_TIMER_4HZ);
#if defined(CORE_STM32) //debug purpose, only visual for running code
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
#endif
#if defined(CORE_STM32) // debug purpose, only visual for running code
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
#endif
#if defined(CORE_AVR)
//Reset watchdog timer (Not active currently)
//wdt_reset();
//DIY watchdog
//This is a sign of a crash:
//if( (initialisationComplete == true) && (last250msLoopCount == mainLoopCount) ) { setup(); }
//else { last250msLoopCount = mainLoopCount; }
#endif
#if defined(CORE_AVR)
// Reset watchdog timer (Not active currently)
// wdt_reset();
// DIY watchdog
// This is a sign of a crash:
// if( (initialisationComplete == true) && (last250msLoopCount == mainLoopCount) ) { setup(); }
// else { last250msLoopCount = mainLoopCount; }
#endif
}
//1Hz loop
if (loopSec == 1000)
// 1Hz loop
if(loopSec == 1000)
{
loopSec = 0; //Reset counter.
loopSec = 0; // Reset counter.
BIT_SET(TIMER_mask, BIT_TIMER_1HZ);
dwellLimit_uS = (1000 * configPage4.dwellLimit); //Update uS value in case setting has changed
dwellLimit_uS = (1000 * configPage4.dwellLimit); // Update uS value in case setting has changed
currentStatus.crankRPM = ((unsigned int)configPage4.crankRPM * 10);
//**************************************************************************************************************************************************
//This updates the runSecs variable
//If the engine is running or cranking, we need to update the run time counter.
if (BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN))
{ //NOTE - There is a potential for a ~1sec gap between engine crank starting and the runSec number being incremented. This may delay ASE!
if (currentStatus.runSecs <= 254) //Ensure we cap out at 255 and don't overflow. (which would reset ASE and cause problems with the closed loop fuelling (Which has to wait for the O2 to warmup))
{ currentStatus.runSecs++; } //Increment our run counter by 1 second.
// This updates the runSecs variable
// If the engine is running or cranking, we need to update the run time counter.
if(BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN))
{ // NOTE - There is a potential for a ~1sec gap between engine crank starting and the runSec number being incremented. This may delay ASE!
if(currentStatus.runSecs <= 254) // Ensure we cap out at 255 and don't overflow. (which would reset ASE and cause problems with the closed loop fuelling (Which has to wait for the O2 to warmup))
{
currentStatus.runSecs++;
} // Increment our run counter by 1 second.
}
//**************************************************************************************************************************************************
//This records the number of main loops the system has completed in the last second
// This records the number of main loops the system has completed in the last second
currentStatus.loopsPerSecond = mainLoopCount;
mainLoopCount = 0;
mainLoopCount = 0;
//**************************************************************************************************************************************************
//increment secl (secl is simply a counter that increments every second and is used to track whether the system has unexpectedly reset
// increment secl (secl is simply a counter that increments every second and is used to track whether the system has unexpectedly reset
currentStatus.secl++;
//**************************************************************************************************************************************************
//Check the fan output status
if (configPage2.fanEnable >= 1)
// Check the fan output status
if(configPage2.fanEnable >= 1)
{
fanControl(); // Function to turn the cooling fan on/off
fanControl(); // Function to turn the cooling fan on/off
}
//Check whether fuel pump priming is complete
// Check whether fuel pump priming is complete
if(fpPrimed == false)
{
//fpPrimeTime is the time that the pump priming started. This is 0 on startup, but can be changed if the unit has been running on USB power and then had the ignition turned on (Which starts the priming again)
if( (currentStatus.secl - fpPrimeTime) >= configPage2.fpPrime)
// fpPrimeTime is the time that the pump priming started. This is 0 on startup, but can be changed if the unit has been running on USB power and then had the ignition turned on (Which starts the priming again)
if((currentStatus.secl - fpPrimeTime) >= configPage2.fpPrime)
{
fpPrimed = true; //Mark the priming as being completed
fpPrimed = true; // Mark the priming as being completed
if(currentStatus.RPM == 0)
{
//If we reach here then the priming is complete, however only turn off the fuel pump if the engine isn't running
// If we reach here then the priming is complete, however only turn off the fuel pump if the engine isn't running
digitalWrite(pinFuelPump, LOW);
currentStatus.fuelPumpOn = false;
}
}
}
//**************************************************************************************************************************************************
//Set the flex reading (if enabled). The flexCounter is updated with every pulse from the sensor. If cleared once per second, we get a frequency reading
// Set the flex reading (if enabled). The flexCounter is updated with every pulse from the sensor. If cleared once per second, we get a frequency reading
if(configPage2.flexEnabled == true)
{
byte tempEthPct = 0;
byte tempEthPct = 0;
if(flexCounter < 50)
{
tempEthPct = 0; //Standard GM Continental sensor reads from 50Hz (0 ethanol) to 150Hz (Pure ethanol). Subtracting 50 from the frequency therefore gives the ethanol percentage.
tempEthPct = 0; // Standard GM Continental sensor reads from 50Hz (0 ethanol) to 150Hz (Pure ethanol). Subtracting 50 from the frequency therefore gives the ethanol percentage.
flexCounter = 0;
}
else if (flexCounter > 151) //1 pulse buffer
else if(flexCounter > 151) // 1 pulse buffer
{
if(flexCounter < 169)
{
tempEthPct = 100;
tempEthPct = 100;
flexCounter = 0;
}
else
{
//This indicates an error condition. Spec of the sensor is that errors are above 170Hz)
tempEthPct = 0;
// This indicates an error condition. Spec of the sensor is that errors are above 170Hz)
tempEthPct = 0;
flexCounter = 0;
}
}
else
{
tempEthPct = flexCounter - 50; //Standard GM Continental sensor reads from 50Hz (0 ethanol) to 150Hz (Pure ethanol). Subtracting 50 from the frequency therefore gives the ethanol percentage.
tempEthPct = flexCounter - 50; // Standard GM Continental sensor reads from 50Hz (0 ethanol) to 150Hz (Pure ethanol). Subtracting 50 from the frequency therefore gives the ethanol percentage.
flexCounter = 0;
}
//Off by 1 error check
if (tempEthPct == 1) { tempEthPct = 0; }
// Off by 1 error check
if(tempEthPct == 1) { tempEthPct = 0; }
currentStatus.ethanolPct = ADC_FILTER(tempEthPct, configPage4.FILTER_FLEX, currentStatus.ethanolPct);
//Continental flex sensor fuel temperature can be read with following formula: (Temperature = (41.25 * pulse width(ms)) - 81.25). 1000μs = -40C and 5000μs = 125C
// Continental flex sensor fuel temperature can be read with following formula: (Temperature = (41.25 * pulse width(ms)) - 81.25). 1000μs = -40C and 5000μs = 125C
if(flexPulseWidth > 5000) { flexPulseWidth = 5000; }
else if(flexPulseWidth < 1000) { flexPulseWidth = 1000; }
currentStatus.fuelTemp = div100( (int16_t)(((4224 * (long)flexPulseWidth) >> 10) - 8125) );
currentStatus.fuelTemp = div100((int16_t)(((4224 * (long)flexPulseWidth) >> 10) - 8125));
}
//**************************************************************************************************************************************************
//Handle any of the hardware testing outputs
if( BIT_CHECK(currentStatus.testOutputs, 1) )
// Handle any of the hardware testing outputs
if(BIT_CHECK(currentStatus.testOutputs, 1))
{
//Check whether any of the fuel outputs is on
// Check whether any of the fuel outputs is on
//Check for injector outputs on 50%
// Check for injector outputs on 50%
if(BIT_CHECK(HWTest_INJ_50pc, INJ1_CMD_BIT)) { injector1Toggle(); }
if(BIT_CHECK(HWTest_INJ_50pc, INJ2_CMD_BIT)) { injector2Toggle(); }
if(BIT_CHECK(HWTest_INJ_50pc, INJ3_CMD_BIT)) { injector3Toggle(); }
@ -274,7 +335,7 @@ void oneMSInterval(void) //Most ARM chips can simply call a function
if(BIT_CHECK(HWTest_INJ_50pc, INJ7_CMD_BIT)) { injector7Toggle(); }
if(BIT_CHECK(HWTest_INJ_50pc, INJ8_CMD_BIT)) { injector8Toggle(); }
//Check for ignition outputs on 50%
// Check for ignition outputs on 50%
if(BIT_CHECK(HWTest_IGN_50pc, IGN1_CMD_BIT)) { coil1Toggle(); }
if(BIT_CHECK(HWTest_IGN_50pc, IGN2_CMD_BIT)) { coil2Toggle(); }
if(BIT_CHECK(HWTest_IGN_50pc, IGN3_CMD_BIT)) { coil3Toggle(); }
@ -284,10 +345,9 @@ void oneMSInterval(void) //Most ARM chips can simply call a function
if(BIT_CHECK(HWTest_IGN_50pc, IGN7_CMD_BIT)) { coil7Toggle(); }
if(BIT_CHECK(HWTest_IGN_50pc, IGN8_CMD_BIT)) { coil8Toggle(); }
}
}
#if defined(CORE_AVR) //AVR chips use the ISR for this
//Reset Timer2 to trigger in another ~1ms
TCNT2 = 131; //Preload timer2 with 100 cycles, leaving 156 till overflow.
#if defined(CORE_AVR) // AVR chips use the ISR for this
// Reset Timer2 to trigger in another ~1ms
TCNT2 = 131; // Preload timer2 with 100 cycles, leaving 156 till overflow.
#endif
}

View File

@ -16,44 +16,44 @@
void doUpdates(void)
{
#define CURRENT_DATA_VERSION 22
//Only the latest update for small flash devices must be retained
#ifndef SMALL_FLASH_MODE
#define CURRENT_DATA_VERSION 22
// Only the latest update for small flash devices must be retained
#ifndef SMALL_FLASH_MODE
//May 2017 firmware introduced a -40 offset on the ignition table. Update that table to +40
// May 2017 firmware introduced a -40 offset on the ignition table. Update that table to +40
if(readEEPROMVersion() == 2)
{
auto table_it = ignitionTable.values.begin();
while (!table_it.at_end())
while(!table_it.at_end())
{
auto row = *table_it;
while (!row.at_end())
while(!row.at_end())
{
*row = *row + 40;
++row;
}
}
++table_it;
}
writeAllConfig();
storeEEPROMVersion(3);
}
//June 2017 required the forced addition of some CAN values to avoid weird errors
// June 2017 required the forced addition of some CAN values to avoid weird errors
if(readEEPROMVersion() == 3)
{
configPage9.speeduino_tsCanId = 0;
configPage9.true_address = 256;
configPage9.speeduino_tsCanId = 0;
configPage9.true_address = 256;
configPage9.realtime_base_address = 336;
//There was a bad value in the May base tune for the spark duration setting, fix it here if it's a problem
// There was a bad value in the May base tune for the spark duration setting, fix it here if it's a problem
if(configPage4.sparkDur == 255) { configPage4.sparkDur = 10; }
writeAllConfig();
storeEEPROMVersion(4);
}
//July 2017 adds a cranking enrichment curve in place of the single value. This converts that single value to the curve
// July 2017 adds a cranking enrichment curve in place of the single value. This converts that single value to the curve
if(readEEPROMVersion() == 4)
{
//Some default values for the bins (Doesn't matter too much here as the values against them will all be identical)
// Some default values for the bins (Doesn't matter too much here as the values against them will all be identical)
configPage10.crankingEnrichBins[0] = 0;
configPage10.crankingEnrichBins[1] = 40;
configPage10.crankingEnrichBins[2] = 70;
@ -67,47 +67,48 @@ void doUpdates(void)
writeAllConfig();
storeEEPROMVersion(5);
}
//September 2017 had a major change to increase the minimum table size to 128. This required multiple pieces of data being moved around
// September 2017 had a major change to increase the minimum table size to 128. This required multiple pieces of data being moved around
if(readEEPROMVersion() == 5)
{
//Data after page 4 has to move back 128 bytes
for(int x=0; x < 1152; x++)
// Data after page 4 has to move back 128 bytes
for(int x = 0; x < 1152; x++)
{
int endMem = EEPROM_CONFIG10_END - x;
int startMem = endMem - 128; //
int endMem = EEPROM_CONFIG10_END - x;
int startMem = endMem - 128; //
byte currentVal = EEPROM.read(startMem);
EEPROM.update(endMem, currentVal);
}
//The remaining data only has to move back 64 bytes
for(int x=0; x < 352; x++)
// The remaining data only has to move back 64 bytes
for(int x = 0; x < 352; x++)
{
int endMem = EEPROM_CONFIG10_END - 1152 - x;
int startMem = endMem - 64; //
int endMem = EEPROM_CONFIG10_END - 1152 - x;
int startMem = endMem - 64; //
byte currentVal = EEPROM.read(startMem);
EEPROM.update(endMem, currentVal);
}
storeEEPROMVersion(6);
loadConfig(); //Reload the config after changing everything in EEPROM
loadConfig(); // Reload the config after changing everything in EEPROM
}
//November 2017 added the staging table that comes after boost and vvt in the EEPROM. This required multiple pieces of data being moved around
// November 2017 added the staging table that comes after boost and vvt in the EEPROM. This required multiple pieces of data being moved around
if(readEEPROMVersion() == 6)
{
//Data after page 8 has to move back 82 bytes
for(int x=0; x < 529; x++)
// Data after page 8 has to move back 82 bytes
for(int x = 0; x < 529; x++)
{
int endMem = EEPROM_CONFIG10_END - x;
int startMem = endMem - 82; //
int endMem = EEPROM_CONFIG10_END - x;
int startMem = endMem - 82; //
byte currentVal = EEPROM.read(startMem);
EEPROM.update(endMem, currentVal);
}
storeEEPROMVersion(7);
loadConfig(); //Reload the config after changing everything in EEPROM
loadConfig(); // Reload the config after changing everything in EEPROM
}
if (readEEPROMVersion() == 7) {
//Convert whatever flex fuel settings are there into the new tables
if(readEEPROMVersion() == 7)
{
// Convert whatever flex fuel settings are there into the new tables
configPage10.flexBoostBins[0] = 0;
configPage10.flexBoostAdj[0] = (int8_t)configPage2.aeColdPct;
@ -118,20 +119,20 @@ void doUpdates(void)
configPage10.flexAdvBins[0] = 0;
configPage10.flexAdvAdj[0] = configPage2.aeTaperMin;
for (uint8_t x = 1; x < 6; x++)
for(uint8_t x = 1; x < 6; x++)
{
uint8_t pct = x * 20;
uint8_t pct = x * 20;
configPage10.flexBoostBins[x] = pct;
configPage10.flexFuelBins[x] = pct;
configPage10.flexAdvBins[x] = pct;
configPage10.flexFuelBins[x] = pct;
configPage10.flexAdvBins[x] = pct;
int16_t boostAdder = (((configPage2.aeColdTaperMin - (int8_t)configPage2.aeColdPct) * pct) / 100) + (int8_t)configPage2.aeColdPct;
int16_t boostAdder = (((configPage2.aeColdTaperMin - (int8_t)configPage2.aeColdPct) * pct) / 100) + (int8_t)configPage2.aeColdPct;
configPage10.flexBoostAdj[x] = boostAdder;
uint8_t fuelAdder = (((configPage2.idleUpAdder - configPage2.idleUpPin) * pct) / 100) + configPage2.idleUpPin;
uint8_t fuelAdder = (((configPage2.idleUpAdder - configPage2.idleUpPin) * pct) / 100) + configPage2.idleUpPin;
configPage10.flexFuelAdj[x] = fuelAdder;
uint8_t advanceAdder = (((configPage2.aeTaperMax - configPage2.aeTaperMin) * pct) / 100) + configPage2.aeTaperMin;
uint8_t advanceAdder = (((configPage2.aeTaperMax - configPage2.aeTaperMin) * pct) / 100) + configPage2.aeTaperMin;
configPage10.flexAdvAdj[x] = advanceAdder;
}
@ -139,13 +140,13 @@ void doUpdates(void)
storeEEPROMVersion(8);
}
if (readEEPROMVersion() == 8)
if(readEEPROMVersion() == 8)
{
//May 2018 adds separate load sources for fuel and ignition. Copy the existing load algorithm into Both
configPage2.fuelAlgorithm = configPage2.legacyMAP; //Was configPage2.unused2_38c
configPage2.ignAlgorithm = configPage2.legacyMAP; //Was configPage2.unused2_38c
// May 2018 adds separate load sources for fuel and ignition. Copy the existing load algorithm into Both
configPage2.fuelAlgorithm = configPage2.legacyMAP; // Was configPage2.unused2_38c
configPage2.ignAlgorithm = configPage2.legacyMAP; // Was configPage2.unused2_38c
//Add option back in for open or closed loop boost. For all current configs to use closed
// Add option back in for open or closed loop boost. For all current configs to use closed
configPage4.boostType = 1;
writeAllConfig();
@ -154,14 +155,14 @@ void doUpdates(void)
if(readEEPROMVersion() == 9)
{
//October 2018 set default values for all the aux in variables (These were introduced in Aug, but no defaults were set then)
//All aux channels set to Off
for (byte AuxinChan = 0; AuxinChan <16 ; AuxinChan++)
// October 2018 set default values for all the aux in variables (These were introduced in Aug, but no defaults were set then)
// All aux channels set to Off
for(byte AuxinChan = 0; AuxinChan < 16; AuxinChan++)
{
configPage9.caninput_sel[AuxinChan] = 0;
}
//Ability to change the analog filter values was added. Set default values for these:
// Ability to change the analog filter values was added. Set default values for these:
configPage4.ADCFILTER_TPS = ADCFILTER_TPS_DEFAULT;
configPage4.ADCFILTER_CLT = ADCFILTER_CLT_DEFAULT;
configPage4.ADCFILTER_IAT = ADCFILTER_IAT_DEFAULT;
@ -176,42 +177,42 @@ void doUpdates(void)
if(readEEPROMVersion() == 10)
{
//May 2019 version adds the use of a 2D table for the priming pulse rather than a single value.
//This sets all the values in the 2D table to be the same as the previous single value
configPage2.primePulse[0] = configPage2.aeColdTaperMax / 5; //New priming pulse values are in the range 0-127.5 rather than 0-25.5 so they must be divided by 5
configPage2.primePulse[1] = configPage2.aeColdTaperMax / 5; //New priming pulse values are in the range 0-127.5 rather than 0-25.5 so they must be divided by 5
configPage2.primePulse[2] = configPage2.aeColdTaperMax / 5; //New priming pulse values are in the range 0-127.5 rather than 0-25.5 so they must be divided by 5
configPage2.primePulse[3] = configPage2.aeColdTaperMax / 5; //New priming pulse values are in the range 0-127.5 rather than 0-25.5 so they must be divided by 5
//Set some sane default temperatures for this table
// May 2019 version adds the use of a 2D table for the priming pulse rather than a single value.
// This sets all the values in the 2D table to be the same as the previous single value
configPage2.primePulse[0] = configPage2.aeColdTaperMax / 5; // New priming pulse values are in the range 0-127.5 rather than 0-25.5 so they must be divided by 5
configPage2.primePulse[1] = configPage2.aeColdTaperMax / 5; // New priming pulse values are in the range 0-127.5 rather than 0-25.5 so they must be divided by 5
configPage2.primePulse[2] = configPage2.aeColdTaperMax / 5; // New priming pulse values are in the range 0-127.5 rather than 0-25.5 so they must be divided by 5
configPage2.primePulse[3] = configPage2.aeColdTaperMax / 5; // New priming pulse values are in the range 0-127.5 rather than 0-25.5 so they must be divided by 5
// Set some sane default temperatures for this table
configPage2.primeBins[0] = 0;
configPage2.primeBins[1] = 40;
configPage2.primeBins[2] = 70;
configPage2.primeBins[3] = 100;
//Also added is coolant based ASE for both duration and amount
//All the adder amounts are set to what the single value was previously
// Also added is coolant based ASE for both duration and amount
// All the adder amounts are set to what the single value was previously
configPage2.asePct[0] = configPage2.aeColdTaperMin;
configPage2.asePct[1] = configPage2.aeColdTaperMin;
configPage2.asePct[2] = configPage2.aeColdTaperMin;
configPage2.asePct[3] = configPage2.aeColdTaperMin;
//ASE duration is set to 10s for all coolant values
// ASE duration is set to 10s for all coolant values
configPage2.aseCount[0] = 10;
configPage2.aseCount[1] = 10;
configPage2.aseCount[2] = 10;
configPage2.aseCount[3] = 10;
//Finally the coolant bins for the above are set to sane values (Remembering these are offset values)
// Finally the coolant bins for the above are set to sane values (Remembering these are offset values)
configPage2.aseBins[0] = 0;
configPage2.aseBins[1] = 20;
configPage2.aseBins[2] = 60;
configPage2.aseBins[3] = 80;
//Coolant based ignition advance was added also. Set sane values
configPage4.cltAdvBins[0] = 0;
configPage4.cltAdvBins[1] = 30;
configPage4.cltAdvBins[2] = 60;
configPage4.cltAdvBins[3] = 70;
configPage4.cltAdvBins[4] = 85;
configPage4.cltAdvBins[5] = 100;
// Coolant based ignition advance was added also. Set sane values
configPage4.cltAdvBins[0] = 0;
configPage4.cltAdvBins[1] = 30;
configPage4.cltAdvBins[2] = 60;
configPage4.cltAdvBins[3] = 70;
configPage4.cltAdvBins[4] = 85;
configPage4.cltAdvBins[5] = 100;
configPage4.cltAdvValues[0] = 0;
configPage4.cltAdvValues[1] = 0;
configPage4.cltAdvValues[2] = 0;
@ -219,44 +220,42 @@ void doUpdates(void)
configPage4.cltAdvValues[4] = 0;
configPage4.cltAdvValues[5] = 0;
//March 19 added a tacho pulse duration that could default to stupidly high values. Check if this is the case and fix it if found. 6ms is the maximum allowed value
// March 19 added a tacho pulse duration that could default to stupidly high values. Check if this is the case and fix it if found. 6ms is the maximum allowed value
if(configPage2.tachoDuration > 6) { configPage2.tachoDuration = 3; }
//MAP based AE was introduced, force the AE mode to be TPS for all existing tunes
configPage2.aeMode = AE_MODE_TPS;
// MAP based AE was introduced, force the AE mode to be TPS for all existing tunes
configPage2.aeMode = AE_MODE_TPS;
configPage2.maeThresh = configPage2.taeThresh;
//Set some sane values for the MAP AE curve
// Set some sane values for the MAP AE curve
configPage4.maeRates[0] = 75;
configPage4.maeRates[1] = 75;
configPage4.maeRates[2] = 75;
configPage4.maeRates[3] = 75;
configPage4.maeBins[0] = 7;
configPage4.maeBins[1] = 12;
configPage4.maeBins[2] = 20;
configPage4.maeBins[3] = 40;
configPage4.maeBins[0] = 7;
configPage4.maeBins[1] = 12;
configPage4.maeBins[2] = 20;
configPage4.maeBins[3] = 40;
//The 2nd fuel table was added. To prevent issues, force it to be disabled.
// The 2nd fuel table was added. To prevent issues, force it to be disabled.
configPage10.fuel2Mode = 0;
writeAllConfig();
storeEEPROMVersion(11);
}
if(readEEPROMVersion() == 11)
{
//Sep 2019
//A battery calibration offset value was introduced. Set default value to 0
// Sep 2019
// A battery calibration offset value was introduced. Set default value to 0
configPage4.batVoltCorrect = 0;
//An option was added to select the older method of performing MAP reads with the pullup resistor active
// An option was added to select the older method of performing MAP reads with the pullup resistor active
configPage2.legacyMAP = 0;
//Secondary fuel table was added for switching. Make sure it's all turned off initially
configPage10.fuel2Mode = 0;
configPage10.fuel2SwitchVariable = 0; //Set switch variable to RPM
configPage10.fuel2SwitchValue = 7000; //7000 RPM switch point is safe
// Secondary fuel table was added for switching. Make sure it's all turned off initially
configPage10.fuel2Mode = 0;
configPage10.fuel2SwitchVariable = 0; // Set switch variable to RPM
configPage10.fuel2SwitchValue = 7000; // 7000 RPM switch point is safe
writeAllConfig();
storeEEPROMVersion(12);
@ -264,11 +263,11 @@ void doUpdates(void)
if(readEEPROMVersion() == 12)
{
//Nov 2019
//New option to only apply voltage correction to dead time. Set existing tunes to use old method
// Nov 2019
// New option to only apply voltage correction to dead time. Set existing tunes to use old method
configPage2.battVCorMode = BATTV_COR_MODE_WHOLE;
//Manual baro correction curve was added. Give it some default values (All baro readings set to 100%)
// Manual baro correction curve was added. Give it some default values (All baro readings set to 100%)
configPage4.baroFuelBins[0] = 80;
configPage4.baroFuelBins[1] = 85;
configPage4.baroFuelBins[2] = 90;
@ -287,17 +286,17 @@ void doUpdates(void)
configPage4.baroFuelValues[6] = 100;
configPage4.baroFuelValues[7] = 100;
//Idle advance curve was added. Add default values
configPage2.idleAdvEnabled = 0; //Turn this off by default
configPage2.idleAdvTPS = 5; //Active below 5% tps
configPage2.idleAdvRPM = 20; //Active below 2000 RPM
configPage4.idleAdvBins[0] = 30;
configPage4.idleAdvBins[1] = 40;
configPage4.idleAdvBins[2] = 50;
configPage4.idleAdvBins[3] = 60;
configPage4.idleAdvBins[4] = 70;
configPage4.idleAdvBins[5] = 80;
configPage4.idleAdvValues[0] = 15; //These values offset by 15, so this is just making this equal to 0
// Idle advance curve was added. Add default values
configPage2.idleAdvEnabled = 0; // Turn this off by default
configPage2.idleAdvTPS = 5; // Active below 5% tps
configPage2.idleAdvRPM = 20; // Active below 2000 RPM
configPage4.idleAdvBins[0] = 30;
configPage4.idleAdvBins[1] = 40;
configPage4.idleAdvBins[2] = 50;
configPage4.idleAdvBins[3] = 60;
configPage4.idleAdvBins[4] = 70;
configPage4.idleAdvBins[5] = 80;
configPage4.idleAdvValues[0] = 15; // These values offset by 15, so this is just making this equal to 0
configPage4.idleAdvValues[1] = 15;
configPage4.idleAdvValues[2] = 15;
configPage4.idleAdvValues[3] = 15;
@ -310,113 +309,112 @@ void doUpdates(void)
if(readEEPROMVersion() == 13)
{
//202005
//Cranking enrichment range 0..1275% instead of older 0.255, so need to divide old values by 5
// 202005
// Cranking enrichment range 0..1275% instead of older 0.255, so need to divide old values by 5
configPage10.crankingEnrichValues[0] = configPage10.crankingEnrichValues[0] / 5;
configPage10.crankingEnrichValues[1] = configPage10.crankingEnrichValues[1] / 5;
configPage10.crankingEnrichValues[2] = configPage10.crankingEnrichValues[2] / 5;
configPage10.crankingEnrichValues[3] = configPage10.crankingEnrichValues[3] / 5;
//Added the injector timing curve
//Set all the values to be the same as the first one.
configPage2.injAng[0] = configPage2.injAng[0]; //Obviously not needed, but here for completeness
// Added the injector timing curve
// Set all the values to be the same as the first one.
configPage2.injAng[0] = configPage2.injAng[0]; // Obviously not needed, but here for completeness
configPage2.injAng[1] = configPage2.injAng[0];
configPage2.injAng[2] = configPage2.injAng[0];
configPage2.injAng[3] = configPage2.injAng[0];
//The RPMs are divided by 100
// The RPMs are divided by 100
configPage2.injAngRPM[0] = 5;
configPage2.injAngRPM[1] = 25;
configPage2.injAngRPM[2] = 45;
configPage2.injAngRPM[3] = 65;
//Introduced a DFCO delay option. Default it to 0
// Introduced a DFCO delay option. Default it to 0
configPage2.dfcoDelay = 0;
//Introduced a minimum temperature for DFCO. Default it to 40C
configPage2.dfcoMinCLT = 80; //CALIBRATION_TEMPERATURE_OFFSET is 40
// Introduced a minimum temperature for DFCO. Default it to 40C
configPage2.dfcoMinCLT = 80; // CALIBRATION_TEMPERATURE_OFFSET is 40
//Update flex fuel ignition config values for 40 degrees offset
for (int i=0; i<6; i++)
// Update flex fuel ignition config values for 40 degrees offset
for(int i = 0; i < 6; i++)
{
configPage10.flexAdvAdj[i] += 40;
}
//AE cold modifier added. Default to sane values
configPage2.aeColdPct = 100;
// AE cold modifier added. Default to sane values
configPage2.aeColdPct = 100;
configPage2.aeColdTaperMin = 40;
configPage2.aeColdTaperMax = 100;
//New PID resolution, old resolution was 100% for each increase, 100% now is stored as 32
// New PID resolution, old resolution was 100% for each increase, 100% now is stored as 32
if(configPage6.idleKP >= 8) { configPage6.idleKP = 255; }
else { configPage6.idleKP = configPage6.idleKP<<5; }
else { configPage6.idleKP = configPage6.idleKP << 5; }
if(configPage6.idleKI >= 8) { configPage6.idleKI = 255; }
else { configPage6.idleKI = configPage6.idleKI<<5; }
else { configPage6.idleKI = configPage6.idleKI << 5; }
if(configPage6.idleKD >= 8) { configPage6.idleKD = 255; }
else { configPage6.idleKD = configPage6.idleKD<<5; }
else { configPage6.idleKD = configPage6.idleKD << 5; }
if(configPage10.vvtCLKP >= 8) { configPage10.vvtCLKP = 255; }
else { configPage10.vvtCLKP = configPage10.vvtCLKP<<5; }
else { configPage10.vvtCLKP = configPage10.vvtCLKP << 5; }
if(configPage10.vvtCLKI >= 8) { configPage10.vvtCLKI = 255; }
else { configPage10.vvtCLKI = configPage10.vvtCLKI<<5; }
else { configPage10.vvtCLKI = configPage10.vvtCLKI << 5; }
if(configPage10.vvtCLKD >= 8) { configPage10.vvtCLKD = 255; }
else { configPage10.vvtCLKD = configPage10.vvtCLKD<<5; }
else { configPage10.vvtCLKD = configPage10.vvtCLKD << 5; }
//Cranking enrichment to run taper added. Default it to 0,1 secs
// Cranking enrichment to run taper added. Default it to 0,1 secs
configPage10.crankingEnrichTaper = 1;
//ASE to run taper added. Default it to 0,1 secs
// ASE to run taper added. Default it to 0,1 secs
configPage2.aseTaperTime = 1;
// there is now option for fixed and relative timing retard for soft limit. This sets the soft limiter to the old fixed timing mode.
configPage2.SoftLimitMode = SOFT_LIMIT_FIXED;
//VSS was added for testing, disable it by default
// VSS was added for testing, disable it by default
configPage2.vssMode = 0;
writeAllConfig();
storeEEPROMVersion(14);
}
if(readEEPROMVersion() == 14)
{
//202008
// 202008
//MAJOR update to move the coolant, IAT and O2 calibrations to 2D tables
// MAJOR update to move the coolant, IAT and O2 calibrations to 2D tables
int y;
for(int x=0; x<(CALIBRATION_TABLE_SIZE/16); x++) //Each calibration table is 512 bytes long
for(int x = 0; x < (CALIBRATION_TABLE_SIZE / 16); x++) // Each calibration table is 512 bytes long
{
y = EEPROM_CALIBRATION_CLT_OLD + (x * 16);
y = EEPROM_CALIBRATION_CLT_OLD + (x * 16);
cltCalibration_values[x] = EEPROM.read(y);
cltCalibration_bins[x] = (x * 32);
cltCalibration_bins[x] = (x * 32);
y = EEPROM_CALIBRATION_IAT_OLD + (x * 16);
y = EEPROM_CALIBRATION_IAT_OLD + (x * 16);
iatCalibration_values[x] = EEPROM.read(y);
iatCalibration_bins[x] = (x * 32);
iatCalibration_bins[x] = (x * 32);
y = EEPROM_CALIBRATION_O2_OLD + (x * 16);
y = EEPROM_CALIBRATION_O2_OLD + (x * 16);
o2Calibration_values[x] = EEPROM.read(y);
o2Calibration_bins[x] = (x * 32);
o2Calibration_bins[x] = (x * 32);
}
writeCalibration();
//Oil and fuel pressure inputs were introduced. Disable them both by default
// Oil and fuel pressure inputs were introduced. Disable them both by default
configPage10.oilPressureProtEnbl = false;
configPage10.oilPressureEnable = false;
configPage10.fuelPressureEnable = false;
//wmi
configPage10.wmiEnabled = 0;
configPage10.wmiMode = 0;
configPage10.wmiOffset = 0;
configPage10.oilPressureEnable = false;
configPage10.fuelPressureEnable = false;
// wmi
configPage10.wmiEnabled = 0;
configPage10.wmiMode = 0;
configPage10.wmiOffset = 0;
configPage10.wmiIndicatorEnabled = 0;
configPage10.wmiEmptyEnabled = 0;
configPage10.wmiAdvEnabled = 0;
for(int i=0; i<6; i++)
configPage10.wmiEmptyEnabled = 0;
configPage10.wmiAdvEnabled = 0;
for(int i = 0; i < 6; i++)
{
configPage10.wmiAdvBins[i] = i*100/2;
configPage10.wmiAdvAdj[i] = OFFSET_IGNITION;
configPage10.wmiAdvBins[i] = i * 100 / 2;
configPage10.wmiAdvAdj[i] = OFFSET_IGNITION;
}
//Programmable outputs added. Set all to disabled
// Programmable outputs added. Set all to disabled
configPage13.outputPin[0] = 0;
configPage13.outputPin[1] = 0;
configPage13.outputPin[2] = 0;
@ -426,15 +424,15 @@ void doUpdates(void)
configPage13.outputPin[6] = 0;
configPage13.outputPin[7] = 0;
//New multiply MAP option added. Set new option to be the same as old
// New multiply MAP option added. Set new option to be the same as old
configPage2.multiplyMAP = configPage2.crkngAddCLTAdv;
//New AE option added to allow for PW added in addition to existing PW multiply
configPage2.aeApplyMode = 0; //Set the AE mode to Multiply
// New AE option added to allow for PW added in addition to existing PW multiply
configPage2.aeApplyMode = 0; // Set the AE mode to Multiply
//Injector priming delay added
// Injector priming delay added
configPage2.primingDelay = 0;
//ASE taper time added
configPage2.aseTaperTime = 10; //1 second taper
// ASE taper time added
configPage2.aseTaperTime = 10; // 1 second taper
writeAllConfig();
storeEEPROMVersion(15);
@ -442,25 +440,25 @@ void doUpdates(void)
if(readEEPROMVersion() == 15)
{
//202012
configPage10.spark2Mode = 0; //Disable 2nd spark table
// 202012
configPage10.spark2Mode = 0; // Disable 2nd spark table
writeAllConfig();
storeEEPROMVersion(16);
}
//Move this #endif to only do latest updates to safe ROM space on small devices.
#endif
// Move this #endif to only do latest updates to safe ROM space on small devices.
#endif
if(readEEPROMVersion() == 16)
{
//Fix for wrong placed page 13
for(int x=EEPROM_CONFIG14_END; x>=EEPROM_CONFIG13_START; x--)
// Fix for wrong placed page 13
for(int x = EEPROM_CONFIG14_END; x >= EEPROM_CONFIG13_START; x--)
{
EEPROM.update(x, EEPROM.read(x-112));
EEPROM.update(x, EEPROM.read(x - 112));
}
configPage6.iacPWMrun = false; // just in case. This should be false anyways, but sill.
configPage2.useDwellMap = 0; //Dwell map added, use old fixed value as default
configPage6.iacPWMrun = false; // just in case. This should be false anyways, but sill.
configPage2.useDwellMap = 0; // Dwell map added, use old fixed value as default
writeAllConfig();
storeEEPROMVersion(17);
@ -468,44 +466,44 @@ void doUpdates(void)
if(readEEPROMVersion() == 17)
{
//VVT stuff has now 0.5 accuracy, so shift values in vvt table by one.
// VVT stuff has now 0.5 accuracy, so shift values in vvt table by one.
auto table_it = vvtTable.values.begin();
while (!table_it.at_end())
while(!table_it.at_end())
{
auto row = *table_it;
while (!row.at_end())
while(!row.at_end())
{
*row = *row << 1;
++row;
}
}
++table_it;
}
configPage10.vvtCLholdDuty = configPage10.vvtCLholdDuty << 1;
configPage10.vvtCLminDuty = configPage10.vvtCLminDuty << 1;
configPage10.vvtCLmaxDuty = configPage10.vvtCLmaxDuty << 1;
configPage10.vvtCLminDuty = configPage10.vvtCLminDuty << 1;
configPage10.vvtCLmaxDuty = configPage10.vvtCLmaxDuty << 1;
//VVT2 added, so default values and disable it
configPage10.vvt2Enabled = 0;
configPage4.vvt2PWMdir = 0;
// VVT2 added, so default values and disable it
configPage10.vvt2Enabled = 0;
configPage4.vvt2PWMdir = 0;
configPage10.TrigEdgeThrd = 0;
//Old use as On/Off selection is removed, so change VVT mode to On/Off based on that
// Old use as On/Off selection is removed, so change VVT mode to On/Off based on that
if(configPage6.tachoMode == 1) { configPage6.vvtMode = VVT_MODE_ONOFF; }
//Closed loop VVT improvements. Set safety limits to max/min working values and filter to minimum.
configPage10.vvtCLMinAng = 0;
configPage10.vvtCLMaxAng = 200;
// Closed loop VVT improvements. Set safety limits to max/min working values and filter to minimum.
configPage10.vvtCLMinAng = 0;
configPage10.vvtCLMaxAng = 200;
configPage4.ANGLEFILTER_VVT = 0;
configPage2.idleAdvDelay *= 2; //Increased resolution to 0.5 second
//RPM switch point added for map sample method. Set to 0 to not affect existing tunes.
configPage2.idleAdvDelay *= 2; // Increased resolution to 0.5 second
// RPM switch point added for map sample method. Set to 0 to not affect existing tunes.
configPage2.mapSwitchPoint = 0;
configPage9.boostByGearEnabled = 0;
//Added possibility to set minimum programmable output time
// Added possibility to set minimum programmable output time
configPage13.outputTimeLimit[0] = 0;
configPage13.outputTimeLimit[1] = 0;
configPage13.outputTimeLimit[2] = 0;
@ -521,11 +519,11 @@ void doUpdates(void)
if(readEEPROMVersion() == 18)
{
//202202
// 202202
configPage2.fanEnable = configPage6.fanUnused; // PWM Fan mode added, but take the previous setting of Fan in use.
//TPS resolution increased to 0.5%
//configPage2.taeThresh *= 2;
// TPS resolution increased to 0.5%
// configPage2.taeThresh *= 2;
configPage2.idleAdvTPS *= 2;
configPage2.iacTPSlimit *= 2;
configPage4.floodClear *= 2;
@ -540,8 +538,8 @@ void doUpdates(void)
// Each table Y axis need to be updated as well if TPS is the source
if(configPage2.fuelAlgorithm == LOAD_SOURCE_TPS)
{
multiplyTableLoad(&fuelTable, fuelTable.type_key, 4);
multiplyTableLoad(&afrTable, afrTable.type_key, 4);
multiplyTableLoad(&fuelTable, fuelTable.type_key, 4);
multiplyTableLoad(&afrTable, afrTable.type_key, 4);
multiplyTableLoad(&trim1Table, trim1Table.type_key, 4);
multiplyTableLoad(&trim2Table, trim2Table.type_key, 4);
multiplyTableLoad(&trim3Table, trim3Table.type_key, 4);
@ -551,7 +549,7 @@ void doUpdates(void)
multiplyTableLoad(&trim7Table, trim7Table.type_key, 4);
multiplyTableLoad(&trim8Table, trim8Table.type_key, 4);
if(configPage4.sparkMode == IGN_MODE_ROTARY)
{
{
for(uint8_t x = 0; x < 8; x++)
{
configPage10.rotarySplitBins[x] *= 2;
@ -565,138 +563,137 @@ void doUpdates(void)
if(configPage6.vvtLoadSource == VVT_LOAD_TPS)
{
//NOTE: The VVT tables all had 1.0 as the multiply value rather than 2.0 used in all other tables. For this reason they only need to be multiplied by 2 when updating
// NOTE: The VVT tables all had 1.0 as the multiply value rather than 2.0 used in all other tables. For this reason they only need to be multiplied by 2 when updating
multiplyTableLoad(&vvtTable, vvtTable.type_key, 2);
multiplyTableLoad(&vvt2Table, vvt2Table.type_key, 2);
}
else
{
//NOTE: The VVT tables all had 1.0 as the multiply value rather than 2.0 used in all other tables. For this reason they need to be divided by 2 when updating
// NOTE: The VVT tables all had 1.0 as the multiply value rather than 2.0 used in all other tables. For this reason they need to be divided by 2 when updating
divideTableLoad(&vvtTable, vvtTable.type_key, 2);
divideTableLoad(&vvt2Table, vvt2Table.type_key, 2);
}
configPage4.vvtDelay = 0;
configPage4.vvtDelay = 0;
configPage4.vvtMinClt = 0;
//Set SD logging related settings to zero.
// Set SD logging related settings to zero.
configPage13.onboard_log_csv_separator = 0;
configPage13.onboard_log_file_style = 0;
configPage13.onboard_log_file_rate = 0;
configPage13.onboard_log_filenaming = 0;
configPage13.onboard_log_storage = 0;
configPage13.onboard_log_trigger_boot = 0;
configPage13.onboard_log_trigger_RPM = 0;
configPage13.onboard_log_trigger_prot = 0;
configPage13.onboard_log_trigger_Vbat = 0;
configPage13.onboard_log_trigger_Epin = 0;
configPage13.onboard_log_tr1_duration = 0;
configPage13.onboard_log_tr2_thr_on = 0;
configPage13.onboard_log_tr2_thr_off = 0;
configPage13.onboard_log_tr3_thr_RPM = 0;
configPage13.onboard_log_tr3_thr_MAP = 0;
configPage13.onboard_log_tr3_thr_Oil = 0;
configPage13.onboard_log_tr3_thr_AFR = 0;
configPage13.onboard_log_tr4_thr_on = 0;
configPage13.onboard_log_tr4_thr_off = 0;
configPage13.onboard_log_tr5_Epin_pin = 0;
configPage13.onboard_log_file_style = 0;
configPage13.onboard_log_file_rate = 0;
configPage13.onboard_log_filenaming = 0;
configPage13.onboard_log_storage = 0;
configPage13.onboard_log_trigger_boot = 0;
configPage13.onboard_log_trigger_RPM = 0;
configPage13.onboard_log_trigger_prot = 0;
configPage13.onboard_log_trigger_Vbat = 0;
configPage13.onboard_log_trigger_Epin = 0;
configPage13.onboard_log_tr1_duration = 0;
configPage13.onboard_log_tr2_thr_on = 0;
configPage13.onboard_log_tr2_thr_off = 0;
configPage13.onboard_log_tr3_thr_RPM = 0;
configPage13.onboard_log_tr3_thr_MAP = 0;
configPage13.onboard_log_tr3_thr_Oil = 0;
configPage13.onboard_log_tr3_thr_AFR = 0;
configPage13.onboard_log_tr4_thr_on = 0;
configPage13.onboard_log_tr4_thr_off = 0;
configPage13.onboard_log_tr5_Epin_pin = 0;
writeAllConfig();
storeEEPROMVersion(19);
}
if(readEEPROMVersion() == 19)
{
//202207
// 202207
//Option added to select injector pairing on 4 cylinder engines
if( configPage4.inj4cylPairing > INJ_PAIR_14_23 ) { configPage4.inj4cylPairing = 0; } //Check valid value
if( configPage2.nCylinders == 4 )
// Option added to select injector pairing on 4 cylinder engines
if(configPage4.inj4cylPairing > INJ_PAIR_14_23) { configPage4.inj4cylPairing = 0; } // Check valid value
if(configPage2.nCylinders == 4)
{
if ( configPage2.injLayout == INJ_SEQUENTIAL ) { configPage4.inj4cylPairing = INJ_PAIR_13_24; } //Since #478 engine will always start in semi, make the sequence right for the majority of inlie 4 engines
else { configPage4.inj4cylPairing = INJ_PAIR_14_23; } //Force setting to use the default mode from previous FW versions. This is to prevent issues on any setups that have been wired accordingly
if(configPage2.injLayout == INJ_SEQUENTIAL) { configPage4.inj4cylPairing = INJ_PAIR_13_24; } // Since #478 engine will always start in semi, make the sequence right for the majority of inlie 4 engines
else { configPage4.inj4cylPairing = INJ_PAIR_14_23; } // Force setting to use the default mode from previous FW versions. This is to prevent issues on any setups that have been wired accordingly
}
configPage9.hardRevMode = 1; //Set hard rev limiter to Fixed mode
configPage6.tachoMode = 0;
configPage9.hardRevMode = 1; // Set hard rev limiter to Fixed mode
configPage6.tachoMode = 0;
//CAN broadcast introduced
// CAN broadcast introduced
configPage2.canBMWCluster = 0;
configPage2.canVAGCluster = 0;
configPage15.boostDCWhenDisabled = 0;
configPage15.boostControlEnable = EN_BOOST_CONTROL_BARO;
//Fill the boostTableLookupDuty with all 50% duty cycle. This is the same as the hardcoded 50% DC that had been used before.
//This makes the boostcontrol fully backwards compatible.
configPage15.boostControlEnable = EN_BOOST_CONTROL_BARO;
// Fill the boostTableLookupDuty with all 50% duty cycle. This is the same as the hardcoded 50% DC that had been used before.
// This makes the boostcontrol fully backwards compatible.
auto table_it = boostTableLookupDuty.values.begin();
while (!table_it.at_end())
while(!table_it.at_end())
{
auto row = *table_it;
while (!row.at_end())
while(!row.at_end())
{
*row = 50*2;
*row = 50 * 2;
++row;
}
}
++table_it;
}
//Set some sensible values at the RPM axis
auto table_X = boostTableLookupDuty.axisX.begin();
uint16_t i = 0;
while (!table_X.at_end())
// Set some sensible values at the RPM axis
auto table_X = boostTableLookupDuty.axisX.begin();
uint16_t i = 0;
while(!table_X.at_end())
{
++i;
*table_X = 1000+(500*i);
*table_X = 1000 + (500 * i);
++table_X;
}
//Set some sensible values at the boosttarget axis
// Set some sensible values at the boosttarget axis
auto table_Y = boostTableLookupDuty.axisY.begin();
i = 0;
while (!table_Y.at_end())
i = 0;
while(!table_Y.at_end())
{
++i;
*table_Y = (120 + 10*i);
*table_Y = (120 + 10 * i);
++table_Y;
}
//AFR Protection added, add default values
configPage9.afrProtectEnabled = 0; //Disable by default
configPage9.afrProtectMinMAP = 90; //Is divided by 2, vlue represents 180kPa
configPage9.afrProtectMinRPM = 40; //4000 RPM min
configPage9.afrProtectMinTPS = 160; //80% TPS min
configPage9.afrProtectDeviation = 14; //1.4 AFR deviation
// AFR Protection added, add default values
configPage9.afrProtectEnabled = 0; // Disable by default
configPage9.afrProtectMinMAP = 90; // Is divided by 2, vlue represents 180kPa
configPage9.afrProtectMinRPM = 40; // 4000 RPM min
configPage9.afrProtectMinTPS = 160; // 80% TPS min
configPage9.afrProtectDeviation = 14; // 1.4 AFR deviation
writeAllConfig();
storeEEPROMVersion(20);
}
if(readEEPROMVersion() == 20)
{
//202305
configPage2.taeMinChange = 4; //Default is 2% minimum change to match prior behaviour. (4 = 2% account for 0.5 resolution)
configPage2.maeMinChange = 2; //Default is 2% minimum change to match prior behaviour.
// 202305
configPage2.taeMinChange = 4; // Default is 2% minimum change to match prior behaviour. (4 = 2% account for 0.5 resolution)
configPage2.maeMinChange = 2; // Default is 2% minimum change to match prior behaviour.
configPage2.decelAmount = 100; //Default decel fuel amount is 100%, so no change in fueling in decel as before.
//full status structure has been changed. Update programmable outputs settings to match.
for (uint8_t y = 0; y < sizeof(configPage13.outputPin); y++)
configPage2.decelAmount = 100; // Default decel fuel amount is 100%, so no change in fueling in decel as before.
// full status structure has been changed. Update programmable outputs settings to match.
for(uint8_t y = 0; y < sizeof(configPage13.outputPin); y++)
{
if ((configPage13.firstDataIn[y] > 22) && (configPage13.firstDataIn[y] < 240)) {configPage13.firstDataIn[y]++;}
if ((configPage13.firstDataIn[y] > 92) && (configPage13.firstDataIn[y] < 240)) {configPage13.firstDataIn[y]++;}
if ((configPage13.secondDataIn[y] > 22) && (configPage13.secondDataIn[y] < 240)) {configPage13.secondDataIn[y]++;}
if ((configPage13.secondDataIn[y] > 92) && (configPage13.secondDataIn[y] < 240)) {configPage13.secondDataIn[y]++;}
if((configPage13.firstDataIn[y] > 22) && (configPage13.firstDataIn[y] < 240)) { configPage13.firstDataIn[y]++; }
if((configPage13.firstDataIn[y] > 92) && (configPage13.firstDataIn[y] < 240)) { configPage13.firstDataIn[y]++; }
if((configPage13.secondDataIn[y] > 22) && (configPage13.secondDataIn[y] < 240)) { configPage13.secondDataIn[y]++; }
if((configPage13.secondDataIn[y] > 92) && (configPage13.secondDataIn[y] < 240)) { configPage13.secondDataIn[y]++; }
}
//AC Control (configPage15)
//Set A/C default values - these line up with the ini file defaults
// AC Control (configPage15)
// Set A/C default values - these line up with the ini file defaults
configPage15.airConEnable = 0;
//Oil Pressure protection delay added. Set to 0 to match existing behaviour
// Oil Pressure protection delay added. Set to 0 to match existing behaviour
configPage10.oilPressureProtTime = 0;
//Option to power stepper motor constantly was added. Default to previous behaviour
// Option to power stepper motor constantly was added. Default to previous behaviour
configPage9.iacStepperPower = 0;
writeAllConfig();
@ -705,9 +702,9 @@ void doUpdates(void)
if(readEEPROMVersion() == 21)
{
//202306
// 202306
//Rolling cut curve added. Default values
// Rolling cut curve added. Default values
configPage15.rollingProtRPMDelta[0] = -30;
configPage15.rollingProtRPMDelta[1] = -20;
configPage15.rollingProtRPMDelta[2] = -10;
@ -720,13 +717,13 @@ void doUpdates(void)
writeAllConfig();
storeEEPROMVersion(22);
}
//Final check is always for 255 and 0 (Brand new arduino)
if( (readEEPROMVersion() == 0) || (readEEPROMVersion() == 255) )
// Final check is always for 255 and 0 (Brand new arduino)
if((readEEPROMVersion() == 0) || (readEEPROMVersion() == 255))
{
configPage9.true_address = 0x200;
//Programmable outputs added. Set all to disabled
// Programmable outputs added. Set all to disabled
configPage13.outputPin[0] = 0;
configPage13.outputPin[1] = 0;
configPage13.outputPin[2] = 0;
@ -741,8 +738,8 @@ void doUpdates(void)
storeEEPROMVersion(CURRENT_DATA_VERSION);
}
//Check to see if someone has downgraded versions:
if( readEEPROMVersion() > CURRENT_DATA_VERSION ) { storeEEPROMVersion(CURRENT_DATA_VERSION); }
// Check to see if someone has downgraded versions:
if(readEEPROMVersion() > CURRENT_DATA_VERSION) { storeEEPROMVersion(CURRENT_DATA_VERSION); }
}
void multiplyTableLoad(const void *pTable, table_type_t key, uint8_t multiplier)
@ -750,7 +747,7 @@ void multiplyTableLoad(const void *pTable, table_type_t key, uint8_t multiplier)
auto y_it = y_begin(pTable, key);
while(!y_it.at_end())
{
*y_it = *y_it * multiplier;
*y_it = *y_it * multiplier;
++y_it;
}
}
@ -760,7 +757,7 @@ void divideTableLoad(const void *pTable, table_type_t key, uint8_t divisor)
auto y_it = y_begin(pTable, key);
while(!y_it.at_end())
{
*y_it = *y_it / divisor; //Previous TS scale was 2.0, now is 0.5, 4x increase
*y_it = *y_it / divisor; // Previous TS scale was 2.0, now is 0.5, 4x increase
++y_it;
}
}

View File

@ -19,10 +19,9 @@
uint8_t ioDelay[sizeof(configPage13.outputPin)];
uint8_t ioOutDelay[sizeof(configPage13.outputPin)];
uint8_t pinIsValid = 0;
uint8_t pinIsValid = 0;
uint8_t currentRuleStatus = 0;
/** Translate between the pin list that appears in TS and the actual pin numbers.
For the **digital IO**, this will simply return the same number as the rawPin value as those are mapped directly.
For **analog pins**, it will translate them into the correct internal pin number.
@ -37,8 +36,8 @@ byte pinTranslate(byte rawPin)
return outputPin;
}
/** Translate a pin number (0 - 22) to the relevant Ax (analog) pin reference.
* This is required as some ARM chips do not have all analog pins in order (EG pin A15 != A14 + 1).
* */
* This is required as some ARM chips do not have all analog pins in order (EG pin A15 != A14 + 1).
* */
byte pinTranslateAnalog(byte rawPin)
{
byte outputPin = rawPin;
@ -58,45 +57,44 @@ byte pinTranslateAnalog(byte rawPin)
case 11: outputPin = A11; break;
case 12: outputPin = A12; break;
case 13: outputPin = A13; break;
#if BOARD_MAX_ADC_PINS >= 14
case 14: outputPin = A14; break;
#endif
#if BOARD_MAX_ADC_PINS >= 15
case 15: outputPin = A15; break;
#endif
#if BOARD_MAX_ADC_PINS >= 16
case 16: outputPin = A16; break;
#endif
#if BOARD_MAX_ADC_PINS >= 17
case 17: outputPin = A17; break;
#endif
#if BOARD_MAX_ADC_PINS >= 18
case 18: outputPin = A18; break;
#endif
#if BOARD_MAX_ADC_PINS >= 19
case 19: outputPin = A19; break;
#endif
#if BOARD_MAX_ADC_PINS >= 20
case 20: outputPin = A20; break;
#endif
#if BOARD_MAX_ADC_PINS >= 21
case 21: outputPin = A21; break;
#endif
#if BOARD_MAX_ADC_PINS >= 22
case 22: outputPin = A22; break;
#endif
#if BOARD_MAX_ADC_PINS >= 14
case 14: outputPin = A14; break;
#endif
#if BOARD_MAX_ADC_PINS >= 15
case 15: outputPin = A15; break;
#endif
#if BOARD_MAX_ADC_PINS >= 16
case 16: outputPin = A16; break;
#endif
#if BOARD_MAX_ADC_PINS >= 17
case 17: outputPin = A17; break;
#endif
#if BOARD_MAX_ADC_PINS >= 18
case 18: outputPin = A18; break;
#endif
#if BOARD_MAX_ADC_PINS >= 19
case 19: outputPin = A19; break;
#endif
#if BOARD_MAX_ADC_PINS >= 20
case 20: outputPin = A20; break;
#endif
#if BOARD_MAX_ADC_PINS >= 21
case 21: outputPin = A21; break;
#endif
#if BOARD_MAX_ADC_PINS >= 22
case 22: outputPin = A22; break;
#endif
}
return outputPin;
}
void setResetControlPinState(void)
{
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_RESET_PREVENT);
/* Setup reset control initial state */
switch (resetControl)
switch(resetControl)
{
case RESET_CONTROL_PREVENT_WHEN_RUNNING:
/* Set the reset control pin LOW and change it to HIGH later when we get sync. */
@ -121,19 +119,19 @@ void setResetControlPinState(void)
void initialiseProgrammableIO(void)
{
uint8_t outputPin;
for (uint8_t y = 0; y < sizeof(configPage13.outputPin); y++)
for(uint8_t y = 0; y < sizeof(configPage13.outputPin); y++)
{
ioDelay[y] = 0;
ioDelay[y] = 0;
ioOutDelay[y] = 0;
outputPin = configPage13.outputPin[y];
if (outputPin > 0)
outputPin = configPage13.outputPin[y];
if(outputPin > 0)
{
if ( outputPin >= 128 ) //Cascate rule usage
if(outputPin >= 128) // Cascate rule usage
{
BIT_WRITE(currentStatus.outputsStatus, y, BIT_CHECK(configPage13.outputInverted, y));
BIT_SET(pinIsValid, y);
}
else if ( !pinIsUsed(outputPin) )
else if(!pinIsUsed(outputPin))
{
pinMode(outputPin, OUTPUT);
digitalWrite(outputPin, BIT_CHECK(configPage13.outputInverted, y));
@ -153,83 +151,83 @@ void checkProgrammableIO(void)
{
int16_t data, data2;
uint8_t dataRequested;
bool firstCheck, secondCheck;
bool firstCheck, secondCheck;
for (uint8_t y = 0; y < sizeof(configPage13.outputPin); y++)
for(uint8_t y = 0; y < sizeof(configPage13.outputPin); y++)
{
firstCheck = false;
firstCheck = false;
secondCheck = false;
if ( BIT_CHECK(pinIsValid, y) ) //if outputPin == 0 it is disabled
if(BIT_CHECK(pinIsValid, y)) // if outputPin == 0 it is disabled
{
dataRequested = configPage13.firstDataIn[y];
if ( dataRequested > 239U ) //Somehow using 239 uses 9 bytes of RAM, why??
if(dataRequested > 239U) // Somehow using 239 uses 9 bytes of RAM, why??
{
dataRequested -= REUSE_RULES;
if ( dataRequested <= sizeof(configPage13.outputPin) ) { data = BIT_CHECK(currentRuleStatus, dataRequested); }
if(dataRequested <= sizeof(configPage13.outputPin)) { data = BIT_CHECK(currentRuleStatus, dataRequested); }
else { data = 0; }
}
else { data = ProgrammableIOGetData(dataRequested); }
data2 = configPage13.firstTarget[y];
if ( (configPage13.operation[y].firstCompType == COMPARATOR_EQUAL) && (data == data2) ) { firstCheck = true; }
else if ( (configPage13.operation[y].firstCompType == COMPARATOR_NOT_EQUAL) && (data != data2) ) { firstCheck = true; }
else if ( (configPage13.operation[y].firstCompType == COMPARATOR_GREATER) && (data > data2) ) { firstCheck = true; }
else if ( (configPage13.operation[y].firstCompType == COMPARATOR_GREATER_EQUAL) && (data >= data2) ) { firstCheck = true; }
else if ( (configPage13.operation[y].firstCompType == COMPARATOR_LESS) && (data < data2) ) { firstCheck = true; }
else if ( (configPage13.operation[y].firstCompType == COMPARATOR_LESS_EQUAL) && (data <= data2) ) { firstCheck = true; }
else if ( (configPage13.operation[y].firstCompType == COMPARATOR_AND) && ((data & data2) != 0) ) { firstCheck = true; }
else if ( (configPage13.operation[y].firstCompType == COMPARATOR_XOR) && ((data ^ data2) != 0) ) { firstCheck = true; }
if((configPage13.operation[y].firstCompType == COMPARATOR_EQUAL) && (data == data2)) { firstCheck = true; }
else if((configPage13.operation[y].firstCompType == COMPARATOR_NOT_EQUAL) && (data != data2)) { firstCheck = true; }
else if((configPage13.operation[y].firstCompType == COMPARATOR_GREATER) && (data > data2)) { firstCheck = true; }
else if((configPage13.operation[y].firstCompType == COMPARATOR_GREATER_EQUAL) && (data >= data2)) { firstCheck = true; }
else if((configPage13.operation[y].firstCompType == COMPARATOR_LESS) && (data < data2)) { firstCheck = true; }
else if((configPage13.operation[y].firstCompType == COMPARATOR_LESS_EQUAL) && (data <= data2)) { firstCheck = true; }
else if((configPage13.operation[y].firstCompType == COMPARATOR_AND) && ((data & data2) != 0)) { firstCheck = true; }
else if((configPage13.operation[y].firstCompType == COMPARATOR_XOR) && ((data ^ data2) != 0)) { firstCheck = true; }
if (configPage13.operation[y].bitwise != BITWISE_DISABLED)
if(configPage13.operation[y].bitwise != BITWISE_DISABLED)
{
dataRequested = configPage13.secondDataIn[y];
if ( dataRequested <= (REUSE_RULES + sizeof(configPage13.outputPin)) ) //Failsafe check
if(dataRequested <= (REUSE_RULES + sizeof(configPage13.outputPin))) // Failsafe check
{
if ( dataRequested > 239U ) //Somehow using 239 uses 9 bytes of RAM, why??
if(dataRequested > 239U) // Somehow using 239 uses 9 bytes of RAM, why??
{
dataRequested -= REUSE_RULES;
data = BIT_CHECK(currentRuleStatus, dataRequested);
}
else { data = ProgrammableIOGetData(dataRequested); }
data2 = configPage13.secondTarget[y];
if ( (configPage13.operation[y].secondCompType == COMPARATOR_EQUAL) && (data == data2) ) { secondCheck = true; }
else if ( (configPage13.operation[y].secondCompType == COMPARATOR_NOT_EQUAL) && (data != data2) ) { secondCheck = true; }
else if ( (configPage13.operation[y].secondCompType == COMPARATOR_GREATER) && (data > data2) ) { secondCheck = true; }
else if ( (configPage13.operation[y].secondCompType == COMPARATOR_GREATER_EQUAL) && (data >= data2) ) { secondCheck = true; }
else if ( (configPage13.operation[y].secondCompType == COMPARATOR_LESS) && (data < data2) ) { secondCheck = true; }
else if ( (configPage13.operation[y].secondCompType == COMPARATOR_LESS_EQUAL) && (data <= data2) ) { secondCheck = true; }
else if ( (configPage13.operation[y].secondCompType == COMPARATOR_AND) && ((data & data2) != 0) ) { secondCheck = true; }
else if ( (configPage13.operation[y].secondCompType == COMPARATOR_XOR) && ((data ^ data2) != 0) ) { secondCheck = true; }
if (configPage13.operation[y].bitwise == BITWISE_AND) { firstCheck &= secondCheck; }
if (configPage13.operation[y].bitwise == BITWISE_OR) { firstCheck |= secondCheck; }
if (configPage13.operation[y].bitwise == BITWISE_XOR) { firstCheck ^= secondCheck; }
if((configPage13.operation[y].secondCompType == COMPARATOR_EQUAL) && (data == data2)) { secondCheck = true; }
else if((configPage13.operation[y].secondCompType == COMPARATOR_NOT_EQUAL) && (data != data2)) { secondCheck = true; }
else if((configPage13.operation[y].secondCompType == COMPARATOR_GREATER) && (data > data2)) { secondCheck = true; }
else if((configPage13.operation[y].secondCompType == COMPARATOR_GREATER_EQUAL) && (data >= data2)) { secondCheck = true; }
else if((configPage13.operation[y].secondCompType == COMPARATOR_LESS) && (data < data2)) { secondCheck = true; }
else if((configPage13.operation[y].secondCompType == COMPARATOR_LESS_EQUAL) && (data <= data2)) { secondCheck = true; }
else if((configPage13.operation[y].secondCompType == COMPARATOR_AND) && ((data & data2) != 0)) { secondCheck = true; }
else if((configPage13.operation[y].secondCompType == COMPARATOR_XOR) && ((data ^ data2) != 0)) { secondCheck = true; }
if(configPage13.operation[y].bitwise == BITWISE_AND) { firstCheck &= secondCheck; }
if(configPage13.operation[y].bitwise == BITWISE_OR) { firstCheck |= secondCheck; }
if(configPage13.operation[y].bitwise == BITWISE_XOR) { firstCheck ^= secondCheck; }
}
}
//If the limiting time is active(>0) and using maximum time
if (BIT_CHECK(configPage13.kindOfLimiting, y))
// If the limiting time is active(>0) and using maximum time
if(BIT_CHECK(configPage13.kindOfLimiting, y))
{
if(firstCheck)
{
if ((configPage13.outputTimeLimit[y] != 0) && (ioOutDelay[y] >= configPage13.outputTimeLimit[y])) { firstCheck = false; } //Time has counted, disable the output
if((configPage13.outputTimeLimit[y] != 0) && (ioOutDelay[y] >= configPage13.outputTimeLimit[y])) { firstCheck = false; } // Time has counted, disable the output
}
else
{
//Released before Maximum time, set delay to maximum to flip the output next
// Released before Maximum time, set delay to maximum to flip the output next
if(BIT_CHECK(currentStatus.outputsStatus, y)) { ioOutDelay[y] = configPage13.outputTimeLimit[y]; }
else { ioOutDelay[y] = 0; } //Reset the counter for next time
else { ioOutDelay[y] = 0; } // Reset the counter for next time
}
}
if ( (firstCheck == true) && (configPage13.outputDelay[y] < 255) )
if((firstCheck == true) && (configPage13.outputDelay[y] < 255))
{
if (ioDelay[y] >= configPage13.outputDelay[y])
if(ioDelay[y] >= configPage13.outputDelay[y])
{
bool bitStatus = BIT_CHECK(configPage13.outputInverted, y) ^ firstCheck;
if (BIT_CHECK(currentStatus.outputsStatus, y) && (ioOutDelay[y] < configPage13.outputTimeLimit[y])) { ioOutDelay[y]++; }
if (configPage13.outputPin[y] < 128) { digitalWrite(configPage13.outputPin[y], bitStatus); }
if(BIT_CHECK(currentStatus.outputsStatus, y) && (ioOutDelay[y] < configPage13.outputTimeLimit[y])) { ioOutDelay[y]++; }
if(configPage13.outputPin[y] < 128) { digitalWrite(configPage13.outputPin[y], bitStatus); }
else { BIT_WRITE(currentRuleStatus, y, bitStatus); }
BIT_WRITE(currentStatus.outputsStatus, y, bitStatus);
}
@ -237,10 +235,10 @@ void checkProgrammableIO(void)
}
else
{
if (ioOutDelay[y] >= configPage13.outputTimeLimit[y])
if(ioOutDelay[y] >= configPage13.outputTimeLimit[y])
{
bool bitStatus = BIT_CHECK(configPage13.outputInverted, y) ^ firstCheck;
if (configPage13.outputPin[y] < 128) { digitalWrite(configPage13.outputPin[y], bitStatus); }
if(configPage13.outputPin[y] < 128) { digitalWrite(configPage13.outputPin[y], bitStatus); }
else { BIT_WRITE(currentRuleStatus, y, bitStatus); }
BIT_WRITE(currentStatus.outputsStatus, y, bitStatus);
if(!BIT_CHECK(configPage13.kindOfLimiting, y)) { ioOutDelay[y] = 0; }
@ -260,7 +258,7 @@ void checkProgrammableIO(void)
int16_t ProgrammableIOGetData(uint16_t index)
{
int16_t result;
if ( index < LOG_ENTRY_SIZE )
if(index < LOG_ENTRY_SIZE)
{
/*
for(uint8_t x = 0; x<sizeof(fsIntIndex); x++)
@ -271,14 +269,13 @@ int16_t ProgrammableIOGetData(uint16_t index)
if (x >= sizeof(fsIntIndex)) { result = getTSLogEntry(index); } // 8-bit, coerce to 16 bit result
else { result = word(getTSLogEntry(index+1), getTSLogEntry(index)); } // Assemble 2 bytes to word of 16 bit result
*/
if(is2ByteEntry(index)) { result = word(getTSLogEntry(index+1), getTSLogEntry(index)); }
if(is2ByteEntry(index)) { result = word(getTSLogEntry(index + 1), getTSLogEntry(index)); }
else { result = getTSLogEntry(index); }
//Special cases for temperatures
if( (index == 6) || (index == 7) ) { result -= CALIBRATION_TEMPERATURE_OFFSET; }
// Special cases for temperatures
if((index == 6) || (index == 7)) { result -= CALIBRATION_TEMPERATURE_OFFSET; }
}
else if ( index == 239U ) { result = (int16_t)max((uint32_t)runSecsX10, (uint32_t)32768); } //STM32 used std lib
else { result = -1; } //Index is bigger than fullStatus array
else if(index == 239U) { result = (int16_t)max((uint32_t)runSecsX10, (uint32_t)32768); } // STM32 used std lib
else { result = -1; } // Index is bigger than fullStatus array
return result;
}