Add auto generated location id list.
[freeems-vanilla.git] / src / fuelAndIgnitionCalcs.c
blob01cd29a382956563253465626e8fcd8471790cd0
1 /* FreeEMS - the open source engine management system
3 Copyright 2008, 2009 Fred Cooke
5 This file is part of the FreeEMS project.
7 FreeEMS software is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 FreeEMS software is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with any FreeEMS software. If not, see http://www.gnu.org/licenses/
20 We ask that if you make any changes to this file you email them upstream to
21 us at admin(at)diyefi(dot)org or, even better, fork the code on github.com!
23 Thank you for choosing FreeEMS to run your engine! */
26 /** @file fuelAndIgnitionCalcs.c
27 * @ingroup measurementsAndCalculations
29 * @brief Fuel and ignition calculations.
31 * This file contains all of the main fuel and ignition calculations based
32 * upon the variables that we have already determined in previous stages.
34 * @author Fred Cooke
38 #define FUELANDIGNITIONCALCS_C
39 #include "inc/freeEMS.h"
40 #include "inc/commsCore.h"
41 #include "inc/tableLookup.h"
42 #include "inc/fuelAndIgnitionCalcs.h"
45 /** @brief Fuel and ignition calculations
47 * Using a variety of primary algorithms calculate a base pulsewidth and then
48 * apply various corrections to it such as injector dead time, transient fuel
49 * correction, engine temperature enrichment and per cylinder trims. The fuel
50 * injection timing is also determined here.
52 * Calculate the ignition timing and dwell here too. Several corrections are
53 * applied to these as well.
55 * @todo TODO implement the all of the ignition stuff and finish off all of the fuel injection stuff.
56 * @todo TODO change the way configuration is done and make sure the most common options are after the first if().
57 * @todo TODO add actual configuration options to the fixed config blocks for these items.
59 * @author Fred Cooke
61 void calculateFuelAndIgnition(){
62 /*&&&&&&&&&&&&& Perform the basic calculations one step at a time to get a final pulsewidth &&&&&&&&&&&&*/
64 if(TRUE /* Genuine method */){
65 unsigned short airInletTemp = CoreVars->IAT; /* All except MAF use this. */
66 /* Determine the type of air flow data */
67 if(TRUE /* SpeedDensity */){
68 /* This won't overflow until 512kPa or about 60psi of boost with 128% VE. */
69 DerivedVars->AirFlow = ((unsigned long)CoreVars->MAP * DerivedVars->VEMain) / oneHundredPercentVE;
70 /* Result is 450 - 65535 always. */
71 }else if(FALSE /*AlphaN*/){
72 DerivedVars->AirFlow = DerivedVars->VEMain; /* Not actually VE, but rather tuned air flow without density information */
73 }else if(FALSE /*MAF*/){
74 DerivedVars->AirFlow = CoreVars->MAF; /* Just fix temperature at appropriate level to provide correct Lambda */
75 /// @todo TODO figure out what the correct "temperature" is to make MAF work correctly!
76 airInletTemp = roomTemperature; // 293.15k is 20c * 100 to get value, so divide by 100 to get real number
77 }else if(FALSE /*FixedAF*/){ /* Fixed air flow from config */
78 DerivedVars->AirFlow = fixedConfigs2.sensorPresets.presetAF;
79 }else{ /* Default to no fuel delivery and error */
80 DerivedVars->AirFlow = 0;
81 /* If anyone is listening, let them know something is wrong */
82 // sendError(AIRFLOW_NOT_CONFIGURED_CODE); // or maybe queue it?
86 /* This won't overflow until well past 125C inlet, 1.5 Lambda and fuel as dense as water */
87 DerivedVars->densityAndFuel = (((unsigned long)((unsigned long)airInletTemp * DerivedVars->Lambda) / stoichiometricLambda) * fixedConfigs1.engineSettings.densityOfFuelAtSTP) / densityOfFuelTotalDivisor;
88 /* Result is 7500 - 60000 always. */
90 /* Divisors for air inlet temp and pressure :
91 * #define airInletTempDivisor 100
92 * #define airPressureDivisor 100
93 * cancel each other out! all others are used. */
96 DerivedVars->BasePW = (bootFuelConst * DerivedVars->AirFlow) / DerivedVars->densityAndFuel;
97 }else if(FALSE /*configured*/){ /* Fixed PW from config */
98 DerivedVars->BasePW = fixedConfigs2.sensorPresets.presetBPW;
99 }else{ /* Default to no fuel delivery and error */
100 DerivedVars->BasePW = 0;
101 /* If anyone is listening, let them know something is wrong */
102 // sendError(BPW_NOT_CONFIGURED_CODE); // or maybe queue it?
105 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
110 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&& Apply All Corrections PCFC, ETE, IDT, TFC etc &&&&&&&&&&&&&&&&&&&&&&&&&&&*/
112 /* Apply the corrections after calculating */
113 DerivedVars->FinalPW = DerivedVars->BasePW;
114 DerivedVars->FinalPW += DerivedVars->TFCTotal; /** @todo TODO check for overflow when TFC is positive and underflow when negative */
115 DerivedVars->FinalPW += DerivedVars->ETE; /** @todo TODO check for overflow of ETE always */
118 unsigned char channel; // the declaration of this variable is used in multiple loops below.
119 #define oneHundredPercentPCFT 32768 /** @todo TODO move oneHundredPercentPCFT to a header with all other #defines found in code */
121 /* "Calculate" the individual fuel pulse widths */
122 for(channel = 0; channel < INJECTION_CHANNELS; channel++){ /// @todo TODO make injector channels come from config, not defines.
123 /* Add or subtract the per cylinder fuel trims */
124 unsigned short trimmedPW;
125 trimmedPW = ((unsigned long)DerivedVars->FinalPW * TablesB.SmallTablesB.perCylinderFuelTrims[channel]) / oneHundredPercentPCFT;
127 /* Check for overflow */
128 unsigned short absoluteLastPW;
129 /* If the trim is greater than 100% then the trimmedPW MUST be larger */
130 /* If it's less than 100% it can't have overflowed */ /* If it's not larger, it overflowed */
131 if((TablesB.SmallTablesB.perCylinderFuelTrims[channel] > oneHundredPercentPCFT) && (DerivedVars->FinalPW > trimmedPW)){
132 absoluteLastPW = SHORTMAX; /* So max it out! */
133 }else{
134 /* Add on the IDT and check again */
135 unsigned short withIDTPW = trimmedPW + DerivedVars->IDT;
136 if(trimmedPW > withIDTPW){ /* If it's not larger, it overflowed */
137 absoluteLastPW = SHORTMAX; /* So max it out! */
138 }else{
139 absoluteLastPW = withIDTPW;
143 /* Load the final value with trim and opening time checked for overflow into the array */
144 injectorMainPulseWidthsMath[channel] = absoluteLastPW;
147 /* Reference PW for comparisons etc */
148 unsigned short refPW = DerivedVars->FinalPW + DerivedVars->IDT;
149 if(DerivedVars->FinalPW > refPW){ /* If it's not larger, it overflowed */
150 refPW = SHORTMAX; /* So max it out! */
152 DerivedVars->RefPW = refPW;
153 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
158 /*&&&&&&&&&&&&&&&&& Based on IDT schedule PW start such that Fuel is correctly timed &&&&&&&&&&&&&&&&&&&*/
160 for(channel = 0;channel < INJECTION_CHANNELS;channel++){ /// @todo TODO make injector channels come from config, not defines.
161 //injectorMainAdvances[channel] = IDT blah blah.
164 /* This will involve using RPM, injector firing angle and IDT to schedule the events correctly */
166 /** @todo TODO work needs to be done on scheduling before this can be completed. */
168 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
173 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Calculate Dwell and Ignition angle &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
174 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
179 /*&&&&&&&&&&&&&&& Based on Dwell and Ignition angle schedule the start and end of dwell &&&&&&&&&&&&&&&&*/
180 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
185 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TEMPORARY (and old) &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
187 /* "Calculate" the nominal total pulse width before per channel corrections */
188 masterPulseWidth = (ADCArrays->EGO << 6) + (ADCArrays->MAP >> 4);
190 /* "Calculate" the individual fuel pulse widths */
191 for(channel = 0; channel < INJECTION_CHANNELS; channel++){
192 injectorMainPulseWidthsMath[channel] = masterPulseWidth;
195 /// @todo TODO x 6 main pulsewidths, x 6 staged pulsewidths, x 6 flags for staged channels if(coreSettingsA & STAGED_ON){}
197 /* Set the staged status on or off (for now based on changeable settings) */
198 if(fixedConfigs1.coreSettingsA & STAGED_ON){
199 coreStatusA |= STAGED_REQUIRED;
200 /// @todo TODO determine the requirement for staged based on some sort of map and or complex load based configuration.
201 }else{
202 coreStatusA &= STAGED_NOT_REQUIRED;
205 // temporary ign tests
206 unsigned short intendedAdvance = ADCArrays->MAT << 6;
207 unsigned short intendedDwell = intendedAdvance >> 1;
209 short c;
210 for(c=0;c<IGNITION_CHANNELS;c++){
211 ignitionAdvances[IGNITION_CHANNELS] = intendedAdvance;
213 *currentDwellMath = intendedDwell;
215 // unsigned short minPeriod = ignitionMinimumDwell << 1;
216 // if(intendedDwell < ignitionMinimumDwell){
217 // dwellLength = ignitionMinimumDwell;
218 // }else{
219 // dwellLength = intendedDwell;
220 // }
221 // if(intendedPeriod < minPeriod){
222 // dwellPeriod = minPeriod;
223 // }else{
224 // dwellPeriod = intendedPeriod;
225 // }
226 // PITLD0 = dwellPeriod;
228 /** @todo TODO Calculate the fuel advances (six of) */
229 // just use one for all for now...
230 totalAngleAfterReferenceInjection = (ADCArrays->TPS << 6);
232 /** @todo TODO Calculate the dwell period (one of) */
234 /** @todo TODO Calculate the ignition advances (twelve of) */
236 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TEMPORARY END &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/