00001 /* fuelAndIgnitionCalcs.c 00002 00003 Copyright 2008 Fred Cooke 00004 00005 This file is part of the FreeEMS project. 00006 00007 FreeEMS software is free software: you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation, either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 FreeEMS software is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with any FreeEMS software. If not, see <http://www.gnu.org/licenses/>. 00019 00020 We ask that if you make any changes to this file you send them upstream to us at admin@diyefi.org 00021 00022 Thank you for choosing FreeEMS to run your engine! */ 00023 00024 #define FUELANDIGNITIONCALCS_C 00025 #include "inc/freeEMS.h" 00026 #include "inc/commsCore.h" 00027 #include "inc/tableLookup.h" 00028 #include "inc/fuelAndIgnitionCalcs.h" 00029 00030 /* Based on the latest ADC readings, determine pulsewidth, dwell, and advance for all channels */ 00031 void calculateFuelAndIgnition(){ 00032 /*&&&&&&&&&&&&& Perform the basic calculations one step at a time to get a final pulsewidth &&&&&&&&&&&&*/ 00033 00034 if(TRUE /* Genuine method */){ 00035 unsigned short airInletTemp = CoreVars.IAT[mathInternalBank]; /* All except MAF use this. */ 00036 /* Determine the type of air flow data */ 00037 if(TRUE /* SpeedDensity */){ 00038 /* This won't overflow until 512kPa or about 60psi of boost with 128% VE. */ 00039 DerivedVars.AirFlow[mathInternalBank] = ((unsigned long)CoreVars.MAP[mathInternalBank] * DerivedVars.VEMain[mathInternalBank]) / oneHundredPercentVE; 00040 /* Result is 450 - 65535 always. */ 00041 }else if(FALSE /*AlphaN*/){ 00042 DerivedVars.AirFlow[mathInternalBank] = DerivedVars.VEMain[mathInternalBank]; /* Not actually VE, but rather tuned air flow without density information */ 00043 }else if(FALSE /*MAF*/){ 00044 DerivedVars.AirFlow[mathInternalBank] = CoreVars.MAF[mathInternalBank]; /* Just fix temperature at appropriate level to provide correct Lambda */ 00045 // TODO figure out what the correct "temperature" is to make MAF work correctly! 00046 airInletTemp = roomTemperature; // 293.15k is 20c * 100 to get value, so divide by 100 to get real number 00047 }else if(FALSE /*FixedAF*/){ /* Fixed air flow from config */ 00048 DerivedVars.AirFlow[mathInternalBank] = fixedConfigs.presetAF; 00049 }else{ /* Default to no fuel delivery and error */ 00050 DerivedVars.AirFlow[mathInternalBank] = 0; 00051 /* If anyone is listening, let them know something is wrong */ 00052 // sendError(AIRFLOW_NOT_CONFIGURED_CODE); // or maybe queue it? 00053 } 00054 00055 00056 /* This won't overflow until well past 125C inlet, 1.5 Lambda and fuel as dense as water */ 00057 DerivedVars.densityAndFuel[mathInternalBank] = (((unsigned long)((unsigned long)airInletTemp * DerivedVars.Lambda[mathInternalBank]) / stoichiometricLambda) * fixedConfigs.densityOfFuelAtSTP) / densityOfFuelTotalDivisor; 00058 /* Result is 7500 - 60000 always. */ 00059 00060 /* Divisors for air inlet temp and pressure : 00061 * #define airInletTempDivisor 100 00062 * #define airPressureDivisor 100 00063 * cancel each other out! all others are used. */ 00064 00065 00066 DerivedVars.BasePW[mathInternalBank] = (bootFuelConst * DerivedVars.AirFlow[mathInternalBank]) / DerivedVars.densityAndFuel[mathInternalBank]; 00067 }else if(FALSE /*configured*/){ /* Fixed PW from config */ 00068 DerivedVars.BasePW[mathInternalBank] = fixedConfigs.presetBPW; 00069 }else{ /* Default to no fuel delivery and error */ 00070 DerivedVars.BasePW[mathInternalBank] = 0; 00071 /* If anyone is listening, let them know something is wrong */ 00072 // sendError(BPW_NOT_CONFIGURED_CODE); // or maybe queue it? 00073 } 00074 00075 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00076 00077 00078 00079 00080 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&& Apply All Corrections PCFC, ETE, IDT, TFC etc &&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00081 00082 /* Apply the corrections after calculating */ 00083 DerivedVars.FinalPW[mathInternalBank] = DerivedVars.BasePW[mathInternalBank]; 00084 DerivedVars.FinalPW[mathInternalBank] += DerivedVars.TFCTotal[mathInternalBank]; /* TODO check for overflow when TFC is positive and underflow when negative */ 00085 DerivedVars.FinalPW[mathInternalBank] += DerivedVars.ETE[mathInternalBank]; /* TODO check for overflow always */ 00086 00087 00088 /* "Calculate" the individual fuel pulse widths */ 00089 unsigned char channel; 00090 /* TODO move this to a header with all other #defines found in code */ 00091 #define oneHundredPercentPCFT 32768 00092 for(channel = 0; channel < INJECTION_CHANNELS; channel++){ // TODO make injector channels come from config, not defines. 00093 /* Add or subtract the per cylinder fuel trims */ 00094 unsigned short trimmedPW; 00095 trimmedPW = ((unsigned long)DerivedVars.FinalPW[mathInternalBank] * SmallTablesBFlash.perCylinderFuelTrims[channel]) / oneHundredPercentPCFT; 00096 00097 /* Check for overflow */ 00098 unsigned short absoluteLastPW; 00099 /* If the trim is greater than 100% then the trimmedPW MUST be larger */ 00100 /* If it's less than 100% it can't have overflowed */ /* If it's not larger, it overflowed */ 00101 if((SmallTablesBFlash.perCylinderFuelTrims[channel] > oneHundredPercentPCFT) && (DerivedVars.FinalPW[mathInternalBank] > trimmedPW)){ 00102 absoluteLastPW = SHORTMAX; /* So max it out! */ 00103 }else{ 00104 /* Add on the IDT and check again */ 00105 unsigned short withIDTPW = trimmedPW + DerivedVars.IDT[mathInternalBank]; 00106 if(trimmedPW > withIDTPW){ /* If it's not larger, it overflowed */ 00107 absoluteLastPW = SHORTMAX; /* So max it out! */ 00108 }else{ 00109 absoluteLastPW = withIDTPW; 00110 } 00111 } 00112 00113 /* Load the final value with trim and opening time checked for overflow into the array */ 00114 injectorMainPulseWidths[channel + mathInternalInjectionOffset] = absoluteLastPW; 00115 } 00116 00117 /* Reference PW for comparisons etc */ 00118 unsigned short refPW = DerivedVars.FinalPW[mathInternalBank] + DerivedVars.IDT[mathInternalBank]; 00119 if(DerivedVars.FinalPW[mathInternalBank] > refPW){ /* If it's not larger, it overflowed */ 00120 refPW = SHORTMAX; /* So max it out! */ 00121 } 00122 DerivedVars.RefPW[mathInternalBank] = refPW; 00123 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00124 00125 00126 00127 00128 /*&&&&&&&&&&&&&&&&& Based on IDT schedule PW start such that Fuel is correctly timed &&&&&&&&&&&&&&&&&&&*/ 00129 00130 // unsigned char channel; 00131 for(channel = 0;channel < INJECTION_CHANNELS;channel++){ // TODO make injector channels come from config, not defines. 00132 //injectorMainAdvances[channel] = IDT blah blah. 00133 } 00134 00135 /* This will involve using RPM, injector firing angle and IDT to schedule the events correctly */ 00136 00137 /* TODO work needs to be done on scheduling before this can be completed. */ 00138 00139 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00140 00141 00142 00143 00144 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Calculate Dwell and Ignition angle &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00145 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00146 00147 00148 00149 00150 /*&&&&&&&&&&&&&&& Based on Dwell and Ignition angle schedule the start and end of dwell &&&&&&&&&&&&&&&&*/ 00151 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00152 00153 00154 00155 00156 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TEMPORARY (and old) &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00157 00158 /* "Calculate" the nominal total pulse width before per channel corrections */ 00159 masterPulseWidth = (ADCArrays.EGO[mathInputBank] << 6) + (ADCArrays.MAP[mathInputBank] >> 4); 00160 00161 /* "Calculate" the individual fuel pulse widths */ 00162 // unsigned char channel; 00163 for(channel = 0; channel < INJECTION_CHANNELS; channel++){ 00164 injectorMainPulseWidths[channel + mathInternalInjectionOffset] = masterPulseWidth; 00165 } 00166 00167 // TODO x 6 main, x 6 staged, x 6 flags for staged if(coreSettingsA & STAGED_ON){} 00168 00169 /* Set the staged status on or off (for now based on changeable settings) */ 00170 if(fixedConfigs.coreSettingsA & STAGED_ON){ 00171 coreStatusA |= STAGED_REQUIRED; 00172 }else{ 00173 coreStatusA &= STAGED_NOT_REQUIRED; 00174 } 00175 00176 // temporary ign tests 00177 unsigned short intendedAdvance = ADCArrays.MAT[mathInputBank] << 6; 00178 unsigned short intendedDwell = intendedAdvance >> 1; 00179 00180 short c; 00181 for(c=0;c<IGNITION_CHANNELS;c++){ 00182 ignitionAdvances[IGNITION_CHANNELS + mathInternalIgnitionOffset] = intendedAdvance; 00183 } 00184 currentDwell[mathInternalBank] = intendedDwell; 00185 00186 // unsigned short minPeriod = ignitionMinimumDwell << 1; 00187 // if(intendedDwell < ignitionMinimumDwell){ 00188 // dwellLength = ignitionMinimumDwell; 00189 // }else{ 00190 // dwellLength = intendedDwell; 00191 // } 00192 // if(intendedPeriod < minPeriod){ 00193 // dwellPeriod = minPeriod; 00194 // }else{ 00195 // dwellPeriod = intendedPeriod; 00196 // } 00197 // PITLD0 = dwellPeriod; 00198 00199 /* Calculate the fuel advances */ 00200 // TODO x 6 00201 // just use one for all for now 00202 totalAngleAfterReferenceInjection = (ADCArrays.TPS[mathInputBank] << 6); 00203 00204 /* Calculate the dwell period */ 00205 // TODO x 1 00206 00207 /* Calculate the ignition advances */ 00208 //TODO x 12 00209 00210 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& TEMPORARY END &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00211 }