1 /* FreeEMS - the open source engine management system
3 * Copyright 2008-2012 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!
29 * @ingroup measurementsAndCalculations
31 * @brief Generate and average the core variables.
33 * This file contains the function that transfers the raw ADC values to actual
34 * physical measurements and averages them.
40 #define COREVARSGENERATOR_C
41 #include "inc/freeEMS.h"
42 #include "inc/commsCore.h"
43 #include "inc/coreVarsGenerator.h"
44 #include "inc/decoderInterface.h"
47 /** @brief Generate the core variables and average them.
49 * Each raw ADC value is converted to a usable measurement via a variety of
50 * methods chosen at runtime by configured settings. Once in their native units
51 * and therefore closer to maximal use of the available data range they are
54 * @todo TODO incorporate averaging code, right now its a straight copy.
55 * @todo TODO change the way configuration is done and make sure the most common options are after the first if().
56 * @todo TODO add actual configuration options to the fixed config blocks for these items.
60 void generateCoreVars(){
61 /*&&&&&&&& Calculate and obtain the basic variables with which we will perform the calculations &&&&&&&&*/
64 /* Pre calculate things used in multiple places */
66 /* Bound the TPS ADC reading and shift it to start at zero */
67 unsigned short unboundedTPSADC
= ADCBuffers
->TPS
;
68 if(unboundedTPSADC
> fixedConfigs2
.sensorRanges
.TPSMaximumADC
){
69 boundedTPSADC
= TPSADCRange
;
70 }else if(unboundedTPSADC
> fixedConfigs2
.sensorRanges
.TPSMinimumADC
){ // force secondary config to be used... TODO remove this
71 boundedTPSADC
= unboundedTPSADC
- fixedConfigs2
.sensorRanges
.TPSMinimumADC
;
77 /* Get BRV from ADC using transfer variables (all installations need this) */
78 unsigned short localBRV
;
79 if(TRUE
){ /* If BRV connected */
80 /// @todo TODO WARNING: HACK!!! Remove ASAP!!! IE, As Soon As Preston (get's a new cpu on the TA card!)
82 localBRV
= (((unsigned long)ADCBuffers
->MAT
* fixedConfigs2
.sensorRanges
.BRVRange
) / ADC_DIVISIONS
) + fixedConfigs2
.sensorRanges
.BRVMinimum
;
84 localBRV
= (((unsigned long)ADCBuffers
->BRV
* fixedConfigs2
.sensorRanges
.BRVRange
) / ADC_DIVISIONS
) + fixedConfigs2
.sensorRanges
.BRVMinimum
;
86 }else if(FALSE
){ /* Configured to be fixed value */
87 /* Get the preferred BRV figure from configuration settings */
88 localBRV
= fixedConfigs2
.sensorPresets
.presetBRV
;
89 }else{ /* Fail safe if config is broken */
90 /* Default to normal alternator charging voltage 14.4V */
91 localBRV
= VOLTS(14.4);
92 /* If anyone is listening, let them know something is wrong */
93 sendErrorIfClear(BRV_NOT_CONFIGURED_CODE
);
97 unsigned short localCHT
;
98 /* Get CHT from ADC using the transfer table (all installations need this) */
99 if(TRUE
){ /* If CHT connected */
100 localCHT
= CHTTransferTable
[ADCBuffers
->CHT
];
101 }else if(FALSE
){ /* Configured to be read From ADC as dashpot */
102 /* Transfer the ADC reading to an engine temperature in a reasonable way */
103 localCHT
= (ADCBuffers
->CHT
* 10) + DEGREES_C(0); /* 0 ADC = 0C = 273.15K = 27315, 1023 ADC = 102.3C = 375.45K = 37545 */
104 }else if(FALSE
){ /* Configured to be fixed value */
105 /* Get the preferred CHT figure from configuration settings */
106 localCHT
= fixedConfigs2
.sensorPresets
.presetCHT
;
107 }else{ /* Fail safe if config is broken */
108 /* Default to normal running temperature of 85C/358K */
109 localCHT
= DEGREES_C(85);
110 /* If anyone is listening, let them know something is wrong */
111 sendErrorIfClear(CHT_NOT_CONFIGURED_CODE
);
115 unsigned short localIAT
;
116 /* Get IAT from ADC using the transfer table (all installations need this) */
117 if(TRUE
){ /* If IAT connected */ /* using false here causes iat to default to room temp, useful with heatsoaked OEM sensors like the Volvo's... */
118 localIAT
= IATTransferTable
[ADCBuffers
->IAT
];
119 }else if(FALSE
){ /* Configured to be read From ADC as dashpot */
120 /* Transfer the ADC reading to an air temperature in a reasonable way */
121 localIAT
= (ADCBuffers
->IAT
* 10) + 27315; /* 0 ADC = 0C = 273.15K = 27315, 1023 ADC = 102.3C = 375.45K = 37545 */
122 }else if(FALSE
){ /* Configured to be fixed value */
123 /* Get the preferred IAT figure from configuration settings */
124 localIAT
= fixedConfigs2
.sensorPresets
.presetIAT
;
125 }else{ /* Fail safe if config is broken */
126 /* Default to room temperature (20C/293K) TODO poor choice, fix. */
127 localIAT
= DEGREES_C(20);
128 /* If anyone is listening, let them know something is wrong */
129 sendErrorIfClear(IAT_NOT_CONFIGURED_CODE
);
133 unsigned short localMAT
;
134 /* Determine the MAT reading for future calculations */
135 if(TRUE
){ /* If MAT sensor is connected */
136 /* Get MAT from ADC using same transfer table as IAT (too much space to waste on having two) */
137 localMAT
= IATTransferTable
[ADCBuffers
->MAT
];
138 }else if(FALSE
){ /* Configured to be fixed value */
139 /* Get the preferred MAT figure from configuration settings */
140 localMAT
= fixedConfigs2
.sensorPresets
.presetMAT
;
141 }else{ /* Fail safe if config is broken */
142 /* If not, default to same value as IAT */
144 /* If anyone is listening, let them know something is wrong */
145 sendErrorIfClear(MAT_NOT_CONFIGURED_CODE
);
149 unsigned short localMAP
;
150 unsigned short localIAP
;
151 /* Determine the MAP pressure to use for future calculations */
152 if(TRUE
){ /* If MAP sensor is connected */
153 /* get MAP from ADC using transfer variables */
154 localMAP
= (((unsigned long)ADCBuffers
->MAP
* fixedConfigs2
.sensorRanges
.MAPRange
) / ADC_DIVISIONS
) + fixedConfigs2
.sensorRanges
.MAPMinimum
;
155 if(TRUE
){ /* If Intercooler boost sensor connected */
156 /* Get IAP from ADC using the same transfer variables as they both need to read the same range */
157 localIAP
= (((unsigned long)ADCBuffers
->IAP
* fixedConfigs2
.sensorRanges
.MAPRange
) / ADC_DIVISIONS
) + fixedConfigs2
.sensorRanges
.MAPMinimum
;
159 }else if(FALSE
){ /* Configured for MAP to imitate TPS signal */
160 /* Get MAP from TPS via conversion */
161 localMAP
= (((unsigned long)boundedTPSADC
* TPSMAPRange
) / TPSADCRange
) + fixedConfigs2
.sensorRanges
.TPSClosedMAP
;
162 }else if(FALSE
){ /* Configured for dash potentiometer on ADC */
163 /* Get MAP from ADC via conversion to internal kPa figure where 1023ADC = 655kPa */
164 localMAP
= ADCBuffers
->MAP
<< 6;
165 if(TRUE
){ /* If Intercooler boost sensor enabled */
166 /* Get IAP from ADC via conversion to internal kPa figure where 1023ADC = 655kPa */
167 localIAP
= ADCBuffers
->IAP
<< 6;
169 }else if(FALSE
){ /* Configured for fixed MAP from config */
170 /* Get the preferred MAP figure from configuration settings */
171 localMAP
= fixedConfigs2
.sensorPresets
.presetMAP
;
172 }else{ /* Fail safe if config is broken */
173 /* Default to zero to nulify all other calcs and effectively cut fuel */
175 /* If anyone is listening, let them know something is wrong */
176 sendErrorIfClear(MAP_NOT_CONFIGURED_CODE
); // or maybe queue it?
180 /* Determine MAF variable if required */
181 unsigned short localMAF
= 0; // Default to zero as it is not required for anything except main PW calcs optionally
183 localMAF
= MAFTransferTable
[ADCBuffers
->MAF
];
186 unsigned short localAAP
;
187 /* Determine the Atmospheric pressure to use for future calculations */
188 if(TRUE
){ /* Configured for second sensor to read AAP */
189 /* get AAP from ADC using separate vars to allow 115kPa sensor etc to be used */
190 localAAP
= (((unsigned long)ADCBuffers
->AAP
* fixedConfigs2
.sensorRanges
.AAPRange
) / ADC_DIVISIONS
) + fixedConfigs2
.sensorRanges
.AAPMinimum
;
191 }else if(FALSE
){ /* Configured for dash potentiometer on ADC */
192 /* Get AAP from ADC via conversion to internal kPa figure where 1023ADC = 102.3kPa */
193 localAAP
= ADCBuffers
->AAP
* 10;
194 }else if(FALSE
){ /* Configured for fixed AAP from config */
195 /* Get the preferred AAP figure from configuration settings */
196 localAAP
= fixedConfigs2
.sensorPresets
.presetAAP
;
197 }else{ /* Fail safe if config is broken */
198 /* Default to sea level */
200 /* If anyone is listening, let them know something is wrong */
201 sendErrorIfClear(AAP_NOT_CONFIGURED_CODE
); // or maybe queue it?
205 unsigned short localEGO
;
206 /* Get main Lambda reading */
207 if(TRUE
){ /* If WBO2-1 is connected */
208 /* Get EGO from ADCs using transfer variables */
209 localEGO
= (((unsigned long)ADCBuffers
->EGO
* fixedConfigs2
.sensorRanges
.EGORange
) / ADC_DIVISIONS
) + fixedConfigs2
.sensorRanges
.EGOMinimum
;
210 }else if(FALSE
){ /* Configured for fixed EGO from config */
211 /* Get the preferred EGO figure from configuration settings */
212 localEGO
= fixedConfigs2
.sensorPresets
.presetEGO
;
213 }else{ /* Default value if not connected incase other things are misconfigured */
214 /* Default to stoichiometric */
215 localEGO
= LAMBDA(1.0);
216 /* If anyone is listening, let them know something is wrong */
217 sendErrorIfClear(EGO_NOT_CONFIGURED_CODE
); // or maybe queue it?
221 unsigned short localEGO2
;
222 /* Get second Lambda reading */
223 if(TRUE
){ /* If WBO2-2 is connected */
224 /* Get EGO2 from ADCs using same transfer variables as EGO */
225 localEGO2
= (((unsigned long)ADCBuffers
->EGO2
* fixedConfigs2
.sensorRanges
.EGORange
) / ADC_DIVISIONS
) + fixedConfigs2
.sensorRanges
.EGOMinimum
;
226 }else if(FALSE
){ /* Configured for fixed EGO2 from config */
227 /* Get the preferred EGO2 figure from configuration settings */
228 localEGO2
= fixedConfigs2
.sensorPresets
.presetEGO2
;
229 }else{ /* Default value if not connected incase other things are misconfigured */
230 /* Default to stoichiometric */
231 localEGO2
= LAMBDA(1.0);
232 /* If anyone is listening, let them know something is wrong */
233 sendErrorIfClear(EGO2_NOT_CONFIGURED_CODE
); // or maybe queue it?
237 unsigned short localTPS
;
238 /* Get TPS percentage */
239 if(TRUE
){ /* If TPS is connected */
240 /* Get TPS from ADC no need to add TPS min as we know it is zero by definition */
241 localTPS
= ((unsigned long)boundedTPSADC
* PERCENT(100)) / TPSADCRange
;
242 }else if(FALSE
){ /* Configured for TPS to imitate MAP signal */
243 /* Get TPS from MAP via conversion */
244 /* Box MAP signal down */
245 if(localTPS
> fixedConfigs2
.sensorRanges
.TPSOpenMAP
){ /* Greater than ~95kPa */
246 localTPS
= PERCENT(100);
247 }else if(localTPS
< fixedConfigs2
.sensorRanges
.TPSClosedMAP
){ /* Less than ~30kPa */
249 }else{ /* Scale MAP range to TPS range */
250 localTPS
= localMAP
- fixedConfigs2
.sensorRanges
.TPSClosedMAP
;
252 // get TPS from MAP no need to add TPS min as we know it is zero by definition
253 localTPS
= ((unsigned long)localTPS
* PERCENT(100)) / (fixedConfigs2
.sensorRanges
.TPSOpenMAP
- fixedConfigs2
.sensorRanges
.TPSClosedMAP
);
254 }else if(FALSE
){ /* Configured for dash potentiometer on ADC */
255 /* Get TPS from ADC as shown : 1023 ADC = 100%, 0 ADC = 0% */
256 localTPS
= ((unsigned long)ADCBuffers
->TPS
* PERCENT(100)) / ADC_DIVISIONS
;
257 }else if(FALSE
){ /* Configured for fixed TPS from config */
258 /* Get the preferred TPS figure from configuration settings */
259 localTPS
= fixedConfigs2
.sensorPresets
.presetTPS
;
260 }else{ /* Fail safe if config is broken */
261 /* Default to 50% to not trigger any WOT or CT conditions */
262 localTPS
= PERCENT(50); // TODO YAGNI?
263 /* If anyone is listening, let them know something is wrong */
264 sendErrorIfClear(TPS_NOT_CONFIGURED_CODE
); // or maybe queue it?
268 /* Get RPM by locking out ISRs for a second and grabbing the Tooth logging data */
273 // Calculate RPM and delta RPM and delta delta RPM from data recorded
274 if(*ticksPerDegree
!= 0){
275 CoreVars
->RPM
= (unsigned short)(degreeTicksPerMinute
/ *ticksPerDegree
);
280 CoreVars
->DRPM
= *ticksPerDegree
;
281 // unsigned short localDRPM = 0;
282 // unsigned short localDDRPM = 0;
285 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
290 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&& Average the variables as per the configuration &&&&&&&&&&&&&&&&&&&&&&&&&&*/
291 /* Strictly speaking only the primary variables need to be averaged. After that, the derived ones are */
292 /* already averaged in a way. However, there may be some advantage to some short term averaging on the */
293 /* derived ones also, so it is something to look into later. */
295 /// @todo TODO average the generated values here
297 // newVal var word ' the value from the ADC
298 // smoothed var word ' a nicely smoothed result
300 // if newval > smoothed then
301 // smoothed = smoothed + (newval - smoothed)/alpha
303 // smoothed = smoothed - (smoothed - newval)/alpha
306 // from : http://www.tigoe.net/pcomp/code/category/code/arduinowiring/41
308 // for now just copy them in.
309 CoreVars
->IAT
= localIAT
;
310 CoreVars
->CHT
= localCHT
;
311 CoreVars
->TPS
= localTPS
;
312 CoreVars
->EGO
= localEGO
;
313 CoreVars
->BRV
= localBRV
;
314 CoreVars
->MAP
= localMAP
;
315 CoreVars
->AAP
= localAAP
;
316 CoreVars
->MAT
= localMAT
;
318 CoreVars
->EGO2
= localEGO2
;
319 CoreVars
->IAP
= localIAP
;
320 CoreVars
->MAF
= localMAF
;
321 // CoreVars->DRPM = localDRPM;
322 // CoreVars->DDRPM = localDDRPM;
323 // CoreVars->DTPS = localDTPS;
327 for(i
=0;i
<sizeof(CoreVar
);i
++){ // TODO
328 /* Perform averaging on all primary variables as per the configuration array */
330 // process new and old to produce result based on config array value */
331 // assign result to old value holder
334 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/