Brought a bunch of files inline with the new doxygen standards.
[freeems-vanilla.git] / src / fuelAndIgnitionCalcs.c
blob133ee609e78066484830f0498dc014502e13f20c
1 /* Copyright 2008 Fred Cooke
3 This file is part of the FreeEMS project.
5 FreeEMS software is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 FreeEMS software is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with any FreeEMS software. If not, see http://www.gnu.org/licenses/
18 We ask that if you make any changes to this file you send them upstream to us at admin@diyefi.org
20 Thank you for choosing FreeEMS to run your engine! */
23 /** @file fuelAndIgnitionCalcs.c
25 * @ingroup measurementsAndCalculations
27 * @brief Fuel and ignition calculations.
29 * This file contains all of the main fuel and ignition calculations based
30 * upon the variables that we have already determined in previous stages.
32 * @author Fred Cooke
36 #define FUELANDIGNITIONCALCS_C
37 #include "inc/freeEMS.h"
38 #include "inc/commsCore.h"
39 #include "inc/tableLookup.h"
40 #include "inc/fuelAndIgnitionCalcs.h"
43 /** Calculate Fuel And Ignition
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 = fixedConfigs1.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.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 = fixedConfigs1.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 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/