Merge pull request #44 from noisymime/master

update from speedy 30092017
This commit is contained in:
Autohome2 2017-09-30 01:40:00 +01:00 committed by GitHub
commit c9dc3360f8
82 changed files with 96947 additions and 39139 deletions

4
.gitignore vendored
View File

@ -10,7 +10,11 @@ table.py
reference/hardware/v0.2/~$schematic v0.2_bom.xlsx
reference/hardware/v0.4/gerbers/Archive.zip
.pioenvs
.piolibdeps
.clang_complete
.gcc-flags.json
.project
.vscode
.build

View File

@ -59,8 +59,10 @@ script:
- cd /home/travis/build
- git clone --depth=20 https://github.com/noisymime/cppcheck.git noisymime/cppcheck
- cd noisymime/speeduino
- platformio run -e megaatmega2560 -e teensy35
- platformio update
- platformio run -e megaatmega2560 -e teensy35 -e bluepill_f103c8 -e genericSTM32F103RB
- cd ..
- chmod +x speeduino/misra/check_misra.sh
- speeduino/misra/check_misra.sh
notifications:

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<msq xmlns="http://www.msefi.com/:msq">
<bibliography author="TunerStudio MS(Beta) 3.0.26 - EFI Analytics, Inc." tuneComment="" writeDate="Wed Jul 05 15:59:26 BST 2017"/>
<versionInfo fileFormat="5.0" firmwareInfo="Speeduino+2017.06-dev" nPages="10" signature="speeduino 201706-dev"/>
<bibliography author="TunerStudio MS(Beta) 3.0.28 - EFI Analytics, Inc." tuneComment="" writeDate="Sat Sep 09 21:28:59 AEST 2017"/>
<versionInfo fileFormat="5.0" firmwareInfo="Speeduino+2017.07" nPages="11" signature="speeduino 201708"/>
<page>
<pcVariable name="tsCanId">"CAN ID 0"</pcVariable>
</page>
@ -122,9 +122,9 @@
<constant name="baroCorr">"Off"</constant>
<constant name="injLayout">"Paired"</constant>
<constant name="perToothIgn">"No"</constant>
<constant name="unused2-38h">"No"</constant>
<constant name="dfcoEnabled">"Off"</constant>
<constant digits="1" name="primePulse" units="ms">1.0</constant>
<constant digits="0" name="dutyLim" units="%">85.0</constant>
<constant digits="0" name="dutyLim" units="%">90.0</constant>
<constant digits="0" name="flexFreqLow" units="Hz">50.0</constant>
<constant digits="0" name="flexFreqHigh" units="Hz">150.0</constant>
<constant digits="0" name="boostMaxDuty" units="%">100.0</constant>
@ -214,15 +214,14 @@
<constant name="TrigEdgeSec">"Leading"</constant>
<constant name="fuelPumpPin">"Board Default"</constant>
<constant name="useResync">"No"</constant>
<constant digits="1" name="sparkDur" units="ms">25.5</constant>
<constant digits="1" name="sparkDur" units="ms">1.0</constant>
<constant digits="0" name="IdleAdvRPM" units="RPM">3200.0</constant>
<constant digits="0" name="IdleAdvCLT" units="F">-5.814</constant>
<constant digits="1" name="IdleAdvCLT" units="C">-21.0</constant>
<constant digits="0" name="IdleDelayTime" units="sec">38.0</constant>
<constant digits="0" name="StgCycles" units="cycles">2.0</constant>
<constant name="dwellcont">"Dwell control"</constant>
<constant name="useDwellLim">"On"</constant>
<constant name="sparkMode">"Wasted Spark"</constant>
<constant name="dfcoEnabled">"Off"</constant>
<constant name="TrigFilter">"Off"</constant>
<constant name="ignCranklock">"On"</constant>
<constant digits="1" name="dwellcrank" units="ms">4.5</constant>
@ -247,17 +246,17 @@
74.0
85.0
</constant>
<constant cols="1" digits="0" name="wueBins" rows="10" units="F">
-40.014
-14.814
17.586
48.186
78.786
100.386
120.186
139.986
156.186
175.986
<constant cols="1" digits="0" name="wueBins" rows="10" units="C">
-40.0
-26.0
-8.0
9.0
26.0
38.0
49.0
60.0
69.0
80.0
</constant>
<constant digits="0" name="dwellLim" units="ms">8.0</constant>
<constant cols="1" digits="0" name="dwellRates" rows="6" units="%">
@ -268,13 +267,13 @@
91.0
85.0
</constant>
<constant cols="1" digits="0" name="iatRetBins" rows="6" units="F">
136.386
179.586
199.386
219.186
240.786
283.986
<constant cols="1" digits="0" name="iatRetBins" rows="6" units="C">
58.0
82.0
93.0
104.0
116.0
140.0
</constant>
<constant cols="1" digits="0" name="iatRetRates" rows="6" units="deg">
0.0
@ -356,7 +355,7 @@
<constant digits="0" name="egoKP" units="%">100.0</constant>
<constant digits="0" name="egoKI" units="%">20.0</constant>
<constant digits="0" name="egoKD" units="%">0.0</constant>
<constant digits="0" name="egoTemp" units="F">157.986</constant>
<constant digits="0" name="egoTemp" units="C">70.0</constant>
<constant digits="0" name="egoCount">16.0</constant>
<constant digits="0" name="egoDelta" units="%">1.0</constant>
<constant digits="0" name="egoLimit">15.0</constant>
@ -366,8 +365,8 @@
<constant digits="0" name="egoRPM" units="rpm">1200.0</constant>
<constant digits="0" name="egoTPSMax" units="%">70.0</constant>
<constant name="vvtPin">"Board Default"</constant>
<constant name="unused6-13e">"ONE"</constant>
<constant name="unused6-13f">"ONE"</constant>
<constant name="useExtBaro">"No"</constant>
<constant name="boostMode">"Simple"</constant>
<constant name="boostPin">"Board Default"</constant>
<constant name="unused6-14e">"ONE"</constant>
<constant name="unused6-14f">"ONE"</constant>
@ -387,16 +386,16 @@
100.0
98.0
</constant>
<constant cols="1" digits="0" name="airDenBins" rows="9" units="F">
-40.014
-4.014
31.986
67.986
94.986
121.986
139.986
193.986
247.986
<constant cols="1" digits="0" name="airDenBins" rows="9" units="C">
-40.0
-20.0
0.0
20.0
35.0
50.0
60.0
90.0
120.0
</constant>
<constant cols="1" digits="0" name="airDenRates" rows="9" units="%">
126.0
@ -429,10 +428,7 @@
<constant name="lnchPullRes">"Pullup"</constant>
<constant name="fuelTrimEnabled">"No"</constant>
<constant name="flatSEnable">"No"</constant>
<constant name="unused6-60e">"ONE"</constant>
<constant name="unused6-60f">"ONE"</constant>
<constant name="unused6-60g">"ONE"</constant>
<constant name="unused6-60h">"ONE"</constant>
<constant name="baroPin">"A0"</constant>
<constant digits="0" name="flatSSoftWin" units="rpm">400.0</constant>
<constant digits="0" name="flatSRetard" units="deg">5.0</constant>
<constant digits="0" name="flatSArm" units="rpm">2000.0</constant>
@ -474,17 +470,17 @@
16.0
9.0
</constant>
<constant cols="1" digits="0" name="iacBins" rows="10" units="F">
-36.414
-2.214
33.786
62.586
93.186
121.986
145.386
174.186
208.386
289.386
<constant cols="1" digits="0" name="iacBins" rows="10" units="C">
-38.0
-19.0
1.0
17.0
34.0
50.0
63.0
79.0
98.0
143.0
</constant>
<constant cols="1" digits="0" name="iacCrankSteps" rows="4" units="Steps">
123.0
@ -498,30 +494,30 @@
44.0
60.0
</constant>
<constant cols="1" digits="0" name="iacCrankBins" rows="4" units="F">
-18.414
42.786
111.186
168.786
<constant cols="1" digits="0" name="iacCrankBins" rows="4" units="C">
-28.0
6.0
44.0
76.0
</constant>
<constant name="iacAlgorithm">"None"</constant>
<constant name="iacStepTime">"3"</constant>
<constant name="iacChannels">"1"</constant>
<constant name="iacPWMdir">"Normal"</constant>
<constant digits="0" name="iacFastTemp" units="F">67.986</constant>
<constant digits="0" name="iacFastTemp" units="C">20.0</constant>
<constant digits="0" name="iacStepHome" units="Steps">240.0</constant>
<constant digits="0" name="iacStepHyster" units="Steps">4.0</constant>
<constant name="fanInv">"No"</constant>
<constant name="fanEnable">"Off"</constant>
<constant name="fanPin">"Board Default"</constant>
<constant digits="0" name="fanSP" units="F">166.986</constant>
<constant digits="0" name="fanHyster" units="F">36.0</constant>
<constant digits="0" name="fanSP" units="C">75.0</constant>
<constant digits="0" name="fanHyster" units="C">2.0</constant>
<constant digits="0" name="fanFreq" units="Hz">6.0</constant>
<constant cols="1" digits="0" name="fanPWMBins" rows="4" units="F">
139.986
-4.014
-40.014
316.386
<constant cols="1" digits="0" name="fanPWMBins" rows="4" units="C">
60.0
-20.0
-40.0
158.0
</constant>
</page>
<page number="7" size="160">
@ -686,16 +682,16 @@
</page>
<page number="9" size="128">
<constant name="enable_canbus">"Disable"</constant>
<constant name="enable_candata_in">"Off"</constant>
<constant name="enable_candata_in">"On"</constant>
<constant name="caninput_sel0">"Off"</constant>
<constant name="caninput_sel1">"Off"</constant>
<constant name="caninput_sel2">"Off"</constant>
<constant name="caninput_sel3">"Off"</constant>
<constant name="caninput_sel4">"Off"</constant>
<constant name="caninput_sel5">"Off"</constant>
<constant name="caninput_sel6">"Off"</constant>
<constant name="caninput_sel7">"Off"</constant>
<constant name="caninput_sel8">"Off"</constant>
<constant name="caninput_sel1">"On"</constant>
<constant name="caninput_sel2">"On"</constant>
<constant name="caninput_sel3">"On"</constant>
<constant name="caninput_sel4">"On"</constant>
<constant name="caninput_sel5">"On"</constant>
<constant name="caninput_sel6">"On"</constant>
<constant name="caninput_sel7">"On"</constant>
<constant name="caninput_sel8">"On"</constant>
<constant name="caninput_sel9">"Off"</constant>
<constant name="caninput_sel10">"Off"</constant>
<constant name="caninput_sel11">"Off"</constant>
@ -703,22 +699,22 @@
<constant name="caninput_sel13">"Off"</constant>
<constant name="caninput_sel14">"Off"</constant>
<constant name="caninput_sel15">"Off"</constant>
<constant name="caninput_param_group0">"0x200"</constant>
<constant name="caninput_param_group1">"0x200"</constant>
<constant name="caninput_param_group2">"0x200"</constant>
<constant name="caninput_param_group3">"0x200"</constant>
<constant name="caninput_param_group4">"0x200"</constant>
<constant name="caninput_param_group5">"0x200"</constant>
<constant name="caninput_param_group6">"0x200"</constant>
<constant name="caninput_param_group7">"0x200"</constant>
<constant name="caninput_param_group8">"0x200"</constant>
<constant name="caninput_param_group9">"0x200"</constant>
<constant name="caninput_param_group10">"0x200"</constant>
<constant name="caninput_param_group11">"0x200"</constant>
<constant name="caninput_param_group12">"0x200"</constant>
<constant name="caninput_param_group13">"0x200"</constant>
<constant name="caninput_param_group14">"0x200"</constant>
<constant name="caninput_param_group15">"0x200"</constant>
<constant name="caninput_param_group0">"blank"</constant>
<constant name="caninput_param_group1">"blank"</constant>
<constant name="caninput_param_group2">"blank"</constant>
<constant name="caninput_param_group3">"blank"</constant>
<constant name="caninput_param_group4">"blank"</constant>
<constant name="caninput_param_group5">"blank"</constant>
<constant name="caninput_param_group6">"blank"</constant>
<constant name="caninput_param_group7">"blank"</constant>
<constant name="caninput_param_group8">"blank"</constant>
<constant name="caninput_param_group9">"blank"</constant>
<constant name="caninput_param_group10">"blank"</constant>
<constant name="caninput_param_group11">"blank"</constant>
<constant name="caninput_param_group12">"blank"</constant>
<constant name="caninput_param_group13">"blank"</constant>
<constant name="caninput_param_group14">"blank"</constant>
<constant name="caninput_param_group15">"blank"</constant>
<constant name="caninput_param_start_byte0">"7"</constant>
<constant name="caninput_param_start_byte1">"0"</constant>
<constant name="caninput_param_start_byte2">"0"</constant>
@ -728,13 +724,13 @@
<constant name="caninput_param_start_byte6">"0"</constant>
<constant name="caninput_param_start_byte7">"0"</constant>
<constant name="caninput_param_start_byte8">"0"</constant>
<constant name="caninput_param_start_byte9">"0"</constant>
<constant name="caninput_param_start_byte10">"0"</constant>
<constant name="caninput_param_start_byte11">"0"</constant>
<constant name="caninput_param_start_byte12">"0"</constant>
<constant name="caninput_param_start_byte13">"0"</constant>
<constant name="caninput_param_start_byte14">"0"</constant>
<constant name="caninput_param_start_byte15">"0"</constant>
<constant name="caninput_param_start_byte9">"7"</constant>
<constant name="caninput_param_start_byte10">"7"</constant>
<constant name="caninput_param_start_byte11">"7"</constant>
<constant name="caninput_param_start_byte12">"7"</constant>
<constant name="caninput_param_start_byte13">"7"</constant>
<constant name="caninput_param_start_byte14">"7"</constant>
<constant name="caninput_param_start_byte15">"7"</constant>
<constant name="caninput_param_num_bytes0">"1"</constant>
<constant name="caninput_param_num_bytes1">"1"</constant>
<constant name="caninput_param_num_bytes2">"1"</constant>
@ -785,9 +781,9 @@
<constant digits="0" name="unused10_98">255.0</constant>
<constant digits="0" name="unused10_99">255.0</constant>
<constant name="speeduino_tsCanId">"CAN ID 0"</constant>
<constant name="true_address">"0x100"</constant>
<constant name="realtime_base_address">"0x150"</constant>
<constant name="obd_address">"0x7FF"</constant>
<constant name="true_address">"0x101"</constant>
<constant name="realtime_base_address">"0x201"</constant>
<constant name="obd_address">"0x2FF"</constant>
<constant digits="0" name="unused10_107">255.0</constant>
<constant digits="0" name="unused10_108">255.0</constant>
<constant digits="0" name="unused10_109">255.0</constant>
@ -808,13 +804,27 @@
<constant digits="0" name="unused10_124">255.0</constant>
<constant digits="0" name="unused10_125">255.0</constant>
<constant digits="0" name="unused10_126">255.0</constant>
<constant digits="0" name="unused10_127">255.0</constant>
<constant digits="0" name="unused10_127">1.0</constant>
</page>
<page number="10" size="192">
<constant cols="1" digits="0" name="crankingEnrichBins" rows="4" units="C">
-40.0
0.0
30.0
70.0
</constant>
<constant cols="1" digits="0" name="crankingEnrichValues" rows="4" units="%">
138.0
115.0
105.0
100.0
</constant>
</page>
<settings Comment="These setting are only used if this msq is opened without a project.">
<setting name="enablehardware_test_OFF" value="enablehardware_test_OFF"/>
<setting name="FAHRENHEIT" value="FAHRENHEIT"/>
<setting name="SPEED_DENSITY" value="SPEED_DENSITY"/>
<setting name="CAN_COMMANDS" value="CAN_COMMANDS"/>
<setting name="CAN_COMMANDS_OFF" value="CAN_COMMANDS_OFF"/>
<setting name="CELSIUS" value="CELSIUS"/>
<setting name="AFR" value="AFR"/>
</settings>
<userComments Comment="These are user comments that can be related to a particular setting or dialog."/>

View File

@ -0,0 +1,128 @@
$fn = 100;
// standard board thicknesses (mm)
PCB_THICK_06 = 0.6;
PCB_THICK_08 = 0.8;
PCB_THICK_10 = 1.0;
PCB_THICK_12 = 1.2;
PCB_THICK_16 = 1.6;
// standard board hole diameters
PCB_HOLE_30 = 3.0;
HEIGHT = 1.8;
// standard stand-off heights
STANDOFF_4 = 3.0;
// base dimensions
BASE_THICKNESS = 3.0;
BASE_DIAMETER = 12.0;
module pcb_support(coord,hole_dia,pcb_thick,standoff_height)
{
translate(coord)
{
standoff(hole_dia,standoff_height);
translate([standoff_height,0,0]) clip(hole_dia,pcb_thick,standoff_height);
}
}
module baseWedge(hole_dia,base_thickness)
{
standoff_side = hole_dia*1.2; // width of standoff
//standoff_thickness = hole_dia * .75; // thickness of standoff bar
standoff_thickness = HEIGHT; // thickness of standoff bar
translate([0,-base_thickness,0])
linear_extrude(height=standoff_thickness)
{
polygon
(
points=
[
[-(standoff_side/2+base_thickness),0],
[-standoff_side/2,base_thickness],
[standoff_side/2,base_thickness],
[standoff_side/2+base_thickness,0]
]
);
}
}
module standoff(hole_dia,height,base_thickness)
{
standoff_side = hole_dia*1.2; // width of standoff
//standoff_thickness = hole_dia * .75; // thickness of standoff bar
standoff_thickness = HEIGHT; // thickness of standoff bar
shaft_width = hole_dia * 1.0; // width of clip part that rests inside of the PCB hole
slot_length = height/5-2; // length of cut slot
slot_width = shaft_width * 0.4; // amount of gap in the slot
base_inset = 0.1; // inset of wedge into bottom of base
// standoff
translate([-standoff_side/2,0,0])
{
difference()
{
cube([standoff_side,height,standoff_thickness]);
translate([standoff_side/2-slot_width/2,height-slot_length,0]) cube([slot_width,slot_length,standoff_thickness]);
}
}
difference()
{
baseWedge(hole_dia,base_thickness);
translate([-(standoff_side+base_thickness*2)/2,-base_thickness,0]) cube([standoff_side+base_thickness*2,base_inset,standoff_thickness]);
}
}
//pcb_support([0,0,0],3,PCB_THICK_16,8);
module clip(hole_dia,pcb_thick)
{
clip_length = pcb_thick * 3; // total length of clip
clip_width = hole_dia * 1.2; // width of clip at its widest
//clip_thickness = hole_dia * .75; // thickness of of the entire clip in the Z direction
clip_thickness = HEIGHT; // thickness of of the entire clip in the Z direction
shaft_length = pcb_thick * 1.1; // length of clip part that rests inside of the PCB hole
shaft_width = hole_dia * 0.9; // width of clip part that rests inside of the PCB hole
slot_length = clip_length; // length of cut slot
slot_width = shaft_width * 0.4; // amount of gap in the slot
clip_lip = 0.4; // overhange on one side
clip_chamfer = hole_dia/3; // side of triangle taken off of clip to produce a chamfer
translate([-shaft_width/2,0,0])
linear_extrude(height=clip_thickness)
{
polygon
(
points=
[
// left clip
[0,0],
[0,shaft_length],
[-clip_lip,shaft_length+clip_chamfer],
[-clip_lip,clip_length-clip_chamfer],
[0,clip_length],
[(shaft_width-slot_width)/2,clip_length],
[(shaft_width-slot_width)/2,clip_length-slot_length],
// right clip
[(shaft_width-slot_width)/2+slot_width,clip_length-slot_length],
[(shaft_width-slot_width)/2+slot_width,clip_length],
[shaft_width,clip_length],
[shaft_width+clip_lip,clip_length-clip_chamfer],
[shaft_width+clip_lip,shaft_length+clip_chamfer],
[shaft_width,shaft_length],
[shaft_width,0]
]
);
}
}
scale([1.8,3.2,2.5])
{
translate([0,STANDOFF_4,0]) clip(PCB_HOLE_30,PCB_THICK_16);
standoff(PCB_HOLE_30,STANDOFF_4,BASE_THICKNESS);
}

View File

@ -1,26 +0,0 @@
G04 MADE WITH FRITZING*
G04 WWW.FRITZING.ORG*
G04 DOUBLE SIDED*
G04 HOLES PLATED*
G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
%ASAXBY*%
%FSLAX23Y23*%
%MOIN*%
%OFA0B0*%
%SFA1.0B1.0*%
%ADD10R,0.984252X0.984252*%
%ADD11C,0.008000*%
%ADD10C,0.008*%
%LNCONTOUR*%
G90*
G70*
G54D10*
G54D11*
X4Y980D02*
X980Y980D01*
X980Y4D01*
X4Y4D01*
X4Y980D01*
D02*
G04 End of contour*
M02*

View File

@ -1,39 +0,0 @@
; NON-PLATED HOLES START AT T1
; THROUGH (PLATED) HOLES START AT T100
M48
INCH
T100C0.039370
T101C0.035000
T102C0.015748
%
T100
X003694Y006148
X003694Y004148
X006694Y005148
X006694Y003148
X003694Y005148
X003694Y003148
X006694Y006148
X006694Y004148
T101
X008194Y008148
X008194Y001398
X004194Y008148
X004194Y001398
T102
X002694Y001148
X005444Y003148
X004944Y004148
X002944Y006898
X001444Y002648
X000444Y009148
X002444Y002648
X001944Y001398
X009444Y007398
X005694Y007398
X004944Y001148
X000694Y007148
X005194Y008398
X006444Y007398
T00
M30

View File

@ -1,136 +0,0 @@
G04 MADE WITH FRITZING*
G04 WWW.FRITZING.ORG*
G04 DOUBLE SIDED*
G04 HOLES PLATED*
G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
%ASAXBY*%
%FSLAX23Y23*%
%MOIN*%
%OFA0B0*%
%SFA1.0B1.0*%
%ADD10C,0.049370*%
%ADD11C,0.085000*%
%ADD12C,0.089370*%
%ADD13R,0.065118X0.069055*%
%ADD14R,0.069055X0.065118*%
%ADD15R,0.089370X0.089370*%
%ADD16C,0.026000*%
%LNMASK0*%
G90*
G70*
G54D10*
X569Y740D03*
X644Y740D03*
X944Y740D03*
G54D11*
X819Y815D03*
X419Y815D03*
G54D10*
X519Y840D03*
X544Y315D03*
X194Y140D03*
X269Y115D03*
X69Y715D03*
G54D11*
X819Y140D03*
X419Y140D03*
G54D12*
X369Y615D03*
X669Y615D03*
X369Y515D03*
X669Y515D03*
X369Y415D03*
X669Y415D03*
X369Y315D03*
X669Y315D03*
G54D10*
X494Y115D03*
X244Y265D03*
X144Y265D03*
X44Y915D03*
X294Y690D03*
X494Y415D03*
G54D13*
X869Y240D03*
X789Y240D03*
X869Y440D03*
X789Y440D03*
X119Y640D03*
X200Y640D03*
X144Y365D03*
X225Y365D03*
X114Y865D03*
X194Y865D03*
X569Y915D03*
X650Y915D03*
G54D14*
X544Y615D03*
X544Y534D03*
X119Y465D03*
X119Y546D03*
G54D13*
X344Y915D03*
X425Y915D03*
X869Y340D03*
X789Y340D03*
G54D14*
X569Y140D03*
X569Y221D03*
G54D13*
X794Y640D03*
X875Y640D03*
G54D14*
X669Y215D03*
X669Y134D03*
G54D15*
X369Y615D03*
G54D16*
X330Y240D02*
X308Y240D01*
D02*
X330Y215D02*
X308Y215D01*
D02*
X330Y190D02*
X308Y190D01*
D02*
X330Y165D02*
X308Y165D01*
D02*
X330Y140D02*
X308Y140D01*
D02*
X330Y115D02*
X308Y115D01*
D02*
X330Y90D02*
X308Y90D01*
D02*
X330Y65D02*
X308Y65D01*
D02*
X118Y64D02*
X96Y64D01*
D02*
X118Y89D02*
X96Y89D01*
D02*
X118Y114D02*
X96Y114D01*
D02*
X118Y139D02*
X96Y139D01*
D02*
X118Y164D02*
X96Y164D01*
D02*
X118Y189D02*
X96Y189D01*
D02*
X118Y214D02*
X96Y214D01*
D02*
X118Y239D02*
X96Y239D01*
G04 End of Mask0*
M02*

View File

@ -1,77 +0,0 @@
G04 MADE WITH FRITZING*
G04 WWW.FRITZING.ORG*
G04 DOUBLE SIDED*
G04 HOLES PLATED*
G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
%ASAXBY*%
%FSLAX23Y23*%
%MOIN*%
%OFA0B0*%
%SFA1.0B1.0*%
%ADD10C,0.049370*%
%ADD11C,0.085000*%
%ADD12C,0.089370*%
%ADD13R,0.069055X0.065118*%
%ADD14R,0.065118X0.069055*%
%ADD15R,0.034000X0.097000*%
%ADD16R,0.089370X0.089370*%
%LNMASK1*%
G90*
G70*
G54D10*
X569Y740D03*
X644Y740D03*
X944Y740D03*
G54D11*
X819Y815D03*
X419Y815D03*
G54D10*
X519Y840D03*
X544Y315D03*
X194Y140D03*
X269Y115D03*
X69Y715D03*
G54D11*
X819Y140D03*
X419Y140D03*
G54D12*
X369Y615D03*
X669Y615D03*
X369Y515D03*
X669Y515D03*
X369Y415D03*
X669Y415D03*
X369Y315D03*
X669Y315D03*
G54D10*
X494Y115D03*
X244Y265D03*
X144Y265D03*
X44Y915D03*
X294Y690D03*
X494Y415D03*
G54D13*
X819Y590D03*
X819Y509D03*
G54D14*
X819Y665D03*
X900Y665D03*
G54D13*
X194Y365D03*
X194Y446D03*
G54D15*
X94Y584D03*
X144Y584D03*
X194Y584D03*
X244Y584D03*
X244Y790D03*
X194Y790D03*
X144Y790D03*
X94Y790D03*
G54D14*
X219Y65D03*
X139Y65D03*
G54D16*
X369Y615D03*
G04 End of Mask1*
M02*

View File

@ -1,98 +0,0 @@
G04 MADE WITH FRITZING*
G04 WWW.FRITZING.ORG*
G04 DOUBLE SIDED*
G04 HOLES PLATED*
G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
%ASAXBY*%
%FSLAX23Y23*%
%MOIN*%
%OFA0B0*%
%SFA1.0B1.0*%
%ADD10R,0.055118X0.059055*%
%ADD11R,0.059055X0.055118*%
%ADD12C,0.016000*%
%LNPASTEMASK0*%
G90*
G70*
G54D10*
X869Y240D03*
X789Y240D03*
X869Y440D03*
X789Y440D03*
X119Y640D03*
X200Y640D03*
X144Y365D03*
X225Y365D03*
X114Y865D03*
X194Y865D03*
X569Y915D03*
X650Y915D03*
G54D11*
X544Y615D03*
X544Y534D03*
X119Y465D03*
X119Y546D03*
G54D10*
X344Y915D03*
X425Y915D03*
X869Y340D03*
X789Y340D03*
G54D11*
X569Y140D03*
X569Y221D03*
G54D10*
X794Y640D03*
X875Y640D03*
G54D11*
X669Y215D03*
X669Y134D03*
G54D12*
X330Y240D02*
X308Y240D01*
D02*
X330Y215D02*
X308Y215D01*
D02*
X330Y190D02*
X308Y190D01*
D02*
X330Y165D02*
X308Y165D01*
D02*
X330Y140D02*
X308Y140D01*
D02*
X330Y115D02*
X308Y115D01*
D02*
X330Y90D02*
X308Y90D01*
D02*
X330Y65D02*
X308Y65D01*
D02*
X118Y64D02*
X96Y64D01*
D02*
X118Y89D02*
X96Y89D01*
D02*
X118Y114D02*
X96Y114D01*
D02*
X118Y139D02*
X96Y139D01*
D02*
X118Y164D02*
X96Y164D01*
D02*
X118Y189D02*
X96Y189D01*
D02*
X118Y214D02*
X96Y214D01*
D02*
X118Y239D02*
X96Y239D01*
G04 End of PasteMask0*
M02*

View File

@ -1,39 +0,0 @@
G04 MADE WITH FRITZING*
G04 WWW.FRITZING.ORG*
G04 DOUBLE SIDED*
G04 HOLES PLATED*
G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
%ASAXBY*%
%FSLAX23Y23*%
%MOIN*%
%OFA0B0*%
%SFA1.0B1.0*%
%ADD10R,0.059055X0.055118*%
%ADD11R,0.055118X0.059055*%
%ADD12R,0.024000X0.087000*%
%LNPASTEMASK1*%
G90*
G70*
G54D10*
X819Y590D03*
X819Y509D03*
G54D11*
X819Y665D03*
X900Y665D03*
G54D10*
X194Y365D03*
X194Y446D03*
G54D12*
X94Y584D03*
X144Y584D03*
X194Y584D03*
X244Y584D03*
X244Y790D03*
X194Y790D03*
X144Y790D03*
X94Y790D03*
G54D11*
X219Y65D03*
X139Y65D03*
G04 End of PasteMask1*
M02*

View File

@ -1,121 +0,0 @@
*Pick And Place List
*Company=
*Author=
*eMail=
*
*Project=VR Conditioner v2
*Date=23:30:08
*CreatedBy=Fritzing 0.9.2b.11.19.8d2d5970658f0bed09c661c9ea9a515b5f40f44c
*
*
*Coordinates in mm, always center of component
*Origin 0/0=Lower left corner of PCB
*Rotation in degree (0-360, math. pos.)
*
*No;Value;Package;X;Y;Rotation;Side;Name
1;;;22.0472;-14.8654;0;Bottom;Copper Fill43
2;;;15.9512;-6.2802;0;Bottom;Copper Fill20
3;10k;0805 [SMD];4.0589;-16.2511;180;Bottom;R13
4;;;18.9992;-15.602;0;Bottom;Copper Fill42
5;;;14.2748;-8.0455;0;Bottom;Copper Fill53
6;;;14.4145;-18.3452;0;Bottom;Copper Fill55
7;;;2.2098;-18.2055;0;Bottom;Copper Fill29
8;;;3.66888;-6.72612;0;Bottom;Via3
9;;;20.32;-11.8428;0;Bottom;Copper Fill12
10;;;22.6808;-9.35918;90;Bottom;TXT3
11;;;13.2842;-8.0455;0;Bottom;Copper Fill30
12;;;18.7452;-11.157;0;Bottom;Copper Fill44
13;;so08;4.30388;-17.4449;0;Top;IC2
14;;;13.1445;-20.8852;0;Bottom;Copper Fill31
15;;;8.4582;-6.1151;0;Bottom;Copper Fill34
16;;;16.3688;-18.7911;0;Bottom;Via14
17;;;12.3698;-4.3244;0;Bottom;Copper Fill23
18;;;7.493;-6.8898;0;Bottom;Copper Fill47
19;;;6.6802;-1.8606;0;Bottom;Copper Fill26
20;;;7.4549;-17.0752;0;Bottom;Copper Fill64
21;;DIP (Dual Inline) [THT];13.1939;-11.8061;0;Bottom;IC1
22;;;6.84388;-2.91612;0;Bottom;Via12
23;;;6.3246;-13.1636;0;Bottom;Copper Fill9
24;;;15.4178;-3.1814;0;Bottom;Copper Fill50
25;;;2.3368;-3.6386;0;Bottom;Copper Fill48
26;;;15.5194;-13.189;0;Bottom;Copper Fill13
27;;;12.5589;-2.91612;0;Bottom;Via1
28;;;13.0048;-10.5855;0;Bottom;Copper Fill57
29;;;14.4145;-19.3358;0;Bottom;Copper Fill33
30;1nF;0805 [SMD, multilayer];3.03388;-12.8311;90;Bottom;C5
31;;;22.1488;-3.5624;0;Bottom;Copper Fill22
32;;;6.477;-20.0851;0;Bottom;Copper Fill61
33;;;6.1849;-20.8344;0;Bottom;Copper Fill60
34;;;1.12888;-23.2361;0;Bottom;Via4
35;220;0805 [SMD];4.5489;-1.6461;180;Top;R2
36;;;20.536;-1.021;0;Bottom;TXT5
37;;;13.8049;-7.5502;0;Bottom;Copper Fill52
38;10k;0805 [SMD];3.91387;-21.9661;180;Bottom;R9
39;0.01µF;0805 [SMD, multilayer];21.0588;-8.6311;0;Bottom;C2
40;10k;0805 [SMD];17.0039;-4.43111;-90;Bottom;R6
41;;;2.5654;-23.476;0;Bottom;Copper Fill1
42;;;13.1939;-21.3311;0;Bottom;Via8
43;;;1.76388;-18.1561;0;Bottom;Via13
44;;;2.7432;-9.9632;0;Bottom;Copper Fill45
45;1k;0805 [SMD];13.8289;-14.5911;-90;Bottom;R3
46;;;4.93888;-3.55112;0;Bottom;Via10
47;;;23.4433;-6.87236;90;Bottom;TXT1
48;;;19.736;-0.964559;0;Bottom;TXT4
49;10k;0805 [SMD];20.8138;-13.9561;90;Top;R16
50;;;3.5052;-19.92;0;Bottom;Copper Fill5
51;10k;0805 [SMD];4.6939;-9.2661;180;Bottom;R11
52;;;7.4549;-17.0752;0;Bottom;Copper Fill35
53;;;18.923;-4.7816;0;Bottom;Copper Fill18
54;1µF;0805 [SMD, multilayer];21.0588;-11.1711;0;Bottom;C3
55;;;6.477;-14.8527;0;Bottom;Copper Fill59
56;4.7k;THT;15.7339;-3.55111;180;Bottom;R12
57;;;7.4549;-18.0658;0;Bottom;Copper Fill63
58;;;3.2004;-7.6518;0;Bottom;Copper Fill16
59;220;0805 [SMD];4.93888;-10.2911;-90;Top;R1
60;;;14.6304;-16.6942;0;Bottom;Copper Fill8
61;;;7.9248;-17.5451;0;Bottom;Copper Fill65
62;;;13.6398;-21.3551;0;Bottom;Copper Fill54
63;;;6.2484;-16.0084;0;Bottom;Copper Fill38
64;;;22.6568;-21.6726;0;Bottom;Copper Fill2
65;;;10.3632;-14.4082;0;Bottom;Copper Fill7
66;;;23.9888;-18.7911;0;Bottom;Via15
67;;;13.6398;-21.3551;0;Bottom;Copper Fill32
68;10k;0805 [SMD];15.4889;-23.2361;180;Bottom;R7
69;;;7.47888;-17.5211;0;Bottom;Via5
70;;;6.6294;-3.791;0;Bottom;Copper Fill49
71;;;3.6449;-20.8344;0;Bottom;Copper Fill62
72;;;12.5589;-10.5361;0;Bottom;Via6
73;;;2.032;-11.4618;0;Bottom;Copper Fill14
74;1nF;0805 [SMD, multilayer];9.77387;-23.2361;180;Bottom;C4
75;;;17.018;-9.7854;0;Bottom;Copper Fill46
76;;;8.0264;-21.952;0;Bottom;Copper Fill3
77;;;18.4404;-15.9576;0;Bottom;Copper Fill10
78;;;11.684;-17.9134;0;Bottom;Copper Fill39
79;;;17.0434;-21.4186;0;Bottom;Copper Fill40
80;;;6.985;-4.6038;0;Bottom;Copper Fill21
81;;;4.7244;-20.4026;0;Bottom;Copper Fill6
82;;;21.7678;-7.3724;0;Bottom;Copper Fill17
83;1k;0805 [SMD];21.2039;-16.2511;180;Bottom;R5
84;;;3.8354;-22.1298;0;Bottom;Copper Fill37
85;;;6.20888;-6.72612;0;Bottom;Via2
86;;;14.4639;-18.7911;0;Bottom;Via16
87;;;14.5796;-2.902;0;Bottom;Copper Fill25
88;;;1.5494;-14.9924;0;Bottom;Copper Fill11
89;;;2.1844;-21.4186;0;Bottom;Copper Fill36
90;;;21.8702;-9.95258;90;Bottom;TXT2
91;;;4.318;-2.6988;0;Bottom;Copper Fill24
92;;;13.8289;-7.99612;0;Bottom;Via9
93;0.1µF;0805 [SMD, multilayer];21.0588;-6.0911;0;Bottom;C1
94;;QSOP16;5.42149;-4.17341;0;Bottom;MAX9926
95;10k;0805 [SMD];21.8389;-16.8861;0;Top;R15
96;10k;0805 [SMD];14.4639;-4.5761;90;Bottom;R4
97;;;21.7678;-9.9124;0;Bottom;Copper Fill15
98;;;15.6972;-20.682;0;Bottom;Copper Fill4
99;;;6.1849;-15.602;0;Bottom;Copper Fill58
100;;;12.5349;-11.0808;0;Bottom;Copper Fill56
101;;;16.0528;-10.5855;0;Bottom;Copper Fill51
102;4.7k;THT;15.7339;-20.6961;180;Bottom;R10
103;;;11.2776;-7.22;0;Bottom;Copper Fill19
104;;;19.3802;-19.3358;0;Bottom;Copper Fill41
105;;;1.7145;-18.7008;0;Bottom;Copper Fill27
106;;;1.2192;-18.2055;0;Bottom;Copper Fill28

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
; NON-PLATED HOLES START AT T1
; THROUGH (PLATED) HOLES START AT T100
M48
INCH
T100C0.035000
T101C0.015748
T102C0.039370
T103C0.038000
%
T100
X009921Y009135
X005921Y009135
X009921Y008135
X005921Y008135
T101
X005421Y001885
X007671Y003135
T102
X004171Y006135
X007171Y007135
X004171Y004135
X007171Y005135
X004171Y007135
X004171Y005135
X007171Y006135
X007171Y004135
T103
X007921Y001510
X008921Y001510
T00
M30

View File

@ -0,0 +1,44 @@
G04 MADE WITH FRITZING*
G04 WWW.FRITZING.ORG*
G04 DOUBLE SIDED*
G04 HOLES PLATED*
G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
%ASAXBY*%
%FSLAX23Y23*%
%MOIN*%
%OFA0B0*%
%SFA1.0B1.0*%
%ADD10C,0.085000*%
%ADD11C,0.089370*%
%ADD12C,0.049370*%
%ADD13C,0.088000*%
%ADD14R,0.089370X0.089370*%
%LNMASK0*%
G90*
G70*
G54D10*
X592Y814D03*
X992Y814D03*
G54D11*
X417Y714D03*
X717Y714D03*
X417Y614D03*
X717Y614D03*
X417Y514D03*
X717Y514D03*
X417Y414D03*
X717Y414D03*
G54D10*
X992Y914D03*
X592Y914D03*
G54D12*
X767Y314D03*
G54D13*
X892Y151D03*
X792Y151D03*
G54D12*
X542Y189D03*
G54D14*
X417Y714D03*
G04 End of Mask0*
M02*

View File

@ -0,0 +1,122 @@
G04 MADE WITH FRITZING*
G04 WWW.FRITZING.ORG*
G04 DOUBLE SIDED*
G04 HOLES PLATED*
G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
%ASAXBY*%
%FSLAX23Y23*%
%MOIN*%
%OFA0B0*%
%SFA1.0B1.0*%
%ADD10C,0.085000*%
%ADD11C,0.089370*%
%ADD12C,0.049370*%
%ADD13C,0.088000*%
%ADD14R,0.089370X0.089370*%
%ADD15R,0.065118X0.069055*%
%ADD16R,0.069055X0.065118*%
%ADD17C,0.026000*%
%LNMASK1*%
G90*
G70*
G54D10*
X592Y814D03*
X992Y814D03*
G54D11*
X417Y714D03*
X717Y714D03*
X417Y614D03*
X717Y614D03*
X417Y514D03*
X717Y514D03*
X417Y414D03*
X717Y414D03*
G54D10*
X992Y914D03*
X592Y914D03*
G54D12*
X767Y314D03*
G54D13*
X892Y151D03*
X792Y151D03*
G54D12*
X542Y189D03*
G54D14*
X417Y714D03*
G54D15*
X830Y714D03*
X910Y714D03*
X830Y614D03*
X910Y614D03*
X830Y514D03*
X910Y514D03*
G54D16*
X830Y426D03*
X830Y345D03*
X930Y426D03*
X930Y345D03*
G54D15*
X317Y914D03*
X398Y914D03*
X767Y1001D03*
X848Y1001D03*
G54D16*
X242Y914D03*
X242Y994D03*
G54D15*
X242Y664D03*
X323Y664D03*
X317Y564D03*
X236Y564D03*
X242Y464D03*
X323Y464D03*
G54D17*
X690Y138D02*
X668Y138D01*
D02*
X690Y163D02*
X668Y163D01*
D02*
X690Y188D02*
X668Y188D01*
D02*
X690Y213D02*
X668Y213D01*
D02*
X690Y238D02*
X668Y238D01*
D02*
X690Y263D02*
X668Y263D01*
D02*
X690Y288D02*
X668Y288D01*
D02*
X690Y313D02*
X668Y313D01*
D02*
X478Y314D02*
X456Y314D01*
D02*
X478Y289D02*
X456Y289D01*
D02*
X478Y264D02*
X456Y264D01*
D02*
X478Y239D02*
X456Y239D01*
D02*
X478Y214D02*
X456Y214D01*
D02*
X478Y189D02*
X456Y189D01*
D02*
X478Y164D02*
X456Y164D01*
D02*
X478Y139D02*
X456Y139D01*
G04 End of Mask1*
M02*

View File

@ -0,0 +1,93 @@
G04 MADE WITH FRITZING*
G04 WWW.FRITZING.ORG*
G04 DOUBLE SIDED*
G04 HOLES PLATED*
G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
%ASAXBY*%
%FSLAX23Y23*%
%MOIN*%
%OFA0B0*%
%SFA1.0B1.0*%
%ADD10R,0.055118X0.059055*%
%ADD11R,0.059055X0.055118*%
%ADD12C,0.016000*%
%LNPASTEMASK1*%
G90*
G70*
G54D10*
X830Y714D03*
X910Y714D03*
X830Y614D03*
X910Y614D03*
X830Y514D03*
X910Y514D03*
G54D11*
X830Y426D03*
X830Y345D03*
X930Y426D03*
X930Y345D03*
G54D10*
X317Y914D03*
X398Y914D03*
X767Y1001D03*
X848Y1001D03*
G54D11*
X242Y914D03*
X242Y994D03*
G54D10*
X242Y664D03*
X323Y664D03*
X317Y564D03*
X236Y564D03*
X242Y464D03*
X323Y464D03*
G54D12*
X690Y138D02*
X668Y138D01*
D02*
X690Y163D02*
X668Y163D01*
D02*
X690Y188D02*
X668Y188D01*
D02*
X690Y213D02*
X668Y213D01*
D02*
X690Y238D02*
X668Y238D01*
D02*
X690Y263D02*
X668Y263D01*
D02*
X690Y288D02*
X668Y288D01*
D02*
X690Y313D02*
X668Y313D01*
D02*
X478Y314D02*
X456Y314D01*
D02*
X478Y289D02*
X456Y289D01*
D02*
X478Y264D02*
X456Y264D01*
D02*
X478Y239D02*
X456Y239D01*
D02*
X478Y214D02*
X456Y214D01*
D02*
X478Y189D02*
X456Y189D01*
D02*
X478Y164D02*
X456Y164D01*
D02*
X478Y139D02*
X456Y139D01*
G04 End of PasteMask1*
M02*

View File

@ -0,0 +1,67 @@
*Pick And Place List
*Company=
*Author=
*eMail=
*
*Project=VR Conditioner v3
*Date=19:16:10
*CreatedBy=Fritzing 0.9.3b.04.19.5c895d327c44a3114e5fcc9d8260daf0cbb52806
*
*
*Coordinates in mm, always center of component
*Origin 0/0=Lower left corner of PCB
*Rotation in degree (0-360, math. pos.)
*
*No;Value;Package;X;Y;Rotation;Side;Name
1;;DIP (Dual Inline) [THT];14.4059;-14.3144;0;Bottom;IC1
2;;;15.9512;-14.2933;0;Bottom;Copper Fill24
3;;;22.1742;-8.04494;0;Bottom;Copper Fill20
4;4.7k;THT;20.1209;-20.6644;0;Bottom;R12
5;;;19.4858;-7.96443;0;Bottom;Via14
6;;;6.0564;-7.14176;0;Bottom;TXT5
7;;;12.7;-19.3987;0;Bottom;Copper Fill2
8;1k;0805 [SMD];23.6134;-9.79692;90;Top;R4
9;4.7k;THT;20.1209;-23.2044;180;Bottom;R10
10;;;19.2786;-11.7787;0;Bottom;Copper Fill10
11;;;11.4554;-6.76224;0;Bottom;Copper Fill25
12;1nF;0805 [SMD, multilayer];6.15085;-24.2294;-90;Top;C4
13;;;16.9926;-11.4485;0;Bottom;Copper Fill9
14;;;13.9954;-14.4965;0;Bottom;Copper Fill1
15;10k;0805 [SMD];20.5109;-25.4269;0;Top;R7
16;;;19.2786;-14.1663;0;Bottom;Copper Fill8
17;;;17.1704;-14.2933;0;Bottom;Copper Fill7
18;;;17.5514;-6.76224;0;Bottom;Copper Fill29
19;;;18.5928;-4.28574;0;Bottom;Copper Fill23
20;;;4.572;-23.9707;0;Bottom;Copper Fill11
21;;;25.6196;-12.6698;-90;Bottom;TXT3
22;;;7.47786;-7.22642;0;Bottom;TXT4
23;;;17.9832;-16.3761;0;Bottom;Copper Fill3
24;10k;0805 [SMD];7.17586;-16.8544;0;Top;R13
25;0.01µF;0805 [SMD, multilayer];22.0984;-15.5844;0;Top;C2
26;;;13.7708;-4.78943;0;Bottom;Via15
27;;;21.082;-12.2613;0;Bottom;Copper Fill5
28;;;24.2316;-15.3601;0;Bottom;Copper Fill16
29;;;9.6012;-13.7091;0;Bottom;Copper Fill12
30;1k;0805 [SMD];21.0734;-9.79692;90;Top;R6
31;1nF;0805 [SMD, multilayer];7.03084;-14.3144;180;Top;C5
32;0.1µF;0805 [SMD, multilayer];22.0984;-13.0444;0;Top;C1
33;;THT;21.3909;-3.83692;90;Bottom;J1
34;;;17.1704;-16.8333;0;Bottom;Copper Fill6
35;;QSOP16;14.5583;-5.41172;180;Top;MAX9926
36;;;14.2735;-25.0931;0;Bottom;TXT1
37;;;20.701;-15.1061;0;Bottom;Copper Fill15
38;10k;0805 [SMD];7.17586;-11.7744;0;Top;R11
39;;;17.5514;-4.83184;0;Bottom;Copper Fill27
40;;;11.6586;-14.4711;0;Bottom;Copper Fill18
41;;;20.2946;-7.13054;0;Bottom;Copper Fill22
42;;;11.4554;-5.49224;0;Bottom;Copper Fill28
43;;;12.9286;-16.9349;0;Bottom;Copper Fill4
44;10k;0805 [SMD];9.08086;-23.2044;0;Top;R9
45;;;7.2644;-19.3733;0;Bottom;Copper Fill13
46;;;10.287;-19.0685;0;Bottom;Copper Fill14
47;;;17.2085;-3.37134;0;Bottom;Copper Fill26
48;;;9.9568;-14.2933;0;Bottom;Copper Fill19
49;;;22.4815;-12.723;-90;Bottom;IMG1
50;1µF;0805 [SMD, multilayer];22.0984;-18.1244;0;Top;C3
51;;;8.2804;-14.3187;0;Bottom;Copper Fill17
52;;;24.4094;-6.57174;0;Bottom;Copper Fill21

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.2" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" width="120" height="120" viewBox="0 0 120 120" xml:space="preserve">
<g id="board">
<rect fill="#338040" x="10" y="10" width="100" height="100" rx="15" ry="15"/>
</g>
<g id="silkscreen">
<rect fill="none" stroke="#FFFFFF" stroke-width="0.576" x="10" y="10" width="100" height="100" rx="15" ry="15"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 516 B

File diff suppressed because it is too large Load Diff

View File

@ -21,8 +21,8 @@ T1
X035411Y031280
X037661Y012280
T2
X001411Y021530
X001411Y030530
X001437Y021481
X001437Y030579
T100
X036411Y034811
X036411Y036780
@ -37,21 +37,39 @@ X033911Y036983
T103
X018161Y033045
X025911Y023030
X026161Y015030
X024927Y023030
X018161Y034030
X025177Y015030
X026161Y015030
X018161Y034030
X018161Y035045
X025177Y017030
X005421Y033789
X005421Y032805
X026161Y017030
X018161Y036030
X025177Y017030
X024927Y021030
X025911Y021030
X005421Y035789
X005421Y034805
X024927Y021030
X024927Y023030
T104
X010911Y032530
X023161Y010780
X020911Y010280
X037911Y006280
X023161Y006780
X016411Y014530
X031911Y014530
X031411Y002280
X017411Y006030
X017411Y018530
X032911Y007280
X019661Y030280
X024161Y036280
X024161Y013780
X032911Y010280
X016661Y037780
X004661Y019030
X019661Y026280
X016652Y033521
X020661Y030280
X016661Y035530
@ -59,31 +77,31 @@ X020661Y026280
X031661Y023280
X029161Y013280
X012911Y011280
X029911Y006030
X021411Y006030
X035911Y017530
X029911Y006030
X015911Y011030
X023661Y030280
X016661Y034530
X022661Y021030
X023661Y030280
X020661Y018780
X012911Y007280
X031661Y022280
X015911Y007030
X021911Y007280
X012411Y006280
X021911Y007280
X037911Y002280
X023661Y025030
X023661Y026280
X035911Y016530
X029911Y005030
X030911Y007280
X035911Y016530
X021911Y010280
X017661Y030280
X030911Y010280
X031661Y021280
X021911Y018780
X017411Y014530
X021911Y018780
X017661Y026280
X016661Y029530
X023161Y017780
@ -117,20 +135,20 @@ X010911Y036530
X025911Y030030
X012652Y033521
X024661Y025030
X035661Y023280
X020661Y013780
X035661Y023280
X016411Y018530
X031911Y007280
X006911Y033530
X018661Y030280
X012661Y035530
X018661Y030280
X016661Y025530
X010911Y035530
X023161Y013780
X031911Y010280
X018661Y026280
X035661Y022280
X025161Y013280
X035661Y022280
X024161Y017780
X016411Y006280
X031911Y017530
@ -140,8 +158,8 @@ X021911Y013780
X012661Y034530
X010911Y034530
X035661Y021280
X031911Y016530
X019911Y007280
X031911Y016530
X010911Y033530
X014911Y011030
X019911Y010280
@ -154,25 +172,20 @@ X020911Y007280
X022661Y025030
X022661Y026280
X012661Y032530
X010911Y032530
X023161Y010780
X020911Y010280
X037911Y006280
X023161Y006780
X016411Y014530
X031911Y014530
X031411Y002280
X017411Y006030
X017411Y018530
X032911Y007280
X019661Y030280
X024161Y036280
X024161Y013780
X032911Y010280
X016661Y037780
X004661Y019030
X019661Y026280
T105
X037911Y025280
X017911Y012280
X036911Y017280
X017911Y031280
X026911Y012280
X026911Y031280
X036911Y020280
X035911Y012280
X037911Y024280
X036911Y016280
X012311Y031280
X029911Y012280
X029911Y031280
X037911Y023280
X012911Y012280
X036911Y015280
@ -191,22 +204,22 @@ X009311Y031280
X024911Y031280
X036911Y029280
X033911Y012280
X033911Y031280
X037911Y021280
X033911Y031280
X037911Y017280
X010311Y031280
X018911Y031280
X036911Y028280
X027911Y031280
X037911Y020280
X010911Y012280
X036911Y031280
X010911Y012280
X037911Y016280
X036911Y027280
X013311Y031280
X036911Y030280
X013911Y012280
X037911Y015280
X013911Y012280
X022911Y012280
X036911Y026280
X007311Y031280
@ -224,15 +237,15 @@ X036911Y024280
X019911Y012280
X011311Y031280
X019911Y031280
X028911Y012280
X037911Y028280
X028911Y012280
X028911Y031280
X037911Y031280
X036911Y023280
X011911Y012280
X020911Y012280
X020911Y031280
X037911Y027280
X020911Y031280
X036911Y019280
X014311Y031280
X037911Y030280
@ -240,32 +253,18 @@ X036911Y022280
X014911Y012280
X037911Y026280
X023911Y012280
X008311Y031280
X036911Y018280
X008311Y031280
X023911Y031280
X032911Y012280
X032911Y031280
X036911Y021280
X037911Y025280
X017911Y012280
X036911Y017280
X017911Y031280
X026911Y012280
X026911Y031280
X036911Y020280
X035911Y012280
X037911Y024280
X036911Y016280
X012311Y031280
X029911Y012280
X029911Y031280
T106
X008911Y011780
X007911Y016780
X008911Y003780
X007911Y008780
X008911Y016780
X008911Y008780
X006161Y024530
X007911Y022780
X007911Y014780
X008911Y022780
@ -275,6 +274,7 @@ X007911Y019780
X008911Y006780
X008911Y019780
X007911Y020780
X006161Y027530
X007911Y012780
X008911Y020780
X007911Y004780
@ -284,13 +284,16 @@ X008911Y004780
X007911Y009780
X008911Y017780
X008911Y009780
X006161Y025530
X007911Y010780
X006161Y023529
X008911Y010780
X007911Y015780
X007911Y007780
X008911Y015780
X008911Y007780
X007911Y021780
X006161Y028530
X007911Y013780
X008911Y021780
X007911Y005780
@ -298,124 +301,137 @@ X008911Y013780
X007911Y018780
X008911Y005780
X008911Y018780
X006161Y026530
X007911Y011780
X007911Y003780
X008911Y011780
X007911Y016780
T107
X014911Y025030
X020661Y024780
X021931Y037280
X014911Y025030
X030661Y036280
X003891Y037780
X025161Y033280
X001411Y033030
X003411Y033030
X014911Y028280
X018661Y022280
X021161Y033030
X002411Y033030
X011911Y010760
X019661Y022280
X022161Y033030
X020161Y033030
X014911Y023030
X001411Y033030
X003411Y033030
X018661Y022280
X021161Y033030
X030661Y033300
X028661Y037030
X026661Y037030
X020661Y022280
X027661Y037030
X028661Y037030
X002421Y035289
X000911Y036530
X014911Y029280
X001421Y035289
X003421Y035289
X002421Y035289
X014911Y024030
X000911Y036530
X020911Y037280
X018661Y024780
X019661Y024780
X014911Y027280
X024911Y037280
X020911Y037280
X018661Y024780
X011911Y007780
X000911Y037780
X017931Y037280
X021161Y035280
X003891Y036530
X025161Y036260
X022161Y035280
X020161Y035280
X000911Y037780
X020661Y024780
X021161Y035280
T108
X014411Y014530
X032161Y033780
X013911Y013780
X015411Y014530
X028911Y035280
X028661Y010030
X029911Y030030
X017411Y008280
X026911Y033280
X028911Y030030
X026661Y021030
X037911Y011030
X031661Y013530
X033661Y013530
X028911Y033280
X004911Y018030
X002911Y018030
X024411Y003280
X007661Y028530
X030911Y030030
X032911Y030030
X034911Y030030
X024411Y008280
X026411Y003280
X031911Y030030
X033911Y030030
X035911Y030030
X029911Y025030
X025911Y010280
X007661Y026530
X028911Y025030
X032411Y037280
X030411Y037280
X017411Y010280
X030911Y025030
X032911Y025030
X034911Y025030
X028661Y008030
X031911Y025030
X033911Y025030
X035911Y025030
X014661Y003780
X016661Y003780
X011411Y003780
X013411Y003780
X037911Y009030
X013911Y009780
X024411Y010280
X025411Y005780
X023411Y005780
X014411Y016530
X032161Y035780
X015411Y016530
X025911Y008280
X013911Y007780
X011911Y013780
X004911Y016780
X002911Y016780
X026911Y035280
X028911Y035280
X028661Y010030
X026661Y023030
X014411Y014530
X032161Y033780
X028911Y030030
X015411Y014530
X029911Y030030
X017411Y008280
X031661Y013530
X033661Y013530
X026911Y033280
X028911Y033280
X026661Y021030
X037911Y011030
X004911Y018030
X002911Y018030
X024411Y003280
X026411Y003280
X007661Y028530
X031911Y030030
X033911Y030030
X035911Y030030
X025911Y010280
X030911Y030030
X032911Y030030
X034911Y030030
X024411Y008280
X028911Y025030
X029911Y025030
X007661Y026530
X028661Y008030
X032411Y037280
X030411Y037280
X031911Y025030
X033911Y025030
X035911Y025030
X017411Y010280
X030911Y025030
X032911Y025030
X034911Y025030
X011411Y003780
X013411Y003780
X013911Y009780
X023411Y005780
X014661Y003780
X016661Y003780
X037911Y009030
X024411Y010280
X025911Y008280
X013911Y007780
X025411Y005780
X014411Y016530
X032161Y035780
X015411Y016530
T109
X001911Y009530
X001911Y012530
X005911Y002530
X035661Y008780
X004911Y013530
X003911Y005530
X001911Y008530
X004911Y009530
X001911Y011530
X004911Y012530
X003911Y004530
X002911Y015530
X001911Y007530
X035661Y010780
X004911Y008530
X001911Y010530
X006161Y026530
X004911Y011530
X003911Y003530
X002911Y014530
X001911Y006530
X005911Y015530
X004911Y007530
X006161Y025530
X005911Y015530
X004911Y010530
X003911Y002530
X002911Y013530
@ -423,27 +439,25 @@ X001911Y005530
X005911Y014530
X004911Y006530
X002911Y009530
X006161Y024530
X027911Y028280
X002911Y012530
X001911Y004530
X005911Y013530
X029911Y004030
X005911Y013530
X004911Y005530
X035661Y007280
X002911Y008530
X006161Y023530
X027911Y027280
X005911Y009530
X002911Y011530
X001911Y003530
X032661Y004030
X005911Y012530
X030911Y004030
X005911Y012530
X004911Y004530
X035661Y006280
X003911Y015530
X002911Y007530
X003911Y015530
X027911Y026280
X005911Y008530
X002911Y010530
@ -462,16 +476,16 @@ X005911Y006530
X003911Y009530
X003911Y012530
X002911Y004530
X005911Y005530
X001911Y015530
X005911Y005530
X003911Y008530
X003911Y011530
X002911Y003530
X033661Y004030
X005911Y004530
X001911Y014530
X003911Y007530
X005911Y004530
X004911Y015530
X003911Y007530
X003911Y010530
X002911Y002530
X001911Y013530
@ -479,25 +493,7 @@ X005911Y003530
X035661Y009780
X004911Y014530
X003911Y006530
X001911Y009530
X001911Y012530
X005911Y002530
X006161Y028530
X035661Y008780
X004911Y013530
X003911Y005530
X001911Y008530
X004911Y009530
X001911Y011530
X006161Y027530
X004911Y012530
X003911Y004530
X002911Y015530
T110
X027661Y023530
X030661Y022530
X027661Y014530
X030661Y023530
X027661Y015530
X030661Y014530
X027661Y016530
@ -510,49 +506,54 @@ X030661Y020530
X030661Y017530
X027661Y022530
X030661Y021530
X027661Y023530
X030661Y022530
X027661Y014530
X030661Y023530
T111
X012411Y016280
X021411Y016780
X018911Y012280
X035661Y004280
X030661Y006030
X038161Y013030
X013411Y016280
X006411Y017530
X034911Y025780
X036911Y013030
X012411Y016280
X028661Y015030
X031661Y004030
X034911Y025780
X027661Y018280
X015911Y036030
X013661Y036780
X033161Y016030
X015411Y008030
X015911Y036030
X001661Y026530
X033911Y023780
X034911Y028780
X027911Y018780
X003911Y019530
X013161Y014780
X035911Y028780
X001661Y026530
X038161Y007780
X034911Y028780
X027911Y018780
X034911Y027030
X009661Y026530
X038161Y007780
X007161Y025530
X025411Y029030
X037161Y004280
X006161Y022030
X016911Y016280
X028661Y017530
X038661Y020780
X020161Y029530
X022161Y029530
X006161Y022030
X028661Y017530
X012411Y003780
X038661Y020780
X029661Y023530
X015023Y006280
X030661Y002780
X029661Y023530
X010661Y003530
X035161Y018280
X030661Y006030
X030661Y002780
X031161Y008530
X008911Y032780
X036911Y013030
X021411Y016780
X018911Y012280
X035161Y018280
X035661Y004280
T00
M30

View File

@ -8,23 +8,23 @@ G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
%MOIN*%
%OFA0B0*%
%SFA1.0B1.0*%
%ADD10C,0.049370*%
%ADD11C,0.085000*%
%ADD12C,0.080000*%
%ADD13C,0.088000*%
%ADD14C,0.140000*%
%ADD15C,0.084000*%
%ADD16C,0.082917*%
%ADD17C,0.135984*%
%ADD18C,0.175354*%
%ADD10C,0.084000*%
%ADD11C,0.175354*%
%ADD12C,0.049370*%
%ADD13C,0.085000*%
%ADD14C,0.080000*%
%ADD15C,0.088000*%
%ADD16C,0.140000*%
%ADD17C,0.082917*%
%ADD18C,0.135984*%
%ADD19C,0.092000*%
%ADD20C,0.061496*%
%ADD21C,0.089370*%
%ADD22C,0.072992*%
%ADD23C,0.109055*%
%ADD24R,0.080000X0.080000*%
%ADD25R,0.085000X0.085000*%
%ADD26R,0.084000X0.084000*%
%ADD24R,0.084000X0.084000*%
%ADD25R,0.080000X0.080000*%
%ADD26R,0.085000X0.085000*%
%ADD27R,0.092000X0.092000*%
%ADD28R,0.089370X0.089370*%
%ADD29R,0.072992X0.072992*%
@ -33,12 +33,33 @@ G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
G90*
G70*
G54D10*
X616Y2853D03*
X616Y2753D03*
X616Y2653D03*
X616Y2553D03*
X616Y2453D03*
X616Y2353D03*
G54D11*
X144Y3058D03*
X144Y2148D03*
G54D10*
X616Y2853D03*
X616Y2753D03*
X616Y2653D03*
X616Y2553D03*
X616Y2453D03*
X616Y2353D03*
G54D11*
X144Y3058D03*
X144Y2148D03*
G54D12*
X1366Y3678D03*
X3691Y1303D03*
X3816Y1303D03*
G54D11*
G54D13*
X2416Y3628D03*
X2416Y3228D03*
G54D10*
G54D12*
X3491Y2878D03*
X3491Y2703D03*
X3491Y2578D03*
@ -56,7 +77,7 @@ X2866Y1753D03*
X2966Y2353D03*
X3391Y2378D03*
X1502Y628D03*
G54D12*
G54D14*
X3591Y3003D03*
X3591Y2503D03*
X3491Y3003D03*
@ -73,7 +94,7 @@ X2991Y3003D03*
X2991Y2503D03*
X2891Y3003D03*
X2891Y2503D03*
G54D10*
G54D12*
X3866Y2078D03*
X1591Y3603D03*
X3166Y403D03*
@ -82,12 +103,12 @@ X3816Y778D03*
X891Y3278D03*
X1541Y803D03*
X1891Y1228D03*
G54D11*
G54D13*
X3791Y228D03*
X3791Y628D03*
X3141Y228D03*
X3541Y228D03*
G54D13*
G54D15*
X191Y1553D03*
X291Y1553D03*
X391Y1553D03*
@ -158,7 +179,7 @@ X591Y1153D03*
X591Y1253D03*
X591Y1353D03*
X591Y1453D03*
G54D11*
G54D13*
X1891Y728D03*
X1891Y1028D03*
X1991Y728D03*
@ -167,12 +188,12 @@ X2091Y728D03*
X2091Y1028D03*
X2191Y728D03*
X2191Y1028D03*
G54D14*
G54D16*
X1241Y2628D03*
X1241Y2828D03*
X1241Y2428D03*
X1241Y2228D03*
G54D10*
G54D12*
X1316Y1478D03*
X3316Y1603D03*
X2866Y1503D03*
@ -189,7 +210,7 @@ X2766Y1828D03*
X1241Y1628D03*
X1341Y1628D03*
X3516Y1828D03*
G54D11*
G54D13*
X3091Y728D03*
X3091Y1028D03*
X3191Y728D03*
@ -198,7 +219,7 @@ X3291Y728D03*
X3291Y1028D03*
X3391Y728D03*
X3391Y1028D03*
G54D15*
G54D10*
X891Y2278D03*
X891Y2178D03*
X891Y2078D03*
@ -239,7 +260,7 @@ X791Y678D03*
X791Y578D03*
X791Y478D03*
X791Y378D03*
G54D16*
G54D17*
X2991Y1228D03*
X1391Y1228D03*
X3091Y1228D03*
@ -326,11 +347,9 @@ X3791Y1628D03*
X3791Y1528D03*
X3791Y1428D03*
X2891Y1228D03*
G54D17*
G54D18*
X3766Y1228D03*
X3541Y3128D03*
G54D18*
X141Y3053D03*
G54D19*
X1491Y2503D03*
X1491Y2403D03*
@ -344,27 +363,19 @@ X1491Y2728D03*
X2066Y2228D03*
X1966Y2228D03*
X1866Y2228D03*
G54D12*
G54D14*
X1191Y1378D03*
X1391Y1378D03*
G54D11*
G54D13*
X1291Y728D03*
X1291Y1128D03*
G54D19*
X2516Y3328D03*
X2516Y3626D03*
G54D11*
G54D13*
X466Y1903D03*
X66Y1903D03*
G54D18*
X141Y2153D03*
G54D13*
X616Y2853D03*
X616Y2753D03*
X616Y2653D03*
X616Y2553D03*
X616Y2453D03*
X616Y2353D03*
G54D15*
X3566Y528D03*
X3566Y628D03*
X3566Y728D03*
@ -374,17 +385,17 @@ X3566Y878D03*
X2791Y2828D03*
X2791Y2728D03*
X2791Y2628D03*
G54D11*
G54D13*
X2991Y603D03*
X3391Y603D03*
X2991Y503D03*
X3391Y503D03*
G54D13*
G54D15*
X2991Y403D03*
X3091Y403D03*
X3266Y403D03*
X3366Y403D03*
G54D11*
G54D13*
X3591Y1453D03*
X3191Y1453D03*
X2366Y3028D03*
@ -405,7 +416,7 @@ G54D19*
X2666Y3703D03*
X2766Y3703D03*
X2866Y3703D03*
G54D12*
G54D14*
X3041Y3728D03*
X3241Y3728D03*
X2891Y3528D03*
@ -437,7 +448,7 @@ X3066Y2253D03*
X2766Y2253D03*
X3066Y2353D03*
X2766Y2353D03*
G54D11*
G54D13*
X3591Y1553D03*
X3191Y1553D03*
X1866Y3028D03*
@ -454,16 +465,16 @@ X1766Y3028D03*
X1766Y2628D03*
X3566Y2228D03*
X3166Y2228D03*
G54D12*
G54D14*
X3366Y1353D03*
X3166Y1353D03*
G54D11*
G54D13*
X2066Y1378D03*
X2066Y1878D03*
G54D12*
G54D14*
X2666Y2103D03*
X2666Y2303D03*
G54D11*
G54D13*
X2591Y2503D03*
X2591Y3003D03*
X2191Y1878D03*
@ -487,14 +498,14 @@ X2518Y1503D03*
X2616Y1503D03*
X2493Y2103D03*
X2591Y2103D03*
G54D11*
G54D13*
X1741Y1853D03*
X1741Y1453D03*
X2141Y603D03*
X1741Y603D03*
X1641Y628D03*
X1241Y628D03*
G54D12*
G54D14*
X1741Y828D03*
X1741Y1028D03*
X1666Y378D03*
@ -503,7 +514,7 @@ X1391Y778D03*
X1391Y978D03*
X1341Y378D03*
X1141Y378D03*
G54D11*
G54D13*
X1591Y703D03*
X1591Y1103D03*
X1491Y703D03*
@ -511,7 +522,7 @@ X1491Y1103D03*
G54D19*
X1191Y778D03*
X1191Y1076D03*
G54D12*
G54D14*
X2866Y803D03*
X2866Y1003D03*
X291Y1678D03*
@ -526,14 +537,14 @@ X2341Y578D03*
X2541Y578D03*
X2641Y328D03*
X2441Y328D03*
G54D11*
G54D13*
X2766Y678D03*
X2766Y1078D03*
X2316Y678D03*
X2316Y1078D03*
X2916Y1328D03*
X2516Y1328D03*
G54D12*
G54D14*
X1441Y1453D03*
X1441Y1653D03*
X2591Y828D03*
@ -542,7 +553,7 @@ X3791Y1103D03*
X3791Y903D03*
X1541Y1653D03*
X1541Y1453D03*
G54D11*
G54D13*
X1641Y1853D03*
X1641Y1453D03*
X1091Y3253D03*
@ -583,7 +594,7 @@ X142Y3529D03*
X2016Y3528D03*
X2116Y3528D03*
X2216Y3528D03*
G54D11*
G54D13*
X1091Y3353D03*
X691Y3353D03*
X1265Y3352D03*
@ -604,12 +615,15 @@ G54D23*
X3641Y3678D03*
X3641Y3481D03*
G54D24*
X616Y2853D03*
X616Y2853D03*
G54D25*
X2891Y2503D03*
X3491Y2503D03*
G54D25*
G54D26*
X1891Y728D03*
X3091Y728D03*
G54D26*
G54D24*
X791Y2278D03*
G54D27*
X1491Y2503D03*

View File

@ -8,23 +8,23 @@ G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
%MOIN*%
%OFA0B0*%
%SFA1.0B1.0*%
%ADD10C,0.049370*%
%ADD11C,0.085000*%
%ADD12C,0.080000*%
%ADD13C,0.088000*%
%ADD14C,0.140000*%
%ADD15C,0.084000*%
%ADD16C,0.082917*%
%ADD17C,0.135984*%
%ADD18C,0.175354*%
%ADD10C,0.084000*%
%ADD11C,0.175354*%
%ADD12C,0.049370*%
%ADD13C,0.085000*%
%ADD14C,0.080000*%
%ADD15C,0.088000*%
%ADD16C,0.140000*%
%ADD17C,0.082917*%
%ADD18C,0.135984*%
%ADD19C,0.092000*%
%ADD20C,0.061496*%
%ADD21C,0.089370*%
%ADD22C,0.072992*%
%ADD23C,0.109055*%
%ADD24R,0.080000X0.080000*%
%ADD25R,0.085000X0.085000*%
%ADD26R,0.084000X0.084000*%
%ADD24R,0.084000X0.084000*%
%ADD25R,0.080000X0.080000*%
%ADD26R,0.085000X0.085000*%
%ADD27R,0.092000X0.092000*%
%ADD28R,0.089370X0.089370*%
%ADD29R,0.072992X0.072992*%
@ -33,12 +33,23 @@ G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
G90*
G70*
G54D10*
X616Y2853D03*
X616Y2753D03*
X616Y2653D03*
X616Y2553D03*
X616Y2453D03*
X616Y2353D03*
G54D11*
X144Y3058D03*
X144Y2148D03*
G54D12*
X1366Y3678D03*
X3691Y1303D03*
X3816Y1303D03*
G54D11*
G54D13*
X2416Y3628D03*
X2416Y3228D03*
G54D10*
G54D12*
X3491Y2878D03*
X3491Y2703D03*
X3491Y2578D03*
@ -56,7 +67,7 @@ X2866Y1753D03*
X2966Y2353D03*
X3391Y2378D03*
X1502Y628D03*
G54D12*
G54D14*
X3591Y3003D03*
X3591Y2503D03*
X3491Y3003D03*
@ -73,7 +84,7 @@ X2991Y3003D03*
X2991Y2503D03*
X2891Y3003D03*
X2891Y2503D03*
G54D10*
G54D12*
X3866Y2078D03*
X1591Y3603D03*
X3166Y403D03*
@ -82,12 +93,12 @@ X3816Y778D03*
X891Y3278D03*
X1541Y803D03*
X1891Y1228D03*
G54D11*
G54D13*
X3791Y228D03*
X3791Y628D03*
X3141Y228D03*
X3541Y228D03*
G54D13*
G54D15*
X191Y1553D03*
X291Y1553D03*
X391Y1553D03*
@ -158,7 +169,7 @@ X591Y1153D03*
X591Y1253D03*
X591Y1353D03*
X591Y1453D03*
G54D11*
G54D13*
X1891Y728D03*
X1891Y1028D03*
X1991Y728D03*
@ -167,7 +178,7 @@ X2091Y728D03*
X2091Y1028D03*
X2191Y728D03*
X2191Y1028D03*
G54D14*
G54D16*
X1241Y2628D03*
X1241Y2828D03*
X1241Y2428D03*
@ -176,7 +187,7 @@ X1241Y2628D03*
X1241Y2828D03*
X1241Y2428D03*
X1241Y2228D03*
G54D10*
G54D12*
X1316Y1478D03*
X3316Y1603D03*
X2866Y1503D03*
@ -193,7 +204,7 @@ X2766Y1828D03*
X1241Y1628D03*
X1341Y1628D03*
X3516Y1828D03*
G54D11*
G54D13*
X3091Y728D03*
X3091Y1028D03*
X3191Y728D03*
@ -202,7 +213,7 @@ X3291Y728D03*
X3291Y1028D03*
X3391Y728D03*
X3391Y1028D03*
G54D15*
G54D10*
X891Y2278D03*
X891Y2178D03*
X891Y2078D03*
@ -243,7 +254,7 @@ X791Y678D03*
X791Y578D03*
X791Y478D03*
X791Y378D03*
G54D16*
G54D17*
X2991Y1228D03*
X1391Y1228D03*
X3091Y1228D03*
@ -330,11 +341,9 @@ X3791Y1628D03*
X3791Y1528D03*
X3791Y1428D03*
X2891Y1228D03*
G54D17*
G54D18*
X3766Y1228D03*
X3541Y3128D03*
G54D18*
X141Y3053D03*
G54D19*
X1491Y2503D03*
X1491Y2403D03*
@ -348,27 +357,19 @@ X1491Y2728D03*
X2066Y2228D03*
X1966Y2228D03*
X1866Y2228D03*
G54D12*
G54D14*
X1191Y1378D03*
X1391Y1378D03*
G54D11*
G54D13*
X1291Y728D03*
X1291Y1128D03*
G54D19*
X2516Y3328D03*
X2516Y3626D03*
G54D11*
G54D13*
X466Y1903D03*
X66Y1903D03*
G54D18*
X141Y2153D03*
G54D13*
X616Y2853D03*
X616Y2753D03*
X616Y2653D03*
X616Y2553D03*
X616Y2453D03*
X616Y2353D03*
G54D15*
X3566Y528D03*
X3566Y628D03*
X3566Y728D03*
@ -378,17 +379,17 @@ X3566Y878D03*
X2791Y2828D03*
X2791Y2728D03*
X2791Y2628D03*
G54D11*
G54D13*
X2991Y603D03*
X3391Y603D03*
X2991Y503D03*
X3391Y503D03*
G54D13*
G54D15*
X2991Y403D03*
X3091Y403D03*
X3266Y403D03*
X3366Y403D03*
G54D11*
G54D13*
X3591Y1453D03*
X3191Y1453D03*
X2366Y3028D03*
@ -409,7 +410,7 @@ G54D19*
X2666Y3703D03*
X2766Y3703D03*
X2866Y3703D03*
G54D12*
G54D14*
X3041Y3728D03*
X3241Y3728D03*
X2891Y3528D03*
@ -443,7 +444,7 @@ X3066Y2253D03*
X2766Y2253D03*
X3066Y2353D03*
X2766Y2353D03*
G54D11*
G54D13*
X3591Y1553D03*
X3191Y1553D03*
X1866Y3028D03*
@ -460,16 +461,16 @@ X1766Y3028D03*
X1766Y2628D03*
X3566Y2228D03*
X3166Y2228D03*
G54D12*
G54D14*
X3366Y1353D03*
X3166Y1353D03*
G54D11*
G54D13*
X2066Y1378D03*
X2066Y1878D03*
G54D12*
G54D14*
X2666Y2103D03*
X2666Y2303D03*
G54D11*
G54D13*
X2591Y2503D03*
X2591Y3003D03*
X2191Y1878D03*
@ -493,14 +494,14 @@ X2518Y1503D03*
X2616Y1503D03*
X2493Y2103D03*
X2591Y2103D03*
G54D11*
G54D13*
X1741Y1853D03*
X1741Y1453D03*
X2141Y603D03*
X1741Y603D03*
X1641Y628D03*
X1241Y628D03*
G54D12*
G54D14*
X1741Y828D03*
X1741Y1028D03*
X1666Y378D03*
@ -509,7 +510,7 @@ X1391Y778D03*
X1391Y978D03*
X1341Y378D03*
X1141Y378D03*
G54D11*
G54D13*
X1591Y703D03*
X1591Y1103D03*
X1491Y703D03*
@ -517,7 +518,7 @@ X1491Y1103D03*
G54D19*
X1191Y778D03*
X1191Y1076D03*
G54D12*
G54D14*
X2866Y803D03*
X2866Y1003D03*
X291Y1678D03*
@ -532,14 +533,14 @@ X2341Y578D03*
X2541Y578D03*
X2641Y328D03*
X2441Y328D03*
G54D11*
G54D13*
X2766Y678D03*
X2766Y1078D03*
X2316Y678D03*
X2316Y1078D03*
X2916Y1328D03*
X2516Y1328D03*
G54D12*
G54D14*
X1441Y1453D03*
X1441Y1653D03*
X2591Y828D03*
@ -548,7 +549,7 @@ X3791Y1103D03*
X3791Y903D03*
X1541Y1653D03*
X1541Y1453D03*
G54D11*
G54D13*
X1641Y1853D03*
X1641Y1453D03*
X1091Y3253D03*
@ -589,7 +590,7 @@ X142Y3529D03*
X2016Y3528D03*
X2116Y3528D03*
X2216Y3528D03*
G54D11*
G54D13*
X1091Y3353D03*
X691Y3353D03*
X1265Y3352D03*
@ -610,12 +611,14 @@ G54D23*
X3641Y3678D03*
X3641Y3481D03*
G54D24*
X616Y2853D03*
G54D25*
X2891Y2503D03*
X3491Y2503D03*
G54D25*
G54D26*
X1891Y728D03*
X3091Y728D03*
G54D26*
G54D24*
X791Y2278D03*
G54D27*
X1491Y2503D03*

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

@ -7,11 +7,11 @@
queryCommand = "Q"
;signature = 20
signature = "speeduino 201706-dev"
signature = "speeduino 201709-dev"
versionInfo = "S" ; Put this in the title bar.
;[TunerStudio]
; iniSpecVersion = 3.24
[TunerStudio]
iniSpecVersion = 3.46
;-------------------------------------------------------------------------------
@ -98,23 +98,35 @@
endianness = little
nPages = 10
burnCommand = "B"
pageSize = 288, 64, 288, 64, 288, 64, 64, 160, 192, 128
; pageIdentifier = "\$tsCanId\x01", "\$tsCanId\x02", "\$tsCanId\x03", "\$tsCanId\x04", "\$tsCanId\x05", "\$tsCanId\x06", "\$tsCanId\x07", "\$tsCanId\x08", "\$tsCanId\x09", "\$tsCanId\x0A"
pageActivationDelay = 10
pageActivate = "P\001", "P\002", "P\003", "P\004", "P\005", "P\006", "P\007", "P\010", "P\011", "P\012"
pageReadCommand = "V", "V", "V", "V", "V", "V", "V", "V", "V", "V"
pageValueWrite = "W%2o%v", "W%o%v", "W%2o%v", "W%o%v", "W%2o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v"
; pageChunkWrite = "" ; No chunk write for standard MS
;pageSize = 288, 64, 288, 64, 288, 64, 64, 160, 192, 128, 192
pageSize = 288, 128, 288, 128, 288, 128, 160, 192, 128, 192
;burnCommand = "B"
;pageActivate = "P\001", "P\002", "P\003", "P\004", "P\005", "P\006", "P\007", "P\010", "P\011", "P\012", "P\013"
;pageReadCommand = "V", "V", "V", "V", "V", "V", "V", "V", "V", "V", "V"
;pageValueWrite = "W%2o%v", "W%o%v", "W%2o%v", "W%o%v", "W%2o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v", "W%o%v"
;pageChunkWrite = "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v", "w%2o%2c%v"
;pageChunkWrite = "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v", "X%o%c%v"
; New commands
;pageSize = 288, 128, 288, 128, 288, 128, 128, 160, 192, 128, 192
pageIdentifier = "\$tsCanId\x01", "\$tsCanId\x02", "\$tsCanId\x03", "\$tsCanId\x04", "\$tsCanId\x05", "\$tsCanId\x06", "\$tsCanId\x07", "\$tsCanId\x08", "\$tsCanId\x09", "\$tsCanId\x0A"
burnCommand = "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i", "b%2i"
pageReadCommand = "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v", "p%2i%2o%2c%v"
pageValueWrite = "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v"
pageChunkWrite = "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v"
;pageChunkWrite = "w%2i%2o%2c%v", "", "w%2i%2o%2c%v", "", "w%2i%2o%2c%v", "", "", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v", "w%2i%2o%2c%v"
blockingFactor = 2048
tableBlockingFactor = 2048
delayAfterPortOpen=1000
;validateArrayBounds = true
blockReadTimeout = 2000
;tsWriteBlocks = off
;writeBlocks = off
interWriteDelay = 10
;tsWriteBlocks = on
interWriteDelay = 5 ;Ignored when tsWriteBlocks is on
pageActivationDelay = 10
;New for TS 3.0.08ish upwards, define lists of standard I/O options
@ -122,7 +134,7 @@
#define PIN_OUT16inv = "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
#define tsCanId_list = "CAN ID 0", "CAN ID 1", "CAN ID 2", "CAN ID 3", "CAN ID 4", "CAN ID 5", "CAN ID 6", "CAN ID 7", "CAN ID 8", "CAN ID 9", "CAN ID 10","CAN ID 11","CAN ID 12","CAN ID 13","CAN ID 14","INVALID"
#define CAN_ADDRESS_HEX_inv255 = $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT10inv, "INVALID", "INVALID", "INVALID", "INVALID", "blank"
#define CAN_ADDRESS_HEX_inv255 = $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT16inv, $PIN_OUT10inv, "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "blank"
#define CAN_ADDRESS_HEX_00XX = "INVALID", "0x001", "0x002", "0x003", "0x004", "0x005", "0x006", "0x007", "0x008", "0x009", "0x00A", "0x00B", "0x00C", "0x00D", "0x00E", "0x00F", "0x010", "0x011", "0x012", "0x013", "0x014", "0x015", "0x016", "0x017", "0x018", "0x019", "0x01A", "0x01B", "0x01C", "0x01D", "0x01E", "0x01F", "0x020", "0x021", "0x022", "0x023", "0x024", "0x025", "0x026", "0x027", "0x028", "0x029", "0x02A", "0x02B", "0x02C", "0x02D", "0x02E", "0x02F", "0x030", "0x031", "0x032", "0x033", "0x034", "0x035", "0x036", "0x037", "0x038", "0x039", "0x03A", "0x03B", "0x03C", "0x03D", "0x03E", "0x03F", "0x040", "0x041", "0x042", "0x043", "0x044", "0x045", "0x046", "0x047", "0x048", "0x049", "0x04A", "0x04B", "0x04C", "0x04D", "0x04E", "0x04F", "0x050", "0x051", "0x052", "0x053", "0x054", "0x055", "0x056", "0x057", "0x058", "0x059", "0x05A", "0x05B", "0x05C", "0x05D", "0x05E", "0x05F" ,"0x060", "0x061", "0x062", "0x063", "0x064", "0x065", "0x066", "0x067", "0x068", "0x069", "0x06A", "0x06B", "0x06C", "0x06D", "0x06E", "0x06F", "0x070", "0x071", "0x072", "0x073", "0x074", "0x075", "0x076", "0x077", "0x078", "0x079", "0x07A", "0x07B", "0x07C", "0x07D", "0x07E", "0x07F", "0x080", "0x081", "0x082", "0x083", "0x084", "0x085", "0x086", "0x087", "0x088", "0x089", "0x08A", "0x08B", "0x08C", "0x08D", "0x08E", "0x08F" ,"0x090", "0x091", "0x092", "0x093", "0x094", "0x095", "0x096", "0x097", "0x098", "0x099", "0x09A", "0x09B", "0x09C", "0x09D", "0x09E", "0x09F", "0x0A0", "0x0A1", "0x0A2", "0x0A3", "0x0A4", "0x0A5", "0x0A6", "0x0A7", "0x0A8", "0x0A9", "0x0AA", "0x0AB", "0x0AC", "0x0AD", "0x0AE", "0x0AF", "0x0B0", "0x0B1", "0x0B2", "0x0B3", "0x0B4", "0x0B5", "0x0B6", "0x0B7", "0x0B8", "0x0B9", "0x0BA", "0x0BB", "0x0BC", "0x0BD", "0x0BE", "0x0BF" ,"0x0C0", "0x0C1", "0x0C2", "0x0C3", "0x0C4", "0x0C5", "0x0C6", "0x0C7", "0x0C8", "0x0C9", "0x0CA", "0x0CB", "0x0CC", "0x0CD", "0x0CE", "0x0CF", "0x0D0", "0x0D1", "0x0D2", "0x0D3", "0x0D4", "0x0D5", "0x0D6", "0x0D7", "0x0D8", "0x0D9", "0x0DA", "0x0DB", "0x0DC", "0x0DD", "0x0DE", "0x0DF", "0x0E0", "0x0E1", "0x0E2", "0x0E3", "0x0E4", "0x0E5", "0x0E6", "0x0E7", "0x0E8", "0x0E9", "0x0EA", "0x0EB", "0x0EC", "0x0ED", "0x0EE", "0x0EF" ,"0x0F0", "0x0F1", "0x0F2", "0x0F3", "0x0F4", "0x0F5", "0x0F6", "0x0F7", "0x0F8", "0x0F9", "0x0FA", "0x0FB", "0x0FC", "0x0FD", "0x0FE", "0x0FF"
#define CAN_ADDRESS_HEX_01XX = "0x100", "0x101", "0x102", "0x103", "0x104", "0x105", "0x106", "0x107", "0x108", "0x109", "0x10A", "0x10B", "0x10C", "0x10D", "0x10E", "0x10F", "0x110", "0x111", "0x112", "0x113", "0x114", "0x115", "0x116", "0x117", "0x118", "0x119", "0x11A", "0x11B", "0x11C", "0x11D", "0x11E", "0x11F", "0x120", "0x121", "0x122", "0x123", "0x124", "0x125", "0x126", "0x127", "0x128", "0x129", "0x12A", "0x12B", "0x12C", "0x12D", "0x12E", "0x12F", "0x130", "0x131", "0x132", "0x133", "0x134", "0x135", "0x136", "0x137", "0x138", "0x139", "0x13A", "0x13B", "0x13C", "0x13D", "0x13E", "0x13F", "0x140", "0x141", "0x142", "0x143", "0x144", "0x145", "0x146", "0x147", "0x148", "0x149", "0x14A", "0x14B", "0x14C", "0x14D", "0x14E", "0x14F", "0x150", "0x151", "0x152", "0x153", "0x154", "0x155", "0x156", "0x157", "0x158", "0x159", "0x15A", "0x15B", "0x15C", "0x15D", "0x15E", "0x15F" ,"0x160", "0x161", "0x162", "0x163", "0x164", "0x165", "0x166", "0x167", "0x168", "0x169", "0x16A", "0x16B", "0x16C", "0x16D", "0x16E", "0x16F", "0x170", "0x171", "0x172", "0x173", "0x174", "0x175", "0x176", "0x177", "0x178", "0x179", "0x17A", "0x17B", "0x17C", "0x17D", "0x17E", "0x17F", "0x180", "0x181", "0x182", "0x183", "0x184", "0x185", "0x186", "0x187", "0x188", "0x189", "0x18A", "0x18B", "0x18C", "0x18D", "0x18E", "0x18F" ,"0x190", "0x191", "0x192", "0x193", "0x194", "0x195", "0x196", "0x197", "0x198", "0x199", "0x19A", "0x19B", "0x19C", "0x19D", "0x19E", "0x19F", "0x1A0", "0x1A1", "0x1A2", "0x1A3", "0x1A4", "0x1A5", "0x1A6", "0x1A7", "0x1A8", "0x1A9", "0x1AA", "0x1AB", "0x1AC", "0x1AD", "0x1AE", "0x1AF", "0x1B0", "0x1B1", "0x1B2", "0x1B3", "0x1B4", "0x1B5", "0x1B6", "0x1B7", "0x1B8", "0x1B9", "0x1BA", "0x1BB", "0x1BC", "0x1BD", "0x1BE", "0x1BF" ,"0x1C0", "0x1C1", "0x1C2", "0x1C3", "0x1C4", "0x1C5", "0x1C6", "0x1C7", "0x1C8", "0x1C9", "0x1CA", "0x1CB", "0x1CC", "0x1CD", "0x1CE", "0x1CF", "0x1D0", "0x1D1", "0x1D2", "0x1D3", "0x1D4", "0x1D5", "0x1D6", "0x1D7", "0x1D8", "0x1D9", "0x1DA", "0x1DB", "0x1DC", "0x1DD", "0x1DE", "0x1DF", "0x1E0", "0x1E1", "0x1E2", "0x1E3", "0x1E4", "0x1E5", "0x1E6", "0x1E7", "0x1E8", "0x1E9", "0x1EA", "0x1EB", "0x1EC", "0x1ED", "0x1EE", "0x1EF" ,"0x1F0", "0x1F1", "0x1F2", "0x1F3", "0x1F4", "0x1F5", "0x1F6", "0x1F7", "0x1F8", "0x1F9", "0x1FA", "0x1FB", "0x1FC", "0x1FD", "0x1FE", "0x1FF"
#define CAN_ADDRESS_HEX_02XX = "0x200", "0x201", "0x202", "0x203", "0x204", "0x205", "0x206", "0x207", "0x208", "0x209", "0x20A", "0x20B", "0x20C", "0x20D", "0x20E", "0x20F", "0x210", "0x211", "0x212", "0x213", "0x214", "0x215", "0x216", "0x217", "0x218", "0x219", "0x21A", "0x21B", "0x21C", "0x21D", "0x21E", "0x21F", "0x220", "0x221", "0x222", "0x223", "0x224", "0x225", "0x226", "0x227", "0x228", "0x229", "0x22A", "0x22B", "0x22C", "0x22D", "0x22E", "0x22F", "0x230", "0x231", "0x232", "0x233", "0x234", "0x235", "0x236", "0x237", "0x238", "0x239", "0x23A", "0x23B", "0x23C", "0x23D", "0x23E", "0x23F", "0x240", "0x241", "0x242", "0x243", "0x244", "0x245", "0x246", "0x247", "0x248", "0x249", "0x24A", "0x24B", "0x24C", "0x24D", "0x24E", "0x24F", "0x250", "0x251", "0x252", "0x253", "0x254", "0x255", "0x256", "0x257", "0x258", "0x259", "0x25A", "0x25B", "0x25C", "0x25D", "0x25E", "0x25F" ,"0x260", "0x261", "0x262", "0x263", "0x264", "0x265", "0x266", "0x267", "0x268", "0x269", "0x26A", "0x26B", "0x26C", "0x26D", "0x26E", "0x26F", "0x270", "0x271", "0x272", "0x273", "0x274", "0x275", "0x276", "0x277", "0x278", "0x279", "0x27A", "0x27B", "0x27C", "0x27D", "0x27E", "0x27F", "0x280", "0x281", "0x282", "0x283", "0x284", "0x285", "0x286", "0x287", "0x288", "0x289", "0x28A", "0x28B", "0x28C", "0x28D", "0x28E", "0x28F" ,"0x290", "0x291", "0x292", "0x293", "0x294", "0x295", "0x296", "0x297", "0x298", "0x299", "0x29A", "0x29B", "0x29C", "0x29D", "0x29E", "0x29F", "0x2A0", "0x2A1", "0x2A2", "0x2A3", "0x2A4", "0x2A5", "0x2A6", "0x2A7", "0x2A8", "0x2A9", "0x2AA", "0x2AB", "0x2AC", "0x2AD", "0x2AE", "0x2AF", "0x2B0", "0x2B1", "0x2B2", "0x2B3", "0x2B4", "0x2B5", "0x2B6", "0x2B7", "0x2B8", "0x2B9", "0x2BA", "0x2BB", "0x2BC", "0x2BD", "0x2BE", "0x2BF" ,"0x2C0", "0x2C1", "0x2C2", "0x2C3", "0x2C4", "0x2C5", "0x2C6", "0x2C7", "0x2C8", "0x2C9", "0x2CA", "0x2CB", "0x2CC", "0x2CD", "0x2CE", "0x2CF", "0x2D0", "0x2D1", "0x2D2", "0x2D3", "0x2D4", "0x2D5", "0x2D6", "0x2D7", "0x2D8", "0x2D9", "0x2DA", "0x2DB", "0x2DC", "0x2DD", "0x2DE", "0x2DF", "0x2E0", "0x2E1", "0x2E2", "0x2E3", "0x2E4", "0x2E5", "0x2E6", "0x2E7", "0x2E8", "0x2E9", "0x2EA", "0x2EB", "0x2EC", "0x2ED", "0x2EE", "0x2EF" ,"0x2F0", "0x2F1", "0x2F2", "0x2F3", "0x2F4", "0x2F5", "0x2F6", "0x2F7", "0x2F8", "0x2F9", "0x2FA", "0x2FB", "0x2FC", "0x2FD", "0x2FE", "0x2FF"
@ -216,7 +228,7 @@ page = 2
baroCorr = bits, U08, 38, [3:3], "Off", "On"
injLayout = bits, U08, 38, [4:5], "Paired", "Semi-Sequential", "INVALID", "Sequential"
perToothIgn= bits, U08, 38, [6:6], "No", "Yes"
unused2-38h= bits, U08, 38, [7:7], "No", "Yes"
dfcoEnabled= bits, U08, 38, [7:7], "Off", "On"
primePulse = scalar, U08, 39, "ms", 0.1, 0.0, 0.0, 25.5, 1
dutyLim = scalar, U08, 40, "%", 1.0, 0.0, 0.0, 100.0, 0
@ -226,7 +238,7 @@ page = 2
boostMaxDuty = scalar, U08, 43, "%", 1.0, 0.0, 0.0, 100.0, 0
tpsMin = scalar, U08, 44, "ADC", 1.0, 0.0, 0.0, 255.0, 0
tpsMax = scalar, U08, 45, "ADC", 1.0, 0.0, 0.0, 255.0, 0
mapMin = scalar, U08, 46, "kpa", 1.0, 0.0, 0.0, 255.0, 0
mapMin = scalar, S08, 46, "kpa", 1.0, 0.0, -100, 127.0, 0
mapMax = scalar, U16, 47, "kpa", 1.0, 0.0, 0.0, 25500, 0
fpPrime = scalar, U08, 49, "s", 1.0, 0.0, 0.0, 255.0, 0
stoich = scalar, U08, 50, ":1", 0.1, 0.0, 0.0, 25.5, 1
@ -243,6 +255,7 @@ page = 2
iacCLmaxDuty = scalar, U08, 62, "%", 1.0, 0.0, 0.0, 100.0, 0
boostMinDuty = scalar, U08, 63, "%", 1.0, 0.0, 0.0, 100.0, 0 ; Minimum and maximum duty cycles for boost control
unused2-64 = array, U08, 64, [63], "%", 1.0, 0.0, 0.0, 255, 0
;--------------------------------------------------
@ -273,8 +286,8 @@ page = 4
TrigEdge = bits, U08, 5,[0:0], "Leading", "Trailing"
TrigSpeed = bits, U08, 5,[1:1], "Crank Speed", "Cam Speed"
IgInv = bits, U08, 5,[2:2], "Going Low", "Going High"
oddfire = bits, U08, 5,[3:3], "No", "Yes"
TrigPattern= bits, U08, 5,[4:7], "Missing Tooth", "Basic Distributor", "Dual Wheel", "GM 7X", "4G63 / Miata / 3000GT", "GM 24X", "Jeep 2000", "Audi 135", "Honda D17", "Miata 99-05", "Mazda AU", "Non-360 Dual", "Nissan 360", "Subaru 6/7", "Daihatsu +1", "INVALID"
unused4-5d = bits, U08, 5,[3:3], "No", "Yes"
TrigPattern= bits, U08, 5,[4:7], "Missing Tooth", "Basic Distributor", "Dual Wheel", "GM 7X", "4G63 / Miata / 3000GT", "GM 24X", "Jeep 2000", "Audi 135", "Honda D17", "Miata 99-05", "Mazda AU", "Non-360 Dual", "Nissan 360", "Subaru 6/7", "Daihatsu +1", "Harley EVO"
TrigEdgeSec= bits, U08, 6,[0:0], "Leading", "Trailing"
fuelPumpPin= bits , U08, 6,[1:6], "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", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
useResync = bits, U08, 6,[7:7], "No", "Yes"
@ -293,8 +306,7 @@ page = 4
;Dwell control
dwellcont = bits, U08, 12, [0:0], "INVALID", "Dwell control"
useDwellLim= bits, U08, 12, [1:1], "Off", "On"
sparkMode = bits, U08, 12, [2:3], "Wasted Spark", "Single Channel", "Wasted COP", "Sequential"
dfcoEnabled= bits, U08, 12, [4:4], "Off", "On"
sparkMode = bits, U08, 12, [2:4], "Wasted Spark", "Single Channel", "Wasted COP", "Sequential", "Rotary", "INVALID", "INVALID", "INVALID"
TrigFilter = bits, U08, 12, [5:6], "Off", "Weak", "Medium", "Aggressive"
ignCranklock=bits, U08, 12, [7:7], "Off", "On"
dwellcrank = scalar, U08, 13, "ms", 0.1, 0, 0, 25, 1
@ -340,7 +352,7 @@ page = 4
ignBypassPin = bits , U08, 63, [1:6], "INVALID", "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", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
ignBypassHiLo = bits, U08, 63, [7:7], "LOW", "HIGH"
unused4-64 = array, U08, 64, [63], "%", 1.0, 0.0, 0.0, 255, 0
;--------------------------------------------------
;Start AFR page
;--------------------------------------------------
@ -370,7 +382,7 @@ page = 6
egoType = bits , U08, 0, [2:3], "Disabled", "Narrow Band", "Wide Band", "INVALID" ; egoOption
boostEnabled= bits, U08, 0, [4:4], "Off", "On"
vvtEnabled = bits, U08, 0, [5:5], "Off", "On"
boostCutType= bits, U08, 0, [6:7], "Off", "Spark Only", "Fuel Only","Both"
boostCutType= bits, U08, 0, [6:7], "Off", "Spark Only", "Fuel Only","Both"
egoKP = scalar, U08, 1, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte)
egoKI = scalar, U08, 2, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte)
@ -389,8 +401,8 @@ page = 6
egoRPM = scalar, U08, 11, "rpm", 100, 0.0, 100, 25500, 0
egoTPSMax = scalar, U08, 12, "%", 1, 0, 0, 120, 0
vvtPin = bits , U08, 13, [0:5], "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", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
unused6-13e = bits, U08, 13, [6:6], "ONE", "INVALID"
unused6-13f = bits, U08, 13, [7:7], "ONE", "INVALID"
useExtBaro = bits, U08, 13, [6:6], "No", "Yes"
boostMode = bits, U08, 13, [7:7], "Simple", "Full"
boostPin = bits, U08, 14, [0:5], "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", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
unused6-14e = bits, U08, 14, [6:6], "ONE", "INVALID"
unused6-14f = bits, U08, 14, [7:7], "ONE", "INVALID"
@ -429,72 +441,66 @@ page = 6
lnchPullRes = bits, U08, 60, [0:1], "Float" , "Pullup", "INVALID", "INVALID"
fuelTrimEnabled= bits, U08, 60, [2:2], "No", "Yes"
flatSEnable = bits, U08, 60, [3:3], "No", "Yes"
unused6-60e = bits, U08, 60, [4:4], "ONE", "INVALID"
unused6-60f = bits, U08, 60, [5:5], "ONE", "INVALID"
unused6-60g = bits, U08, 60, [6:6], "ONE", "INVALID"
unused6-60h = bits, U08, 60, [7:7], "ONE", "INVALID"
; Baro Sensor pin
baroPin = bits, U08, 60, [4:7], "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A8", "A10", "A11", "A12", "A13", "A14", "A15"
; Flat shift
flatSSoftWin = scalar, U08, 61, "rpm", 100, 0.0, 100, 25500, 0
flatSRetard = scalar, U08, 62, "deg", 1.0, 0.0, 0.0, 80, 0
flatSArm = scalar, U08, 63, "rpm", 100, 0.0, 100, 25500, 0
;--------------------------------------------------
;Start idle and fan controls (Page 7)
;--------------------------------------------------
page = 7
iacCLValues = array, U08, 0, [10], "RPM", 10.0, 0.0, 0, 2550, 0
iacOLStepVal = array, U08, 10, [10], "Steps", 3, 0, 0, 765, 0
iacOLPWMVal = array, U08, 20, [10], "Duty %", 1.0, 0, 0, 100, 0
iacCLValues = array, U08, 64, [10], "RPM", 10.0, 0.0, 0, 2550, 0
iacOLStepVal = array, U08, 74, [10], "Steps", 3, 0, 0, 765, 0
iacOLPWMVal = array, U08, 84, [10], "Duty %", 1.0, 0, 0, 100, 0
#if CELSIUS
iacBins = array, U08, 30, [10], "C", 1.0, -40, -40, 215, 0
iacBins = array, U08, 94, [10], "C", 1.0, -40, -40, 215, 0
#else
iacBins = array, U08, 30, [10], "F", 1.8, -22.23, -40, 215, 0
iacBins = array, U08, 94, [10], "F", 1.8, -22.23, -40, 215, 0
#endif
iacCrankSteps= array, U08, 40, [4], "Steps", 3, 0, 0, 765, 0
iacCrankDuty = array, U08, 44, [4], "Duty %", 1.0, 0, 0, 100, 0
iacCrankSteps= array, U08, 104, [4], "Steps", 3, 0, 0, 765, 0
iacCrankDuty = array, U08, 108, [4], "Duty %", 1.0, 0, 0, 100, 0
#if CELSIUS
iacCrankBins = array, U08, 48, [4], "C", 1.0, -40, -40, 215, 0
iacCrankBins = array, U08, 112, [4], "C", 1.0, -40, -40, 215, 0
#else
iacCrankBins = array, U08, 48, [4], "F", 1.8, -22.23, -40, 215, 0
iacCrankBins = array, U08, 112, [4], "F", 1.8, -22.23, -40, 215, 0
#endif
iacAlgorithm = bits , U08, 52, [0:2], "None", "On/Off", "PWM Open loop", "PWM Closed loop", "Stepper Open Loop", "Stepper Closed Loop", "INVALID", "INVALID"
iacStepTime = bits , U08, 52, [3:5], "INVALID","1", "2", "3", "4", "5", "6","INVALID"
iacChannels = bits, U08, 52, [6:6], "1", "2"
iacPWMdir = bits , U08, 52, [7:7], "Normal", "Reverse"
iacAlgorithm = bits , U08, 116, [0:2], "None", "On/Off", "PWM Open loop", "PWM Closed loop", "Stepper Open Loop", "Stepper Closed Loop", "INVALID", "INVALID"
iacStepTime = bits , U08, 116, [3:5], "INVALID","1", "2", "3", "4", "5", "6","INVALID"
iacChannels = bits, U08, 116, [6:6], "1", "2"
iacPWMdir = bits , U08, 116, [7:7], "Normal", "Reverse"
#if CELSIUS
iacFastTemp = scalar, U08, 53, "C", 1.0, -40, -40, 215, 0
iacFastTemp = scalar, U08, 117, "C", 1.0, -40, -40, 215, 0
#else
iacFastTemp = scalar, U08, 53, "F", 1.8, -22.23, -40, 215, 0
iacFastTemp = scalar, U08, 117, "F", 1.8, -22.23, -40, 215, 0
#endif
iacStepHome = scalar, U08, 54, "Steps", 3, 0, 0, 765, 0
iacStepHyster= scalar, U08, 55, "Steps", 1, 0.0, 0.0, 10, 0
iacStepHome = scalar, U08, 118, "Steps", 3, 0, 0, 765, 0
iacStepHyster= scalar, U08, 119, "Steps", 1, 0.0, 0.0, 10, 0
; Begin fan control vairables
fanInv = bits, U08, 56, [0:0], "No", "Yes"
fanEnable = bits, U08, 56, [1:1], "Off", "On/Off"
fanPin = bits , U08, 56, [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", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
fanInv = bits, U08, 120, [0:0], "No", "Yes"
fanEnable = bits, U08, 120, [1:1], "Off", "On/Off"
fanPin = bits , U08, 120, [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", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
#if CELSIUS
fanSP = scalar, U08, 57, "C", 1.0, -40, -40, 215.0, 0
fanHyster = scalar, U08, 58, "C", 1.0, 0.0, 0.0, 40, 0
fanSP = scalar, U08, 121, "C", 1.0, -40, -40, 215.0, 0
fanHyster = scalar, U08, 122, "C", 1.0, 0.0, 0.0, 40, 0
#else
fanSP = scalar, U08, 57, "F", 1.8, -22.23, -40, 215.0, 0
fanHyster = scalar, U08, 58, "F", 1.0, 0.0, 0.0, 40, 0
fanSP = scalar, U08, 121, "F", 1.8, -22.23, -40, 215.0, 0
fanHyster = scalar, U08, 122, "F", 1.0, 0.0, 0.0, 40, 0
#endif
fanFreq = scalar, U08 , 59, "Hz", 2.0, 0.0, 10, 511, 0
fanFreq = scalar, U08 , 123, "Hz", 2.0, 0.0, 10, 511, 0
#if CELSIUS
fanPWMBins = array, U08, 60, [4], "C", 1.0, -40, -40, 215, 0
fanPWMBins = array, U08, 124, [4], "C", 1.0, -40, -40, 215, 0
#else
fanPWMBins = array, U08, 60, [4], "F", 1.8, -22.23, -40, 215, 0
fanPWMBins = array, U08, 124, [4], "F", 1.8, -22.23, -40, 215, 0
#endif
;--------------------------------------------------
;Boost and vvt maps (Page 8)
;Boost and vvt maps (Page 7)
;--------------------------------------------------
page = 8
page = 7
;notes for boostTable in PSI~~~There are 6.895 psis to a kPa then x 2 like the kPa ver~~~div atmos. pressure in kPa by 2 and make neg so to subtract instead of add
; #if BOOSTPSI
; boostTable = array, U08, 0,[8x8], "PSI", 0.29007547546041846, -50.6625, 0, 74, 0
@ -508,11 +514,11 @@ page = 8
tpsBinsVVT = array, U08, 152,[ 8], "TPS", 1.0, 0.0, 0.0, 255.0, 0
;--------------------------------------------------
;Sequential fuel trim tables (Page 9)
;Sequential fuel trim tables (Page 8)
;--------------------------------------------------
page = 9
page = 8
fuelTrim1Table = array, U08, 0,[6x6], "%", 1.0, -128, -50, 50, 0
fuelTrim1rpmBins = array, U08, 36,[ 6], "RPM", 100.0, 0.0, 100, 25500, 0
fuelTrim1rpmBins = array, U08, 36,[ 6], "RPM", 100.0, 0.0, 0, 25500, 0
#if SPEED_DENSITY
fuelTrim1loadBins = array, U08, 42,[ 6], "kPa", 2.0, 0.0, 0.0, 511.0, 0
#elif ALPHA_N
@ -520,7 +526,7 @@ page = 9
#endif
fuelTrim2Table = array, U08, 48,[6x6], "%", 1.0, -128, -50, 50, 0
fuelTrim2rpmBins = array, U08, 84,[ 6], "RPM", 100.0, 0.0, 100, 25500, 0
fuelTrim2rpmBins = array, U08, 84,[ 6], "RPM", 100.0, 0.0, 0, 25500, 0
#if SPEED_DENSITY
fuelTrim2loadBins = array, U08, 90,[ 6], "kPa", 2.0, 0.0, 0.0, 511.0, 0
#elif ALPHA_N
@ -528,7 +534,7 @@ page = 9
#endif
fuelTrim3Table = array, U08, 96,[6x6], "%", 1.0, -128, -50, 50, 0
fuelTrim3rpmBins = array, U08, 132,[ 6], "RPM", 100.0, 0.0, 100, 25500, 0
fuelTrim3rpmBins = array, U08, 132,[ 6], "RPM", 100.0, 0.0, 0, 25500, 0
#if SPEED_DENSITY
fuelTrim3loadBins = array, U08, 138,[ 6], "kPa", 2.0, 0.0, 0.0, 511.0, 0
#elif ALPHA_N
@ -536,7 +542,7 @@ page = 9
#endif
fuelTrim4Table = array, U08, 144,[6x6], "%", 1.0, -128, -50, 50, 0
fuelTrim4rpmBins = array, U08, 180,[ 6], "RPM", 100.0, 0.0, 100, 25500, 0
fuelTrim4rpmBins = array, U08, 180,[ 6], "RPM", 100.0, 0.0, 0, 25500, 0
#if SPEED_DENSITY
fuelTrim4loadBins = array, U08, 186,[ 6], "kPa", 2.0, 0.0, 0.0, 511.0, 0
#elif ALPHA_N
@ -544,9 +550,9 @@ page = 9
#endif
;--------------------------------------------------
;CANBUS control (Page 10)
;CANBUS control (Page 9)
;--------------------------------------------------
page = 10
page = 9
#if CAN_COMMANDS
enable_canbus = bits, U08, 0, [0:1], "Disable", "On Via Secondary Serial", "ON via Internal CAN ", "INVALID"
#else
@ -694,6 +700,32 @@ page = 10
unused10_126 = scalar, U08, 126, "", 1, 0, 0, 255, 0
unused10_127 = scalar, U08, 127, "", 1, 0, 0, 255, 0
page = 10
#if CELSIUS
crankingEnrichBins = array, U08, 0, [4], "C", 1.0, -40, -40, 215, 0
#else
crankingEnrichBins = array, U08, 0, [4], "F", 1.8, -22.23, -40, 215, 0
#endif
crankingEnrichValues= array, U08, 4, [4], "%", 1.0, 0.0, 0, 255, 0 ; Values for the cranking enrichment curve
rotaryType = bits , U08, 8, [0:1], "FC", "FD", "RX8", "INVALID"
unused11-8c = bits , U08, 8, [2:2], "Off","On"
unused11-8d = bits , U08, 8, [3:3], "Off","On"
unused11-8e = bits , U08, 8, [4:4], "Off","On"
unused11-8f = bits , U08, 8, [5:5], "Off","On"
unused11-8g = bits , U08, 8, [6:6], "Off","On"
unused11-8h = bits , U08, 8, [7:7], "Off","On"
rotarySplitValues = array, U08, 9, [8], "degrees", 1.0, 0.0, 0.0, 40, 0
#if SPEED_DENSITY
rotarySplitBins = array, U08, 17, [8], "kPa", 2.0, 0.0, 0.0, 511.0, 0
#elif ALPHA_N
rotarySplitBins = array, U08, 17, [8], "TPS", 2.0, 0.0, 0.0, 100.0, 0
#endif
boostSens = scalar, U16, 25, "", 1, 0, 0, 5000, 0
boostIntv = scalar, U08, 27, "ms", 1, 0, 0, 250, 0
unused11_28_192 = array, U08, 28,[164], "RPM", 100.0, 0.0, 100, 25500, 0
;-------------------------------------------------------------------------------
[ConstantsExtensions]
@ -722,8 +754,9 @@ page = 10
requiresPowerCycle = oddfire4
requiresPowerCycle = iacCLminDuty
requiresPowerCycle = iacCLmaxDuty
requiresPowerCycle = boostMinDuty
requiresPowerCycle = boostMaxDuty
requiresPowerCycle = useExtBaro
requiresPowerCycle = baroPin
requiresPowerCycle = rotaryType
defaultValue = pinLayout, 1
defaultValue = TrigPattern, 0
@ -762,6 +795,8 @@ page = 10
defaultValue = iacCLmaxDuty,100
defaultValue = boostMinDuty,0
defaultValue = boostMaxDuty,100
defaultValue = boostSens, 2000
defaultValue = boostIntv, 30
defaultValue = sparkDur, 1.0
defaultValue = speeduino_tsCanId, 0
defaultValue = true_address, 256
@ -833,6 +868,7 @@ menuDialog = main
subMenu = dwellSettings, "Dwell settings"
subMenu = dwell_correction_curve, "Dwell Compensation"
subMenu = iat_retard_curve, "&IAT Retard"
subMenu = rotary_ignition, "Rotary Ignition", { sparkMode == 4 }
;subMenu = wheelsim, "Stim for wheel"
;subMenu = oddwheel, "Oddfire Wheel settings", 7, { wheelon && oddfire }
@ -923,7 +959,7 @@ menuDialog = main
TrigFilter = "Tuning of the trigger filter algorithm. The more aggressive the setting, the more noise will be removed, however this increases the chance of some true readings being filtered out (False positive). Medium is safe for most setups. Only select 'Aggressive' if no other options are working"
sparkMode = "Wasted Spark: Ignition outputs are on the channels <= half the number of cylinders. Eg 4 cylinder outputs on IGN1 and IGN2.\nSingle Channel: All ignition pulses are output on IGN1.\nWasted COP: Ignition pulses are output on all ignition channels up to the number of cylinders. Eg 4 cylinder outputs on all ignition channels. No valid for >4 cylinders"
IgInv = "Whether the spark fires when the ignition sign goes high or goes low. Most ignition systems 'Going Low' but please verify this as damage to coils can result from the incorrect selection"
IgInv = "Whether the spark fires when the ignition signal goes high or goes low. Nearly all ignition systems use 'Going Low' but please verify this as damage to coils can result from the incorrect selection. (NOTE: THIS IS NOT MEGASQUIRT. THIS SETTING IS USUALLY THE OPPOSITE OF WHAT THEY USE!)"
sparkDur = "The duration of the spark at full dwell. Typically around 1ms"
fanInv = ""
@ -956,6 +992,7 @@ menuDialog = main
multiplyMAP = "If enabled, the MAP reading is included directly into the pulsewidth calculation. This results in a flatter VE table that can be easier to tune in some instances. VE table must be retuned when this value is changed."
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)"
@ -1056,6 +1093,8 @@ menuDialog = main
cmdtestspk350dc = "this will cycle the output at 50% Duty cycle"
cmdtestspk450dc = "this will cycle the output at 50% Duty cycle"
boostIntv = "The closed loop control interval will run every this many ms. Generally values between 50% and 100% of the valve frequency work best"
[UserDefined]
; Enhanced TunerStudio dialogs can be defined here
@ -1077,6 +1116,9 @@ menuDialog = main
; dialog which will be added.
; dialogs can be nested and can be mixed with fields
dialog = wc_note
field = "Final enrichment value must be 100%. Typical maximum is 255% (cold)."
dialog = engine_constants_southwest, "Speeduino Board"
field = "Stoichiometric ratio", stoich
field = "Injector Layout", injLayout, { nCylinders <= 4 }
@ -1265,20 +1307,33 @@ menuDialog = main
dialog = fuelpump, "Fuel pump"
field = "Fuel pump pin", fuelPumpPin
field = "Fuel pump prime duration", fpPrime
dialog = crankPW, "Cranking Pulsewidths (ms)"
topicHelp = "http://speeduino.com/wiki/index.php/Cranking"
dialog = crankingEnrichDialog, "Cranking Enrichment", yAxis
panel = cranking_enrich_curve
dialog = crankingIgnOptions, "Cranking Timing", yAxis
field = "Cranking advance Angle", CrankAng
field = "Cranking bypass", ignBypassEnable
field = "Bypass output pin", ignBypassPin { ignBypassEnable }
field = "Fix cranking timing with trigger", ignCranklock, { TrigPattern == 1 || TrigPattern == 4 || TrigPattern == 10 || TrigPattern == 9 }
dialog = crankingOptions, "", yAxis
field = "Cranking RPM (Max)", crankRPM
field = "Flood Clear level", tpsflood
field = ""
field = "Fuel pump prime duration", fpPrime
field = "Priming Pulsewidth", primePulse
field = ""
field = "Cranking Enrichment %", crankingPct
field = ""
field = "Cranking bypass", ignBypassEnable
field = "Bypass output pin", ignBypassPin { ignBypassEnable }
field = "Fix cranking timing with trigger", ignCranklock, { TrigPattern == 1 || TrigPattern == 4 || TrigPattern == 10}
dialog = crankPW, "Cranking Settings", yAxis
topicHelp = "http://speeduino.com/wiki/index.php/Cranking"
panel = crankingOptions, North
;field = ""
;field = "Cranking Enrichment %", crankingPct
panel = crankingEnrichDialog, Center
;field = ""
panel = crankingIgnOptions, South
dialog = aseSettings, "Afterstart Enrichment"
field = "Enrichment %", asePct
@ -1301,12 +1356,12 @@ menuDialog = main
field = "Note: This is the number of revolutions that will be skipped during"
field = "cranking before the injectors and coils are fired"
field = "Trigger edge", TrigEdge
field = "Secondary trigger edge", TrigEdgeSec, { TrigPattern == 0 || TrigPattern == 2 } ;Missing tooth and dual wheel
field = "Secondary trigger edge", TrigEdgeSec, { TrigPattern == 0 || TrigPattern == 2 || TrigPattern == 9 || TrigPattern == 12 } ;Missing tooth, dual wheel and Miata 9905
field = "Trigger Filter", TrigFilter
field = "Re-sync every cycle", useResync, { TrigPattern == 2 || TrigPattern == 4 || TrigPattern == 7 } ;Dual wheel, 4G63 and Audi 135
field = "Re-sync every cycle", useResync, { TrigPattern == 2 || TrigPattern == 4 || TrigPattern == 7 || TrigPattern == 12 } ;Dual wheel, 4G63, Audi 135, Nissan 360
field = ""
field = "#The below option is EXPERIMENTAL! If unsure what this is, please set to No"
field = "User per tooth ignition calculation", perToothIgn, {TrigPattern == 0} ;Only works for missing tooth
field = "User per tooth ignition calculation", perToothIgn, {TrigPattern == 0 || TrigPattern == 1 || TrigPattern == 2 || TrigPattern == 4 || TrigPattern == 12 } ;Only works for missing tooth, distributor, dual wheel, nissan 360
dialog = sparkSettings,"Spark Settings",4
field = "Spark output mode", sparkMode
@ -1336,6 +1391,10 @@ menuDialog = main
field = "Note: Set the maximum dwell time at least 3ms above"
field = "your desired dwell time (Including cranking)"
dialog = rotary_ignition, "Rotary Ignition", 4
field = "Ignition Configuration", rotaryType
panel = rotaryTrailing_curve
dialog = RevLimiterS, "Rev Limiter", 4
topicHelp = "http://speeduino.com/wiki/index.php/Rev_Limits"
field = "Rev Limiter"
@ -1381,7 +1440,7 @@ menuDialog = main
dialog = mapCal, "Calibrate MAP"
field = "#MAP Sensor"
settingSelector = "Common MAP Sensors"
settingSelector = "Common Pressure Sensors"
settingOption = "MPX4115", mapMin=10, mapMax=122
settingOption = "MPX4250", mapMin=10, mapMax=260
settingOption = "GM 1-BAR", mapMin=10, mapMax=105
@ -1396,28 +1455,37 @@ menuDialog = main
field = "Value At 0.0 Volts", mapMin
field = "Value At 5.0 Volts", mapMax
field = "#Baro Sensor"
field = "Use external Baro sensor", useExtBaro
field = "Analog pin to use for ext. Baro sensor", baroPin, { useExtBaro }
dialog = boostCut, "Boost Cut"
field = "Boost Cut", boostCutType, { boostEnabled }
field = "Boost Limit", boostLimit, { boostEnabled && boostCutType }
dialog = boostSettings, "Boost Control"
topicHelp = "http://speeduino.com/wiki/index.php/Boost_Control"
field = "Boost Control Enabled", boostEnabled
field = "Boost output pin", boostPin, { boostEnabled }
field = "Boost solenoid freq.", boostFreq, { boostEnabled }
field = "Boost Cut", boostCutType, { boostEnabled }
field = "Boost Limit", boostLimit, { boostEnabled && boostCutType }
field = "Closed Loop settings"
field = "P", boostKP, { boostEnabled }
field = "I", boostKI, { boostEnabled }
field = "D", boostKD, { boostEnabled }
field = "Valve minimum duty cycle", boostMinDuty, { boostEnabled }
field = "Valve maximum duty cycle", boostMaxDuty, { boostEnabled }
panel = boostCut
field = "Closed Loop settings"
field = "Control mode", boostMode, { boostEnabled }
slider = "Sensitivity", boostSens, horizontal, { boostEnabled }
field = "Control interval", boostIntv, { boostEnabled }
field = "P", boostKP, { boostEnabled && boostMode }
field = "I", boostKI, { boostEnabled && boostMode}
field = "D", boostKD, { boostEnabled && boostMode}
dialog = vvtSettings, "VVT Control"
field = "VVT Control Enabled", vvtEnabled
field = "VVT output pin", vvtPin, { vvtEnabled }
field = "VVT solenoid freq.", vvtFreq, { vvtEnabled }
dialog = wc_note
field = "For 99% of engines, warmup must have 100% in the final row. Typical maximum is 255% (cold)."
dialog = warmup, "Warmup Enrichment (WUE) - Percent Multiplier"
panel = warmup_curve
panel = wc_note
@ -1426,7 +1494,7 @@ menuDialog = main
;Fuel trim composite dialog
dialog = inj_trim1TblTitle, "Channel #1"
panel = fuelTrimTable1Tbl, Center, { fuelTrimEnabled }
panel = fuelTrimTable1Tbl, { fuelTrimEnabled }
dialog = inj_trim2TblTitle, "Channel #2"
panel = fuelTrimTable2Tbl, { fuelTrimEnabled }
dialog = inj_trim3TblTitle, "Channel #3"
@ -1441,9 +1509,12 @@ menuDialog = main
panel = inj_trim3TblTitle
panel = inj_trim4TblTitle
dialog = inj_trimad,"Injector Cyl 1-4 Trims", yAxis
dialog = inj_trim_enable, ""
field = "Individual fuel trim enabled", fuelTrimEnabled, { injLayout == 3 }
panel = inj_trimadt, North
dialog = inj_trimad,"Injector Cyl 1-4 Trims", yAxis
panel = inj_trim_enable, North
panel = inj_trimadt, Center
panel = inj_trimadb, South
dialog = outputtest_warningmessage, ""
@ -1809,8 +1880,6 @@ cmdtestspk450dc = "E\x03\x0C"
xBins = brvBins, batteryVoltage
yBins = injBatRates
; Correction curve for Air Density vs temperature
curve = airdensity_curve, "IAT density correction"
columnLabel = "Air Temperature", "Fuel Amount"
@ -1873,6 +1942,18 @@ cmdtestspk450dc = "E\x03\x0C"
xBins = iacBins, coolant
yBins = iacCLValues
curve = rotaryTrailing_curve, "Rotary Trailing Split"
columnLabel = "Engine load", "Split"
yAxis = 0, 40, 4
#if SPEED_DENSITY
xBins = rotarySplitBins, map
xAxis = 0, 250, 5
#else
xBins = rotarySplitBins, throttle
xAxis = 0, 100, 5
#endif
yBins = rotarySplitValues
; Warmup enrichment curve
curve = warmup_curve, "Warmup Enrichment (WUE) Curve"
;topicHelp = "file://$getProjectsDirPath()/docs/xxx.pdf#wue"
@ -1883,6 +1964,16 @@ cmdtestspk450dc = "E\x03\x0C"
yBins = wueRates
gauge = cltGauge
; Cranking enrichment curve
curve = cranking_enrich_curve, "Cranking Enrichment Curve"
;topicHelp = "file://$getProjectsDirPath()/docs/xxx.pdf#wue"
columnLabel = "Coolant", "Enrich %"
xAxis = -40, 110, 9
yAxis = 0, 200, 6
xBins = crankingEnrichBins, coolant
yBins = crankingEnrichValues
;gauge = cltGau25
; Warmup enrichment VEAL AFR adjustment curve (Not currently working)
;curve = warmup_afr_curve, "AFR Target Temperature Adustment"
; columnLabel = "Coolant Temp", "AFR Offset %"
@ -2148,7 +2239,7 @@ cmdtestspk450dc = "E\x03\x0C"
indicator = { launchSoft }, "Launch Soft", "Launch Soft", white, black, green, black
indicator = { softlimitOn }, "Soft Limit OFF","Soft Limiter", white, black, red, black
indicator = { hardLimitOn }, "Hard Limit OFF","Hard Limiter", white, black, red, black
indicator = { boostCutOut }, "Boost Cut OFF", "Boost Cut", 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
;-------------------------------------------------------------------------------
@ -2227,7 +2318,7 @@ cmdtestspk450dc = "E\x03\x0C"
deadValue = { 0 } ; Convenient unchanging value.
ochGetCommand = "r\$tsCanId\x30%2o%2c"
ochBlockSize = 73
ochBlockSize = 74
secl = scalar, U08, 0, "sec", 1.000, 0.000
squirt = scalar, U08, 1, "bits", 1.000, 0.000
@ -2249,39 +2340,37 @@ cmdtestspk450dc = "E\x03\x0C"
mapaccaen = bits, U08, 2, [6:6]
mapaccden = bits, U08, 2, [7:7]
dwell = scalar, U08, 3, "ms", 0.100, 0.000
map = scalar, U08, 4, "kpa", 2.000, 0.000
iatRaw = scalar, U08, 5, "°C", 1.000, 0.000
coolantRaw = scalar, U08, 6, "°C", 1.000, 0.000
tpsADC = scalar, U08, 7, "ADC", 1.000, 0.000
batteryVoltage = scalar, U08, 8, "V", 0.100, 0.000
afr = scalar, U08, 9, "O2", 0.100, 0.000
egoCorrection = scalar, U08, 10, "%", 1.000, 0.000
airCorrection = scalar, U08, 11, "%", 1.000, 0.000
warmupEnrich = scalar, U08, 12, "%", 1.000, 0.000
rpm = scalar, U16, 13, "rpm", 1.000, 0.000
accelEnrich = scalar, U08, 15, "%", 1.000, 0.000
baro = scalar, U08, 16, "%", 1.000, 0.000
map = scalar, U16, 4, "kpa", 1.000, 0.000
iatRaw = scalar, U08, 6, "°C", 1.000, 0.000
coolantRaw = scalar, U08, 7, "°C", 1.000, 0.000
batCorrection = scalar, U08, 8, "%", 1.000, 0.000
batteryVoltage = scalar, U08, 9, "V", 0.100, 0.000
afr = scalar, U08, 10, "O2", 0.100, 0.000
egoCorrection = scalar, U08, 11, "%", 1.000, 0.000
airCorrection = scalar, U08, 12, "%", 1.000, 0.000
warmupEnrich = scalar, U08, 13, "%", 1.000, 0.000
rpm = scalar, U16, 14, "rpm", 1.000, 0.000
accelEnrich = scalar, U08, 16, "%", 1.000, 0.000
gammaEnrich = scalar, U08, 17, "%", 1.000, 0.000
veCurr = scalar, U08, 18, "%", 1.000, 0.000
afrTarget = scalar, U08, 19, "O2", 0.100, 0.000
pulseWidth = scalar, U08, 20, "ms", 0.1, 0.000
TPSdot = scalar, U08, 21, "%/s", 10.00, 0.000
;advance = scalar, U08, 22, "deg", 1.000, 0.000
advance = scalar, S08, 22, "deg", 1.000, 0.000
tps = scalar, U08, 23, "%", 1.000, 0.000
loopsPerSecond = scalar, U16, 24, "loops", 1.000, 0.000
freeRAM = scalar, S16, 26, "bytes", 1.000, 0.000
batCorrection = scalar, U08, 28, "%", 1.000, 0.000
spark = scalar, U08, 29, "bits", 1.000, 0.000
launchHard = bits, U08, 29, [0:0]
launchSoft = bits, U08, 29, [1:1]
hardLimitOn = bits, U08, 29, [2:2]
softlimitOn = bits, U08, 29, [3:3]
boostCutSpark = bits, U08, 29, [4:4]
error = bits, U08, 29, [5:5]
idle = bits, U08, 29, [6:6]
sync = bits, U08, 29, [7:7]
afr2 = scalar, U08, 30, "O2", 0.100, 0.000
freeRAM = scalar, U16, 26, "bytes", 1.000, 0.000
boostTarget = scalar, U08, 28, "kPa", 2.000, 0.000
boostDuty = scalar, U08, 29, "%", 1.000, 0.000
spark = scalar, U08, 30, "bits", 1.000, 0.000
launchHard = bits, U08, 30, [0:0]
launchSoft = bits, U08, 30, [1:1]
hardLimitOn = bits, U08, 30, [2:2]
softlimitOn = bits, U08, 30, [3:3]
boostCutSpark = bits, U08, 30, [4:4]
error = bits, U08, 30, [5:5]
idle = bits, U08, 30, [6:6]
sync = bits, U08, 30, [7:7]
rpmDOT = scalar, S16, 31, "rpm/s", 1.000, 0.000
flex = scalar, U08, 33, "%", 1.000, 0.000
flexFuelCor = scalar, U08, 34, "%", 1.000, 0.000
@ -2289,12 +2378,12 @@ cmdtestspk450dc = "E\x03\x0C"
errors = scalar, U08, 36, "bits", 1.000, 0.000
errorNum = bits, U08, 36, [0:1]
currentError = bits, U08, 36, [2:7]
boostTarget = scalar, U08, 37, "kPa", 2.000, 0.000
boostDuty = scalar, U08, 38, "%", 1.000, 0.000
idleLoad = scalar, U08, 39, { bitStringValue( idleUnits , iacAlgorithm ) }, 2.000, 0.000 ; This is a combined variable covering both PWM and stepper IACs. The units used depend on which idle algorithm is chosen
testoutputs = scalar, U08, 40, "bits", 1.000, 0.000
testenabled = bits, U08, 40, [0:0]
testactive = bits, U08, 40, [1:1]
idleLoad = scalar, U08, 37, { bitStringValue( idleUnits , iacAlgorithm ) }, 2.000, 0.000 ; This is a combined variable covering both PWM and stepper IACs. The units used depend on which idle algorithm is chosen
testoutputs = scalar, U08, 38, "bits", 1.000, 0.000
testenabled = bits, U08, 38, [0:0]
testactive = bits, U08, 38, [1:1]
afr2 = scalar, U08, 39, "O2", 0.100, 0.000
baro = scalar, U08, 40, "kpa", 1.000, 0.000
canin_gauge0 = scalar, U16, 41, "", 1.000, 0.000
canin_gauge1 = scalar, U16, 43, "", 1.000, 0.000
canin_gauge2 = scalar, U16, 45, "", 1.000, 0.000
@ -2304,13 +2393,14 @@ cmdtestspk450dc = "E\x03\x0C"
canin_gauge6 = scalar, U16, 53, "", 1.000, 0.000
canin_gauge7 = scalar, U16, 55, "", 1.000, 0.000
canin_gauge8 = scalar, U16, 57, "", 1.000, 0.000
canin_gauge9 = scalar, U16, 59, "", 1.000, 0.000
canin_gauge10 = scalar, U16, 61, "", 1.000, 0.000
canin_gauge11 = scalar, U16, 63, "", 1.000, 0.000
canin_gauge12 = scalar, U16, 65, "", 1.000, 0.000
canin_gauge13 = scalar, U16, 67, "", 1.000, 0.000
canin_gauge14 = scalar, U16, 69, "", 1.000, 0.000
canin_gauge15 = scalar, U16, 71, "", 1.000, 0.000
canin_gauge9 = scalar, U16, 59, "", 1.000, 0.000
canin_gauge10 = scalar, U16, 61, "", 1.000, 0.000
canin_gauge11 = scalar, U16, 63, "", 1.000, 0.000
canin_gauge12 = scalar, U16, 65, "", 1.000, 0.000
canin_gauge13 = scalar, U16, 67, "", 1.000, 0.000
canin_gauge14 = scalar, U16, 69, "", 1.000, 0.000
canin_gauge15 = scalar, U16, 71, "", 1.000, 0.000
tpsADC = scalar, U08, 73, "ADC",1.000, 0.000
; Computed output channels. See "megatuneExamples.ini" for all the
; pre-defined variables, search for "???" and you'll see them.
@ -2391,10 +2481,9 @@ cmdtestspk450dc = "E\x03\x0C"
entry = rpm, "RPM", int, "%d"
entry = map, "MAP", int, "%d"
entry = MAPxRPM, "MAPxRPM", int, "%d"
entry = tpsADC, "tpsADC", int, "%d"
entry = tps, "TPS", int, "%d"
entry = afr, "O2", float, "%.3f"
entry = lambda, "%", float, "%.3f"
entry = lambda, "Lambda", float, "%.3f"
entry = iat, "IAT", int, "%d"
entry = coolant, "CLT", int, "%d"
entry = engine, "Engine", int, "%d"
@ -2426,7 +2515,9 @@ cmdtestspk450dc = "E\x03\x0C"
entry = boostDuty, "Boost Duty", int, "%d", { boostEnabled }
entry = boostCutOut , "Boost cut", int, "%d"
entry = idleLoad, "IAC value", int, "%d"
entry = baro, "Baro Pressure",int, "%d"
#if CAN_COMMANDS
entry = canin_gauge0, "CanIn CH0", int, "%d"
entry = canin_gauge1, "CanIn CH1", int, "%d"
entry = canin_gauge2, "CanIn CH2", int, "%d"
@ -2435,6 +2526,7 @@ cmdtestspk450dc = "E\x03\x0C"
entry = canin_gauge5, "CanIn CH5", int, "%d"
entry = canin_gauge6, "CanIn CH6", int, "%d"
entry = canin_gauge7, "CanIn CH7", int, "%d"
#endif
[LoggerDefinition]

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
reference/wiki/TS_9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -6,6 +6,61 @@ void boostControl();
void vvtControl();
void initialiseFan();
#if defined(CORE_AVR)
#define ENABLE_BOOST_TIMER() TIMSK1 |= (1 << OCIE1A)
#define DISABLE_BOOST_TIMER() TIMSK1 &= ~(1 << OCIE1A)
#define ENABLE_VVT_TIMER() TIMSK1 |= (1 << OCIE1B)
#define DISABLE_VVT_TIMER() TIMSK1 &= ~(1 << OCIE1B)
#define BOOST_TIMER_COMPARE OCR1A
#define BOOST_TIMER_COUNTER TCNT1
#define VVT_TIMER_COMPARE OCR1B
#define VVT_TIMER_COUNTER TCNT1
#elif defined(CORE_TEENSY)
#define ENABLE_BOOST_TIMER() FTM1_C0SC |= FTM_CSC_CHIE
#define DISABLE_BOOST_TIMER() FTM1_C0SC &= ~FTM_CSC_CHIE
#define ENABLE_VVT_TIMER() FTM1_C1SC |= FTM_CSC_CHIE
#define DISABLE_VVT_TIMER() FTM1_C1SC &= ~FTM_CSC_CHIE
#define BOOST_TIMER_COMPARE FTM1_C0V
#define BOOST_TIMER_COUNTER FTM1_CNT
#define VVT_TIMER_COMPARE FTM1_C1V
#define VVT_TIMER_COUNTER FTM1_CNT
#elif defined(CORE_STM32)
#if defined(ARDUINO_ARCH_STM32) // STM32GENERIC core
#define ENABLE_BOOST_TIMER() (TIM1)->CCER |= TIM_CCER_CC2E
#define DISABLE_BOOST_TIMER() (TIM1)->CCER &= ~TIM_CCER_CC2E
#define ENABLE_VVT_TIMER() (TIM1)->CCER |= TIM_CCER_CC3E
#define DISABLE_VVT_TIMER() (TIM1)->CCER &= ~TIM_CCER_CC3E
#define BOOST_TIMER_COMPARE (TIM1)->CCR2
#define BOOST_TIMER_COUNTER (TIM1)->CNT
#define VVT_TIMER_COMPARE (TIM1)->CCR3
#define VVT_TIMER_COUNTER (TIM1)->CNT
#else //libmaple core aka STM32DUINO
#define ENABLE_BOOST_TIMER() (TIMER1->regs).gen->CCER |= TIMER_CCER_CC2E
#define DISABLE_BOOST_TIMER() (TIMER1->regs).gen->CCER &= ~TIMER_CCER_CC2E
#define ENABLE_VVT_TIMER() (TIMER1->regs).gen->CCER |= TIMER_CCER_CC3E
#define DISABLE_VVT_TIMER() (TIMER1->regs).gen->CCER &= ~TIMER_CCER_CC3E
#define BOOST_TIMER_COMPARE (TIMER1->regs).gen->CCR2
#define BOOST_TIMER_COUNTER (TIMER1->regs).gen->CNT
#define VVT_TIMER_COMPARE (TIMER1->regs).gen->CCR3
#define VVT_TIMER_COUNTER (TIMER1->regs).gen->CNT
#endif
#endif
#define BOOST_PIN_LOW() *boost_pin_port &= ~(boost_pin_mask)
#define BOOST_PIN_HIGH() *boost_pin_port |= (boost_pin_mask)
#define VVT_PIN_LOW() *vvt_pin_port &= ~(vvt_pin_mask)
#define VVT_PIN_HIGH() *vvt_pin_port |= (vvt_pin_mask)
volatile byte *boost_pin_port;
volatile byte boost_pin_mask;
volatile byte *vvt_pin_port;
@ -17,15 +72,15 @@ volatile unsigned int boost_pwm_cur_value;
long boost_pwm_target_value;
long boost_cl_target_boost;
byte boostCounter;
//Boost control uses a scaling factor of 100 on the MAP reading and MAP target in order to have a reasonable response time
//These are the values that are passed to the PID controller
long MAPx100;
long boostTargetx100;
volatile bool vvt_pwm_state;
unsigned int vvt_pwm_max_count; //Used for variable PWM frequency
volatile unsigned int vvt_pwm_cur_value;
long vvt_pwm_target_value;
#if defined (CORE_TEENSY) || defined(CORE_STM32)
static inline void boostInterrupt();
static inline void vvtInterrupt();
#endif
#endif

View File

@ -3,14 +3,16 @@ Speeduino - Simple engine management for the Arduino Mega 2560 platform
Copyright (C) Josh Stewart
A full copy of the license may be found in the projects root directory
*/
integerPID boostPID(&MAPx100, &boost_pwm_target_value, &boostTargetx100, 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
//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
/*
Fan control
*/
void initialiseFan()
{
if( configPage4.fanInv == 1 ) { fanHIGH = LOW; fanLOW = HIGH; }
if( configPage3.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;
@ -18,85 +20,107 @@ void initialiseFan()
void fanControl()
{
if( configPage4.fanEnable == 1 )
if( configPage3.fanEnable == 1 )
{
int onTemp = (int)configPage4.fanSP - CALIBRATION_TEMPERATURE_OFFSET;
int offTemp = onTemp - configPage4.fanHyster;
int onTemp = (int)configPage3.fanSP - CALIBRATION_TEMPERATURE_OFFSET;
int offTemp = onTemp - configPage3.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; }
}
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
void initialiseAuxPWM()
{
TCCR1B = 0x00; //Disbale Timer1 while we set it up
TCNT1 = 0; //Reset Timer Count
TIFR1 = 0x00; //Timer1 INT Flag Reg: Clear Timer Overflow Flag
TCCR1A = 0x00; //Timer1 Control Reg A: Wave Gen Mode normal (Simply counts up from 0 to 65535 (16-bit int)
TCCR1B = (1 << CS12); //Timer1 Control Reg B: Timer Prescaler set to 256. 1 tick = 16uS. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
#if defined(CORE_AVR)
TCCR1B = 0x00; //Disbale Timer1 while we set it up
TCNT1 = 0; //Reset Timer Count
TIFR1 = 0x00; //Timer1 INT Flag Reg: Clear Timer Overflow Flag
TCCR1A = 0x00; //Timer1 Control Reg A: Wave Gen Mode normal (Simply counts up from 0 to 65535 (16-bit int)
TCCR1B = (1 << CS12); //Timer1 Control Reg B: Timer Prescaler set to 256. 1 tick = 16uS. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
#elif defined(CORE_TEENSY)
//REALLY NEED TO DO THIS!
#elif defined(CORE_STM32)
Timer1.attachInterrupt(2, boostInterrupt);
Timer1.attachInterrupt(3, vvtInterrupt);
Timer1.resume();
#endif
boost_pin_port = portOutputRegister(digitalPinToPort(pinBoost));
boost_pin_mask = digitalPinToBitMask(pinBoost);
vvt_pin_port = portOutputRegister(digitalPinToPort(pinVVT_1));
vvt_pin_mask = digitalPinToBitMask(pinVVT_1);
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
#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
#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
#endif
//TIMSK1 |= (1 << OCIE1A); <---- Not required as compare A is turned on when needed by boost control
TIMSK1 |= (1 << OCIE1B); //Turn on the B compare unit (ie turn on the interrupt)
ENABLE_VVT_TIMER(); //Turn on the B compare unit (ie turn on the interrupt)
boostPID.SetOutputLimits(percentage(configPage1.boostMinDuty, boost_pwm_max_count) , percentage(configPage1.boostMaxDuty, boost_pwm_max_count));
boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD);
boostPID.SetMode(AUTOMATIC); //Turn PID on
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); }
currentStatus.boostDuty = 0;
boostCounter = 0;
}
#define BOOST_HYSTER 40
void boostControl()
{
if( configPage3.boostEnabled==1 )
{
if(currentStatus.MAP >= 100)
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) )
{
MAPx100 = currentStatus.MAP * 100;
boost_cl_target_boost = get3DTableValue(&boostTable, currentStatus.TPS, currentStatus.RPM) * 2; //Boost target table is in kpa and divided by 2
//If flex fuel is enabled, there can be an adder to the boost target based on ethanol content
if( configPage1.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
boost_cl_target_boost = boost_cl_target_boost + boostAdder;
currentStatus.boostTarget += boostAdder;
}
boostTargetx100 = boost_cl_target_boost * 100;
currentStatus.boostTarget = boost_cl_target_boost >> 1; //Boost target is sent as a byte value to TS and so is divided by 2
if(currentStatus.boostTarget > 0)
{
if( (boostCounter & 31) == 1) { boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); } //This only needs to be run very infrequently, once every 32 calls to boostControl(). This is approx. once per second
//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);
if(configPage3.boostMode == BOOST_MODE_SIMPLE) { boostPID.SetTunings(100, 100, 100); }
else { boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); }
}
bool PIDcomputed = boostPID.Compute(); //Compute() returns false if the required interval has not yet passed.
if(currentStatus.boostDuty == 0) { DISABLE_BOOST_TIMER(); BOOST_PIN_LOW(); } //If boost duty is 0, shut everything down
else
{
if(PIDcomputed == true)
{
boost_pwm_target_value = ((unsigned long)(currentStatus.boostDuty) * boost_pwm_max_count) / 10000; //Convert boost duty (Which is a % multipled by 100) to a pwm count
ENABLE_BOOST_TIMER(); //Turn on the compare unit (ie turn on the interrupt) if boost duty >0
}
}
boostPID.Compute();
currentStatus.boostDuty = (unsigned long)(boost_pwm_target_value * 100UL) / boost_pwm_max_count;
TIMSK1 |= (1 << OCIE1A); //Turn on the compare unit (ie turn on the interrupt)
}
else
{
//If boost target is 0, turn everything off
TIMSK1 &= ~(1 << OCIE1A); //Turn off timer
digitalWrite(pinBoost, LOW);
boostDisable();
}
}
else
{
//Boost control does nothing if kPa below 100
TIMSK1 &= ~(1 << OCIE1A); //Turn off timer
digitalWrite(pinBoost, LOW); //Make sure solenoid is off (0% duty)
//Boost control does nothing if kPa below the hyster point
boostDisable();
}
}
else { TIMSK1 &= ~(1 << OCIE1A); } // Disable timer channel
else { DISABLE_BOOST_TIMER(); } // Disable timer channel
boostCounter++;
}
@ -106,53 +130,75 @@ void vvtControl()
if( configPage3.vvtEnabled == 1 )
{
byte vvtDuty = get3DTableValue(&vvtTable, currentStatus.TPS, currentStatus.RPM);
vvt_pwm_target_value = percentage(vvtDuty, vvt_pwm_max_count);
if(vvtDuty == 0)
{
//Make sure solenoid is off (0% duty)
VVT_PIN_LOW();
DISABLE_VVT_TIMER();
}
else if (vvtDuty >= 100)
{
//Make sure solenoid is on (100% duty)
VVT_PIN_HIGH();
DISABLE_VVT_TIMER();
}
else
{
vvt_pwm_target_value = percentage(vvtDuty, vvt_pwm_max_count);
ENABLE_VVT_TIMER();
}
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
else { TIMSK1 &= ~(1 << OCIE1B); } // Disable timer channel
#endif
else { DISABLE_VVT_TIMER(); } // Disable timer channel
}
void boostDisable()
{
boostPID.Initialize(); //This resets the ITerm value to prevent rubber banding
currentStatus.boostDuty = 0;
DISABLE_BOOST_TIMER(); //Turn off timer
BOOST_PIN_LOW(); //Make sure solenoid is off (0% duty)
}
//The interrupt to control the Boost PWM
ISR(TIMER1_COMPA_vect)
#if defined(CORE_AVR)
ISR(TIMER1_COMPA_vect)
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
static inline void boostInterrupt() //Most ARM chips can simply call a function
#endif
{
if (boost_pwm_state)
{
*boost_pin_port &= ~(boost_pin_mask); // Switch pin to low
OCR1A = TCNT1 + (boost_pwm_max_count - boost_pwm_cur_value);
BOOST_PIN_LOW(); // Switch pin to low
BOOST_TIMER_COMPARE = BOOST_TIMER_COUNTER + (boost_pwm_max_count - boost_pwm_cur_value);
boost_pwm_state = false;
}
else
{
*boost_pin_port |= (boost_pin_mask); // Switch pin high
OCR1A = TCNT1 + boost_pwm_target_value;
BOOST_PIN_HIGH(); // Switch pin high
BOOST_TIMER_COMPARE = BOOST_TIMER_COUNTER + boost_pwm_target_value;
boost_pwm_cur_value = boost_pwm_target_value;
boost_pwm_state = true;
}
}
//The interrupt to control the VVT PWM
ISR(TIMER1_COMPB_vect)
#if defined(CORE_AVR)
ISR(TIMER1_COMPB_vect)
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
static inline void vvtInterrupt() //Most ARM chips can simply call a function
#endif
{
if (vvt_pwm_state)
{
*vvt_pin_port &= ~(vvt_pin_mask); // Switch pin to low
OCR1B = TCNT1 + (vvt_pwm_max_count - vvt_pwm_cur_value);
VVT_PIN_LOW(); // Switch pin to low
VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + (vvt_pwm_max_count - vvt_pwm_cur_value);
vvt_pwm_state = false;
}
else
{
*vvt_pin_port |= (vvt_pin_mask); // Switch pin high
OCR1B = TCNT1 + vvt_pwm_target_value;
VVT_PIN_HIGH(); // Switch pin high
VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + vvt_pwm_target_value;
vvt_pwm_cur_value = vvt_pwm_target_value;
vvt_pwm_state = true;
}
}
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
//YET TO BE IMPLEMENTED ON TEENSY
void initialiseAuxPWM() { }
void boostControl() { }
void vvtControl() { }
#endif

View File

@ -1,26 +1,30 @@
#ifndef CANCOMMS_H
#define CANCOMMS_H
//These are the page numbers that the Tuner Studio serial protocol uses to transverse the different map and config pages.
#define veMapPage 1
uint8_t currentcanCommand;
uint8_t currentCanPage = 1;//Not the same as the speeduino config page numbers
uint8_t nCanretry = 0; //no of retrys
uint8_t cancmdfail = 0; //command fail yes/no
uint8_t canlisten = 0;
uint8_t Lbuffer[8]; //8 byte buffer to store incomng can data
uint8_t Gdata[9];
uint8_t Glow, Ghigh;
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
HardwareSerial &CANSerial = Serial3;
#elif defined(CORE_STM32)
HardwareSerial &CANSerial = Serial2;
#elif defined(CORE_TEENSY)
HardwareSerial &CANSerial = Serial2;
#endif
void canCommand();//This is the heart of the Command Line Interpeter. All that needed to be done was to make it human readable.
void sendCancommand(uint8_t cmdtype , uint16_t canadddress, uint8_t candata1, uint8_t candata2, uint16_t paramgroup);
#endif // CANCOMMS_H
#ifndef CANCOMMS_H
#define CANCOMMS_H
//These are the page numbers that the Tuner Studio serial protocol uses to transverse the different map and config pages.
#define veMapPage 1
uint8_t currentcanCommand;
uint8_t currentCanPage = 1;//Not the same as the speeduino config page numbers
uint8_t nCanretry = 0; //no of retrys
uint8_t cancmdfail = 0; //command fail yes/no
uint8_t canlisten = 0;
uint8_t Lbuffer[8]; //8 byte buffer to store incomng can data
uint8_t Gdata[9];
uint8_t Glow, Ghigh;
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
HardwareSerial &CANSerial = Serial3;
#elif defined(CORE_STM32)
#if defined(ARDUINO_ARCH_STM32) // STM32GENERIC core
SerialUART &CANSerial = Serial2;
#else //libmaple core aka STM32DUINO
HardwareSerial &CANSerial = Serial2;
#endif
#elif defined(CORE_TEENSY)
HardwareSerial &CANSerial = Serial2;
#endif
void canCommand();//This is the heart of the Command Line Interpeter. All that needed to be done was to make it human readable.
void sendCancommand(uint8_t cmdtype , uint16_t canadddress, uint8_t candata1, uint8_t candata2, uint16_t paramgroup);
#endif // CANCOMMS_H

View File

@ -7,18 +7,21 @@
#define ignSetPage 4//Config Page 2
#define afrMapPage 5
#define afrSetPage 6//Config Page 3
#define iacPage 7//Config Page 4
#define boostvvtPage 8
#define seqFuelPage 9
#define canbusPage 10//Config Page 10
#define boostvvtPage 7
#define seqFuelPage 8
#define canbusPage 9//Config Page 9
#define warmupPage 10 //Config Page 10
#define packetSize 73
#define packetSize 74
byte currentPage = 1;//Not the same as the speeduino config page numbers
bool isMap = true;
unsigned long requestCount = 0; //The number of times the A command has been issued
byte currentCommand;
bool cmdPending = false;
bool chunkPending = false;
uint16_t chunkComplete = 0;
int16_t chunkSize = 0;
byte cmdGroup = 0;
byte cmdValue = 0;
int cmdCombined = 0; //the cmdgroup as high byte and cmdvalue as low byte

View File

@ -15,7 +15,9 @@ A detailed description of each call can be found at: http://www.msextra.com/doc/
void command()
{
if (!cmdPending) { currentCommand = Serial.read(); }
int valueOffset; //cannot use offset as a variable name, it is a reserved word for several teensy libraries
if (cmdPending == false) { currentCommand = Serial.read(); }
switch (currentCommand)
{
@ -26,13 +28,31 @@ void command()
case 'B': // Burn current values to eeprom
writeConfig();
writeAllConfig();
break;
case 'b': // New EEPROM burn command to only burn a single page at a time
cmdPending = true;
if (Serial.available() >= 2)
{
Serial.read(); //Ignore the first table value, it's always 0
writeConfig(Serial.read());
cmdPending = false;
}
break;
case 'C': // test communications. This is used by Tunerstudio to see whether there is an ECU on a given serial port
testComm();
break;
case 'c': //Send the current loops/sec value
Serial.write(lowByte(currentStatus.loopsPerSecond));
Serial.write(highByte(currentStatus.loopsPerSecond));
break;
//The following can be used to show the amount of free memory
case 'E': // receive command button commands
cmdPending = true;
@ -47,10 +67,20 @@ void command()
}
break;
case 'F': // send serial protocol version
Serial.print("001");
break;
case 'L': // List the contents of current page in human readable form
sendPage(true);
break;
case 'm': //Send the current free memory
currentStatus.freeRAM = freeRam();
Serial.write(lowByte(currentStatus.freeRAM));
Serial.write(highByte(currentStatus.freeRAM));
break;
case 'N': // Displays a new line. Like pushing enter in a text editor
Serial.println();
break;
@ -62,31 +92,100 @@ void command()
if (Serial.available() > 0)
{
currentPage = Serial.read();
if (currentPage >= '0') {//This converts the ascii number char into binary
currentPage -= '0';
//This converts the ascii number char into binary. Note that this will break everyything if there are ever more than 48 pages (48 = asci code for '0')
if (currentPage >= '0') { currentPage -= '0'; }
// Detecting if the current page is a table/map
if ( (currentPage == veMapPage) || (currentPage == ignMapPage) || (currentPage == afrMapPage) ) { isMap = true; }
else { isMap = false; }
cmdPending = false;
}
break;
/*
* New method for sending page values
*/
case 'p':
cmdPending = true;
//6 bytes required:
//2 - Page identifier
//2 - offset
//2 - Length
if(Serial.available() >= 6)
{
byte offset1, offset2, length1, length2;
int length;
byte tempPage;
Serial.read(); // First byte of the page identifier can be ignored. It's always 0
tempPage = Serial.read();
//currentPage = 1;
offset1 = Serial.read();
offset2 = Serial.read();
valueOffset = word(offset2, offset1);
length1 = Serial.read();
length2 = Serial.read();
length = word(length2, length1);
for(int i = 0; i < length; i++)
{
Serial.write( getPageValue(tempPage, valueOffset + i) );
}
if ( (currentPage == veMapPage) || (currentPage == ignMapPage) || (currentPage == afrMapPage) ) { // Detecting if the current page is a table/map
isMap = true;
cmdPending = false;
}
break;
case 'Q': // send code version
Serial.print("speeduino 201709-dev");
break;
case 'r': //New format for the optimised OutputChannels
cmdPending = true;
byte cmd;
if (Serial.available() >= 6)
{
tsCanId = Serial.read(); //Read the $tsCanId
cmd = Serial.read(); // read the command
uint16_t offset, length;
if(cmd == 0x30) //Send output channels command 0x30 is 48dec
{
byte tmp;
tmp = Serial.read();
offset = word(Serial.read(), tmp);
tmp = Serial.read();
length = word(Serial.read(), tmp);
sendValues(offset, length,cmd, 0);
}
else {
isMap = false;
else
{
//No other r/ commands should be called
}
cmdPending = false;
}
break;
case 'F': // send serial protocol version
Serial.print("001");
break;
case 'S': // send code version
Serial.print("Speeduino 2017.06-dev");
Serial.print("Speeduino 2017.09-dev");
currentStatus.secl = 0; //This is required in TS3 due to its stricter timings
break;
case 'Q': // send code version
Serial.print("speeduino 201706-dev");
break;
case 'T': //Send 256 tooth log entries to Tuner Studios tooth logger
sendToothLog(false); //Sends tooth log values as ints
break;
case 't': // receive new Calibration info. Command structure: "t", <tble_idx> <data array>. This is an MS2/Extra command, NOT part of MS1 spec
byte tableID;
//byte canID;
//The first 2 bytes sent represent the canID and tableID
while (Serial.available() == 0) { }
tableID = Serial.read(); //Not currently used for anything
receiveCalibration(tableID); //Receive new values and store in memory
writeCalibration(); //Store received values in EEPROM
break;
case 'V': // send VE table and constants in binary
sendPage(false);
@ -95,8 +194,6 @@ void command()
case 'W': // receive new VE obr constant at 'W'+<offset>+<newbyte>
cmdPending = true;
int valueOffset; //cannot use offset as a variable name, it is a reserved word for several teensy libraries
if (isMap)
{
if(Serial.available() >= 3) // 1 additional byte is required on the MAP pages which are larger than 255 bytes
@ -121,17 +218,40 @@ void command()
break;
case 't': // receive new Calibration info. Command structure: "t", <tble_idx> <data array>. This is an MS2/Extra command, NOT part of MS1 spec
byte tableID;
//byte canID;
case 'w':
cmdPending = true;
//The first 2 bytes sent represent the canID and tableID
while (Serial.available() == 0) { }
tableID = Serial.read(); //Not currently used for anything
if(chunkPending == false)
{
//This means it's a new request
//7 bytes required:
//2 - Page identifier
//2 - offset
//2 - Length (Should always be 1 until chunk write is setup)
//1 - New value
if(Serial.available() >= 7)
{
byte offset1, offset2, length1, length2;
receiveCalibration(tableID); //Receive new values and store in memory
writeCalibration(); //Store received values in EEPROM
Serial.read(); // First byte of the page identifier can be ignored. It's always 0
currentPage = Serial.read();
//currentPage = 1;
offset1 = Serial.read();
offset2 = Serial.read();
valueOffset = word(offset2, offset1);
length1 = Serial.read(); // Length to be written (Should always be 1)
length2 = Serial.read(); // Length to be written (Should always be 1)
chunkSize = word(length2, length1);
//chunkPending = true;
for(int i = 0; i < chunkSize; i++)
{
while(Serial.available() == 0) { } //For chunk writes, we can safely loop here
receiveValue( (valueOffset + i), Serial.read());
}
cmdPending = false;
}
}
break;
case 'Z': //Totally non-standard testing function. Will be removed once calibration testing is completed. This function takes 1.5kb of program space! :S
@ -166,41 +286,10 @@ void command()
Serial.flush();
break;
case 'T': //Send 256 tooth log entries to Tuner Studios tooth logger
sendToothLog(false); //Sends tooth log values as ints
break;
case 'z': //Send 256 tooth log entries to a terminal emulator
sendToothLog(true); //Sends tooth log values as chars
break;
case 'r': //New format for the optimised OutputChannels
cmdPending = true;
byte cmd;
if (Serial.available() >= 6)
{
tsCanId = Serial.read(); //Read the $tsCanId
cmd = Serial.read(); // read the command
uint16_t offset, length;
if(cmd == 0x30) //Send output channels command 0x30 is 48dec
{
byte tmp;
tmp = Serial.read();
offset = word(Serial.read(), tmp);
tmp = Serial.read();
length = word(Serial.read(), tmp);
sendValues(offset, length,cmd, 0);
}
else
{
//No other r/ commands should be called
}
cmdPending = false;
}
break;
case '?':
Serial.println
(F(
@ -258,8 +347,8 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum)
}
else
{
CANSerial.write("r"); //confirm cmd type
CANSerial.write(cmd);
CANSerial.write("r"); //confirm cmd type
CANSerial.write(cmd);
}
#endif
}
@ -275,19 +364,19 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum)
fullStatus[1] = currentStatus.squirt; //Squirt Bitfield
fullStatus[2] = currentStatus.engine; //Engine Status Bitfield
fullStatus[3] = (byte)(divu100(currentStatus.dwell)); //Dwell in ms * 10
fullStatus[4] = (byte)(currentStatus.MAP >> 1); //map value is divided by 2
fullStatus[5] = (byte)(currentStatus.IAT + CALIBRATION_TEMPERATURE_OFFSET); //mat
fullStatus[6] = (byte)(currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //Coolant ADC
fullStatus[7] = currentStatus.tpsADC; //TPS (Raw 0-255)
fullStatus[8] = currentStatus.battery10; //battery voltage
fullStatus[9] = currentStatus.O2; //O2
fullStatus[10] = currentStatus.egoCorrection; //Exhaust gas correction (%)
fullStatus[11] = currentStatus.iatCorrection; //Air temperature Correction (%)
fullStatus[12] = currentStatus.wueCorrection; //Warmup enrichment (%)
fullStatus[13] = lowByte(currentStatus.RPM); //rpm HB
fullStatus[14] = highByte(currentStatus.RPM); //rpm LB
fullStatus[15] = currentStatus.TAEamount; //acceleration enrichment (%)
fullStatus[16] = currentStatus.baro; //Barometer value
fullStatus[4] = lowByte(currentStatus.MAP); //2 bytes for MAP
fullStatus[5] = highByte(currentStatus.MAP);
fullStatus[6] = (byte)(currentStatus.IAT + CALIBRATION_TEMPERATURE_OFFSET); //mat
fullStatus[7] = (byte)(currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //Coolant ADC
fullStatus[8] = currentStatus.batCorrection; //Battery voltage correction (%)
fullStatus[9] = currentStatus.battery10; //battery voltage
fullStatus[10] = currentStatus.O2; //O2
fullStatus[11] = currentStatus.egoCorrection; //Exhaust gas correction (%)
fullStatus[12] = currentStatus.iatCorrection; //Air temperature Correction (%)
fullStatus[13] = currentStatus.wueCorrection; //Warmup enrichment (%)
fullStatus[14] = lowByte(currentStatus.RPM); //rpm HB
fullStatus[15] = highByte(currentStatus.RPM); //rpm LB
fullStatus[16] = currentStatus.TAEamount; //acceleration enrichment (%)
fullStatus[17] = currentStatus.corrections; //Total GammaE (%)
fullStatus[18] = currentStatus.VE; //Current VE 1 (%)
fullStatus[19] = currentStatus.afrTarget;
@ -304,9 +393,9 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum)
fullStatus[26] = lowByte(currentStatus.freeRAM); //(byte)((currentStatus.loopsPerSecond >> 8) & 0xFF);
fullStatus[27] = highByte(currentStatus.freeRAM);
fullStatus[28] = currentStatus.batCorrection; //Battery voltage correction (%)
fullStatus[29] = currentStatus.spark; //Spark related bitfield
fullStatus[30] = currentStatus.O2_2; //O2
fullStatus[28] = (byte)(currentStatus.boostTarget >> 1); //Divide boost target by 2 to fit in a byte
fullStatus[29] = (byte)(currentStatus.boostDuty / 100);
fullStatus[30] = currentStatus.spark; //Spark related bitfield
//rpmDOT must be sent as a signed integer
fullStatus[31] = lowByte(currentStatus.rpmDOT);
@ -316,10 +405,13 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum)
fullStatus[34] = currentStatus.flexCorrection; //Flex fuel correction (% above or below 100)
fullStatus[35] = currentStatus.flexIgnCorrection; //Ignition correction (Increased degrees of advance) for flex fuel
fullStatus[36] = getNextError();
fullStatus[37] = currentStatus.boostTarget;
fullStatus[38] = currentStatus.boostDuty;
fullStatus[39] = currentStatus.idleLoad;
fullStatus[40] = currentStatus.testOutputs;
fullStatus[37] = currentStatus.idleLoad;
fullStatus[38] = currentStatus.testOutputs;
fullStatus[39] = currentStatus.O2_2; //O2
fullStatus[40] = currentStatus.baro; //Barometer value
fullStatus[41] = lowByte(currentStatus.canin[0]);
fullStatus[42] = highByte(currentStatus.canin[0]);
fullStatus[43] = lowByte(currentStatus.canin[1]);
@ -352,7 +444,9 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum)
fullStatus[70] = highByte(currentStatus.canin[14]);
fullStatus[71] = lowByte(currentStatus.canin[15]);
fullStatus[72] = highByte(currentStatus.canin[15]);
fullStatus[73] = currentStatus.tpsADC;
for(byte x=0; x<packetLength; x++)
{
if (portNum == 0) { Serial.write(fullStatus[offset+x]); }
@ -365,6 +459,7 @@ void receiveValue(int valueOffset, byte newValue)
{
void* pnt_configPage;//This only stores the address of the value that it's pointing to and not the max size
int tempOffset;
switch (currentPage)
{
@ -381,19 +476,23 @@ void receiveValue(int valueOffset, byte newValue)
//X Axis
fuelTable.axisX[(valueOffset - 256)] = ((int)(newValue) * TABLE_RPM_MULTIPLIER); //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
}
else
else if(valueOffset < 288)
{
//Y Axis
int tempOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order (Due to us using (0,0) in the top left rather than bottom right
tempOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order (Due to us using (0,0) in the top left rather than bottom right
fuelTable.axisY[tempOffset] = (int)(newValue) * TABLE_LOAD_MULTIPLIER;
}
else
{
//This should never happen. It means there's an invalid offset value coming through
}
}
break;
case veSetPage:
pnt_configPage = &configPage1; //Setup a pointer to the relevant config page
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if (valueOffset < page_size)
if (valueOffset < npage_size[veSetPage])
{
*((byte *)pnt_configPage + (byte)valueOffset) = newValue;
}
@ -412,10 +511,10 @@ void receiveValue(int valueOffset, byte newValue)
//X Axis
ignitionTable.axisX[(valueOffset - 256)] = (int)(newValue) * TABLE_RPM_MULTIPLIER; //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct
}
else
else if(valueOffset < 288)
{
//Y Axis
int tempOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order
tempOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order
ignitionTable.axisY[tempOffset] = (int)(newValue) * TABLE_LOAD_MULTIPLIER;
}
}
@ -424,7 +523,7 @@ void receiveValue(int valueOffset, byte newValue)
case ignSetPage:
pnt_configPage = &configPage2;
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if (valueOffset < page_size)
if (valueOffset < npage_size[ignSetPage])
{
*((byte *)pnt_configPage + (byte)valueOffset) = newValue;
}
@ -446,7 +545,7 @@ void receiveValue(int valueOffset, byte newValue)
else
{
//Y Axis
int tempOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order
tempOffset = 15 - (valueOffset - 272); //Need to do a translation to flip the order
afrTable.axisY[tempOffset] = int(newValue) * TABLE_LOAD_MULTIPLIER;
}
@ -456,16 +555,7 @@ void receiveValue(int valueOffset, byte newValue)
case afrSetPage:
pnt_configPage = &configPage3;
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if (valueOffset < page_size)
{
*((byte *)pnt_configPage + (byte)valueOffset) = newValue;
}
break;
case iacPage: //Idle Air Control settings page (Page 4)
pnt_configPage = &configPage4;
//For some reason, TunerStudio is sending offsets greater than the maximum page size. I'm not sure if it's their bug or mine, but the fix is to only update the config page if the offset is less than the maximum size
if (valueOffset < page_size)
if (valueOffset < npage_size[afrSetPage])
{
*((byte *)pnt_configPage + (byte)valueOffset) = newValue;
}
@ -486,40 +576,38 @@ void receiveValue(int valueOffset, byte newValue)
}
else if (valueOffset < 144) //New value is part of the vvt map
{
int tempOffset = valueOffset - 80;
tempOffset = valueOffset - 80;
vvtTable.values[7 - (tempOffset / 8)][tempOffset % 8] = newValue;
}
else if (valueOffset < 152) //New value is on the X (RPM) axis of the vvt table
{
int tempOffset = valueOffset - 144;
tempOffset = valueOffset - 144;
vvtTable.axisX[tempOffset] = int(newValue) * TABLE_RPM_MULTIPLIER; //The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
}
else //New value is on the Y (Load) axis of the vvt table
else if (valueOffset < 161) //New value is on the Y (Load) axis of the vvt table
{
int tempOffset = valueOffset - 152;
tempOffset = valueOffset - 152;
vvtTable.axisY[(7 - tempOffset)] = int(newValue); //TABLE_LOAD_MULTIPLIER is NOT used for vvt as it is TPS based (0-100)
}
break;
case seqFuelPage:
{
int tempOffset;
if (valueOffset < 36) { trim1Table.values[5 - (valueOffset / 6)][valueOffset % 6] = newValue; } //Trim1 values
else if (valueOffset < 42) { trim1Table.axisX[(valueOffset - 36)] = int(newValue) * TABLE_RPM_MULTIPLIER; } //New value is on the X (RPM) axis of the trim1 table. The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
else if (valueOffset < 48) { trim1Table.axisY[(5 - (valueOffset - 42))] = int(newValue) * TABLE_LOAD_MULTIPLIER; } //New value is on the Y (TPS) axis of the boost table
//Trim table 2
else if (valueOffset < 84) { tempOffset = valueOffset - 48; trim2Table.values[5 - (tempOffset / 6)][tempOffset % 6] = newValue; } //New value is part of the trim2 map
else if (valueOffset < 90) { tempOffset = valueOffset - 84; trim2Table.axisX[tempOffset] = int(newValue) * TABLE_RPM_MULTIPLIER; } //New value is on the X (RPM) axis of the table. The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
else if (valueOffset < 96) { tempOffset = valueOffset - 90; trim2Table.axisY[(5 - tempOffset)] = int(newValue) * TABLE_LOAD_MULTIPLIER; } //New value is on the Y (Load) axis of the table
//Trim table 3
else if (valueOffset < 132) { tempOffset = valueOffset - 96; trim3Table.values[5 - (tempOffset / 6)][tempOffset % 6] = newValue; } //New value is part of the trim2 map
else if (valueOffset < 138) { tempOffset = valueOffset - 132; trim3Table.axisX[tempOffset] = int(newValue) * TABLE_RPM_MULTIPLIER; } //New value is on the X (RPM) axis of the table. The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
else if (valueOffset < 144) { tempOffset = valueOffset - 138; trim3Table.axisY[(5 - tempOffset)] = int(newValue) * TABLE_LOAD_MULTIPLIER; } //New value is on the Y (Load) axis of the table
//Trim table 4
else if (valueOffset < 180) { tempOffset = valueOffset - 144; trim4Table.values[5 - (tempOffset / 6)][tempOffset % 6] = newValue; } //New value is part of the trim2 map
else if (valueOffset < 186) { tempOffset = valueOffset - 180; trim4Table.axisX[tempOffset] = int(newValue) * TABLE_RPM_MULTIPLIER; } //New value is on the X (RPM) axis of the table. The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
else if (valueOffset < 192) { tempOffset = valueOffset - 186; trim4Table.axisY[(5 - tempOffset)] = int(newValue) * TABLE_LOAD_MULTIPLIER; } //New value is on the Y (Load) axis of the table
}
if (valueOffset < 36) { trim1Table.values[5 - (valueOffset / 6)][valueOffset % 6] = newValue; } //Trim1 values
else if (valueOffset < 42) { trim1Table.axisX[(valueOffset - 36)] = int(newValue) * TABLE_RPM_MULTIPLIER; } //New value is on the X (RPM) axis of the trim1 table. The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
else if (valueOffset < 48) { trim1Table.axisY[(5 - (valueOffset - 42))] = int(newValue) * TABLE_LOAD_MULTIPLIER; } //New value is on the Y (TPS) axis of the boost table
//Trim table 2
else if (valueOffset < 84) { tempOffset = valueOffset - 48; trim2Table.values[5 - (tempOffset / 6)][tempOffset % 6] = newValue; } //New value is part of the trim2 map
else if (valueOffset < 90) { tempOffset = valueOffset - 84; trim2Table.axisX[tempOffset] = int(newValue) * TABLE_RPM_MULTIPLIER; } //New value is on the X (RPM) axis of the table. The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
else if (valueOffset < 96) { tempOffset = valueOffset - 90; trim2Table.axisY[(5 - tempOffset)] = int(newValue) * TABLE_LOAD_MULTIPLIER; } //New value is on the Y (Load) axis of the table
//Trim table 3
else if (valueOffset < 132) { tempOffset = valueOffset - 96; trim3Table.values[5 - (tempOffset / 6)][tempOffset % 6] = newValue; } //New value is part of the trim2 map
else if (valueOffset < 138) { tempOffset = valueOffset - 132; trim3Table.axisX[tempOffset] = int(newValue) * TABLE_RPM_MULTIPLIER; } //New value is on the X (RPM) axis of the table. The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
else if (valueOffset < 144) { tempOffset = valueOffset - 138; trim3Table.axisY[(5 - tempOffset)] = int(newValue) * TABLE_LOAD_MULTIPLIER; } //New value is on the Y (Load) axis of the table
//Trim table 4
else if (valueOffset < 180) { tempOffset = valueOffset - 144; trim4Table.values[5 - (tempOffset / 6)][tempOffset % 6] = newValue; } //New value is part of the trim2 map
else if (valueOffset < 186) { tempOffset = valueOffset - 180; trim4Table.axisX[tempOffset] = int(newValue) * TABLE_RPM_MULTIPLIER; } //New value is on the X (RPM) axis of the table. The RPM values sent by TunerStudio are divided by 100, need to multiply it back by 100 to make it correct (TABLE_RPM_MULTIPLIER)
else if (valueOffset < 192) { tempOffset = valueOffset - 186; trim4Table.axisY[(5 - tempOffset)] = int(newValue) * TABLE_LOAD_MULTIPLIER; } //New value is on the Y (Load) axis of the table
break;
case canbusPage:
@ -531,9 +619,19 @@ void receiveValue(int valueOffset, byte newValue)
}
break;
case warmupPage:
pnt_configPage = &configPage11;
//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])
{
*((byte *)pnt_configPage + (byte)valueOffset) = newValue;
}
break;
default:
break;
}
//if(Serial.available() > 16) { command(); }
}
/*
@ -544,22 +642,19 @@ useChar - If true, all values are send as chars, this is for the serial command
*/
void sendPage(bool useChar)
{
void* pnt_configPage;
struct table3D currentTable;
void* pnt_configPage = &configPage1; //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
switch (currentPage)
{
case veMapPage:
{
currentTitleIndex = 0;
currentTable = fuelTable;
break;
}
case veSetPage:
{
// currentTitleIndex = 27;
if (useChar)
{
@ -586,22 +681,18 @@ void sendPage(bool useChar)
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);
// Following loop displays remaining byte values of the page
for (pnt_configPage = (uint16_t *)&configPage1.mapMax + 1; pnt_configPage < (byte *)&configPage1 + page_size; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
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)); }
sendComplete = true;
}
else { pnt_configPage = &configPage1; } //Create a pointer to Page 1 in memory
break;
}
case ignMapPage:
{
currentTitleIndex = 42;// the index to the first char of the third string in pageTitles
currentTable = ignitionTable;
break;
}
case ignSetPage:
{
//currentTitleIndex = 56;
if (useChar)
{
@ -640,7 +731,7 @@ void sendPage(bool useChar)
Serial.print(' ');
}
Serial.println();
for (pnt_configPage = (byte *)&configPage2.dwellCorrectionValues[5] + 1; pnt_configPage < (byte *)&configPage2 + page_size; pnt_configPage = (byte *)pnt_configPage + 1)
for (pnt_configPage = (byte *)&configPage2.dwellCorrectionValues[5] + 1; pnt_configPage < (byte *)&configPage2 + npage_size[ignSetPage]; pnt_configPage = (byte *)pnt_configPage + 1)
{
Serial.println(*((byte *)pnt_configPage));// Displaying remaining byte values of the page
}
@ -648,17 +739,13 @@ void sendPage(bool useChar)
}
else { pnt_configPage = &configPage2; } //Create a pointer to Page 2 in memory
break;
}
case afrMapPage:
{
currentTitleIndex = 71;//Array index to next string
currentTable = afrTable;
break;
}
case afrSetPage:
{
//currentTitleIndex = 91;
if (useChar)
{
@ -695,18 +782,15 @@ 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 + page_size; pnt_configPage = (byte *)pnt_configPage + 1)
for (pnt_configPage = (byte *)&configPage3.airDenRates[8] + 1; pnt_configPage < (byte *)&configPage3 + 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
break;
}
case iacPage:
{
//Old configPage4 STARTED HERE!
//currentTitleIndex = 106;
//To Display Values from Config Page 4
if (useChar)
@ -717,10 +801,10 @@ void sendPage(bool useChar)
byte * currentVar;
switch (y)
{
case 1: currentVar = configPage4.iacBins; break;
case 2: currentVar = configPage4.iacOLPWMVal; break;
case 3: currentVar = configPage4.iacOLStepVal; break;
case 4: currentVar = configPage4.iacCLValues; break;
case 1: currentVar = configPage3.iacBins; break;
case 2: currentVar = configPage3.iacOLPWMVal; break;
case 3: currentVar = configPage3.iacOLStepVal; break;
case 4: currentVar = configPage3.iacCLValues; break;
default: break;
}
for (byte x = 10; x; x--)
@ -735,9 +819,9 @@ void sendPage(bool useChar)
byte * currentVar;
switch (y)
{
case 1: currentVar = configPage4.iacCrankBins; break;
case 2: currentVar = configPage4.iacCrankDuty; break;
case 3: currentVar = configPage4.iacCrankSteps; break;
case 1: currentVar = configPage3.iacCrankBins; break;
case 2: currentVar = configPage3.iacCrankDuty; break;
case 3: currentVar = configPage3.iacCrankSteps; break;
default: break;
}
for (byte x = 4; x; x--)
@ -748,15 +832,13 @@ void sendPage(bool useChar)
Serial.println();
}
// Following loop is for remaining byte value of page
for (pnt_configPage = (byte *)&configPage4.iacCrankBins[3] + 1; pnt_configPage < (byte *)&configPage4 + page_size; pnt_configPage = (byte *)pnt_configPage + 1) { Serial.println(*((byte *)pnt_configPage)); }
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)); }
sendComplete = true;
}
else { pnt_configPage = &configPage4; } //Create a pointer to Page 4 in memory
else { pnt_configPage = &configPage3; } //Create a pointer to Page 4 in memory
break;
}
case boostvvtPage:
{
if(useChar)
{
currentTable = boostTable;
@ -779,9 +861,8 @@ void sendPage(bool useChar)
sendComplete = true;
}
break;
}
case seqFuelPage:
{
if(useChar)
{
currentTable = trim1Table;
@ -842,10 +923,8 @@ void sendPage(bool useChar)
sendComplete = true;
}
break;
}
case canbusPage:
{
//currentTitleIndex = 141;
if (useChar)
{
@ -859,14 +938,22 @@ void sendPage(bool useChar)
}
else { pnt_configPage = &configPage10; } //Create a pointer to Page 10 in memory
break;
}
case warmupPage:
if (useChar)
{
sendComplete = true;
}
else { pnt_configPage = &configPage11; } //Create a pointer to Page 11 in memory
break;
default:
{
Serial.println(F("\nPage has not been implemented yet. Change to another page."));
//Just set default Values to avoid warnings
pnt_configPage = &configPage11;
currentTable = fuelTable;
sendComplete = true;
break;
}
}
if(!sendComplete)
{
@ -936,7 +1023,7 @@ void sendPage(bool useChar)
}
else currentTitleIndex = 0;
}while(currentTitleIndex == 132); //Should never loop unless going to display vvtTable
}
} //use char
else
{
//Need to perform a translation of the values[yaxis][xaxis] into the MS expected format
@ -951,7 +1038,7 @@ void sendPage(bool useChar)
//loop();
Serial.write((byte *)&response, sizeof(response));
}
}
} //is map
else
{
/*if(useChar)
@ -980,6 +1067,126 @@ void sendPage(bool useChar)
} //sendComplete
}
byte getPageValue(byte page, uint16_t valueAddress)
{
void* pnt_configPage = &configPage1; //Default value is for safety only. Will be changed below if needed.
uint16_t tempAddress;
byte returnValue = 0;
switch (page)
{
case veMapPage:
if( valueAddress < 256) { returnValue = fuelTable.values[15 - (valueAddress / 16)][valueAddress % 16]; } //This is slightly non-intuitive, but essentially just flips the table vertically (IE top line becomes the bottom line etc). Columns are unchanged. Every 16 loops, manually call loop() to avoid potential misses
else if(valueAddress < 272) { returnValue = byte(fuelTable.axisX[(valueAddress - 256)] / TABLE_RPM_MULTIPLIER); } //RPM Bins for VE table (Need to be dvidied by 100)
else if (valueAddress < 288) { returnValue = byte(fuelTable.axisY[15 - (valueAddress - 272)] / TABLE_LOAD_MULTIPLIER); } //MAP or TPS bins for VE table
break;
case veSetPage:
pnt_configPage = &configPage1; //Create a pointer to Page 1 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
case ignMapPage:
if( valueAddress < 256) { returnValue = ignitionTable.values[15 - (valueAddress / 16)][valueAddress % 16]; } //This is slightly non-intuitive, but essentially just flips the table vertically (IE top line becomes the bottom line etc). Columns are unchanged. Every 16 loops, manually call loop() to avoid potential misses
else if(valueAddress < 272) { returnValue = byte(ignitionTable.axisX[(valueAddress - 256)] / TABLE_RPM_MULTIPLIER); } //RPM Bins for VE table (Need to be dvidied by 100)
else if (valueAddress < 288) { returnValue = byte(ignitionTable.axisY[15 - (valueAddress - 272)] / TABLE_LOAD_MULTIPLIER); } //MAP or TPS bins for VE table
break;
case ignSetPage:
pnt_configPage = &configPage2; //Create a pointer to Page 2 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
case afrMapPage:
if( valueAddress < 256) { returnValue = afrTable.values[15 - (valueAddress / 16)][valueAddress % 16]; } //This is slightly non-intuitive, but essentially just flips the table vertically (IE top line becomes the bottom line etc). Columns are unchanged. Every 16 loops, manually call loop() to avoid potential misses
else if(valueAddress < 272) { returnValue = byte(afrTable.axisX[(valueAddress - 256)] / TABLE_RPM_MULTIPLIER); } //RPM Bins for VE table (Need to be dvidied by 100)
else if (valueAddress < 288) { returnValue = byte(afrTable.axisY[15 - (valueAddress - 272)] / TABLE_LOAD_MULTIPLIER); } //MAP or TPS bins for VE table
break;
case afrSetPage:
pnt_configPage = &configPage3; //Create a pointer to Page 3 in memory
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
case boostvvtPage:
{
//Need to perform a translation of the values[MAP/TPS][RPM] into the MS expected format
if(valueAddress < 80)
{
//Boost table
if(valueAddress < 64) { returnValue = boostTable.values[7 - (valueAddress / 8)][valueAddress % 8]; }
else if(valueAddress < 72) { returnValue = byte(boostTable.axisX[(valueAddress - 64)] / TABLE_RPM_MULTIPLIER); }
else if(valueAddress < 80) { returnValue = byte(boostTable.axisY[7 - (valueAddress - 72)]); }
}
else
{
tempAddress = valueAddress - 80;
//VVT table
if(tempAddress < 64) { returnValue = vvtTable.values[7 - (tempAddress / 8)][tempAddress % 8]; }
else if(tempAddress < 72) { returnValue = byte(vvtTable.axisX[(tempAddress - 64)] / TABLE_RPM_MULTIPLIER); }
else if(tempAddress < 80) { returnValue = byte(vvtTable.axisY[7 - (tempAddress - 72)]); }
}
}
break;
case seqFuelPage:
{
//Need to perform a translation of the values[MAP/TPS][RPM] into the TS expected format
if(valueAddress < 48)
{
//trim1 table
if(valueAddress < 36) { returnValue = trim1Table.values[5 - (valueAddress / 6)][valueAddress % 6]; }
else if(valueAddress < 42) { returnValue = byte(trim1Table.axisX[(valueAddress - 36)] / TABLE_RPM_MULTIPLIER); }
else if(valueAddress < 48) { returnValue = byte(trim1Table.axisY[5 - (valueAddress - 42)] / TABLE_LOAD_MULTIPLIER); }
}
else if(valueAddress < 96)
{
tempAddress = valueAddress - 48;
//trim2 table
if(tempAddress < 36) { returnValue = trim2Table.values[5 - (tempAddress / 6)][tempAddress % 6]; }
else if(tempAddress < 42) { returnValue = byte(trim2Table.axisX[(tempAddress - 36)] / TABLE_RPM_MULTIPLIER); }
else if(tempAddress < 48) { returnValue = byte(trim2Table.axisY[5 - (tempAddress - 42)] / TABLE_LOAD_MULTIPLIER); }
}
else if(valueAddress < 144)
{
tempAddress = valueAddress - 96;
//trim3 table
if(tempAddress < 36) { returnValue = trim3Table.values[5 - (tempAddress / 6)][tempAddress % 6]; }
else if(tempAddress < 42) { returnValue = byte(trim3Table.axisX[(tempAddress - 36)] / TABLE_RPM_MULTIPLIER); }
else if(tempAddress < 48) { returnValue = byte(trim3Table.axisY[5 - (tempAddress - 42)] / TABLE_LOAD_MULTIPLIER); }
}
else if(valueAddress < 192)
{
tempAddress = valueAddress - 144;
//trim4 table
if(tempAddress < 36) { returnValue = trim4Table.values[5 - (tempAddress / 6)][tempAddress % 6]; }
else if(tempAddress < 42) { returnValue = byte(trim4Table.axisX[(tempAddress - 36)] / TABLE_RPM_MULTIPLIER); }
else if(tempAddress < 48) { returnValue = byte(trim4Table.axisY[5 - (tempAddress - 42)] / TABLE_LOAD_MULTIPLIER); }
}
}
break;
case canbusPage:
pnt_configPage = &configPage10; //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
returnValue = *((byte *)pnt_configPage + valueAddress);
break;
default:
Serial.println(F("\nPage has not been implemented yet. Change to another page."));
//Just set default Values to avoid warnings
pnt_configPage = &configPage11;
break;
}
return returnValue;
}
/*
This function is used to store calibration data sent by Tuner Studio.
*/
@ -1016,6 +1223,11 @@ void receiveCalibration(byte tableID)
break;
default:
OFFSET = 0;
pnt_TargetTable = (byte *)&o2CalibrationTable;
DIVISION_FACTOR = 1;
BYTES_PER_VALUE = 1;
EEPROM_START = EEPROM_CALIBRATION_O2;
break; //Should never get here, but if we do, just fail back to main loop
}

View File

@ -112,7 +112,11 @@ 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 + configPage1.crankingPct; }
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
{
crankingValue = table2D_getValue(&crankingEnrichTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET);
}
return crankingValue;
}
@ -152,12 +156,13 @@ static inline byte correctionAccel()
if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_ACC) )
{
//If it is currently running, check whether it should still be running or whether it's reached it's end time
if( currentLoopTime >= currentStatus.TAEEndTime )
if( micros() >= currentStatus.TAEEndTime )
{
//Time to turn enrichment off
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_ACC);
currentStatus.TAEamount = 0;
accelValue = 100;
currentStatus.tpsDOT = 0;
}
else
{
@ -173,6 +178,7 @@ static inline byte correctionAccel()
if (TPS_change <= 2)
{
accelValue = 100;
currentStatus.tpsDOT = 0;
}
else
{
@ -256,7 +262,7 @@ static inline byte correctionLaunch()
static inline bool correctionDFCO()
{
bool DFCOValue = false;
if ( configPage2.dfcoEnabled == 1 )
if ( configPage1.dfcoEnabled == 1 )
{
if ( bitRead(currentStatus.squirt, BIT_SQUIRT_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 ); }
@ -472,7 +478,7 @@ uint16_t correctionsDwell(uint16_t dwell)
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
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) && (configPage1.nCylinders > 1) ) //No point in running this for 1 cylinder engines
if( ( (configPage2.sparkMode == IGN_MODE_SINGLE) || (configPage2.sparkMode == IGN_MODE_ROTARY) ) && (configPage1.nCylinders > 1) ) //No point in running this for 1 cylinder engines
{
pulsesPerRevolution = (configPage1.nCylinders >> 1);
dwellPerRevolution = dwellPerRevolution * pulsesPerRevolution;

View File

@ -15,6 +15,8 @@ static inline void addToothLogEntry(unsigned long);
static inline uint16_t stdGetRPM();
static inline void setFilter(unsigned long);
static inline int crankingGetRPM(byte);
static inline void doPerToothTiming(uint16_t crankAngle);
void triggerSetup_missingTooth();
void triggerPri_missingTooth();
void triggerSec_missingTooth();
@ -59,6 +61,7 @@ unsigned int triggerSecFilterTime_duration; // The shortest valid time (in uS) p
volatile int triggerToothAngle; //The number of crank degrees that elapse per tooth
bool secondDerivEnabled; //The use of the 2nd derivative calculation is limited to certain decoders. This is set to either true or false in each decoders setup routine
bool decoderIsSequential; //Whether or not the decoder supports sequential operation
bool decoderIsLowRes = false; //Is set true, certain extra calculations are performed for better timing accuracy
byte checkSyncToothCount; //How many teeth must've been seen on this revolution before we try to confirm sync (Useful for missing tooth type decoders)
int16_t ignition1EndTooth = 0;

File diff suppressed because it is too large Load Diff

View File

@ -9,13 +9,25 @@
#define CORE_AVR
#elif defined(CORE_TEENSY)
#define BOARD_NR_GPIO_PINS 34
#elif defined(STM32_MCU_SERIES) || defined(_VARIANT_ARDUINO_STM32_)
#elif defined(STM32_MCU_SERIES) || defined(ARDUINO_ARCH_STM32) || defined(__STM32F1__) || defined(STM32F4) || defined(STM32)
#define CORE_STM32
#define LED_BUILTIN 33
#if defined (STM32F1) || defined(__STM32F1__)
#define BOARD_NR_GPIO_PINS 34
#define LED_BUILTIN 33
#elif defined(ARDUINO_BLACK_F407VE) || defined(STM32F4)
#define BOARD_NR_GPIO_PINS 80
#define LED_BUILTIN PA7
#endif
extern "C" char* sbrk(int incr); //Used to freeRam
inline unsigned char digitalPinToInterrupt(unsigned char Interrupt_pin) { return Interrupt_pin; } //This isn't included in the stm32duino libs (yet)
#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
#if defined(ARDUINO_ARCH_STM32) // STM32GENERIC core
#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
#endif
#else
#error Incorrect board selected. Please select the correct board (Usually Mega 2560) and upload again
#endif
@ -28,6 +40,10 @@
#define MS_IN_MINUTE 60000
#define US_IN_MINUTE 60000000
//Define the load algorithm
#define LOAD_SOURCE_MAP 0
#define LOAD_SOURCE_TPS 1
//Define bit positions within engine virable
#define BIT_ENGINE_RUN 0 // Engine running
#define BIT_ENGINE_CRANK 1 // Engine cranking
@ -67,6 +83,12 @@
#define BIT_SPARK2_UNUSED7 6
#define BIT_SPARK2_UNUSED8 7
#define BIT_TIMER_1HZ 0
#define BIT_TIMER_4HZ 1
#define BIT_TIMER_10HZ 2
#define BIT_TIMER_15HZ 3
#define BIT_TIMER_30HZ 4
#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
@ -82,6 +104,14 @@
#define IGN_MODE_SINGLE 1
#define IGN_MODE_WASTEDCOP 2
#define IGN_MODE_SEQUENTIAL 3
#define IGN_MODE_ROTARY 4
#define ROTARY_IGN_FC 0
#define ROTARY_IGN_FD 1
#define ROTARY_IGN_RX8 2
#define BOOST_MODE_SIMPLE 0
#define BOOST_MODE_FULL 1
#define SIZE_BYTE 8
#define SIZE_INT 16
@ -99,6 +129,9 @@
#define SERIAL_BUFFER_THRESHOLD 32 // When the serial buffer is filled to greater than this threshold value, the serial processing operations will be performed more urgently in order to avoid it overflowing. Serial buffer is 64 bytes long, so the threshold is set at half this as a reasonable figure
#define FUEL_PUMP_ON() *pump_pin_port |= (pump_pin_mask)
#define FUEL_PUMP_OFF() *pump_pin_port &= ~(pump_pin_mask)
const byte signature = 20;
//const char signature[] = "speeduino";
@ -106,9 +139,9 @@ const char displaySignature[] = "speeduino 201609-dev";
const char TSfirmwareVersion[] = "Speeduino 2016.09";
const byte data_structure_version = 2; //This identifies the data structure when reading / writing.
const byte page_size = 64;
const int npage_size[11] = {0,288,64,288,64,288,64,64,160,192,128};
//const byte page10_size = 128;
//const byte page_size = 64;
const int npage_size[11] = {0,288,128,288,128,288,128,160,192,128,192};
//const byte page11_size = 128;
#define MAP_PAGE_SIZE 288
struct table3D fuelTable; //16x16 fuel map
@ -122,10 +155,12 @@ struct table3D trim3Table; //6x6 Fuel trim 3 map
struct table3D trim4Table; //6x6 Fuel trim 4 map
struct table2D taeTable; //4 bin TPS Acceleration Enrichment map (2D)
struct table2D WUETable; //10 bin Warm Up Enrichment map (2D)
struct table2D crankingEnrichTable; //4 bin cranking Enrichment map (2D)
struct table2D dwellVCorrectionTable; //6 bin dwell voltage correction (2D)
struct table2D injectorVCorrectionTable; //6 bin injector voltage correction (2D)
struct table2D 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)
//These are for the direct port manipulation of the injectors and coils
volatile byte *inj1_pin_port;
@ -152,6 +187,8 @@ volatile byte ign5_pin_mask;
volatile byte *tach_pin_port;
volatile byte tach_pin_mask;
volatile byte *pump_pin_port;
volatile byte pump_pin_mask;
volatile byte *triggerPri_pin_port;
volatile byte triggerPri_pin_mask;
@ -173,6 +210,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)
volatile byte TIMER_mask;
volatile byte LOOP_TIMER;
//The status struct contains the current values for all 'live' variables
//In current version this is 64 bytes
struct statuses {
@ -180,8 +220,9 @@ struct statuses {
uint16_t RPM;
long longRPM;
int mapADC;
int baroADC;
long MAP; //Has to be a long for PID calcs (Boost control)
byte baro; //Barometric pressure is simply the inital MAP reading, taken before the engine is running
byte baro; //Barometric pressure is simply the inital MAP reading, taken before the engine is running. Alternatively, can be taken from an external sensor
byte TPS; //The current TPS reading (0% - 100%)
byte TPSlast; //The previous TPS reading
unsigned long TPS_time; //The time the TPS sample was taken
@ -230,17 +271,18 @@ struct statuses {
volatile unsigned int loopsPerSecond;
boolean launchingSoft; //True when in launch control soft limit mode
boolean launchingHard; //True when in launch control hard limit mode
int freeRAM;
uint16_t freeRAM;
unsigned int clutchEngagedRPM;
bool flatShiftingHard;
volatile byte startRevolutions; //A counter for how many revolutions have been completed since sync was achieved.
byte boostTarget;
volatile uint16_t startRevolutions; //A counter for how many revolutions have been completed since sync was achieved.
uint16_t boostTarget;
byte testOutputs;
bool testActive;
byte boostDuty;
uint16_t boostDuty; //Percentage value * 100 to give 2 points of precision
byte idleLoad; //Either the current steps or current duty cycle for the idle control.
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
//Helpful bitwise operations:
//Useful reference: http://playground.arduino.cc/Code/BitMath
@ -313,7 +355,7 @@ struct config1 {
byte baroCorr : 1;
byte injLayout : 2;
byte perToothIgn : 1;
byte unused2_38h : 1;
byte dfcoEnabled : 1; //Whether or not DFCO is turned on
byte primePulse;
byte dutyLim;
@ -323,7 +365,7 @@ struct config1 {
byte boostMaxDuty;
byte tpsMin;
byte tpsMax;
byte mapMin;
int8_t mapMin; //Must be signed
uint16_t mapMax;
byte fpPrime; //Time (In seconds) that the fuel pump should be primed for on power up
byte stoich;
@ -339,6 +381,8 @@ struct config1 {
byte iacCLmaxDuty;
byte boostMinDuty;
byte unused1_64[63];
#if defined(CORE_AVR)
};
#else
@ -357,7 +401,7 @@ struct config2 {
byte TrigEdge : 1;
byte TrigSpeed : 1;
byte IgInv : 1;
byte oddfire : 1;
byte unused4_5d : 1;
byte TrigPattern : 4;
byte TrigEdgeSec : 1;
@ -372,8 +416,7 @@ struct config2 {
byte dwellCont : 1; //Fixed duty dwell control
byte useDwellLim : 1; //Whether the dwell limiter is off or on
byte sparkMode : 2; //Spark output mode (Eg Wasted spark, single channel or Wasted COP)
byte dfcoEnabled : 1; //Whether or not DFCO is turned on
byte sparkMode : 3; //Spark output mode (Eg Wasted spark, single channel or Wasted COP)
byte triggerFilter : 2; //The mode of trigger filter being used (0=Off, 1=Light (Not currently used), 2=Normal, 3=Aggressive)
byte ignCranklock : 1; //Whether or not the ignition timing during cranking is locked to a CAS pulse. Only currently valid for Basic distributor and 4G63.
@ -402,6 +445,8 @@ struct config2 {
byte ignBypassPin : 6; //Pin the ignition bypass is activated on
byte ignBypassHiLo : 1; //Whether this should be active high or low.
byte unused2_64[63];
#if defined(CORE_AVR)
};
#else
@ -431,7 +476,8 @@ struct config3 {
byte egoRPM; //RPM must be above this for closed loop to function
byte egoTPSMax; //TPS must be below this for closed loop to function
byte vvtPin : 6;
byte unused6_13 : 2;
byte useExtBaro : 1;
byte boostMode : 1; //Simple of full boost contrl
byte boostPin : 6;
byte unused6_14 : 2;
byte voltageCorrectionBins[6]; //X axis bins for voltage correction tables
@ -464,21 +510,11 @@ struct config3 {
byte lnchPullRes : 2;
byte fuelTrimEnabled : 1;
byte flatSEnable : 1;
byte unused60 : 4;
byte baroPin : 4;
byte flatSSoftWin;
byte flatSRetard;
byte flatSArm;
#if defined(CORE_AVR)
};
#else
} __attribute__((__packed__)); //The 32 bit systems require all structs to be fully packed
#endif
//Page 4 of the config mostly deals with idle control
//See ini file for further info (Config Page 7 in the ini)
struct config4 {
byte iacCLValues[10]; //Closed loop target RPM value
byte iacOLStepVal[10]; //Open loop step values for stepper motors
byte iacOLPWMVal[10]; //Open loop duty values for PMWM valves
@ -561,6 +597,31 @@ struct config10 {
} __attribute__((__packed__)); //The 32 bit systems require all structs to be fully packed
#endif
/*
Page 11 - 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 {
byte crankingEnrichBins[4];
byte crankingEnrichValues[4];
byte rotaryType : 2;
byte unused11_8c : 6;
byte rotarySplitValues[8];
byte rotarySplitBins[8];
uint16_t boostSens;
byte boostIntv;
byte unused11_28_192[164];
#if defined(CORE_AVR)
};
#else
} __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
@ -619,6 +680,7 @@ byte pinStepperEnable; //Turning the DRV8825 driver on/off
byte pinLaunch;
byte pinIgnBypass; //The pin used for an ignition bypass (Optional)
byte pinFlex; //Pin with the flex sensor attached
byte pinBaro; //Pin that an external barometric pressure sensor is attached to (If used)
// global variables // from speeduino.ino
extern struct statuses currentStatus; // from speeduino.ino
@ -627,10 +689,12 @@ extern struct table3D ignitionTable; //16x16 ignition map
extern struct table3D afrTable; //16x16 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 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)
extern byte ignitionCount;

View File

@ -40,14 +40,19 @@ struct StepperIdle
#define IDLE_TIMER_DISABLE() FTM2_C0SC &= ~FTM_CSC_CHIE
#elif defined(CORE_STM32)
#if defined(ARDUINO_ARCH_STM32) // STM32GENERIC core
#define IDLE_COUNTER (TIM1)->CNT
#define IDLE_COMPARE (TIM1)->CCR4
//Placeholders only
#define IDLE_COUNTER 0
#define IDLE_COMPARE 0
#define IDLE_TIMER_ENABLE()
#define IDLE_TIMER_DISABLE()
#define IDLE_TIMER_ENABLE() (TIM1)->CCER |= TIM_CCER_CC4E
#define IDLE_TIMER_DISABLE() (TIM1)->CCER &= ~TIM_CCER_CC4E
#else //libmaple core aka STM32DUINO
#define IDLE_COUNTER (TIMER1->regs).gen->CNT
#define IDLE_COMPARE (TIMER1->regs).gen->CCR4
#define IDLE_TIMER_ENABLE() (TIMER1->regs).gen->CCER |= TIMER_CCER_CC4E
#define IDLE_TIMER_DISABLE() (TIMER1->regs).gen->CCER &= ~TIMER_CCER_CC4E
#endif
#endif
struct table2D iacClosedLoopTable;
@ -81,5 +86,8 @@ static inline void enableIdle();
static inline byte isStepperHomed();
static inline byte checkForStepping();
static inline void doStep();
#if defined (CORE_TEENSY) || defined(CORE_STM32)
static inline void idleInterrupt();
#endif
#endif

View File

@ -24,7 +24,7 @@ void initialiseIdle()
#elif defined (CORE_TEENSY)
if( (configPage4.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage4.iacAlgorithm == IAC_ALGORITHM_PWM_CL) )
if( (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_OL) || (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_CL) )
{
//FlexTimer 2 is used for idle
FTM2_MODE |= FTM_MODE_WPDIS; // Write Protection Disable
@ -78,19 +78,20 @@ void initialiseIdle()
NVIC_ENABLE_IRQ(IRQ_FTM2);
}
#elif defined(MCU_STM32F103RB)
#elif defined(CORE_STM32)
Timer1.attachInterrupt(4, idleInterrupt);
Timer1.resume();
#endif
//Initialising comprises of setting the 2D tables with the relevant values from the config pages
switch(configPage4.iacAlgorithm)
switch(configPage3.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) < configPage4.iacFastTemp)
if ((currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < configPage3.iacFastTemp)
{
digitalWrite(pinIdle1, HIGH);
idleOn = true;
@ -101,20 +102,24 @@ void initialiseIdle()
//Case 2 is PWM open loop
iacPWMTable.xSize = 10;
iacPWMTable.valueSize = SIZE_BYTE;
iacPWMTable.values = configPage4.iacOLPWMVal;
iacPWMTable.axisX = configPage4.iacBins;
iacPWMTable.values = configPage3.iacOLPWMVal;
iacPWMTable.axisX = configPage3.iacBins;
iacCrankDutyTable.xSize = 4;
iacCrankDutyTable.valueSize = SIZE_BYTE;
iacCrankDutyTable.values = configPage4.iacCrankDuty;
iacCrankDutyTable.axisX = configPage4.iacCrankBins;
iacCrankDutyTable.values = configPage3.iacCrankDuty;
iacCrankDutyTable.axisX = configPage3.iacCrankBins;
idle_pin_port = portOutputRegister(digitalPinToPort(pinIdle1));
idle_pin_mask = digitalPinToBitMask(pinIdle1);
idle2_pin_port = portOutputRegister(digitalPinToPort(pinIdle2));
idle2_pin_mask = digitalPinToBitMask(pinIdle2);
idle_pwm_max_count = 1000000L / (16 * configPage3.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz
#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
#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
#endif
enableIdle();
break;
@ -122,19 +127,23 @@ void initialiseIdle()
//Case 3 is PWM closed loop
iacClosedLoopTable.xSize = 10;
iacClosedLoopTable.valueSize = SIZE_BYTE;
iacClosedLoopTable.values = configPage4.iacCLValues;
iacClosedLoopTable.axisX = configPage4.iacBins;
iacClosedLoopTable.values = configPage3.iacCLValues;
iacClosedLoopTable.axisX = configPage3.iacBins;
iacCrankDutyTable.xSize = 4;
iacCrankDutyTable.valueSize = SIZE_BYTE;
iacCrankDutyTable.values = configPage4.iacCrankDuty;
iacCrankDutyTable.axisX = configPage4.iacCrankBins;
iacCrankDutyTable.values = configPage3.iacCrankDuty;
iacCrankDutyTable.axisX = configPage3.iacCrankBins;
idle_pin_port = portOutputRegister(digitalPinToPort(pinIdle1));
idle_pin_mask = digitalPinToBitMask(pinIdle1);
idle2_pin_port = portOutputRegister(digitalPinToPort(pinIdle2));
idle2_pin_mask = digitalPinToBitMask(pinIdle2);
idle_pwm_max_count = 1000000L / (16 * configPage3.idleFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz
#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
#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
#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.SetMode(AUTOMATIC); //Turn PID on
@ -146,13 +155,13 @@ void initialiseIdle()
//Case 2 is Stepper open loop
iacStepTable.xSize = 10;
iacStepTable.valueSize = SIZE_BYTE;
iacStepTable.values = configPage4.iacOLStepVal;
iacStepTable.axisX = configPage4.iacBins;
iacStepTable.values = configPage3.iacOLStepVal;
iacStepTable.axisX = configPage3.iacBins;
iacCrankStepsTable.xSize = 4;
iacCrankStepsTable.values = configPage4.iacCrankSteps;
iacCrankStepsTable.axisX = configPage4.iacCrankBins;
iacStepTime = configPage4.iacStepTime * 1000;
iacCrankStepsTable.values = configPage3.iacCrankSteps;
iacCrankStepsTable.axisX = configPage3.iacCrankBins;
iacStepTime = configPage3.iacStepTime * 1000;
completedHomeSteps = 0;
idleStepper.curIdleStep = 0;
@ -163,20 +172,20 @@ void initialiseIdle()
//Case 5 is Stepper closed loop
iacClosedLoopTable.xSize = 10;
iacClosedLoopTable.valueSize = SIZE_BYTE;
iacClosedLoopTable.values = configPage4.iacCLValues;
iacClosedLoopTable.axisX = configPage4.iacBins;
iacClosedLoopTable.values = configPage3.iacCLValues;
iacClosedLoopTable.axisX = configPage3.iacBins;
iacCrankStepsTable.xSize = 4;
iacCrankStepsTable.values = configPage4.iacCrankSteps;
iacCrankStepsTable.axisX = configPage4.iacCrankBins;
iacStepTime = configPage4.iacStepTime * 1000;
iacCrankStepsTable.values = configPage3.iacCrankSteps;
iacCrankStepsTable.axisX = configPage3.iacCrankBins;
iacStepTime = configPage3.iacStepTime * 1000;
completedHomeSteps = 0;
idleCounter = 0;
idleStepper.curIdleStep = 0;
idleStepper.stepperStatus = SOFF;
idlePID.SetOutputLimits(0, (configPage4.iacStepHome * 3)); //Maximum number of steps probably needs its own setting
idlePID.SetOutputLimits(0, (configPage3.iacStepHome * 3)); //Maximum number of steps probably needs its own setting
idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD);
idlePID.SetMode(AUTOMATIC); //Turn PID on
break;
@ -185,21 +194,21 @@ void initialiseIdle()
//Well this just shouldn't happen
break;
}
idleInitComplete = configPage4.iacAlgorithm; //Sets which idle method was initialised
idleInitComplete = configPage3.iacAlgorithm; //Sets which idle method was initialised
currentStatus.idleLoad = 0;
}
void idleControl()
{
if(idleInitComplete != configPage4.iacAlgorithm) { initialiseIdle(); }
if(idleInitComplete != configPage3.iacAlgorithm) { initialiseIdle(); }
switch(configPage4.iacAlgorithm)
switch(configPage3.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) < configPage4.iacFastTemp) //All temps are offset by 40 degrees
if ( (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < configPage3.iacFastTemp) //All temps are offset by 40 degrees
{
digitalWrite(pinIdle1, HIGH);
idleOn = true;
@ -261,7 +270,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 = configPage4.iacStepTime * 1000;
iacStepTime = configPage3.iacStepTime * 1000;
}
doStep();
}
@ -277,7 +286,7 @@ void idleControl()
{
//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 = configPage4.iacStepTime * 1000;
iacStepTime = configPage3.iacStepTime * 1000;
}
idle_cl_target_rpm = table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) * 10; //All temps are offset by 40 degrees
@ -305,7 +314,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 < (configPage4.iacStepHome * 3) ) //Home steps are divided by 3 from TS
if( completedHomeSteps < (configPage3.iacStepHome * 3) ) //Home steps are divided by 3 from TS
{
digitalWrite(pinStepperDir, STEPPER_BACKWARD); //Sets stepper direction to backwards
digitalWrite(pinStepperStep, HIGH);
@ -360,7 +369,7 @@ Performs a step
*/
static inline void doStep()
{
if ( (idleStepper.targetIdleStep <= (idleStepper.curIdleStep - configPage4.iacStepHyster)) || (idleStepper.targetIdleStep >= (idleStepper.curIdleStep + configPage4.iacStepHyster)) ) //Hysteris check
if ( (idleStepper.targetIdleStep <= (idleStepper.curIdleStep - configPage3.iacStepHyster)) || (idleStepper.targetIdleStep >= (idleStepper.curIdleStep + configPage3.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
@ -376,12 +385,12 @@ static inline void doStep()
//This function simply turns off the idle PWM and sets the pin low
static inline void disableIdle()
{
if( (configPage4.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage4.iacAlgorithm == IAC_ALGORITHM_PWM_OL) )
if( (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_OL) )
{
IDLE_TIMER_DISABLE();
digitalWrite(pinIdle1, LOW);
}
else if ( (configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_OL) )
else if ( (configPage3.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage3.iacAlgorithm == IAC_ALGORITHM_STEP_OL) )
{
digitalWrite(pinStepperEnable, HIGH); //Disable the DRV8825
idleStepper.targetIdleStep = idleStepper.curIdleStep; //Don't try to move anymore
@ -392,11 +401,11 @@ static inline void disableIdle()
//Typically this is enabling the PWM interrupt
static inline void enableIdle()
{
if( (configPage4.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage4.iacAlgorithm == IAC_ALGORITHM_PWM_OL) )
if( (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_CL) || (configPage3.iacAlgorithm == IAC_ALGORITHM_PWM_OL) )
{
IDLE_TIMER_ENABLE();
}
else if ( (configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_OL) )
else if ( (configPage3.iacAlgorithm == IAC_ALGORITHM_STEP_CL) || (configPage3.iacAlgorithm == IAC_ALGORITHM_STEP_OL) )
{
}
@ -407,38 +416,37 @@ ISR(TIMER4_COMPC_vect)
#elif defined (CORE_TEENSY) || defined (CORE_STM32)
static inline void idleInterrupt() //Most ARM chips can simply call a function
#endif
#if defined(CORE_AVR) || defined (CORE_TEENSY)
{
if (idle_pwm_state)
{
if (configPage4.iacPWMdir == 0)
if (configPage3.iacPWMdir == 0)
{
//Normal direction
*idle_pin_port &= ~(idle_pin_mask); // Switch pin to low (1 pin mode)
if(configPage4.iacChannels == 1) { *idle2_pin_port |= (idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
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
}
else
{
//Reversed direction
*idle_pin_port |= (idle_pin_mask); // Switch pin high
if(configPage4.iacChannels == 1) { *idle2_pin_port &= ~(idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
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
}
IDLE_COMPARE = IDLE_COUNTER + (idle_pwm_max_count - idle_pwm_cur_value);
idle_pwm_state = false;
}
else
{
if (configPage4.iacPWMdir == 0)
if (configPage3.iacPWMdir == 0)
{
//Normal direction
*idle_pin_port |= (idle_pin_mask); // Switch pin high
if(configPage4.iacChannels == 1) { *idle2_pin_port &= ~(idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
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
}
else
{
//Reversed direction
*idle_pin_port &= ~(idle_pin_mask); // Switch pin to low (1 pin mode)
if(configPage4.iacChannels == 1) { *idle2_pin_port |= (idle2_pin_mask); } //If 2 idle channels are in use, flip idle2 to be the opposite of idle1
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
}
IDLE_COMPARE = IDLE_COUNTER + idle_pwm_target_value;
idle_pwm_cur_value = idle_pwm_target_value;
@ -446,8 +454,3 @@ static inline void idleInterrupt() //Most ARM chips can simply call a function
}
}
#elif defined (CORE_STM32)
{
//No PWM idle for STM32 yet
}
#endif

View File

@ -4,4 +4,14 @@
int fastMap1023toX(int, int);
unsigned long percentage(byte, unsigned long);
#define degreesToUS(degrees) (decoderIsLowRes == true ) ? ((degrees * 166666UL) / currentStatus.RPM) : degrees * (unsigned long)timePerDegree
#define uSToDegrees(time) (((unsigned long)time * currentStatus.RPM) / 166666)
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) ^ ((d) < 0)) ? (((n) - (d)/2)/(d)) : (((n) + (d)/2)/(d)))
//This is a dedicated function that specifically handles the case of mapping 0-1023 values into a 0 to X range
//This is a common case because it means converting from a standard 10-bit analog input to a byte or 10-bit analog into 0-511 (Eg the temperature readings)
#define fastMap1023toX(x, out_max) ( ((unsigned long)x * out_max) >> 10)
//This is a new version that allows for out_min
#define fastMap10Bit(x, out_min, out_max) ( ( ((unsigned long)x * (out_max-out_min)) >> 10 ) + out_min)
#endif

View File

@ -1,7 +1,5 @@
#include "maths.h"
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) ^ ((d) < 0)) ? (((n) - (d)/2)/(d)) : (((n) + (d)/2)/(d)))
//Replace the standard arduino map() function to use the div function instead
int fastMap(unsigned long x, int in_min, int in_max, int out_min, int out_max)
{
@ -14,12 +12,6 @@ int fastMap(unsigned long x, int in_min, int in_max, int out_min, int out_max)
//return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
//This is a dedicated function that specifically handles the case of mapping 0-1023 values into a 0 to X range
//This is a common case because it means converting from a standard 10-bit analog input to a byte or 10-bit analog into 0-511 (Eg the temperature readings)
//int fastMap1023toX(unsigned long x, int in_min, int in_max, int out_min, int out_max)
//removed ununsed variables, in_min and out_min is aways 0, in_max is aways 1023
#define fastMap1023toX(x, out_max) ( ((unsigned long)x * out_max) >> 10)
/*
The following are all fast versions of specific divisions
Ref: http://www.hackersdelight.org/divcMore.pdf

View File

@ -16,6 +16,12 @@ inline void endCoil4Charge();
inline void beginCoil5Charge();
inline void endCoil5Charge();
//The following functions are used specifically for the trailing coil on rotary engines. They are separate as they also control the switching of the trailing select pin
inline void beginTrailingCoilCharge();
inline void endTrailingCoilCharge1();
inline void endTrailingCoilCharge2();
#define openInjector1() *inj1_pin_port |= (inj1_pin_mask); BIT_SET(currentStatus.squirt, BIT_SQUIRT_INJ1)
#define closeInjector1() *inj1_pin_port &= ~(inj1_pin_mask); BIT_CLEAR(currentStatus.squirt, BIT_SQUIRT_INJ1)
#define openInjector2() *inj2_pin_port |= (inj2_pin_mask); BIT_SET(currentStatus.squirt, BIT_SQUIRT_INJ2)

View File

@ -18,12 +18,14 @@ volatile bool tachoAlt = true;
inline void beginCoil5Charge() { digitalWrite(pinCoil5, coilHIGH); TACH_PULSE_LOW(); }
inline void endCoil5Charge() { digitalWrite(pinCoil5, coilLOW); TACH_PULSE_HIGH(); }
inline void beginTrailingCoilCharge() { digitalWrite(pinCoil2, coilHIGH); }
inline void endTrailingCoilCharge1() { digitalWrite(pinCoil2, coilLOW); *ign3_pin_port |= ign3_pin_mask; } //Sets ign3 (Trailing select) high
inline void endTrailingCoilCharge2() { digitalWrite(pinCoil2, coilLOW); *ign3_pin_port &= ~(ign3_pin_mask); } //sets ign3 (Trailing select) low
//As above but for ignition (Wasted COP mode)
void beginCoil1and3Charge() { digitalWrite(pinCoil1, coilHIGH); digitalWrite(pinCoil3, coilHIGH); digitalWrite(pinTachOut, LOW); }
void endCoil1and3Charge() { digitalWrite(pinCoil1, coilLOW); digitalWrite(pinCoil3, coilLOW); }
void beginCoil2and4Charge() { digitalWrite(pinCoil2, coilHIGH); digitalWrite(pinCoil4, coilHIGH); digitalWrite(pinTachOut, LOW); }
void endCoil2and4Charge() { digitalWrite(pinCoil2, coilLOW); digitalWrite(pinCoil4, coilLOW); }
void beginCoil1and3Charge() { digitalWrite(pinCoil1, coilHIGH); digitalWrite(pinCoil3, coilHIGH); TACH_PULSE_LOW(); }
void endCoil1and3Charge() { digitalWrite(pinCoil1, coilLOW); digitalWrite(pinCoil3, coilLOW); TACH_PULSE_HIGH(); }
void beginCoil2and4Charge() { digitalWrite(pinCoil2, coilHIGH); digitalWrite(pinCoil4, coilHIGH); TACH_PULSE_LOW(); }
void endCoil2and4Charge() { digitalWrite(pinCoil2, coilLOW); digitalWrite(pinCoil4, coilLOW); TACH_PULSE_HIGH(); }
void nullCallback() { return; }

View File

@ -162,59 +162,103 @@ See page 136 of the processors datasheet: http://www.atmel.com/Images/doc2549.pd
#define uS_TO_TIMER_COMPARE_SLOW(uS) ((uS * 15) >> 5)
#elif defined(CORE_STM32)
//Placeholders ONLY!
//https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/master/STM32F4/cores/maple/libmaple/timer.h#L51
#define MAX_TIMER_PERIOD 131070 //The longest period of time (in uS) that the timer can permit (IN this case it is 65535 * 2, as each timer tick is 2uS)
#define uS_TO_TIMER_COMPARE(uS) (uS >> 1) //Converts a given number of uS into the required number of timer ticks until that time has passed.
#define uS_TO_TIMER_COMPARE_SLOW(uS) (uS >> 1) //Converts a given number of uS into the required number of timer ticks until that time has passed.
#if defined(ARDUINO_ARCH_STM32) // STM32GENERIC core
#include "HardwareTimer.h"
#define FUEL1_COUNTER (TIM2)->CNT
#define FUEL2_COUNTER (TIM2)->CNT
#define FUEL3_COUNTER (TIM2)->CNT
#define FUEL4_COUNTER (TIM2)->CNT
#define FUEL5_COUNTER (TIM2)->CNT
#define FUEL1_COUNTER (TIMER2->regs).gen->CNT
#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 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 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 FUEL1_COMPARE (TIM2)->CCR1
#define FUEL2_COMPARE (TIM2)->CCR2
#define FUEL3_COMPARE (TIM2)->CCR3
#define FUEL4_COMPARE (TIM2)->CCR4
#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 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 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
//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
//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 IGN1_TIMER_ENABLE() (TIM3)->CCER |= TIM_CCER_CC1E
#define IGN2_TIMER_ENABLE() (TIM3)->CCER |= TIM_CCER_CC2E
#define IGN3_TIMER_ENABLE() (TIM3)->CCER |= TIM_CCER_CC3E
#define IGN4_TIMER_ENABLE() (TIM3)->CCER |= TIM_CCER_CC4E
#define IGN5_TIMER_ENABLE() (TIM1)->CCER |= TIM_CCER_CC1E
#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 FUEL1_TIMER_DISABLE() (TIM2)->CCER &= ~TIM_CCER_CC1E
#define FUEL2_TIMER_DISABLE() (TIM2)->CCER &= ~TIM_CCER_CC2E
#define FUEL3_TIMER_DISABLE() (TIM2)->CCER &= ~TIM_CCER_CC3E
#define FUEL4_TIMER_DISABLE() (TIM2)->CCER &= ~TIM_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 IGN1_TIMER_DISABLE() (TIM3)->CCER &= ~TIM_CCER_CC1E
#define IGN2_TIMER_DISABLE() (TIM3)->CCER &= ~TIM_CCER_CC2E
#define IGN3_TIMER_DISABLE() (TIM3)->CCER &= ~TIM_CCER_CC3E
#define IGN4_TIMER_DISABLE() (TIM3)->CCER &= ~TIM_CCER_CC4E
#define IGN5_TIMER_DISABLE() (TIM1)->CCER &= ~TIM_CCER_CC1E
#else //libmaple core aka STM32DUINO
#define FUEL1_COUNTER (TIMER2->regs).gen->CNT
#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 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 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 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 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
//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 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 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 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
#endif
#endif
void initialiseSchedulers();
@ -360,4 +404,4 @@ static inline unsigned int popQueue(volatile Schedule *queue[])
}
#endif // SCHEDULER_H
#endif // SCHEDULER_H

View File

@ -161,23 +161,40 @@ void initialiseSchedulers()
NVIC_ENABLE_IRQ(IRQ_FTM1);
#elif defined(CORE_STM32)
//see https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/754bc2969921f1ef262bd69e7faca80b19db7524/STM32F1/system/libmaple/include/libmaple/timer.h#L444
(TIMER1->regs).bas->PSC = (CYCLES_PER_MICROSECOND << 1) - 1; //2us resolution
(TIMER2->regs).bas->PSC = (CYCLES_PER_MICROSECOND << 1) - 1; //2us resolution
(TIMER3->regs).bas->PSC = (CYCLES_PER_MICROSECOND << 1) - 1; //2us resolution
// Alternative 2us resolution:
//TimerX.setPrescaleFactor(CYCLES_PER_MICROSECOND * 2U);
#if defined(ARDUINO_ARCH_STM32) // STM32GENERIC core
//see https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/754bc2969921f1ef262bd69e7faca80b19db7524/STM32F1/system/libmaple/include/libmaple/timer.h#L444
Timer1.setPrescaleFactor((HAL_RCC_GetHCLKFreq() * 2U)-1); //2us resolution
Timer2.setPrescaleFactor((HAL_RCC_GetHCLKFreq() * 2U)-1); //2us resolution
Timer3.setPrescaleFactor((HAL_RCC_GetHCLKFreq() * 2U)-1); //2us resolution
Timer2.setMode(1, TIMER_OUTPUT_COMPARE);
Timer2.setMode(2, TIMER_OUTPUT_COMPARE);
Timer2.setMode(3, TIMER_OUTPUT_COMPARE);
Timer2.setMode(4, TIMER_OUTPUT_COMPARE);
Timer2.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
Timer2.setMode(TIMER_CH2, TIMER_OUTPUT_COMPARE);
Timer2.setMode(TIMER_CH3, TIMER_OUTPUT_COMPARE);
Timer2.setMode(TIMER_CH4, TIMER_OUTPUT_COMPARE);
Timer3.setMode(1, TIMER_OUTPUT_COMPARE);
Timer3.setMode(2, TIMER_OUTPUT_COMPARE);
Timer3.setMode(3, TIMER_OUTPUT_COMPARE);
Timer3.setMode(4, TIMER_OUTPUT_COMPARE);
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
Timer3.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
Timer3.setMode(TIMER_CH2, TIMER_OUTPUT_COMPARE);
Timer3.setMode(TIMER_CH3, TIMER_OUTPUT_COMPARE);
Timer3.setMode(TIMER_CH4, TIMER_OUTPUT_COMPARE);
#else //libmaple core aka STM32DUINO
//see https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/754bc2969921f1ef262bd69e7faca80b19db7524/STM32F1/system/libmaple/include/libmaple/timer.h#L444
//(CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz).
//Timer2 to 4 is on APB1, Timer1 on APB2. http://www.st.com/resource/en/datasheet/stm32f103cb.pdf sheet 12
Timer1.setPrescaleFactor((72 * 2U)-1); //2us resolution
Timer2.setPrescaleFactor((36 * 2U)-1); //2us resolution
Timer3.setPrescaleFactor((36 * 2U)-1); //2us resolution
Timer2.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
Timer2.setMode(TIMER_CH2, TIMER_OUTPUT_COMPARE);
Timer2.setMode(TIMER_CH3, TIMER_OUTPUT_COMPARE);
Timer2.setMode(TIMER_CH4, TIMER_OUTPUT_COMPARE);
Timer3.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
Timer3.setMode(TIMER_CH2, TIMER_OUTPUT_COMPARE);
Timer3.setMode(TIMER_CH3, TIMER_OUTPUT_COMPARE);
Timer3.setMode(TIMER_CH4, TIMER_OUTPUT_COMPARE);
#endif
Timer2.attachInterrupt(1, fuelSchedule1Interrupt);
Timer2.attachInterrupt(2, fuelSchedule2Interrupt);
Timer2.attachInterrupt(3, fuelSchedule3Interrupt);
@ -187,7 +204,11 @@ void initialiseSchedulers()
Timer3.attachInterrupt(2, ignitionSchedule2Interrupt);
Timer3.attachInterrupt(3, ignitionSchedule3Interrupt);
Timer3.attachInterrupt(4, ignitionSchedule4Interrupt);
Timer1.attachInterrupt(1, ignitionSchedule5Interrupt);
Timer1.resume();
Timer2.resume();
Timer3.resume();
#endif
fuelSchedule1.Status = OFF;
@ -445,6 +466,14 @@ void setIgnitionSchedule3(void (*startCallback)(), unsigned long timeout, unsign
interrupts();
IGN3_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
ignitionSchedule3.nextStartCompare = IGN3_COUNTER + uS_TO_TIMER_COMPARE(timeout);
ignitionSchedule3.nextEndCompare = ignitionSchedule3.nextStartCompare + uS_TO_TIMER_COMPARE(duration);
ignitionSchedule3.hasNextSchedule = true;
}
}
void setIgnitionSchedule4(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
{
@ -469,6 +498,14 @@ void setIgnitionSchedule4(void (*startCallback)(), unsigned long timeout, unsign
interrupts();
IGN4_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
ignitionSchedule4.nextStartCompare = IGN4_COUNTER + uS_TO_TIMER_COMPARE_SLOW(timeout);
ignitionSchedule4.nextEndCompare = ignitionSchedule4.nextStartCompare + uS_TO_TIMER_COMPARE_SLOW(duration);
ignitionSchedule4.hasNextSchedule = true;
}
}
void setIgnitionSchedule5(void (*startCallback)(), unsigned long timeout, unsigned long duration, void(*endCallback)())
{
@ -653,7 +690,6 @@ static inline void ignitionSchedule1Interrupt() //Most ARM chips can simply call
ignitionSchedule1.StartCallback();
ignitionSchedule1.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
ignitionSchedule1.startTime = micros();
ign1LastRev = currentStatus.startRevolutions;
IGN1_COMPARE = ignitionSchedule1.endCompare;
}
else if (ignitionSchedule1.Status == RUNNING)
@ -677,7 +713,6 @@ static inline void ignitionSchedule2Interrupt() //Most ARM chips can simply call
ignitionSchedule2.StartCallback();
ignitionSchedule2.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
ignitionSchedule2.startTime = micros();
ign2LastRev = currentStatus.startRevolutions;
IGN2_COMPARE = ignitionSchedule2.endCompare; //OCR5B = TCNT5 + (ignitionSchedule2.duration >> 2);
}
else if (ignitionSchedule2.Status == RUNNING)
@ -701,7 +736,6 @@ static inline void ignitionSchedule3Interrupt() //Most ARM chips can simply call
ignitionSchedule3.StartCallback();
ignitionSchedule3.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
ignitionSchedule3.startTime = micros();
ign3LastRev = currentStatus.startRevolutions;
IGN3_COMPARE = ignitionSchedule3.endCompare; //OCR5C = TCNT5 + (ignitionSchedule3.duration >> 2);
}
else if (ignitionSchedule3.Status == RUNNING)
@ -710,7 +744,17 @@ static inline void ignitionSchedule3Interrupt() //Most ARM chips can simply call
ignitionSchedule3.EndCallback();
ignitionSchedule3.schedulesSet = 0;
ignitionCount += 1; //Increment the igintion counter
IGN3_TIMER_DISABLE();
//If there is a next schedule queued up, activate it
if(ignitionSchedule3.hasNextSchedule == true)
{
IGN3_COMPARE = ignitionSchedule3.nextStartCompare;
ignitionSchedule3.endCompare = ignitionSchedule3.nextEndCompare;
ignitionSchedule3.Status = PENDING;
ignitionSchedule3.schedulesSet = 1;
ignitionSchedule3.hasNextSchedule = false;
}
else { IGN3_TIMER_DISABLE(); }
}
}
@ -725,7 +769,6 @@ static inline void ignitionSchedule4Interrupt() //Most ARM chips can simply call
ignitionSchedule4.StartCallback();
ignitionSchedule4.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
ignitionSchedule4.startTime = micros();
ign4LastRev = currentStatus.startRevolutions;
IGN4_COMPARE = ignitionSchedule4.endCompare;
}
else if (ignitionSchedule4.Status == RUNNING)
@ -734,7 +777,17 @@ static inline void ignitionSchedule4Interrupt() //Most ARM chips can simply call
ignitionSchedule4.EndCallback();
ignitionSchedule4.schedulesSet = 0;
ignitionCount += 1; //Increment the igintion counter
IGN4_TIMER_DISABLE();
//If there is a next schedule queued up, activate it
if(ignitionSchedule4.hasNextSchedule == true)
{
IGN4_COMPARE = ignitionSchedule4.nextStartCompare;
ignitionSchedule4.endCompare = ignitionSchedule4.nextEndCompare;
ignitionSchedule4.Status = PENDING;
ignitionSchedule4.schedulesSet = 1;
ignitionSchedule4.hasNextSchedule = false;
}
else { IGN4_TIMER_DISABLE(); }
}
}
@ -749,7 +802,6 @@ static inline void ignitionSchedule5Interrupt() //Most ARM chips can simply call
ignitionSchedule5.StartCallback();
ignitionSchedule5.Status = RUNNING; //Set the status to be in progress (ie The start callback has been called, but not the end callback)
ignitionSchedule5.startTime = micros();
ign5LastRev = currentStatus.startRevolutions;
IGN5_COMPARE = ignitionSchedule5.endCompare;
}
else if (ignitionSchedule5.Status == RUNNING)
@ -787,4 +839,4 @@ void ftm0_isr(void)
else if(interrupt8) { FTM0_C7SC &= ~FTM_CSC_CHF; ignitionSchedule4Interrupt(); }
}
#endif
#endif

View File

@ -12,6 +12,7 @@
#define ADCFILTER_O2 128
#define ADCFILTER_BAT 128
#define ADCFILTER_MAP 20 //This is only used on Instantaneous MAP readings and is intentionally very weak to allow for faster response
#define ADCFILTER_BARO 64
#define BARO_MIN 87
#define BARO_MAX 108

View File

@ -61,10 +61,12 @@ void instanteneousMAPReading()
if( (tempReading >= VALID_MAP_MAX) || (tempReading <= VALID_MAP_MIN) ) { mapErrorCount += 1; }
else { mapErrorCount = 0; }
currentStatus.mapADC = ADC_FILTER(tempReading, ADCFILTER_MAP, currentStatus.mapADC); //Very weak filter
currentStatus.MAP = fastMap1023toX(currentStatus.mapADC, configPage1.mapMax); //Get the current MAP value
//During startup a call is made here to get the baro reading. In this case, we can't apply the ADC filter
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
if(currentStatus.MAP < 0) { currentStatus.MAP = 0; } //Sanity check
}
@ -96,7 +98,10 @@ void readMAP()
//Error check
if( (tempReading < VALID_MAP_MAX) && (tempReading > VALID_MAP_MIN) )
{
MAPrunningValue = MAPrunningValue + (unsigned long)tempReading; //Add the current reading onto the total
currentStatus.mapADC = ADC_FILTER(tempReading, ADCFILTER_MAP, currentStatus.mapADC);
MAPrunningValue += currentStatus.mapADC; //Add the current reading onto the total
//Old method (No filter)
//MAPrunningValue = MAPrunningValue + (unsigned long)tempReading;
MAPcount++;
}
else { mapErrorCount += 1; }
@ -108,7 +113,9 @@ void readMAP()
if( (MAPrunningValue != 0) && (MAPcount != 0) )
{
currentStatus.mapADC = ldiv(MAPrunningValue, MAPcount).quot;
currentStatus.MAP = fastMap1023toX(currentStatus.mapADC, configPage1.mapMax); //Get the current MAP value
currentStatus.MAP = fastMap10Bit(currentStatus.mapADC, configPage1.mapMin, configPage1.mapMax); //Get the current MAP value
//currentStatus.MAP = fastMap1023toX(currentStatus.mapADC, configPage1.mapMax);
if(currentStatus.MAP < 0) { currentStatus.MAP = 0; } //Sanity check
MAPcurRev = currentStatus.startRevolutions; //Reset the current rev count
MAPrunningValue = 0;
MAPcount = 0;
@ -142,7 +149,8 @@ void readMAP()
{
//Reaching here means that the last cylce has completed and the MAP value should be calculated
currentStatus.mapADC = MAPrunningValue;
currentStatus.MAP = fastMap1023toX(currentStatus.mapADC, configPage1.mapMax); //Get the current MAP value
currentStatus.MAP = fastMap10Bit(currentStatus.mapADC, configPage1.mapMin, configPage1.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
}
@ -202,6 +210,25 @@ void readIAT()
currentStatus.IAT = iatCalibrationTable[currentStatus.iatADC] - CALIBRATION_TEMPERATURE_OFFSET;
}
void readBaro()
{
if ( configPage3.useExtBaro != 0 )
{
int tempReading;
// readings
#if defined(ANALOG_ISR_MAP)
tempReading = AnChannel[pinBaro-A0];
#else
tempReading = analogRead(pinBaro);
tempReading = analogRead(pinBaro);
#endif
currentStatus.baroADC = ADC_FILTER(tempReading, ADCFILTER_BARO, currentStatus.baroADC); //Very weak filter
currentStatus.baro = fastMap10Bit(currentStatus.baroADC, configPage1.mapMin, configPage1.mapMax); //Get the current MAP value
}
}
void readO2()
{
unsigned int tempReading;

View File

@ -52,16 +52,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
struct config1 configPage1;
struct config2 configPage2;
struct config3 configPage3;
struct config4 configPage4;
struct config10 configPage10;
struct config11 configPage11;
int req_fuel_uS, inj_opentime_uS;
volatile byte ign1LastRev;
volatile byte ign2LastRev;
volatile byte ign3LastRev;
volatile byte ign4LastRev;
volatile byte ign5LastRev;
bool ignitionOn = false; //The current state of the ignition system
bool fuelOn = false; //The current state of the ignition system
bool fuelPumpOn = false; //The current status of the fuel pump
@ -94,7 +89,7 @@ static byte coilLOW = LOW;
static byte fanHIGH = HIGH; // Used to invert the cooling fan output
static byte fanLOW = LOW; // Used to invert the cooling fan output
volatile int mainLoopCount;
volatile uint16_t mainLoopCount;
byte deltaToothCount = 0; //The last tooth that was used with the deltaV calc
int rpmDelta;
byte ignitionCount;
@ -127,14 +122,15 @@ void (*ign4EndFunction)();
void (*ign5StartFunction)();
void (*ign5EndFunction)();
int timePerDegree;
volatile int timePerDegree;
byte degreesPerLoop; //The number of crank degrees that pass for each mainloop of the program
volatile bool fpPrimed = false; //Tracks whether or not the fuel pump priming has been completed yet
bool initialisationComplete = false; //Tracks whether the setup() functino has run completely
void setup()
{
initialiseTimers();
digitalWrite(LED_BUILTIN, LOW);
//Setup the dummy fuel and ignition tables
//dummyFuelTable(&fuelTable);
//dummyIgnitionTable(&ignitionTable);
@ -148,20 +144,23 @@ void setup()
table3D_setSize(&trim3Table, 6);
table3D_setSize(&trim4Table, 6);
#if defined(CORE_STM32)
EEPROM.init();
#endif
loadConfig();
doUpdates(); //Check if any data items need updating (Occurs ith firmware updates)
Serial.begin(115200);
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //ATmega2561 does not have Serial3
if (configPage10.enable_canbus == 1) { Serial3.begin(115200); }
if (configPage10.enable_canbus == 1) { CANSerial.begin(115200); }
#elif defined(CORE_STM32)
if (configPage10.enable_canbus == 1) { Serial2.begin(115200); }
if (configPage10.enable_canbus == 1) { CANSerial.begin(115200); }
else if (configPage10.enable_canbus == 2)
{
//enable local can interface
}
#elif defined(CORE_TEENSY)
if (configPage10.enable_canbus == 1) { Serial2.begin(115200); }
if (configPage10.enable_canbus == 1) { CANSerial.begin(115200); }
else if (configPage10.enable_canbus == 2)
{
//Teensy onboard CAN not used currently
@ -182,6 +181,10 @@ void setup()
WUETable.xSize = 10;
WUETable.values = configPage1.wueValues;
WUETable.axisX = configPage2.wueBins;
crankingEnrichTable.valueSize = SIZE_BYTE;
crankingEnrichTable.xSize = 4;
crankingEnrichTable.values = configPage11.crankingEnrichValues;
crankingEnrichTable.axisX = configPage11.crankingEnrichBins;
dwellVCorrectionTable.valueSize = SIZE_BYTE;
dwellVCorrectionTable.xSize = 6;
@ -199,12 +202,21 @@ void setup()
IATRetardTable.xSize = 6;
IATRetardTable.values = configPage2.iatRetValues;
IATRetardTable.axisX = configPage2.iatRetBins;
rotarySplitTable.valueSize = SIZE_BYTE;
rotarySplitTable.xSize = 8;
rotarySplitTable.values = configPage11.rotarySplitValues;
rotarySplitTable.axisX = configPage11.rotarySplitBins;
//Setup the calibration tables
loadCalibration();
//Set the pin mappings
if(configPage1.pinMapping > BOARD_NR_GPIO_PINS) { setPinMapping(3); } //First time running? set to v0.4
if(configPage1.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.
}
else { setPinMapping(configPage1.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
@ -225,30 +237,8 @@ void setup()
//Set the tacho output default state
digitalWrite(pinTachOut, HIGH);
//Lookup the current MAP reading for barometric pressure
readMAP();
/*
* The highest sea-level pressure on Earth occurs in Siberia, where the Siberian High often attains a sea-level pressure above 105 kPa;
* with record highs close to 108.5 kPa.
* The lowest measurable sea-level pressure is found at the centers of tropical cyclones and tornadoes, with a record low of 87 kPa;
*/
if ((currentStatus.MAP >= BARO_MIN) && (currentStatus.MAP <= BARO_MAX)) //Check if engine isn't running
{
currentStatus.baro = currentStatus.MAP;
EEPROM.update(EEPROM_LAST_BARO, currentStatus.baro);
}
else
{
//Attempt to use the last known good baro reading from EEPROM
if ((EEPROM.read(EEPROM_LAST_BARO) >= BARO_MIN) && (EEPROM.read(EEPROM_LAST_BARO) <= BARO_MAX)) //Make sure it's not invalid (Possible on first run etc)
{ currentStatus.baro = EEPROM.read(EEPROM_LAST_BARO); } //last baro correction
else { currentStatus.baro = 100; } //Final fall back position.
}
//Perform all initialisations
initialiseSchedulers();
initialiseTimers();
//initialiseDisplay();
initialiseIdle();
initialiseFan();
@ -256,6 +246,35 @@ void setup()
initialiseCorrections();
initialiseADC();
//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 )
{
readBaro();
EEPROM.update(EEPROM_LAST_BARO, currentStatus.baro);
}
else
{
/*
* The highest sea-level pressure on Earth occurs in Siberia, where the Siberian High often attains a sea-level pressure above 105 kPa;
* with record highs close to 108.5 kPa.
* The lowest measurable sea-level pressure is found at the centers of tropical cyclones and tornadoes, with a record low of 87 kPa;
*/
if ((currentStatus.MAP >= BARO_MIN) && (currentStatus.MAP <= BARO_MAX)) //Check if engine isn't running
{
currentStatus.baro = currentStatus.MAP;
EEPROM.update(EEPROM_LAST_BARO, currentStatus.baro);
}
else
{
//Attempt to use the last known good baro reading from EEPROM
if ((EEPROM.read(EEPROM_LAST_BARO) >= BARO_MIN) && (EEPROM.read(EEPROM_LAST_BARO) <= BARO_MAX)) //Make sure it's not invalid (Possible on first run etc)
{ currentStatus.baro = EEPROM.read(EEPROM_LAST_BARO); } //last baro correction
else { currentStatus.baro = 100; } //Final fall back position.
}
}
//Check whether the flex sensor is enabled and if so, attach an interupt for it
if(configPage1.flexEnabled)
{
@ -270,8 +289,6 @@ void setup()
//Begin the main crank trigger interrupt pin setup
//The interrupt numbering is a bit odd - See here for reference: http://arduino.cc/en/Reference/AttachInterrupt
//These assignments are based on the Arduino Mega AND VARY BETWEEN BOARDS. Please confirm the board you are using and update acordingly.
byte triggerInterrupt = 0; // By default, use the first interrupt
byte triggerInterrupt2 = 1;
currentStatus.RPM = 0;
currentStatus.hasSync = false;
currentStatus.runSecs = 0;
@ -279,271 +296,14 @@ 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)
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);
#if defined(CORE_AVR)
switch (pinTrigger) {
//Arduino Mega 2560 mapping
case 2:
triggerInterrupt = 0; break;
case 3:
triggerInterrupt = 1; break;
case 18:
triggerInterrupt = 5; break;
case 19:
triggerInterrupt = 4; break;
case 20:
triggerInterrupt = 3; break;
case 21:
triggerInterrupt = 2; break;
default:
triggerInterrupt = 0; break; //This should NEVER happen
}
#else
triggerInterrupt = pinTrigger;
#endif
#if defined(CORE_AVR)
switch (pinTrigger2) {
//Arduino Mega 2560 mapping
case 2:
triggerInterrupt2 = 0; break;
case 3:
triggerInterrupt2 = 1; break;
case 18:
triggerInterrupt2 = 5; break;
case 19:
triggerInterrupt2 = 4; break;
case 20:
triggerInterrupt2 = 3; break;
case 21:
triggerInterrupt2 = 2; break;
default:
triggerInterrupt2 = 0; break; //This should NEVER happen
}
#else
triggerInterrupt2 = pinTrigger2;
#endif
pinMode(pinTrigger, INPUT);
pinMode(pinTrigger2, INPUT);
pinMode(pinTrigger3, INPUT);
//digitalWrite(pinTrigger, HIGH);
//Set the trigger function based on the decoder in the config
switch (configPage2.TrigPattern)
{
case 0:
//Missing tooth decoder
triggerSetup_missingTooth();
trigger = triggerPri_missingTooth;
triggerSecondary = triggerSec_missingTooth;
getRPM = getRPM_missingTooth;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, RISING); }
else { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, FALLING); }
break;
case 1:
// Basic distributor
triggerSetup_BasicDistributor();
trigger = triggerPri_BasicDistributor;
getRPM = getRPM_BasicDistributor;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
break;
case 2:
triggerSetup_DualWheel();
trigger = triggerPri_DualWheel;
getRPM = getRPM_DualWheel;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, RISING); }
else { attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, FALLING); }
break;
case 3:
triggerSetup_GM7X();
trigger = triggerPri_GM7X;
getRPM = getRPM_GM7X;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
break;
case 4:
triggerSetup_4G63();
trigger = triggerPri_4G63;
getRPM = getRPM_4G63;
getCrankAngle = getCrankAngle_4G63;
triggerSetEndTeeth = triggerSetEndTeeth_4G63;
//These may both need to change, not sure
if(configPage2.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
}
else
{
attachInterrupt(triggerInterrupt, trigger, CHANGE); // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_4G63, FALLING);
}
break;
case 5:
triggerSetup_24X();
trigger = triggerPri_24X;
getRPM = getRPM_24X;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_24X, CHANGE);
break;
case 6:
triggerSetup_Jeep2000();
trigger = triggerPri_Jeep2000;
getRPM = getRPM_Jeep2000;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_Jeep2000, CHANGE);
break;
case 7:
triggerSetup_Audi135();
trigger = triggerPri_Audi135;
getRPM = getRPM_Audi135;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
attachInterrupt(triggerInterrupt2, triggerSec_Audi135, RISING);
break;
case 8:
triggerSetup_HondaD17();
trigger = triggerPri_HondaD17;
getRPM = getRPM_HondaD17;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_HondaD17, CHANGE);
break;
case 9:
triggerSetup_Miata9905();
trigger = triggerPri_Miata9905;
getRPM = getRPM_Miata9905;
getCrankAngle = getCrankAngle_Miata9905;
triggerSetEndTeeth = triggerSetEndTeeth_Miata9905;
//These may both need to change, not sure
if(configPage2.TrigEdge == 0)
{
attachInterrupt(triggerInterrupt, trigger, RISING); // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering)
attachInterrupt(triggerInterrupt2, triggerSec_Miata9905, FALLING); //changed
}
else
{
attachInterrupt(triggerInterrupt, trigger, FALLING); // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_Miata9905, RISING);
}
break;
case 10:
triggerSetup_MazdaAU();
trigger = triggerPri_MazdaAU;
getRPM = getRPM_MazdaAU;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_MazdaAU, FALLING);
break;
case 11:
triggerSetup_non360();
trigger = triggerPri_DualWheel; //Is identical to the dual wheel decoder, so that is used. Same goes for the secondary below
getRPM = getRPM_non360;
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)
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;
case 12:
triggerSetup_Nissan360();
trigger = triggerPri_Nissan360;
getRPM = getRPM_Nissan360;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
attachInterrupt(triggerInterrupt2, triggerSec_Nissan360, CHANGE);
break;
case 13:
triggerSetup_Subaru67();
trigger = triggerPri_Subaru67;
getRPM = getRPM_Subaru67;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
attachInterrupt(triggerInterrupt2, triggerSec_Subaru67, FALLING);
break;
case 14:
triggerSetup_Daihatsu();
trigger = triggerPri_Daihatsu;
getRPM = getRPM_Daihatsu;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
//No secondary input required for this pattern
break;
default:
trigger = triggerPri_missingTooth;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
break;
}
noInterrupts();
initialiseTriggers();
//End crank triger interrupt attachment
req_fuel_uS = req_fuel_uS / engineSquirtsPerCycle; //The req_fuel calculation above gives the total required fuel (At VE 100%) in the full cycle. If we're doing more than 1 squirt per cycle then we need to split the amount accordingly. (Note that in a non-sequential 4-stroke setup you cannot have less than 2 squirts as you cannot determine the stroke to make the single squirt on)
//Initial values for loop times
@ -642,6 +402,12 @@ void setup()
CRANK_ANGLE_MAX_IGN = 720;
}
else if(configPage2.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;
channel4IgnDegrees = 180;
}
}
else
{
@ -829,6 +595,23 @@ void setup()
ign5EndFunction = endCoil5Charge;
break;
case IGN_MODE_ROTARY:
if(configPage11.rotaryType == ROTARY_IGN_FC)
{
ign1StartFunction = beginCoil1Charge;
ign1EndFunction = endCoil1Charge;
ign2StartFunction = beginCoil1Charge;
ign2EndFunction = endCoil1Charge;
ign3StartFunction = beginTrailingCoilCharge;
ign3EndFunction = endTrailingCoilCharge1;
ign4StartFunction = beginTrailingCoilCharge;
ign4EndFunction = endTrailingCoilCharge2;
}
break;
default:
//Wasted spark (Shouldn't ever happen anyway)
ign1StartFunction = beginCoil1Charge;
@ -847,74 +630,55 @@ void setup()
//Begin priming the fuel pump. This is turned off in the low resolution, 1s interrupt in timers.ino
digitalWrite(pinFuelPump, HIGH);
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));
initialisationComplete = true;
digitalWrite(LED_BUILTIN, HIGH);
}
void loop()
{
mainLoopCount++;
LOOP_TIMER = TIMER_mask;
//Check for any requets from serial. Serial operations are checked under 2 scenarios:
// 1) Every 64 loops (64 Is more than fast enough for TunerStudio). This function is equivalent to ((loopCount % 64) == 1) but is considerably faster due to not using the mod or division operations
// 2) If the amount of data in the serial buffer is greater than a set threhold (See globals.h). This is to avoid serial buffer overflow when large amounts of data is being sent
//if ( (BIT_CHECK(TIMER_mask, BIT_TIMER_15HZ)) || (Serial.available() > SERIAL_BUFFER_THRESHOLD) )
//if ( (timer15Hz == true) )
if ( ((mainLoopCount & 31) == 1) or (Serial.available() > SERIAL_BUFFER_THRESHOLD) )
{
if (Serial.available() > 0)
{
command();
}
if (Serial.available() > 0) { command(); }
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //ATmega2561 does not have Serial3
//if serial3 interface is enabled then check for serial3 requests.
if (configPage10.enable_canbus == 1)
{
if ( ((mainLoopCount & 31) == 1) or (CANSerial.available() > SERIAL_BUFFER_THRESHOLD) )
{
if (CANSerial.available() > 0)
{
canCommand();
}
}
}
{
if ( (BIT_CHECK(LOOP_TIMER, BIT_TIMER_15HZ)) || (CANSerial.available() > SERIAL_BUFFER_THRESHOLD) )
{
if (CANSerial.available() > 0) { canCommand(); }
}
}
#elif defined(CORE_STM32)
#elif defined(CORE_TEENSY) || defined(CORE_STM32)
//if can or secondary serial interface is enabled then check for requests.
if (configPage10.enable_canbus == 1) //secondary serial interface enabled
{
if ( ((mainLoopCount & 31) == 1) or (Serial2.available() > SERIAL_BUFFER_THRESHOLD) )
{
if (Serial2.available() > 0)
{
canCommand();
}
}
}
{
if ( (BIT_CHECK(LOOP_TIMER, BIT_TIMER_15HZ)) || (CANSerial.available() > SERIAL_BUFFER_THRESHOLD) )
{
if (CANSerial.available() > 0) { canCommand(); }
}
}
else if (configPage10.enable_canbus == 2) // can module enabled
{
//check local can module
}
#elif defined(CORE_TEENSY)
//if can or secondary serial interface is enabled then check for requests.
if (configPage10.enable_canbus == 1) //secondary serial interface enabled
{
if ( ((mainLoopCount & 31) == 1) or (Serial2.available() > SERIAL_BUFFER_THRESHOLD) )
{
if (Serial2.available() > 0)
{
canCommand();
}
}
}
else if (configPage10.enable_canbus == 2) // can module enabled
{
//check local can module
// if ( ((mainLoopCount & 31) == 1) or (CANbus0.available())
// if ( (BIT_CHECK(LOOP_TIMER, BIT_TIMER_15HZ)) or (CANbus0.available())
// {
// CANbus0.read(rx_msg);
// }
@ -930,7 +694,8 @@ void loop()
if ( (timeToLastTooth < MAX_STALL_TIME) || (toothLastToothTime > currentLoopTime) ) //Check how long ago the last tooth was seen compared to now. If it was more than half a second ago then the engine is probably stopped. toothLastToothTime can be greater than currentLoopTime if a pulse occurs between getting the lastest time and doing the comparison
{
currentStatus.RPM = currentStatus.longRPM = getRPM(); //Long RPM is included here
if(fuelPumpOn == false) { digitalWrite(pinFuelPump, HIGH); fuelPumpOn = true; } //Check if the fuel pump is on and turn it on if it isn't.
FUEL_PUMP_ON();
fuelPumpOn = true; //Not sure if this is needed.
}
else
{
@ -939,21 +704,30 @@ void loop()
currentStatus.PW1 = 0;
currentStatus.VE = 0;
toothLastToothTime = 0;
toothLastSecToothTime = 0;
//toothLastMinusOneToothTime = 0;
currentStatus.hasSync = false;
currentStatus.runSecs = 0; //Reset the counter for number of seconds running.
secCounter = 0; //Reset our seconds counter.
currentStatus.startRevolutions = 0;
toothSystemCount = 0;
secondaryToothCount = 0;
MAPcurRev = 0;
MAPcount = 0;
currentStatus.rpmDOT = 0;
ignitionOn = false;
fuelOn = false;
if (fpPrimed) { digitalWrite(pinFuelPump, LOW); } //Turn off the fuel pump, but only if the priming is complete
fuelPumpOn = false;
if (fpPrimed == true) { digitalWrite(pinFuelPump, LOW); fuelPumpOn = false; } //Turn off the fuel pump, but only if the priming is complete
disableIdle(); //Turn off the idle PWM
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_CRANK); //Clear cranking bit (Can otherwise get stuck 'on' even with 0 rpm)
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_WARMUP); //Same as above except for WUE
//This is a safety check. If for some reason the interrupts have got screwed up (Leading to 0rpm), this resets them.
//It can possibly be run much less frequently.
initialiseTriggers();
VVT_PIN_LOW();
DISABLE_VVT_TIMER();
boostDisable();
}
//Uncomment the following for testing
@ -966,8 +740,9 @@ void loop()
//-----------------------------------------------------------------------------------------------------
readMAP();
if ((mainLoopCount & 31) == 1) //Every 32 loops
if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_15HZ)) //Every 32 loops
{
BIT_CLEAR(TIMER_mask, BIT_TIMER_15HZ);
readTPS(); //TPS reading to be performed every 32 loops (any faster and it can upset the TPSdot sampling time)
//Check for launching/flat shift (clutch) can be done around here too
@ -1010,18 +785,29 @@ void loop()
//And check whether the tooth log buffer is ready
if(toothHistoryIndex > TOOTH_LOG_SIZE) { BIT_SET(currentStatus.squirt, BIT_SQUIRT_TOOTHLOG1READY); }
}
if( (mainLoopCount & 63) == 1) //Every 64 loops
if(BIT_CHECK(LOOP_TIMER, BIT_TIMER_30HZ)) //30 hertz
{
boostControl(); //Most boost tends to run at about 30Hz, so placing it here ensures a new target time is fetched frequently enough
//Nothing here currently
BIT_CLEAR(TIMER_mask, BIT_TIMER_30HZ);
//Most boost tends to run at about 30Hz, so placing it here ensures a new target time is fetched frequently enough
//currentStatus.RPM = 3000;
boostControl();
}
//The IAT and CLT readings can be done less frequently. This still runs about 4 times per second
if ((mainLoopCount & 255) == 1) //Every 256 loops
//The IAT and CLT readings can be done less frequently (4 times per second)
if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_4HZ))
{
BIT_CLEAR(TIMER_mask, BIT_TIMER_4HZ);
readCLT();
readIAT();
readO2();
readBat();
if(eepromWritesPending == true) { writeAllConfig(); } //Check for any outstanding EEPROM writes.
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //ATmega2561 does not have Serial3
//if Can interface is enabled then check for serial3 requests.
if (configPage10.enable_canbus == 1) // megas only support can via secondary serial
@ -1077,15 +863,21 @@ void loop()
vvtControl();
idleControl(); //Perform any idle related actions. Even at higher frequencies, running 4x per second is sufficient.
}
if(configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_OL || configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_CL) { idleControl(); } //Run idlecontrol every loop for stepper idle.
if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_1HZ)) //Once per second)
{
BIT_CLEAR(TIMER_mask, BIT_TIMER_1HZ);
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.
//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 >= configPage2.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 > ((unsigned int)configPage2.crankRPM * 100)) //Crank RPM stored in byte as RPM / 100
if(currentStatus.RPM > currentStatus.crankRPM) //Crank RPM stored in byte as RPM / 100
{
BIT_SET(currentStatus.engine, BIT_ENGINE_RUN); //Sets the engine running bit
//Only need to do anything if we're transitioning from cranking to running
@ -1109,7 +901,7 @@ void loop()
//Calculate an injector pulsewidth from the VE
currentStatus.corrections = correctionsFuel();
lastAdvance = currentStatus.advance; //Store the previous advance value
if (configPage1.algorithm == 0) //Check which fuelling algorithm is being used
if (configPage1.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
@ -1133,9 +925,9 @@ void loop()
int injector5StartAngle = 0; //For 5 cylinder testing
int ignition1StartAngle = 0;
int ignition2StartAngle = 0;
int ignition3StartAngle = 0; //Currently used for 3 cylinder only
int ignition4StartAngle = 0; //Not used until sequential or 4+ cylinders support gets written
int ignition5StartAngle = 0; //Not used until sequential or 4+ cylinders support gets written
int ignition3StartAngle = 0;
int ignition4StartAngle = 0;
int ignition5StartAngle = 0;
//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;
@ -1204,6 +996,7 @@ void loop()
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
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)
@ -1212,25 +1005,33 @@ void loop()
case 2:
injector2StartAngle = (configPage1.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 ));
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
if(injector2StartAngle < 0) {injector2StartAngle += CRANK_ANGLE_MAX_INJ;}
injector3StartAngle = (configPage1.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 ));
if(injector2StartAngle > CRANK_ANGLE_MAX_INJ) {injector2StartAngle -= CRANK_ANGLE_MAX_INJ;}
if(injector2StartAngle < 0) {injector2StartAngle += CRANK_ANGLE_MAX_INJ;}
if(configPage1.injLayout == INJ_SEQUENTIAL)
{
injector3StartAngle = (configPage1.inj3Ang + channel3InjDegrees - ( PWdivTimerPerDegree ));
if(injector3StartAngle > CRANK_ANGLE_MAX_INJ) {injector3StartAngle -= CRANK_ANGLE_MAX_INJ;}
if(injector3StartAngle < 0) {injector3StartAngle += CRANK_ANGLE_MAX_INJ;}
injector4StartAngle = (configPage1.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)
{
@ -1290,7 +1091,7 @@ void loop()
else { currentStatus.dwell = (configPage2.dwellRun * 100); }
currentStatus.dwell = correctionsDwell(currentStatus.dwell);
int dwellAngle = (div(currentStatus.dwell, timePerDegree).quot ); //Convert the dwell time to dwell angle based on the current engine speed
int dwellAngle = uSToDegrees(currentStatus.dwell); //Convert the dwell time to dwell angle based on the current engine speed
//Calculate start angle for each channel
//1 cylinder (Everyone gets this)
@ -1333,6 +1134,26 @@ void loop()
ignition4StartAngle = ignition4EndAngle - dwellAngle;
if(ignition4StartAngle > CRANK_ANGLE_MAX_IGN) {ignition4StartAngle -= CRANK_ANGLE_MAX_IGN;}
}
else if(configPage2.sparkMode == IGN_MODE_ROTARY)
{
if(configPage11.rotaryType == ROTARY_IGN_FC)
{
byte splitDegrees = 0;
if (configPage1.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
ignition3EndAngle = ignition1EndAngle + splitDegrees;
ignition3StartAngle = ignition3EndAngle - dwellAngle;
if(ignition3StartAngle > CRANK_ANGLE_MAX_IGN) {ignition3StartAngle -= CRANK_ANGLE_MAX_IGN;}
if(ignition3StartAngle < 0) {ignition3StartAngle += CRANK_ANGLE_MAX_IGN;}
ignition4EndAngle = ignition2EndAngle + splitDegrees;
ignition4StartAngle = ignition4EndAngle - dwellAngle;
if(ignition4StartAngle > CRANK_ANGLE_MAX_IGN) {ignition4StartAngle -= CRANK_ANGLE_MAX_IGN;}
if(ignition4StartAngle < 0) {ignition4StartAngle += CRANK_ANGLE_MAX_IGN;}
}
}
break;
//5 cylinders
case 5:
@ -1494,7 +1315,7 @@ void loop()
//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)) { fixedCrankingOverride = currentStatus.dwell * 2; }
if ( configPage2.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) { 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:
@ -1507,7 +1328,6 @@ void loop()
crankAngle = getCrankAngle(timePerDegree); //Refresh with the latest crank angle
if (crankAngle > CRANK_ANGLE_MAX_IGN ) { crankAngle -= 360; }
//if (ignition1StartAngle <= crankAngle && ignition1.schedulesSet == 0) { ignition1StartAngle += CRANK_ANGLE_MAX_IGN; }
if (ignition1StartAngle > crankAngle)
{
/*
@ -1518,7 +1338,8 @@ void loop()
unsigned long timeout = (unsigned long)(ignition1StartAngle - crankAngle) * 282UL;
*/
setIgnitionSchedule1(ign1StartFunction,
((unsigned long)(ignition1StartAngle - crankAngle) * (unsigned long)timePerDegree), //(timeout/10),
//((unsigned long)(ignition1StartAngle - crankAngle) * (unsigned long)timePerDegree),
degreesToUS((ignition1StartAngle - crankAngle)),
currentStatus.dwell + fixedCrankingOverride, //((unsigned long)((unsigned long)currentStatus.dwell* currentStatus.RPM) / newRPM) + fixedCrankingOverride,
ign1EndFunction
);
@ -1528,11 +1349,9 @@ void loop()
if( tempCrankAngle < 0) { tempCrankAngle += CRANK_ANGLE_MAX_IGN; }
tempStartAngle = ignition2StartAngle - channel2IgnDegrees;
if ( tempStartAngle < 0) { tempStartAngle += CRANK_ANGLE_MAX_IGN; }
//if ( (tempStartAngle > tempCrankAngle) && ign2LastRev != startRevolutions)
//if ( ign2LastRev != startRevolutions )
{
unsigned long ignition2StartTime = 0;
if(tempStartAngle > tempCrankAngle) { ignition2StartTime = ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree); }
if(tempStartAngle > tempCrankAngle) { ignition2StartTime = degreesToUS((tempStartAngle - tempCrankAngle)); }
//else if (tempStartAngle < tempCrankAngle) { ignition2StartTime = ((long)(360 - tempCrankAngle + tempStartAngle) * (long)timePerDegree); }
else { ignition2StartTime = 0; }
@ -1552,7 +1371,7 @@ void loop()
//if (tempStartAngle > tempCrankAngle)
{
long ignition3StartTime = 0;
if(tempStartAngle > tempCrankAngle) { ignition3StartTime = ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree); }
if(tempStartAngle > tempCrankAngle) { ignition3StartTime = degreesToUS((tempStartAngle - tempCrankAngle)); }
//else if (tempStartAngle < tempCrankAngle) { ignition4StartTime = ((long)(360 - tempCrankAngle + tempStartAngle) * (long)timePerDegree); }
else { ignition3StartTime = 0; }
@ -1573,7 +1392,7 @@ void loop()
{
long ignition4StartTime = 0;
if(tempStartAngle > tempCrankAngle) { ignition4StartTime = ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree); }
if(tempStartAngle > tempCrankAngle) { ignition4StartTime = degreesToUS((tempStartAngle - tempCrankAngle)); }
//else if (tempStartAngle < tempCrankAngle) { ignition4StartTime = ((long)(360 - tempCrankAngle + tempStartAngle) * (long)timePerDegree); }
else { ignition4StartTime = 0; }
@ -1594,7 +1413,7 @@ void loop()
{
long ignition5StartTime = 0;
if(tempStartAngle > tempCrankAngle) { ignition5StartTime = ((unsigned long)(tempStartAngle - tempCrankAngle) * (unsigned long)timePerDegree); }
if(tempStartAngle > tempCrankAngle) { ignition5StartTime = degreesToUS((tempStartAngle - tempCrankAngle)); }
//else if (tempStartAngle < tempCrankAngle) { ignition4StartTime = ((long)(360 - tempCrankAngle + tempStartAngle) * (long)timePerDegree); }
else { ignition5StartTime = 0; }

View File

@ -31,7 +31,7 @@
#define FastCRC_tables
#include "inttypes.h"
#if defined(__AVR__) || defined(STM32_MCU_SERIES) || defined(_VARIANT_ARDUINO_STM32_)
#if defined(__AVR__) || defined(STM32_MCU_SERIES) || defined(ARDUINO_ARCH_STM32) || defined(_VARIANT_ARDUINO_STM32_)
#include <avr/pgmspace.h>
#else
#include <pgmspace.h>

View File

@ -302,9 +302,9 @@ void integerPID::SetSampleTime(int NewSampleTime)
if (NewSampleTime > 0)
{
unsigned long ratioX1000 = (unsigned long)(NewSampleTime * 1000) / (unsigned long)SampleTime;
ki = (ki * ratioX1000) / 1000;
ki = ((unsigned long)ki * ratioX1000) / 1000;
//kd /= ratio;
kd = (kd * 1000) / ratioX1000;
kd = ((unsigned long)kd * 1000) / ratioX1000;
SampleTime = (unsigned long)NewSampleTime;
}
}
@ -387,3 +387,175 @@ byte integerPID::GetKi(){ return dispKi;}
byte integerPID::GetKd(){ return dispKd;}
int integerPID::GetMode(){ return inAuto ? AUTOMATIC : MANUAL;}
int integerPID::GetDirection(){ return controllerDirection;}
//************************************************************************************************************************
#define limitMultiplier 100 //How much outMin and OutMax must be multiplied by to get them in the same scale as the output
/*Constructor (...)*********************************************************
* The parameters specified here are those for for which we can't set up
* reliable defaults, so we need to have the user set them.
***************************************************************************/
integerPID_ideal::integerPID_ideal(long* Input, uint16_t* Output, uint16_t* Setpoint, uint16_t* Sensitivity, byte* SampleTime,
byte Kp, byte Ki, byte Kd, byte ControllerDirection)
{
myOutput = Output;
myInput = (long*)Input;
mySetpoint = Setpoint;
mySensitivity = Sensitivity;
mySampleTime = SampleTime;
integerPID_ideal::SetOutputLimits(20, 80); //default output limits
integerPID_ideal::SetControllerDirection(ControllerDirection);
integerPID_ideal::SetTunings(Kp, Ki, Kd);
lastTime = millis()- *mySampleTime;
lastError = 0;
}
/* Compute() **********************************************************************
* This, as they say, is where the magic happens. this function should be called
* every time "void loop()" executes. the function will decide for itself whether a new
* pid Output needs to be computed. returns true when the output is computed,
* false when nothing has been done.
**********************************************************************************/
bool integerPID_ideal::Compute()
{
unsigned long now = millis();
//SampleTime = (now - lastTime);
unsigned long timeChange = (now - lastTime);
if(timeChange >= *mySampleTime)
{
/*Compute all the working error variables*/
uint16_t sensitivity = 10001 - (*mySensitivity * 2);
long unitless_setpoint = (((long)*mySetpoint - 0) * 10000L) / (sensitivity - 0);
long unitless_input = (((long)*myInput - 0) * 10000L) / (sensitivity - 0);
long error = unitless_setpoint - unitless_input;
ITerm += error;
uint16_t bias = 50; //Base target DC%
long output = 0;
if(ki != 0)
{
output = ((outMax - bias) * limitMultiplier * 100) / (long)ki;
if (output < 0) { output = 0; }
}
if (ITerm > output) { ITerm = output; }
if(ki != 0)
{
output = ((bias - outMin) * limitMultiplier * 100) / (long)ki;
if (output < 0) { output = 0; }
}
else { output = 0; }
if (ITerm < -output) { ITerm = -output; }
/*Compute PID Output*/
output = (kp * error) + (ki * ITerm) + (kd * (error - lastError));
output = (bias * limitMultiplier) + (output / 10); //output is % multipled by 1000. To get % with 2 decimal places, divide it by 10. Likewise, bias is % in whole numbers. Multiply it by 100 to get it with 2 places.
if(output > (outMax * limitMultiplier)) { output = (outMax * limitMultiplier); }
if(output < (outMin * limitMultiplier)) { output = (outMin * limitMultiplier); }
*myOutput = output;
/*Remember some variables for next time*/
lastTime = now;
lastError = error;
return true;
}
else return false;
}
/* SetTunings(...)*************************************************************
* This function allows the controller's dynamic performance to be adjusted.
* it's called automatically from the constructor, but tunings can also
* be adjusted on the fly during normal operation
******************************************************************************/
void integerPID_ideal::SetTunings(byte Kp, byte Ki, byte Kd)
{
if (Kp<0 || Ki<0 || Kd<0) return;
if ( dispKp == Kp && dispKi == Ki && dispKd == Kd ) return; //Only do anything if one of the values has changed
dispKp = Kp; dispKi = Ki; dispKd = Kd;
kp = Kp;
ki = Ki;
kd = Kd;
if(controllerDirection == REVERSE)
{
kp = (0 - kp);
ki = (0 - ki);
kd = (0 - kd);
}
}
/* SetOutputLimits(...)****************************************************
* This function will be used far more often than SetInputLimits. while
* the input to the controller will generally be in the 0-1023 range (which is
* the default already,) the output will be a little different. maybe they'll
* be doing a time window and will need 0-8000 or something. or maybe they'll
* want to clamp it from 0-125. who knows. at any rate, that can all be done
* here.
**************************************************************************/
void integerPID_ideal::SetOutputLimits(long Min, long Max)
{
if(Min < Max)
{
outMin = Min;
outMax = Max;
}
/*
long outMax_resized = outMax * limitMultiplier;
long outMin_resized = outMin * limitMultiplier;
if(*myOutput > outMax_resized) { *myOutput = outMax_resized; }
else if(*myOutput < outMin_resized) { *myOutput = outMin_resized; }
if(ITerm > outMax_resized) ITerm = outMax_resized;
else if(ITerm < outMin_resized) ITerm = outMin_resized;
*/
}
/* Initialize()****************************************************************
* does all the things that need to happen to ensure a bumpless transfer
* from manual to automatic mode.
******************************************************************************/
void integerPID_ideal::Initialize()
{
ITerm = 0;
lastInput = *myInput;
lastError = 0;
}
/* SetControllerDirection(...)*************************************************
* The PID will either be connected to a DIRECT acting process (+Output leads
* to +Input) or a REVERSE acting process(+Output leads to -Input.) we need to
* know which one, because otherwise we may increase the output when we should
* be decreasing. This is called from the constructor.
******************************************************************************/
void integerPID_ideal::SetControllerDirection(byte Direction)
{
if(Direction != controllerDirection)
{
kp = (0 - kp);
ki = (0 - ki);
kd = (0 - kd);
}
controllerDirection = Direction;
}
/* Status Funcions*************************************************************
* Just because you set the Kp=-1 doesn't mean it actually happened. these
* functions query the internal state of the PID. they're here for display
* purposes. this are the functions the PID Front-end uses for example
******************************************************************************/
byte integerPID_ideal::GetKp(){ return dispKp; }
byte integerPID_ideal::GetKi(){ return dispKi;}
byte integerPID_ideal::GetKd(){ return dispKd;}
int integerPID_ideal::GetDirection(){ return controllerDirection;}

View File

@ -15,9 +15,9 @@ class PID
#define REVERSE 1
//commonly used functions **************************************************************************
PID(long*, long*, long*, // * constructor. links the PID to the Input, Output, and
PID(long*, long*, long*, // * constructor. links the PID to the Input, Output, and
byte, byte, byte, byte); // Setpoint. Initial tuning parameters are also set here
void SetMode(int Mode); // * sets PID to either Manual (0) or Auto (non-0)
bool Compute(); // * performs the PID calculation. it should be
@ -28,47 +28,47 @@ class PID
void SetOutputLimits(long, long); //clamps the output to a specific range. 0-255 by default, but
//it's likely the user will want to change this depending on
//the application
//available but not commonly used functions ********************************************************
void SetTunings(byte, byte, // * While most users will set the tunings once in the
void SetTunings(byte, byte, // * While most users will set the tunings once in the
byte); // constructor, this function gives the user the option
// of changing tunings during runtime for Adaptive control
void SetControllerDirection(byte); // * Sets the Direction, or "Action" of the controller. DIRECT
// means the output will increase when error is positive. REVERSE
// means the opposite. it's very unlikely that this will be needed
// once it is set in the constructor.
void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which
void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which
// the PID calculation is performed. default is 100
//Display functions ****************************************************************
byte GetKp(); // These functions query the pid for interal values.
byte GetKi(); // they were created mainly for the pid front-end,
byte GetKd(); // where it's important to know what is actually
byte GetKd(); // where it's important to know what is actually
int GetMode(); // inside the PID.
int GetDirection(); //
private:
void Initialize();
byte dispKp; // * we'll hold on to the tuning parameters in user-entered
byte dispKp; // * we'll hold on to the tuning parameters in user-entered
byte dispKi; // format for display purposes
byte dispKd; //
byte kp; // * (P)roportional Tuning Parameter
byte ki; // * (I)ntegral Tuning Parameter
byte kd; // * (D)erivative Tuning Parameter
byte ki; // * (I)ntegral Tuning Parameter
byte kd; // * (D)erivative Tuning Parameter
int controllerDirection;
long *myInput; // * Pointers to the Input, Output, and Setpoint variables
long *myOutput; // This creates a hard link between the variables and the
long *myOutput; // This creates a hard link between the variables and the
long *mySetpoint; // PID, freeing the user from having to constantly tell us
// what these values are. with pointers we'll just know.
unsigned long lastTime;
long ITerm, lastInput;
@ -90,9 +90,9 @@ class integerPID
#define REVERSE 1
//commonly used functions **************************************************************************
integerPID(long*, long*, long*, // * constructor. links the PID to the Input, Output, and
integerPID(long*, long*, long*, // * constructor. links the PID to the Input, Output, and
byte, byte, byte, byte); // Setpoint. Initial tuning parameters are also set here
void SetMode(int Mode); // * sets PID to either Manual (0) or Auto (non-0)
bool Compute(); // * performs the PID calculation. it should be
@ -103,47 +103,47 @@ class integerPID
void SetOutputLimits(long, long); //clamps the output to a specific range. 0-255 by default, but
//it's likely the user will want to change this depending on
//the application
//available but not commonly used functions ********************************************************
void SetTunings(byte, byte, // * While most users will set the tunings once in the
void SetTunings(byte, byte, // * While most users will set the tunings once in the
byte); // constructor, this function gives the user the option
// of changing tunings during runtime for Adaptive control
void SetControllerDirection(byte); // * Sets the Direction, or "Action" of the controller. DIRECT
// means the output will increase when error is positive. REVERSE
// means the opposite. it's very unlikely that this will be needed
// once it is set in the constructor.
void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which
void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which
// the PID calculation is performed. default is 100
//Display functions ****************************************************************
byte GetKp(); // These functions query the pid for interal values.
byte GetKi(); // they were created mainly for the pid front-end,
byte GetKd(); // where it's important to know what is actually
byte GetKd(); // where it's important to know what is actually
int GetMode(); // inside the PID.
int GetDirection(); //
private:
void Initialize();
byte dispKp; // * we'll hold on to the tuning parameters in user-entered
byte dispKp; // * we'll hold on to the tuning parameters in user-entered
byte dispKi; // format for display purposes
byte dispKd; //
int kp; // * (P)roportional Tuning Parameter
int ki; // * (I)ntegral Tuning Parameter
int kd; // * (D)erivative Tuning Parameter
uint16_t kp; // * (P)roportional Tuning Parameter
uint16_t ki; // * (I)ntegral Tuning Parameter
uint16_t kd; // * (D)erivative Tuning Parameter
int controllerDirection;
long *myInput; // * Pointers to the Input, Output, and Setpoint variables
long *myOutput; // This creates a hard link between the variables and the
long *myOutput; // This creates a hard link between the variables and the
long *mySetpoint; // PID, freeing the user from having to constantly tell us
// what these values are. with pointers we'll just know.
unsigned long lastTime;
long ITerm, lastInput;
@ -151,5 +151,77 @@ class integerPID
long outMin, outMax;
bool inAuto;
};
#endif
class integerPID_ideal
{
public:
//Constants used in some of the functions below
#define AUTOMATIC 1
#define MANUAL 0
#define DIRECT 0
#define REVERSE 1
//commonly used functions **************************************************************************
integerPID_ideal(long*, uint16_t*, uint16_t*, uint16_t*, byte*, // * constructor. links the PID to the Input, Output, and
byte, byte, byte, byte); // Setpoint. Initial tuning parameters are also set here
bool Compute(); // * performs the PID calculation. it should be
// called every time loop() cycles. ON/OFF and
// calculation frequency can be set using SetMode
// SetSampleTime respectively
void SetOutputLimits(long, long); //clamps the output to a specific range. 0-255 by default, but
//it's likely the user will want to change this depending on
//the application
//available but not commonly used functions ********************************************************
void SetTunings(byte, byte, // * While most users will set the tunings once in the
byte); // constructor, this function gives the user the option
// of changing tunings during runtime for Adaptive control
void SetControllerDirection(byte); // * Sets the Direction, or "Action" of the controller. DIRECT
// means the output will increase when error is positive. REVERSE
// means the opposite. it's very unlikely that this will be needed
// once it is set in the constructor.
//Display functions ****************************************************************
byte GetKp(); // These functions query the pid for interal values.
byte GetKi(); // they were created mainly for the pid front-end,
byte GetKd(); // where it's important to know what is actually
int GetMode(); // inside the PID.
int GetDirection(); //
void Initialize();
private:
byte dispKp; // * we'll hold on to the tuning parameters in user-entered
byte dispKi; // format for display purposes
byte dispKd; //
uint16_t kp; // * (P)roportional Tuning Parameter
uint16_t ki; // * (I)ntegral Tuning Parameter
uint16_t kd; // * (D)erivative Tuning Parameter
int controllerDirection;
long *myInput; //
uint16_t *myOutput; // This is a percentage figure multipled by 100 (To give 2 points of precision)
uint16_t *mySetpoint; //
uint16_t *mySensitivity;
byte *mySampleTime;
unsigned long lastTime;
long lastError;
long ITerm, lastInput;
long outMin, outMax;
};
#endif

View File

@ -1,11 +1,15 @@
#ifndef STORAGE_H
#define STORAGE_H
void writeAllConfig();
void writeConfig();
void loadConfig();
void loadCalibration();
void writeCalibration();
#define EEPROM_MAX_WRITE_BLOCK 30 //The maximum number of write operations that will be performed in one go. If we try to write to the EEPROM too fast (Each write takes ~3ms) then the rest of the system can hang)
bool eepromWritesPending = false;
/*
Current layout of EEPROM data (Version 3) is as follows (All sizes are in bytes):
|---------------------------------------------------|
@ -48,7 +52,8 @@ Current layout of EEPROM data (Version 3) is as follows (All sizes are in bytes)
| 1441 |2 | X and Y size4 |
| 1443 |36 | PAGE 9 MAP4 |
| 1479 |6 | X and Y Bins4 |
| 1500 |128 | CANBUS config and data |
| 1500 |128 | CANBUS config and data (Table 10_) |
| 1628 |192 | Table 11 - General settings |
| |
| 2559 |512 | Calibration data (O2) |
| 3071 |512 | Calibration data (IAT) |
@ -64,57 +69,57 @@ Current layout of EEPROM data (Version 3) is as follows (All sizes are in bytes)
#define EEPROM_CONFIG1_XBINS 259
#define EEPROM_CONFIG1_YBINS 275
#define EEPROM_CONFIG2_START 291
#define EEPROM_CONFIG2_END 355 // +64 131
#define EEPROM_CONFIG3_XSIZE 355
#define EEPROM_CONFIG3_YSIZE 356
#define EEPROM_CONFIG3_MAP 357
#define EEPROM_CONFIG3_XBINS 613
#define EEPROM_CONFIG3_YBINS 629
#define EEPROM_CONFIG4_START 645
#define EEPROM_CONFIG4_END 709
#define EEPROM_CONFIG5_XSIZE 709
#define EEPROM_CONFIG5_YSIZE 710
#define EEPROM_CONFIG5_MAP 711
#define EEPROM_CONFIG5_XBINS 967
#define EEPROM_CONFIG5_YBINS 983
#define EEPROM_CONFIG6_START 999
#define EEPROM_CONFIG6_END 1063
#define EEPROM_CONFIG7_START 1063
#define EEPROM_CONFIG7_END 1127
#define EEPROM_CONFIG8_XSIZE1 1127
#define EEPROM_CONFIG8_YSIZE1 1128
#define EEPROM_CONFIG8_MAP1 1129
#define EEPROM_CONFIG8_XBINS1 1193
#define EEPROM_CONFIG8_YBINS1 1201
#define EEPROM_CONFIG8_XSIZE2 1209
#define EEPROM_CONFIG8_YSIZE2 1210
#define EEPROM_CONFIG8_MAP2 1211
#define EEPROM_CONFIG8_XBINS2 1275
#define EEPROM_CONFIG8_YBINS2 1283
#define EEPROM_CONFIG8_END 1291
#define EEPROM_CONFIG2_END 419
#define EEPROM_CONFIG3_XSIZE 419
#define EEPROM_CONFIG3_YSIZE 420
#define EEPROM_CONFIG3_MAP 421
#define EEPROM_CONFIG3_XBINS 677
#define EEPROM_CONFIG3_YBINS 693
#define EEPROM_CONFIG4_START 709
#define EEPROM_CONFIG4_END 837
#define EEPROM_CONFIG5_XSIZE 837
#define EEPROM_CONFIG5_YSIZE 838
#define EEPROM_CONFIG5_MAP 839
#define EEPROM_CONFIG5_XBINS 1095
#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_CONFIG8_END 1419
#define EEPROM_CONFIG9_XSIZE1 1291
#define EEPROM_CONFIG9_YSIZE1 1292
#define EEPROM_CONFIG9_MAP1 1293
#define EEPROM_CONFIG9_XBINS1 1329
#define EEPROM_CONFIG9_YBINS1 1335
#define EEPROM_CONFIG9_XSIZE2 1341
#define EEPROM_CONFIG9_YSIZE2 1342
#define EEPROM_CONFIG9_MAP2 1343
#define EEPROM_CONFIG9_XBINS2 1379
#define EEPROM_CONFIG9_YBINS2 1385
#define EEPROM_CONFIG9_XSIZE3 1391
#define EEPROM_CONFIG9_YSIZE3 1392
#define EEPROM_CONFIG9_MAP3 1393
#define EEPROM_CONFIG9_XBINS3 1429
#define EEPROM_CONFIG9_YBINS3 1435
#define EEPROM_CONFIG9_XSIZE4 1441
#define EEPROM_CONFIG9_YSIZE4 1442
#define EEPROM_CONFIG9_MAP4 1443
#define EEPROM_CONFIG9_XBINS4 1479
#define EEPROM_CONFIG9_YBINS4 1485
#define EEPROM_CONFIG10_START 1500
#define EEPROM_CONFIG10_END 1628
#define EEPROM_CONFIG9_XSIZE1 1419
#define EEPROM_CONFIG9_YSIZE1 1420
#define EEPROM_CONFIG9_MAP1 1421
#define EEPROM_CONFIG9_XBINS1 1457
#define EEPROM_CONFIG9_YBINS1 1463
#define EEPROM_CONFIG9_XSIZE2 1469
#define EEPROM_CONFIG9_YSIZE2 1470
#define EEPROM_CONFIG9_MAP2 1471
#define EEPROM_CONFIG9_XBINS2 1507
#define EEPROM_CONFIG9_YBINS2 1513
#define EEPROM_CONFIG9_XSIZE3 1519
#define EEPROM_CONFIG9_YSIZE3 1520
#define EEPROM_CONFIG9_MAP3 1521
#define EEPROM_CONFIG9_XBINS3 1557
#define EEPROM_CONFIG9_YBINS3 1563
#define EEPROM_CONFIG9_XSIZE4 1569
#define EEPROM_CONFIG9_YSIZE4 1570
#define EEPROM_CONFIG9_MAP4 1571
#define EEPROM_CONFIG9_XBINS4 1607
#define EEPROM_CONFIG9_YBINS4 1613
#define EEPROM_CONFIG10_START 1628
#define EEPROM_CONFIG10_END 1756
#define EEPROM_CONFIG11_START 1756
#define EEPROM_CONFIG11_END 1948
//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

@ -7,13 +7,29 @@ A full copy of the license may be found in the projects root directory
#include "storage.h"
#include "globals.h"
#include "table.h"
#include "comms.h"
#include <EEPROM.h>
void writeAllConfig()
{
writeConfig(1);
if (eepromWritesPending == false) { writeConfig(2); }
if (eepromWritesPending == false) { writeConfig(3); }
if (eepromWritesPending == false) { writeConfig(4); }
if (eepromWritesPending == false) { writeConfig(5); }
if (eepromWritesPending == false) { writeConfig(6); }
if (eepromWritesPending == false) { writeConfig(7); }
if (eepromWritesPending == false) { writeConfig(8); }
if (eepromWritesPending == false) { writeConfig(9); }
if (eepromWritesPending == false) { writeConfig(10); }
}
/*
Takes the current configuration (config pages and maps)
and writes them to EEPROM as per the layout defined in storage.h
*/
void writeConfig()
void writeConfig(byte tableNum)
{
/*
We only ever write to the EEPROM where the new value is different from the currently stored byte
@ -21,258 +37,342 @@ void writeConfig()
*/
int offset;
int i, z, y;
int writeCounter = 0;
byte newVal; //Used for tempoerarily storing the new intended value
//Create a pointer to the config page
byte* pnt_configPage;
switch(tableNum)
{
case veMapPage:
/*---------------------------------------------------
| Fuel table (See storage.h for data layout) - Page 1
| 16x16 table itself + the 16 values along each of the axis
-----------------------------------------------------*/
if(EEPROM.read(EEPROM_CONFIG1_XSIZE) != fuelTable.xSize) { EEPROM.write(EEPROM_CONFIG1_XSIZE, fuelTable.xSize); writeCounter++; } //Write the VE Tables RPM dimension size
if(EEPROM.read(EEPROM_CONFIG1_YSIZE) != fuelTable.ySize) { EEPROM.write(EEPROM_CONFIG1_YSIZE, fuelTable.ySize); writeCounter++; } //Write the VE Tables MAP/TPS dimension size
for(int x=EEPROM_CONFIG1_MAP; x<EEPROM_CONFIG1_XBINS; 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_CONFIG1_MAP;
if( EEPROM.read(x) != (fuelTable.values[15-(offset/16)][offset%16]) ) { EEPROM.write(x, fuelTable.values[15-(offset/16)][offset%16]); writeCounter++; } //Write the 16x16 map
}
/*---------------------------------------------------
| Fuel table (See storage.h for data layout) - Page 1
| 16x16 table itself + the 16 values along each of the axis
-----------------------------------------------------*/
if(EEPROM.read(EEPROM_CONFIG1_XSIZE) != fuelTable.xSize) { EEPROM.write(EEPROM_CONFIG1_XSIZE, fuelTable.xSize); } //Write the VE Tables RPM dimension size
if(EEPROM.read(EEPROM_CONFIG1_YSIZE) != fuelTable.ySize) { EEPROM.write(EEPROM_CONFIG1_YSIZE, fuelTable.ySize); } //Write the VE Tables MAP/TPS dimension size
for(int x=EEPROM_CONFIG1_MAP; x<EEPROM_CONFIG1_XBINS; x++)
{
offset = x - EEPROM_CONFIG1_MAP;
if( EEPROM.read(x) != (fuelTable.values[15-(offset/16)][offset%16]) ) { EEPROM.write(x, fuelTable.values[15-(offset/16)][offset%16]); } //Write the 16x16 map
}
//RPM bins
for(int x=EEPROM_CONFIG1_XBINS; x<EEPROM_CONFIG1_YBINS; 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_CONFIG1_XBINS;
if( EEPROM.read(x) != (byte(fuelTable.axisX[offset]/TABLE_RPM_MULTIPLIER)) ) { EEPROM.write(x, byte(fuelTable.axisX[offset]/TABLE_RPM_MULTIPLIER)); writeCounter++; } //RPM bins are divided by 100 and converted to a byte
}
//TPS/MAP bins
for(int x=EEPROM_CONFIG1_YBINS; x<EEPROM_CONFIG2_START; 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_CONFIG1_YBINS;
EEPROM.update(x, fuelTable.axisY[offset] / TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
}
if(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
else { eepromWritesPending = false; }
break;
//That concludes the writing of the VE table
//RPM bins
for(int x=EEPROM_CONFIG1_XBINS; x<EEPROM_CONFIG1_YBINS; x++)
{
offset = x - EEPROM_CONFIG1_XBINS;
if( EEPROM.read(x) != (byte(fuelTable.axisX[offset]/TABLE_RPM_MULTIPLIER)) ) { EEPROM.write(x, byte(fuelTable.axisX[offset]/TABLE_RPM_MULTIPLIER)); } //RPM bins are divided by 100 and converted to a byte
}
//TPS/MAP bins
for(int x=EEPROM_CONFIG1_YBINS; x<EEPROM_CONFIG2_START; x++)
{
offset = x - EEPROM_CONFIG1_YBINS;
EEPROM.update(x, fuelTable.axisY[offset] / TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
}
//That concludes the writing of the VE table
//*********************************************************************************************************************************************************************************
case veSetPage:
/*---------------------------------------------------
| 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
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.
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG2_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG2_START))); writeCounter++; }
}
/*---------------------------------------------------
| 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
for(int x=EEPROM_CONFIG2_START; x<EEPROM_CONFIG2_END; x++)
{
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG2_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG2_START))); }
}
//*********************************************************************************************************************************************************************************
if(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
else { eepromWritesPending = false; }
break;
/*---------------------------------------------------
| Ignition table (See storage.h for data layout) - Page 1
| 16x16 table itself + the 16 values along each of the axis
-----------------------------------------------------*/
//Begin writing the Ignition table, basically the same thing as above
if(EEPROM.read(EEPROM_CONFIG3_XSIZE) != ignitionTable.xSize) { EEPROM.write(EEPROM_CONFIG3_XSIZE,ignitionTable.xSize); } //Write the ignition Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG3_YSIZE) != ignitionTable.ySize) { EEPROM.write(EEPROM_CONFIG3_YSIZE,ignitionTable.ySize); } //Write the ignition Table MAP/TPS dimension size
case ignMapPage:
/*---------------------------------------------------
| Ignition table (See storage.h for data layout) - Page 1
| 16x16 table itself + the 16 values along each of the axis
-----------------------------------------------------*/
//Begin writing the Ignition table, basically the same thing as above
if(EEPROM.read(EEPROM_CONFIG3_XSIZE) != ignitionTable.xSize) { EEPROM.write(EEPROM_CONFIG3_XSIZE,ignitionTable.xSize); writeCounter++; } //Write the ignition Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG3_YSIZE) != ignitionTable.ySize) { EEPROM.write(EEPROM_CONFIG3_YSIZE,ignitionTable.ySize); writeCounter++; } //Write the ignition Table MAP/TPS dimension size
for(int x=EEPROM_CONFIG3_MAP; x<EEPROM_CONFIG3_XBINS; x++)
{
offset = x - EEPROM_CONFIG3_MAP;
if(EEPROM.read(x) != (ignitionTable.values[15-(offset/16)][offset%16]) ) { EEPROM.write(x, ignitionTable.values[15-(offset/16)][offset%16]); } //Write the 16x16 map with translation
}
//RPM bins
for(int x=EEPROM_CONFIG3_XBINS; x<EEPROM_CONFIG3_YBINS; x++)
{
offset = x - EEPROM_CONFIG3_XBINS;
if(EEPROM.read(x) != byte(ignitionTable.axisX[offset]/TABLE_RPM_MULTIPLIER)) { EEPROM.write(x, byte(ignitionTable.axisX[offset]/TABLE_RPM_MULTIPLIER)); } //RPM bins are divided by 100 and converted to a byte
}
//TPS/MAP bins
for(int x=EEPROM_CONFIG3_YBINS; x<EEPROM_CONFIG4_START; x++)
{
offset = x - EEPROM_CONFIG3_YBINS;
EEPROM.update(x, ignitionTable.axisY[offset]/TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
}
//That concludes the writing of the IGN table
//*********************************************************************************************************************************************************************************
for(int x=EEPROM_CONFIG3_MAP; x<EEPROM_CONFIG3_XBINS; 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_CONFIG3_MAP;
newVal = ignitionTable.values[15-(offset/16)][offset%16];
if(EEPROM.read(x) != newVal) { EEPROM.write(x, newVal); writeCounter++; } //Write the 16x16 map with translation
}
//RPM bins
for(int x=EEPROM_CONFIG3_XBINS; x<EEPROM_CONFIG3_YBINS; 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_CONFIG3_XBINS;
newVal = ignitionTable.axisX[offset]/TABLE_RPM_MULTIPLIER;
if(EEPROM.read(x) != newVal) { EEPROM.write(x, newVal); writeCounter++; } //RPM bins are divided by 100 and converted to a byte
}
//TPS/MAP bins
for(int x=EEPROM_CONFIG3_YBINS; x<EEPROM_CONFIG4_START; 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_CONFIG3_YBINS;
newVal = ignitionTable.axisY[offset]/TABLE_LOAD_MULTIPLIER;
if(EEPROM.read(x) != newVal) { EEPROM.write(x, newVal); writeCounter++; } //Table load is divided by 2 (Allows for MAP up to 511)
}
/*---------------------------------------------------
| 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
for(int x=EEPROM_CONFIG4_START; x<EEPROM_CONFIG4_END; x++)
{
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG4_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG4_START))); }
}
//*********************************************************************************************************************************************************************************
if(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
else { eepromWritesPending = false; }
break;
/*---------------------------------------------------
| AFR table (See storage.h for data layout) - Page 5
| 16x16 table itself + the 16 values along each of the axis
-----------------------------------------------------*/
//Begin writing the Ignition table, basically the same thing as above
if(EEPROM.read(EEPROM_CONFIG5_XSIZE) != afrTable.xSize) { EEPROM.write(EEPROM_CONFIG5_XSIZE,afrTable.xSize); } //Write the ignition Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG5_YSIZE) != afrTable.ySize) { EEPROM.write(EEPROM_CONFIG5_YSIZE,afrTable.ySize); } //Write the ignition Table MAP/TPS dimension size
case ignSetPage:
/*---------------------------------------------------
| 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
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.
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG4_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG4_START))); writeCounter++; }
}
for(int x=EEPROM_CONFIG5_MAP; x<EEPROM_CONFIG5_XBINS; x++)
{
offset = x - EEPROM_CONFIG5_MAP;
if(EEPROM.read(x) != (afrTable.values[15-(offset/16)][offset%16]) ) { EEPROM.write(x, afrTable.values[15-(offset/16)][offset%16]); } //Write the 16x16 map
}
//RPM bins
for(int x=EEPROM_CONFIG5_XBINS; x<EEPROM_CONFIG5_YBINS; x++)
{
offset = x - EEPROM_CONFIG5_XBINS;
if(EEPROM.read(x) != byte(afrTable.axisX[offset]/TABLE_RPM_MULTIPLIER)) { EEPROM.write(x, byte(afrTable.axisX[offset]/TABLE_RPM_MULTIPLIER)); } //RPM bins are divided by 100 and converted to a byte
}
//TPS/MAP bins
for(int x=EEPROM_CONFIG5_YBINS; x<EEPROM_CONFIG6_START; x++)
{
offset = x - EEPROM_CONFIG5_YBINS;
EEPROM.update(x, afrTable.axisY[offset]/TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
}
//That concludes the writing of the AFR table
//*********************************************************************************************************************************************************************************
if(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
else { eepromWritesPending = false; }
/*---------------------------------------------------
| 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
for(int x=EEPROM_CONFIG6_START; x<EEPROM_CONFIG6_END; x++)
{
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG6_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG6_START))); }
}
//*********************************************************************************************************************************************************************************
break;
/*---------------------------------------------------
| Config page 4 (See storage.h for data layout)
| 64 byte long config table
-----------------------------------------------------*/
pnt_configPage = (byte *)&configPage4; //Create a pointer to Page 4 in memory
//The next 128 bytes can simply be pulled straight from the configTable
for(int x=EEPROM_CONFIG7_START; x<EEPROM_CONFIG7_END; x++)
{
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG7_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG7_START))); }
}
case afrMapPage:
/*---------------------------------------------------
| AFR table (See storage.h for data layout) - Page 5
| 16x16 table itself + the 16 values along each of the axis
-----------------------------------------------------*/
//Begin writing the Ignition table, basically the same thing as above
if(EEPROM.read(EEPROM_CONFIG5_XSIZE) != afrTable.xSize) { EEPROM.write(EEPROM_CONFIG5_XSIZE,afrTable.xSize); writeCounter++; } //Write the ignition Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG5_YSIZE) != afrTable.ySize) { EEPROM.write(EEPROM_CONFIG5_YSIZE,afrTable.ySize); writeCounter++; } //Write the ignition Table MAP/TPS dimension size
/*---------------------------------------------------
| Boost and vvt tables (See storage.h for data layout) - Page 8
| 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); } //Write the boost Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG8_YSIZE1) != boostTable.ySize) { EEPROM.write(EEPROM_CONFIG8_YSIZE1,boostTable.ySize); } //Write the boost Table MAP/TPS dimension size
if(EEPROM.read(EEPROM_CONFIG8_XSIZE2) != vvtTable.xSize) { EEPROM.write(EEPROM_CONFIG8_XSIZE2,vvtTable.xSize); } //Write the vvt Table RPM dimension size
if(EEPROM.read(EEPROM_CONFIG8_YSIZE2) != vvtTable.ySize) { EEPROM.write(EEPROM_CONFIG8_YSIZE2,vvtTable.ySize); } //Write the vvt Table MAP/TPS dimension size
for(int x=EEPROM_CONFIG5_MAP; x<EEPROM_CONFIG5_XBINS; 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_CONFIG5_MAP;
if(EEPROM.read(x) != (afrTable.values[15-(offset/16)][offset%16]) ) { EEPROM.write(x, afrTable.values[15-(offset/16)][offset%16]); writeCounter++; } //Write the 16x16 map
}
//RPM bins
for(int x=EEPROM_CONFIG5_XBINS; x<EEPROM_CONFIG5_YBINS; 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_CONFIG5_XBINS;
if(EEPROM.read(x) != byte(afrTable.axisX[offset]/TABLE_RPM_MULTIPLIER)) { EEPROM.write(x, byte(afrTable.axisX[offset]/TABLE_RPM_MULTIPLIER)); writeCounter++; } //RPM bins are divided by 100 and converted to a byte
}
//TPS/MAP bins
for(int x=EEPROM_CONFIG5_YBINS; x<EEPROM_CONFIG6_START; 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_CONFIG5_YBINS;
EEPROM.update(x, afrTable.axisY[offset]/TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
}
int y = EEPROM_CONFIG8_MAP2; //We do the 2 maps together in the same loop
for(int x=EEPROM_CONFIG8_MAP1; x<EEPROM_CONFIG8_XBINS1; x++)
{
offset = x - EEPROM_CONFIG8_MAP1;
if(EEPROM.read(x) != (boostTable.values[7-(offset/8)][offset%8]) ) { EEPROM.write(x, boostTable.values[7-(offset/8)][offset%8]); } //Write the 8x8 map
offset = y - EEPROM_CONFIG8_MAP2;
if(EEPROM.read(y) != (vvtTable.values[7-(offset/8)][offset%8]) ) { EEPROM.write(y, vvtTable.values[7-(offset/8)][offset%8]); } //Write the 8x8 map
y++;
}
//RPM bins
y = EEPROM_CONFIG8_XBINS2;
for(int x=EEPROM_CONFIG8_XBINS1; x<EEPROM_CONFIG8_YBINS1; x++)
{
offset = x - EEPROM_CONFIG8_XBINS1;
if(EEPROM.read(x) != byte(boostTable.axisX[offset]/TABLE_RPM_MULTIPLIER)) { EEPROM.write(x, byte(boostTable.axisX[offset]/TABLE_RPM_MULTIPLIER)); } //RPM bins are divided by 100 and converted to a byte
offset = y - EEPROM_CONFIG8_XBINS2;
if(EEPROM.read(y) != byte(vvtTable.axisX[offset]/TABLE_RPM_MULTIPLIER)) { EEPROM.write(y, byte(vvtTable.axisX[offset]/TABLE_RPM_MULTIPLIER)); } //RPM bins are divided by 100 and converted to a byte
y++;
}
//TPS/MAP bins
y=EEPROM_CONFIG8_YBINS2;
for(int x=EEPROM_CONFIG8_YBINS1; x<EEPROM_CONFIG8_XSIZE2; x++)
{
offset = x - EEPROM_CONFIG8_YBINS1;
EEPROM.update(x, boostTable.axisY[offset]); //TABLE_LOAD_MULTIPLIER is NOT used for boost as it is TPS based (0-100)
offset = y - EEPROM_CONFIG8_YBINS2;
EEPROM.update(y, vvtTable.axisY[offset]); //TABLE_LOAD_MULTIPLIER is NOT used for VVT as it is TPS based (0-100)
y++;
}
if(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
else { eepromWritesPending = false; }
/*---------------------------------------------------
| Fuel trim tables (See storage.h for data layout) - Page 9
| 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)
EEPROM.update(EEPROM_CONFIG9_XSIZE1,trim1Table.xSize); //Write the boost Table RPM dimension size
EEPROM.update(EEPROM_CONFIG9_YSIZE1,trim1Table.ySize); //Write the boost Table MAP/TPS dimension size
EEPROM.update(EEPROM_CONFIG9_XSIZE2,trim2Table.xSize); //Write the boost Table RPM dimension size
EEPROM.update(EEPROM_CONFIG9_YSIZE2,trim2Table.ySize); //Write the boost Table MAP/TPS dimension size
EEPROM.update(EEPROM_CONFIG9_XSIZE3,trim3Table.xSize); //Write the boost Table RPM dimension size
EEPROM.update(EEPROM_CONFIG9_YSIZE3,trim3Table.ySize); //Write the boost Table MAP/TPS dimension size
EEPROM.update(EEPROM_CONFIG9_XSIZE4,trim4Table.xSize); //Write the boost Table RPM dimension size
EEPROM.update(EEPROM_CONFIG9_YSIZE4,trim4Table.ySize); //Write the boost Table MAP/TPS dimension size
break;
y = EEPROM_CONFIG9_MAP2; //We do the 4 maps together in the same loop
int z = EEPROM_CONFIG9_MAP3; //We do the 4 maps together in the same loop
int i = EEPROM_CONFIG9_MAP4; //We do the 4 maps together in the same loop
for(int x=EEPROM_CONFIG9_MAP1; x<EEPROM_CONFIG9_XBINS1; x++)
{
offset = x - EEPROM_CONFIG9_MAP1;
EEPROM.update(x, (trim1Table.values[5-(offset/6)][offset%6]) ); //Write the 6x6 map
offset = y - EEPROM_CONFIG9_MAP2;
EEPROM.update(y, trim2Table.values[5-(offset/6)][offset%6]); //Write the 6x6 map
offset = z - EEPROM_CONFIG9_MAP3;
EEPROM.update(z, trim3Table.values[5-(offset/6)][offset%6]); //Write the 6x6 map
offset = i - EEPROM_CONFIG9_MAP4;
EEPROM.update(i, trim4Table.values[5-(offset/6)][offset%6]); //Write the 6x6 map
y++;
z++;
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++)
{
offset = x - EEPROM_CONFIG9_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;
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;
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;
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++)
{
offset = x - EEPROM_CONFIG9_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;
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;
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;
EEPROM.update(i, trim4Table.axisY[offset]/TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
y++;
z++;
i++;
}
//*********************************************************************************************************************************************************************************
case afrSetPage:
/*---------------------------------------------------
| 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
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.
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG6_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG6_START))); writeCounter++; }
}
/*---------------------------------------------------
| 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++)
{
if(EEPROM.read(x) != *(pnt_configPage + byte(x - EEPROM_CONFIG10_START))) { EEPROM.write(x, *(pnt_configPage + byte(x - EEPROM_CONFIG10_START))); }
}
//*********************************************************************************************************************************************************************************
if(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
else { eepromWritesPending = false; }
break;
case boostvvtPage:
/*---------------------------------------------------
| Boost and vvt tables (See storage.h for data layout) - Page 8
| 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
y = EEPROM_CONFIG8_MAP2; //We do the 2 maps together in the same loop
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_CONFIG8_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;
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
y++;
}
//RPM bins
y = EEPROM_CONFIG8_XBINS2;
for(int x=EEPROM_CONFIG8_XBINS1; x<EEPROM_CONFIG8_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;
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;
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
y++;
}
//TPS/MAP bins
y=EEPROM_CONFIG8_YBINS2;
for(int x=EEPROM_CONFIG8_YBINS1; x<EEPROM_CONFIG8_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;
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;
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)
y++;
}
if(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
else { eepromWritesPending = false; }
break;
case seqFuelPage:
/*---------------------------------------------------
| Fuel trim tables (See storage.h for data layout) - Page 9
| 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
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
for(int x=EEPROM_CONFIG9_MAP1; x<EEPROM_CONFIG9_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;
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;
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;
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;
newVal = trim4Table.values[5-(offset/6)][offset%6];
if (EEPROM.read(i) != newVal ) { EEPROM.update(i, newVal); writeCounter++; } //Write the 6x6 map
y++;
z++;
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++)
{
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;
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;
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;
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;
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++)
{
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;
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;
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;
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;
EEPROM.update(i, trim4Table.axisY[offset]/TABLE_LOAD_MULTIPLIER); //Table load is divided by 2 (Allows for MAP up to 511)
y++;
z++;
i++;
}
if(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
else { eepromWritesPending = false; }
break;
case canbusPage:
/*---------------------------------------------------
| 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++)
{
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(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
else { eepromWritesPending = false; }
break;
case warmupPage:
/*---------------------------------------------------
| 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
//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++)
{
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(writeCounter > EEPROM_MAX_WRITE_BLOCK) { eepromWritesPending = true; }
else { eepromWritesPending = false; }
break;
default:
break;
}
}
void loadConfig()
@ -364,17 +464,6 @@ void loadConfig()
*(pnt_configPage + byte(x - EEPROM_CONFIG6_START)) = EEPROM.read(x);
}
//*********************************************************************************************************************************************************************************
//CONFIG PAGE (4)
pnt_configPage = (byte *)&configPage4; //Create a pointer to Page 3 in memory
//Begin writing the Ignition table, basically the same thing as above
//The first 64 bytes can simply be pulled straight from the configTable
for(int x=EEPROM_CONFIG7_START; x<EEPROM_CONFIG7_END; x++)
{
*(pnt_configPage + byte(x - EEPROM_CONFIG7_START)) = EEPROM.read(x);
}
//*********************************************************************************************************************************************************************************
// Boost and vvt tables load
int y = EEPROM_CONFIG8_MAP2;
@ -476,6 +565,14 @@ void loadConfig()
//*********************************************************************************************************************************************************************************
//CONFIG PAGE (11)
pnt_configPage = (byte *)&configPage11; //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++)
{
*(pnt_configPage + byte(x - EEPROM_CONFIG11_START)) = EEPROM.read(x);
}
}
/*

View File

@ -103,6 +103,7 @@ int table2D_getValue(struct table2D *fromTable, int X_in)
{
returnValue = fromTable->values[x]; //Simply return the coresponding value
valueFound = true;
break;
}
else
{
@ -143,6 +144,7 @@ int table2D_getValue(struct table2D *fromTable, int X_in)
{
returnValue = fromTable->values16[x]; //Simply return the coresponding value
valueFound = true;
break;
}
else
{
@ -374,13 +376,29 @@ int get3DTableValue(struct table3D *fromTable, int Y_in, int X_in)
//Initial check incase the values were hit straight on
long p = (long)X - xMinValue;
if (xMaxValue == xMinValue) { p = (p << 8); } //This only occurs if the requested X value was equal to one of the X axis bins
else { p = ( (p << 8) / (xMaxValue - xMinValue) ); } //This is the standard case
long q = (long)Y - yMinValue;
if (yMaxValue == yMinValue) { q = (q << 8); }
else { q = 256 - ( (q << 8) / (yMinValue - yMaxValue) ); }
long q;
if (yMaxValue == yMinValue)
{
q = (long)Y - yMinValue;
q = (q << 8);
}
//Standard case
else
{
q = long(Y) - yMaxValue;
q = 256 - ( (q << 8) / (yMinValue - yMaxValue) );
}
/*
long q;
if (yMaxValue == yMinValue) { q = ((long)(Y - yMinValue) << 8); }
else { q = 256 - (((long)(Y - yMaxValue) << 8) / (yMinValue - yMaxValue)); }
*/
int m = ((256-p) * (256-q)) >> 8;
int n = (p * (256-q)) >> 8;
@ -390,152 +408,3 @@ int get3DTableValue(struct table3D *fromTable, int Y_in, int X_in)
}
return tableResult;
}
/* Executed a benchmark on all options and this is the results
* Stadard:226224 91 |FP Math:32240 91.89 |Clean code:34056 91, Number of loops:2500
*
//This function pulls a value from a 3D table given a target for X and Y coordinates.
//It performs a 2D linear interpolation as descibred in: http://www.megamanual.com/v22manual/ve_tuner.pdf
float get3DTableValueF(struct table3D *fromTable, int Y, int X)
{
float m, n, o ,p, q, r;
byte xMin, xMax;
byte yMin, yMax;
int yMaxValue, yMinValue;
int xMaxValue, xMinValue;
if(fromTable->lastXMin==0) {fromTable->lastXMin = fromTable->xSize-1;}
else {xMin = fromTable->lastXMin;}
if(fromTable->lastYMin==0) {fromTable->lastYMin = fromTable->ySize-1;}
else {yMin = fromTable->lastYMin;}
//yMin = fromTable->lastYMin;
if(xMin>fromTable->xSize-1)
{
fromTable->lastXMin = fromTable->xSize-1;
xMin = fromTable->xSize-1;
}
if(yMin>fromTable->ySize-1)
{
fromTable->lastYMin = fromTable->ySize-1;
yMin = fromTable->ySize-1;
}
do //RPM axis
{
if(X>=fromTable->axisX[xMin]) {break;}
xMin--;
}while(1);
fromTable->lastXMin = xMin + 1;
do //MAP axis
{
if(Y<=fromTable->axisY[yMin]) {break;}
yMin--;
}while(1);
fromTable->lastYMin = yMin + 1;
xMax = xMin + 1;
yMax = yMin + 1;
if (xMax>fromTable->xSize-1) //Overflow protection
{
xMax = fromTable->xSize-1;
xMin = xMax - 1;
}
if (yMax>fromTable->ySize-1) //Overflow protection
{
yMax = fromTable->ySize-1;
yMin = yMax - 1;
}
yMaxValue = fromTable->axisY[yMax];
yMinValue = fromTable->axisY[yMin];
xMaxValue = fromTable->axisX[xMax];
xMinValue = fromTable->axisX[xMin];
int A = fromTable->values[yMin][xMin];
int B = fromTable->values[yMin][xMax];
int C = fromTable->values[yMax][xMin];
int D = fromTable->values[yMax][xMax];
p = float(X - xMinValue) / (xMaxValue - xMinValue); //(RPM - RPM[1])/(RPM[2]- RPM[1])
q = float(Y - yMinValue) / (yMaxValue - yMinValue); //(MAP - MAP[1])/(MAP[2]- MAP[1])
m = (1.0-p) * (1.0-q);
n = p * (1-q);
o = (1-p) * q;
r = p * q;
return ( (A * m) + (B * n) + (C * o) + (D * r) );
}
//This function pulls a value from a 3D table given a target for X and Y coordinates.
//It performs a 2D linear interpolation as descibred in: http://www.megamanual.com/v22manual/ve_tuner.pdf
int get3DTableValueS(struct table3D *fromTable, int Y, int X)
{
byte xMin, xMax;
byte yMin, yMax;
long p, q;
int yMaxValue, yMinValue;
int xMaxValue, xMinValue;
if(fromTable->lastXMin==0) {fromTable->lastXMin=fromTable->xSize-1;}
else {xMin = fromTable->lastXMin;}
if(fromTable->lastYMin==0) {fromTable->lastYMin=fromTable->ySize-1;}
else {yMin = fromTable->lastYMin;}
if(xMin>fromTable->xSize-1)
{
fromTable->lastXMin = fromTable->xSize-1;
xMin = fromTable->xSize-1;
}
if(yMin>fromTable->ySize-1)
{
fromTable->lastYMin = fromTable->ySize-1;
yMin = fromTable->ySize-1;
}
do //RPM axis
{
if(X>=fromTable->axisX[xMin]) {break;}
xMin--;
}while(1);
fromTable->lastXMin = xMin + 1;
do //MAP axis
{
if(Y<=fromTable->axisY[yMin]) {break;}
yMin--;
}while(1);
fromTable->lastYMin = yMin + 1;
xMax = xMin + 1;
yMax = yMin + 1;
if (xMax>fromTable->xSize-1) //Overflow protection
{
xMax = fromTable->xSize-1;
xMin = xMax - 1;
}
if (yMax>fromTable->ySize-1) //Overflow protection
{
yMax = fromTable->ySize-1;
yMin = yMax - 1;
}
yMaxValue = fromTable->axisY[yMax];
yMinValue = fromTable->axisY[yMin];
xMaxValue = fromTable->axisX[xMax];
xMinValue = fromTable->axisX[xMin];
int A = fromTable->values[yMin][xMin];
int B = fromTable->values[yMin][xMax];
int C = fromTable->values[yMax][xMin];
int D = fromTable->values[yMax][xMax];
p = ((long)(X - xMinValue) << 8) / (xMaxValue - xMinValue); //(RPM - RPM[1])/(RPM[2]- RPM[1])
q = 256 - (((long)(Y - yMaxValue) << 8) / (yMinValue - yMaxValue)); //(MAP - MAP[2])/(MAP[2]- MAP[1])
int m = ((256-p) * (256-q)) >> 8;
int n = (p * (256-q)) >> 8;
int o = ((256-p) * q) >> 8;
int r = (p * q) >> 8;
return ( (A * m) + (B * n) + (C * o) + (D * r) ) >> 8;
}
*/

View File

@ -19,12 +19,15 @@ Hence we will preload the timer with 131 cycles to leave 125 until overflow (1ms
#ifndef TIMERS_H
#define TIMERS_H
volatile int loop100ms;
volatile int loop250ms;
volatile byte loop33ms;
volatile byte loop66ms;
volatile byte loop100ms;
volatile byte loop250ms;
volatile int loopSec;
volatile unsigned int dwellLimit_uS;
volatile uint16_t lastRPM_100ms; //Need to record this for rpmDOT calculation
volatile uint16_t last250msLoopCount = 1000; //Set to effectively random number on startup. Just need this to be different to what mainLoopCount equals initially (Probably 0)
#if defined (CORE_TEENSY)
IntervalTimer lowResTimer;

View File

@ -42,18 +42,27 @@ void initialiseTimers()
#elif defined(CORE_STM32)
Timer4.setPeriod(1000); // Set up period
// Set up an interrupt
Timer4.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
Timer4.attachInterrupt(1, oneMSInterval);
Timer4.resume(); //Start Timer
#endif
dwellLimit_uS = (1000 * configPage2.dwellLimit);
#if defined(CORE_STM32)
pinMode(LED_BUILTIN, OUTPUT);
#endif
lastRPM_100ms = 0;
loop33ms = 0;
loop66ms = 0;
loop100ms = 0;
loop250ms = 0;
loopSec = 0;
}
//Timer2 Overflow Interrupt Vector, called when the timer overflows.
//Executes every ~1ms.
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
#if defined(CORE_AVR) //AVR chips use the ISR for this
ISR(TIMER2_OVF_vect, ISR_NOBLOCK)
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
void oneMSInterval() //Most ARM chips can simply call a function
@ -61,6 +70,8 @@ void oneMSInterval() //Most ARM chips can simply call a function
{
//Increment Loop Counters
loop33ms++;
loop66ms++;
loop100ms++;
loop250ms++;
loopSec++;
@ -69,19 +80,40 @@ 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
//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) ) { endCoil1Charge(); } }
if(ignitionSchedule2.Status == RUNNING) { if( (ignitionSchedule2.startTime < targetOverdwellTime) && (configPage2.useDwellLim) ) { endCoil2Charge(); } }
if(ignitionSchedule3.Status == RUNNING) { if( (ignitionSchedule3.startTime < targetOverdwellTime) && (configPage2.useDwellLim) ) { endCoil3Charge(); } }
if(ignitionSchedule4.Status == RUNNING) { if( (ignitionSchedule4.startTime < targetOverdwellTime) && (configPage2.useDwellLim) ) { endCoil4Charge(); } }
if(ignitionSchedule5.Status == RUNNING) { if( (ignitionSchedule5.startTime < targetOverdwellTime) && (configPage2.useDwellLim) ) { endCoil5Charge(); } }
if(ignitionSchedule1.Status == RUNNING) { if( (ignitionSchedule1.startTime < targetOverdwellTime) && (configPage2.useDwellLim) && (isCrankLocked != true) ) { endCoil1Charge(); } }
if(ignitionSchedule2.Status == RUNNING) { if( (ignitionSchedule2.startTime < targetOverdwellTime) && (configPage2.useDwellLim) && (isCrankLocked != true) ) { endCoil2Charge(); } }
if(ignitionSchedule3.Status == RUNNING) { if( (ignitionSchedule3.startTime < targetOverdwellTime) && (configPage2.useDwellLim) && (isCrankLocked != true) ) { endCoil3Charge(); } }
if(ignitionSchedule4.Status == RUNNING) { if( (ignitionSchedule4.startTime < targetOverdwellTime) && (configPage2.useDwellLim) && (isCrankLocked != true) ) { endCoil4Charge(); } }
if(ignitionSchedule5.Status == RUNNING) { if( (ignitionSchedule5.startTime < targetOverdwellTime) && (configPage2.useDwellLim) && (isCrankLocked != true) ) { endCoil5Charge(); } }
//30Hz loop
if (loop33ms == 33)
{
loop33ms = 0;
BIT_SET(TIMER_mask, BIT_TIMER_30HZ);
}
//15Hz loop
if (loop66ms == 66)
{
loop66ms = 0;
BIT_SET(TIMER_mask, BIT_TIMER_15HZ);
}
//Loop executed every 100ms loop
//Anything inside this if statement will run every 100ms.
if (loop100ms == 100)
{
loop100ms = 0; //Reset counter
BIT_SET(TIMER_mask, BIT_TIMER_10HZ);
#if defined(CORE_STM32) //debug purpose, only visal for running code
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
#endif
currentStatus.rpmDOT = (currentStatus.RPM - lastRPM_100ms) * 10; //This is the RPM per second that the engine has accelerated/decelleratedin the last loop
lastRPM_100ms = currentStatus.RPM; //Record the current RPM for next calc
@ -91,10 +123,16 @@ void oneMSInterval() //Most ARM chips can simply call a function
//Anything inside this if statement will run every 250ms.
if (loop250ms == 250)
{
loop250ms = 0; //Reset Counter.
loop250ms = 0; //Reset Counter
BIT_SET(TIMER_mask, BIT_TIMER_4HZ);
#if defined(CORE_AVR)
//Reset watchdog timer (Not active currently)
//wdt_reset();
//DIY watchdog
//This is a sign of a crash:
//if( (initialisationComplete == true) && (last250msLoopCount == mainLoopCount) ) { setup(); }
//else { last250msLoopCount = mainLoopCount; }
#endif
}
@ -102,9 +140,10 @@ void oneMSInterval() //Most ARM chips can simply call a function
if (loopSec == 1000)
{
loopSec = 0; //Reset counter.
BIT_SET(TIMER_mask, BIT_TIMER_1HZ);
dwellLimit_uS = (1000 * configPage2.dwellLimit); //Update uS value incase setting has changed
if ( configPage2.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) { dwellLimit_uS = dwellLimit_uS * 3; } //Make sure the overdwell doesn't clobber the fixed ignition cranking if enabled.
currentStatus.crankRPM = ((unsigned int)configPage2.crankRPM * 100);
//**************************************************************************************************************************************************
//This updates the runSecs variable
@ -123,18 +162,23 @@ void oneMSInterval() //Most ARM chips can simply call a function
currentStatus.secl++;
//**************************************************************************************************************************************************
//Check the fan output status
if (configPage4.fanEnable == 1)
if (configPage3.fanEnable == 1)
{
fanControl(); // Fucntion to turn the cooling fan on/off
}
//Check whether fuel pump priming is complete
if(!fpPrimed)
if(fpPrimed == false)
{
if(currentStatus.secl >= configPage1.fpPrime)
{
fpPrimed = true; //Mark the priming as being completed
if(currentStatus.RPM == 0) { digitalWrite(pinFuelPump, LOW); fuelPumpOn = false; } //If we reach here then the priming is complete, however only turn off the fuel pump if the engine isn't running
if(currentStatus.RPM == 0)
{
//If we reach here then the priming is complete, however only turn off the fuel pump if the engine isn't running
digitalWrite(pinFuelPump, LOW);
fuelPumpOn = false;
}
}
}
//**************************************************************************************************************************************************
@ -173,7 +217,7 @@ void oneMSInterval() //Most ARM chips can simply call a function
}
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
#if defined(CORE_AVR) //AVR chips use the ISR for this
//Reset Timer2 to trigger in another ~1ms
TCNT2 = 131; //Preload timer2 with 100 cycles, leaving 156 till overflow.
TIFR2 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag

View File

@ -8,7 +8,7 @@
void doUpdates()
{
#define CURRENT_DATA_VERSION 3
#define CURRENT_DATA_VERSION 6
//May 2017 firmware introduced a -40 offset on the ignition table. Update that table to +40
if(EEPROM.read(EEPROM_DATA_VERSION) == 2)
@ -20,15 +20,70 @@ void doUpdates()
ignitionTable.values[x][y] = ignitionTable.values[x][y] + 40;
}
}
writeConfig();
writeAllConfig();
EEPROM.write(EEPROM_DATA_VERSION, 3);
}
//June 2017 required the forced addition of some CAN values to avoid weird errors
if(EEPROM.read(EEPROM_DATA_VERSION) == 3)
{
configPage10.speeduino_tsCanId = 0;
configPage10.true_address = 256;
configPage10.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; }
writeAllConfig();
EEPROM.write(EEPROM_DATA_VERSION, 4);
}
//July 2017 adds a cranking enrichment curve in place of the single value. This converts that single value to the curve
if(EEPROM.read(EEPROM_DATA_VERSION) == 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;
configPage11.crankingEnrichValues[0] = 100 + configPage1.crankingPct;
configPage11.crankingEnrichValues[1] = 100 + configPage1.crankingPct;
configPage11.crankingEnrichValues[2] = 100 + configPage1.crankingPct;
configPage11.crankingEnrichValues[3] = 100 + configPage1.crankingPct;
writeAllConfig();
EEPROM.write(EEPROM_DATA_VERSION, 5);
}
//September 2017 had a major change to increase the minimum table size to 128. This required multiple pieces of data being moved around
if(EEPROM.read(EEPROM_DATA_VERSION) == 5)
{
//Data after page 4 has to move back 128 bytes
for(int x=0; x < 1152; x++)
{
int endMem = EEPROM_CONFIG11_END - x;
int startMem = endMem - 128; //
byte currentVal = EEPROM.read(startMem);
EEPROM.update(endMem, currentVal);
}
//The remaining data only has to move back 64 bytes
for(int x=0; x < 352; x++)
{
int endMem = EEPROM_CONFIG11_END - 1152 - x;
int startMem = endMem - 64; //
byte currentVal = EEPROM.read(startMem);
EEPROM.update(endMem, currentVal);
}
EEPROM.write(EEPROM_DATA_VERSION, 6);
loadConfig(); //Reload the config after changing everything in EEPROM
}
//Final check is always for 255 and 0 (Brand new arduino)
if( (EEPROM.read(EEPROM_DATA_VERSION) == 0) || (EEPROM.read(EEPROM_DATA_VERSION) == 255) )
{
configPage10.true_address = 0x200;
EEPROM.write(EEPROM_DATA_VERSION, CURRENT_DATA_VERSION);
}
//Check to see if someone has downgraded versions:
if( EEPROM.read(EEPROM_DATA_VERSION) > CURRENT_DATA_VERSION ) { EEPROM.write(EEPROM_DATA_VERSION, CURRENT_DATA_VERSION); }
}

View File

@ -1,15 +1,56 @@
/*
These are some utility functions and variables used through the main code
*/
*/
#ifndef UTILS_H
#define UTILS_H
#include <Arduino.h>
int freeRam ();
uint16_t freeRam ();
void setPinMapping(byte boardID);
unsigned int PW();
unsigned int PW_SD();
unsigned int PW_AN();
//This is dumb, but it'll do for now to get things compiling
#if defined(CORE_STM32)
//STM32F1/variants/.../board.cpp
#if defined (STM32F4)
#define A0 PA0
#define A1 PA1
#define A2 PA2
#define A3 PA3
#define A4 PA4
#define A5 PA5
#define A6 PA6
#define A7 PA7
#define A8 PB0
#define A9 PB1
#define A10 PC0
#define A11 PC1
#define A12 PC2
#define A13 PC3
#define A14 PC4
#define A15 PC5
#else
#define A0 PB0
#define A1 PA7
#define A2 PA6
#define A3 PA5
#define A4 PA4
#define A5 PA3
#define A6 PA2
#define A7 PA1
#define A8 PA0
//STM32F1 have only 9 12bit adc
#define A9 PB0
#define A10 PA7
#define A11 PA6
#define A12 PA5
#define A13 PA4
#define A14 PA3
#define A15 PA2
#endif
#endif
#endif // UTILS_H

View File

@ -7,15 +7,18 @@
/*
Returns how much free dynamic memory exists (between heap and stack)
This function is one big MISRA violation. MISRA advisories forbid directly poking at memory addresses, however there is no other way of determining heap size on embedded systems.
*/
#include "utils.h"
int freeRam ()
uint16_t freeRam ()
{
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
uint16_t v;
return (uint16_t) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
#elif defined(CORE_TEENSY)
uint32_t stackTop;
uint32_t heapTop;
@ -31,35 +34,14 @@ int freeRam ()
// The difference is the free, available ram.
return (uint16_t)stackTop - heapTop;
#elif defined(CORE_STM32)
//Figure this out some_time
return 0;
char top = 't';
return &top - reinterpret_cast<char*>(sbrk(0));
#endif
}
void setPinMapping(byte boardID)
{
//This is dumb, but it'll do for now to get things compiling
#if defined(CORE_STM32)
//STM32F1/variants/.../board.cpp
#define A0 boardADCPins[0]
#define A1 boardADCPins[1]
#define A2 boardADCPins[2]
#define A3 boardADCPins[3]
#define A4 boardADCPins[4]
#define A5 boardADCPins[5]
#define A6 boardADCPins[6]
#define A7 boardADCPins[7]
#define A8 boardADCPins[8]
#define A9 boardADCPins[9]
//STM32F1 have only 9 12bit adc
#define A10 boardADCPins[0]
#define A11 boardADCPins[1]
#define A12 boardADCPins[2]
#define A13 boardADCPins[3]
#define A14 boardADCPins[4]
#define A15 boardADCPins[5]
#endif
switch (boardID)
{
case 0:
@ -164,35 +146,6 @@ void setPinMapping(byte boardID)
pinCoil4 = 21;
pinCoil3 = 30;
pinO2 = A22;
#elif defined(CORE_STM32)
//http://docs.leaflabs.com/static.leaflabs.com/pub/leaflabs/maple-docs/0.0.12/hardware/maple-mini.html#master-pin-map
//pins 23, 24 and 33 couldn't be used
pinInjector1 = 15; //Output pin injector 1 is on
pinInjector2 = 16; //Output pin injector 2 is on
pinInjector3 = 17; //Output pin injector 3 is on
pinInjector4 = 18; //Output pin injector 4 is on
pinCoil1 = 19; //Pin for coil 1
pinCoil2 = 20; //Pin for coil 2
pinCoil3 = 21; //Pin for coil 3
pinCoil4 = 26; //Pin for coil 4
pinCoil5 = 27; //Pin for coil 5
pinTPS = A0; //TPS input pin
pinMAP = A1; //MAP sensor pin
pinIAT = A2; //IAT sensor pin
pinCLT = A3; //CLS sensor pin
pinO2 = A4; //O2 Sensor pin
pinBat = A5; //Battery reference voltage pin
pinStepperDir = 12; //Direction pin for DRV8825 driver
pinStepperStep = 13; //Step pin for DRV8825 driver
pinStepperEnable = 14; //Enable pin for DRV8825
pinDisplayReset = 2; // OLED reset pin
pinFan = 1; //Pin for the fan output
pinFuelPump = 0; //Fuel pump output
pinTachOut = 31; //Tacho output pin
//external interrupt enabled pins
pinFlex = 32; // Flex sensor (Must be external interrupt enabled)
pinTrigger = 25; //The CAS pin
pinTrigger2 = 22; //The Cam Sensor pin
#endif
break;
@ -241,6 +194,37 @@ void setPinMapping(byte boardID)
pinCoil4 = 29;
pinCoil3 = 30;
pinO2 = A22;
#elif defined(STM32F4)
pinInjector1 = PE7; //Output pin injector 1 is on
pinInjector2 = PE8; //Output pin injector 2 is on
pinInjector3 = PE9; //Output pin injector 3 is on
pinInjector4 = PE10; //Output pin injector 4 is on
pinInjector5 = PE11; //Output pin injector 5 is on
pinCoil1 = PB10; //Pin for coil 1
pinCoil2 = PB11; //Pin for coil 2
pinCoil3 = PB12; //Pin for coil 3
pinCoil4 = PB13; //Pin for coil 4
pinCoil5 = PB14; //Pin for coil 5
pinTPS = A0; //TPS input pin
pinMAP = A1; //MAP sensor pin
pinIAT = A2; //IAT sensor pin
pinCLT = A3; //CLS sensor pin
pinO2 = A4; //O2 Sensor pin
pinBat = A5; //Battery reference voltage pin
pinBaro = A6;
pinStepperDir = PD8; //Direction pin for DRV8825 driver
pinStepperStep = PB15; //Step pin for DRV8825 driver
pinStepperEnable = PD9; //Enable pin for DRV8825
pinDisplayReset = PE1; // OLED reset pin
pinFan = PE2; //Pin for the fan output
pinFuelPump = PA6; //Fuel pump output
pinTachOut = PA7; //Tacho output pin
//external interrupt enabled pins
pinFlex = PC4; // Flex sensor (Must be external interrupt enabled)
pinTrigger = PC5; //The CAS pin
pinTrigger2 = PC6; //The Cam Sensor pin
pinBoost = PE0; //Boost control
pinVVT_1 = PE1; //Default VVT output
#elif defined(CORE_STM32)
//http://docs.leaflabs.com/static.leaflabs.com/pub/leaflabs/maple-docs/0.0.12/hardware/maple-mini.html#master-pin-map
//pins 23, 24 and 33 couldn't be used
@ -270,6 +254,9 @@ void setPinMapping(byte boardID)
pinFlex = 32; // Flex sensor (Must be external interrupt enabled)
pinTrigger = 25; //The CAS pin
pinTrigger2 = 22; //The Cam Sensor pin
pinBaro = pinMAP;
pinBoost = 1; //Boost control
pinVVT_1 = 0; //Default VVT output
#endif
break;
@ -277,13 +264,13 @@ void setPinMapping(byte boardID)
//Pin mappings as per the MX5 PNP shield
pinInjector1 = 11; //Output pin injector 1 is on
pinInjector2 = 10; //Output pin injector 2 is on
pinInjector3 = 9; //Output pin injector 3 is on
pinInjector4 = 8; //Output pin injector 4 is on
pinInjector3 = 8; //Output pin injector 3 is on
pinInjector4 = 9; //Output pin injector 4 is on
pinInjector5 = 14; //Output pin injector 5 is on
pinCoil1 = 39; //Pin for coil 1
pinCoil2 = 41; //Pin for coil 2
pinCoil3 = 35; //Pin for coil 3
pinCoil4 = 37; //Pin for coil 4
pinCoil4 = 33; //Pin for coil 4
pinCoil5 = 34; //Pin for coil 5 PLACEHOLDER value for now
pinTrigger = 19; //The CAS pin
pinTrigger2 = 18; //The Cam Sensor pin
@ -296,13 +283,14 @@ void setPinMapping(byte boardID)
pinDisplayReset = 48; // OLED reset pin
pinTachOut = 49; //Tacho output pin (Goes to ULN2803)
pinIdle1 = 2; //Single wire idle control
pinIdle2 = 3; //2 wire idle control (Note this is shared with boost!!!)
pinFuelPump = 37; //Fuel pump output (Goes to ULN2803)
pinBoost = 4;
pinIdle2 = 4; //2 wire idle control (Note this is shared with boost!!!)
pinFuelPump = 37; //Fuel pump output
pinStepperDir = 16; //Direction pin for DRV8825 driver
pinStepperStep = 17; //Step pin for DRV8825 driver
pinFan = 47; //Pin for the fan output (Goes to ULN2803)
pinLaunch = 12; //Can be overwritten below
pinFlex = 2; // Flex sensor (Must be external interrupt enabled)
pinFlex = 3; // Flex sensor (Must be external interrupt enabled)
break;
case 10:
@ -370,6 +358,7 @@ void setPinMapping(byte boardID)
pinFan = 47; //Pin for the fan output
pinFuelPump = 4; //Fuel pump output
pinTachOut = 49; //Tacho output pin
break;
case 30:
//Pin mappings as per the dazv6 shield
@ -436,21 +425,22 @@ void setPinMapping(byte boardID)
pinFan = 47; //Pin for the fan output
pinFuelPump = 4; //Fuel pump output
pinTachOut = 49; //Tacho output pin
pinFlex = 3; // Flex sensor (Must be external interrupt enabled)
pinBoost = 5;
pinIdle1 = 6;
break;
}
//First time running?
if (configPage3.launchPin < BOARD_NR_GPIO_PINS)
{
//Setup any devices that are using selectable pins
if (configPage3.launchPin != 0) { pinLaunch = configPage3.launchPin; }
if (configPage2.ignBypassPin != 0) { pinIgnBypass = configPage2.ignBypassPin; }
if (configPage1.tachoPin != 0) { pinTachOut = configPage1.tachoPin; }
if (configPage2.fuelPumpPin != 0) { pinFuelPump = configPage2.fuelPumpPin; }
if (configPage4.fanPin != 0) { pinFan = configPage4.fanPin; }
if (configPage3.boostPin != 0) { pinBoost = configPage3.boostPin; }
if (configPage3.vvtPin != 0) { pinVVT_1 = configPage3.vvtPin; }
}
//Setup any devices that are using selectable pins
if ( (configPage3.launchPin != 0) && (configPage3.launchPin < BOARD_NR_GPIO_PINS) ) { pinLaunch = configPage3.launchPin; }
if ( (configPage2.ignBypassPin != 0) && (configPage2.ignBypassPin < BOARD_NR_GPIO_PINS) ) { pinIgnBypass = configPage2.ignBypassPin; }
if ( (configPage1.tachoPin != 0) && (configPage1.tachoPin < BOARD_NR_GPIO_PINS) ) { pinTachOut = configPage1.tachoPin; }
if ( (configPage2.fuelPumpPin != 0) && (configPage2.fuelPumpPin < BOARD_NR_GPIO_PINS) ) { pinFuelPump = configPage2.fuelPumpPin; }
if ( (configPage3.fanPin != 0) && (configPage3.fanPin < BOARD_NR_GPIO_PINS) ) { pinFan = configPage3.fanPin; }
if ( (configPage3.boostPin != 0) && (configPage3.boostPin < BOARD_NR_GPIO_PINS) ) { pinBoost = configPage3.boostPin; }
if ( (configPage3.vvtPin != 0) && (configPage3.vvtPin < BOARD_NR_GPIO_PINS) ) { pinVVT_1 = configPage3.vvtPin; }
if ( (configPage3.useExtBaro != 0) && (configPage3.baroPin < BOARD_NR_GPIO_PINS) ) { pinBaro = configPage3.baroPin + A0; }
//Finally, set the relevant pin modes for outputs
pinMode(pinCoil1, OUTPUT);
@ -499,31 +489,37 @@ void setPinMapping(byte boardID)
tach_pin_port = portOutputRegister(digitalPinToPort(pinTachOut));
tach_pin_mask = digitalPinToBitMask(pinTachOut);
pump_pin_port = portOutputRegister(digitalPinToPort(pinFuelPump));
pump_pin_mask = digitalPinToBitMask(pinFuelPump);
//And for inputs
//And for inputs
#if defined(CORE_STM32)
pinMode(pinMAP, INPUT_ANALOG);
pinMode(pinO2, INPUT_ANALOG);
pinMode(pinO2_2, INPUT_ANALOG);
pinMode(pinTPS, INPUT_ANALOG);
pinMode(pinIAT, INPUT_ANALOG);
pinMode(pinCLT, INPUT_ANALOG);
pinMode(pinBat, INPUT_ANALOG);
#else
pinMode(pinMAP, INPUT);
pinMode(pinO2, INPUT);
pinMode(pinO2_2, INPUT);
pinMode(pinTPS, INPUT);
pinMode(pinIAT, INPUT);
pinMode(pinCLT, INPUT);
pinMode(pinBat, INPUT);
#ifndef ARDUINO_ARCH_STM32 //libmaple core aka STM32DUINO
pinMode(pinMAP, INPUT_ANALOG);
pinMode(pinO2, INPUT_ANALOG);
pinMode(pinO2_2, INPUT_ANALOG);
pinMode(pinTPS, INPUT_ANALOG);
pinMode(pinIAT, INPUT_ANALOG);
pinMode(pinCLT, INPUT_ANALOG);
pinMode(pinBat, INPUT_ANALOG);
pinMode(pinBaro, INPUT_ANALOG);
#else
pinMode(pinMAP, INPUT);
pinMode(pinO2, INPUT);
pinMode(pinO2_2, INPUT);
pinMode(pinTPS, INPUT);
pinMode(pinIAT, INPUT);
pinMode(pinCLT, INPUT);
pinMode(pinBat, INPUT);
pinMode(pinBaro, INPUT);
#endif
#endif
pinMode(pinTrigger, INPUT);
pinMode(pinTrigger2, INPUT);
pinMode(pinTrigger3, INPUT);
pinMode(pinFlex, INPUT_PULLUP); //Standard GM / Continental flex sensor requires pullup
// pinMode(pinLaunch, INPUT_PULLUP); //This should work for both NO and NC grounding switches
if (configPage3.lnchPullRes) {
if (configPage3.lnchPullRes == true) {
pinMode(pinLaunch, INPUT_PULLUP);
}
else {
@ -545,6 +541,281 @@ void setPinMapping(byte boardID)
#endif
}
void initialiseTriggers()
{
byte triggerInterrupt = 0; // By default, use the first interrupt
byte triggerInterrupt2 = 1;
#if defined(CORE_AVR)
switch (pinTrigger) {
//Arduino Mega 2560 mapping
case 2:
triggerInterrupt = 0; break;
case 3:
triggerInterrupt = 1; break;
case 18:
triggerInterrupt = 5; break;
case 19:
triggerInterrupt = 4; break;
case 20:
triggerInterrupt = 3; break;
case 21:
triggerInterrupt = 2; break;
default:
triggerInterrupt = 0; break; //This should NEVER happen
}
#else
triggerInterrupt = pinTrigger;
#endif
#if defined(CORE_AVR)
switch (pinTrigger2) {
//Arduino Mega 2560 mapping
case 2:
triggerInterrupt2 = 0; break;
case 3:
triggerInterrupt2 = 1; break;
case 18:
triggerInterrupt2 = 5; break;
case 19:
triggerInterrupt2 = 4; break;
case 20:
triggerInterrupt2 = 3; break;
case 21:
triggerInterrupt2 = 2; break;
default:
triggerInterrupt2 = 0; break; //This should NEVER happen
}
#else
triggerInterrupt2 = pinTrigger2;
#endif
pinMode(pinTrigger, INPUT);
pinMode(pinTrigger2, INPUT);
pinMode(pinTrigger3, INPUT);
//digitalWrite(pinTrigger, HIGH);
detachInterrupt(triggerInterrupt);
detachInterrupt(triggerInterrupt2);
//Set the trigger function based on the decoder in the config
switch (configPage2.TrigPattern)
{
case 0:
//Missing tooth decoder
triggerSetup_missingTooth();
trigger = triggerPri_missingTooth;
triggerSecondary = triggerSec_missingTooth;
getRPM = getRPM_missingTooth;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, RISING); }
else { attachInterrupt(triggerInterrupt2, triggerSec_missingTooth, FALLING); }
break;
case 1:
// Basic distributor
triggerSetup_BasicDistributor();
trigger = triggerPri_BasicDistributor;
getRPM = getRPM_BasicDistributor;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
break;
case 2:
triggerSetup_DualWheel();
trigger = triggerPri_DualWheel;
getRPM = getRPM_DualWheel;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, RISING); }
else { attachInterrupt(triggerInterrupt2, triggerSec_DualWheel, FALLING); }
break;
case 3:
triggerSetup_GM7X();
trigger = triggerPri_GM7X;
getRPM = getRPM_GM7X;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
break;
case 4:
triggerSetup_4G63();
trigger = triggerPri_4G63;
getRPM = getRPM_4G63;
getCrankAngle = getCrankAngle_4G63;
triggerSetEndTeeth = triggerSetEndTeeth_4G63;
//These may both need to change, not sure
if(configPage2.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
}
else
{
attachInterrupt(triggerInterrupt, trigger, CHANGE); // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_4G63, FALLING);
}
break;
case 5:
triggerSetup_24X();
trigger = triggerPri_24X;
getRPM = getRPM_24X;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_24X, CHANGE);
break;
case 6:
triggerSetup_Jeep2000();
trigger = triggerPri_Jeep2000;
getRPM = getRPM_Jeep2000;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_Jeep2000, CHANGE);
break;
case 7:
triggerSetup_Audi135();
trigger = triggerPri_Audi135;
getRPM = getRPM_Audi135;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
attachInterrupt(triggerInterrupt2, triggerSec_Audi135, RISING);
break;
case 8:
triggerSetup_HondaD17();
trigger = triggerPri_HondaD17;
getRPM = getRPM_HondaD17;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_HondaD17, CHANGE);
break;
case 9:
triggerSetup_Miata9905();
trigger = triggerPri_Miata9905;
getRPM = getRPM_Miata9905;
getCrankAngle = getCrankAngle_Miata9905;
triggerSetEndTeeth = triggerSetEndTeeth_Miata9905;
//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); }
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
if(configPage2.TrigEdgeSec == 0) { attachInterrupt(triggerInterrupt2, triggerSec_Miata9905, RISING); }
else { attachInterrupt(triggerInterrupt2, triggerSec_Miata9905, FALLING); }
break;
case 10:
triggerSetup_MazdaAU();
trigger = triggerPri_MazdaAU;
getRPM = getRPM_MazdaAU;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); } // Primary trigger connects to
attachInterrupt(triggerInterrupt2, triggerSec_MazdaAU, FALLING);
break;
case 11:
triggerSetup_non360();
trigger = triggerPri_DualWheel; //Is identical to the dual wheel decoder, so that is used. Same goes for the secondary below
getRPM = getRPM_non360;
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)
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;
case 12:
triggerSetup_Nissan360();
trigger = triggerPri_Nissan360;
getRPM = getRPM_Nissan360;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
attachInterrupt(triggerInterrupt2, triggerSec_Nissan360, CHANGE);
break;
case 13:
triggerSetup_Subaru67();
trigger = triggerPri_Subaru67;
getRPM = getRPM_Subaru67;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
attachInterrupt(triggerInterrupt2, triggerSec_Subaru67, FALLING);
break;
case 14:
triggerSetup_Daihatsu();
trigger = triggerPri_Daihatsu;
getRPM = getRPM_Daihatsu;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
//No secondary input required for this pattern
break;
case 15:
triggerSetup_Harley();
trigger = triggerPri_Harley;
//triggerSecondary = triggerSec_Harley;
getRPM = getRPM_Harley;
getCrankAngle = getCrankAngle_Harley;
triggerSetEndTeeth = triggerSetEndTeeth_Harley;
attachInterrupt(triggerInterrupt, trigger, RISING);
// attachInterrupt(triggerInterrupt2, triggerSec_Harley, FALLING);
break;
default:
trigger = triggerPri_missingTooth;
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)
else { attachInterrupt(triggerInterrupt, trigger, FALLING); }
break;
}
}
/*
This function retuns a pulsewidth time (in us) using a either Alpha-N or Speed Density algorithms, given the following:
REQ_FUEL
@ -556,46 +827,49 @@ void setPinMapping(byte boardID)
This function is called by PW_SD and PW_AN for speed0density and pure Alpha-N calculations respectively.
*/
unsigned int PW(int REQ_FUEL, byte VE, byte MAP, int corrections, int injOpen)
unsigned int PW(int REQ_FUEL, byte VE, long MAP, int corrections, int injOpen)
{
//Standard float version of the calculation
//return (REQ_FUEL * (float)(VE/100.0) * (float)(MAP/100.0) * (float)(TPS/100.0) * (float)(corrections/100.0) + injOpen);
//Note: The MAP and TPS portions are currently disabled, we use VE and corrections only
unsigned int iVE, iMAP, iAFR, iCorrections;
uint16_t iVE, iCorrections;
uint16_t iMAP = 100;
uint16_t iAFR = 147;
//100% float free version, does sacrifice a little bit of accuracy, but not much.
iVE = ((unsigned int)VE << 7) / 100;
if ( configPage1.multiplyMAP ) {
if ( configPage1.multiplyMAP == true ) {
iMAP = ((unsigned int)MAP << 7) / currentStatus.baro; //Include multiply MAP (vs baro) if enabled
}
if ( configPage1.includeAFR && (configPage3.egoType == 2)) {
if ( (configPage1.includeAFR == true) && (configPage3.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 ) {
intermediate = (intermediate * iMAP) >> 7;
if ( configPage1.multiplyMAP == true ) {
intermediate = (intermediate * (unsigned long)iMAP) >> 7;
}
if ( configPage1.includeAFR && (configPage3.egoType == 2)) {
intermediate = (intermediate * iAFR) >> 7; //EGO type must be set to wideband for this to be used
if ( (configPage1.includeAFR == true) && (configPage3.egoType == 2) ) {
intermediate = (intermediate * (unsigned long)iAFR) >> 7; //EGO type must be set to wideband for this to be used
}
intermediate = (intermediate * iCorrections) >> 7;
if (intermediate == 0) {
return 0; //If the pulsewidth is 0, we return here before the opening time gets added
}
intermediate += injOpen; //Add the injector opening time
if ( intermediate > 65535) {
intermediate = 65535; //Make sure this won't overflow when we convert to uInt. This means the maximum pulsewidth possible is 65.535mS
intermediate = (intermediate * (unsigned long)iCorrections) >> 7;
if (intermediate != 0)
{
//If intermeditate is not 0, we need to add the opening time (0 typically indicates that one of the full fuel cuts is active)
intermediate += injOpen; //Add the injector opening time
if ( intermediate > 65535)
{
intermediate = 65535; //Make sure this won't overflow when we convert to uInt. This means the maximum pulsewidth possible is 65.535mS
}
}
return (unsigned int)(intermediate);
}
//Convenience functions for Speed Density and Alpha-N
unsigned int PW_SD(int REQ_FUEL, byte VE, byte MAP, int corrections, int injOpen)
unsigned int PW_SD(int REQ_FUEL, byte VE, long MAP, int corrections, int injOpen)
{
return PW(REQ_FUEL, VE, MAP, corrections, injOpen);
//return PW(REQ_FUEL, VE, 100, corrections, injOpen);
@ -603,9 +877,5 @@ unsigned int PW_SD(int REQ_FUEL, byte VE, byte MAP, int corrections, int injOpen
unsigned int PW_AN(int REQ_FUEL, byte VE, byte TPS, int corrections, int injOpen)
{
//Sanity check
if (TPS > 100) {
TPS = 100;
}
return PW(REQ_FUEL, VE, currentStatus.MAP, corrections, injOpen);
}