Merge branch 'master' of git://github.com/noisymime/speeduino

This commit is contained in:
VitorBoss 2018-02-01 18:28:53 -02:00
commit 27e22eef1b
25 changed files with 1766 additions and 823 deletions

2
.gitignore vendored
View File

@ -19,3 +19,5 @@ reference/hardware/v0.4/gerbers/Archive.zip
.vscode
.build
.kicad_pcb-bak
.vscode/c_cpp_properties.json
.vscode/launch.json

View File

@ -46,6 +46,13 @@ lib_deps = EEPROM
;build_flags = -fpermissive -std=gnu++11 -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,-Map,output.map
build_flags = -fpermissive -std=gnu++11 -Os
;Support for the stm32f407 doesn't look ready in platformio yet
;[env:genericSTM32F407VE]
;platform = https://github.com/maichaell/platform-ststm32
;framework = arduino
;board = disco_f407vg
;lib_deps = EEPROM
;build_flags = -fpermissive -std=gnu++11 -DUSE_STM32GENERIC -DMENU_USB_SERIAL
[platformio]
src_dir=speeduino

View File

@ -0,0 +1,251 @@
:1000000092C00000ABC00000A9C00000A7C0000063
:10001000A5C00000A3C00000A1C000009FC0000058
:100020009DC000009BC0000099C0000014C40000E7
:10003000B9C4000093C0000091C000008FC0000050
:100040008DC000008BC0000089C0000087C0000088
:1000500085C0000083C0000081C00000E7C100002F
:100060007DC000007BC0000079C0000077C00000A8
:1000700075C000002803530070006500650064002F
:10008000750069006E006F0020004D00650067007C
:1000900061002000320035003600300000003203DD
:1000A000410072006400750069006E006F0020005E
:1000B00028007700770077002E006100720064004E
:1000C000750069006E006F002E0063006300290058
:1000D00000000403090409023E00020100C03209C5
:1000E00004000001020201000524000110042402A2
:1000F000060524060001070582030800FF09040124
:1001000000020A0000000705040240000107058301
:10011000024000011201100102000008EB034B2015
:1001200001000102DC0111241FBECFEFD2E0DEBFCF
:10013000CDBF11E0A0E0B1E0ECE7FFE002C0059028
:100140000D92A831B107D9F722E0A8E1B1E001C0D2
:100150001D92A133B207E1F74CD00EC751CFFC017D
:10016000E058FF4FA081B1816C93A081B1819D01C6
:100170002F5F3F4F2E173F0761F0318320832FB74A
:10018000F894FC01EC57FF4F80818F5F80832FBF75
:10019000089512969C938E931197F1CF84B7877F21
:1001A00084BF0FB6F894A895809160008861809311
:1001B0006000109260000FBE87E690E09093CD0043
:1001C0008093CC0086E08093CA001092C80088E13A
:1001D0008093C900539A5A9A8AB180638AB98BB1C5
:1001E00080638BB92DD384E085BD5F9A579A279899
:1001F0000895D4DF2FB7F89480EA91E0909321021C
:100200008093200290932302809322022FBF2FB766
:10021000F8948BE191E090939C0180939B019093E3
:100220009E0180939D012FBF78948C0183E0F82E6E
:100230009FB7F894809124029FBF8038D1F080E06E
:1002400091E048D6EC0197FD14C0909116019923D6
:1002500051F0863441F460E680EA91E080DF61E0AD
:1002600080EA91E07CDF6C2F80EA91E078DF1092E9
:1002700016018FB7F894C0919F018FBFA89902C053
:10028000C13618F1A89A80919F01882319F05D98D2
:10029000F0921801C15008F042C0809118018823E3
:1002A00041F080911801815080931801811101C0A3
:1002B0005D9A80911901882341F080911901815044
:1002C00080931901811101C05C9A9FB7F8948091C5
:1002D00024029FBF8823F1F0E0912202F0912302D3
:1002E000919182E0E032F807C1F1F0932302E093AC
:1002F00022022FB7F8948091240281508093240227
:100300002FBF8091C80085FFFCCF9093CE005C98F2
:10031000F092190180E091E0CFD5C5D489CFE0916A
:100320009D01F0919E01619181E0EB39F80781F028
:10033000F0939E01E0939D019FB7F89480919F01F7
:10034000815080939F019FBF80E091E067D5A2CF4D
:1003500010939E0100939D01EFCF20EA31E030938E
:10036000230220932202C5CF80E091E013C580E0F4
:1003700091E0ABC40F931F93CF938C01FC01848950
:10038000C0E3813021F0C0E2823009F0C0E0F80122
:100390008389823009F4C860F80185898730E9F1E2
:1003A0008830E9F1863009F4C2601092C9001092D9
:1003B000C8001092CA00F801278530894189528906
:1003C0002115F1EE3F074105510559F1CA01B90167
:1003D000969587957795679560587B47814E9F4F97
:1003E000A3D5215031093093CD002093CC00C09388
:1003F000CA00F80187859089A189B2898115914E3B
:10040000A105B10589F082E08093C80088E9809356
:10041000C900CF911F910F910895C460C6CFC660E7
:10042000C4CF20E130E0DFCF80E0EECF1F920F920B
:100430000FB60F9211242F933F934F935F936F93B7
:100440007F938F939F93AF93BF93EF93FF936091AD
:10045000CE008EB3843019F48BE191E080DEFF9101
:10046000EF91BF91AF919F918F917F916F915F912C
:100470004F913F912F910F900FBE0F901F901895A5
:1004800023B1FC01858580FF07C027FD05C081E001
:10049000809316015F9808955F9A0895292F332756
:1004A0002230310571F02330310581F021303105E2
:1004B000A1F482E190E024E131E0FA01318320836C
:1004C00008958EE390E026ED30E0F7CF9927813054
:1004D000910571F038F0029771F090E080E030E023
:1004E00020E0EBCFE2EDF0E0849190E09F01E5CFDA
:1004F000EEE9F0E0F9CFE4E7F0E0F6CFAC0128E078
:1005000030E080E02417350718F08295807F089549
:100510008F5F220F331FF6CF8093E900EBEEF0E000
:10052000808181608083EDEEF0E010826093EC00CA
:1005300040838091EE00881F8827881F08951092BD
:10054000F40080E08093E9001092F0001092E8003F
:100550001092ED009091EB009E7F9093EB008F5FE7
:10056000853081F708958091290287FF11C080911D
:10057000E80082FF06C08091E8008B778093E80056
:1005800003C08EB38111F3CF08958EB38823E1F3B6
:100590008091E80080FFF9CF8091E8008E77EECF60
:1005A00085E69091EC0090FF06C09091E80090FFE6
:1005B00006C080E008959091E80092FDFACF9EB3C6
:1005C0009923A1F09EB3953099F09091EB0095FDA1
:1005D00011C09091E10092FFE4CF9091E1009B7FE8
:1005E0009093E1008150E9F684E0089582E0089557
:1005F00083E0089581E0089520912F023091300228
:1006000026173707A0F06115710529F42091E8003D
:100610002E772093E80030E06115710551F4311117
:1006200008C08091E80082FF30C080E00895B901E1
:10063000F2CF2091E80023FD30C02091E80022FD98
:10064000F0CF2EB3222359F12EB3253021F1209182
:10065000E80020FFE1CF2091F200FC01CF016115FD
:10066000710511F0283050F031E0283009F030E009
:100670002091E8002E772093E800CECF81918093DF
:10068000F100615071092F5FE9CF8EB3882339F0F3
:100690008EB3853031F683E0089581E0089582E0DD
:1006A000089520912F023091300226173707A0F0CD
:1006B0006115710529F42091E8002E772093E80058
:1006C00030E06115710551F4311108C08091E800E6
:1006D00082FF31C080E00895B901F2CF2091E80097
:1006E00023FD31C02091E80022FDF0CF2EB322235C
:1006F00061F12EB3253029F12091E80020FFE1CFF0
:100700002091F200FC01CF016115710511F0283034
:1007100050F031E0283009F030E02091E8002E77E9
:100720002093E800CECF84918093F100615071094D
:100730002F5F3196E8CF8EB3882339F08EB38530A2
:1007400029F683E0089581E0089582E00895611517
:10075000710529F42091E8002B772093E8006115BA
:10076000710531F48091E80080FF20C080E0089599
:100770002091E80023FD22C02EB3222309F12EB3DD
:100780002530D1F02091E80022FFE9CF2091F2003E
:10079000222301F39C012F5F3F4F4091F100FC01A8
:1007A000408361507109C90189F7D4CF8EB3882382
:1007B00039F08EB38530B1F683E0089581E0089575
:1007C00082E0089542D044D01EBA109227021092BF
:1007D00026021092250284E089BD89B5826089BD18
:1007E00009B400FEFDCF8091D800982F9F77909399
:1007F000D80080688093D800809163008E7F8093BA
:1008000063008091D8008F7D8093D8008091E000B4
:100810008E7F8093E0008091E1008E7F8093E100E5
:100820008091E20081608093E2008091E100877F07
:100830008093E1008091E20088608093E200089557
:10084000C1DF81E08093280208951092E2000895AC
:100850001092E10008951F920F920FB60F9211248B
:100860002F933F934F935F936F937F938F939F93B8
:10087000AF93BF93EF93FF938091E10080FF1BC084
:100880008091E20080FF17C08091E1008E7F80930D
:10089000E1008091E2008E7F8093E2008091E2008F
:1008A00080618093E2008091D80080628093D800BC
:1008B00019BC1EBAF7D18091E10084FF27C0809156
:1008C000E20084FF23C084E089BD89B5826089BDD0
:1008D00009B400FEFDCF8091D8008F7D8093D800B1
:1008E0008091E1008F7E8093E1008091E2008F7E15
:1008F0008093E2008091E20081608093E200809129
:10090000270281114DC081E08EBBCCD18091E100E6
:1009100083FF27C08091E20083FF23C08091E10024
:10092000877F8093E10082E08EBB10922702809146
:10093000E1008E7F8093E1008091E2008E7F8093C2
:10094000E2008091E20080618093E200F8DD42E005
:1009500060E080E0E1DD8091F00088608093F0004D
:10096000A1D18091E10082FF0AC08091E20082FF64
:1009700006C08091E1008B7F8093E10093D1FF91CD
:10098000EF91BF91AF919F918F917F916F915F9107
:100990004F913F912F910F900FBE0F901F90189580
:1009A00084E0B2CF1F920F920FB60F921124FF92E4
:1009B0000F931F932F933F934F935F936F937F9367
:1009C0008F939F93AF93BF93CF93DF93EF93FF9357
:1009D000C9EED0E088818770F82E188200EF10E011
:1009E000F8018081877F808378941DD0F8941882E5
:1009F000F801808188608083F882FF91EF91DF9118
:100A0000CF91BF91AF919F918F917F916F915F91A6
:100A10004F913F912F911F910F91FF900F900FBE1B
:100A20000F901F9018951F93CF93DF93CDB7DEB72C
:100A3000AA970FB6F894DEBF0FBECDBFE9E2F2E091
:100A40008091F100819322E0E133F207C9F78091B0
:100A5000290290912A029A3008F022C1E92FF0E091
:100A6000ED5CFA4F83C23D056205500662055006F3
:100A7000BD05D90550062B063706803881F082382F
:100A800009F00EC180912D0287708093E90080915A
:100A9000EB0085FB882780F91092E90006C0809161
:100AA000250290912602911182609091E800977F33
:100AB0009093E8008093F1001092F1008091E8009B
:100AC0008E772EC0282F2D7F09F0EAC08823D1F021
:100AD000823051F18091E80083FF0AC08091EB00E1
:100AE00080628093EB008091E800877F8093E8002C
:100AF000AA960FB6F894DEBF0FBECDBFDF91CF919F
:100B00001F91089580912B02813021F7933009F0D5
:100B100080E0809326021092E9008091E800877FB0
:100B20008093E80020DDD6CF80912B028111F3CF96
:100B300080912D02877071F28093E9002091EB0083
:100B400020FFC8CF933031F48091EB008062809316
:100B5000EB00E1CF9091EB0090619093EB0021E0EE
:100B600030E001C0220F8A95EAF72093EA00109244
:100B7000EA008091EB008860EACF811191C010916A
:100B80002B028091E800877F8093E800ECDC809165
:100B9000E80080FF0AC0812F8F7792E009F093E090
:100BA0009EBB80688093E30095CF8EB38111EFCF19
:100BB00091CF8058823008F073C080912B029091C1
:100BC0002C028C3D23E0920799F583E08A838AE228
:100BD00089834FB7F894DE01139620E03EE051E29E
:100BE000E32FF0E050935700E49120FF03C0E2951B
:100BF000EF703F5FEF7080E38E0F8A3310F087E372
:100C00008E0F90E08D939D932F5F243149F74FBF56
:100C10008091E800877F8093E8006AE270E0CE016F
:100C20000196EADC8091E8008B778093E80052CF50
:100C3000AE014F5F5F4F60912D0230DCBC01892B0C
:100C400009F448CF9091E800977F9093E80089815C
:100C50009A8127DDE7CF803819F58091E800877FFA
:100C60008093E800809127028093F10027CF8111C3
:100C700017C090912B02923008F02CCF8091E800A1
:100C8000877F8093E800909327026DDC8091270294
:100C9000811104C083E08EBB67DB1CCF84E0FBCFF7
:100CA00066DB18CF0895CF938EB3882359F0C09197
:100CB000E900C7701092E9008091E80083FDB3DE7F
:100CC000C093E900CF9108950895CF93DF93EC018D
:100CD0008091E80083FF0FC0288180912D029091C0
:100CE0002E022817190639F480912A028132C1F0A8
:100CF00028F4803249F1DF91CF9108958232C1F119
:100D00008332C9F7809129028132A9F78091E800E6
:100D1000877F8093E80060912B02CE01D5DF37C03A
:100D200080912902813A39F78091E800877F80938A
:100D3000E80067E070E0CE010F965EDC8091E8008D
:100D40008B778093E800D7CF80912902813299F682
:100D50008091E800877F8093E80067E070E0CE0133
:100D60000F96F5DCCE0106DB8091E8008E77E9CFA7
:100D700080912902813209F0BECF8091E800877FFF
:100D80008093E80080912B028D87CE0179DBDF9183
:100D9000CF91E9CB0F931F93CF93DF93EC01FC012D
:100DA0003D9689E0DF011D928A95E9F78A819B8152
:100DB0002C8110E0211114E00981A0DB812B482F48
:100DC000426061E8802FA8DB882311F18E819F812A
:100DD000288510E0211114E00D8190DB812B482F34
:100DE000426060E8802F98DB882391F08A859B859C
:100DF0002C8510E0211114E0C98580DB812B482F60
:100E0000426061EC8C2FDF91CF911F910F9184CBC9
:100E100080E0DF91CF911F910F910895CF93C62F5E
:100E20002EB32430F1F4FC01478550896189728921
:100E3000452B462B472BA9F081818093E9008091B7
:100E4000E80085FF05C0C093F10080E0CF910895D0
:100E50008091E8008E778093E800A2DB882399F3E5
:100E6000F5CF82E0F3CF2EB3243021F5FC01478586
:100E7000508961897289452B462B472BD9F0818196
:100E80008093E9008091F200811102C080E0089512
:100E90009091E8008091E8008E778093E80095FDBE
:100EA000F5CF7EDB811107C09091E8009E7790938B
:100EB000E800089582E008952EB3243051F4FC0137
:100EC0004785508961897289452B462B472B09F04C
:100ED000CACF08952EB3243019F08FEF9FEF0895F5
:100EE000FC014785508961897289452B462B472B28
:100EF000A1F385818093E9008091E80082FFEDCF26
:100F00008091F200882369F08091F10090E02091B7
:100F1000F200211105C02091E8002B772093E80012
:100F200008958FEF9FEFF3CFA1E21A2EAA1BBB1BF0
:100F3000FD010DC0AA1FBB1FEE1FFF1FA217B307A5
:100F4000E407F50720F0A21BB30BE40BF50B661FBB
:100F5000771F881F991F1A9469F76095709580957F
:100F600090959B01AC01BD01CF010895EE0FFF1FCD
:0C0F70000590F491E02D0994F894FFCF57
:100F7C0000034000000440000002080000000000D4
:080F8C0000000000000001005C
:00000001FF

View File

@ -1,4 +1,4 @@
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
#unset CAN_COMMANDS
#unset enablehardware_test
@ -10,7 +10,7 @@
versionInfo = "S" ;This info is what is displayed to user
[TunerStudio]
iniSpecVersion = 3.46
iniSpecVersion = 3.51
;-------------------------------------------------------------------------------
@ -158,8 +158,8 @@ page = 1
;Page 2 is all general settings (Previously part of page 1)
;--------------------------------------------------
page = 2
flexBoostLow = scalar, S08, 0, "kPa", 1.0, 0.0, -127, 127, 0
flexBoostHigh = scalar, U08, 1, "kPa", 1.0, 0.0, 0.0, 255, 0
unused2-1 = scalar, S08, 0, "kPa", 1.0, 0.0, -127, 127, 0
unused2-2 = scalar, U08, 1, "kPa", 1.0, 0.0, 0.0, 255, 0
asePct = scalar, U08, 2, "%", 1.0, 0.0, 0.0, 95.0, 0
aseCount = scalar, U08, 3, "s", 1.0, 0.0, 0.0, 255, 0
wueRates = array, U08, 4, [10], "%", 1.0, 0.0, 0.0, 255, 0
@ -236,10 +236,10 @@ page = 2
oddfire3 = scalar, U16, 53, "deg", 1.0, 0.0, 0.0, 720, 0 ; * ( 2 byte)
oddfire4 = scalar, U16, 55, "deg", 1.0, 0.0, 0.0, 720, 0 ; * ( 2 byte)
flexFuelLow = scalar, U08, 57, "%", 1.0, 0.0, 0.0, 250.0, 0
flexFuelHigh = scalar, U08, 58, "%", 1.0, 0.0, 0.0, 250.0, 0
flexAdvLow = scalar, U08, 59, "Deg", 1.0, 0.0, 0.0, 250.0, 0
flexAdvHigh = scalar, U08, 60, "Deg", 1.0, 0.0, 0.0, 250.0, 0
unused2-57 = scalar, U08, 57, "%", 1.0, 0.0, 0.0, 250.0, 0
unused2-58 = scalar, U08, 58, "%", 1.0, 0.0, 0.0, 250.0, 0
unused2-59 = scalar, U08, 59, "Deg", 1.0, 0.0, 0.0, 250.0, 0
unused2-60 = scalar, U08, 60, "Deg", 1.0, 0.0, 0.0, 250.0, 0
iacCLminDuty = scalar, U08, 61, "%", 1.0, 0.0, 0.0, 100.0, 0 ; Minimum and maximum duty cycles when using closed loop idle
iacCLmaxDuty = scalar, U08, 62, "%", 1.0, 0.0, 0.0, 100.0, 0
@ -281,8 +281,10 @@ page = 4
useResync = bits, U08, 6,[7:7], "No", "Yes"
sparkDur = scalar, U08, 7, "ms", 0.1, 0, 0, 25.5, 1 ; Spark duration
trigPatternSec = bits, U08, 8,[0:7], "Single tooth cam", "4-1 cam", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
unused4-9 = scalar, U08, 9, "ms", 0.1, 0.0, 0.0, 25.5, 1
unused4-10 = scalar, U08, 10, "ms", 0.1, 0.0, 0.0, 25.5, 1
bootloaderCaps = scalar, U08, 9, "level", 1, 0, 0, 255, 0
resetControl_custom = bits, U08, 10,[0:1], "Disabled", "Prevent When Running", "Prevent Always", "Serial Command"
resetControl_standard = bits, U08, 10,[0:1], "Disabled", "INVALID", "INVALID", "Enabled"
resetControlPin = bits, U08, 10,[2:7], "Board Default", "INVALID", "INVALID", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15", "INVALID"
SkipCycles = scalar, U08, 11, "cycles", 1, 0, 0, 255, 0
; name = array, type, offset, shape, units, scale, translate, lo, hi, digits
@ -716,8 +718,17 @@ page = 10
boostIntv = scalar, U08, 27, "ms", 1, 0, 0, 250, 0
stagedInjSizePri = scalar, U16, 28, "cc/min", 1, 0, 0, 1500, 0
stagedInjSizeSec = scalar, U16, 30, "cc/min", 1, 0, 0, 1500, 0
lnchCtrlTPS = scalar, U08, 32, "%TPS", 1, 0, 0, 100, 0
unused11_32_192 = array, U08, 32, [159], "RPM", 100.0, 0.0, 100, 25500, 0
flexBoostBins = array, U08, 33, [6], "%", 1.0, 0.0, 0.0, 250.0, 0
; The boost range is obviously arbitrary since int16_t has ~32k in both directions
flexBoostAdj = array, S16, 39, [6], "kPa", 1.0, 0.0, -500.0, 500.0, 0
flexFuelBins = array, U08, 51, [6], "%", 1.0, 0.0, 0.0, 250.0, 0
flexFuelAdj = array, U08, 57, [6], "%", 1.0, 0.0, 0.0, 250.0, 0
flexAdvBins = array, U08, 63, [6], "%", 1.0, 0.0, 0.0, 250.0, 0
flexAdvAdj = array, U08, 69, [6], "Deg", 1.0, 0.0, 0.0, 250.0, 0
unused11_75_192 = array, U08, 75,[117],"RPM", 100.0, 0.0, 100, 25500, 0
;-------------------------------------------------------------------------------
@ -754,6 +765,9 @@ page = 10
requiresPowerCycle = stagedInjSizePri
requiresPowerCycle = stagedInjSizeSec
requiresPowerCycle = stagingEnabled
requiresPowerCycle = resetControl_custom
requiresPowerCycle = resetControl_standard
requiresPowerCycle = resetControlPin
defaultValue = pinLayout, 1
defaultValue = TrigPattern, 0
@ -803,6 +817,10 @@ page = 10
defaultValue = realtime_base_address, 336
defaultValue = VVTasOnOff, 0
defaultValue = stagingEnabled, 0
defaultValue = lnchCtrlTPS, 0
defaultValue = resetControl_custom, 0
defaultValue = resetControl_standard, 0
defaultValue = bootloaderCaps, 0
; defaultValue = obd_address, 0
;Default pins
@ -813,6 +831,10 @@ page = 10
defaultValue = fuelPumpPin, 0
defaultValue = tachoPin, 0
defaultValue = perToothIgn, 0
defaultValue = resetControlPin, 0
controllerPriority = bootloaderCaps
[Menu]
;----------------------------------------------------------------------------
@ -847,6 +869,7 @@ menuDialog = main
subMenu = triggerSettings, "Trigger Setup"
;subMenu = OLED, "OLED Setup"
subMenu = airdensity_curve, "IAT Density"
subMenu = reset_control, "Reset Control"
menu = "&Tuning"
@ -989,15 +1012,12 @@ menuDialog = main
includeAFR = "When enabled, the current AFR reading is incorporated directly in the pulsewidth calculation as a percentage of the current target ratio. VE table must be retuned when this value is changed. "
useExtBaro = "By Default, Speeduino will measure barometric pressure upon startup. Optionally however, a 2nd pressure sensor can be used to perform live barometric readings whilst the system is on."
flexEnabled = "Turns on readings from the Flex sensor and enables the below adjustments"
flexFreqLow = "The frequency of the sensor at 0% ethanol (50Hz for standard GM/Continental sensor)"
flexEnabled = "Turns on readings from the Flex sensor and enables the below adjustments"
flexFreqLow = "The frequency of the sensor at 0% ethanol (50Hz for standard GM/Continental sensor)"
flexFreqHigh = "The frequency of the sensor at 100% ethanol (150Hz for standard GM/Continental sensor)"
flexFuelLow = "Fuel % to be used for the lowest ethanol reading (Typically 100%. ie No adjustment)"
flexFuelHigh = "Fuel % to be used for the highest ethanol reading (Typically 163% for 100% ethanol)"
flexAdvLow = "Additional advance (in degrees) at lowest ethanol reading (Typically 0)"
flexAdvHigh = "Additional advance (in degrees) at highest ethanol reading (Typically 10-20 degrees)"
flexBoostHigh = "This amount that will be added to the boost target at E100. Between E0 and E100, the amount added to the boost target will be scaled from 0 to this value"
flexBoostLow = "Typically should be set to 0, but can be used to lower boost at E0 if the bast tune is setup with some ethanol"
flexFuelAdj = "Fuel % to be used for the current ethanol % (Typically 100% @ 0%, 163% @ 100%)"
flexAdvAdj = "Additional advance (in degrees) for the current ethanol % (Typically 0 @ 0%, 10-20 @ 100%)"
flexBoostAdj = "Adjustment, in kPa, to the boost target for the current ethanol %. Negative values are allowed to lower boost at lower ethanol % if necessary."
flatSArm = "The RPM switch point that determines whether an eganged clutch is for launch control or flat shift. Below this figure, an engaged clutch is considered to be for launch, above this figure an active clutch input will be considered a flat shift. This should be set at least several hundred RPM above idle"
flatSSoftWin= "The number of RPM below the flat shift point where the softlimit will be applied (aka Soft limit window). Recommended values are 200-1000"
@ -1095,6 +1115,10 @@ menuDialog = main
stagedInjSizePri= "Size of the primary injectors. The sum of the Pri and Sec injectors values MUST match the value used in the req_fuel calculation"
stagedInjSizeSec= "Size of the secondary injectors. The sum of the Pri and Sec injectors values MUST match the value used in the req_fuel calculation"
resetControl_standard = "Whether to enable reset control of the Arduino's automatic reset feature. If this feature is enabled, the selected control pin will be held high at all times. In order to update your Speeduino's firmware, you will first need to open a serial terminal and send a 'U' command so that the Arduino resets when the upload starts. The control pin should be connected to the Arduino's reset pin."
resetControl_custom = "How to control the Arduino's automatic reset feature. NOTE: Some of these settings require modifying your hardware and replacing the Arduino bootloader. See the Wiki for more details.\n\nDisabled: Allow the Arduino to reset when a new serial connection is made.\n\nPrevent When Running: Hold the control pin high while the engine is running.\n\nPrevent Always: Always hold the control pin high.\n\nSerial Command: Normally hold the control pin high, but pull it low when the 'U' serial command is issued and reset upon receiving more data."
resetControlPin = "The Arduino pin used to control resets."
[UserDefined]
; Enhanced TunerStudio dialogs can be defined here
@ -1140,42 +1164,23 @@ menuDialog = main
panel = engine_constants_east, East
# Flex fuel stuff
dialog = flexFueling, "Flex Fuel"
field = "Flex sensor", flexEnabled
dialog = flexFuelSettings, "", yAxis
field = "Flex Fuel Sensor ", flexEnabled
field = "Low (E0) ", flexFreqLow, { flexEnabled }
field = "High (E100) ", flexFreqHigh, { flexEnabled }
dialog = flexLeft, ""
field = "Component"
field = "Sensor Frequency"
field = "Fuel Adjustment"
field = "Additional advance"
field = "Additional boost", { boostEnabled }
dialog = flexFuelWest, "", border
panel = flexFuelSettings, North
dialog = flexMiddle, ""
field = "Low (E0)"
field = "", flexFreqLow, { flexEnabled }
field = "", flexFuelLow, { flexEnabled }
field = "", flexAdvLow, { flexEnabled }
field = "", flexBoostLow, { boostEnabled }
dialog = flexCurves, "", indexCard
panel = flex_fuel_curve, { flexEnabled }
panel = flex_adv_curve, { flexEnabled }
panel = flex_boost_curve, { flexEnabled && boostEnabled }
dialog = flexRight, ""
field = "High (E100)"
field = "", flexFreqHigh, { flexEnabled }
field = "", flexFuelHigh, { flexEnabled }
field = "", flexAdvHigh, { flexEnabled }
field = "", flexBoostHigh, { flexEnabled && boostEnabled }
dialog = flexMain, "Flex Fuel Calibration", xAxis
panel = flexLeft
panel = flexMiddle
panel = flexRight
dialog = flexFuelTop, ""
field = "Flex Fuel Sensor", flexEnabled
dialog = flexFueling, "Fuel Sensor Settings", yAxis
dialog = flexFueling, "Fuel Sensor Settings", border
topicHelp = "http://speeduino.com/wiki/index.php/Flex_Fuel"
panel = flexFuelTop
panel = flexMain
panel = flexFuelWest, West
panel = flexCurves, Center
dialog = tacho, "Tacho"
field = "Output pin", tachoPin
@ -1389,6 +1394,7 @@ menuDialog = main
; Launch control
field = "Launch Control"
field = "Enable Launch", launchEnable
field = "TPS threshold", lnchCtrlTPS, { launchEnable }
field = "Soft rev limit", lnchSoftLim, { launchEnable }
field = "Soft limit absolute timing", lnchRetard, { launchEnable }
field = "Hard rev limit", lnchHardLim, { launchEnable }
@ -1801,6 +1807,13 @@ menuDialog = main
topicHelp = "http://speeduino.com/wiki/index.php/Serial3_IO_interface"
field = "Enable Second Serial", enable_canbus
dialog = reset_control, "Reset Control"
; Control type options for custom firmware
field = "Control Type", resetControl_custom, { bootloaderCaps > 0 }, { bootloaderCaps > 0 }
; Control type options for standard / unmodifyable firmware
field = "Control Type", resetControl_standard, { bootloaderCaps == 0 }, { bootloaderCaps == 0 }
field = "Control Pin", resetControlPin
;-------------------------------------------------------------------------------
; General help text
@ -1982,6 +1995,30 @@ cmdtestspk450dc = "E\x03\x0C"
; xBins = wueAFRBins, coolant
; yBins = wueAFRRates
; Flex fuel correction curves
curve = flex_fuel_curve, "Flex Fuel Adjustments"
columnLabel = "Ethanol", "Fuel"
xAxis = 0, 100, 5
yAxis = 0, 255, 10
xBins = flexFuelBins, flex
yBins = flexFuelAdj
size = 400, 200
curve = flex_adv_curve, "Flex Timing Advance"
columnLabel = "Ethanol", "Advance"
xAxis = 0, 100, 5
yAxis = 0, 100, 5
xBins = flexAdvBins, flex
yBins = flexAdvAdj
size = 400, 200
curve = flex_boost_curve, "Flex Boost Adjustments"
columnLabel = "Ethanol", "Boost"
xAxis = 0, 100, 5
yAxis = -100, 200, 5
xBins = flexBoostBins, flex
yBins = flexBoostAdj
size = 400, 200
[TableEditor]
; table_id, map3d_id, "title", page
@ -2234,6 +2271,8 @@ cmdtestspk450dc = "E\x03\x0C"
indicator = { hardLimitOn }, "Hard Limit OFF","Hard Limiter", white, black, red, black
indicator = { boostCutOut }, "Ign Cut OFF", "Ign Cut (Boost)", white, black, red, black
indicator = { sync }, "No Sync", "Sync", white, black, green, black
indicator = { resetLockOn }, "Reset Lock OFF","Reset Lock ON", red, black, green, black
indicator = { bootloaderCaps > 0 }, "Std. Boot", "Custom Boot", white, black, white, black
;-------------------------------------------------------------------------------
@ -2244,7 +2283,7 @@ cmdtestspk450dc = "E\x03\x0C"
; you change it.
ochGetCommand = "r\$tsCanId\x30%2o%2c"
ochBlockSize = 81
ochBlockSize = 84
secl = scalar, U08, 0, "sec", 1.000, 0.000
status1 = scalar, U08, 1, "bits", 1.000, 0.000
@ -2331,7 +2370,10 @@ cmdtestspk450dc = "E\x03\x0C"
pulseWidth2 = scalar, U16, 75, "ms", 0.001, 0.000
pulseWidth3 = scalar, U16, 77, "ms", 0.001, 0.000
pulseWidth4 = scalar, U16, 79, "ms", 0.001, 0.000
status3 = scalar, U08, 81, "bits", 1.000, 0.000
resetLockOn = bits, U08, 81, [0:0]
unused81_1-7 = bits, U08, 81, [1:7]
flexBoostCor = scalar, S16, 81, "kPa", 1.000, 0.000
#if CELSIUS
coolant = { coolantRaw - 40 } ; Temperature readings are offset by 40 to allow for negatives
iat = { iatRaw - 40 } ; Temperature readings are offset by 40 to allow for negatives

View File

