Place braces on expressionless loops in utils.
[freeems-vanilla.git] / src / fuelAndIgnitionCalcs.c
blobeaffc216bcbd01c4848da99ab2faa2caed3f3e53
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!
27 /** @file fuelAndIgnitionCalcs.c
28 * @ingroup measurementsAndCalculations
30 * @brief Fuel and ignition calculations.
32 * This file contains all of the main fuel and ignition calculations based
33 * upon the variables that we have already determined in previous stages.
35 * @author Fred Cooke
39 #define FUELANDIGNITIONCALCS_C
40 #include "inc/freeEMS.h"
41 #include "inc/commsCore.h"
42 #include "inc/tableLookup.h"
43 #include "inc/fuelAndIgnitionCalcs.h"
46 /** @brief Fuel and ignition calculations
48 * Using a variety of primary algorithms calculate a base pulsewidth and then
49 * apply various corrections to it such as injector dead time, transient fuel
50 * correction, engine temperature enrichment and per cylinder trims. The fuel
51 * injection timing is also determined here.
53 * Calculate the ignition timing and dwell here too. Several corrections are
54 * applied to these as well.
56 * @todo TODO implement the all of the ignition stuff and finish off all of the fuel injection stuff.
57 * @todo TODO change the way configuration is done and make sure the most common options are after the first if().
58 * @todo TODO add actual configuration options to the fixed config blocks for these items.
60 * @author Fred Cooke
62 void calculateFuelAndIgnition(){
63 /*&&&&&&&&&&&&& Perform the basic calculations one step at a time to get a final pulsewidth &&&&&&&&&&&&*/
65 if(TRUE /* Genuine method */){
66 unsigned short airInletTemp = CoreVars->IAT; /* All except MAF use this. */
67 /* Determine the type of air flow data */
68 if(TRUE /* SpeedDensity */){
69 /* This won't overflow until 512kPa or about 60psi of boost with 128% VE. */
70 DerivedVars->AirFlow = ((unsigned long)CoreVars->MAP * DerivedVars->VEMain) / oneHundredPercentVE;
71 /* Result is 450 - 65535 always. */
72 }else if(FALSE /*AlphaN*/){
73 DerivedVars->AirFlow = DerivedVars->VEMain; /* Not actually VE, but rather tuned air flow without density information */
74 }else if(FALSE /*MAF*/){
75 DerivedVars->AirFlow = CoreVars->MAF; /* Just fix temperature at appropriate level to provide correct Lambda */
76 /// @todo TODO figure out what the correct "temperature" is to make MAF work correctly!
77 airInletTemp = roomTemperature; // 293.15k is 20c * 100 to get value, so divide by 100 to get real number
78 }else if(FALSE /*FixedAF*/){ /* Fixed air flow from config */
79 DerivedVars->AirFlow = fixedConfigs2.sensorPresets.presetAF;
80 }else{ /* Default to no fuel delivery and error */
81 DerivedVars->AirFlow = 0;
82 /* If anyone is listening, let them know something is wrong */
83 // sendError(AIRFLOW_NOT_CONFIGURED_CODE); // or maybe queue it?
87 /* This won't overflow until well past 125C inlet, 1.5 Lambda and fuel as dense as water */
88 DerivedVars->densityAndFuel = (((unsigned long)((unsigned long)airInletTemp * DerivedVars->Lambda) / stoichiometricLambda) * fixedConfigs1.engineSettings.densityOfFuelAtSTP) / densityOfFuelTotalDivisor;
89 /* Result is 7500 - 60000 always. */
91 /* Divisors for air inlet temp and pressure :
92 * #define airInletTempDivisor 100
93 * #define airPressureDivisor 100
94 * cancel each other out! all others are used. */
97 DerivedVars->BasePW = (bootFuelConst * DerivedVars->AirFlow) / DerivedVars->densityAndFuel;
98 }else if(FALSE /*configured*/){ /* Fixed PW from config */
99 DerivedVars->BasePW = fixedConfigs2.sensorPresets.presetBPW;
100 }else{ /* Default to no fuel delivery and error */
101 DerivedVars->BasePW = 0;
102 /* If anyone is listening, let them know something is wrong */
103 // sendError(BPW_NOT_CONFIGURED_CODE); // or maybe queue it?
106 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
111 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&& Apply All Corrections PCFC, ETE, IDT, TFC etc &&&&&&&&&&&&&&&&&&&&&&&&&&&*/
113 /* Apply the corrections after calculating */
114 DerivedVars->FinalPW = DerivedVars->BasePW;
115 DerivedVars->FinalPW += DerivedVars->TFCTotal; /** @todo TODO check for overflow when TFC is positive and underflow when negative */
116 DerivedVars->FinalPW += DerivedVars->ETE; /** @todo TODO check for overflow of ETE always */
119 unsigned char channel; // the declaration of this variable is used in multiple loops below.
120 #define oneHundredPercentPCFT 32768 /** @todo TODO move oneHundredPercentPCFT to a header with all other #defines found in code */
122 /* "Calculate" the individual fuel pulse widths */
123 for(channel = 0; channel < INJECTION_CHANNELS; channel++){ /// @todo TODO make injector channels come from config, not defines.
124 /* Add or subtract the per cylinder fuel trims */
125 unsigned short trimmedPW;
126 trimmedPW = ((unsigned long)DerivedVars->FinalPW * TablesB.SmallTablesB.perCylinderFuelTrims[channel]) / oneHundredPercentPCFT;
128 /* Check for overflow */
129 unsigned short absoluteLastPW;
130 /* If the trim is greater than 100% then the trimmedPW MUST be larger */
131 /* If it's less than 100% it can't have overflowed */ /* If it's not larger, it overflowed */
132 if((TablesB.SmallTablesB.perCylinderFuelTrims[channel] > oneHundredPercentPCFT) && (DerivedVars->FinalPW > trimmedPW)){
133 absoluteLastPW = SHORTMAX; /* So max it out! */
134 }else{
135 /* Add on the IDT and check again */
136 unsigned short withIDTPW = trimmedPW + DerivedVars->IDT;
137 if(trimmedPW > withIDTPW){ /* If it's not larger, it overflowed */
138 absoluteLastPW = SHORTMAX; /* So max it out! */
139 }else{
140 absoluteLastPW = withIDTPW;
144 /* Load the final value with trim and opening time checked for overflow into the array */
145 injectorMainPulseWidthsMath[channel] = absoluteLastPW;
148 /* Reference PW for comparisons etc */
149 unsigned short refPW = DerivedVars->FinalPW + DerivedVars->IDT;
150 if(DerivedVars->FinalPW > refPW){ /* If it's not larger, it overflowed */
151 refPW = SHORTMAX; /* So max it out! */
153 DerivedVars->RefPW = refPW;
154 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
159 /*&&&&&&&&&&&&&&&&& Based on IDT schedule PW start such that Fuel is correctly timed &&&&&&&&&&&&&&&&&&&*/
161 for(channel = 0;channel < INJECTION_CHANNELS;channel++){ /// @todo TODO make injector channels come from config, not defines.
162 //injectorMainAdvances[channel] = IDT blah blah.
165 /* This will involve using RPM, injector firing angle and IDT to schedule the events correctly */
167 /** @todo TODO work needs to be done on scheduling before this can be completed. */
169 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
174 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Calculate Dwell and Ignition angle &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
175 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
180 /*&&&&&&&&&&&&&&& Based on Dwell and Ignition angle schedule the start and end of dwell &&&&&&&&&&&&&&&&*/
181 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
186 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TEMPORARY (and old) &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
188 /* "Calculate" the nominal total pulse width before per channel corrections */
189 masterPulseWidth = (ADCArrays->EGO << 6) + (ADCArrays->MAP >> 4);
191 /* "Calculate" the individual fuel pulse widths */
192 for(channel = 0; channel < INJECTION_CHANNELS; channel++){
193 injectorMainPulseWidthsMath[channel] = masterPulseWidth;
196 /// @todo TODO x 6 main pulsewidths, x 6 staged pulsewidths, x 6 flags for staged channels if(coreSettingsA & STAGED_ON){}
198 /* Set the staged status on or off (for now based on changeable settings) */
199 if(fixedConfigs1.coreSettingsA & STAGED_ON){
200 coreStatusA |= STAGED_REQUIRED;
201 /// @todo TODO determine the requirement for staged based on some sort of map and or complex load based configuration.
202 }else{
203 coreStatusA &= STAGED_NOT_REQUIRED;
206 // temporary ign tests
207 unsigned short intendedAdvance = ADCArrays->MAT << 6;
208 unsigned short intendedDwell = intendedAdvance >> 1;
210 short c;
211 for(c=0;c<IGNITION_CHANNELS;c++){
212 ignitionAdvances[IGNITION_CHANNELS] = intendedAdvance;
214 *currentDwellMath = intendedDwell;
216 // unsigned short minPeriod = ignitionMinimumDwell << 1;
217 // if(intendedDwell < ignitionMinimumDwell){
218 // dwellLength = ignitionMinimumDwell;
219 // }else{
220 // dwellLength = intendedDwell;
221 // }
222 // if(intendedPeriod < minPeriod){
223 // dwellPeriod = minPeriod;
224 // }else{
225 // dwellPeriod = intendedPeriod;
226 // }
227 // PITLD0 = dwellPeriod;
229 /** @todo TODO Calculate the fuel advances (six of) */
230 // just use one for all for now...
231 totalAngleAfterReferenceInjection = (ADCArrays->TPS << 6);
233 /** @todo TODO Calculate the dwell period (one of) */
235 /** @todo TODO Calculate the ignition advances (twelve of) */
237 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TEMPORARY END &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/