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.
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.
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! */
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! */
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.
202 coreStatusA
&= STAGED_NOT_REQUIRED
;
205 // temporary ign tests
206 unsigned short intendedAdvance
= ADCArrays
->MAT
<< 6;
207 unsigned short intendedDwell
= intendedAdvance
>> 1;
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;
219 // dwellLength = intendedDwell;
221 // if(intendedPeriod < minPeriod){
222 // dwellPeriod = minPeriod;
224 // dwellPeriod = intendedPeriod;
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 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/