@ -4,15 +4,15 @@ Copyright (C) Josh Stewart
A full copy of the license may be found in the projects root directory
*/
//Old PID method. Retained incase the new one has issues
//integerPID boostPID(&MAPx100, &boost_pwm_target_value, &boostTargetx100, configPage3.boostKP, configPage3.boostKI, configPage3.boostKD, DIRECT);
integerPID_ideal boostPID(&currentStatus.MAP, &currentStatus.boostDuty , &currentStatus.boostTarget, &configPage11.boostSens, &configPage11.boostIntv, configPage3.boostKP, configPage3.boostKI, configPage3.boostKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
//integerPID boostPID(&MAPx100, &boost_pwm_target_value, &boostTargetx100, configPage6.boostKP, configPage6.boostKI, configPage6.boostKD, DIRECT);
integerPID_ideal boostPID(&currentStatus.MAP, &currentStatus.boostDuty , &currentStatus.boostTarget, &configPage10.boostSens, &configPage10.boostIntv, configPage6.boostKP, configPage6.boostKI, configPage6.boostKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
/*
Fan control
*/
void initialiseFan()
{
if( configPage3.fanInv == 1 ) { fanHIGH = LOW; fanLOW = HIGH; }
if( configPage6.fanInv == 1 ) { fanHIGH = LOW; fanLOW = HIGH; }
else { fanHIGH = HIGH; fanLOW = LOW; }
digitalWrite(pinFan, fanLOW); //Initiallise program with the fan in the off state
currentStatus.fanOn = false;
@ -20,10 +20,10 @@ void initialiseFan()
void fanControl()
{
if( configPage3.fanEnable == 1 )
if( configPage6.fanEnable == 1 )
{
int onTemp = (int)configPage3.fanSP - CALIBRATION_TEMPERATURE_OFFSET;
int offTemp = onTemp - configPage3.fanHyster;
int onTemp = (int)configPage6.fanSP - CALIBRATION_TEMPERATURE_OFFSET;
int offTemp = onTemp - configPage6.fanHyster;
if ( (!currentStatus.fanOn) && (currentStatus.coolant >= onTemp) ) { digitalWrite(pinFan,fanHIGH); currentStatus.fanOn = true; }
if ( (currentStatus.fanOn) && (currentStatus.coolant <= offTemp) ) { digitalWrite(pinFan, fanLOW); currentStatus.fanOn = false; }
@ -48,18 +48,18 @@ void initialiseAuxPWM()
vvt_pin_mask = digitalPinToBitMask(pinVVT_1);
#if defined(CORE_STM32) //2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / (configPage3.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 freqneucies up to 511Hz
vvt_pwm_max_count = 1000000L / (configPage3.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle
boost_pwm_max_count = 1000000L / (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 freqneucies up to 511Hz
vvt_pwm_max_count = 1000000L / (configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle
#else
boost_pwm_max_count = 1000000L / (16 * configPage3.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 freqneucies up to 511Hz
vvt_pwm_max_count = 1000000L / (16 * configPage3.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle
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 freqneucies 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
#endif
//TIMSK1 |= (1 << OCIE1A); <---- Not required as compare A is turned on when needed by boost control
ENABLE_VVT_TIMER(); //Turn on the B compare unit (ie turn on the interrupt)
boostPID.SetOutputLimits(configPage1.boostMinDuty, configPage1.boostMaxDuty);
if(configPage3.boostMode == BOOST_MODE_SIMPLE) { boostPID.SetTunings(100, 100, 100); }
else { boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); }
boostPID.SetOutputLimits(configPage2.boostMinDuty, configPage2.boostMaxDuty);
if(configPage6.boostMode == BOOST_MODE_SIMPLE) { boostPID.SetTunings(100, 100, 100); }
else { boostPID.SetTunings(configPage6.boostKP, configPage6.boostKI, configPage6.boostKD); }
currentStatus.boostDuty = 0;
boostCounter = 0;
@ -75,17 +75,19 @@ void initialiseAuxPWM()
#define BOOST_HYSTER 40
void boostControl()
{
if( configPage3.boostEnabled==1 )
if( configPage6.boostEnabled==1 )
{
if( (boostCounter & 7) == 1) { currentStatus.boostTarget = get3DTableValue(&boostTable, currentStatus.TPS, currentStatus.RPM) * 2; } //Boost target table is in kpa and divided by 2
if(currentStatus.MAP >= (currentStatus.boostTarget - BOOST_HYSTER) )
{
//If flex fuel is enabled, there can be an adder to the boost target based on ethanol content
if( configPage1.flexEnabled == 1 )
if( configPage2.flexEnabled == 1 )
{
int16_t boostAdder = (((int16_t)configPage1.flexBoostHigh - (int16_t)configPage1.flexBoostLow) * currentStatus.ethanolPct) / 100;
boostAdder = boostAdder + configPage1.flexBoostLow; //Required in case flexBoostLow is less than 0
currentStatus.boostTarget += boostAdder;
currentStatus.boostTarget += table2D_getValue(&flexBoostTable, currentStatus.ethanolPct);;
}
else
{
currentStatus.flexBoostCorrection = 0;
}
if(currentStatus.boostTarget > 0)
@ -93,10 +95,10 @@ void boostControl()
//This only needs to be run very infrequently, once every 16 calls to boostControl(). This is approx. once per second
if( (boostCounter & 15) == 1)
{
boostPID.SetOutputLimits(configPage1.boostMinDuty, configPage1.boostMaxDuty);
boostPID.SetOutputLimits(configPage2.boostMinDuty, configPage2.boostMaxDuty);
if(configPage3.boostMode == BOOST_MODE_SIMPLE) { boostPID.SetTunings(100, 100, 100); }
else { boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); }
if(configPage6.boostMode == BOOST_MODE_SIMPLE) { boostPID.SetTunings(100, 100, 100); }
else { boostPID.SetTunings(configPage6.boostKP, configPage6.boostKI, configPage6.boostKD); }
}
bool PIDcomputed = boostPID.Compute(); //Compute() returns false if the required interval has not yet passed.
@ -123,19 +125,22 @@ void boostControl()
boostDisable();
}
}
else { DISABLE_BOOST_TIMER(); } // Disable timer channel
else { // Disable timer channel and zero the flex boost correction status
DISABLE_BOOST_TIMER();
currentStatus.flexBoostCorrection = 0;
}
boostCounter++;
}
void vvtControl()
{
if( configPage3.vvtEnabled == 1 )
if( configPage6.vvtEnabled == 1 )
{
byte vvtDuty = get3DTableValue(&vvtTable, currentStatus.TPS, currentStatus.RPM);
//VVT table can be used for controlling on/off switching. If this is turned on, then disregard any interpolation or non-binary values
if( (configPage3.VVTasOnOff == true) && (vvtDuty < 100) ) { vvtDuty = 0; }
if( (configPage6.VVTasOnOff == true) && (vvtDuty < 100) ) { vvtDuty = 0; }
if(vvtDuty == 0)
{

View File

@ -33,12 +33,12 @@ void canCommand()
{
Gdata[Gx] = CANSerial.read();
}
Glow = Gdata[(configPage10.caninput_source_start_byte[destcaninchannel]&7)];
if ((BIT_CHECK(configPage10.caninput_source_num_bytes,destcaninchannel))) //if true then num bytes is 2
Glow = Gdata[(configPage9.caninput_source_start_byte[destcaninchannel]&7)];
if ((BIT_CHECK(configPage9.caninput_source_num_bytes,destcaninchannel))) //if true then num bytes is 2
{
if ((configPage10.caninput_source_start_byte[destcaninchannel]&7) < 8) //you cant have a 2 byte value starting at byte 7(8 on the list)
if ((configPage9.caninput_source_start_byte[destcaninchannel]&7) < 8) //you cant have a 2 byte value starting at byte 7(8 on the list)
{
Ghigh = Gdata[((configPage10.caninput_source_start_byte[destcaninchannel]&7)+1)];
Ghigh = Gdata[((configPage9.caninput_source_start_byte[destcaninchannel]&7)+1)];
}
else{Ghigh = 0;}
}

View File

@ -12,7 +12,7 @@
#define canbusPage 9//Config Page 9
#define warmupPage 10 //Config Page 10
#define SERIAL_PACKET_SIZE 81
#define SERIAL_PACKET_SIZE 84
byte currentPage = 1;//Not the same as the speeduino config page numbers
bool isMap = true;
@ -32,14 +32,14 @@ byte tsCanId = 0; // current tscanid requested
const char pageTitles[] PROGMEM //This is being stored in the avr flash instead of SRAM which there is not very much of
{
"\nVE Map\0"//This is an alternative to using a 2D array which would waste space because of the different lengths of the strings
"\nPg 1 Config\0"//The configuration page titles' indexes are found by counting the chars
"\nIgnition Map\0"//The map page titles' indexes are put into a var called currentTitleIndex. That represents the first char of each string.
"\nPg 2 Config\0"
"\nAFR Map\0"
"\nPg 3 Config\0"
"\nPg 4 Config\0"
"\nBoost Map\0"
"\nVVT Map\0"//No need to put a trailing null because it's the last string and the compliler does it for you.
"\nPg 1 Config\0"// 21-The configuration page titles' indexes are found by counting the chars
"\nIgnition Map\0"//35-The map page titles' indexes are put into a var called currentTitleIndex. That represents the first char of each string.
"\nPg 2 Config\0" //48
"\nAFR Map\0" //56
"\nPg 3 Config\0" //69
"\nPg 4 Config\0" //82
"\nBoost Map\0" //93
"\nVVT Map\0"//102-No need to put a trailing null because it's the last string and the compliler does it for you.
"\nPg 10 Config"
};

View File

@ -183,6 +183,24 @@ void command()
break;
case 'U': //User wants to reset the Arduino (probably for FW update)
if (resetControl != RESET_CONTROL_DISABLED)
{
#ifndef SMALL_FLASH_MODE
if (!cmdPending) { Serial.println(F("Comms halted. Next byte will reset the Arduino.")); }
#endif
while (Serial.available() == 0) { }
digitalWrite(pinResetControl, LOW);
}
else
{
#ifndef SMALL_FLASH_MODE
if (!cmdPending) { Serial.println(F("Reset control is currently disabled.")); }
#endif
}
break;
case 'V': // send VE table and constants in binary
sendPage(false);
break;
@ -282,9 +300,9 @@ void command()
Serial.println(F("WUE"));
for (int x = 0; x < 10; x++)
{
Serial.print(configPage2.wueBins[x]);
Serial.print(configPage4.wueBins[x]);
Serial.print(", ");
Serial.println(configPage1.wueValues[x]);
Serial.println(configPage2.wueValues[x]);
}
Serial.flush();
#endif
@ -294,6 +312,16 @@ void command()
sendToothLog(true); //Sends tooth log values as chars
break;
case '`': //Custom 16u2 firmware is making its presence known
cmdPending = true;
if (Serial.available() >= 1) {
configPage4.bootloaderCaps = Serial.read();
cmdPending = false;
}
break;
case '?':
#ifndef SMALL_FLASH_MODE
Serial.println
@ -321,6 +349,7 @@ void command()
"Z - Display calibration values\n"
"T - Displays 256 tooth log entries in binary\n"
"r - Displays 256 tooth log entries\n"
"U - Prepare for firmware update. The next byte received will cause the Arduino to reset.\n"
"? - Displays this help page"
));
#endif
@ -458,6 +487,10 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum)
fullStatus[79] = lowByte(currentStatus.PW4); //Pulsewidth 4 multiplied by 10 in ms. Have to convert from uS to mS.
fullStatus[80] = highByte(currentStatus.PW4); //Pulsewidth 4 multiplied by 10 in ms. Have to convert from uS to mS.
fullStatus[81] = currentStatus.status3;
fullStatus[82] = lowByte(currentStatus.flexBoostCorrection);
fullStatus[83] = highByte(currentStatus.flexBoostCorrection);
for(byte x=0; x<packetLength; x++)
{
if (portNum == 0) { Serial.write(fullStatus[offset+x]); }
@ -501,7 +534,7 @@ void receiveValue(int valueOffset, byte newValue)
break;
case veSetPage:
pnt_configPage = &configPage1; //Setup a pointer to the relevant config page
pnt_configPage = &configPage2; //Setup a pointer to the relevant config page
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if (valueOffset < npage_size[veSetPage])
{
@ -532,7 +565,7 @@ void receiveValue(int valueOffset, byte newValue)
break;
case ignSetPage:
pnt_configPage = &configPage2;
pnt_configPage = &configPage4;
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if (valueOffset < npage_size[ignSetPage])
{
@ -564,7 +597,7 @@ void receiveValue(int valueOffset, byte newValue)
break;
case afrSetPage:
pnt_configPage = &configPage3;
pnt_configPage = &configPage6;
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if (valueOffset < npage_size[afrSetPage])
{
@ -639,7 +672,7 @@ void receiveValue(int valueOffset, byte newValue)
break;
case canbusPage:
pnt_configPage = &configPage10;
pnt_configPage = &configPage9;
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if (valueOffset < npage_size[currentPage])
{
@ -648,7 +681,7 @@ void receiveValue(int valueOffset, byte newValue)
break;
case warmupPage:
pnt_configPage = &configPage11;
pnt_configPage = &configPage10;
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if (valueOffset < npage_size[currentPage])
{
@ -670,7 +703,7 @@ useChar - If true, all values are send as chars, this is for the serial command
*/
void sendPage(bool useChar)
{
void* pnt_configPage = &configPage1; //Default value is for safety only. Will be changed below if needed.
void* pnt_configPage = &configPage2; //Default value is for safety only. Will be changed below if needed.
struct table3D currentTable = fuelTable; //Default value is for safety only. Will be changed below if needed.
byte currentTitleIndex = 0;// This corresponds to the count up to the first char of a string in pageTitles
bool sendComplete = false; //Used to track whether all send operations are complete
@ -692,27 +725,27 @@ void sendPage(bool useChar)
Serial.println((const __FlashStringHelper *)&pageTitles[27]);//27 is the index to the first char in the second sting in pageTitles
// The following loop displays in human readable form of all byte values in config page 1 up to but not including the first array.
// incrementing void pointers is cumbersome. Thus we have "pnt_configPage = (byte *)pnt_configPage + 1"
for (pnt_configPage = &configPage1; pnt_configPage < &configPage1.wueValues[0]; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
for (pnt_configPage = &configPage2; pnt_configPage < &configPage2.wueValues[0]; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
for (byte x = 10; x; x--)// The x between the ';' has the same representation as the "x != 0" test or comparision
{
Serial.print(configPage1.wueValues[10 - x]);// This displays the values horizantially on the screen
Serial.print(configPage2.wueValues[10 - x]);// This displays the values horizantially on the screen
Serial.print(' ');
}
Serial.println();
for (pnt_configPage = (byte *)&configPage1.wueValues[9] + 1; pnt_configPage < &configPage1.inj1Ang; pnt_configPage = (byte *)pnt_configPage + 1) {
for (pnt_configPage = (byte *)&configPage2.wueValues[9] + 1; pnt_configPage < &configPage2.inj1Ang; pnt_configPage = (byte *)pnt_configPage + 1) {
Serial.println(*((byte *)pnt_configPage));// This displays all the byte values between the last array up to but not including the first unsigned int on config page 1
}
// The following loop displays four unsigned ints
for (pnt16_configPage = (uint16_t *)&configPage1.inj1Ang; pnt16_configPage < (uint16_t*)&configPage1.inj4Ang + 1; pnt16_configPage = (uint16_t*)pnt16_configPage + 1)
for (pnt16_configPage = (uint16_t *)&configPage2.inj1Ang; pnt16_configPage < (uint16_t*)&configPage2.inj4Ang + 1; pnt16_configPage = (uint16_t*)pnt16_configPage + 1)
{ Serial.println(*((uint16_t *)pnt16_configPage)); }
// Following loop displays byte values between the unsigned ints
for (pnt_configPage = (uint16_t *)&configPage1.inj4Ang + 1; pnt_configPage < &configPage1.mapMax; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
Serial.println(configPage1.mapMax);
for (pnt_configPage = (uint16_t *)&configPage2.inj4Ang + 1; pnt_configPage < &configPage2.mapMax; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
Serial.println(configPage2.mapMax);
// Following loop displays remaining byte values of the page
for (pnt_configPage = (uint16_t *)&configPage1.mapMax + 1; pnt_configPage < (byte *)&configPage1 + npage_size[veSetPage]; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
for (pnt_configPage = (uint16_t *)&configPage2.mapMax + 1; pnt_configPage < (byte *)&configPage2 + npage_size[veSetPage]; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
sendComplete = true;
}
else { pnt_configPage = &configPage1; } //Create a pointer to Page 1 in memory
else { pnt_configPage = &configPage2; } //Create a pointer to Page 1 in memory
break;
case ignMapPage:
@ -726,17 +759,17 @@ void sendPage(bool useChar)
{
//To Display Values from Config Page 2
Serial.println((const __FlashStringHelper *)&pageTitles[56]);
Serial.println(configPage2.triggerAngle);// configPsge2.triggerAngle is an int so just display it without complication
Serial.println(configPage4.triggerAngle);// configPsge2.triggerAngle is an int so just display it without complication
// Following loop displays byte values after that first int up to but not including the first array in config page 2
for (pnt_configPage = (int *)&configPage2 + 1; pnt_configPage < &configPage2.taeBins[0]; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
for (pnt_configPage = (int *)&configPage4 + 1; pnt_configPage < &configPage4.taeBins[0]; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
for (byte y = 2; y; y--)// Displaying two equal sized arrays
{
byte * currentVar;// A placeholder for each array
if (y == 2) {
currentVar = configPage2.taeBins;
currentVar = configPage4.taeBins;
}
else {
currentVar = configPage2.taeValues;
currentVar = configPage4.taeValues;
}
for (byte j = 4; j; j--)
@ -748,24 +781,24 @@ void sendPage(bool useChar)
}
for (byte x = 10; x ; x--)
{
Serial.print(configPage2.wueBins[10 - x]);//Displaying array horizontally across screen
Serial.print(configPage4.wueBins[10 - x]);//Displaying array horizontally across screen
Serial.print(' ');
}
Serial.println();
Serial.println(configPage2.dwellLimit);// Little lonely byte stuck between two arrays. No complications just display it.
Serial.println(configPage4.dwellLimit);// Little lonely byte stuck between two arrays. No complications just display it.
for (byte x = 6; x; x--)
{
Serial.print(configPage2.dwellCorrectionValues[6 - x]);
Serial.print(configPage4.dwellCorrectionValues[6 - x]);
Serial.print(' ');
}
Serial.println();
for (pnt_configPage = (byte *)&configPage2.dwellCorrectionValues[5] + 1; pnt_configPage < (byte *)&configPage2 + npage_size[ignSetPage]; pnt_configPage = (byte *)pnt_configPage + 1)
for (pnt_configPage = (byte *)&configPage4.dwellCorrectionValues[5] + 1; pnt_configPage < (byte *)&configPage4 + npage_size[ignSetPage]; pnt_configPage = (byte *)pnt_configPage + 1)
{
Serial.println(*((byte *)pnt_configPage));// Displaying remaining byte values of the page
}
sendComplete = true;
}
else { pnt_configPage = &configPage2; } //Create a pointer to Page 2 in memory
else { pnt_configPage = &configPage4; } //Create a pointer to Page 2 in memory
break;
case afrMapPage:
@ -779,15 +812,15 @@ void sendPage(bool useChar)
{
//To Display Values from Config Page 3
Serial.println((const __FlashStringHelper *)&pageTitles[91]);//special typecasting to enable suroutine that the F macro uses
for (pnt_configPage = &configPage3; pnt_configPage < &configPage3.voltageCorrectionBins[0]; pnt_configPage = (byte *)pnt_configPage + 1)
for (pnt_configPage = &configPage6; pnt_configPage < &configPage6.voltageCorrectionBins[0]; pnt_configPage = (byte *)pnt_configPage + 1)
{
Serial.println(*((byte *)pnt_configPage));// Displaying byte values of config page 3 up to but not including the first array
}
for (byte y = 2; y; y--)// Displaying two equally sized arrays that are next to each other
{
byte * currentVar;
if (y == 2) { currentVar = configPage3.voltageCorrectionBins; }
else { currentVar = configPage3.injVoltageCorrectionValues; }
if (y == 2) { currentVar = configPage6.voltageCorrectionBins; }
else { currentVar = configPage6.injVoltageCorrectionValues; }
for (byte x = 6; x; x--)
{
@ -799,8 +832,8 @@ void sendPage(bool useChar)
for (byte y = 2; y; y--)// and again
{
byte* currentVar;
if (y == 2) { currentVar = configPage3.airDenBins; }
else { currentVar = configPage3.airDenRates; }
if (y == 2) { currentVar = configPage6.airDenBins; }
else { currentVar = configPage6.airDenRates; }
for (byte x = 9; x; x--)
{
@ -810,13 +843,13 @@ void sendPage(bool useChar)
Serial.println();
}
// Following loop displays the remaining byte values of the page
for (pnt_configPage = (byte *)&configPage3.airDenRates[8] + 1; pnt_configPage < (byte *)&configPage3 + npage_size[afrSetPage]; pnt_configPage = (byte *)pnt_configPage + 1)
for (pnt_configPage = (byte *)&configPage6.airDenRates[8] + 1; pnt_configPage < (byte *)&configPage6 + npage_size[afrSetPage]; pnt_configPage = (byte *)pnt_configPage + 1)
{
Serial.println(*((byte *)pnt_configPage));
}
sendComplete = true;
}
else { pnt_configPage = &configPage3; } //Create a pointer to Page 3 in memory
else { pnt_configPage = &configPage6; } //Create a pointer to Page 3 in memory
//Old configPage4 STARTED HERE!
//currentTitleIndex = 106;
@ -829,10 +862,10 @@ void sendPage(bool useChar)
byte * currentVar;
switch (y)
{
case 1: currentVar = configPage3.iacBins; break;
case 2: currentVar = configPage3.iacOLPWMVal; break;
case 3: currentVar = configPage3.iacOLStepVal; break;
case 4: currentVar = configPage3.iacCLValues; break;
case 1: currentVar = configPage6.iacBins; break;
case 2: currentVar = configPage6.iacOLPWMVal; break;
case 3: currentVar = configPage6.iacOLStepVal; break;
case 4: currentVar = configPage6.iacCLValues; break;
default: break;
}
for (byte x = 10; x; x--)
@ -847,9 +880,9 @@ void sendPage(bool useChar)
byte * currentVar;
switch (y)
{
case 1: currentVar = configPage3.iacCrankBins; break;
case 2: currentVar = configPage3.iacCrankDuty; break;
case 3: currentVar = configPage3.iacCrankSteps; break;
case 1: currentVar = configPage6.iacCrankBins; break;
case 2: currentVar = configPage6.iacCrankDuty; break;
case 3: currentVar = configPage6.iacCrankSteps; break;
default: break;
}
for (byte x = 4; x; x--)
@ -860,10 +893,10 @@ void sendPage(bool useChar)
Serial.println();
}
// Following loop is for remaining byte value of page
for (pnt_configPage = (byte *)&configPage3.iacCrankBins[3] + 1; pnt_configPage < (byte *)&configPage3 + npage_size[afrSetPage]; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
for (pnt_configPage = (byte *)&configPage6.iacCrankBins[3] + 1; pnt_configPage < (byte *)&configPage6 + npage_size[afrSetPage]; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
sendComplete = true;
}
else { pnt_configPage = &configPage3; } //Create a pointer to Page 4 in memory
else { pnt_configPage = &configPage6; } //Create a pointer to Page 4 in memory
break;
case boostvvtPage:
@ -963,14 +996,14 @@ void sendPage(bool useChar)
if (useChar)
{
//To Display Values from Config Page 10
Serial.println((const __FlashStringHelper *)&pageTitles[141]);//special typecasting to enable suroutine that the F macro uses
for (pnt_configPage = &configPage10; pnt_configPage < ((byte *)pnt_configPage + 128); pnt_configPage = (byte *)pnt_configPage + 1)
Serial.println((const __FlashStringHelper *)&pageTitles[103]);//special typecasting to enable suroutine that the F macro uses
for (pnt_configPage = &configPage9; pnt_configPage < ((byte *)pnt_configPage + 128); pnt_configPage = (byte *)pnt_configPage + 1)
{
Serial.println(*((byte *)pnt_configPage));// Displaying byte values of config page 3 up to but not including the first array
}
sendComplete = true;
}
else { pnt_configPage = &configPage10; } //Create a pointer to Page 10 in memory
else { pnt_configPage = &configPage9; } //Create a pointer to Page 10 in memory
break;
case warmupPage:
@ -978,7 +1011,7 @@ void sendPage(bool useChar)
{
sendComplete = true;
}
else { pnt_configPage = &configPage11; } //Create a pointer to Page 11 in memory
else { pnt_configPage = &configPage10; } //Create a pointer to Page 11 in memory
break;
default:
@ -986,7 +1019,7 @@ void sendPage(bool useChar)
Serial.println(F("\nPage has not been implemented yet"));
#endif
//Just set default Values to avoid warnings
pnt_configPage = &configPage11;
pnt_configPage = &configPage10;
currentTable = fuelTable;
sendComplete = true;
break;
@ -1105,7 +1138,7 @@ void sendPage(bool useChar)
byte getPageValue(byte page, uint16_t valueAddress)
{
void* pnt_configPage = &configPage1; //Default value is for safety only. Will be changed below if needed.
void* pnt_configPage = &configPage2; //Default value is for safety only. Will be changed below if needed.
uint16_t tempAddress;
byte returnValue = 0;
@ -1118,7 +1151,7 @@ byte getPageValue(byte page, uint16_t valueAddress)
break;
case veSetPage:
pnt_configPage = &configPage1; //Create a pointer to Page 1 in memory
pnt_configPage = &configPage2; //Create a pointer to Page 1 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
@ -1129,7 +1162,7 @@ byte getPageValue(byte page, uint16_t valueAddress)
break;
case ignSetPage:
pnt_configPage = &configPage2; //Create a pointer to Page 2 in memory
pnt_configPage = &configPage4; //Create a pointer to Page 2 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
@ -1140,7 +1173,7 @@ byte getPageValue(byte page, uint16_t valueAddress)
break;
case afrSetPage:
pnt_configPage = &configPage3; //Create a pointer to Page 3 in memory
pnt_configPage = &configPage6; //Create a pointer to Page 3 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
@ -1213,12 +1246,12 @@ byte getPageValue(byte page, uint16_t valueAddress)
break;
case canbusPage:
pnt_configPage = &configPage10; //Create a pointer to Page 10 in memory
pnt_configPage = &configPage9; //Create a pointer to Page 10 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
case warmupPage:
pnt_configPage = &configPage11; //Create a pointer to Page 11 in memory
pnt_configPage = &configPage10; //Create a pointer to Page 11 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
@ -1227,7 +1260,7 @@ byte getPageValue(byte page, uint16_t valueAddress)
Serial.println(F("\nPage has not been implemented yet"));
#endif
//Just set default Values to avoid warnings
pnt_configPage = &configPage11;
pnt_configPage = &configPage10;
break;
}
return returnValue;

View File

@ -17,7 +17,7 @@ Flood clear mode etc.
#include "globals.h"
long PID_O2, PID_output, PID_AFRTarget;
PID egoPID(&PID_O2, &PID_output, &PID_AFRTarget, configPage3.egoKP, configPage3.egoKI, configPage3.egoKD, REVERSE); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
PID egoPID(&PID_O2, &PID_output, &PID_AFRTarget, configPage6.egoKP, configPage6.egoKI, configPage6.egoKD, REVERSE); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
void initialiseCorrections()
{
@ -114,7 +114,7 @@ Additional fuel % to be added when the engine is cranking
static inline byte correctionCranking()
{
byte crankingValue = 100;
//if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) { crankingValue = 100 + configPage1.crankingPct; }
//if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) { crankingValue = 100 + configPage2.crankingPct; }
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
{
crankingValue = table2D_getValue(&crankingEnrichTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET);
@ -133,10 +133,10 @@ static inline byte correctionASE()
//Two checks are requiredL:
//1) Is the negine run time less than the configured ase time
//2) Make sure we're not still cranking
if ( (currentStatus.runSecs < configPage1.aseCount) && !(BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) )
if ( (currentStatus.runSecs < configPage2.aseCount) && !(BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) )
{
BIT_SET(currentStatus.engine, BIT_ENGINE_ASE); //Mark ASE as active.
ASEValue = 100 + configPage1.asePct;
ASEValue = 100 + configPage2.asePct;
}
else
{
@ -189,10 +189,10 @@ static inline int16_t correctionAccel()
int rateOfChange = ldiv(1000000, (currentStatus.TPS_time - currentStatus.TPSlast_time)).quot * TPS_change; //This is the % per second that the TPS has moved
currentStatus.tpsDOT = rateOfChange / 10; //The TAE bins are divided by 10 in order to allow them to be stored in a byte. Faster as this than divu10
if (rateOfChange > configPage1.tpsThresh)
if (rateOfChange > configPage2.tpsThresh)
{
BIT_SET(currentStatus.engine, BIT_ENGINE_ACC); //Mark accleration enrichment as active.
currentStatus.TAEEndTime = micros() + ((unsigned long)configPage1.taeTime * 10000); //Set the time in the future where the enrichment will be turned off. taeTime is stored as mS / 10, so multiply it by 100 to get it in uS
currentStatus.TAEEndTime = micros() + ((unsigned long)configPage2.taeTime * 10000); //Set the time in the future where the enrichment will be turned off. taeTime is stored as mS / 10, so multiply it by 100 to get it in uS
accelValue = 100 + table2D_getValue(&taeTable, currentStatus.tpsDOT);
}
}
@ -212,7 +212,7 @@ static inline byte correctionFloodClear()
if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
{
//Engine is currently cranking, check what the TPS is
if(currentStatus.TPS >= configPage2.floodClear)
if(currentStatus.TPS >= configPage4.floodClear)
{
//Engine is cranking and TPS is above threshold. Cut all fuel
floodValue = 0;
@ -254,7 +254,7 @@ This simple check applies the extra fuel if we're currently launching
static inline byte correctionLaunch()
{
byte launchValue = 100;
if(currentStatus.launchingHard || currentStatus.launchingSoft) { launchValue = (100 + configPage3.lnchFuelAdd); }
if(currentStatus.launchingHard || currentStatus.launchingSoft) { launchValue = (100 + configPage6.lnchFuelAdd); }
return launchValue;
}
@ -265,10 +265,10 @@ static inline byte correctionLaunch()
static inline bool correctionDFCO()
{
bool DFCOValue = false;
if ( configPage1.dfcoEnabled == 1 )
if ( configPage2.dfcoEnabled == 1 )
{
if ( bitRead(currentStatus.status1, BIT_STATUS1_DFCO) == 1 ) { DFCOValue = ( currentStatus.RPM > ( configPage2.dfcoRPM * 10) ) && ( currentStatus.TPS < configPage2.dfcoTPSThresh ); }
else { DFCOValue = ( currentStatus.RPM > (unsigned int)( (configPage2.dfcoRPM * 10) + configPage2.dfcoHyster) ) && ( currentStatus.TPS < configPage2.dfcoTPSThresh ); }
if ( bitRead(currentStatus.status1, BIT_STATUS1_DFCO) == 1 ) { DFCOValue = ( currentStatus.RPM > ( configPage4.dfcoRPM * 10) ) && ( currentStatus.TPS < configPage4.dfcoTPSThresh ); }
else { DFCOValue = ( currentStatus.RPM > (unsigned int)( (configPage4.dfcoRPM * 10) + configPage4.dfcoHyster) ) && ( currentStatus.TPS < configPage4.dfcoTPSThresh ); }
}
return DFCOValue;
}
@ -280,10 +280,10 @@ static inline bool correctionDFCO()
static inline byte correctionFlex()
{
byte flexValue = 100;
if(configPage1.flexEnabled == 1)
if (configPage2.flexEnabled == 1)
{
byte flexRange = configPage1.flexFuelHigh - configPage1.flexFuelLow;
flexValue = percentage(currentStatus.ethanolPct, flexRange) + 100;
flexValue = table2D_getValue(&flexFuelTable, currentStatus.ethanolPct);
}
return flexValue;
}
@ -305,34 +305,34 @@ PID (Best suited to wideband sensors):
static inline byte correctionAFRClosedLoop()
{
byte AFRValue = 100;
if( configPage3.egoType > 0 ) //egoType of 0 means no O2 sensor
if( configPage6.egoType > 0 ) //egoType of 0 means no O2 sensor
{
currentStatus.afrTarget = currentStatus.O2; //Catch all incase the below doesn't run. This prevents the Include AFR option from doing crazy things if the AFR target conditions aren't met. This value is changed again below if all conditions are met.
//Determine whether the Y axis of the AFR target table tshould be MAP (Speed-Density) or TPS (Alpha-N)
byte yValue;
if (configPage1.algorithm == 0) { yValue = currentStatus.MAP; }
if (configPage2.algorithm == 0) { yValue = currentStatus.MAP; }
else { yValue = currentStatus.TPS; }
currentStatus.afrTarget = get3DTableValue(&afrTable, yValue, currentStatus.RPM); //Perform the target lookup
//Check all other requirements for closed loop adjustments
if( (currentStatus.coolant > (int)(configPage3.egoTemp - CALIBRATION_TEMPERATURE_OFFSET)) && (currentStatus.RPM > (unsigned int)(configPage3.egoRPM * 100)) && (currentStatus.TPS < configPage3.egoTPSMax) && (currentStatus.O2 < configPage3.ego_max) && (currentStatus.O2 > configPage3.ego_min) && (currentStatus.runSecs > configPage3.ego_sdelay) )
if( (currentStatus.coolant > (int)(configPage6.egoTemp - CALIBRATION_TEMPERATURE_OFFSET)) && (currentStatus.RPM > (unsigned int)(configPage6.egoRPM * 100)) && (currentStatus.TPS < configPage6.egoTPSMax) && (currentStatus.O2 < configPage6.ego_max) && (currentStatus.O2 > configPage6.ego_min) && (currentStatus.runSecs > configPage6.ego_sdelay) )
{
AFRValue = currentStatus.egoCorrection; //Need to record this here, just to make sure the correction stays 'on' even if the nextCycle count isn't ready
if(ignitionCount >= AFRnextCycle)
{
AFRnextCycle = ignitionCount + configPage3.egoCount; //Set the target ignition event for the next calculation
AFRnextCycle = ignitionCount + configPage6.egoCount; //Set the target ignition event for the next calculation
//Check which algorithm is used, simple or PID
if (configPage3.egoAlgorithm == EGO_ALGORITHM_SIMPLE)
if (configPage6.egoAlgorithm == EGO_ALGORITHM_SIMPLE)
{
//*************************************************************************************************************************************
//Simple algorithm
if(currentStatus.O2 > currentStatus.afrTarget)
{
//Running lean
if(currentStatus.egoCorrection < (100 + configPage3.egoLimit) ) //Fueling adjustment must be at most the egoLimit amount (up or down)
if(currentStatus.egoCorrection < (100 + configPage6.egoLimit) ) //Fueling adjustment must be at most the egoLimit amount (up or down)
{
if(currentStatus.egoCorrection >= 100) { AFRValue = (currentStatus.egoCorrection + 1); } //Increase the fueling by 1%
else { AFRValue += 1; } //This means that the last reading had been rich, so start counting back towards 100%
@ -341,19 +341,19 @@ static inline byte correctionAFRClosedLoop()
}
else
//Running Rich
if(currentStatus.egoCorrection > (100 - configPage3.egoLimit) ) //Fueling adjustment must be at most the egoLimit amount (up or down)
if(currentStatus.egoCorrection > (100 - configPage6.egoLimit) ) //Fueling adjustment must be at most the egoLimit amount (up or down)
{
if(currentStatus.egoCorrection <= 100) { AFRValue = (currentStatus.egoCorrection - 1); } //Increase the fueling by 1%
else { AFRValue -= 1; } //This means that the last reading had been lean, so start count back towards 100%
}
else { AFRValue = currentStatus.egoCorrection; } //Means we're at the maximum adjustment amount, so simply return then again
}
else if(configPage3.egoAlgorithm == EGO_ALGORITHM_PID)
else if(configPage6.egoAlgorithm == EGO_ALGORITHM_PID)
{
//*************************************************************************************************************************************
//PID algorithm
egoPID.SetOutputLimits((long)(-configPage3.egoLimit), (long)(configPage3.egoLimit)); //Set the limits again, just incase the user has changed them since the last loop. Note that these are sent to the PID library as (Eg:) -15 and +15
egoPID.SetTunings(configPage3.egoKP, configPage3.egoKI, configPage3.egoKD); //Set the PID values again, just incase the user has changed them since the last loop
egoPID.SetOutputLimits((long)(-configPage6.egoLimit), (long)(configPage6.egoLimit)); //Set the limits again, just incase the user has changed them since the last loop. Note that these are sent to the PID library as (Eg:) -15 and +15
egoPID.SetTunings(configPage6.egoKP, configPage6.egoKI, configPage6.egoKD); //Set the PID values again, just incase the user has changed them since the last loop
PID_O2 = (long)(currentStatus.O2);
PID_AFRTarget = (long)(currentStatus.afrTarget);
@ -390,27 +390,23 @@ int8_t correctionsIgn(int8_t base_advance)
static inline int8_t correctionFixedTiming(int8_t advance)
{
byte ignFixValue = advance;
if (configPage2.FixAng != 0) { ignFixValue = configPage2.FixAng; } //Check whether the user has set a fixed timing angle
if (configPage4.FixAng != 0) { ignFixValue = configPage4.FixAng; } //Check whether the user has set a fixed timing angle
return ignFixValue;
}
static inline int8_t correctionCrankingFixedTiming(int8_t advance)
{
byte ignCrankFixValue = advance;
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) { ignCrankFixValue = configPage2.CrankAng; } //Use the fixed cranking ignition angle
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) { ignCrankFixValue = configPage4.CrankAng; } //Use the fixed cranking ignition angle
return ignCrankFixValue;
}
static inline int8_t correctionFlexTiming(int8_t advance)
{
byte ignFlexValue = advance;
if( configPage1.flexEnabled == 1 ) //Check for flex being enabled
if( configPage2.flexEnabled == 1 ) //Check for flex being enabled
{
byte flexRange = configPage1.flexAdvHigh - configPage1.flexAdvLow;
if (currentStatus.ethanolPct != 0) { currentStatus.flexIgnCorrection = percentage(currentStatus.ethanolPct, flexRange); }
else { currentStatus.flexIgnCorrection = 0; }
currentStatus.flexIgnCorrection = table2D_getValue(&flexAdvTable, currentStatus.ethanolPct);
ignFlexValue = advance + currentStatus.flexIgnCorrection;
}
return ignFlexValue;
@ -432,7 +428,7 @@ static inline int8_t correctionSoftRevLimit(int8_t advance)
{
byte ignSoftRevValue = advance;
BIT_CLEAR(currentStatus.spark, BIT_SPARK_SFTLIM);
if (currentStatus.RPM > ((unsigned int)(configPage2.SoftRevLim) * 100) ) { BIT_SET(currentStatus.spark, BIT_SPARK_SFTLIM); ignSoftRevValue = configPage2.SoftLimRetard; } //Softcut RPM limit (If we're above softcut limit, delay timing by configured number of degrees)
if (currentStatus.RPM > ((unsigned int)(configPage4.SoftRevLim) * 100) ) { BIT_SET(currentStatus.spark, BIT_SPARK_SFTLIM); ignSoftRevValue = configPage4.SoftLimRetard; } //Softcut RPM limit (If we're above softcut limit, delay timing by configured number of degrees)
return ignSoftRevValue;
}
@ -441,11 +437,11 @@ static inline int8_t correctionSoftLaunch(int8_t advance)
{
byte ignSoftLaunchValue = advance;
//SoftCut rev limit for 2-step launch control.
if (configPage3.launchEnabled && clutchTrigger && (currentStatus.clutchEngagedRPM < ((unsigned int)(configPage3.flatSArm) * 100)) && (currentStatus.RPM > ((unsigned int)(configPage3.lnchSoftLim) * 100)) )
if (configPage6.launchEnabled && clutchTrigger && (currentStatus.clutchEngagedRPM < ((unsigned int)(configPage6.flatSArm) * 100)) && (currentStatus.RPM > ((unsigned int)(configPage6.lnchSoftLim) * 100)) && (currentStatus.TPS >= configPage10.lnchCtrlTPS) )
{
currentStatus.launchingSoft = true;
BIT_SET(currentStatus.spark, BIT_SPARK_SLAUNCH);
ignSoftLaunchValue = configPage3.lnchRetard;
ignSoftLaunchValue = configPage6.lnchRetard;
}
else
{
@ -460,10 +456,10 @@ static inline int8_t correctionSoftFlatShift(int8_t advance)
{
byte ignSoftFlatValue = advance;
if(configPage3.flatSEnable && clutchTrigger && (currentStatus.clutchEngagedRPM > ((unsigned int)(configPage3.flatSArm) * 100)) && (currentStatus.RPM > (currentStatus.clutchEngagedRPM-configPage3.flatSSoftWin) ) )
if(configPage6.flatSEnable && clutchTrigger && (currentStatus.clutchEngagedRPM > ((unsigned int)(configPage6.flatSArm) * 100)) && (currentStatus.RPM > (currentStatus.clutchEngagedRPM-configPage6.flatSSoftWin) ) )
{
BIT_SET(currentStatus.spark2, BIT_SPARK2_FLATSS);
ignSoftFlatValue = configPage3.flatSRetard;
ignSoftFlatValue = configPage6.flatSRetard;
}
else { BIT_CLEAR(currentStatus.spark2, BIT_SPARK2_FLATSS); }
@ -479,19 +475,19 @@ uint16_t correctionsDwell(uint16_t dwell)
if (currentStatus.dwellCorrection != 100) { tempDwell = divs100(dwell) * currentStatus.dwellCorrection; }
//Dwell limiter
uint16_t dwellPerRevolution = tempDwell + (uint16_t)(configPage2.sparkDur * 100); //Spark duration is in mS*10. Multiple it by 100 to get spark duration in uS
uint16_t dwellPerRevolution = tempDwell + (uint16_t)(configPage4.sparkDur * 100); //Spark duration is in mS*10. Multiple it by 100 to get spark duration in uS
int8_t pulsesPerRevolution = 1;
//Single channel spark mode is the only time there will be more than 1 pulse per revolution on any given output
if( ( (configPage2.sparkMode == IGN_MODE_SINGLE) || (configPage2.sparkMode == IGN_MODE_ROTARY) ) && (configPage1.nCylinders > 1) ) //No point in running this for 1 cylinder engines
if( ( (configPage4.sparkMode == IGN_MODE_SINGLE) || (configPage4.sparkMode == IGN_MODE_ROTARY) ) && (configPage2.nCylinders > 1) ) //No point in running this for 1 cylinder engines
{
pulsesPerRevolution = (configPage1.nCylinders >> 1);
pulsesPerRevolution = (configPage2.nCylinders >> 1);
dwellPerRevolution = dwellPerRevolution * pulsesPerRevolution;
}
if(dwellPerRevolution > revolutionTime)
{
//Possibly need some method of reducing spark duration here as well, but this is a start
tempDwell = (revolutionTime / pulsesPerRevolution) - (configPage2.sparkDur * 100);
tempDwell = (revolutionTime / pulsesPerRevolution) - (configPage4.sparkDur * 100);
}
return tempDwell;
}

View File

@ -74,9 +74,9 @@ static inline uint16_t stdGetRPM()
*/
static inline void setFilter(unsigned long curGap)
{
if(configPage2.triggerFilter == 1) { triggerFilterTime = curGap >> 2; } //Lite filter level is 25% of previous gap
else if(configPage2.triggerFilter == 2) { triggerFilterTime = curGap >> 1; } //Medium filter level is 50% of previous gap
else if (configPage2.triggerFilter == 3) { triggerFilterTime = (curGap * 3) >> 2; } //Aggressive filter level is 75% of previous gap
if(configPage4.triggerFilter == 1) { triggerFilterTime = curGap >> 2; } //Lite filter level is 25% of previous gap
else if(configPage4.triggerFilter == 2) { triggerFilterTime = curGap >> 1; } //Medium filter level is 50% of previous gap
else if (configPage4.triggerFilter == 3) { triggerFilterTime = (curGap * 3) >> 2; } //Aggressive filter level is 75% of previous gap
else { triggerFilterTime = 0; } //trigger filter is turned off.
}
@ -89,7 +89,7 @@ It takes an argument of the full (COMPLETE) number of teeth per revolution. For
static inline int crankingGetRPM(byte totalTeeth)
{
uint16_t tempRPM = 0;
if( (currentStatus.startRevolutions >= configPage2.StgCycles) && (currentStatus.hasSync == true) )
if( (currentStatus.startRevolutions >= configPage4.StgCycles) && (currentStatus.hasSync == true) )
{
if( (toothLastToothTime > 0) && (toothLastMinusOneToothTime > 0) && (toothLastToothTime > toothLastMinusOneToothTime) )
{
@ -124,19 +124,19 @@ Note: This does not currently support dual wheel (ie missing tooth + single toot
*/
void triggerSetup_missingTooth()
{
triggerToothAngle = 360 / configPage2.triggerTeeth; //The number of degrees that passes from tooth to tooth
if(configPage2.TrigSpeed == 1) { triggerToothAngle = 720 / configPage2.triggerTeeth; } //Account for cam speed missing tooth
triggerActualTeeth = configPage2.triggerTeeth - configPage2.triggerMissingTeeth; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt
triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage2.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
triggerSecFilterTime = (int)((trigPatternSec == true) ? 1000000 * 60 / MAX_RPM / 4 / 2 : 1000000 * 60 / MAX_RPM / 2 / 2); //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed)
triggerToothAngle = 360 / configPage4.triggerTeeth; //The number of degrees that passes from tooth to tooth
if(configPage4.TrigSpeed == 1) { triggerToothAngle = 720 / configPage4.triggerTeeth; } //Account for cam speed missing tooth
triggerActualTeeth = configPage4.triggerTeeth - configPage4.triggerMissingTeeth; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt
triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage4.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
triggerSecFilterTime = (int)((configPage4.trigPatternSec == SEC_TRIGGER_4_1 ) ? 1000000 * 60 / MAX_RPM / 4 / 2 : 1000000 * 60 / MAX_RPM / 2 / 2); //For 4-1 came wheel. Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed)
secondDerivEnabled = false;
decoderIsSequential = false;
checkSyncToothCount = (configPage2.triggerTeeth) >> 1; //50% of the total teeth.
checkSyncToothCount = (configPage4.triggerTeeth) >> 1; //50% of the total teeth.
toothLastMinusOneToothTime = 0;
toothCurrentCount = 0;
toothOneTime = 0;
toothOneMinusOneTime = 0;
MAX_STALL_TIME = (3333UL * triggerToothAngle * (configPage2.triggerMissingTeeth + 1)); //Minimum 50rpm. (3333uS is the time per degree at 50rpm)
MAX_STALL_TIME = (3333UL * triggerToothAngle * (configPage4.triggerMissingTeeth + 1)); //Minimum 50rpm. (3333uS is the time per degree at 50rpm)
}
void triggerPri_missingTooth()
@ -153,7 +153,7 @@ void triggerPri_missingTooth()
{
//Begin the missing tooth detection
//If the time between the current tooth and the last is greater than 1.5x the time between the last tooth and the tooth before that, we make the assertion that we must be at the first tooth after the gap
if(configPage2.triggerMissingTeeth == 1) { targetGap = (3 * (toothLastToothTime - toothLastMinusOneToothTime)) >> 1; } //Multiply by 1.5 (Checks for a gap 1.5x greater than the last one) (Uses bitshift to multiply by 3 then divide by 2. Much faster than multiplying by 1.5)
if(configPage4.triggerMissingTeeth == 1) { targetGap = (3 * (toothLastToothTime - toothLastMinusOneToothTime)) >> 1; } //Multiply by 1.5 (Checks for a gap 1.5x greater than the last one) (Uses bitshift to multiply by 3 then divide by 2. Much faster than multiplying by 1.5)
else { targetGap = ((toothLastToothTime - toothLastMinusOneToothTime)) * 2; } //Multiply by 2 (Checks for a gap 2x greater than the last one)
if( (toothLastToothTime == 0) || (toothLastMinusOneToothTime == 0) ) { curGap = 0; }
@ -188,9 +188,9 @@ void triggerPri_missingTooth()
}
//EXPERIMENTAL!
if(configPage1.perToothIgn == true)
if(configPage2.perToothIgn == true)
{
uint16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage2.triggerAngle;
uint16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage4.triggerAngle;
doPerToothTiming(crankAngle);
}
}
@ -207,8 +207,7 @@ void triggerSec_missingTooth()
) { curGap2 = 0; }
if ( curGap2 >= triggerSecFilterTime )
{
#ifndef SMALL_FLASH_MODE
if ( trigPatternSec == true )
if ( configPage4.trigPatternSec == SEC_TRIGGER_4_1 )
{
targetGap2 = (3 * (toothLastSecToothTime - toothLastMinusOneSecToothTime)) >> 1; //If the time between the current tooth and the last is greater than 1.5x the time between the last tooth and the tooth before that, we make the assertion that we must be at the first tooth after the gap
toothLastMinusOneSecToothTime = toothLastSecToothTime;
@ -225,11 +224,10 @@ void triggerSec_missingTooth()
}
}
else
#endif
{
revolutionOne = 1; //Sequential revolution reset
}
toothLastSecToothTime = curTime2;
}
toothLastSecToothTime = curTime2;
} //Trigger filter
}
@ -240,14 +238,14 @@ uint16_t getRPM_missingTooth()
{
if(toothCurrentCount != 1)
{
if(configPage2.TrigSpeed == 1) { tempRPM = crankingGetRPM(configPage2.triggerTeeth/2); } //Account for cam speed
else { tempRPM = crankingGetRPM(configPage2.triggerTeeth); }
if(configPage4.TrigSpeed == 1) { tempRPM = crankingGetRPM(configPage4.triggerTeeth/2); } //Account for cam speed
else { tempRPM = crankingGetRPM(configPage4.triggerTeeth); }
}
else { tempRPM = currentStatus.RPM; } //Can't do per tooth RPM if we're at tooth #1 as the missing tooth messes the calculation
}
else
{
if(configPage2.TrigSpeed == 1) { tempRPM = (stdGetRPM() * 2); } //Account for cam speed
if(configPage4.TrigSpeed == 1) { tempRPM = (stdGetRPM() * 2); } //Account for cam speed
else { tempRPM = stdGetRPM(); }
}
return tempRPM;
@ -266,7 +264,7 @@ int getCrankAngle_missingTooth(int timePerDegree)
tempRevolutionOne = revolutionOne;
interrupts();
int crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage2.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
int crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage4.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
//Estimate the number of degrees travelled since the last tooth}
long elapsedTime = (micros() - tempToothLastToothTime);
//crankAngle += DIV_ROUND_CLOSEST(elapsedTime, timePerDegree);
@ -287,24 +285,24 @@ int getCrankAngle_missingTooth(int timePerDegree)
void triggerSetEndTeeth_missingTooth()
{
ignition1EndTooth = ( (ignition1EndAngle - configPage2.triggerAngle) / triggerToothAngle ) - 1;
if(ignition1EndTooth > configPage2.triggerTeeth) { ignition1EndTooth -= configPage2.triggerTeeth; }
if(ignition1EndTooth <= 0) { ignition1EndTooth -= configPage2.triggerTeeth; }
ignition1EndTooth = ( (ignition1EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1;
if(ignition1EndTooth > configPage4.triggerTeeth) { ignition1EndTooth -= configPage4.triggerTeeth; }
if(ignition1EndTooth <= 0) { ignition1EndTooth -= configPage4.triggerTeeth; }
if(ignition1EndTooth > triggerActualTeeth) { ignition1EndTooth = triggerActualTeeth; }
ignition2EndTooth = ( (ignition2EndAngle - configPage2.triggerAngle) / triggerToothAngle ) - 1;
if(ignition2EndTooth > configPage2.triggerTeeth) { ignition2EndTooth -= configPage2.triggerTeeth; }
if(ignition2EndTooth <= 0) { ignition2EndTooth -= configPage2.triggerTeeth; }
ignition2EndTooth = ( (ignition2EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1;
if(ignition2EndTooth > configPage4.triggerTeeth) { ignition2EndTooth -= configPage4.triggerTeeth; }
if(ignition2EndTooth <= 0) { ignition2EndTooth -= configPage4.triggerTeeth; }
if(ignition2EndTooth > triggerActualTeeth) { ignition2EndTooth = triggerActualTeeth; }
ignition3EndTooth = ( (ignition3EndAngle - configPage2.triggerAngle) / triggerToothAngle ) - 1;
if(ignition3EndTooth > configPage2.triggerTeeth) { ignition3EndTooth -= configPage2.triggerTeeth; }
if(ignition3EndTooth <= 0) { ignition3EndTooth -= configPage2.triggerTeeth; }
ignition3EndTooth = ( (ignition3EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1;
if(ignition3EndTooth > configPage4.triggerTeeth) { ignition3EndTooth -= configPage4.triggerTeeth; }
if(ignition3EndTooth <= 0) { ignition3EndTooth -= configPage4.triggerTeeth; }
if(ignition3EndTooth > triggerActualTeeth) { ignition3EndTooth = triggerActualTeeth; }
ignition4EndTooth = ( (ignition4EndAngle - configPage2.triggerAngle) / triggerToothAngle ) - 1;
if(ignition4EndTooth > configPage2.triggerTeeth) { ignition4EndTooth -= configPage2.triggerTeeth; }
if(ignition4EndTooth <= 0) { ignition4EndTooth -= configPage2.triggerTeeth; }
ignition4EndTooth = ( (ignition4EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1;
if(ignition4EndTooth > configPage4.triggerTeeth) { ignition4EndTooth -= configPage4.triggerTeeth; }
if(ignition4EndTooth <= 0) { ignition4EndTooth -= configPage4.triggerTeeth; }
if(ignition4EndTooth > triggerActualTeeth) { ignition4EndTooth = triggerActualTeeth; }
@ -317,10 +315,10 @@ Note: There can be no missing teeth on the primary wheel
*/
void triggerSetup_DualWheel()
{
triggerToothAngle = 360 / configPage2.triggerTeeth; //The number of degrees that passes from tooth to tooth
if(configPage2.TrigSpeed == 1) { triggerToothAngle = 720 / configPage2.triggerTeeth; } //Account for cam speed missing tooth
triggerToothAngle = 360 / configPage4.triggerTeeth; //The number of degrees that passes from tooth to tooth
if(configPage4.TrigSpeed == 1) { triggerToothAngle = 720 / configPage4.triggerTeeth; } //Account for cam speed missing tooth
toothCurrentCount = 255; //Default value
triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage2.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage4.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
triggerSecFilterTime = (int)(1000000 / (MAX_RPM / 60 * 2)) / 2; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed)
secondDerivEnabled = false;
decoderIsSequential = true;
@ -343,7 +341,7 @@ void triggerPri_DualWheel()
if ( currentStatus.hasSync == true )
{
if ( (toothCurrentCount == 1) || (toothCurrentCount > configPage2.triggerTeeth) )
if ( (toothCurrentCount == 1) || (toothCurrentCount > configPage4.triggerTeeth) )
{
toothCurrentCount = 1;
revolutionOne = !revolutionOne; //Flip sequential revolution tracker
@ -356,9 +354,9 @@ void triggerPri_DualWheel()
}
//EXPERIMENTAL!
if(configPage1.perToothIgn == true)
if(configPage2.perToothIgn == true)
{
uint16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage2.triggerAngle;
uint16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage4.triggerAngle;
doPerToothTiming(crankAngle);
}
} //TRigger filter
@ -378,12 +376,13 @@ void triggerSec_DualWheel()
if(currentStatus.hasSync == false)
{
toothLastToothTime = micros();
toothLastMinusOneToothTime = (toothOneTime - 6000000) / configPage2.triggerTeeth; //Fixes RPM at 10rpm until a full revolution has taken place
toothCurrentCount = configPage2.triggerTeeth;
//CONFIRM THE BELOW! IT DOESN'T LOOK RIGHT (toothOneTime??)
toothLastMinusOneToothTime = (toothOneTime - 6000000) / configPage4.triggerTeeth; //Fixes RPM at 10rpm until a full revolution has taken place
toothCurrentCount = configPage4.triggerTeeth;
currentStatus.hasSync = true;
}
else if (configPage2.useResync == 1) { toothCurrentCount = configPage2.triggerTeeth; }
else if (configPage4.useResync == 1) { toothCurrentCount = configPage4.triggerTeeth; }
revolutionOne = 1; //Sequential revolution reset
} //Trigger filter
@ -394,7 +393,7 @@ uint16_t getRPM_DualWheel()
uint16_t tempRPM = 0;
if( currentStatus.hasSync == true )
{
if(currentStatus.RPM < currentStatus.crankRPM) { tempRPM = crankingGetRPM(configPage2.triggerTeeth); }
if(currentStatus.RPM < currentStatus.crankRPM) { tempRPM = crankingGetRPM(configPage4.triggerTeeth); }
else { tempRPM = stdGetRPM(); }
}
return tempRPM;
@ -414,9 +413,9 @@ int getCrankAngle_DualWheel(int timePerDegree)
interrupts();
//Handle case where the secondary tooth was the last one seen
if(tempToothCurrentCount == 0) { tempToothCurrentCount = configPage2.triggerTeeth; }
if(tempToothCurrentCount == 0) { tempToothCurrentCount = configPage4.triggerTeeth; }
int crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage2.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
int crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage4.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
//Estimate the number of degrees travelled since the last tooth}
long elapsedTime = micros() - tempToothLastToothTime;
if(elapsedTime < SHRT_MAX ) { crankAngle += div((int)elapsedTime, timePerDegree).quot; } //This option is much faster, but only available for smaller values of elapsedTime
@ -434,24 +433,24 @@ int getCrankAngle_DualWheel(int timePerDegree)
void triggerSetEndTeeth_DualWheel()
{
ignition1EndTooth = ( (ignition1EndAngle - configPage2.triggerAngle) / triggerToothAngle ) - 1;
if(ignition1EndTooth > configPage2.triggerTeeth) { ignition1EndTooth -= configPage2.triggerTeeth; }
if(ignition1EndTooth <= 0) { ignition1EndTooth -= configPage2.triggerTeeth; }
ignition1EndTooth = ( (ignition1EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1;
if(ignition1EndTooth > configPage4.triggerTeeth) { ignition1EndTooth -= configPage4.triggerTeeth; }
if(ignition1EndTooth <= 0) { ignition1EndTooth -= configPage4.triggerTeeth; }
if(ignition1EndTooth > triggerActualTeeth) { ignition1EndTooth = triggerActualTeeth; }
ignition2EndTooth = ( (ignition2EndAngle - configPage2.triggerAngle) / triggerToothAngle ) - 1;
if(ignition2EndTooth > configPage2.triggerTeeth) { ignition2EndTooth -= configPage2.triggerTeeth; }
if(ignition2EndTooth <= 0) { ignition2EndTooth -= configPage2.triggerTeeth; }
ignition2EndTooth = ( (ignition2EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1;
if(ignition2EndTooth > configPage4.triggerTeeth) { ignition2EndTooth -= configPage4.triggerTeeth; }
if(ignition2EndTooth <= 0) { ignition2EndTooth -= configPage4.triggerTeeth; }
if(ignition2EndTooth > triggerActualTeeth) { ignition2EndTooth = triggerActualTeeth; }
ignition3EndTooth = ( (ignition3EndAngle - configPage2.triggerAngle) / triggerToothAngle ) - 1;
if(ignition3EndTooth > configPage2.triggerTeeth) { ignition3EndTooth -= configPage2.triggerTeeth; }
if(ignition3EndTooth <= 0) { ignition3EndTooth -= configPage2.triggerTeeth; }
ignition3EndTooth = ( (ignition3EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1;
if(ignition3EndTooth > configPage4.triggerTeeth) { ignition3EndTooth -= configPage4.triggerTeeth; }
if(ignition3EndTooth <= 0) { ignition3EndTooth -= configPage4.triggerTeeth; }
if(ignition3EndTooth > triggerActualTeeth) { ignition3EndTooth = triggerActualTeeth; }
ignition4EndTooth = ( (ignition4EndAngle - configPage2.triggerAngle) / triggerToothAngle ) - 1;
if(ignition4EndTooth > configPage2.triggerTeeth) { ignition4EndTooth -= configPage2.triggerTeeth; }
if(ignition4EndTooth <= 0) { ignition4EndTooth -= configPage2.triggerTeeth; }
ignition4EndTooth = ( (ignition4EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1;
if(ignition4EndTooth > configPage4.triggerTeeth) { ignition4EndTooth -= configPage4.triggerTeeth; }
if(ignition4EndTooth <= 0) { ignition4EndTooth -= configPage4.triggerTeeth; }
if(ignition4EndTooth > triggerActualTeeth) { ignition4EndTooth = triggerActualTeeth; }
}
@ -463,10 +462,10 @@ Note: This is a very simple decoder. See http://www.megamanual.com/ms2/GM_7pinHE
*/
void triggerSetup_BasicDistributor()
{
triggerActualTeeth = configPage1.nCylinders;
triggerActualTeeth = configPage2.nCylinders;
if(triggerActualTeeth == 0) { triggerActualTeeth = 1; }
triggerToothAngle = 720 / triggerActualTeeth; //The number of degrees that passes from tooth to tooth
triggerFilterTime = 60000000L / MAX_RPM / configPage1.nCylinders; // Minimum time required between teeth
triggerFilterTime = 60000000L / MAX_RPM / configPage2.nCylinders; // Minimum time required between teeth
triggerFilterTime = triggerFilterTime / 2; //Safety margin
triggerFilterTime = 0;
secondDerivEnabled = false;
@ -474,7 +473,7 @@ void triggerSetup_BasicDistributor()
toothCurrentCount = 0; //Default value
decoderHasFixedCrankingTiming = true;
triggerToothAngleIsCorrect = true;
if(configPage1.nCylinders <= 4) { MAX_STALL_TIME = (1851UL * triggerToothAngle); }//Minimum 90rpm. (1851uS is the time per degree at 90rpm). This uses 90rpm rather than 50rpm due to the potentially very high stall time on a 4 cylinder if we wait that long.
if(configPage2.nCylinders <= 4) { MAX_STALL_TIME = (1851UL * triggerToothAngle); }//Minimum 90rpm. (1851uS is the time per degree at 90rpm). This uses 90rpm rather than 50rpm due to the potentially very high stall time on a 4 cylinder if we wait that long.
else { MAX_STALL_TIME = (3200UL * triggerToothAngle); } //Minimum 50rpm. (3200uS is the time per degree at 50rpm).
}
@ -501,7 +500,7 @@ void triggerPri_BasicDistributor()
setFilter(curGap); //Recalc the new filter value
addToothLogEntry(curGap);
if ( configPage2.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
if ( configPage4.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
{
endCoil1Charge();
endCoil2Charge();
@ -509,9 +508,9 @@ void triggerPri_BasicDistributor()
endCoil4Charge();
}
if(configPage1.perToothIgn == true)
if(configPage2.perToothIgn == true)
{
uint16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage2.triggerAngle;
uint16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage4.triggerAngle;
if ( (toothCurrentCount == ignition1EndTooth) && (ignitionSchedule1.Status == RUNNING) )
{
IGN1_COMPARE = IGN1_COUNTER + uS_TO_TIMER_COMPARE( (ignition1EndAngle - crankAngle) * timePerDegree );
@ -554,7 +553,7 @@ int getCrankAngle_BasicDistributor(int timePerDegree)
tempToothLastToothTime = toothLastToothTime;
interrupts();
int crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage2.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
int crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage4.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
//Estimate the number of degrees travelled since the last tooth}
long elapsedTime = micros() - tempToothLastToothTime;
if(elapsedTime < SHRT_MAX ) { crankAngle += div((int)elapsedTime, timePerDegree).quot; } //This option is much faster, but only available for smaller values of elapsedTime
@ -569,9 +568,9 @@ int getCrankAngle_BasicDistributor(int timePerDegree)
void triggerSetEndTeeth_BasicDistributor()
{
ignition1EndTooth = ( (ignition1EndAngle - configPage2.triggerAngle) / triggerToothAngle ) - 1;
if(ignition1EndTooth > configPage2.triggerTeeth) { ignition1EndTooth -= configPage2.triggerTeeth; }
if(ignition1EndTooth <= 0) { ignition1EndTooth -= configPage2.triggerTeeth; }
ignition1EndTooth = ( (ignition1EndAngle - configPage4.triggerAngle) / triggerToothAngle ) - 1;
if(ignition1EndTooth > configPage4.triggerTeeth) { ignition1EndTooth -= configPage4.triggerTeeth; }
if(ignition1EndTooth <= 0) { ignition1EndTooth -= configPage4.triggerTeeth; }
if(ignition1EndTooth > triggerActualTeeth) { ignition1EndTooth = triggerActualTeeth; }
}
@ -692,7 +691,7 @@ void triggerSetup_4G63()
//decoderIsLowRes = true;
//Note that these angles are for every rising and falling edge
if(configPage1.nCylinders == 6)
if(configPage2.nCylinders == 6)
{
// 70 / 50 for 6 cylinder applications
toothAngles[0] = 185; //
@ -766,15 +765,15 @@ void triggerPri_4G63()
if (currentStatus.hasSync == true)
{
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && configPage2.ignCranklock && (currentStatus.startRevolutions >= configPage2.StgCycles))
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && configPage4.ignCranklock && (currentStatus.startRevolutions >= configPage4.StgCycles))
{
if(configPage1.nCylinders == 4)
if(configPage2.nCylinders == 4)
{
//This operates in forced wasted spark mode during cranking to align with crank teeth
if( (toothCurrentCount == 1) || (toothCurrentCount == 5) ) { endCoil1Charge(); endCoil3Charge(); }
else if( (toothCurrentCount == 3) || (toothCurrentCount == 7) ) { endCoil2Charge(); endCoil4Charge(); }
}
else if(configPage1.nCylinders == 6)
else if(configPage2.nCylinders == 6)
{
if( toothCurrentCount == 1 ) { endCoil1Charge(); }
else if( toothCurrentCount == 3 ) { endCoil2Charge(); }
@ -783,14 +782,14 @@ void triggerPri_4G63()
}
//Whilst this is an uneven tooth pattern, if the specific angle between the last 2 teeth is specified, 1st deriv prediction can be used
if( (configPage2.triggerFilter == 1) || (currentStatus.RPM < 1400) )
if( (configPage4.triggerFilter == 1) || (currentStatus.RPM < 1400) )
{
//Lite filter
if( (toothCurrentCount == 1) || (toothCurrentCount == 3) || (toothCurrentCount == 5) || (toothCurrentCount == 7) )
{
triggerToothAngle = 70;
triggerFilterTime = curGap; //Trigger filter is set to whatever time it took to do 70 degrees (Next trigger is 110 degrees away)
if(configPage1.nCylinders == 6)
if(configPage2.nCylinders == 6)
{
triggerFilterTime = (curGap >> 2); //Trigger filter is set to (70/4)=17.5=17 degrees (Next trigger is 50 degrees away).
}
@ -799,20 +798,20 @@ void triggerPri_4G63()
{
triggerToothAngle = 110;
triggerFilterTime = (curGap * 3) >> 3; //Trigger filter is set to (110*3)/8=41.25=41 degrees (Next trigger is 70 degrees away).
if(configPage1.nCylinders == 6)
if(configPage2.nCylinders == 6)
{
triggerToothAngle = 50;
triggerFilterTime = (curGap * 3) >> 2; //Trigger filter is set to (50*3)/4=37.5=37 degrees (Next trigger is 70 degrees away).
}
}
}
else if(configPage2.triggerFilter == 2)
else if(configPage4.triggerFilter == 2)
{
//Medium filter level
if( (toothCurrentCount == 1) || (toothCurrentCount == 3) || (toothCurrentCount == 5) || (toothCurrentCount == 7) ) { triggerToothAngle = 70; triggerFilterTime = (curGap * 5) >> 2 ; } //87.5 degrees with a target of 110
else { triggerToothAngle = 110; triggerFilterTime = (curGap >> 1); } //55 degrees with a target of 70
}
else if (configPage2.triggerFilter == 3)
else if (configPage4.triggerFilter == 3)
{
//Aggressive filter level
if( (toothCurrentCount == 1) || (toothCurrentCount == 3) || (toothCurrentCount == 5) || (toothCurrentCount == 7) ) { triggerToothAngle = 70; triggerFilterTime = (curGap * 11) >> 3 ; } //96.26 degrees with a target of 110
@ -827,7 +826,7 @@ void triggerPri_4G63()
}
//EXPERIMENTAL!
if(configPage1.perToothIgn == true)
if(configPage2.perToothIgn == true)
{
uint16_t crankAngle = toothAngles[(toothCurrentCount-1)];
doPerToothTiming(crankAngle);
@ -895,7 +894,7 @@ void triggerSec_4G63()
}
//if ( (micros() - secondaryLastToothTime1) < triggerSecFilterTime_duration && configPage2.useResync )
if ( (configPage2.useResync == 1) && (currentStatus.hasSync == true) )
if ( (configPage4.useResync == 1) && (currentStatus.hasSync == true) )
{
triggerSecFilterTime_duration = (micros() - secondaryLastToothTime1) >> 1;
if(READ_PRI_TRIGGER() == true)// && (crankState == digitalRead(pinTrigger)))
@ -921,7 +920,7 @@ uint16_t getRPM_4G63()
//Because these signals aren't even (Alternating 110 and 70 degrees), this needs a special function
if(currentStatus.hasSync == true)
{
if( (currentStatus.RPM < currentStatus.crankRPM) || (configPage1.perToothIgn == true) )
if( (currentStatus.RPM < currentStatus.crankRPM) || (configPage2.perToothIgn == true) )
{
int tempToothAngle;
unsigned long toothTime;
@ -966,7 +965,7 @@ int getCrankAngle_4G63(int timePerDegree)
tempToothLastMinusOneToothTime = toothLastMinusOneToothTime;
interrupts();
crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage2.triggerAngle; //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage4.triggerAngle; //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
//Estimate the number of degrees travelled since the last tooth}
unsigned long elapsedTime = micros() - tempToothLastToothTime;
@ -984,10 +983,10 @@ int getCrankAngle_4G63(int timePerDegree)
void triggerSetEndTeeth_4G63()
{
if((ignition1EndAngle - configPage2.triggerAngle) > 355) { ignition1EndTooth = 1; }
if((ignition1EndAngle - configPage4.triggerAngle) > 355) { ignition1EndTooth = 1; }
else { ignition1EndTooth = 4; }
//ignition1EndTooth = 1;
//ignition1EndTooth = ( (ignition1EndAngle - configPage2.triggerAngle) /
//ignition1EndTooth = ( (ignition1EndAngle - configPage4.triggerAngle) /
}
/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -1080,8 +1079,8 @@ int getCrankAngle_24X(int timePerDegree)
interrupts();
int crankAngle;
if (toothCurrentCount == 0) { crankAngle = 0 + configPage2.triggerAngle; } //This is the special case to handle when the 'last tooth' seen was the cam tooth. 0 is the angle at which the crank tooth goes high (Within 360 degrees).
else { crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage2.triggerAngle;} //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
if (toothCurrentCount == 0) { crankAngle = 0 + configPage4.triggerAngle; } //This is the special case to handle when the 'last tooth' seen was the cam tooth. 0 is the angle at which the crank tooth goes high (Within 360 degrees).
else { crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage4.triggerAngle;} //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
//Estimate the number of degrees travelled since the last tooth}
long elapsedTime = micros() - tempToothLastToothTime;
@ -1182,8 +1181,8 @@ int getCrankAngle_Jeep2000(int timePerDegree)
interrupts();
int crankAngle;
if (toothCurrentCount == 0) { crankAngle = 146 + configPage2.triggerAngle; } //This is the special case to handle when the 'last tooth' seen was the cam tooth. 146 is the angle at which the crank tooth goes high.
else { crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage2.triggerAngle;} //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
if (toothCurrentCount == 0) { crankAngle = 146 + configPage4.triggerAngle; } //This is the special case to handle when the 'last tooth' seen was the cam tooth. 146 is the angle at which the crank tooth goes high.
else { crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage4.triggerAngle;} //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
//Estimate the number of degrees travelled since the last tooth}
long elapsedTime = micros() - tempToothLastToothTime;
if(elapsedTime < SHRT_MAX ) { crankAngle += div((int)elapsedTime, timePerDegree).quot; } //This option is much faster, but only available for smaller values of elapsedTime
@ -1272,7 +1271,7 @@ void triggerSec_Audi135()
currentStatus.hasSync = true;
toothSystemCount = 3; //Need to set this to 3 so that the next primary tooth is counted
}
else if (configPage2.useResync == 1) { toothCurrentCount = 0; toothSystemCount = 3; }
else if (configPage4.useResync == 1) { toothCurrentCount = 0; toothSystemCount = 3; }
else if ( (currentStatus.startRevolutions < 100) && (toothCurrentCount != 45) ) { toothCurrentCount = 0; }
revolutionOne = 1; //Sequential revolution reset
}
@ -1298,7 +1297,7 @@ int getCrankAngle_Audi135(int timePerDegree)
//Handle case where the secondary tooth was the last one seen
if(tempToothCurrentCount == 0) { tempToothCurrentCount = 45; }
int crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage2.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
int crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage4.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
//Estimate the number of degrees travelled since the last tooth}
long elapsedTime = micros() - tempToothLastToothTime;
if(elapsedTime < SHRT_MAX ) { crankAngle += div((int)elapsedTime, timePerDegree).quot; } //This option is much faster, but only available for smaller values of elapsedTime
@ -1393,11 +1392,11 @@ int getCrankAngle_HondaD17(int timePerDegree)
int crankAngle;
if( tempToothCurrentCount == 0 )
{
crankAngle = (11 * triggerToothAngle) + configPage2.triggerAngle; //if temptoothCurrentCount is 0, the last tooth seen was the 13th one. Based on this, ignore the 13th tooth and use the 12th one as the last reference.
crankAngle = (11 * triggerToothAngle) + configPage4.triggerAngle; //if temptoothCurrentCount is 0, the last tooth seen was the 13th one. Based on this, ignore the 13th tooth and use the 12th one as the last reference.
}
else
{
crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage2.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
crankAngle = ((tempToothCurrentCount - 1) * triggerToothAngle) + configPage4.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
}
//Estimate the number of degrees travelled since the last tooth}
@ -1478,7 +1477,7 @@ void triggerPri_Miata9905()
}
else
{
if( (currentStatus.hasSync == false) || (configPage2.useResync == true) )
if( (currentStatus.hasSync == false) || (configPage4.useResync == true) )
{
if(secondaryToothCount == 2)
{
@ -1493,25 +1492,25 @@ void triggerPri_Miata9905()
addToothLogEntry(curGap);
//Whilst this is an uneven tooth pattern, if the specific angle between the last 2 teeth is specified, 1st deriv prediction can be used
if( (configPage2.triggerFilter == 1) )
if( (configPage4.triggerFilter == 1) )
{
//Lite filter
if( (toothCurrentCount == 1) || (toothCurrentCount == 3) || (toothCurrentCount == 5) || (toothCurrentCount == 7) ) { triggerToothAngle = 70; triggerFilterTime = curGap; } //Trigger filter is set to whatever time it took to do 70 degrees (Next trigger is 110 degrees away)
else { triggerToothAngle = 110; triggerFilterTime = (curGap * 3) >> 3; } //Trigger filter is set to (110*3)/8=41.25=41 degrees (Next trigger is 70 degrees away).
}
else if(configPage2.triggerFilter == 2)
else if(configPage4.triggerFilter == 2)
{
//Medium filter level
if( (toothCurrentCount == 1) || (toothCurrentCount == 3) || (toothCurrentCount == 5) || (toothCurrentCount == 7) ) { triggerToothAngle = 70; triggerFilterTime = (curGap * 5) >> 2 ; } //87.5 degrees with a target of 110
else { triggerToothAngle = 110; triggerFilterTime = (curGap >> 1); } //55 degrees with a target of 70
}
else if (configPage2.triggerFilter == 3)
else if (configPage4.triggerFilter == 3)
{
//Aggressive filter level
if( (toothCurrentCount == 1) || (toothCurrentCount == 3) || (toothCurrentCount == 5) || (toothCurrentCount == 7) ) { triggerToothAngle = 70; triggerFilterTime = (curGap * 11) >> 3 ; } //96.26 degrees with a target of 110
else { triggerToothAngle = 110; triggerFilterTime = (curGap * 9) >> 5; } //61.87 degrees with a target of 70
}
else if (configPage2.triggerFilter == 0)
else if (configPage4.triggerFilter == 0)
{
//trigger filter is turned off.
triggerFilterTime = 0;
@ -1525,7 +1524,7 @@ void triggerPri_Miata9905()
toothLastMinusOneToothTime = toothLastToothTime;
toothLastToothTime = curTime;
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && configPage2.ignCranklock)
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && configPage4.ignCranklock)
{
//This operates in waasted spark mode during cranking to align with crank teeth
if( (toothCurrentCount == 1) || (toothCurrentCount == 5) ) { endCoil1Charge(); endCoil3Charge(); }
@ -1602,7 +1601,7 @@ int getCrankAngle_Miata9905(int timePerDegree)
tempToothLastToothTime = toothLastToothTime;
interrupts();
crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage2.triggerAngle; //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage4.triggerAngle; //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
//Estimate the number of degrees travelled since the last tooth}
unsigned long elapsedTime = micros() - tempToothLastToothTime;
@ -1668,7 +1667,7 @@ void triggerPri_MazdaAU()
if (currentStatus.hasSync == true)
{
// Locked cranking timing is available, fixed at 12* BTDC
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && configPage2.ignCranklock )
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && configPage4.ignCranklock )
{
if( toothCurrentCount == 1 ) { endCoil1Charge(); }
else if( toothCurrentCount == 3 ) { endCoil2Charge(); }
@ -1755,7 +1754,7 @@ int getCrankAngle_MazdaAU(int timePerDegree)
tempToothLastToothTime = toothLastToothTime;
interrupts();
crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage2.triggerAngle; //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage4.triggerAngle; //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
//Estimate the number of degrees travelled since the last tooth}
long elapsedTime = micros() - tempToothLastToothTime;
@ -1782,9 +1781,9 @@ Note: There can be no missing teeth on the primary wheel
*/
void triggerSetup_non360()
{
triggerToothAngle = (360 * configPage2.TrigAngMul) / configPage2.triggerTeeth; //The number of degrees that passes from tooth to tooth multiplied by the additional multiplier
triggerToothAngle = (360 * configPage4.TrigAngMul) / configPage4.triggerTeeth; //The number of degrees that passes from tooth to tooth multiplied by the additional multiplier
toothCurrentCount = 255; //Default value
triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage2.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage4.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
triggerSecFilterTime = (int)(1000000 / (MAX_RPM / 60 * 2)) / 2; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed)
secondDerivEnabled = false;
decoderIsSequential = true;
@ -1807,7 +1806,7 @@ uint16_t getRPM_non360()
uint16_t tempRPM = 0;
if( (currentStatus.hasSync == true) && (toothCurrentCount != 0) )
{
if(currentStatus.RPM < currentStatus.crankRPM) { tempRPM = crankingGetRPM(configPage2.triggerTeeth); }
if(currentStatus.RPM < currentStatus.crankRPM) { tempRPM = crankingGetRPM(configPage4.triggerTeeth); }
else { tempRPM = stdGetRPM(); }
}
return tempRPM;
@ -1825,11 +1824,11 @@ int getCrankAngle_non360(int timePerDegree)
interrupts();
//Handle case where the secondary tooth was the last one seen
if(tempToothCurrentCount == 0) { tempToothCurrentCount = configPage2.triggerTeeth; }
if(tempToothCurrentCount == 0) { tempToothCurrentCount = configPage4.triggerTeeth; }
//Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
int crankAngle = (tempToothCurrentCount - 1) * triggerToothAngle;
crankAngle = (crankAngle / configPage2.TrigAngMul) + configPage2.triggerAngle; //Have to divide by the multiplier to get back to actual crank angle.
crankAngle = (crankAngle / configPage4.TrigAngMul) + configPage4.triggerAngle; //Have to divide by the multiplier to get back to actual crank angle.
//Estimate the number of degrees travelled since the last tooth}
long elapsedTime = micros() - tempToothLastToothTime;
@ -1890,9 +1889,9 @@ void triggerPri_Nissan360()
//setFilter(curGap);
//EXPERIMENTAL!
if(configPage1.perToothIgn == true)
if(configPage2.perToothIgn == true)
{
int16_t crankAngle = ( (toothCurrentCount-1) * 2 ) + configPage2.triggerAngle;
int16_t crankAngle = ( (toothCurrentCount-1) * 2 ) + configPage4.triggerAngle;
//if(crankAngle > CRANK_ANGLE_MAX_IGN) { crankAngle -= CRANK_ANGLE_MAX_IGN; }
//if(crankAngle < CRANK_ANGLE_MAX_IGN) {
doPerToothTiming(crankAngle);
@ -1914,7 +1913,7 @@ void triggerSec_Nissan360()
//Calculate number of primary teeth that this window has been active for
byte trigEdge;
if(configPage2.TrigEdgeSec == 0) { trigEdge = LOW; }
if(configPage4.TrigEdgeSec == 0) { trigEdge = LOW; }
else { trigEdge = HIGH; }
if( (secondaryToothCount == 0) || (READ_SEC_TRIGGER() == trigEdge) ) { secondaryToothCount = toothCurrentCount; } //This occurs on the first rotation upon powerup OR the start of a secondary window
@ -1925,7 +1924,7 @@ void triggerSec_Nissan360()
if(currentStatus.hasSync == false)
{
if(configPage1.nCylinders == 4)
if(configPage2.nCylinders == 4)
{
if( (secondaryDuration >= 15) && (secondaryDuration <= 17) ) //Duration of window = 16 primary teeth
{
@ -1949,7 +1948,7 @@ void triggerSec_Nissan360()
}
else { currentStatus.hasSync = false; } //This should really never happen
}
else if(configPage1.nCylinders == 6)
else if(configPage2.nCylinders == 6)
{
//Pattern on the 6 cylinders is 4-8-12-16-12-8
//We can therefore only get sync on the 4 and 16 pulses as they are the only unique ones
@ -1968,17 +1967,17 @@ void triggerSec_Nissan360()
}
else
{
if (configPage2.useResync == true)
if (configPage4.useResync == true)
{
//Already have sync, but do a verify every 720 degrees.
if(configPage1.nCylinders == 4)
if(configPage2.nCylinders == 4)
{
if( (secondaryDuration >= 15) && (secondaryDuration <= 17) ) //Duration of window = 16 primary teeth
{
toothCurrentCount = 16; //End of first window (The longest) occurs 16 teeth after TDC
}
}
else if(configPage1.nCylinders == 6)
else if(configPage2.nCylinders == 6)
{
if(secondaryDuration == 4)
{
@ -2031,7 +2030,7 @@ int getCrankAngle_Nissan360(int timePerDegree)
tempToothCurrentCount = toothCurrentCount;
interrupts();
crankAngle = ( (tempToothCurrentCount - 1) * 2) + configPage2.triggerAngle;
crankAngle = ( (tempToothCurrentCount - 1) * 2) + configPage4.triggerAngle;
unsigned long halfTooth = (tempToothLastToothTime - tempToothLastMinusOneToothTime) >> 1;
if ( (micros() - tempToothLastToothTime) > halfTooth)
{
@ -2049,10 +2048,10 @@ int getCrankAngle_Nissan360(int timePerDegree)
void triggerSetEndTeeth_Nissan360()
{
//This uses 4 prior teeth, just to ensure there is sufficient time to set the schedule etc
ignition1EndTooth = ( (ignition1EndAngle - configPage2.triggerAngle) / 2 ) - 4;
ignition2EndTooth = ( (ignition2EndAngle - configPage2.triggerAngle) / 2 ) - 4;
ignition3EndTooth = ( (ignition3EndAngle - configPage2.triggerAngle) / 2 ) - 4;
ignition4EndTooth = ( (ignition4EndAngle - configPage2.triggerAngle) / 2 ) - 4;
ignition1EndTooth = ( (ignition1EndAngle - configPage4.triggerAngle) / 2 ) - 4;
ignition2EndTooth = ( (ignition2EndAngle - configPage4.triggerAngle) / 2 ) - 4;
ignition3EndTooth = ( (ignition3EndAngle - configPage4.triggerAngle) / 2 ) - 4;
ignition4EndTooth = ( (ignition4EndAngle - configPage4.triggerAngle) / 2 ) - 4;
}
/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -2097,7 +2096,7 @@ void triggerPri_Subaru67()
toothLastMinusOneToothTime = toothLastToothTime;
toothLastToothTime = curTime;
if ( (currentStatus.hasSync == false) || configPage2.useResync || (currentStatus.startRevolutions == 0) )
if ( (currentStatus.hasSync == false) || configPage4.useResync || (currentStatus.startRevolutions == 0) )
{
//Sync is determined by counting the number of cam teeth that have passed between the crank teeth
switch(secondaryToothCount)
@ -2136,7 +2135,7 @@ void triggerPri_Subaru67()
if ( currentStatus.hasSync == true )
{
//Locked timing during cranking. This is fixed at 10* BTDC.
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && configPage2.ignCranklock)
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && configPage4.ignCranklock)
{
if( (toothCurrentCount == 1) || (toothCurrentCount == 7) ) { endCoil1Charge(); endCoil3Charge(); }
else if( (toothCurrentCount == 4) || (toothCurrentCount == 10) ) { endCoil2Charge(); endCoil4Charge(); }
@ -2153,7 +2152,7 @@ void triggerPri_Subaru67()
//Recalc the new filter value
//setFilter(curGap);
}
}
void triggerSec_Subaru67()
{
@ -2168,7 +2167,7 @@ void triggerSec_Subaru67()
uint16_t getRPM_Subaru67()
{
//if(currentStatus.RPM < currentStatus.crankRPM) { return crankingGetRPM(configPage2.triggerTeeth); }
//if(currentStatus.RPM < currentStatus.crankRPM) { return crankingGetRPM(configPage4.triggerTeeth); }
uint16_t tempRPM = 0;
if(currentStatus.startRevolutions > 0)
@ -2194,7 +2193,7 @@ int getCrankAngle_Subaru67(int timePerDegree)
tempToothLastToothTime = toothLastToothTime;
interrupts();
crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage2.triggerAngle; //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
crankAngle = toothAngles[(tempToothCurrentCount - 1)] + configPage4.triggerAngle; //Perform a lookup of the fixed toothAngles array to find what the angle of the last tooth passed was.
//Estimate the number of degrees travelled since the last tooth}
unsigned long elapsedTime = micros() - tempToothLastToothTime;
@ -2221,16 +2220,16 @@ Note: This is a very simple decoder. See http://www.megamanual.com/ms2/GM_7pinHE
*/
void triggerSetup_Daihatsu()
{
triggerActualTeeth = configPage1.nCylinders + 1;
triggerActualTeeth = configPage2.nCylinders + 1;
triggerToothAngle = 720 / triggerActualTeeth; //The number of degrees that passes from tooth to tooth
triggerFilterTime = 60000000L / MAX_RPM / configPage1.nCylinders; // Minimum time required between teeth
triggerFilterTime = 60000000L / MAX_RPM / configPage2.nCylinders; // Minimum time required between teeth
triggerFilterTime = triggerFilterTime / 2; //Safety margin
secondDerivEnabled = false;
decoderIsSequential = false;
MAX_STALL_TIME = (1851UL * triggerToothAngle)*4;//Minimum 90rpm. (1851uS is the time per degree at 90rpm). This uses 90rpm rather than 50rpm due to the potentially very high stall time on a 4 cylinder if we wait that long.
if(configPage1.nCylinders == 3)
if(configPage2.nCylinders == 3)
{
toothAngles[0] = 0; //tooth #1
toothAngles[1] = 30; //tooth #2 (Extra tooth)
@ -2278,7 +2277,7 @@ void triggerPri_Daihatsu()
//addToothLogEntry(curGap);
if ( configPage2.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
if ( configPage4.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
{
//This locks the cranking timing to 0 degrees BTDC (All the triggers allow for)
if(toothCurrentCount == 1) { endCoil1Charge(); }
@ -2295,7 +2294,7 @@ void triggerPri_Daihatsu()
unsigned long targetTime;
//We need to try and find the extra tooth (#2) which is located 30 degrees after tooth #1
//Aim for tooth times less than about 60 degrees
if(configPage1.nCylinders == 3)
if(configPage2.nCylinders == 3)
{
targetTime = (toothLastToothTime - toothLastMinusOneToothTime) >> 2; //Teeth are 240 degrees apart for 3 cylinder. 240/3 = 60
}
@ -2358,7 +2357,7 @@ int getCrankAngle_Daihatsu(int timePerDegree)
tempToothLastToothTime = toothLastToothTime;
interrupts();
crankAngle = toothAngles[tempToothCurrentCount-1] + configPage2.triggerAngle; //Crank angle of the last tooth seen
crankAngle = toothAngles[tempToothCurrentCount-1] + configPage4.triggerAngle; //Crank angle of the last tooth seen
//Estimate the number of degrees travelled since the last tooth}
long elapsedTime = micros() - tempToothLastToothTime;
if(elapsedTime < SHRT_MAX ) { crankAngle += div((int)elapsedTime, timePerDegree).quot; } //This option is much faster, but only available for smaller values of elapsedTime
@ -2447,7 +2446,7 @@ uint16_t getRPM_Harley()
uint16_t tempRPM = 0;
if (currentStatus.hasSync == true)
{
if ( currentStatus.RPM < (unsigned int)(configPage2.crankRPM * 100) )
if ( currentStatus.RPM < (unsigned int)(configPage4.crankRPM * 100) )
{
// Kein Unterschied mit dieser Option
int tempToothAngle;
@ -2491,10 +2490,10 @@ int getCrankAngle_Harley(int timePerDegree)
int crankAngle;
if ( (tempToothCurrentCount == 1) || (tempToothCurrentCount == 3) )
{
crankAngle = 0 + configPage2.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
crankAngle = 0 + configPage4.triggerAngle; //Number of teeth that have passed since tooth 1, multiplied by the angle each tooth represents, plus the angle that tooth 1 is ATDC. This gives accuracy only to the nearest tooth.
}
else {
crankAngle = 157 + configPage2.triggerAngle;
crankAngle = 157 + configPage4.triggerAngle;
}
//Estimate the number of degrees travelled since the last tooth}
@ -2527,10 +2526,10 @@ void triggerSetup_ThirtySixMinus222()
{
triggerToothAngle = 10; //The number of degrees that passes from tooth to tooth
triggerActualTeeth = 30; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt
triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage2.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage4.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
secondDerivEnabled = false;
decoderIsSequential = false;
checkSyncToothCount = (configPage2.triggerTeeth) >> 1; //50% of the total teeth.
checkSyncToothCount = (configPage4.triggerTeeth) >> 1; //50% of the total teeth.
toothLastMinusOneToothTime = 0;
toothCurrentCount = 0;
toothOneTime = 0;
@ -2607,9 +2606,9 @@ void triggerPri_ThirtySixMinus222()
toothLastToothTime = curTime;
//EXPERIMENTAL!
if(configPage1.perToothIgn == true)
if(configPage2.perToothIgn == true)
{
uint16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage2.triggerAngle;
uint16_t crankAngle = ( (toothCurrentCount-1) * triggerToothAngle ) + configPage4.triggerAngle;
doPerToothTiming(crankAngle);
}

View File

@ -3,6 +3,10 @@
#include <Arduino.h>
#include "table.h"
//These are configuration options for changing around the outputs that are used
#define INJ_CHANNELS 4
#define IGN_CHANNELS 5
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
#define BOARD_DIGITAL_GPIO_PINS 54
#define BOARD_NR_GPIO_PINS 62
@ -13,8 +17,10 @@
#define BOARD_NR_GPIO_PINS 34
#elif defined(STM32_MCU_SERIES) || defined(ARDUINO_ARCH_STM32) || defined(__STM32F1__) || defined(STM32F4) || defined(STM32)
#define CORE_STM32
#define word(h, l) ((h << 8) | l) //word() function not defined for this platform in the main library
#if defined (STM32F1) || defined(__STM32F1__)
#define BOARD_DIGITAL_GPIO_PINS 34
#undef BOARD_NR_GPIO_PINS //This is declared as 49 in .../framework-arduinoststm32/STM32F1/variants/generic_stm32f103r8/board/board.h
#define BOARD_NR_GPIO_PINS 34
#ifndef LED_BUILTIN
#define LED_BUILTIN PB1 //Maple Mini
@ -36,8 +42,11 @@
#define portOutputRegister(port) (volatile byte *)( &(port->ODR) )
#define portInputRegister(port) (volatile byte *)( &(port->IDR) )
#else //libmaple core aka STM32DUINO
#define portOutputRegister(port) (volatile byte *)( &(port->regs->ODR) ) //These are defined in STM32F1/variants/generic_stm32f103c/variant.h but return a non byte* value
#define portInputRegister(port) (volatile byte *)( &(port->regs->IDR) ) //These are defined in STM32F1/variants/generic_stm32f103c/variant.h but return a non byte* value
//These are defined in STM32F1/variants/generic_stm32f103c/variant.h but return a non byte* value
#undef portOutputRegister
#undef portInputRegister
#define portOutputRegister(port) (volatile byte *)( &(port->regs->ODR) )
#define portInputRegister(port) (volatile byte *)( &(port->regs->IDR) )
#endif
#else
#error Incorrect board selected. Please select the correct board (Usually Mega 2560) and upload again
@ -100,6 +109,14 @@
#define BIT_TIMER_15HZ 3
#define BIT_TIMER_30HZ 4
#define BIT_STATUS3_RESET_PREVENT 0 //Indicates whether reset prevention is enabled
#define BIT_STATUS3_UNUSED2 1
#define BIT_STATUS3_UNUSED3 2
#define BIT_STATUS3_UNUSED4 3
#define BIT_STATUS3_UNUSED5 4
#define BIT_STATUS3_UNUSED6 5
#define BIT_STATUS3_UNUSED7 6
#define VALID_MAP_MAX 1022 //The largest ADC value that is valid for the MAP sensor
#define VALID_MAP_MIN 2 //The smallest ADC value that is valid for the MAP sensor
@ -117,6 +134,9 @@
#define IGN_MODE_SEQUENTIAL 3
#define IGN_MODE_ROTARY 4
#define SEC_TRIGGER_SINGLE 0
#define SEC_TRIGGER_4_1 1
#define ROTARY_IGN_FC 0
#define ROTARY_IGN_FD 1
#define ROTARY_IGN_RX8 2
@ -139,6 +159,11 @@
#define STAGING_MODE_TABLE 0
#define STAGING_MODE_AUTO 1
#define RESET_CONTROL_DISABLED 0
#define RESET_CONTROL_PREVENT_WHEN_RUNNING 1
#define RESET_CONTROL_PREVENT_ALWAYS 2
#define RESET_CONTROL_SERIAL_COMMAND 3
#define MAX_RPM 18000 //This is the maximum rpm that the ECU will attempt to run at. It is NOT related to the rev limiter, but is instead dictates how fast certain operations will be allowed to run. Lower number gives better performance
#define engineSquirtsPerCycle 2 //Would be 1 for a 2 stroke
@ -179,6 +204,9 @@ struct table2D injectorVCorrectionTable; //6 bin injector voltage correction (2D
struct table2D IATDensityCorrectionTable; //9 bin inlet air temperature density correction (2D)
struct table2D IATRetardTable; //6 bin ignition adjustment based on inlet air 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)
//These are for the direct port manipulation of the injectors and coils
volatile byte *inj1_pin_port;
@ -219,6 +247,9 @@ bool channel2InjEnabled = false;
bool channel3InjEnabled = false;
bool channel4InjEnabled = false;
bool channel5InjEnabled = false;
bool channel6InjEnabled = false;
bool channel7InjEnabled = false;
bool channel8InjEnabled = false;
int ignition1EndAngle = 0;
int ignition2EndAngle = 0;
@ -228,6 +259,9 @@ int ignition4EndAngle = 0;
//This is used across multiple files
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)
//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;
@ -284,6 +318,10 @@ struct statuses {
unsigned int PW2; //In uS
unsigned int PW3; //In uS
unsigned int PW4; //In uS
unsigned int PW5; //In uS
unsigned int PW6; //In uS
unsigned int PW7; //In uS
unsigned int PW8; //In uS
volatile byte runSecs; //Counter of seconds since cranking commenced (overflows at 255 obviously)
volatile byte secl; //Continous
volatile unsigned int loopsPerSecond;
@ -301,6 +339,8 @@ struct statuses {
uint16_t canin[16]; //16bit raw value of selected canin data for channel 0-15
uint8_t current_caninchannel = 0; //start off at channel 0
uint16_t crankRPM = 400; //The actual cranking RPM limit. Saves us multiplying it everytime from the config page
volatile byte status3;
int16_t flexBoostCorrection; //Amount of boost added based on flex
//Helpful bitwise operations:
//Useful reference: http://playground.arduino.cc/Code/BitMath
@ -313,10 +353,10 @@ struct statuses currentStatus; //The global status object
//Page 1 of the config - See the ini file for further reference
//This mostly covers off variables that are required for fuel
struct config1 {
struct config2 {
int8_t flexBoostLow; //Must be signed to allow for negatives
byte flexBoostHigh;
byte unused2_1;
byte unused2_2;
byte asePct; //Afterstart enrichment (%)
byte aseCount; //Afterstart enrichment cycles. This is the number of ignition cycles that the afterstart enrichment % lasts for
byte wueValues[10]; //Warm up enrichment array (10 bytes)
@ -391,10 +431,10 @@ struct config1 {
uint16_t oddfire2; //The ATDC angle of channel 2 for oddfire
uint16_t oddfire3; //The ATDC angle of channel 3 for oddfire
uint16_t oddfire4; //The ATDC angle of channel 4 for oddfire
byte flexFuelLow; //Fuel % to be used for the lowest ethanol reading (Typically 100%)
byte flexFuelHigh; //Fuel % to be used for the highest ethanol reading (Typically 163%)
byte flexAdvLow; //Additional advance (in degrees) at lowest ethanol reading (Typically 0)
byte flexAdvHigh; //Additional advance (in degrees) at highest ethanol reading (Varies, usually 10-20)
byte unused2_57;
byte unused2_58;
byte unused2_59;
byte unused2_60;
byte iacCLminDuty;
byte iacCLmaxDuty;
@ -413,7 +453,7 @@ struct config1 {
//Page 2 of the config - See the ini file for further reference
//This mostly covers off variables that are required for ignition
struct config2 {
struct config4 {
int16_t triggerAngle;
byte FixAng;
@ -430,9 +470,12 @@ struct config2 {
byte useResync : 1;
byte sparkDur; //Spark duration in ms * 10
bool trigPatternSec; //Mode for Missing tooth secondary trigger. Either single tooth cam wheel or 4-1
byte unused4_9;
byte unused4_10;
byte trigPatternSec; //Mode for Missing tooth secondary trigger. Either single tooth cam wheel or 4-1
uint8_t bootloaderCaps; //Capabilities of the bootloader over stock. e.g., 0=Stock, 1=Reset protection, etc.
byte resetControl : 2; //Which method of reset control to use (0=None, 1=Prevent When Running, 2=Prevent Always, 3=Serial Command)
byte resetControlPin : 6;
byte StgCycles; //The number of initial cycles before the ignition should fire when first cranking
byte dwellCont : 1; //Fixed duty dwell control
@ -474,9 +517,9 @@ struct config2 {
} __attribute__((__packed__)); //The 32 bi systems require all structs to be fully packed
#endif
//Page 3 of the config - See the ini file for further reference
//Page 6 of the config - See the ini file for further reference
//This mostly covers off variables that are required for AFR targets and closed loop
struct config3 {
struct config6 {
byte egoAlgorithm : 2;
byte egoType : 2;
@ -568,9 +611,9 @@ struct config3 {
} __attribute__((__packed__)); //The 32 bit systems require all structs to be fully packed
#endif
//Page 10 of the config mostly deals with CANBUS control
//Page 9 of the config mostly deals with CANBUS control
//See ini file for further info (Config Page 10 in the ini)
struct config10 {
struct config9 {
byte enable_canbus:2;
byte enable_candata_in:1;
uint16_t caninput_sel; //bit status on/off if input is enabled
@ -620,11 +663,11 @@ struct config10 {
#endif
/*
Page 11 - No specific purpose. Created initially for the cranking enrich curve
Page 10 - No specific purpose. Created initially for the cranking enrich curve
192 bytes long
See ini file for further info (Config Page 11 in the ini)
*/
struct config11 {
struct config10 {
byte crankingEnrichBins[4];
byte crankingEnrichValues[4];
@ -640,7 +683,17 @@ struct config11 {
byte boostIntv;
uint16_t stagedInjSizePri;
uint16_t stagedInjSizeSec;
byte unused11_28_192[160];
byte lnchCtrlTPS;
uint8_t flexBoostBins[6];
int16_t flexBoostAdj[6]; //kPa to be added to the boost target @ current ethanol (negative values allowed)
uint8_t flexFuelBins[6];
uint8_t flexFuelAdj[6]; //Fuel % @ current ethanol (typically 100% @ 0%, 163% @ 100%)
uint8_t flexAdvBins[6];
uint8_t flexAdvAdj[6]; //Additional advance (in degrees) @ current ethanol (typically 0 @ 0%, 10-20 @ 100%)
//And another three corn rows die.
byte unused11_75_192[117];
#if defined(CORE_AVR)
};
@ -648,7 +701,6 @@ struct config11 {
} __attribute__((__packed__)); //The 32 bit systems require all structs to be fully packed
#endif
byte pinInjector1; //Output pin injector 1
byte pinInjector2; //Output pin injector 2
byte pinInjector3; //Output pin injector 3 is on
@ -707,6 +759,7 @@ byte pinLaunch;
byte pinIgnBypass; //The pin used for an ignition bypass (Optional)
byte pinFlex; //Pin with the flex sensor attached
byte pinBaro; //Pin that an external barometric pressure sensor is attached to (If used)
byte pinResetControl; // Output pin used control resetting the Arduino
// global variables // from speeduino.ino
extern struct statuses currentStatus; // from speeduino.ino
@ -717,11 +770,11 @@ extern struct table3D stagingTable; //8x8 afr target map
extern struct table2D taeTable; //4 bin TPS Acceleration Enrichment map (2D)
extern struct table2D WUETable; //10 bin Warm Up Enrichment map (2D)
extern struct table2D crankingEnrichTable; //4 bin cranking Enrichment map (2D)
extern struct config1 configPage1;
extern struct config2 configPage2;
extern struct config3 configPage3;
extern struct config4 configPage4;
extern struct config6 configPage6;
extern struct config9 configPage9;
extern struct config10 configPage10;
extern struct config11 configPage11;
extern unsigned long currentLoopTime; //The time the current loop started (uS)
extern unsigned long previousLoopTime; //The time the previous loop started (uS)
volatile uint16_t ignitionCount; //The count of ignition events that have taken place since the engine started
@ -729,7 +782,4 @@ extern byte cltCalibrationTable[CALIBRATION_TABLE_SIZE];
extern byte iatCalibrationTable[CALIBRATION_TABLE_SIZE];
extern byte o2CalibrationTable[CALIBRATION_TABLE_SIZE];
// alias(es) for ease of code reading!!
bool& trigPatternSec = configPage2.trigPatternSec;
#endif // GLOBALS_H

View File

@ -13,7 +13,7 @@ These functions cover the PWM and stepper idle control
Idle Control
Currently limited to on/off control and open loop PWM and stepper drive
*/
integerPID idlePID(&currentStatus.longRPM, &idle_pid_target_value, &idle_cl_target_rpm, configPage3.idleKP, configPage3.idleKI, configPage3.idleKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
integerPID idlePID(&currentStatus.longRPM, &idle_pid_target_value, &idle_cl_target_rpm, configPage6.idleKP, configPage6.idleKI, configPage6.idleKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
void initialiseIdle()
{
@ -24,7 +24,7 @@ void initialiseIdle()
#elif defined (CORE_TEENSY)
if( (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_CL) )
if( (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL) )
{
//FlexTimer 2 is used for idle
FTM2_MODE |= FTM_MODE_WPDIS; // Write Protection Disable
@ -81,14 +81,14 @@ void initialiseIdle()
#endif
//Initialising comprises of setting the 2D tables with the relevant values from the config pages
switch(configPage3.iacAlgorithm)
switch(configPage6.iacAlgorithm)
{
case IAC_ALGORITHM_NONE: //Case 0 is no idle control ('None')
break;
case IAC_ALGORITHM_ONOFF:
//Case 1 is on/off idle control
if ((currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < configPage3.iacFastTemp)
if ((currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < configPage6.iacFastTemp)
{
digitalWrite(pinIdle1, HIGH);
idleOn = true;
@ -99,23 +99,23 @@ void initialiseIdle()
//Case 2 is PWM open loop
iacPWMTable.xSize = 10;
iacPWMTable.valueSize = SIZE_BYTE;
iacPWMTable.values = configPage3.iacOLPWMVal;
iacPWMTable.axisX = configPage3.iacBins;
iacPWMTable.values = configPage6.iacOLPWMVal;
iacPWMTable.axisX = configPage6.iacBins;
iacCrankDutyTable.xSize = 4;
iacCrankDutyTable.valueSize = SIZE_BYTE;
iacCrankDutyTable.values = configPage3.iacCrankDuty;
iacCrankDutyTable.axisX = configPage3.iacCrankBins;
iacCrankDutyTable.values = configPage6.iacCrankDuty;
iacCrankDutyTable.axisX = configPage6.iacCrankBins;
idle_pin_port = portOutputRegister(digitalPinToPort(pinIdle1));
idle_pin_mask = digitalPinToBitMask(pinIdle1);
idle2_pin_port = portOutputRegister(digitalPinToPort(pinIdle2));
idle2_pin_mask = digitalPinToBitMask(pinIdle2);
#if defined(CORE_STM32)
idle_pwm_max_count = 1000000L / (configPage3.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
idle_pwm_max_count = 1000000L / (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
#else
idle_pwm_max_count = 1000000L / (16 * configPage3.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz
idle_pwm_max_count = 1000000L / (16 * configPage6.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz
#endif
enableIdle();
break;
@ -124,25 +124,25 @@ void initialiseIdle()
//Case 3 is PWM closed loop
iacClosedLoopTable.xSize = 10;
iacClosedLoopTable.valueSize = SIZE_BYTE;
iacClosedLoopTable.values = configPage3.iacCLValues;
iacClosedLoopTable.axisX = configPage3.iacBins;
iacClosedLoopTable.values = configPage6.iacCLValues;
iacClosedLoopTable.axisX = configPage6.iacBins;
iacCrankDutyTable.xSize = 4;
iacCrankDutyTable.valueSize = SIZE_BYTE;
iacCrankDutyTable.values = configPage3.iacCrankDuty;
iacCrankDutyTable.axisX = configPage3.iacCrankBins;
iacCrankDutyTable.values = configPage6.iacCrankDuty;
iacCrankDutyTable.axisX = configPage6.iacCrankBins;
idle_pin_port = portOutputRegister(digitalPinToPort(pinIdle1));
idle_pin_mask = digitalPinToBitMask(pinIdle1);
idle2_pin_port = portOutputRegister(digitalPinToPort(pinIdle2));
idle2_pin_mask = digitalPinToBitMask(pinIdle2);
#if defined(CORE_STM32)
idle_pwm_max_count = 1000000L / (configPage3.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
idle_pwm_max_count = 1000000L / (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
#else
idle_pwm_max_count = 1000000L / (16 * configPage3.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz
idle_pwm_max_count = 1000000L / (16 * configPage6.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz
#endif
idlePID.SetOutputLimits(percentage(configPage1.iacCLminDuty, idle_pwm_max_count), percentage(configPage1.iacCLmaxDuty, idle_pwm_max_count));
idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD);
idlePID.SetOutputLimits(percentage(configPage2.iacCLminDuty, idle_pwm_max_count), percentage(configPage2.iacCLmaxDuty, idle_pwm_max_count));
idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD);
idlePID.SetMode(AUTOMATIC); //Turn PID on
idleCounter = 0;
@ -152,13 +152,13 @@ void initialiseIdle()
//Case 2 is Stepper open loop
iacStepTable.xSize = 10;
iacStepTable.valueSize = SIZE_BYTE;
iacStepTable.values = configPage3.iacOLStepVal;
iacStepTable.axisX = configPage3.iacBins;
iacStepTable.values = configPage6.iacOLStepVal;
iacStepTable.axisX = configPage6.iacBins;
iacCrankStepsTable.xSize = 4;
iacCrankStepsTable.values = configPage3.iacCrankSteps;
iacCrankStepsTable.axisX = configPage3.iacCrankBins;
iacStepTime = configPage3.iacStepTime * 1000;
iacCrankStepsTable.values = configPage6.iacCrankSteps;
iacCrankStepsTable.axisX = configPage6.iacCrankBins;
iacStepTime = configPage6.iacStepTime * 1000;
completedHomeSteps = 0;
idleStepper.curIdleStep = 0;
@ -169,21 +169,21 @@ void initialiseIdle()
//Case 5 is Stepper closed loop
iacClosedLoopTable.xSize = 10;
iacClosedLoopTable.valueSize = SIZE_BYTE;
iacClosedLoopTable.values = configPage3.iacCLValues;
iacClosedLoopTable.axisX = configPage3.iacBins;
iacClosedLoopTable.values = configPage6.iacCLValues;
iacClosedLoopTable.axisX = configPage6.iacBins;
iacCrankStepsTable.xSize = 4;
iacCrankStepsTable.values = configPage3.iacCrankSteps;
iacCrankStepsTable.axisX = configPage3.iacCrankBins;
iacStepTime = configPage3.iacStepTime * 1000;
iacCrankStepsTable.values = configPage6.iacCrankSteps;
iacCrankStepsTable.axisX = configPage6.iacCrankBins;
iacStepTime = configPage6.iacStepTime * 1000;
completedHomeSteps = 0;
idleCounter = 0;
idleStepper.curIdleStep = 0;
idleStepper.stepperStatus = SOFF;
idlePID.SetOutputLimits(0, (configPage3.iacStepHome * 3)); //Maximum number of steps probably needs its own setting
idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD);
idlePID.SetOutputLimits(0, (configPage6.iacStepHome * 3)); //Maximum number of steps probably needs its own setting
idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD);
idlePID.SetMode(AUTOMATIC); //Turn PID on
break;
@ -191,7 +191,7 @@ void initialiseIdle()
//Well this just shouldn't happen
break;
}
idleInitComplete = configPage3.iacAlgorithm; //Sets which idle method was initialised
idleInitComplete = configPage6.iacAlgorithm; //Sets which idle method was initialised
currentStatus.idleLoad = 0;
#if defined(CORE_STM32) //Need to be initialised last due to instant interrupt
Timer1.setMode(4, TIMER_OUTPUT_COMPARE);
@ -202,15 +202,15 @@ void initialiseIdle()
void idleControl()
{
if(idleInitComplete != configPage3.iacAlgorithm) { initialiseIdle(); }
if(idleInitComplete != configPage6.iacAlgorithm) { initialiseIdle(); }
switch(configPage3.iacAlgorithm)
switch(configPage6.iacAlgorithm)
{
case IAC_ALGORITHM_NONE: //Case 0 is no idle control ('None')
break;
case IAC_ALGORITHM_ONOFF: //Case 1 is on/off idle control
if ( (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < configPage3.iacFastTemp) //All temps are offset by 40 degrees
if ( (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < configPage6.iacFastTemp) //All temps are offset by 40 degrees
{
digitalWrite(pinIdle1, HIGH);
idleOn = true;
@ -242,7 +242,7 @@ void idleControl()
case IAC_ALGORITHM_PWM_CL: //Case 3 is PWM closed loop
//No cranking specific value for closed loop (yet?)
idle_cl_target_rpm = table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) * 10; //All temps are offset by 40 degrees
if( (idleCounter & 31) == 1) { idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD); } //This only needs to be run very infrequently, once every 32 calls to idleControl(). This is approx. once per second
if( (idleCounter & 31) == 1) { idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD); } //This only needs to be run very infrequently, once every 32 calls to idleControl(). This is approx. once per second
idlePID.Compute();
idle_pwm_target_value = idle_pid_target_value;
@ -272,7 +272,7 @@ void idleControl()
{
//Only do a lookup of the required value around 4 times per second. Any more than this can create too much jitter and require a hyster value that is too high
idleStepper.targetIdleStep = table2D_getValue(&iacStepTable, (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET)) * 3; //All temps are offset by 40 degrees. Step counts are divided by 3 in TS. Multiply back out here
iacStepTime = configPage3.iacStepTime * 1000;
iacStepTime = configPage6.iacStepTime * 1000;
}
doStep();
}
@ -287,8 +287,8 @@ void idleControl()
if( (idleCounter & 31) == 1)
{
//This only needs to be run very infrequently, once every 32 calls to idleControl(). This is approx. once per second
idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD);
iacStepTime = configPage3.iacStepTime * 1000;
idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD);
iacStepTime = configPage6.iacStepTime * 1000;
}
idle_cl_target_rpm = table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) * 10; //All temps are offset by 40 degrees
@ -316,7 +316,7 @@ False: If the motor has not yet been homed. Will also perform another homing ste
static inline byte isStepperHomed()
{
bool isHomed = true; //As it's the most common scenario, default value is true
if( completedHomeSteps < (configPage3.iacStepHome * 3) ) //Home steps are divided by 3 from TS
if( completedHomeSteps < (configPage6.iacStepHome * 3) ) //Home steps are divided by 3 from TS
{
digitalWrite(pinStepperDir, STEPPER_BACKWARD); //Sets stepper direction to backwards
digitalWrite(pinStepperEnable, LOW); //Enable the DRV8825
@ -372,7 +372,7 @@ Performs a step
*/
static inline void doStep()
{
if ( (idleStepper.targetIdleStep <= (idleStepper.curIdleStep - configPage3.iacStepHyster)) || (idleStepper.targetIdleStep >= (idleStepper.curIdleStep + configPage3.iacStepHyster)) ) //Hysteris check
if ( (idleStepper.targetIdleStep <= (idleStepper.curIdleStep - configPage6.iacStepHyster)) || (idleStepper.targetIdleStep >= (idleStepper.curIdleStep + configPage6.iacStepHyster)) ) //Hysteris check
{
if(idleStepper.targetIdleStep < idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_BACKWARD); idleStepper.curIdleStep--; }//Sets stepper direction to backwards
else if (idleStepper.targetIdleStep > idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_FORWARD); idleStepper.curIdleStep++; }//Sets stepper direction to forwards
@ -388,12 +388,12 @@ static inline void doStep()
//This function simply turns off the idle PWM and sets the pin low
static inline void disableIdle()
{
if( (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_OL) )
if( (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) )
{
IDLE_TIMER_DISABLE();
digitalWrite(pinIdle1, LOW);
}
else if ( (configPage3.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage3.iacAlgorithm == IAC_ALGORITHM_STEP_OL) )
else if ( (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OL) )
{
//Only disable the stepper motor if homing is completed
if( isStepperHomed() == true )
@ -408,11 +408,11 @@ static inline void disableIdle()
//Typically this is enabling the PWM interrupt
static inline void enableIdle()
{
if( (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_OL) )
if( (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_PWM_OL) )
{
IDLE_TIMER_ENABLE();
}
else if ( (configPage3.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage3.iacAlgorithm == IAC_ALGORITHM_STEP_OL) )
else if ( (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OL) )
{
}
@ -426,34 +426,34 @@ static inline void idleInterrupt() //Most ARM chips can simply call a function
{
if (idle_pwm_state)
{
if (configPage3.iacPWMdir == 0)
if (configPage6.iacPWMdir == 0)
{
//Normal direction
*idle_pin_port &= ~(idle_pin_mask); // Switch pin to low (1 pin mode)
if(configPage3.iacChannels == 1) { *idle2_pin_port |= (idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
if(configPage6.iacChannels == 1) { *idle2_pin_port |= (idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
}
else
{
//Reversed direction
*idle_pin_port |= (idle_pin_mask); // Switch pin high
if(configPage3.iacChannels == 1) { *idle2_pin_port &= ~(idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
if(configPage6.iacChannels == 1) { *idle2_pin_port &= ~(idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
}
IDLE_COMPARE = IDLE_COUNTER + (idle_pwm_max_count - idle_pwm_cur_value);
idle_pwm_state = false;
}
else
{
if (configPage3.iacPWMdir == 0)
if (configPage6.iacPWMdir == 0)
{
//Normal direction
*idle_pin_port |= (idle_pin_mask); // Switch pin high
if(configPage3.iacChannels == 1) { *idle2_pin_port &= ~(idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
if(configPage6.iacChannels == 1) { *idle2_pin_port &= ~(idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
}
else
{
//Reversed direction
*idle_pin_port &= ~(idle_pin_mask); // Switch pin to low (1 pin mode)
if(configPage3.iacChannels == 1) { *idle2_pin_port |= (idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
if(configPage6.iacChannels == 1) { *idle2_pin_port |= (idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
}
IDLE_COMPARE = IDLE_COUNTER + idle_pwm_target_value;
idle_pwm_cur_value = idle_pwm_target_value;

View File

@ -32,6 +32,13 @@ inline void endTrailingCoilCharge2();
#define closeInjector4() *inj4_pin_port &= ~(inj4_pin_mask); BIT_CLEAR(currentStatus.status1, BIT_STATUS1_INJ4)
#define openInjector5() *inj5_pin_port |= (inj5_pin_mask)
#define closeInjector5() *inj5_pin_port &= ~(inj5_pin_mask)
//Dynamic functions below
#define openInjector6() *inj6_pin_port |= (inj6_pin_mask);
#define closeInjector6() *inj6_pin_port &= ~(inj6_pin_mask);
#define openInjector7() *inj7_pin_port |= (inj7_pin_mask);
#define closeInjector7() *inj7_pin_port &= ~(inj7_pin_mask);
#define openInjector8() *inj8_pin_port |= (inj8_pin_mask);
#define closeInjector8() *inj8_pin_port &= ~(inj8_pin_mask);
#define openInjector1and4() openInjector1(); openInjector4()
#define closeInjector1and4() closeInjector1(); closeInjector4()

View File

@ -1,7 +1,9 @@
volatile bool tachoAlt = true;
#define TACH_PULSE_HIGH() *tach_pin_port |= (tach_pin_mask)
#define TACH_PULSE_LOW() if( (configPage1.tachoDiv == 0) || tachoAlt ) { *tach_pin_port &= ~(tach_pin_mask); tachoAlt = !tachoAlt; }
#define TACH_PULSE_LOW() if( (configPage2.tachoDiv == 0) || tachoAlt ) { *tach_pin_port &= ~(tach_pin_mask); tachoAlt = !tachoAlt; }
inline void beginCoil1Charge() { digitalWrite(pinCoil1, coilHIGH); TACH_PULSE_LOW(); }
inline void endCoil1Charge() { digitalWrite(pinCoil1, coilLOW); TACH_PULSE_HIGH(); }

View File

@ -36,46 +36,76 @@ See page 136 of the processors datasheet: http://www.atmel.com/Images/doc2549.pd
#define FUEL3_COUNTER TCNT3
#define FUEL4_COUNTER TCNT4
#define FUEL5_COUNTER TCNT3
//The following are for the additional dynamic modes and share the counter and compares with the ignition
#define FUEL6_COUNTER TCNT4 //Takes off ignition 4
#define FUEL7_COUNTER TCNT5
#define FUEL8_COUNTER TCNT5
#define IGN1_COUNTER TCNT5
#define IGN2_COUNTER TCNT5
#define IGN3_COUNTER TCNT5
#define IGN4_COUNTER TCNT4
#define IGN5_COUNTER TCNT1
//The following are for the additional dynamic modes and share the counter and compares with the injectors
#define IGN6_COUNTER TCNT4 //Replaces injector 4
#define IGN7_COUNTER TCNT3 //Replaces injector 3
#define IGN8_COUNTER TCNT3 //Replaces injector 2
#define FUEL1_COMPARE OCR3A
#define FUEL2_COMPARE OCR3B
#define FUEL3_COMPARE OCR3C
#define FUEL4_COMPARE OCR4B
#define FUEL5_COMPARE OCR3A //Shared with FUEL1
//The following are for the additional dynamic modes and share the counter and compares with the ignition
#define FUEL6_COMPARE OCR4A //Replaces ignition4
#define FUEL7_COMPARE OCR5C //Replaces ignition3
#define FUEL8_COMPARE OCR5B //Replaces ignition2
#define IGN1_COMPARE OCR5A
#define IGN2_COMPARE OCR5B
#define IGN3_COMPARE OCR5C
#define IGN4_COMPARE OCR4A
#define IGN5_COMPARE OCR1C
//The following are for the additional dynamic modes and share the counter and compares with the injectors
#define IGN6_COMPARE OCR4B //Replaces injector 4
#define IGN7_COMPARE OCR3C //Replaces injector 3
#define IGN8_COMPARE OCR3B //Replaces injector 2
#define FUEL1_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3A) //Turn on the A compare unit (ie turn on the interrupt)
#define FUEL2_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3B) //Turn on the B compare unit (ie turn on the interrupt)
#define FUEL3_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3C) //Turn on the C compare unit (ie turn on the interrupt)
#define FUEL4_TIMER_ENABLE() TIMSK4 |= (1 << OCIE4B) //Turn on the B compare unit (ie turn on the interrupt)
#define FUEL5_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3B) //
#define FUEL6_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3B) //
#define FUEL7_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3C) //
#define FUEL8_TIMER_ENABLE() TIMSK4 |= (1 << OCIE4B) //
#define FUEL1_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3A); //Turn off this output compare unit
#define FUEL2_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3B); //Turn off this output compare unit
#define FUEL3_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3C); //Turn off this output compare unit
#define FUEL4_TIMER_DISABLE() TIMSK4 &= ~(1 << OCIE4B); //Turn off this output compare unit
#define FUEL5_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3A); //
#define FUEL6_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3B); //
#define FUEL7_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3C); //
#define FUEL8_TIMER_DISABLE() TIMSK4 &= ~(1 << OCIE4B); //
#define IGN1_TIMER_ENABLE() TIMSK5 |= (1 << OCIE5A) //Turn on the A compare unit (ie turn on the interrupt)
#define IGN2_TIMER_ENABLE() TIMSK5 |= (1 << OCIE5B) //Turn on the B compare unit (ie turn on the interrupt)
#define IGN3_TIMER_ENABLE() TIMSK5 |= (1 << OCIE5C) //Turn on the C compare unit (ie turn on the interrupt)
#define IGN4_TIMER_ENABLE() TIMSK4 |= (1 << OCIE4A) //Turn on the A compare unit (ie turn on the interrupt)
#define IGN5_TIMER_ENABLE() TIMSK1 |= (1 << OCIE1C) //Turn on the A compare unit (ie turn on the interrupt)
#define IGN6_TIMER_ENABLE() TIMSK4 |= (1 << OCIE4B) //Replaces injector 4
#define IGN7_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3C) //Replaces injector 3
#define IGN8_TIMER_ENABLE() TIMSK3 |= (1 << OCIE3B) //Replaces injector 2
#define IGN1_TIMER_DISABLE() TIMSK5 &= ~(1 << OCIE5A) //Turn off this output compare unit
#define IGN2_TIMER_DISABLE() TIMSK5 &= ~(1 << OCIE5B) //Turn off this output compare unit
#define IGN3_TIMER_DISABLE() TIMSK5 &= ~(1 << OCIE5C) //Turn off this output compare unit
#define IGN4_TIMER_DISABLE() TIMSK4 &= ~(1 << OCIE4A) //Turn off this output compare unit
#define IGN5_TIMER_DISABLE() TIMSK1 &= ~(1 << OCIE1C) //Turn off this output compare unit
#define IGN6_TIMER_DISABLE() TIMSK4 &= ~(1 << OCIE4B) //Replaces injector 4
#define IGN7_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3C) //Replaces injector 3
#define IGN8_TIMER_DISABLE() TIMSK3 &= ~(1 << OCIE3B) //Replaces injector 2
#define MAX_TIMER_PERIOD 262140UL //The longest period of time (in uS) that the timer can permit (IN this case it is 65535 * 4, as each timer tick is 4uS)
#define MAX_TIMER_PERIOD_SLOW 1048560UL //The longest period of time (in uS) that the timer can permit (IN this case it is 65535 * 16, as each timer tick is 16uS)
@ -174,30 +204,47 @@ See page 136 of the processors datasheet: http://www.atmel.com/Images/doc2549.pd
#define FUEL2_COUNTER (TIM2)->CNT
#define FUEL3_COUNTER (TIM2)->CNT
#define FUEL4_COUNTER (TIM2)->CNT
#define FUEL5_COUNTER (TIM2)->CNT
#define FUEL5_COUNTER (TIM4)->CNT
#define FUEL6_COUNTER (TIM4)->CNT
#define FUEL7_COUNTER (TIM4)->CNT
#define FUEL8_COUNTER (TIM4)->CNT
#define IGN1_COUNTER (TIM3)->CNT
#define IGN2_COUNTER (TIM3)->CNT
#define IGN3_COUNTER (TIM3)->CNT
#define IGN4_COUNTER (TIM3)->CNT
#define IGN5_COUNTER (TIM3)->CNT
#define IGN5_COUNTER (TIM4)->CNT
#define IGN6_COUNTER (TIM4)->CNT
#define IGN7_COUNTER (TIM4)->CNT
#define IGN8_COUNTER (TIM4)->CNT
#define FUEL1_COMPARE (TIM2)->CCR1
#define FUEL2_COMPARE (TIM2)->CCR2
#define FUEL3_COMPARE (TIM2)->CCR3
#define FUEL4_COMPARE (TIM2)->CCR4
#define FUEL5_COMPARE (TIM4)->CCR1
#define FUEL6_COMPARE (TIM4)->CCR2
#define FUEL7_COMPARE (TIM4)->CCR3
#define FUEL8_COMPARE (TIM4)->CCR4
#define IGN1_COMPARE (TIM3)->CCR1
#define IGN2_COMPARE (TIM3)->CCR2
#define IGN3_COMPARE (TIM3)->CCR3
#define IGN4_COMPARE (TIM3)->CCR4
#define IGN5_COMPARE (TIM3)->CCR1
#define IGN5_COMPARE (TIM4)->CCR1
#define IGN6_COMPARE (TIM4)->CCR2
#define IGN7_COMPARE (TIM4)->CCR3
#define IGN8_COMPARE (TIM4)->CCR4
//https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/754bc2969921f1ef262bd69e7faca80b19db7524/STM32F1/system/libmaple/include/libmaple/timer.h#L444
#define FUEL1_TIMER_ENABLE() (TIM2)->CCER |= TIM_CCER_CC1E
#define FUEL2_TIMER_ENABLE() (TIM2)->CCER |= TIM_CCER_CC2E
#define FUEL3_TIMER_ENABLE() (TIM2)->CCER |= TIM_CCER_CC3E
#define FUEL4_TIMER_ENABLE() (TIM2)->CCER |= TIM_CCER_CC4E
#define FUEL5_TIMER_ENABLE() (TIM4)->CCER |= TIM_CCER_CC1E
#define FUEL6_TIMER_ENABLE() (TIM4)->CCER |= TIM_CCER_CC2E
#define FUEL7_TIMER_ENABLE() (TIM4)->CCER |= TIM_CCER_CC3E
#define FUEL8_TIMER_ENABLE() (TIM4)->CCER |= TIM_CCER_CC4E
#define IGN1_TIMER_ENABLE() (TIM3)->CCER |= TIM_CCER_CC1E
#define IGN2_TIMER_ENABLE() (TIM3)->CCER |= TIM_CCER_CC2E
@ -220,47 +267,75 @@ See page 136 of the processors datasheet: http://www.atmel.com/Images/doc2549.pd
#define FUEL2_COUNTER (TIMER2->regs).gen->CNT
#define FUEL3_COUNTER (TIMER2->regs).gen->CNT
#define FUEL4_COUNTER (TIMER2->regs).gen->CNT
#define FUEL5_COUNTER (TIMER1->regs).gen->CNT
#define FUEL5_COUNTER (TIMER4->regs).gen->CNT
#define FUEL6_COUNTER (TIMER4->regs).gen->CNT
#define FUEL7_COUNTER (TIMER4->regs).gen->CNT
#define FUEL8_COUNTER (TIMER4->regs).gen->CNT
#define IGN1_COUNTER (TIMER3->regs).gen->CNT
#define IGN2_COUNTER (TIMER3->regs).gen->CNT
#define IGN3_COUNTER (TIMER3->regs).gen->CNT
#define IGN4_COUNTER (TIMER3->regs).gen->CNT
#define IGN5_COUNTER (TIMER1->regs).gen->CNT
#define IGN5_COUNTER (TIMER4->regs).gen->CNT
#define IGN6_COUNTER (TIMER4->regs).gen->CNT
#define IGN7_COUNTER (TIMER4->regs).gen->CNT
#define IGN8_COUNTER (TIMER4->regs).gen->CNT
#define FUEL1_COMPARE (TIMER2->regs).gen->CCR1
#define FUEL2_COMPARE (TIMER2->regs).gen->CCR2
#define FUEL3_COMPARE (TIMER2->regs).gen->CCR3
#define FUEL4_COMPARE (TIMER2->regs).gen->CCR4
#define FUEL5_COMPARE (TIMER4->regs).gen->CCR1
#define FUEL6_COMPARE (TIMER4->regs).gen->CCR2
#define FUEL7_COMPARE (TIMER4->regs).gen->CCR3
#define FUEL8_COMPARE (TIMER4->regs).gen->CCR4
#define IGN1_COMPARE (TIMER3->regs).gen->CCR1
#define IGN2_COMPARE (TIMER3->regs).gen->CCR2
#define IGN3_COMPARE (TIMER3->regs).gen->CCR3
#define IGN4_COMPARE (TIMER3->regs).gen->CCR4
#define IGN5_COMPARE (TIMER1->regs).gen->CCR1
#define IGN5_COMPARE (TIMER4->regs).gen->CCR1
#define IGN6_COMPARE (TIMER4->regs).gen->CCR2
#define IGN7_COMPARE (TIMER4->regs).gen->CCR3
#define IGN8_COMPARE (TIMER4->regs).gen->CCR4
//https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/754bc2969921f1ef262bd69e7faca80b19db7524/STM32F1/system/libmaple/include/libmaple/timer.h#L444
#define FUEL1_TIMER_ENABLE() (TIMER2->regs).gen->CCER |= TIMER_CCER_CC1E
#define FUEL2_TIMER_ENABLE() (TIMER2->regs).gen->CCER |= TIMER_CCER_CC2E
#define FUEL3_TIMER_ENABLE() (TIMER2->regs).gen->CCER |= TIMER_CCER_CC3E
#define FUEL4_TIMER_ENABLE() (TIMER2->regs).gen->CCER |= TIMER_CCER_CC4E
#define FUEL5_TIMER_ENABLE() (TIMER4->regs).gen->CCER |= TIMER_CCER_CC1E
#define FUEL6_TIMER_ENABLE() (TIMER4->regs).gen->CCER |= TIMER_CCER_CC2E
#define FUEL7_TIMER_ENABLE() (TIMER4->regs).gen->CCER |= TIMER_CCER_CC3E
#define FUEL8_TIMER_ENABLE() (TIMER4->regs).gen->CCER |= TIMER_CCER_CC4E
#define IGN1_TIMER_ENABLE() (TIMER3->regs).gen->CCER |= TIMER_CCER_CC1E
#define IGN2_TIMER_ENABLE() (TIMER3->regs).gen->CCER |= TIMER_CCER_CC2E
#define IGN3_TIMER_ENABLE() (TIMER3->regs).gen->CCER |= TIMER_CCER_CC3E
#define IGN4_TIMER_ENABLE() (TIMER3->regs).gen->CCER |= TIMER_CCER_CC4E
#define IGN5_TIMER_ENABLE() (TIMER1->regs).gen->CCER |= TIMER_CCER_CC1E
#define IGN5_TIMER_ENABLE() (TIMER4->regs).gen->CCER |= TIMER_CCER_CC1E
#define IGN6_TIMER_ENABLE() (TIMER4->regs).gen->CCER |= TIMER_CCER_CC2E
#define IGN7_TIMER_ENABLE() (TIMER4->regs).gen->CCER |= TIMER_CCER_CC3E
#define IGN8_TIMER_ENABLE() (TIMER4->regs).gen->CCER |= TIMER_CCER_CC4E
#define FUEL1_TIMER_DISABLE() (TIMER2->regs).gen->CCER &= ~TIMER_CCER_CC1E
#define FUEL2_TIMER_DISABLE() (TIMER2->regs).gen->CCER &= ~TIMER_CCER_CC2E
#define FUEL3_TIMER_DISABLE() (TIMER2->regs).gen->CCER &= ~TIMER_CCER_CC3E
#define FUEL4_TIMER_DISABLE() (TIMER2->regs).gen->CCER &= ~TIMER_CCER_CC4E
#define FUEL5_TIMER_DISABLE() (TIMER4->regs).gen->CCER &= ~TIMER_CCER_CC1E
#define FUEL6_TIMER_DISABLE() (TIMER4->regs).gen->CCER &= ~TIMER_CCER_CC2E
#define FUEL7_TIMER_DISABLE() (TIMER4->regs).gen->CCER &= ~TIMER_CCER_CC3E
#define FUEL8_TIMER_DISABLE() (TIMER4->regs).gen->CCER &= ~TIMER_CCER_CC4E
#define IGN1_TIMER_DISABLE() (TIMER3->regs).gen->CCER &= ~TIMER_CCER_CC1E
#define IGN2_TIMER_DISABLE() (TIMER3->regs).gen->CCER &= ~TIMER_CCER_CC2E
#define IGN3_TIMER_DISABLE() (TIMER3->regs).gen->CCER &= ~TIMER_CCER_CC3E
#define IGN4_TIMER_DISABLE() (TIMER3->regs).gen->CCER &= ~TIMER_CCER_CC4E
#define IGN5_TIMER_DISABLE() (TIMER1->regs).gen->CCER &= ~TIMER_CCER_CC1E
#define IGN5_TIMER_DISABLE() (TIMER4->regs).gen->CCER &= ~TIMER_CCER_CC1E
#define IGN6_TIMER_DISABLE() (TIMER4->regs).gen->CCER &= ~TIMER_CCER_CC2E
#define IGN7_TIMER_DISABLE() (TIMER4->regs).gen->CCER &= ~TIMER_CCER_CC3E
#define IGN8_TIMER_DISABLE() (TIMER4->regs).gen->CCER &= ~TIMER_CCER_CC4E
#endif
#endif
@ -284,19 +359,49 @@ void setIgnitionSchedule8(void (*startCallback)(), unsigned long timeout, unsign
static inline void refreshIgnitionSchedule1(unsigned long timeToEnd) __attribute__((always_inline));
//Needed for STM32 interrupt handlers
#if defined(CORE_STM32)
//The ARM cores use seprate functions for their ISRs
#if defined(CORE_STM32) || defined(CORE_TEENSY)
static inline void fuelSchedule1Interrupt();
static inline void fuelSchedule2Interrupt();
static inline void fuelSchedule3Interrupt();
static inline void fuelSchedule4Interrupt();
#if (INJ_CHANNELS >= 5)
static inline void fuelSchedule5Interrupt();
#endif
#if (INJ_CHANNELS >= 6)
static inline void fuelSchedule6Interrupt();
#endif
#if (INJ_CHANNELS >= 7)
static inline void fuelSchedule7Interrupt();
#endif
#if (INJ_CHANNELS >= 8)
static inline void fuelSchedule8Interrupt();
#endif
#if (IGN_CHANNELS >= 1)
static inline void ignitionSchedule1Interrupt();
#endif
#if (IGN_CHANNELS >= 2)
static inline void ignitionSchedule2Interrupt();
#endif
#if (IGN_CHANNELS >= 3)
static inline void ignitionSchedule3Interrupt();
#endif
#if (IGN_CHANNELS >= 4)
static inline void ignitionSchedule4Interrupt();
#endif
#if (IGN_CHANNELS >= 5)
static inline void ignitionSchedule5Interrupt();
#endif
#if (IGN_CHANNELS >= 6)
static inline void ignitionSchedule6Interrupt();
#endif
#if (IGN_CHANNELS >= 7)
static inline void ignitionSchedule7Interrupt();
#endif
#if (IGN_CHANNELS >= 8)
static inline void ignitionSchedule8Interrupt();
#endif
#endif
enum ScheduleStatus {OFF, PENDING, STAGED, RUNNING}; //The 3 statuses that a schedule can have
@ -313,6 +418,13 @@ struct Schedule {
unsigned int nextStartCompare;
unsigned int nextEndCompare;
volatile bool hasNextSchedule = false;
#if defined(CORE_AVR)
volatile uint16_t * counter;
volatile uint16_t * compare;
#elif defined(CORE_STM32) || defined(CORE_TEENSY)
volatile uint32_t * counter;
volatile uint32_t * compare;
#endif
};
volatile Schedule *timer3Aqueue[4];
@ -327,6 +439,7 @@ Schedule fuelSchedule5;
Schedule fuelSchedule6;
Schedule fuelSchedule7;
Schedule fuelSchedule8;
Schedule ignitionSchedule1;
Schedule ignitionSchedule2;
Schedule ignitionSchedule3;

View File

@ -198,11 +198,21 @@ void initialiseSchedulers()
Timer2.attachInterrupt(3, fuelSchedule3Interrupt);
Timer2.attachInterrupt(4, fuelSchedule4Interrupt);
#if (IGN_CHANNELS >= 1)
Timer3.attachInterrupt(1, ignitionSchedule1Interrupt);
#endif
#if (IGN_CHANNELS >= 2)
Timer3.attachInterrupt(2, ignitionSchedule2Interrupt);
#endif
#if (IGN_CHANNELS >= 3)
Timer3.attachInterrupt(3, ignitionSchedule3Interrupt);
#endif
#if (IGN_CHANNELS >= 4)
Timer3.attachInterrupt(4, ignitionSchedule4Interrupt);
#endif
#if (IGN_CHANNELS >= 5)
Timer1.attachInterrupt(1, ignitionSchedule5Interrupt);
#endif
Timer1.resume();
Timer2.resume();
@ -214,24 +224,45 @@ void initialiseSchedulers()
fuelSchedule3.Status = OFF;
fuelSchedule4.Status = OFF;
fuelSchedule5.Status = OFF;
fuelSchedule6.Status = OFF;
fuelSchedule7.Status = OFF;
fuelSchedule8.Status = OFF;
fuelSchedule1.schedulesSet = 0;
fuelSchedule2.schedulesSet = 0;
fuelSchedule3.schedulesSet = 0;
fuelSchedule4.schedulesSet = 0;
fuelSchedule5.schedulesSet = 0;
fuelSchedule6.schedulesSet = 0;
fuelSchedule7.schedulesSet = 0;
fuelSchedule8.schedulesSet = 0;
fuelSchedule1.counter = &FUEL1_COUNTER;
fuelSchedule2.counter = &FUEL2_COUNTER;
fuelSchedule3.counter = &FUEL3_COUNTER;
fuelSchedule4.counter = &FUEL4_COUNTER;
fuelSchedule5.counter = &FUEL5_COUNTER;
fuelSchedule6.counter = &FUEL6_COUNTER;
fuelSchedule7.counter = &FUEL7_COUNTER;
fuelSchedule8.counter = &FUEL8_COUNTER;
ignitionSchedule1.Status = OFF;
ignitionSchedule2.Status = OFF;
ignitionSchedule3.Status = OFF;
ignitionSchedule4.Status = OFF;
ignitionSchedule5.Status = OFF;
ignitionSchedule6.Status = OFF;
ignitionSchedule7.Status = OFF;
ignitionSchedule8.Status = OFF;
ignitionSchedule1.schedulesSet = 0;
ignitionSchedule2.schedulesSet = 0;
ignitionSchedule3.schedulesSet = 0;
ignitionSchedule4.schedulesSet = 0;
ignitionSchedule5.schedulesSet = 0;
ignitionSchedule6.schedulesSet = 0;
ignitionSchedule7.schedulesSet = 0;
ignitionSchedule8.schedulesSet = 0;
}
@ -244,6 +275,44 @@ timeout: The number of uS in the future that the startCallback should be trigger
duration: The number of uS after startCallback is called before endCallback is called
endCallback: This function is called once the duration time has been reached
*/
//Experimental new generic function
void setFuelSchedule(struct Schedule *targetSchedule, unsigned long timeout, unsigned long duration)
{
if(targetSchedule->Status != RUNNING) //Check that we're not already part way through a schedule
{
//Callbacks no longer used, but retained for now:
//fuelSchedule1.StartCallback = startCallback;
//fuelSchedule1.EndCallback = endCallback;
targetSchedule->duration = duration;
//Need to check that the timeout doesn't exceed the overflow
uint16_t timeout_timer_compare;
if (timeout > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (MAX_TIMER_PERIOD_SLOW - 1) ); } // If the timeout is >16x (Each tick represents 16uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking.
else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case
//The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set
noInterrupts();
targetSchedule->startCompare = *targetSchedule->counter + timeout_timer_compare;
targetSchedule->endCompare = targetSchedule->startCompare + uS_TO_TIMER_COMPARE_SLOW(duration);
targetSchedule->Status = PENDING; //Turn this schedule on
targetSchedule->schedulesSet++; //Increment the number of times this schedule has been set
*targetSchedule->compare = targetSchedule->startCompare;
interrupts();
FUEL1_TIMER_ENABLE();
}
else
{
//If the schedule is already running, we can set the next schedule so it is ready to go
//This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule
targetSchedule->nextStartCompare = *targetSchedule->counter + uS_TO_TIMER_COMPARE_SLOW(timeout);
targetSchedule->nextEndCompare = targetSchedule->nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration);
targetSchedule->hasNextSchedule = true;
}
}
//void setFuelSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
void setFuelSchedule1(unsigned long timeout, unsigned long duration)
{
@ -282,6 +351,7 @@ void setFuelSchedule1(unsigned long timeout, unsigned long duration)
fuelSchedule1.hasNextSchedule = true;
}
}
void setFuelSchedule2(unsigned long timeout, unsigned long duration)
{
if(fuelSchedule2.Status != RUNNING) //Check that we're not already part way through a schedule
@ -383,37 +453,150 @@ void setFuelSchedule4(unsigned long timeout, unsigned long duration) //Uses time
fuelSchedule4.hasNextSchedule = true;
}
}
void setFuelSchedule5(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
{
if(fuelSchedule5.Status != RUNNING) //Check that we're not already part way through a schedule
{
fuelSchedule5.StartCallback = startCallback; //Name the start callback function
fuelSchedule5.EndCallback = endCallback; //Name the end callback function
fuelSchedule5.duration = duration;
/*
* The following must be enclosed in the noIntterupts block to avoid contention caused if the relevant interrupts fires before the state is fully set
*/
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
noInterrupts();
fuelSchedule5.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16
fuelSchedule5.endCompare = fuelSchedule5.startCompare + (duration >> 4);
fuelSchedule5.Status = PENDING; //Turn this schedule on
fuelSchedule5.schedulesSet++; //Increment the number of times this schedule has been set
OCR3A = setQueue(timer3Aqueue, &fuelSchedule1, &fuelSchedule5, TCNT3); //Schedule 1 shares a timer with schedule 5
interrupts();
TIMSK3 |= (1 << OCIE3A); //Turn on the A compare unit (ie turn on the interrupt)
#endif
}
else
{
//If the schedule is already running, we can set the next schedule so it is ready to go
//This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule
fuelSchedule5.nextStartCompare = FUEL5_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout);
fuelSchedule5.nextEndCompare = fuelSchedule5.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration);
fuelSchedule5.hasNextSchedule = true;
}
void setFuelSchedule5(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
{
if(fuelSchedule5.Status != RUNNING) //Check that we're not already part way through a schedule
{
fuelSchedule5.StartCallback = startCallback; //Name the start callback function
fuelSchedule5.EndCallback = endCallback; //Name the end callback function
fuelSchedule5.duration = duration;
/*
* The following must be enclosed in the noIntterupts block to avoid contention caused if the relevant interrupts fires before the state is fully set
*/
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
noInterrupts();
fuelSchedule5.startCompare = TCNT3 + (timeout >> 4); //As above, but with bit shift instead of / 16
fuelSchedule5.endCompare = fuelSchedule5.startCompare + (duration >> 4);
fuelSchedule5.Status = PENDING; //Turn this schedule on
fuelSchedule5.schedulesSet++; //Increment the number of times this schedule has been set
OCR3A = setQueue(timer3Aqueue, &fuelSchedule1, &fuelSchedule5, TCNT3); //Schedule 1 shares a timer with schedule 5
interrupts();
TIMSK3 |= (1 << OCIE3A); //Turn on the A compare unit (ie turn on the interrupt)
#endif
}
else
{
//If the schedule is already running, we can set the next schedule so it is ready to go
//This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule
fuelSchedule5.nextStartCompare = FUEL5_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout);
fuelSchedule5.nextEndCompare = fuelSchedule5.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration);
fuelSchedule5.hasNextSchedule = true;
}
}
#if INJ_CHANNELS >= 6
//This uses timer
void setFuelSchedule6(unsigned long timeout, unsigned long duration)
{
if(fuelSchedule6.Status != RUNNING) //Check that we're not already part way through a schedule
{
//Callbacks no longer used, but retained for now:
//fuelSchedule4.StartCallback = startCallback;
//fuelSchedule4.EndCallback = endCallback;
fuelSchedule6.duration = duration;
//Need to check that the timeout doesn't exceed the overflow
uint16_t timeout_timer_compare;
if (timeout > MAX_TIMER_PERIOD_SLOW) { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW( (MAX_TIMER_PERIOD - 1) ); } // If the timeout is >4x (Each tick represents 4uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking.
else { timeout_timer_compare = uS_TO_TIMER_COMPARE_SLOW(timeout); } //Normal case
//The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set
noInterrupts();
fuelSchedule6.startCompare = FUEL6_COUNTER + timeout_timer_compare;
fuelSchedule6.endCompare = fuelSchedule6.startCompare + uS_TO_TIMER_COMPARE_SLOW(duration);
FUEL6_COMPARE = fuelSchedule6.startCompare; //Use the C copmare unit of timer 3
fuelSchedule6.Status = PENDING; //Turn this schedule on
fuelSchedule6.schedulesSet++; //Increment the number of times this schedule has been set
interrupts();
FUEL6_TIMER_ENABLE();
}
else
{
//If the schedule is already running, we can set the next schedule so it is ready to go
//This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule
fuelSchedule6.nextStartCompare = FUEL6_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout);
fuelSchedule6.nextEndCompare = fuelSchedule6.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration);
fuelSchedule6.hasNextSchedule = true;
}
}
#endif
#if INJ_CHANNELS >= 7
//This uses timer
void setFuelSchedule7(unsigned long timeout, unsigned long duration)
{
if(fuelSchedule7.Status != RUNNING) //Check that we're not already part way through a schedule
{
//Callbacks no longer used, but retained for now:
//fuelSchedule4.StartCallback = startCallback;
//fuelSchedule4.EndCallback = endCallback;
fuelSchedule7.duration = duration;
//Need to check that the timeout doesn't exceed the overflow
uint16_t timeout_timer_compare;
if (timeout > MAX_TIMER_PERIOD) { timeout_timer_compare = uS_TO_TIMER_COMPARE( (MAX_TIMER_PERIOD - 1) ); } // If the timeout is >4x (Each tick represents 4uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking.
else { timeout_timer_compare = uS_TO_TIMER_COMPARE(timeout); } //Normal case
//The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set
noInterrupts();
fuelSchedule7.startCompare = FUEL7_COUNTER + timeout_timer_compare;
fuelSchedule7.endCompare = fuelSchedule6.startCompare + uS_TO_TIMER_COMPARE(duration);
FUEL7_COMPARE = fuelSchedule7.startCompare; //Use the C copmare unit of timer 3
fuelSchedule7.Status = PENDING; //Turn this schedule on
fuelSchedule7.schedulesSet++; //Increment the number of times this schedule has been set
interrupts();
FUEL7_TIMER_ENABLE();
}
else
{
//If the schedule is already running, we can set the next schedule so it is ready to go
//This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule
fuelSchedule7.nextStartCompare = FUEL7_COUNTER + uS_TO_TIMER_COMPARE(timeout);
fuelSchedule7.nextEndCompare = fuelSchedule7.nextStartCompare + uS_TO_TIMER_COMPARE(duration);
fuelSchedule7.hasNextSchedule = true;
}
}
#endif
#if INJ_CHANNELS >= 8
//This uses timer
void setFuelSchedule8(unsigned long timeout, unsigned long duration)
{
if(fuelSchedule8.Status != RUNNING) //Check that we're not already part way through a schedule
{
//Callbacks no longer used, but retained for now:
//fuelSchedule4.StartCallback = startCallback;
//fuelSchedule4.EndCallback = endCallback;
fuelSchedule8.duration = duration;
//Need to check that the timeout doesn't exceed the overflow
uint16_t timeout_timer_compare;
if (timeout > MAX_TIMER_PERIOD) { timeout_timer_compare = uS_TO_TIMER_COMPARE( (MAX_TIMER_PERIOD - 1) ); } // If the timeout is >4x (Each tick represents 4uS) the maximum allowed value of unsigned int (65535), the timer compare value will overflow when appliedcausing erratic behaviour such as erroneous sparking.
else { timeout_timer_compare = uS_TO_TIMER_COMPARE(timeout); } //Normal case
//The following must be enclosed in the noInterupts block to avoid contention caused if the relevant interrupt fires before the state is fully set
noInterrupts();
fuelSchedule8.startCompare = FUEL8_COUNTER + timeout_timer_compare;
fuelSchedule8.endCompare = fuelSchedule8.startCompare + uS_TO_TIMER_COMPARE(duration);
FUEL8_COMPARE = fuelSchedule8.startCompare; //Use the C copmare unit of timer 3
fuelSchedule8.Status = PENDING; //Turn this schedule on
fuelSchedule8.schedulesSet++; //Increment the number of times this schedule has been set
interrupts();
FUEL8_TIMER_ENABLE();
}
else
{
//If the schedule is already running, we can set the next schedule so it is ready to go
//This is required in cases of high rpm and high DC where there otherwise would not be enough time to set the schedule
fuelSchedule8.nextStartCompare = FUEL8_COUNTER + uS_TO_TIMER_COMPARE(timeout);
fuelSchedule8.nextEndCompare = fuelSchedule8.nextStartCompare + uS_TO_TIMER_COMPARE(duration);
fuelSchedule8.hasNextSchedule = true;
}
}
#endif
//Ignition schedulers use Timer 5
void setIgnitionSchedule1(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
{
@ -578,7 +761,7 @@ static inline void fuelSchedule1Interrupt() //Most ARM chips can simply call a f
if (fuelSchedule1.Status == PENDING) //Check to see if this schedule is turn on
{
//To use timer queue, change fuelShedule1 to timer3Aqueue[0];
if (configPage1.injLayout == INJ_SEMISEQUENTIAL) { openInjector1and4(); }
if (configPage2.injLayout == INJ_SEMISEQUENTIAL) { openInjector1and4(); }
else { openInjector1(); }
fuelSchedule1.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
FUEL1_COMPARE = fuelSchedule1.endCompare;
@ -586,7 +769,7 @@ static inline void fuelSchedule1Interrupt() //Most ARM chips can simply call a f
else if (fuelSchedule1.Status == RUNNING)
{
//timer3Aqueue[0]->EndCallback();
if (configPage1.injLayout == INJ_SEMISEQUENTIAL) { closeInjector1and4(); }
if (configPage2.injLayout == INJ_SEMISEQUENTIAL) { closeInjector1and4(); }
else { closeInjector1(); }
fuelSchedule1.Status = OFF; //Turn off the schedule
fuelSchedule1.schedulesSet = 0;
@ -615,7 +798,7 @@ static inline void fuelSchedule2Interrupt() //Most ARM chips can simply call a f
if (fuelSchedule2.Status == PENDING) //Check to see if this schedule is turn on
{
//fuelSchedule2.StartCallback();
if (configPage1.injLayout == INJ_SEMISEQUENTIAL) { openInjector2and3(); }
if (configPage2.injLayout == INJ_SEMISEQUENTIAL) { openInjector2and3(); }
else { openInjector2(); }
fuelSchedule2.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
FUEL2_COMPARE = fuelSchedule2.endCompare;
@ -623,7 +806,7 @@ static inline void fuelSchedule2Interrupt() //Most ARM chips can simply call a f
else if (fuelSchedule2.Status == RUNNING)
{
//fuelSchedule2.EndCallback();
if (configPage1.injLayout == INJ_SEMISEQUENTIAL) { closeInjector2and3(); }
if (configPage2.injLayout == INJ_SEMISEQUENTIAL) { closeInjector2and3(); }
else { closeInjector2(); }
fuelSchedule2.Status = OFF; //Turn off the schedule
fuelSchedule2.schedulesSet = 0;
@ -711,6 +894,41 @@ static inline void fuelSchedule4Interrupt() //Most ARM chips can simply call a f
}
}
#if (INJ_CHANNELS >= 6)
#if defined(CORE_AVR) //AVR chips use the ISR for this
ISR(TIMER4_COMPA_vect) //fuelSchedule6
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
static inline void fuelSchedule6Interrupt() //Most ARM chips can simply call a function
#endif
{
if (fuelSchedule6.Status == PENDING) //Check to see if this schedule is turn on
{
//fuelSchedule4.StartCallback();
openInjector6();
fuelSchedule6.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
FUEL6_COMPARE = fuelSchedule6.endCompare;
}
else if (fuelSchedule6.Status == RUNNING)
{
//fuelSchedule4.EndCallback();
closeInjector6();
fuelSchedule6.Status = OFF; //Turn off the schedule
fuelSchedule6.schedulesSet = 0;
//If there is a next schedule queued up, activate it
if(fuelSchedule6.hasNextSchedule == true)
{
FUEL6_COMPARE = fuelSchedule6.nextStartCompare;
fuelSchedule6.endCompare = fuelSchedule6.nextEndCompare;
fuelSchedule6.Status = PENDING;
fuelSchedule6.schedulesSet = 1;
fuelSchedule6.hasNextSchedule = false;
}
else { FUEL6_TIMER_DISABLE(); }
}
}
#endif
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
ISR(TIMER5_COMPA_vect) //ignitionSchedule1
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
@ -805,7 +1023,7 @@ static inline void ignitionSchedule3Interrupt() //Most ARM chips can simply call
}
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
#if defined(CORE_AVR) //AVR chips use the ISR for this
ISR(TIMER4_COMPA_vect) //ignitionSchedule4
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
static inline void ignitionSchedule4Interrupt() //Most ARM chips can simply call a function

View File

@ -68,7 +68,7 @@ static inline void instanteneousMAPReading()
if(initialisationComplete == true) { currentStatus.mapADC = ADC_FILTER(tempReading, ADCFILTER_MAP, currentStatus.mapADC); } //Very weak filter
else { currentStatus.mapADC = tempReading; } //Baro reading (No filter)
currentStatus.MAP = fastMap10Bit(currentStatus.mapADC, configPage1.mapMin, configPage1.mapMax); //Get the current MAP value
currentStatus.MAP = fastMap10Bit(currentStatus.mapADC, configPage2.mapMin, configPage2.mapMax); //Get the current MAP value
if(currentStatus.MAP < 0) { currentStatus.MAP = 0; } //Sanity check
}
@ -77,7 +77,7 @@ static inline void readMAP()
{
unsigned int tempReading;
//MAP Sampling system
switch(configPage1.mapSample)
switch(configPage2.mapSample)
{
case 0:
//Instantaneous MAP readings
@ -116,8 +116,8 @@ static inline void readMAP()
if( (MAPrunningValue != 0) && (MAPcount != 0) )
{
currentStatus.mapADC = ldiv(MAPrunningValue, MAPcount).quot;
currentStatus.MAP = fastMap10Bit(currentStatus.mapADC, configPage1.mapMin, configPage1.mapMax); //Get the current MAP value
//currentStatus.MAP = fastMap1023toX(currentStatus.mapADC, configPage1.mapMax);
currentStatus.MAP = fastMap10Bit(currentStatus.mapADC, configPage2.mapMin, configPage2.mapMax); //Get the current MAP value
//currentStatus.MAP = fastMap1023toX(currentStatus.mapADC, configPage2.mapMax);
if(currentStatus.MAP < 0) { currentStatus.MAP = 0; } //Sanity check
}
else { instanteneousMAPReading(); }
@ -152,7 +152,7 @@ static inline void readMAP()
{
//Reaching here means that the last cylce has completed and the MAP value should be calculated
currentStatus.mapADC = MAPrunningValue;
currentStatus.MAP = fastMap10Bit(currentStatus.mapADC, configPage1.mapMin, configPage1.mapMax); //Get the current MAP value
currentStatus.MAP = fastMap10Bit(currentStatus.mapADC, configPage2.mapMin, configPage2.mapMax); //Get the current MAP value
if(currentStatus.MAP < 0) { currentStatus.MAP = 0; } //Sanity check
MAPcurRev = currentStatus.startRevolutions; //Reset the current rev count
MAPrunningValue = 1023; //Reset the latest value so the next reading will always be lower
@ -181,9 +181,9 @@ void readTPS()
currentStatus.tpsADC = ADC_FILTER(tempTPS, ADCFILTER_TPS, currentStatus.tpsADC);
//Check that the ADC values fall within the min and max ranges (Should always be the case, but noise can cause these to fluctuate outside the defined range).
byte tempADC = currentStatus.tpsADC; //The tempADC value is used in order to allow TunerStudio to recover and redo the TPS calibration if this somehow gets corrupted
if (currentStatus.tpsADC < configPage1.tpsMin) { tempADC = configPage1.tpsMin; }
else if(currentStatus.tpsADC > configPage1.tpsMax) { tempADC = configPage1.tpsMax; }
currentStatus.TPS = map(tempADC, configPage1.tpsMin, configPage1.tpsMax, 0, 100); //Take the raw TPS ADC value and convert it into a TPS% based on the calibrated values
if (currentStatus.tpsADC < configPage2.tpsMin) { tempADC = configPage2.tpsMin; }
else if(currentStatus.tpsADC > configPage2.tpsMax) { tempADC = configPage2.tpsMax; }
currentStatus.TPS = map(tempADC, configPage2.tpsMin, configPage2.tpsMax, 0, 100); //Take the raw TPS ADC value and convert it into a TPS% based on the calibrated values
currentStatus.TPS_time = currentLoopTime;
}
@ -215,7 +215,7 @@ void readIAT()
void readBaro()
{
if ( configPage3.useExtBaro != 0 )
if ( configPage6.useExtBaro != 0 )
{
int tempReading;
// readings
@ -228,7 +228,7 @@ void readBaro()
currentStatus.baroADC = ADC_FILTER(tempReading, ADCFILTER_BARO, currentStatus.baroADC); //Very weak filter
currentStatus.baro = fastMap10Bit(currentStatus.baroADC, configPage1.baroMin, configPage1.baroMax); //Get the current MAP value
currentStatus.baro = fastMap10Bit(currentStatus.baroADC, configPage2.baroMin, configPage2.baroMax); //Get the current MAP value
}
}

View File

@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef UNIT_TEST // Scope guard for unit testing
#include <stdint.h> //https://developer.mbed.org/handbook/C-Data-Types
//************************************************
#include "speeduino.h"
@ -44,11 +46,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <FlexCAN.h>
#endif
struct config1 configPage1;
struct config2 configPage2;
struct config3 configPage3;
struct config4 configPage4; //Done
struct config6 configPage6;
struct config9 configPage9;
struct config10 configPage10;
struct config11 configPage11;
/*
struct config2 configPage1;
struct config6 configPage3;
struct config9 configPage9;
struct config10 configPage11;
*/
uint16_t req_fuel_uS, inj_opentime_uS;
uint16_t staged_req_fuel_mult_pri;
@ -102,11 +110,17 @@ int channel2IgnDegrees; //The number of crank degrees until cylinder 2 (and 5/6/
int channel3IgnDegrees; //The number of crank degrees until cylinder 3 (and 5/6/7/8) is at TDC
int channel4IgnDegrees; //The number of crank degrees until cylinder 4 (and 5/6/7/8) is at TDC
int channel5IgnDegrees; //The number of crank degrees until cylinder 5 is at TDC
int channel6IgnDegrees; //The number of crank degrees until cylinder 6 is at TDC
int channel7IgnDegrees; //The number of crank degrees until cylinder 7 is at TDC
int channel8IgnDegrees; //The number of crank degrees until cylinder 8 is at TDC
int channel1InjDegrees; //The number of crank degrees until cylinder 1 is at TDC (This is obviously 0 for virtually ALL engines, but there's some weird ones)
int channel2InjDegrees; //The number of crank degrees until cylinder 2 (and 5/6/7/8) is at TDC
int channel3InjDegrees; //The number of crank degrees until cylinder 3 (and 5/6/7/8) is at TDC
int channel4InjDegrees; //The number of crank degrees until cylinder 4 (and 5/6/7/8) is at TDC
int channel5InjDegrees; //The number of crank degrees until cylinder 5 is at TDC
int channel6InjDegrees; //The number of crank degrees until cylinder 6 is at TDC
int channel7InjDegrees; //The number of crank degrees until cylinder 7 is at TDC
int channel8InjDegrees; //The number of crank degrees until cylinder 8 is at TDC
//These are the functions the get called to begin and end the ignition coil charging. They are required for the various spark output modes
void (*ign1StartFunction)();
@ -147,6 +161,10 @@ void setup()
loadConfig();
doUpdates(); //Check if any data items need updating (Occurs ith firmware updates)
//Always start with a clean slate on the bootloader capabilities level
//This should be 0 until we hear otherwise from the 16u2
configPage4.bootloaderCaps = 0;
Serial.begin(115200);
if (configPage10.enable_canbus == 1) { CANSerial.begin(115200); }
@ -165,52 +183,65 @@ void setup()
//Repoint the 2D table structs to the config pages that were just loaded
taeTable.valueSize = SIZE_BYTE; //Set this table to use byte values
taeTable.xSize = 4;
taeTable.values = configPage2.taeValues;
taeTable.axisX = configPage2.taeBins;
taeTable.values = configPage4.taeValues;
taeTable.axisX = configPage4.taeBins;
WUETable.valueSize = SIZE_BYTE; //Set this table to use byte values
WUETable.xSize = 10;
WUETable.values = configPage1.wueValues;
WUETable.axisX = configPage2.wueBins;
WUETable.values = configPage2.wueValues;
WUETable.axisX = configPage4.wueBins;
crankingEnrichTable.valueSize = SIZE_BYTE;
crankingEnrichTable.xSize = 4;
crankingEnrichTable.values = configPage11.crankingEnrichValues;
crankingEnrichTable.axisX = configPage11.crankingEnrichBins;
crankingEnrichTable.values = configPage10.crankingEnrichValues;
crankingEnrichTable.axisX = configPage10.crankingEnrichBins;
dwellVCorrectionTable.valueSize = SIZE_BYTE;
dwellVCorrectionTable.xSize = 6;
dwellVCorrectionTable.values = configPage2.dwellCorrectionValues;
dwellVCorrectionTable.axisX = configPage3.voltageCorrectionBins;
dwellVCorrectionTable.values = configPage4.dwellCorrectionValues;
dwellVCorrectionTable.axisX = configPage6.voltageCorrectionBins;
injectorVCorrectionTable.valueSize = SIZE_BYTE;
injectorVCorrectionTable.xSize = 6;
injectorVCorrectionTable.values = configPage3.injVoltageCorrectionValues;
injectorVCorrectionTable.axisX = configPage3.voltageCorrectionBins;
injectorVCorrectionTable.values = configPage6.injVoltageCorrectionValues;
injectorVCorrectionTable.axisX = configPage6.voltageCorrectionBins;
IATDensityCorrectionTable.valueSize = SIZE_BYTE;
IATDensityCorrectionTable.xSize = 9;
IATDensityCorrectionTable.values = configPage3.airDenRates;
IATDensityCorrectionTable.axisX = configPage3.airDenBins;
IATDensityCorrectionTable.values = configPage6.airDenRates;
IATDensityCorrectionTable.axisX = configPage6.airDenBins;
IATRetardTable.valueSize = SIZE_BYTE;
IATRetardTable.xSize = 6;
IATRetardTable.values = configPage2.iatRetValues;
IATRetardTable.axisX = configPage2.iatRetBins;
IATRetardTable.values = configPage4.iatRetValues;
IATRetardTable.axisX = configPage4.iatRetBins;
rotarySplitTable.valueSize = SIZE_BYTE;
rotarySplitTable.xSize = 8;
rotarySplitTable.values = configPage11.rotarySplitValues;
rotarySplitTable.axisX = configPage11.rotarySplitBins;
rotarySplitTable.values = configPage10.rotarySplitValues;
rotarySplitTable.axisX = configPage10.rotarySplitBins;
flexFuelTable.valueSize = SIZE_BYTE;
flexFuelTable.xSize = 6;
flexFuelTable.values = configPage10.flexFuelAdj;
flexFuelTable.axisX = configPage10.flexFuelBins;
flexAdvTable.valueSize = SIZE_BYTE;
flexAdvTable.xSize = 6;
flexAdvTable.values = configPage10.flexAdvAdj;
flexAdvTable.axisX = configPage10.flexAdvBins;
flexBoostTable.valueSize = SIZE_INT;
flexBoostTable.xSize = 6;
flexBoostTable.values16 = configPage10.flexBoostAdj;
flexBoostTable.axisX = configPage10.flexBoostBins;
//Setup the calibration tables
loadCalibration();
//Set the pin mappings
if((configPage1.pinMapping == 0) || (configPage1.pinMapping > BOARD_NR_GPIO_PINS))
if(configPage2.pinMapping > BOARD_NR_GPIO_PINS)
{
//First time running on this board
setPinMapping(3); //Force board to v0.4
configPage1.flexEnabled = false; //Have to disable flex. If this isn't done and the wrong flex pin is interrupt attached below, system can hang.
configPage2.flexEnabled = false; //Have to disable flex. If this isn't done and the wrong flex pin is interrupt attached below, system can hang.
}
else { setPinMapping(configPage1.pinMapping); }
else { setPinMapping(configPage2.pinMapping); }
//Need to check early on whether the coil charging is inverted. If this is not set straight away it can cause an unwanted spark at bootup
if(configPage2.IgInv == 1) { coilHIGH = LOW, coilLOW = HIGH; }
if(configPage4.IgInv == 1) { coilHIGH = LOW, coilLOW = HIGH; }
else { coilHIGH = HIGH, coilLOW = LOW; }
endCoil1Charge();
endCoil2Charge();
@ -239,7 +270,7 @@ void setup()
//Lookup the current MAP reading for barometric pressure
instanteneousMAPReading();
//barometric reading can be taken from either an external sensor if enabled, or simply by using the initial MAP value
if ( configPage3.useExtBaro != 0 )
if ( configPage6.useExtBaro != 0 )
{
readBaro();
EEPROM.update(EEPROM_LAST_BARO, currentStatus.baro);
@ -266,19 +297,19 @@ void setup()
}
//Check whether the flex sensor is enabled and if so, attach an interupt for it
if(configPage1.flexEnabled)
if(configPage2.flexEnabled)
{
attachInterrupt(digitalPinToInterrupt(pinFlex), flexPulse, RISING);
currentStatus.ethanolPct = 0;
}
//Once the configs have been loaded, a number of one time calculations can be completed
req_fuel_uS = configPage1.reqFuel * 100; //Convert to uS and an int. This is the only variable to be used in calculations
inj_opentime_uS = configPage1.injOpen * 100; //Injector open time. Comes through as ms*10 (Eg 15.5ms = 155).
req_fuel_uS = configPage2.reqFuel * 100; //Convert to uS and an int. This is the only variable to be used in calculations
inj_opentime_uS = configPage2.injOpen * 100; //Injector open time. Comes through as ms*10 (Eg 15.5ms = 155).
if(configPage11.stagingEnabled == true)
if(configPage10.stagingEnabled == true)
{
uint32_t totalInjector = configPage11.stagedInjSizePri + configPage11.stagedInjSizeSec;
uint32_t totalInjector = configPage10.stagedInjSizePri + configPage10.stagedInjSizeSec;
/*
These values are a percentage of the req_fuel value that would be required for each injector channel to deliver that much fuel.
Eg:
@ -289,8 +320,8 @@ void setup()
staged_req_fuel_mult_pri = 300% (The primary injectors would have to run 3x the overall PW in order to be the equivalent of the full 750cc capacity
staged_req_fuel_mult_sec = 150% (The secondary injectors would have to run 1.5x the overall PW in order to be the equivalent of the full 750cc capacity
*/
staged_req_fuel_mult_pri = (100 * totalInjector) / configPage11.stagedInjSizePri;
staged_req_fuel_mult_sec = (100 * totalInjector) / configPage11.stagedInjSizeSec;
staged_req_fuel_mult_pri = (100 * totalInjector) / configPage10.stagedInjSizePri;
staged_req_fuel_mult_sec = (100 * totalInjector) / configPage10.stagedInjSizeSec;
}
//Begin the main crank trigger interrupt pin setup
@ -303,9 +334,9 @@ void setup()
currentStatus.startRevolutions = 0;
currentStatus.flatShiftingHard = false;
currentStatus.launchingHard = false;
currentStatus.crankRPM = ((unsigned int)configPage2.crankRPM * 100); //Crank RPM limit (Saves us calculating this over and over again. It's updated once per second in timers.ino)
currentStatus.crankRPM = ((unsigned int)configPage4.crankRPM * 100); //Crank RPM limit (Saves us calculating this over and over again. It's updated once per second in timers.ino)
triggerFilterTime = 0; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise. This is simply a default value, the actual values are set in the setup() functinos of each decoder
dwellLimit_uS = (1000 * configPage2.dwellLimit);
dwellLimit_uS = (1000 * configPage4.dwellLimit);
noInterrupts();
initialiseTriggers();
@ -320,7 +351,7 @@ void setup()
mainLoopCount = 0;
//Calculate the number of degrees between cylinders
switch (configPage1.nCylinders) {
switch (configPage2.nCylinders) {
case 1:
channel1IgnDegrees = 0;
channel1InjDegrees = 0;
@ -331,21 +362,21 @@ void setup()
case 2:
channel1IgnDegrees = 0;
maxIgnOutputs = 2;
if (configPage1.engineType == EVEN_FIRE )
if (configPage2.engineType == EVEN_FIRE )
{
channel2IgnDegrees = 180;
}
else { channel2IgnDegrees = configPage1.oddfire2; }
else { channel2IgnDegrees = configPage2.oddfire2; }
//For alternating injection, the squirt occurs at different times for each channel
if(configPage1.injLayout == INJ_SEMISEQUENTIAL || configPage1.injLayout == INJ_PAIRED)
if(configPage2.injLayout == INJ_SEMISEQUENTIAL || configPage2.injLayout == INJ_PAIRED)
{
channel1InjDegrees = 0;
channel2InjDegrees = channel2IgnDegrees; //Set to the same as the ignition degrees (Means there's no need for another if to check for oddfire)
if (!configPage1.injTiming) { channel1InjDegrees = channel2InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
if (!configPage2.injTiming) { channel1InjDegrees = channel2InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
}
else if (configPage1.injLayout == INJ_SEQUENTIAL)
else if (configPage2.injLayout == INJ_SEQUENTIAL)
{
channel1InjDegrees = 0;
channel2InjDegrees = channel2IgnDegrees;
@ -361,9 +392,9 @@ void setup()
case 3:
channel1IgnDegrees = 0;
maxIgnOutputs = 3;
if (configPage1.engineType == EVEN_FIRE )
if (configPage2.engineType == EVEN_FIRE )
{
if(configPage2.sparkMode == IGN_MODE_SEQUENTIAL)
if(configPage4.sparkMode == IGN_MODE_SEQUENTIAL)
{
channel2IgnDegrees = 240;
channel3IgnDegrees = 480;
@ -378,20 +409,20 @@ void setup()
}
else
{
channel2IgnDegrees = configPage1.oddfire2;
channel3IgnDegrees = configPage1.oddfire3;
channel2IgnDegrees = configPage2.oddfire2;
channel3IgnDegrees = configPage2.oddfire3;
}
//For alternatiing injection, the squirt occurs at different times for each channel
if(configPage1.injLayout == INJ_SEMISEQUENTIAL || configPage1.injLayout == INJ_PAIRED)
if(configPage2.injLayout == INJ_SEMISEQUENTIAL || configPage2.injLayout == INJ_PAIRED)
{
channel1InjDegrees = 0;
channel2InjDegrees = 120;
channel3InjDegrees = 240;
if (!configPage1.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
if (!configPage2.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
}
else if (configPage1.injLayout == INJ_SEQUENTIAL)
else if (configPage2.injLayout == INJ_SEQUENTIAL)
{
channel1InjDegrees = 0;
channel2InjDegrees = 240;
@ -407,11 +438,11 @@ void setup()
case 4:
channel1IgnDegrees = 0;
maxIgnOutputs = 2; //Default value for 4 cylinder, may be changed below
if (configPage1.engineType == EVEN_FIRE )
if (configPage2.engineType == EVEN_FIRE )
{
channel2IgnDegrees = 180;
if(configPage2.sparkMode == IGN_MODE_SEQUENTIAL)
if(configPage4.sparkMode == IGN_MODE_SEQUENTIAL)
{
channel3IgnDegrees = 360;
channel4IgnDegrees = 540;
@ -419,7 +450,7 @@ void setup()
CRANK_ANGLE_MAX_IGN = 720;
maxIgnOutputs = 4;
}
else if(configPage2.sparkMode == IGN_MODE_ROTARY)
else if(configPage4.sparkMode == IGN_MODE_ROTARY)
{
//Rotary uses the ign 3 and 4 schedules for the trailing spark. They are offset from the ign 1 and 2 channels respectively and so use the same degrees as them
channel3IgnDegrees = 0;
@ -428,20 +459,21 @@ void setup()
}
else
{
channel2IgnDegrees = configPage1.oddfire2;
channel3IgnDegrees = configPage1.oddfire3;
channel4IgnDegrees = configPage1.oddfire4;
channel2IgnDegrees = configPage2.oddfire2;
channel3IgnDegrees = configPage2.oddfire3;
channel4IgnDegrees = configPage2.oddfire4;
maxIgnOutputs = 4;
}
//For alternatiing injection, the squirt occurs at different times for each channel
if(configPage1.injLayout == INJ_SEMISEQUENTIAL || configPage1.injLayout == INJ_PAIRED)
if(configPage2.injLayout == INJ_SEMISEQUENTIAL || configPage2.injLayout == INJ_PAIRED)
{
channel1InjDegrees = 0;
channel2InjDegrees = 180;
if (!configPage1.injTiming) { channel1InjDegrees = channel2InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
if (!configPage2.injTiming) { channel1InjDegrees = channel2InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
}
else if (configPage1.injLayout == INJ_SEQUENTIAL)
else if (configPage2.injLayout == INJ_SEQUENTIAL)
{
channel1InjDegrees = 0;
channel2InjDegrees = 180;
@ -456,7 +488,7 @@ void setup()
}
//Check if injector staging is enabled
if(configPage11.stagingEnabled == true)
if(configPage10.stagingEnabled == true)
{
channel3InjEnabled = true;
channel4InjEnabled = true;
@ -476,7 +508,7 @@ void setup()
channel5IgnDegrees = 288;
maxIgnOutputs = 4; //Only 4 actual outputs, so that's all that can be cut
if(configPage2.sparkMode == IGN_MODE_SEQUENTIAL)
if(configPage4.sparkMode == IGN_MODE_SEQUENTIAL)
{
channel2IgnDegrees = 144;
channel3IgnDegrees = 288;
@ -487,7 +519,7 @@ void setup()
}
//For alternatiing injection, the squirt occurs at different times for each channel
if(configPage1.injLayout == INJ_SEMISEQUENTIAL || configPage1.injLayout == INJ_PAIRED)
if(configPage2.injLayout == INJ_SEMISEQUENTIAL || configPage2.injLayout == INJ_PAIRED)
{
channel1InjDegrees = 0;
channel2InjDegrees = 72;
@ -495,7 +527,7 @@ void setup()
channel4InjDegrees = 216;
channel5InjDegrees = 288;
}
else if (configPage1.injLayout == INJ_SEQUENTIAL)
else if (configPage2.injLayout == INJ_SEQUENTIAL)
{
channel1InjDegrees = 0;
channel2InjDegrees = 144;
@ -505,7 +537,7 @@ void setup()
CRANK_ANGLE_MAX_INJ = 720;
}
if (!configPage1.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = channel4InjDegrees = channel5InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
if (!configPage2.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = channel4InjDegrees = channel5InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
channel1InjEnabled = true;
channel2InjEnabled = true;
@ -522,9 +554,9 @@ void setup()
channel3InjDegrees = 240;
maxIgnOutputs = 3;
if (!configPage1.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
if (!configPage2.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
configPage1.injLayout = 0; //This is a failsafe. We can never run semi-sequential with more than 4 cylinders
configPage2.injLayout = 0; //This is a failsafe. We can never run semi-sequential with more than 4 cylinders
channel1InjEnabled = true;
channel2InjEnabled = true;
@ -537,9 +569,9 @@ void setup()
channel4IgnDegrees = channel4InjDegrees = 270;
maxIgnOutputs = 4;
if (!configPage1.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = channel4InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
if (!configPage2.injTiming) { channel1InjDegrees = channel2InjDegrees = channel3InjDegrees = channel4InjDegrees = 0; } //For simultaneous, all squirts happen at the same time
configPage1.injLayout = 0; //This is a failsafe. We can never run semi-sequential with more than 4 cylinders
configPage2.injLayout = 0; //This is a failsafe. We can never run semi-sequential with more than 4 cylinders
channel1InjEnabled = true;
channel2InjEnabled = true;
@ -554,7 +586,7 @@ void setup()
if(CRANK_ANGLE_MAX_IGN == CRANK_ANGLE_MAX_INJ) { CRANK_ANGLE_MAX = CRANK_ANGLE_MAX_IGN; } //If both the injector max and ignition max angles are the same, make the overall system max this value
switch(configPage2.sparkMode)
switch(configPage4.sparkMode)
{
case IGN_MODE_WASTED:
//Wasted Spark (Normal mode)
@ -587,7 +619,7 @@ void setup()
case IGN_MODE_WASTEDCOP:
//Wasted COP mode. Ignition channels 1&3 and 2&4 are paired together
//This is not a valid mode for >4 cylinders
if( configPage1.nCylinders <= 4 )
if( configPage2.nCylinders <= 4 )
{
ign1StartFunction = beginCoil1and3Charge;
ign1EndFunction = endCoil1and3Charge;
@ -629,7 +661,7 @@ void setup()
break;
case IGN_MODE_ROTARY:
if(configPage11.rotaryType == ROTARY_IGN_FC)
if(configPage10.rotaryType == ROTARY_IGN_FC)
{
ign1StartFunction = beginCoil1Charge;
ign1EndFunction = endCoil1Charge;
@ -665,10 +697,11 @@ void setup()
fuelPumpOn = true;
interrupts();
//Perform the priming pulses. Set these to run at an arbitrary time in the future (100us). The prime pulse value is in ms*10, so need to multiple by 100 to get to uS
setFuelSchedule1(100, (unsigned long)(configPage1.primePulse * 100));
setFuelSchedule2(100, (unsigned long)(configPage1.primePulse * 100));
setFuelSchedule3(100, (unsigned long)(configPage1.primePulse * 100));
setFuelSchedule4(100, (unsigned long)(configPage1.primePulse * 100));
setFuelSchedule1(100, (unsigned long)(configPage2.primePulse * 100));
setFuelSchedule2(100, (unsigned long)(configPage2.primePulse * 100));
setFuelSchedule3(100, (unsigned long)(configPage2.primePulse * 100));
setFuelSchedule4(100, (unsigned long)(configPage2.primePulse * 100));
initialisationComplete = true;
digitalWrite(LED_BUILTIN, HIGH);
}
@ -705,7 +738,7 @@ void loop()
#endif
//Displays currently disabled
// if (configPage1.displayType && (mainLoopCount & 255) == 1) { updateDisplay();}
// if (configPage2.displayType && (mainLoopCount & 255) == 1) { updateDisplay();}
previousLoopTime = currentLoopTime;
currentLoopTime = micros();
@ -770,21 +803,21 @@ void loop()
//Check for launching/flat shift (clutch) can be done around here too
previousClutchTrigger = clutchTrigger;
if(configPage3.launchHiLo) { clutchTrigger = digitalRead(pinLaunch); }
if(configPage6.launchHiLo) { clutchTrigger = digitalRead(pinLaunch); }
else { clutchTrigger = !digitalRead(pinLaunch); }
if(previousClutchTrigger != clutchTrigger) { currentStatus.clutchEngagedRPM = currentStatus.RPM; }
if (configPage3.launchEnabled && clutchTrigger && (currentStatus.clutchEngagedRPM < ((unsigned int)(configPage3.flatSArm) * 100)) && (currentStatus.RPM > ((unsigned int)(configPage3.lnchHardLim) * 100)) ) { currentStatus.launchingHard = true; BIT_SET(currentStatus.spark, BIT_SPARK_HLAUNCH); } //HardCut rev limit for 2-step launch control.
if (configPage6.launchEnabled && clutchTrigger && (currentStatus.clutchEngagedRPM < ((unsigned int)(configPage6.flatSArm) * 100)) && (currentStatus.RPM > ((unsigned int)(configPage6.lnchHardLim) * 100)) && (currentStatus.TPS >= configPage10.lnchCtrlTPS) ) { currentStatus.launchingHard = true; BIT_SET(currentStatus.spark, BIT_SPARK_HLAUNCH); } //HardCut rev limit for 2-step launch control.
else { currentStatus.launchingHard = false; BIT_CLEAR(currentStatus.spark, BIT_SPARK_HLAUNCH); }
if(configPage3.flatSEnable && clutchTrigger && (currentStatus.RPM > ((unsigned int)(configPage3.flatSArm) * 100)) && (currentStatus.RPM > currentStatus.clutchEngagedRPM) ) { currentStatus.flatShiftingHard = true; }
if(configPage6.flatSEnable && clutchTrigger && (currentStatus.RPM > ((unsigned int)(configPage6.flatSArm) * 100)) && (currentStatus.RPM > currentStatus.clutchEngagedRPM) ) { currentStatus.flatShiftingHard = true; }
else { currentStatus.flatShiftingHard = false; }
//Boost cutoff is very similar to launchControl, but with a check against MAP rather than a switch
if(configPage3.boostCutType && currentStatus.MAP > (configPage3.boostLimit * 2) ) //The boost limit is divided by 2 to allow a limit up to 511kPa
if(configPage6.boostCutType && currentStatus.MAP > (configPage6.boostLimit * 2) ) //The boost limit is divided by 2 to allow a limit up to 511kPa
{
switch(configPage3.boostCutType)
switch(configPage6.boostCutType)
{
case 1:
BIT_SET(currentStatus.spark, BIT_SPARK_BOOSTCUT);
@ -833,18 +866,18 @@ void loop()
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //ATmega2561 does not have Serial3
//if Can interface is enabled then check for external data requests.
if (configPage10.enable_candata_in) //if external data input is enabled
if (configPage9.enable_candata_in) //if external data input is enabled
{
if (configPage10.enable_canbus == 1) // megas only support can via secondary serial
if (configPage9.enable_canbus == 1) // megas only support can via secondary serial
{
for (byte caninChan = 0; caninChan <16 ; caninChan++)
{
currentStatus.current_caninchannel = caninChan;
//currentStatus.canin[14] = currentStatus.current_caninchannel;
currentStatus.canin[13] = ((configPage10.caninput_source_can_address[currentStatus.current_caninchannel]&2047)+0x100);
if (BIT_CHECK(configPage10.caninput_sel,currentStatus.current_caninchannel)) //if current input channel bit is enabled
currentStatus.canin[13] = ((configPage9.caninput_source_can_address[currentStatus.current_caninchannel]&2047)+0x100);
if (BIT_CHECK(configPage9.caninput_sel,currentStatus.current_caninchannel)) //if current input channel bit is enabled
{
sendCancommand(2,0,currentStatus.current_caninchannel,0,((configPage10.caninput_source_can_address[currentStatus.current_caninchannel]&2047)+0x100));
sendCancommand(2,0,currentStatus.current_caninchannel,0,((configPage9.caninput_source_can_address[currentStatus.current_caninchannel]&2047)+0x100));
//send an R command for data from caninput_source_address[currentStatus.current_caninchannel]
}
}
@ -853,20 +886,20 @@ void loop()
#elif defined(CORE_STM32) || defined(CORE_TEENSY)
//if serial3io is enabled then check for serial3 requests.
if (configPage10.enable_candata_in)
if (configPage9.enable_candata_in)
{
for (byte caninChan = 0; caninChan <16 ; caninChan++)
{
currentStatus.current_caninchannel == caninChan;
if (BIT_CHECK(configPage10.caninput_sel,currentStatus.current_caninchannel)) //if current input channel is enabled
currentStatus.current_caninchannel = caninChan;
if (BIT_CHECK(configPage9.caninput_sel,currentStatus.current_caninchannel)) //if current input channel is enabled
{
if (configPage10.enable_canbus == 1) //can via secondary serial
if (configPage9.enable_canbus == 1) //can via secondary serial
{
sendCancommand(2,0,currentStatus.current_caninchannel,0,((configPage10.caninput_source_can_address[currentStatus.current_caninchannel]&2047)+256)); //send an R command for data from paramgroup[currentStatus.current_caninchannel]
sendCancommand(2,0,currentStatus.current_caninchannel,0,((configPage9.caninput_source_can_address[currentStatus.current_caninchannel]&2047)+256)); //send an R command for data from paramgroup[currentStatus.current_caninchannel]
}
else if (configPage10.enable_canbus == 2) // can via internal can module
else if (configPage9.enable_canbus == 2) // can via internal can module
{
sendCancommand(3,configPage10.speeduino_tsCanId,currentStatus.current_caninchannel,0,configPage10.caninput_source_can_address[currentStatus.current_caninchannel]); //send via localcanbus the command for data from paramgroup[currentStatus.current_caninchannel]
sendCancommand(3,configPage9.speeduino_tsCanId,currentStatus.current_caninchannel,0,configPage9.caninput_source_can_address[currentStatus.current_caninchannel]); //send via localcanbus the command for data from paramgroup[currentStatus.current_caninchannel]
}
}
}
@ -881,13 +914,13 @@ void loop()
readBaro(); //Infrequent baro readings are not an issue.
}
if(configPage3.iacAlgorithm == IAC_ALGORITHM_STEP_OL || configPage3.iacAlgorithm == IAC_ALGORITHM_STEP_CL) { idleControl(); } //Run idlecontrol every loop for stepper idle.
if(configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OL || configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_CL) { idleControl(); } //Run idlecontrol every loop for stepper idle.
//Always check for sync
//Main loop runs within this clause
if (currentStatus.hasSync && (currentStatus.RPM > 0))
{
if(currentStatus.startRevolutions >= configPage2.StgCycles) { ignitionOn = true; fuelOn = true; } //Enable the fuel and ignition, assuming staging revolutions are complete
if(currentStatus.startRevolutions >= configPage4.StgCycles) { ignitionOn = true; fuelOn = true; } //Enable the fuel and ignition, assuming staging revolutions are complete
//If it is, check is we're running or cranking
if(currentStatus.RPM > currentStatus.crankRPM) //Crank RPM stored in byte as RPM / 100
{
@ -896,7 +929,7 @@ void loop()
if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
{
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_CRANK); //clears the engine cranking bit
if(configPage2.ignBypassEnabled) { digitalWrite(pinIgnBypass, HIGH); }
if(configPage4.ignBypassEnabled) { digitalWrite(pinIgnBypass, HIGH); }
}
}
else
@ -904,7 +937,7 @@ void loop()
BIT_SET(currentStatus.engine, BIT_ENGINE_CRANK);
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_RUN);
currentStatus.runSecs = 0; //We're cranking (hopefully), so reset the engine run time to prompt ASE.
if(configPage2.ignBypassEnabled) { digitalWrite(pinIgnBypass, LOW); }
if(configPage4.ignBypassEnabled) { digitalWrite(pinIgnBypass, LOW); }
}
//END SETTING STATUSES
//-----------------------------------------------------------------------------------------------------
@ -913,7 +946,7 @@ void loop()
//Calculate an injector pulsewidth from the VE
currentStatus.corrections = correctionsFuel();
lastAdvance = currentStatus.advance; //Store the previous advance value
if (configPage1.algorithm == LOAD_SOURCE_MAP) //Check which fuelling algorithm is being used
if (configPage2.algorithm == LOAD_SOURCE_MAP) //Check which fuelling algorithm is being used
{
//Speed Density
currentStatus.VE = get3DTableValue(&fuelTable, currentStatus.MAP, currentStatus.RPM); //Perform lookup into fuel map for RPM vs MAP value
@ -931,14 +964,32 @@ void loop()
int injector1StartAngle = 0;
int injector2StartAngle = 0;
int injector3StartAngle = 0; //Currently used for 3 cylinder only
int injector4StartAngle = 0; //Not used until sequential gets written
int injector3StartAngle = 0;
int injector4StartAngle = 0;
int injector5StartAngle = 0; //For 5 cylinder testing
#if INJ_CHANNELS >= 6
int injector6StartAngle = 0;
#endif
#if INJ_CHANNELS >= 7
int injector7StartAngle = 0;
#endif
#if INJ_CHANNELS >= 8
int injector8StartAngle = 0;
#endif
int ignition1StartAngle = 0;
int ignition2StartAngle = 0;
int ignition3StartAngle = 0;
int ignition4StartAngle = 0;
int ignition5StartAngle = 0;
#if IGN_CHANNELS >= 6
int ignition6StartAngle = 0;
#endif
#if IGN_CHANNELS >= 7
int ignition7StartAngle = 0;
#endif
#if IGN_CHANNELS >= 8
int ignition8StartAngle = 0;
#endif
//These are used for comparisons on channels above 1 where the starting angle (for injectors or ignition) can be less than a single loop time
//(Don't ask why this is needed, it will break your head)
int tempCrankAngle;
@ -956,14 +1007,14 @@ void loop()
{
deltaToothCount = toothCurrentCount;
int angle1, angle2; //These represent the crank angles that are travelled for the last 2 pulses
if(configPage2.TrigPattern == 4)
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(configPage2.TrigPattern == 0)
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; }
@ -1004,18 +1055,18 @@ void loop()
}
//Check that the duty cycle of the chosen pulsewidth isn't too high.
unsigned long pwLimit = percentage(configPage1.dutyLim, revolutionTime); //The pulsewidth limit is determined to be the duty cycle limit (Eg 85%) by the total time it takes to perform 1 revolution
unsigned long pwLimit = percentage(configPage2.dutyLim, revolutionTime); //The pulsewidth limit is determined to be the duty cycle limit (Eg 85%) by the total time it takes to perform 1 revolution
if (CRANK_ANGLE_MAX_INJ == 720) { pwLimit = pwLimit * 2; } //For sequential, the maximum pulse time is double (2 revolutions). Wouldn't work for 2 stroke...
//Apply the pwLimit if staging is dsiabled and engine is not cranking
if( (!BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) && configPage11.stagingEnabled == false) { if (currentStatus.PW1 > pwLimit) { currentStatus.PW1 = pwLimit; } }
if( (!BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) && configPage10.stagingEnabled == false) { if (currentStatus.PW1 > pwLimit) { currentStatus.PW1 = pwLimit; } }
//Calculate staging pulsewidths if used
if(configPage11.stagingEnabled == true)
if(configPage10.stagingEnabled == true)
{
//Scale the 'full' pulsewidth by each of the injector capacities
uint32_t tempPW1 = ((unsigned long)currentStatus.PW1 * staged_req_fuel_mult_pri) / 100;
if(configPage11.stagingMode == STAGING_MODE_TABLE)
if(configPage10.stagingMode == STAGING_MODE_TABLE)
{
uint32_t tempPW3 = ((unsigned long)currentStatus.PW1 * staged_req_fuel_mult_sec) / 100; //This is ONLY needed in in table mode. Auto mode only calculates the difference.
@ -1025,7 +1076,7 @@ void loop()
if(stagingSplit > 0) { currentStatus.PW3 = (stagingSplit * tempPW3) / 100; }
else { currentStatus.PW3 = 0; }
}
else if(configPage11.stagingMode == STAGING_MODE_AUTO)
else if(configPage10.stagingMode == STAGING_MODE_AUTO)
{
currentStatus.PW1 = tempPW1;
//If automatic mode, the primary injectors are used all the way up to their limit (COnfigured by the pulsewidth limit setting)
@ -1045,53 +1096,53 @@ void loop()
currentStatus.PW4 = currentStatus.PW3;
}
//If staging is off, all the pulse widths are set the same (Sequential adjustments will be made below)
else { currentStatus.PW2 = currentStatus.PW3 = currentStatus.PW4 = currentStatus.PW1; } // Initial state is for all pulsewidths to be the same (This gets changed below)
else { currentStatus.PW2 = currentStatus.PW3 = currentStatus.PW4 = currentStatus.PW5 = currentStatus.PW6 = currentStatus.PW7 = currentStatus.PW1; } // Initial state is for all pulsewidths to be the same (This gets changed below)
//***********************************************************************************************
//BEGIN INJECTION TIMING
//Determine next firing angles
if(!configPage1.indInjAng) {configPage1.inj4Ang = configPage1.inj3Ang = configPage1.inj2Ang = configPage1.inj1Ang;} //Forcing all injector close angles to be the same.
if(!configPage2.indInjAng) {configPage2.inj4Ang = configPage2.inj3Ang = configPage2.inj2Ang = configPage2.inj1Ang;} //Forcing all injector close angles to be the same.
int PWdivTimerPerDegree = div(currentStatus.PW1, timePerDegree).quot; //How many crank degrees the calculated PW will take at the current speed
injector1StartAngle = configPage1.inj1Ang - ( PWdivTimerPerDegree ); //This is a little primitive, but is based on the idea that all fuel needs to be delivered before the inlet valve opens. See http://www.extraefi.co.uk/sequential_fuel.html for more detail
injector1StartAngle = configPage2.inj1Ang - ( PWdivTimerPerDegree ); //This is a little primitive, but is based on the idea that all fuel needs to be delivered before the inlet valve opens. See http://www.extraefi.co.uk/sequential_fuel.html for more detail
if(injector1StartAngle < 0) {injector1StartAngle += CRANK_ANGLE_MAX_INJ;}
if(injector1StartAngle > CRANK_ANGLE_MAX_INJ) {injector1StartAngle -= CRANK_ANGLE_MAX_INJ;}
//Repeat the above for each cylinder
switch (configPage1.nCylinders)
switch (configPage2.nCylinders)
{
//2 cylinders
case 2:
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
injector2StartAngle = (configPage2.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
if(injector2StartAngle < 0) {injector2StartAngle += CRANK_ANGLE_MAX_INJ;}
break;
//3 cylinders
case 3:
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
injector2StartAngle = (configPage2.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
if(injector2StartAngle < 0) {injector2StartAngle += CRANK_ANGLE_MAX_INJ;}
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
injector3StartAngle = (configPage2.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
if(injector3StartAngle < 0) {injector3StartAngle += CRANK_ANGLE_MAX_INJ;}
break;
//4 cylinders
case 4:
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
injector2StartAngle = (configPage2.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
if(injector2StartAngle < 0) {injector2StartAngle += CRANK_ANGLE_MAX_INJ;}
if(configPage1.injLayout == INJ_SEQUENTIAL)
if(configPage2.injLayout == INJ_SEQUENTIAL)
{
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
injector3StartAngle = (configPage2.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
if(injector3StartAngle < 0) {injector3StartAngle += CRANK_ANGLE_MAX_INJ;}
injector4StartAngle = (configPage1.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree ));
injector4StartAngle = (configPage2.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree ));
if(injector4StartAngle > CRANK_ANGLE_MAX_INJ) {injector4StartAngle -= CRANK_ANGLE_MAX_INJ;}
if(injector4StartAngle < 0) {injector4StartAngle += CRANK_ANGLE_MAX_INJ;}
if(configPage3.fuelTrimEnabled)
if(configPage6.fuelTrimEnabled)
{
unsigned long pw1percent = 100 + (byte)get3DTableValue(&trim1Table, currentStatus.MAP, currentStatus.RPM) - OFFSET_FUELTRIM;
unsigned long pw2percent = 100 + (byte)get3DTableValue(&trim2Table, currentStatus.MAP, currentStatus.RPM) - OFFSET_FUELTRIM;
@ -1104,10 +1155,10 @@ void loop()
if (pw4percent != 100) { currentStatus.PW4 = (pw4percent * currentStatus.PW4) / 100; }
}
}
else if(configPage11.stagingEnabled == true)
else if(configPage10.stagingEnabled == true)
{
PWdivTimerPerDegree = div(currentStatus.PW3, timePerDegree).quot; //Need to redo this for PW3 as it will be dramatically different to PW1 when staging
injector3StartAngle = configPage1.inj3Ang - ( PWdivTimerPerDegree ); //This is a little primitive, but is based on the idea that all fuel needs to be delivered before the inlet valve opens. See http://www.extraefi.co.uk/sequential_fuel.html for more detail
injector3StartAngle = configPage2.inj3Ang - ( PWdivTimerPerDegree ); //This is a little primitive, but is based on the idea that all fuel needs to be delivered before the inlet valve opens. See http://www.extraefi.co.uk/sequential_fuel.html for more detail
if(injector3StartAngle < 0) {injector3StartAngle += CRANK_ANGLE_MAX_INJ;}
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
@ -1118,29 +1169,40 @@ void loop()
break;
//5 cylinders
case 5:
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
injector2StartAngle = (configPage2.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
injector3StartAngle = (configPage2.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
injector4StartAngle = (configPage1.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree ));
injector4StartAngle = (configPage2.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree ));
if(injector4StartAngle > CRANK_ANGLE_MAX_INJ) {injector4StartAngle -= CRANK_ANGLE_MAX_INJ;}
injector5StartAngle = (configPage1.inj1Ang + channel5InjDegrees - ( PWdivTimerPerDegree ));
injector5StartAngle = (configPage2.inj1Ang + channel5InjDegrees - ( PWdivTimerPerDegree ));
if(injector5StartAngle > CRANK_ANGLE_MAX_INJ) {injector5StartAngle -= CRANK_ANGLE_MAX_INJ;}
break;
//6 cylinders
case 6:
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
injector2StartAngle = (configPage2.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
injector3StartAngle = (configPage2.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
#if INJ_CHANNELS >= 6
if(configPage2.injLayout == INJ_SEQUENTIAL)
{
injector4StartAngle = (configPage2.inj1Ang + channel4InjDegrees - ( PWdivTimerPerDegree ));
if(injector4StartAngle > CRANK_ANGLE_MAX_INJ) {injector4StartAngle -= CRANK_ANGLE_MAX_INJ;}
injector5StartAngle = (configPage2.inj2Ang + channel5InjDegrees - ( PWdivTimerPerDegree ));
if(injector5StartAngle > CRANK_ANGLE_MAX_INJ) {injector5StartAngle -= CRANK_ANGLE_MAX_INJ;}
injector6StartAngle = (configPage2.inj3Ang + channel6InjDegrees - ( PWdivTimerPerDegree ));
if(injector6StartAngle > CRANK_ANGLE_MAX_INJ) {injector6StartAngle -= CRANK_ANGLE_MAX_INJ;}
}
#endif
break;
//8 cylinders
case 8:
injector2StartAngle = (configPage1.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
injector2StartAngle = (configPage2.inj2Ang + channel2InjDegrees - ( PWdivTimerPerDegree ));
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
injector3StartAngle = (configPage2.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
injector4StartAngle = (configPage1.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree ));
injector4StartAngle = (configPage2.inj4Ang + channel4InjDegrees - ( PWdivTimerPerDegree ));
if(injector4StartAngle > CRANK_ANGLE_MAX_INJ) {injector4StartAngle -= CRANK_ANGLE_MAX_INJ;}
break;
//Will hit the default case on 1 cylinder or >8 cylinders. Do nothing in these cases
@ -1150,14 +1212,14 @@ void loop()
//***********************************************************************************************
//| BEGIN IGNITION CALCULATIONS
if (currentStatus.RPM > ((unsigned int)(configPage2.HardRevLim) * 100) ) { BIT_SET(currentStatus.spark, BIT_SPARK_HRDLIM); } //Hardcut RPM limit
if (currentStatus.RPM > ((unsigned int)(configPage4.HardRevLim) * 100) ) { BIT_SET(currentStatus.spark, BIT_SPARK_HRDLIM); } //Hardcut RPM limit
else { BIT_CLEAR(currentStatus.spark, BIT_SPARK_HRDLIM); }
//Set dwell
//Dwell is stored as ms * 10. ie Dwell of 4.3ms would be 43 in configPage2. This number therefore needs to be multiplied by 100 to get dwell in uS
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) { currentStatus.dwell = (configPage2.dwellCrank * 100); }
else { currentStatus.dwell = (configPage2.dwellRun * 100); }
//Dwell is stored as ms * 10. ie Dwell of 4.3ms would be 43 in configPage4. This number therefore needs to be multiplied by 100 to get dwell in uS
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) { currentStatus.dwell = (configPage4.dwellCrank * 100); }
else { currentStatus.dwell = (configPage4.dwellRun * 100); }
currentStatus.dwell = correctionsDwell(currentStatus.dwell);
int dwellAngle = uSToDegrees(currentStatus.dwell); //Convert the dwell time to dwell angle based on the current engine speed
@ -1169,7 +1231,7 @@ void loop()
if(ignition1StartAngle < 0) {ignition1StartAngle += CRANK_ANGLE_MAX_IGN;}
//This test for more cylinders and do the same thing
switch (configPage1.nCylinders)
switch (configPage2.nCylinders)
{
//2 cylinders
case 2:
@ -1193,7 +1255,7 @@ void loop()
if(ignition2StartAngle > CRANK_ANGLE_MAX_IGN) {ignition2StartAngle -= CRANK_ANGLE_MAX_IGN;}
if(ignition2StartAngle < 0) {ignition2StartAngle += CRANK_ANGLE_MAX_IGN;}
if(configPage2.sparkMode == IGN_MODE_SEQUENTIAL)
if(configPage4.sparkMode == IGN_MODE_SEQUENTIAL)
{
ignition3EndAngle = channel3IgnDegrees + CRANK_ANGLE_MAX_IGN - currentStatus.advance;
ignition3StartAngle = ignition3EndAngle - dwellAngle;
@ -1203,12 +1265,12 @@ void loop()
ignition4StartAngle = ignition4EndAngle - dwellAngle;
if(ignition4StartAngle > CRANK_ANGLE_MAX_IGN) {ignition4StartAngle -= CRANK_ANGLE_MAX_IGN;}
}
else if(configPage2.sparkMode == IGN_MODE_ROTARY)
else if(configPage4.sparkMode == IGN_MODE_ROTARY)
{
if(configPage11.rotaryType == ROTARY_IGN_FC)
if(configPage10.rotaryType == ROTARY_IGN_FC)
{
byte splitDegrees = 0;
if (configPage1.algorithm == LOAD_SOURCE_MAP) { splitDegrees = table2D_getValue(&rotarySplitTable, currentStatus.MAP/2); }
if (configPage2.algorithm == LOAD_SOURCE_MAP) { splitDegrees = table2D_getValue(&rotarySplitTable, currentStatus.MAP/2); }
else { splitDegrees = table2D_getValue(&rotarySplitTable, currentStatus.TPS/2); }
//The trailing angles are set relative to the leading ones
@ -1274,7 +1336,7 @@ void loop()
}
//If ignition timing is being tracked per tooth, perform the calcs to get the end teeth
//This only needs to be run if the advance figure has changed, otherwise the end teeth will still be the same
if( (configPage1.perToothIgn == true) && (lastAdvance != currentStatus.advance) ) { triggerSetEndTeeth(); }
if( (configPage2.perToothIgn == true) && (lastAdvance != currentStatus.advance) ) { triggerSetEndTeeth(); }
//***********************************************************************************************
//| BEGIN FUEL SCHEDULES
@ -1286,6 +1348,7 @@ void loop()
int crankAngle = getCrankAngle(timePerDegree);
if (crankAngle > CRANK_ANGLE_MAX_INJ ) { crankAngle -= 360; }
#if INJ_CHANNELS >= 1
if (fuelOn && !BIT_CHECK(currentStatus.status1, BIT_STATUS1_BOOSTCUT))
{
if(currentStatus.PW1 >= inj_opentime_uS)
@ -1299,6 +1362,7 @@ void loop()
);
}
}
#endif
/*-----------------------------------------------------------------------------------------
| A Note on tempCrankAngle and tempStartAngle:
@ -1311,6 +1375,7 @@ void loop()
| This will very likely need to be rewritten when sequential is enabled
|------------------------------------------------------------------------------------------
*/
#if INJ_CHANNELS >= 2
if( (channel2InjEnabled) && (currentStatus.PW2 >= inj_opentime_uS) )
{
tempCrankAngle = crankAngle - channel2InjDegrees;
@ -1326,7 +1391,9 @@ void loop()
);
}
}
#endif
#if INJ_CHANNELS >= 3
if( (channel3InjEnabled) && (currentStatus.PW3 >= inj_opentime_uS) )
{
tempCrankAngle = crankAngle - channel3InjDegrees;
@ -1342,7 +1409,9 @@ void loop()
);
}
}
#endif
#if INJ_CHANNELS >= 4
if( (channel4InjEnabled) && (currentStatus.PW4 >= inj_opentime_uS) )
{
tempCrankAngle = crankAngle - channel4InjDegrees;
@ -1358,8 +1427,10 @@ void loop()
);
}
}
#endif
if(channel5InjEnabled)
#if INJ_CHANNELS >= 5
if( (channel5InjEnabled) && (currentStatus.PW4 >= inj_opentime_uS) )
{
tempCrankAngle = crankAngle - channel5InjDegrees;
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_INJ; }
@ -1381,20 +1452,75 @@ void loop()
);
}
}
#endif
#if INJ_CHANNELS >= 6
if( (channel6InjEnabled) && (currentStatus.PW6 >= inj_opentime_uS) )
{
tempCrankAngle = crankAngle - channel6InjDegrees;
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_INJ; }
tempStartAngle = injector6StartAngle - channel6InjDegrees;
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
if ( (tempStartAngle <= tempCrankAngle) && (fuelSchedule6.Status == RUNNING) ) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
if ( tempStartAngle > tempCrankAngle )
{
setFuelSchedule6(
((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree),
(unsigned long)currentStatus.PW6
);
}
}
#endif
#if INJ_CHANNELS >= 7
if( (channel7InjEnabled) && (currentStatus.PW7 >= inj_opentime_uS) )
{
tempCrankAngle = crankAngle - channel7InjDegrees;
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_INJ; }
tempStartAngle = injector7StartAngle - channel7InjDegrees;
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
if ( (tempStartAngle <= tempCrankAngle) && (fuelSchedule7.Status == RUNNING) ) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
if ( tempStartAngle > tempCrankAngle )
{
setFuelSchedule7(
((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree),
(unsigned long)currentStatus.PW7
);
}
}
#endif
#if INJ_CHANNELS >= 8
if( (channel8InjEnabled) && (currentStatus.PW8 >= inj_opentime_uS) )
{
tempCrankAngle = crankAngle - channel8InjDegrees;
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_INJ; }
tempStartAngle = injector8StartAngle - channel8InjDegrees;
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
if ( (tempStartAngle <= tempCrankAngle) && (fuelSchedule8.Status == RUNNING) ) { tempStartAngle += CRANK_ANGLE_MAX_INJ; }
if ( tempStartAngle > tempCrankAngle )
{
setFuelSchedule8(
((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree),
(unsigned long)currentStatus.PW8
);
}
}
#endif
}
//***********************************************************************************************
//| BEGIN IGNITION SCHEDULES
//Likewise for the ignition
//fixedCrankingOverride is used to extend the dwell during cranking so that the decoder can trigger the spark upon seeing a certain tooth. Currently only available on the basic distributor and 4g63 decoders.
if ( configPage2.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && (decoderHasFixedCrankingTiming == true) ) { fixedCrankingOverride = currentStatus.dwell * 3; }
if ( configPage4.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && (decoderHasFixedCrankingTiming == true) ) { fixedCrankingOverride = currentStatus.dwell * 3; }
else { fixedCrankingOverride = 0; }
//Perform an initial check to see if the ignition is turned on (Ignition only turns on after a preset number of cranking revolutions and:
//Check for any of the hard cut rev limits being on
if(currentStatus.launchingHard || BIT_CHECK(currentStatus.spark, BIT_SPARK_BOOSTCUT) || BIT_CHECK(currentStatus.spark, BIT_SPARK_HRDLIM) || currentStatus.flatShiftingHard)
{
if(configPage1.hardCutType == HARD_CUT_FULL) { ignitionOn = false; }
if(configPage2.hardCutType == HARD_CUT_FULL) { ignitionOn = false; }
else { curRollingCut = ( (currentStatus.startRevolutions / 2) % maxIgnOutputs) + 1; } //Rolls through each of the active ignition channels based on how many revolutions have taken place
}
else { curRollingCut = 0; } //Disables the rolling hard cut
@ -1427,7 +1553,7 @@ void loop()
}
}
/*
if( (ignitionSchedule1.Status == RUNNING) && (ignition1EndAngle > crankAngle) && configPage2.StgCycles == 0)
if( (ignitionSchedule1.Status == RUNNING) && (ignition1EndAngle > crankAngle) && configPage4.StgCycles == 0)
{
unsigned long uSToEnd = 0;
@ -1529,7 +1655,17 @@ void loop()
}
}
} //Ignition schedules on
if (!BIT_CHECK(currentStatus.status3, BIT_STATUS3_RESET_PREVENT) && resetControl == RESET_CONTROL_PREVENT_WHEN_RUNNING) {
//Reset prevention is supposed to be on while the engine is running but isn't. Fix that.
digitalWrite(pinResetControl, HIGH);
BIT_SET(currentStatus.status3, BIT_STATUS3_RESET_PREVENT);
}
} //Has sync and RPM
else if (BIT_CHECK(currentStatus.status3, BIT_STATUS3_RESET_PREVENT) && resetControl == RESET_CONTROL_PREVENT_WHEN_RUNNING) {
digitalWrite(pinResetControl, LOW);
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_RESET_PREVENT);
}
} //loop()
/*
@ -1551,20 +1687,20 @@ static inline unsigned int PW(int REQ_FUEL, byte VE, long MAP, int corrections,
//100% float free version, does sacrifice a little bit of accuracy, but not much.
iVE = ((unsigned int)VE << 7) / 100;
if ( configPage1.multiplyMAP == true ) {
if ( configPage2.multiplyMAP == true ) {
iMAP = ((unsigned int)MAP << 7) / currentStatus.baro; //Include multiply MAP (vs baro) if enabled
}
if ( (configPage1.includeAFR == true) && (configPage3.egoType == 2)) {
if ( (configPage2.includeAFR == true) && (configPage6.egoType == 2)) {
iAFR = ((unsigned int)currentStatus.O2 << 7) / currentStatus.afrTarget; //Include AFR (vs target) if enabled
}
iCorrections = (corrections << 7) / 100;
unsigned long intermediate = ((long)REQ_FUEL * (long)iVE) >> 7; //Need to use an intermediate value to avoid overflowing the long
if ( configPage1.multiplyMAP == true ) {
if ( configPage2.multiplyMAP == true ) {
intermediate = (intermediate * (unsigned long)iMAP) >> 7;
}
if ( (configPage1.includeAFR == true) && (configPage3.egoType == 2) ) {
if ( (configPage2.includeAFR == true) && (configPage6.egoType == 2) ) {
intermediate = (intermediate * (unsigned long)iAFR) >> 7; //EGO type must be set to wideband for this to be used
}
intermediate = (intermediate * (unsigned long)iCorrections) >> 7;
@ -1579,3 +1715,5 @@ static inline unsigned int PW(int REQ_FUEL, byte VE, long MAP, int corrections,
}
return (unsigned int)(intermediate);
}
#endif //Unit testing scope guard

View File

@ -88,48 +88,48 @@ Current layout of EEPROM data (Version 3) is as follows (All sizes are in bytes)
#define EEPROM_CONFIG5_YBINS 1111
#define EEPROM_CONFIG6_START 1127
#define EEPROM_CONFIG6_END 1255
#define EEPROM_CONFIG8_XSIZE1 1255
#define EEPROM_CONFIG8_YSIZE1 1256
#define EEPROM_CONFIG8_MAP1 1257
#define EEPROM_CONFIG8_XBINS1 1321
#define EEPROM_CONFIG8_YBINS1 1329
#define EEPROM_CONFIG8_XSIZE2 1337
#define EEPROM_CONFIG8_YSIZE2 1338
#define EEPROM_CONFIG8_MAP2 1339
#define EEPROM_CONFIG8_XBINS2 1403
#define EEPROM_CONFIG8_YBINS2 1411
#define EEPROM_CONFIG7_XSIZE1 1255
#define EEPROM_CONFIG7_YSIZE1 1256
#define EEPROM_CONFIG7_MAP1 1257
#define EEPROM_CONFIG7_XBINS1 1321
#define EEPROM_CONFIG7_YBINS1 1329
#define EEPROM_CONFIG7_XSIZE2 1337
#define EEPROM_CONFIG7_YSIZE2 1338
#define EEPROM_CONFIG7_MAP2 1339
#define EEPROM_CONFIG7_XBINS2 1403
#define EEPROM_CONFIG7_YBINS2 1411
#define EEPROM_CONFIG8_XSIZE3 1419
#define EEPROM_CONFIG8_YSIZE3 1420
#define EEPROM_CONFIG8_MAP3 1421
#define EEPROM_CONFIG7_XSIZE3 1419
#define EEPROM_CONFIG7_YSIZE3 1420
#define EEPROM_CONFIG7_MAP3 1421
#define EEPROM_CONFIG8_XBINS3 1485
#define EEPROM_CONFIG8_YBINS3 1493
#define EEPROM_CONFIG8_END 1501
#define EEPROM_CONFIG9_XSIZE1 1501
#define EEPROM_CONFIG9_YSIZE1 1502
#define EEPROM_CONFIG9_MAP1 1503
#define EEPROM_CONFIG9_XBINS1 1539
#define EEPROM_CONFIG9_YBINS1 1545
#define EEPROM_CONFIG9_XSIZE2 1551
#define EEPROM_CONFIG9_YSIZE2 1552
#define EEPROM_CONFIG9_MAP2 1553
#define EEPROM_CONFIG9_XBINS2 1589
#define EEPROM_CONFIG9_YBINS2 1595
#define EEPROM_CONFIG9_XSIZE3 1601
#define EEPROM_CONFIG9_YSIZE3 1602
#define EEPROM_CONFIG9_MAP3 1603
#define EEPROM_CONFIG9_XBINS3 1639
#define EEPROM_CONFIG9_YBINS3 1645
#define EEPROM_CONFIG9_XSIZE4 1651
#define EEPROM_CONFIG9_YSIZE4 1652
#define EEPROM_CONFIG9_MAP4 1653
#define EEPROM_CONFIG9_XBINS4 1689
#define EEPROM_CONFIG9_YBINS4 1695
#define EEPROM_CONFIG10_START 1710
#define EEPROM_CONFIG10_END 1838
#define EEPROM_CONFIG11_START 1838
#define EEPROM_CONFIG11_END 2030
#define EEPROM_CONFIG7_XBINS3 1485
#define EEPROM_CONFIG7_YBINS3 1493
#define EEPROM_CONFIG7_END 1501
#define EEPROM_CONFIG8_XSIZE1 1501
#define EEPROM_CONFIG8_YSIZE1 1502
#define EEPROM_CONFIG8_MAP1 1503
#define EEPROM_CONFIG8_XBINS1 1539
#define EEPROM_CONFIG8_YBINS1 1545
#define EEPROM_CONFIG8_XSIZE2 1551
#define EEPROM_CONFIG8_YSIZE2 1552
#define EEPROM_CONFIG8_MAP2 1553
#define EEPROM_CONFIG8_XBINS2 1589
#define EEPROM_CONFIG8_YBINS2 1595
#define EEPROM_CONFIG8_XSIZE3 1601
#define EEPROM_CONFIG8_YSIZE3 1602
#define EEPROM_CONFIG8_MAP3 1603
#define EEPROM_CONFIG8_XBINS3 1639
#define EEPROM_CONFIG8_YBINS3 1645
#define EEPROM_CONFIG8_XSIZE4 1651
#define EEPROM_CONFIG8_YSIZE4 1652
#define EEPROM_CONFIG8_MAP4 1653
#define EEPROM_CONFIG8_XBINS4 1689
#define EEPROM_CONFIG8_YBINS4 1695
#define EEPROM_CONFIG9_START 1710
#define EEPROM_CONFIG9_END 1838
#define EEPROM_CONFIG10_START 1838
#define EEPROM_CONFIG10_END 2030
//Calibration data is stored at the end of the EEPROM (This is in case any further calibration tables are needed as they are large blocks)
#define EEPROM_LAST_BARO 2558

View File

@ -83,7 +83,7 @@ void writeConfig(byte tableNum)
| Config page 2 (See storage.h for data layout)
| 64 byte long config table
-----------------------------------------------------*/
pnt_configPage = (byte *)&configPage1; //Create a pointer to Page 2 in memory
pnt_configPage = (byte *)&configPage2; //Create a pointer to Page 2 in memory
for(int x=EEPROM_CONFIG2_START; x<EEPROM_CONFIG2_END; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
@ -138,7 +138,7 @@ void writeConfig(byte tableNum)
| Config page 2 (See storage.h for data layout)
| 64 byte long config table
-----------------------------------------------------*/
pnt_configPage = (byte *)&configPage2; //Create a pointer to Page 2 in memory
pnt_configPage = (byte *)&configPage4; //Create a pointer to Page 2 in memory
for(int x=EEPROM_CONFIG4_START; x<EEPROM_CONFIG4_END; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
@ -190,7 +190,7 @@ void writeConfig(byte tableNum)
| Config page 3 (See storage.h for data layout)
| 64 byte long config table
-----------------------------------------------------*/
pnt_configPage = (byte *)&configPage3; //Create a pointer to Page 3 in memory
pnt_configPage = (byte *)&configPage6; //Create a pointer to Page 3 in memory
for(int x=EEPROM_CONFIG6_START; x<EEPROM_CONFIG6_END; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
@ -208,53 +208,53 @@ void writeConfig(byte tableNum)
| 8x8 table itself + the 8 values along each of the axis
-----------------------------------------------------*/
//Begin writing the 2 tables, basically the same thing as above but we're doing these 2 together (2 tables per page instead of 1)
if(EEPROM.read(EEPROM_CONFIG8_XSIZE1) != boostTable.xSize) { EEPROM.write(EEPROM_CONFIG8_XSIZE1,boostTable.xSize); writeCounter++; } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG8_YSIZE1) != boostTable.ySize) { EEPROM.write(EEPROM_CONFIG8_YSIZE1,boostTable.ySize); writeCounter++; } //Write the boost Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG8_XSIZE2) != vvtTable.xSize) { EEPROM.write(EEPROM_CONFIG8_XSIZE2,vvtTable.xSize); writeCounter++; } //Write the vvt Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG8_YSIZE2) != vvtTable.ySize) { EEPROM.write(EEPROM_CONFIG8_YSIZE2,vvtTable.ySize); writeCounter++; } //Write the vvt Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG8_XSIZE3) != stagingTable.xSize) { EEPROM.write(EEPROM_CONFIG8_XSIZE3,stagingTable.xSize); writeCounter++; } //Write the staging Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG8_YSIZE3) != stagingTable.ySize) { EEPROM.write(EEPROM_CONFIG8_YSIZE3,stagingTable.ySize); writeCounter++; } //Write the staging Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG7_XSIZE1) != boostTable.xSize) { EEPROM.write(EEPROM_CONFIG7_XSIZE1,boostTable.xSize); writeCounter++; } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG7_YSIZE1) != boostTable.ySize) { EEPROM.write(EEPROM_CONFIG7_YSIZE1,boostTable.ySize); writeCounter++; } //Write the boost Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG7_XSIZE2) != vvtTable.xSize) { EEPROM.write(EEPROM_CONFIG7_XSIZE2,vvtTable.xSize); writeCounter++; } //Write the vvt Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG7_YSIZE2) != vvtTable.ySize) { EEPROM.write(EEPROM_CONFIG7_YSIZE2,vvtTable.ySize); writeCounter++; } //Write the vvt Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG7_XSIZE3) != stagingTable.xSize) { EEPROM.write(EEPROM_CONFIG7_XSIZE3,stagingTable.xSize); writeCounter++; } //Write the staging Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG7_YSIZE3) != stagingTable.ySize) { EEPROM.write(EEPROM_CONFIG7_YSIZE3,stagingTable.ySize); writeCounter++; } //Write the staging Table MAP/TPS dimension size
y = EEPROM_CONFIG8_MAP2; //We do the 3 maps together in the same loop
z = EEPROM_CONFIG8_MAP3;
for(int x=EEPROM_CONFIG8_MAP1; x<EEPROM_CONFIG8_XBINS1; x++)
y = EEPROM_CONFIG7_MAP2; //We do the 3 maps together in the same loop
z = EEPROM_CONFIG7_MAP3;
for(int x=EEPROM_CONFIG7_MAP1; x<EEPROM_CONFIG7_XBINS1; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
offset = x - EEPROM_CONFIG8_MAP1;
offset = x - EEPROM_CONFIG7_MAP1;
if(EEPROM.read(x) != (boostTable.values[7-(offset/8)][offset%8]) ) { EEPROM.write(x, boostTable.values[7-(offset/8)][offset%8]); writeCounter++; } //Write the 8x8 map
offset = y - EEPROM_CONFIG8_MAP2;
offset = y - EEPROM_CONFIG7_MAP2;
if(EEPROM.read(y) != (vvtTable.values[7-(offset/8)][offset%8]) ) { EEPROM.write(y, vvtTable.values[7-(offset/8)][offset%8]); writeCounter++; } //Write the 8x8 map
offset = z - EEPROM_CONFIG8_MAP3;
offset = z - EEPROM_CONFIG7_MAP3;
if(EEPROM.read(z) != (stagingTable.values[7-(offset/8)][offset%8]) ) { EEPROM.write(z, stagingTable.values[7-(offset/8)][offset%8]); writeCounter++; } //Write the 8x8 map
y++;
z++;
}
//RPM bins
y = EEPROM_CONFIG8_XBINS2;
z = EEPROM_CONFIG8_XBINS3;
for(int x=EEPROM_CONFIG8_XBINS1; x<EEPROM_CONFIG8_YBINS1; x++)
y = EEPROM_CONFIG7_XBINS2;
z = EEPROM_CONFIG7_XBINS3;
for(int x=EEPROM_CONFIG7_XBINS1; x<EEPROM_CONFIG7_YBINS1; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
offset = x - EEPROM_CONFIG8_XBINS1;
offset = x - EEPROM_CONFIG7_XBINS1;
if(EEPROM.read(x) != byte(boostTable.axisX[offset]/TABLE_RPM_MULTIPLIER)) { EEPROM.write(x, byte(boostTable.axisX[offset]/TABLE_RPM_MULTIPLIER)); writeCounter++; } //RPM bins are divided by 100 and converted to a byte
offset = y - EEPROM_CONFIG8_XBINS2;
offset = y - EEPROM_CONFIG7_XBINS2;
if(EEPROM.read(y) != byte(vvtTable.axisX[offset]/TABLE_RPM_MULTIPLIER)) { EEPROM.write(y, byte(vvtTable.axisX[offset]/TABLE_RPM_MULTIPLIER)); writeCounter++; } //RPM bins are divided by 100 and converted to a byte
offset = z - EEPROM_CONFIG8_XBINS3;
offset = z - EEPROM_CONFIG7_XBINS3;
if(EEPROM.read(z) != byte(stagingTable.axisX[offset]/TABLE_RPM_MULTIPLIER)) { EEPROM.write(z, byte(stagingTable.axisX[offset]/TABLE_RPM_MULTIPLIER)); writeCounter++; } //RPM bins are divided by 100 and converted to a byte
y++;
z++;
}
//TPS/MAP bins
y=EEPROM_CONFIG8_YBINS2;
z=EEPROM_CONFIG8_YBINS3;
for(int x=EEPROM_CONFIG8_YBINS1; x<EEPROM_CONFIG8_XSIZE2; x++)
y=EEPROM_CONFIG7_YBINS2;
z=EEPROM_CONFIG7_YBINS3;
for(int x=EEPROM_CONFIG7_YBINS1; x<EEPROM_CONFIG7_XSIZE2; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
offset = x - EEPROM_CONFIG8_YBINS1;
offset = x - EEPROM_CONFIG7_YBINS1;
if(EEPROM.read(x) != boostTable.axisY[offset]) { EEPROM.write(x, boostTable.axisY[offset]); writeCounter++; } //TABLE_LOAD_MULTIPLIER is NOT used for boost as it is TPS based (0-100)
offset = y - EEPROM_CONFIG8_YBINS2;
offset = y - EEPROM_CONFIG7_YBINS2;
if(EEPROM.read(y) != vvtTable.axisY[offset]) { EEPROM.write(y, vvtTable.axisY[offset]); writeCounter++; } //TABLE_LOAD_MULTIPLIER is NOT used for VVT as it is TPS based (0-100)
offset = z - EEPROM_CONFIG8_YBINS3;
offset = z - EEPROM_CONFIG7_YBINS3;
if(EEPROM.read(z) != byte(stagingTable.axisY[offset]/TABLE_LOAD_MULTIPLIER)) { EEPROM.write(z, byte(stagingTable.axisY[offset]/TABLE_LOAD_MULTIPLIER)); writeCounter++; } //RPM bins are divided by 100 and converted to a byte
y++;
z++;
@ -271,35 +271,35 @@ void writeConfig(byte tableNum)
| 6x6 tables itself + the 6 values along each of the axis
-----------------------------------------------------*/
//Begin writing the 2 tables, basically the same thing as above but we're doing these 2 together (2 tables per page instead of 1)
if(EEPROM.read(EEPROM_CONFIG9_XSIZE1) != trim1Table.xSize) { EEPROM.write(EEPROM_CONFIG9_XSIZE1,trim1Table.xSize); writeCounter++; } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG9_YSIZE1) != trim1Table.ySize) { EEPROM.write(EEPROM_CONFIG9_YSIZE1,trim1Table.ySize); writeCounter++; } //Write the boost Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG9_XSIZE2) != trim2Table.xSize) { EEPROM.write(EEPROM_CONFIG9_XSIZE2,trim2Table.xSize); writeCounter++; } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG9_YSIZE2) != trim2Table.ySize) { EEPROM.write(EEPROM_CONFIG9_YSIZE2,trim2Table.ySize); writeCounter++; } //Write the boost Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG9_XSIZE3) != trim3Table.xSize) { EEPROM.write(EEPROM_CONFIG9_XSIZE3,trim3Table.xSize); writeCounter++; } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG9_YSIZE3) != trim3Table.ySize) { EEPROM.write(EEPROM_CONFIG9_YSIZE3,trim3Table.ySize); writeCounter++; } //Write the boost Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG9_XSIZE4) != trim4Table.xSize) { EEPROM.write(EEPROM_CONFIG9_XSIZE4,trim4Table.xSize); writeCounter++; } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG9_YSIZE4) != trim4Table.ySize) { EEPROM.write(EEPROM_CONFIG9_YSIZE4,trim4Table.ySize); writeCounter++; } //Write the boost Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG8_XSIZE1) != trim1Table.xSize) { EEPROM.write(EEPROM_CONFIG8_XSIZE1,trim1Table.xSize); writeCounter++; } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG8_YSIZE1) != trim1Table.ySize) { EEPROM.write(EEPROM_CONFIG8_YSIZE1,trim1Table.ySize); writeCounter++; } //Write the boost Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG8_XSIZE2) != trim2Table.xSize) { EEPROM.write(EEPROM_CONFIG8_XSIZE2,trim2Table.xSize); writeCounter++; } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG8_YSIZE2) != trim2Table.ySize) { EEPROM.write(EEPROM_CONFIG8_YSIZE2,trim2Table.ySize); writeCounter++; } //Write the boost Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG8_XSIZE3) != trim3Table.xSize) { EEPROM.write(EEPROM_CONFIG8_XSIZE3,trim3Table.xSize); writeCounter++; } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG8_YSIZE3) != trim3Table.ySize) { EEPROM.write(EEPROM_CONFIG8_YSIZE3,trim3Table.ySize); writeCounter++; } //Write the boost Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG8_XSIZE4) != trim4Table.xSize) { EEPROM.write(EEPROM_CONFIG8_XSIZE4,trim4Table.xSize); writeCounter++; } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG8_YSIZE4) != trim4Table.ySize) { EEPROM.write(EEPROM_CONFIG8_YSIZE4,trim4Table.ySize); writeCounter++; } //Write the boost Table MAP/TPS dimension size
y = EEPROM_CONFIG9_MAP2; //We do the 4 maps together in the same loop
z = EEPROM_CONFIG9_MAP3; //We do the 4 maps together in the same loop
i = EEPROM_CONFIG9_MAP4; //We do the 4 maps together in the same loop
y = EEPROM_CONFIG8_MAP2; //We do the 4 maps together in the same loop
z = EEPROM_CONFIG8_MAP3; //We do the 4 maps together in the same loop
i = EEPROM_CONFIG8_MAP4; //We do the 4 maps together in the same loop
for(int x=EEPROM_CONFIG9_MAP1; x<EEPROM_CONFIG9_XBINS1; x++)
for(int x=EEPROM_CONFIG8_MAP1; x<EEPROM_CONFIG8_XBINS1; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
offset = x - EEPROM_CONFIG9_MAP1;
offset = x - EEPROM_CONFIG8_MAP1;
newVal = trim1Table.values[5-(offset/6)][offset%6];
if (EEPROM.read(x) != newVal ) { EEPROM.update(x, newVal ); writeCounter++; } //Write the 6x6 map
offset = y - EEPROM_CONFIG9_MAP2;
offset = y - EEPROM_CONFIG8_MAP2;
newVal = trim2Table.values[5-(offset/6)][offset%6];
if (EEPROM.read(y) != newVal ) { EEPROM.update(y, newVal); writeCounter++; } //Write the 6x6 map
offset = z - EEPROM_CONFIG9_MAP3;
offset = z - EEPROM_CONFIG8_MAP3;
newVal = trim3Table.values[5-(offset/6)][offset%6];
if (EEPROM.read(z) != newVal ) { EEPROM.update(z, newVal); writeCounter++; } //Write the 6x6 map
offset = i - EEPROM_CONFIG9_MAP4;
offset = i - EEPROM_CONFIG8_MAP4;
newVal = trim4Table.values[5-(offset/6)][offset%6];
if (EEPROM.read(i) != newVal ) { EEPROM.update(i, newVal); writeCounter++; } //Write the 6x6 map
@ -308,38 +308,38 @@ void writeConfig(byte tableNum)
i++;
}
//RPM bins
y = EEPROM_CONFIG9_XBINS2;
z = EEPROM_CONFIG9_XBINS3;
i = EEPROM_CONFIG9_XBINS4;
for(int x=EEPROM_CONFIG9_XBINS1; x<EEPROM_CONFIG9_YBINS1; x++)
y = EEPROM_CONFIG8_XBINS2;
z = EEPROM_CONFIG8_XBINS3;
i = EEPROM_CONFIG8_XBINS4;
for(int x=EEPROM_CONFIG8_XBINS1; x<EEPROM_CONFIG8_YBINS1; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { eepromWritesPending = true; break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
offset = x - EEPROM_CONFIG9_XBINS1;
offset = x - EEPROM_CONFIG8_XBINS1;
EEPROM.update(x, byte(trim1Table.axisX[offset]/TABLE_RPM_MULTIPLIER)); //RPM bins are divided by 100 and converted to a byte
offset = y - EEPROM_CONFIG9_XBINS2;
offset = y - EEPROM_CONFIG8_XBINS2;
EEPROM.update(y, byte(trim2Table.axisX[offset]/TABLE_RPM_MULTIPLIER)); //RPM bins are divided by 100 and converted to a byte
offset = z - EEPROM_CONFIG9_XBINS3;
offset = z - EEPROM_CONFIG8_XBINS3;
EEPROM.update(z, byte(trim3Table.axisX[offset]/TABLE_RPM_MULTIPLIER)); //RPM bins are divided by 100 and converted to a byte
offset = i - EEPROM_CONFIG9_XBINS4;
offset = i - EEPROM_CONFIG8_XBINS4;
EEPROM.update(i, byte(trim4Table.axisX[offset]/TABLE_RPM_MULTIPLIER)); //RPM bins are divided by 100 and converted to a byte
y++;
z++;
i++;
}
//TPS/MAP bins
y=EEPROM_CONFIG9_YBINS2;
z=EEPROM_CONFIG9_YBINS3;
i=EEPROM_CONFIG9_YBINS4;
for(int x=EEPROM_CONFIG9_YBINS1; x<EEPROM_CONFIG9_XSIZE2; x++)
y=EEPROM_CONFIG8_YBINS2;
z=EEPROM_CONFIG8_YBINS3;
i=EEPROM_CONFIG8_YBINS4;
for(int x=EEPROM_CONFIG8_YBINS1; x<EEPROM_CONFIG8_XSIZE2; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { eepromWritesPending = true; break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
offset = x - EEPROM_CONFIG9_YBINS1;
offset = x - EEPROM_CONFIG8_YBINS1;
EEPROM.update(x, trim1Table.axisY[offset]/TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
offset = y - EEPROM_CONFIG9_YBINS2;
offset = y - EEPROM_CONFIG8_YBINS2;
EEPROM.update(y, trim2Table.axisY[offset]/TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
offset = z - EEPROM_CONFIG9_YBINS3;
offset = z - EEPROM_CONFIG8_YBINS3;
EEPROM.update(z, trim3Table.axisY[offset]/TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
offset = i - EEPROM_CONFIG9_YBINS4;
offset = i - EEPROM_CONFIG8_YBINS4;
EEPROM.update(i, trim4Table.axisY[offset]/TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
y++;
z++;
@ -355,11 +355,11 @@ void writeConfig(byte tableNum)
| Config page 10 (See storage.h for data layout)
| 128 byte long config table
-----------------------------------------------------*/
pnt_configPage = (byte *)&configPage10; //Create a pointer to Page 10 in memory
for(int x=EEPROM_CONFIG10_START; x<EEPROM_CONFIG10_END; x++)
pnt_configPage = (byte *)&configPage9; //Create a pointer to Page 10 in memory
for(int x=EEPROM_CONFIG9_START; x<EEPROM_CONFIG9_END; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG10_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG10_START))); writeCounter++; }
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG9_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG9_START))); writeCounter++; }
}
if(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
@ -372,12 +372,12 @@ void writeConfig(byte tableNum)
| Config page 11 (See storage.h for data layout)
| 192 byte long config table
-----------------------------------------------------*/
pnt_configPage = (byte *)&configPage11; //Create a pointer to Page 11 in memory
pnt_configPage = (byte *)&configPage10; //Create a pointer to Page 11 in memory
//As there are no 3d tables in this page, all 192 bytes can simply be read in
for(int x=EEPROM_CONFIG11_START; x<EEPROM_CONFIG11_END; x++)
for(int x=EEPROM_CONFIG10_START; x<EEPROM_CONFIG10_END; x++)
{
if( (writeCounter > EEPROM_MAX_WRITE_BLOCK) ) { break; } //This is a safety check to make sure we don't attempt to write too much to the EEPROM at a time.
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG11_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG11_START))); writeCounter++; }
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG10_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG10_START))); writeCounter++; }
}
if(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
@ -416,7 +416,7 @@ void loadConfig()
fuelTable.axisY[offset] = EEPROM.read(x) * TABLE_LOAD_MULTIPLIER;
}
pnt_configPage = (byte *)&configPage1; //Create a pointer to Page 1 in memory
pnt_configPage = (byte *)&configPage2; //Create a pointer to Page 1 in memory
for(int x=EEPROM_CONFIG2_START; x<EEPROM_CONFIG2_END; x++)
{
*(pnt_configPage + byte(x - EEPROM_CONFIG2_START)) = EEPROM.read(x);
@ -445,7 +445,7 @@ void loadConfig()
ignitionTable.axisY[offset] = EEPROM.read(x) * TABLE_LOAD_MULTIPLIER; //Table load is divided by 2 (Allows for MAP up to 511)
}
pnt_configPage = (byte *)&configPage2; //Create a pointer to Page 2 in memory
pnt_configPage = (byte *)&configPage4; //Create a pointer to Page 4 in memory
for(int x=EEPROM_CONFIG4_START; x<EEPROM_CONFIG4_END; x++)
{
*(pnt_configPage + byte(x - EEPROM_CONFIG4_START)) = EEPROM.read(x);
@ -473,7 +473,7 @@ void loadConfig()
afrTable.axisY[offset] = EEPROM.read(x) * TABLE_LOAD_MULTIPLIER; //Table load is divided by 2 (Allows for MAP up to 511)
}
pnt_configPage = (byte *)&configPage3; //Create a pointer to Page 2 in memory
pnt_configPage = (byte *)&configPage6; //Create a pointer to Page 6 in memory
for(int x=EEPROM_CONFIG6_START; x<EEPROM_CONFIG6_END; x++)
{
*(pnt_configPage + byte(x - EEPROM_CONFIG6_START)) = EEPROM.read(x);
@ -481,45 +481,45 @@ void loadConfig()
//*********************************************************************************************************************************************************************************
// Boost and vvt tables load
int y = EEPROM_CONFIG8_MAP2;
int z = EEPROM_CONFIG8_MAP3;
for(int x=EEPROM_CONFIG8_MAP1; x<EEPROM_CONFIG8_XBINS1; x++)
int y = EEPROM_CONFIG7_MAP2;
int z = EEPROM_CONFIG7_MAP3;
for(int x=EEPROM_CONFIG7_MAP1; x<EEPROM_CONFIG7_XBINS1; x++)
{
offset = x - EEPROM_CONFIG8_MAP1;
offset = x - EEPROM_CONFIG7_MAP1;
boostTable.values[7-(offset/8)][offset%8] = EEPROM.read(x); //Read the 8x8 map
offset = y - EEPROM_CONFIG8_MAP2;
offset = y - EEPROM_CONFIG7_MAP2;
vvtTable.values[7-(offset/8)][offset%8] = EEPROM.read(y); //Read the 8x8 map
offset = z - EEPROM_CONFIG8_MAP3;
offset = z - EEPROM_CONFIG7_MAP3;
stagingTable.values[7-(offset/8)][offset%8] = EEPROM.read(z); //Read the 8x8 map
y++;
z++;
}
//RPM bins
y = EEPROM_CONFIG8_XBINS2;
z = EEPROM_CONFIG8_XBINS3;
for(int x=EEPROM_CONFIG8_XBINS1; x<EEPROM_CONFIG8_YBINS1; x++)
y = EEPROM_CONFIG7_XBINS2;
z = EEPROM_CONFIG7_XBINS3;
for(int x=EEPROM_CONFIG7_XBINS1; x<EEPROM_CONFIG7_YBINS1; x++)
{
offset = x - EEPROM_CONFIG8_XBINS1;
offset = x - EEPROM_CONFIG7_XBINS1;
boostTable.axisX[offset] = (EEPROM.read(x) * TABLE_RPM_MULTIPLIER); //RPM bins are divided by 100 when stored. Multiply them back now
offset = y - EEPROM_CONFIG8_XBINS2;
offset = y - EEPROM_CONFIG7_XBINS2;
vvtTable.axisX[offset] = (EEPROM.read(y) * TABLE_RPM_MULTIPLIER); //RPM bins are divided by 100 when stored. Multiply them back now
offset = z - EEPROM_CONFIG8_XBINS3;
offset = z - EEPROM_CONFIG7_XBINS3;
stagingTable.axisX[offset] = (EEPROM.read(z) * TABLE_RPM_MULTIPLIER); //RPM bins are divided by 100 when stored. Multiply them back now
y++;
z++;
}
//TPS/MAP bins
y = EEPROM_CONFIG8_YBINS2;
z = EEPROM_CONFIG8_YBINS3;
for(int x=EEPROM_CONFIG8_YBINS1; x<EEPROM_CONFIG8_XSIZE2; x++)
y = EEPROM_CONFIG7_YBINS2;
z = EEPROM_CONFIG7_YBINS3;
for(int x=EEPROM_CONFIG7_YBINS1; x<EEPROM_CONFIG7_XSIZE2; x++)
{
offset = x - EEPROM_CONFIG8_YBINS1;
offset = x - EEPROM_CONFIG7_YBINS1;
boostTable.axisY[offset] = EEPROM.read(x); //TABLE_LOAD_MULTIPLIER is NOT used for boost as it is TPS based (0-100)
offset = y - EEPROM_CONFIG8_YBINS2;
offset = y - EEPROM_CONFIG7_YBINS2;
vvtTable.axisY[offset] = EEPROM.read(y); //TABLE_LOAD_MULTIPLIER is NOT used for VVT as it is TPS based (0-100)
offset = z - EEPROM_CONFIG8_YBINS3;
offset = z - EEPROM_CONFIG7_YBINS3;
stagingTable.axisY[offset] = EEPROM.read(z) * TABLE_LOAD_MULTIPLIER;
y++;
z++;
@ -527,18 +527,18 @@ void loadConfig()
//*********************************************************************************************************************************************************************************
// Fuel trim tables load
y = EEPROM_CONFIG9_MAP2;
z = EEPROM_CONFIG9_MAP3;
int i = EEPROM_CONFIG9_MAP4;
for(int x=EEPROM_CONFIG9_MAP1; x<EEPROM_CONFIG9_XBINS1; x++)
y = EEPROM_CONFIG8_MAP2;
z = EEPROM_CONFIG8_MAP3;
int i = EEPROM_CONFIG8_MAP4;
for(int x=EEPROM_CONFIG8_MAP1; x<EEPROM_CONFIG8_XBINS1; x++)
{
offset = x - EEPROM_CONFIG9_MAP1;
offset = x - EEPROM_CONFIG8_MAP1;
trim1Table.values[5-(offset/6)][offset%6] = EEPROM.read(x); //Read the 6x6 map
offset = y - EEPROM_CONFIG9_MAP2;
offset = y - EEPROM_CONFIG8_MAP2;
trim2Table.values[5-(offset/6)][offset%6] = EEPROM.read(y); //Read the 6x6 map
offset = z - EEPROM_CONFIG9_MAP3;
offset = z - EEPROM_CONFIG8_MAP3;
trim3Table.values[5-(offset/6)][offset%6] = EEPROM.read(z); //Read the 6x6 map
offset = i - EEPROM_CONFIG9_MAP4;
offset = i - EEPROM_CONFIG8_MAP4;
trim4Table.values[5-(offset/6)][offset%6] = EEPROM.read(i); //Read the 6x6 map
y++;
z++;
@ -546,18 +546,18 @@ void loadConfig()
}
//RPM bins
y = EEPROM_CONFIG9_XBINS2;
z = EEPROM_CONFIG9_XBINS3;
i = EEPROM_CONFIG9_XBINS4;
for(int x=EEPROM_CONFIG9_XBINS1; x<EEPROM_CONFIG9_YBINS1; x++)
y = EEPROM_CONFIG8_XBINS2;
z = EEPROM_CONFIG8_XBINS3;
i = EEPROM_CONFIG8_XBINS4;
for(int x=EEPROM_CONFIG8_XBINS1; x<EEPROM_CONFIG8_YBINS1; x++)
{
offset = x - EEPROM_CONFIG9_XBINS1;
offset = x - EEPROM_CONFIG8_XBINS1;
trim1Table.axisX[offset] = (EEPROM.read(x) * TABLE_RPM_MULTIPLIER); //RPM bins are divided by 100 when stored. Multiply them back now
offset = y - EEPROM_CONFIG9_XBINS2;
offset = y - EEPROM_CONFIG8_XBINS2;
trim2Table.axisX[offset] = (EEPROM.read(y) * TABLE_RPM_MULTIPLIER); //RPM bins are divided by 100 when stored. Multiply them back now
offset = z - EEPROM_CONFIG9_XBINS3;
offset = z - EEPROM_CONFIG8_XBINS3;
trim3Table.axisX[offset] = (EEPROM.read(z) * TABLE_RPM_MULTIPLIER); //RPM bins are divided by 100 when stored. Multiply them back now
offset = i - EEPROM_CONFIG9_XBINS4;
offset = i - EEPROM_CONFIG8_XBINS4;
trim4Table.axisX[offset] = (EEPROM.read(i) * TABLE_RPM_MULTIPLIER); //RPM bins are divided by 100 when stored. Multiply them back now
y++;
z++;
@ -565,18 +565,18 @@ void loadConfig()
}
//TPS/MAP bins
y = EEPROM_CONFIG9_YBINS2;
z = EEPROM_CONFIG9_YBINS3;
i = EEPROM_CONFIG9_YBINS4;
for(int x=EEPROM_CONFIG9_YBINS1; x<EEPROM_CONFIG9_XSIZE2; x++)
y = EEPROM_CONFIG8_YBINS2;
z = EEPROM_CONFIG8_YBINS3;
i = EEPROM_CONFIG8_YBINS4;
for(int x=EEPROM_CONFIG8_YBINS1; x<EEPROM_CONFIG8_XSIZE2; x++)
{
offset = x - EEPROM_CONFIG9_YBINS1;
offset = x - EEPROM_CONFIG8_YBINS1;
trim1Table.axisY[offset] = EEPROM.read(x) * TABLE_LOAD_MULTIPLIER; //Table load is divided by 2 (Allows for MAP up to 511)
offset = y - EEPROM_CONFIG9_YBINS2;
offset = y - EEPROM_CONFIG8_YBINS2;
trim2Table.axisY[offset] = EEPROM.read(y) * TABLE_LOAD_MULTIPLIER; //Table load is divided by 2 (Allows for MAP up to 511)
offset = z - EEPROM_CONFIG9_YBINS3;
offset = z - EEPROM_CONFIG8_YBINS3;
trim3Table.axisY[offset] = EEPROM.read(z) * TABLE_LOAD_MULTIPLIER; //Table load is divided by 2 (Allows for MAP up to 511)
offset = i - EEPROM_CONFIG9_YBINS4;
offset = i - EEPROM_CONFIG8_YBINS4;
trim4Table.axisY[offset] = EEPROM.read(i) * TABLE_LOAD_MULTIPLIER; //Table load is divided by 2 (Allows for MAP up to 511)
y++;
z++;
@ -584,20 +584,20 @@ void loadConfig()
}
//*********************************************************************************************************************************************************************************
//canbus control page load
pnt_configPage = (byte *)&configPage10; //Create a pointer to Page 10 in memory
for(int x=EEPROM_CONFIG10_START; x<EEPROM_CONFIG10_END; x++)
pnt_configPage = (byte *)&configPage9; //Create a pointer to Page 10 in memory
for(int x=EEPROM_CONFIG9_START; x<EEPROM_CONFIG9_END; x++)
{
*(pnt_configPage + byte(x - EEPROM_CONFIG10_START)) = EEPROM.read(x);
*(pnt_configPage + byte(x - EEPROM_CONFIG9_START)) = EEPROM.read(x);
}
//*********************************************************************************************************************************************************************************
//CONFIG PAGE (11)
pnt_configPage = (byte *)&configPage11; //Create a pointer to Page 11 in memory
//CONFIG PAGE (10)
pnt_configPage = (byte *)&configPage10; //Create a pointer to Page 11 in memory
//All 192 bytes can simply be pulled straight from the configTable
for(int x=EEPROM_CONFIG11_START; x<EEPROM_CONFIG11_END; x++)
for(int x=EEPROM_CONFIG10_START; x<EEPROM_CONFIG10_END; x++)
{
*(pnt_configPage + byte(x - EEPROM_CONFIG11_START)) = EEPROM.read(x);
*(pnt_configPage + byte(x - EEPROM_CONFIG10_START)) = EEPROM.read(x);
}
}

View File

@ -19,12 +19,16 @@ struct table2D {
byte *values;
byte *axisX;
int *values16;
int *axisX16;
int16_t *values16;
int16_t *axisX16;
//Store the last X and Y coordinates in the table. This is used to make the next check faster
int lastXMax;
int lastXMin;
int16_t lastXMax;
int16_t lastXMin;
//Store the last input and output for caching
int16_t lastInput;
int16_t lastOutput;
};
void table2D_setSize(struct table2D targetTable, byte newSize);
@ -37,8 +41,8 @@ struct table3D {
byte ySize;
byte **values;
int *axisX;
int *axisY;
int16_t *axisX;
int16_t *axisY;
//Store the last X and Y coordinates in the table. This is used to make the next check faster
byte lastXMax, lastXMin;

View File

@ -24,8 +24,8 @@ void table2D_setSize(struct table2D* targetTable, byte newSize)
}
else
{
targetTable->values16 = (int *)realloc(targetTable->values16, newSize * sizeof(int));
targetTable->axisX16 = (int *)realloc(targetTable->axisX16, newSize * sizeof(int));
targetTable->values16 = (int16_t *)realloc(targetTable->values16, newSize * sizeof(int16_t));
targetTable->axisX16 = (int16_t *)realloc(targetTable->axisX16, newSize * sizeof(int16_t));
targetTable->xSize = newSize;
} //Byte or int
} //initialisationComplete
@ -39,8 +39,8 @@ void table3D_setSize(struct table3D *targetTable, byte newSize)
targetTable->values = (byte **)malloc(newSize * sizeof(byte*));
for(byte i = 0; i < newSize; i++) { targetTable->values[i] = (byte *)malloc(newSize * sizeof(byte)); }
targetTable->axisX = (int *)malloc(newSize * sizeof(int));
targetTable->axisY = (int *)malloc(newSize * sizeof(int));
targetTable->axisX = (int16_t *)malloc(newSize * sizeof(int16_t));
targetTable->axisY = (int16_t *)malloc(newSize * sizeof(int16_t));
targetTable->xSize = newSize;
targetTable->ySize = newSize;
} //initialisationComplete
@ -198,6 +198,9 @@ int table2D_getValue(struct table2D *fromTable, int X_in)
returnValue = yVal;
}
fromTable->lastInput = X_in;
fromTable->lastOutput = returnValue;
return returnValue;
}

View File

@ -77,14 +77,14 @@ void oneMSInterval() //Most ARM chips can simply call a function
//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 = configPage2.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
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) && (configPage2.useDwellLim) && (isCrankLocked != true) ) { endCoil1Charge(); ignitionSchedule1.Status = OFF; } }
if(ignitionSchedule2.Status == RUNNING) { if( (ignitionSchedule2.startTime < targetOverdwellTime) && (configPage2.useDwellLim) && (isCrankLocked != true) ) { endCoil2Charge(); ignitionSchedule2.Status = OFF; } }
if(ignitionSchedule3.Status == RUNNING) { if( (ignitionSchedule3.startTime < targetOverdwellTime) && (configPage2.useDwellLim) && (isCrankLocked != true) ) { endCoil3Charge(); ignitionSchedule3.Status = OFF; } }
if(ignitionSchedule4.Status == RUNNING) { if( (ignitionSchedule4.startTime < targetOverdwellTime) && (configPage2.useDwellLim) && (isCrankLocked != true) ) { endCoil4Charge(); ignitionSchedule4.Status = OFF; } }
if(ignitionSchedule5.Status == RUNNING) { if( (ignitionSchedule5.startTime < targetOverdwellTime) && (configPage2.useDwellLim) && (isCrankLocked != true) ) { endCoil5Charge(); ignitionSchedule5.Status = OFF; } }
if(ignitionSchedule1.Status == RUNNING) { if( (ignitionSchedule1.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { endCoil1Charge(); ignitionSchedule1.Status = OFF; } }
if(ignitionSchedule2.Status == RUNNING) { if( (ignitionSchedule2.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { endCoil2Charge(); ignitionSchedule2.Status = OFF; } }
if(ignitionSchedule3.Status == RUNNING) { if( (ignitionSchedule3.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { endCoil3Charge(); ignitionSchedule3.Status = OFF; } }
if(ignitionSchedule4.Status == RUNNING) { if( (ignitionSchedule4.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { endCoil4Charge(); ignitionSchedule4.Status = OFF; } }
if(ignitionSchedule5.Status == RUNNING) { if( (ignitionSchedule5.startTime < targetOverdwellTime) && (configPage4.useDwellLim) && (isCrankLocked != true) ) { endCoil5Charge(); ignitionSchedule5.Status = OFF; } }
@ -139,8 +139,8 @@ void oneMSInterval() //Most ARM chips can simply call a function
loopSec = 0; //Reset counter.
BIT_SET(TIMER_mask, BIT_TIMER_1HZ);
dwellLimit_uS = (1000 * configPage2.dwellLimit); //Update uS value incase setting has changed
currentStatus.crankRPM = ((unsigned int)configPage2.crankRPM * 100);
dwellLimit_uS = (1000 * configPage4.dwellLimit); //Update uS value incase setting has changed
currentStatus.crankRPM = ((unsigned int)configPage4.crankRPM * 100);
//**************************************************************************************************************************************************
//This updates the runSecs variable
@ -159,7 +159,7 @@ void oneMSInterval() //Most ARM chips can simply call a function
currentStatus.secl++;
//**************************************************************************************************************************************************
//Check the fan output status
if (configPage3.fanEnable == 1)
if (configPage6.fanEnable == 1)
{
fanControl(); // Fucntion to turn the cooling fan on/off
}
@ -167,7 +167,7 @@ void oneMSInterval() //Most ARM chips can simply call a function
//Check whether fuel pump priming is complete
if(fpPrimed == false)
{
if(currentStatus.secl >= configPage1.fpPrime)
if(currentStatus.secl >= configPage2.fpPrime)
{
fpPrimed = true; //Mark the priming as being completed
if(currentStatus.RPM == 0)
@ -180,7 +180,7 @@ void oneMSInterval() //Most ARM chips can simply call a function
}
//**************************************************************************************************************************************************
//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(configPage1.flexEnabled == true)
if(configPage2.flexEnabled == true)
{
if(flexCounter < 50)
{

View File

@ -8,7 +8,7 @@
void doUpdates()
{
#define CURRENT_DATA_VERSION 7
#define CURRENT_DATA_VERSION 8
uint8_t currentVersion = EEPROM.read(EEPROM_DATA_VERSION);
//May 2017 firmware introduced a -40 offset on the ignition table. Update that table to +40
@ -27,12 +27,12 @@ void doUpdates()
//June 2017 required the forced addition of some CAN values to avoid weird errors
if(currentVersion == 3)
{
configPage10.speeduino_tsCanId = 0;
configPage10.true_address = 256;
configPage10.realtime_base_address = 336;
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
if(configPage2.sparkDur == 255) { configPage2.sparkDur = 10; }
if(configPage4.sparkDur == 255) { configPage4.sparkDur = 10; }
writeAllConfig();
EEPROM.write(EEPROM_DATA_VERSION, 4);
@ -41,15 +41,15 @@ void doUpdates()
if(currentVersion == 4)
{
//Some default values for the bins (Doesn't matter too much here as the values against them will all be identical)
configPage11.crankingEnrichBins[0] = 0;
configPage11.crankingEnrichBins[1] = 40;
configPage11.crankingEnrichBins[2] = 70;
configPage11.crankingEnrichBins[3] = 100;
configPage10.crankingEnrichBins[0] = 0;
configPage10.crankingEnrichBins[1] = 40;
configPage10.crankingEnrichBins[2] = 70;
configPage10.crankingEnrichBins[3] = 100;
configPage11.crankingEnrichValues[0] = 100 + configPage1.crankingPct;
configPage11.crankingEnrichValues[1] = 100 + configPage1.crankingPct;
configPage11.crankingEnrichValues[2] = 100 + configPage1.crankingPct;
configPage11.crankingEnrichValues[3] = 100 + configPage1.crankingPct;
configPage10.crankingEnrichValues[0] = 100 + configPage2.crankingPct;
configPage10.crankingEnrichValues[1] = 100 + configPage2.crankingPct;
configPage10.crankingEnrichValues[2] = 100 + configPage2.crankingPct;
configPage10.crankingEnrichValues[3] = 100 + configPage2.crankingPct;
writeAllConfig();
EEPROM.write(EEPROM_DATA_VERSION, 5);
@ -60,7 +60,7 @@ void doUpdates()
//Data after page 4 has to move back 128 bytes
for(int x=0; x < 1152; x++)
{
int endMem = EEPROM_CONFIG11_END - x;
int endMem = EEPROM_CONFIG10_END - x;
int startMem = endMem - 128; //
byte currentVal = EEPROM.read(startMem);
EEPROM.update(endMem, currentVal);
@ -68,7 +68,7 @@ void doUpdates()
//The remaining data only has to move back 64 bytes
for(int x=0; x < 352; x++)
{
int endMem = EEPROM_CONFIG11_END - 1152 - x;
int endMem = EEPROM_CONFIG10_END - 1152 - x;
int startMem = endMem - 64; //
byte currentVal = EEPROM.read(startMem);
EEPROM.update(endMem, currentVal);
@ -83,7 +83,7 @@ void doUpdates()
//Data after page 8 has to move back 82 bytes
for(int x=0; x < 529; x++)
{
int endMem = EEPROM_CONFIG11_END - x;
int endMem = EEPROM_CONFIG10_END - x;
int startMem = endMem - 82; //
byte currentVal = EEPROM.read(startMem);
EEPROM.update(endMem, currentVal);
@ -93,10 +93,36 @@ void doUpdates()
loadConfig(); //Reload the config after changing everything in EEPROM
}
if (currentVersion == 7) {
//Convert whatever flex fuel settings are there into the new tables
configPage10.flexBoostAdj[0] = (int8_t)configPage2.unused2_1;
configPage10.flexFuelAdj[0] = configPage2.unused2_57;
configPage10.flexAdvAdj[0] = configPage2.unused2_59;
for (uint8_t x = 1; x < 6; x++)
{
uint8_t pct = x * 20;
configPage10.flexBoostBins[x] = configPage10.flexFuelBins[x] = configPage10.flexAdvBins[x] = pct;
int16_t boostAdder = (((configPage2.unused2_2 - (int8_t)configPage2.unused2_1) * pct) / 100) + (int8_t)configPage2.unused2_1;
configPage10.flexBoostAdj[x] = boostAdder;
uint8_t fuelAdder = (((configPage2.unused2_58 - configPage2.unused2_57) * pct) / 100) + configPage2.unused2_57;
configPage10.flexFuelAdj[x] = fuelAdder;
uint8_t advanceAdder = (((configPage2.unused2_60 - configPage2.unused2_59) * pct) / 100) + configPage2.unused2_59;
configPage10.flexAdvAdj[x] = advanceAdder;
}
writeAllConfig();
EEPROM.write(EEPROM_DATA_VERSION, 8);
}
//Final check is always for 255 and 0 (Brand new arduino)
if( (currentVersion == 0) || (currentVersion == 255) )
{
configPage10.true_address = 0x200;
configPage9.true_address = 0x200;
EEPROM.write(EEPROM_DATA_VERSION, CURRENT_DATA_VERSION);
}

View File

@ -48,6 +48,32 @@ byte pinTranslate(byte rawPin)
return outputPin;
}
void setResetControlPinState()
{
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_RESET_PREVENT);
/* Setup reset control initial state */
switch (resetControl)
{
case RESET_CONTROL_PREVENT_WHEN_RUNNING:
/* Set the reset control pin LOW and change it to HIGH later when we get sync. */
digitalWrite(pinResetControl, LOW);
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_RESET_PREVENT);
break;
case RESET_CONTROL_PREVENT_ALWAYS:
/* Set the reset control pin HIGH and never touch it again. */
digitalWrite(pinResetControl, HIGH);
BIT_SET(currentStatus.status3, BIT_STATUS3_RESET_PREVENT);
break;
case RESET_CONTROL_SERIAL_COMMAND:
/* Set the reset control pin HIGH. There currently isn't any practical difference
between this and PREVENT_ALWAYS but it doesn't hurt anything to have them separate. */
digitalWrite(pinResetControl, HIGH);
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_RESET_PREVENT);
break;
}
}
void setPinMapping(byte boardID)
{
switch (boardID)
@ -80,6 +106,7 @@ void setPinMapping(byte boardID)
pinFuelPump = 4; //Fuel pump output
pinTachOut = 49; //Tacho output pin
pinFlex = 19; // Flex sensor (Must be external interrupt enabled)
pinResetControl = 43; //Reset control output
#endif
break;
case 1:
@ -112,6 +139,7 @@ void setPinMapping(byte boardID)
pinFan = 47; //Pin for the fan output
pinFuelPump = 4; //Fuel pump output
pinFlex = 2; // Flex sensor (Must be external interrupt enabled)
pinResetControl = 43; //Reset control output
break;
#endif
case 2:
@ -148,6 +176,7 @@ void setPinMapping(byte boardID)
pinFan = A13; //Pin for the fan output
pinLaunch = 51; //Can be overwritten below
pinFlex = 2; // Flex sensor (Must be external interrupt enabled)
pinResetControl = 50; //Reset control output
#if defined(CORE_TEENSY)
pinTrigger = 23;
@ -196,6 +225,7 @@ void setPinMapping(byte boardID)
pinFan = 47; //Pin for the fan output (Goes to ULN2803)
pinLaunch = 51; //Can be overwritten below
pinFlex = 2; // Flex sensor (Must be external interrupt enabled)
pinResetControl = 43; //Reset control output
#if defined(CORE_TEENSY)
pinTrigger = 23;
@ -316,6 +346,7 @@ void setPinMapping(byte boardID)
pinFan = 35; //Pin for the fan output
pinLaunch = 12; //Can be overwritten below
pinFlex = 3; // Flex sensor (Must be external interrupt enabled)
pinResetControl = 44; //Reset control output
#if defined(CORE_TEENSY)
pinTrigger = 23;
@ -365,6 +396,8 @@ void setPinMapping(byte boardID)
pinFan = 47; //Pin for the fan output
pinTachOut = 49; //Tacho output pin
pinFlex = 2; // Flex sensor (Must be external interrupt enabled)
pinResetControl = 26; //Reset control output
#endif
break;
@ -400,6 +433,7 @@ void setPinMapping(byte boardID)
pinFan = 47; //Pin for the fan output
pinFuelPump = 4; //Fuel pump output
pinTachOut = 49; //Tacho output pin
pinResetControl = 26; //Reset control output
#endif
break;
@ -482,6 +516,7 @@ void setPinMapping(byte boardID)
pinSpareLOut1 = 32; //low current output spare1 - ONLY WITH DB
pinSpareLOut2 = 34; //low current output spare2 - ONLY WITH DB
pinSpareLOut3 = 36; //low current output spare3 - ONLY WITH DB
pinResetControl = 26; //Reset control output
break;
default:
@ -514,20 +549,32 @@ void setPinMapping(byte boardID)
pinFlex = 3; // Flex sensor (Must be external interrupt enabled)
pinBoost = 5;
pinIdle1 = 6;
pinResetControl = 43; //Reset control output
#endif
break;
}
//Setup any devices that are using selectable pins
if ( (configPage3.launchPin != 0) && (configPage3.launchPin < BOARD_NR_GPIO_PINS) ) { pinLaunch = pinTranslate(configPage3.launchPin); }
if ( (configPage2.ignBypassPin != 0) && (configPage2.ignBypassPin < BOARD_NR_GPIO_PINS) ) { pinIgnBypass = pinTranslate(configPage2.ignBypassPin); }
if ( (configPage1.tachoPin != 0) && (configPage1.tachoPin < BOARD_NR_GPIO_PINS) ) { pinTachOut = pinTranslate(configPage1.tachoPin); }
if ( (configPage2.fuelPumpPin != 0) && (configPage2.fuelPumpPin < BOARD_NR_GPIO_PINS) ) { pinFuelPump = pinTranslate(configPage2.fuelPumpPin); }
if ( (configPage3.fanPin != 0) && (configPage3.fanPin < BOARD_NR_GPIO_PINS) ) { pinFan = pinTranslate(configPage3.fanPin); }
if ( (configPage3.boostPin != 0) && (configPage3.boostPin < BOARD_NR_GPIO_PINS) ) { pinBoost = pinTranslate(configPage3.boostPin); }
if ( (configPage3.vvtPin != 0) && (configPage3.vvtPin < BOARD_NR_GPIO_PINS) ) { pinVVT_1 = pinTranslate(configPage3.vvtPin); }
if ( (configPage3.useExtBaro != 0) && (configPage3.baroPin < BOARD_NR_GPIO_PINS) ) { pinBaro = configPage3.baroPin + A0; }
if ( (configPage6.launchPin != 0) && (configPage6.launchPin < BOARD_NR_GPIO_PINS) ) { pinLaunch = pinTranslate(configPage6.launchPin); }
if ( (configPage4.ignBypassPin != 0) && (configPage4.ignBypassPin < BOARD_NR_GPIO_PINS) ) { pinIgnBypass = pinTranslate(configPage4.ignBypassPin); }
if ( (configPage2.tachoPin != 0) && (configPage2.tachoPin < BOARD_NR_GPIO_PINS) ) { pinTachOut = pinTranslate(configPage2.tachoPin); }
if ( (configPage4.fuelPumpPin != 0) && (configPage4.fuelPumpPin < BOARD_NR_GPIO_PINS) ) { pinFuelPump = pinTranslate(configPage4.fuelPumpPin); }
if ( (configPage6.fanPin != 0) && (configPage6.fanPin < BOARD_NR_GPIO_PINS) ) { pinFan = pinTranslate(configPage6.fanPin); }
if ( (configPage6.boostPin != 0) && (configPage6.boostPin < BOARD_NR_GPIO_PINS) ) { pinBoost = pinTranslate(configPage6.boostPin); }
if ( (configPage6.vvtPin != 0) && (configPage6.vvtPin < BOARD_NR_GPIO_PINS) ) { pinVVT_1 = pinTranslate(configPage6.vvtPin); }
if ( (configPage6.useExtBaro != 0) && (configPage6.baroPin < BOARD_NR_GPIO_PINS) ) { pinBaro = configPage6.baroPin + A0; }
/* Reset control is a special case. If reset control is enabled, it needs its initial state set BEFORE its pinMode.
If that doesn't happen and reset control is in "Serial Command" mode, the Arduino will end up in a reset loop
because the control pin will go low as soon as the pinMode is set to OUTPUT. */
if ( (configPage4.resetControl != 0) && (configPage4.resetControlPin < BOARD_NR_GPIO_PINS) )
{
resetControl = configPage4.resetControl;
pinResetControl = pinTranslate(configPage4.resetControlPin);
setResetControlPinState();
pinMode(pinResetControl, OUTPUT);
}
//Finally, set the relevant pin modes for outputs
pinMode(pinCoil1, OUTPUT);
@ -605,7 +652,7 @@ void setPinMapping(byte boardID)
pinMode(pinTrigger2, INPUT);
pinMode(pinTrigger3, INPUT);
pinMode(pinFlex, INPUT_PULLUP); //Standard GM / Continental flex sensor requires pullup
if (configPage3.lnchPullRes == true) {
if (configPage6.lnchPullRes == true) {
pinMode(pinLaunch, INPUT_PULLUP);
}
else {
@ -684,7 +731,7 @@ void initialiseTriggers()
detachInterrupt(triggerInterrupt2);
//Set the trigger function based on the decoder in the config
switch (configPage2.TrigPattern)
switch (configPage4.TrigPattern)
{
case 0:
//Missing tooth decoder
@ -695,9 +742,9 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_missingTooth;
triggerSetEndTeeth = triggerSetEndTeeth_missingTooth;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, RISING); }
if(configPage4.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, RISING); }
else { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, FALLING); }
break;
@ -709,7 +756,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_BasicDistributor;
triggerSetEndTeeth = triggerSetEndTeeth_BasicDistributor;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
break;
@ -720,9 +767,9 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_DualWheel;
triggerSetEndTeeth = triggerSetEndTeeth_DualWheel;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, RISING); }
if(configPage4.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, RISING); }
else { attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, FALLING); }
break;
@ -733,7 +780,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_GM7X;
triggerSetEndTeeth = triggerSetEndTeeth_GM7X;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
break;
@ -745,7 +792,7 @@ void initialiseTriggers()
triggerSetEndTeeth = triggerSetEndTeeth_4G63;
//These may both need to change, not sure
if(configPage2.TrigEdge == 0)
if(configPage4.TrigEdge == 0)
{
attachInterrupt(triggerInterrupt, trigger, CHANGE); // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
attachInterrupt(triggerInterrupt2, triggerSec_4G63, FALLING); //changed
@ -764,7 +811,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_24X;
triggerSetEndTeeth = triggerSetEndTeeth_24X;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_24X, CHANGE);
break;
@ -776,7 +823,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_Jeep2000;
triggerSetEndTeeth = triggerSetEndTeeth_Jeep2000;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_Jeep2000, CHANGE);
break;
@ -788,7 +835,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_Audi135;
triggerSetEndTeeth = triggerSetEndTeeth_Audi135;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
attachInterrupt(triggerInterrupt2, triggerSec_Audi135, RISING);
break;
@ -800,7 +847,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_HondaD17;
triggerSetEndTeeth = triggerSetEndTeeth_HondaD17;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_HondaD17, CHANGE);
break;
@ -814,10 +861,10 @@ void initialiseTriggers()
//These may both need to change, not sure
// Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); }
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); }
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_Miata9905, RISING); }
if(configPage4.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_Miata9905, RISING); }
else { attachInterrupt(triggerInterrupt2, triggerSec_Miata9905, FALLING); }
break;
@ -828,7 +875,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_MazdaAU;
triggerSetEndTeeth = triggerSetEndTeeth_MazdaAU;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_MazdaAU, FALLING);
break;
@ -840,7 +887,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_non360;
triggerSetEndTeeth = triggerSetEndTeeth_Non360;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, FALLING); //Note the use of the Dual Wheel trigger function here. No point in having the same code in twice.
break;
@ -852,7 +899,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_Nissan360;
triggerSetEndTeeth = triggerSetEndTeeth_Nissan360;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
attachInterrupt(triggerInterrupt2, triggerSec_Nissan360, CHANGE);
break;
@ -864,7 +911,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_Subaru67;
triggerSetEndTeeth = triggerSetEndTeeth_Subaru67;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
attachInterrupt(triggerInterrupt2, triggerSec_Subaru67, FALLING);
break;
@ -876,7 +923,7 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_Daihatsu;
triggerSetEndTeeth = triggerSetEndTeeth_Daihatsu;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
//No secondary input required for this pattern
break;
@ -901,9 +948,9 @@ void initialiseTriggers()
getCrankAngle = getCrankAngle_missingTooth; //This uses the same function as the missing tooth decoder, so no need to duplicate code
triggerSetEndTeeth = triggerSetEndTeeth_ThirtySixMinus222;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSecondary, RISING); }
if(configPage4.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSecondary, RISING); }
else { attachInterrupt(triggerInterrupt2, triggerSecondary, FALLING); }
break;
@ -912,7 +959,7 @@ void initialiseTriggers()
getRPM = getRPM_missingTooth;
getCrankAngle = getCrankAngle_missingTooth;
if(configPage2.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
if(configPage4.TrigEdge == 0) { attachInterrupt(triggerInterrupt, trigger, RISING); } // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
break;
}