00001 /* FreeEMS - the open source engine management system 00002 * 00003 * Copyright 2008, 2009 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 email them upstream to 00021 * us at admin(at)diyefi(dot)org or, even better, fork the code on github.com! 00022 * 00023 * Thank you for choosing FreeEMS to run your engine! 00024 */ 00025 00026 00042 #include "inc/main.h" 00043 00044 00061 int main(){ // TODO maybe move this to paged flash ? 00062 // Set everything up. 00063 init(); 00064 00065 //LongNoTime.timeLong = 54; 00066 // Run forever repeating. 00067 while(TRUE){ 00068 // unsigned short start = realTimeClockMillis; 00069 /* If ADCs require forced sampling, sample now */ 00070 if(coreStatusA & FORCE_READING){ 00071 ATOMIC_START(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00072 /* Atomic block to ensure a full set of readings are taken together */ 00073 00074 /* Check to ensure that a reading wasn't take before we entered a non interruptable state */ 00075 if(coreStatusA & FORCE_READING){ // do we still need to do this TODO ? 00076 00077 sampleEachADC(ADCArraysRecord); // TODO still need to do a pair of loops and clock these two functions for performance. 00078 //sampleLoopADC(&ADCArrays); 00079 resetToNonRunningState(); 00080 Counters.timeoutADCreadings++; 00081 00082 /* Set flag to say calc required */ 00083 coreStatusA |= CALC_FUEL_IGN; 00084 00085 /* Clear force reading flag */ 00086 coreStatusA &= CLEAR_FORCE_READING; 00087 } 00088 00089 ATOMIC_END(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00090 } 00091 00092 /* If required, do main fuel and ignition calcs first */ 00093 if(coreStatusA & CALC_FUEL_IGN){ 00094 ATOMIC_START(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00095 /* Atomic block to ensure that we don't clear the flag for the next data set when things are tight */ 00096 00097 /* Switch input bank so that we have a stable set of the latest data */ 00098 if(ADCArrays == &ADCArrays1){ 00099 RPM = &RPM0; // TODO temp, remove 00100 RPMRecord = &RPM1; // TODO temp, remove 00101 ADCArrays = &ADCArrays0; 00102 ADCArraysRecord = &ADCArrays1; 00103 mathSampleTimeStamp = &ISRLatencyVars.mathSampleTimeStamp0; // TODO temp, remove 00104 mathSampleTimeStampRecord = &ISRLatencyVars.mathSampleTimeStamp1; // TODO temp, remove 00105 }else{ 00106 RPM = &RPM1; // TODO temp, remove 00107 RPMRecord = &RPM0; // TODO temp, remove 00108 ADCArrays = &ADCArrays1; 00109 ADCArraysRecord = &ADCArrays0; 00110 mathSampleTimeStamp = &ISRLatencyVars.mathSampleTimeStamp1; // TODO temp, remove 00111 mathSampleTimeStampRecord = &ISRLatencyVars.mathSampleTimeStamp0; // TODO temp, remove 00112 } 00113 00114 /* Clear the calc required flag */ 00115 coreStatusA &= CLEAR_CALC_FUEL_IGN; 00116 00117 ATOMIC_END(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00118 00119 /* Store the latency from sample time to runtime */ 00120 ISRLatencyVars.mathLatency = TCNT - *mathSampleTimeStamp; 00121 /* Keep track of how many calcs we are managing per second... */ 00122 Counters.calculationsPerformed++; 00123 /* ...and how long they take each */ 00124 unsigned short mathStartTime = TCNT; 00125 00126 /* Generate the core variables from sensor input and recorded tooth timings */ 00127 generateCoreVars(); 00128 00129 RuntimeVars.genCoreVarsRuntime = TCNT - mathStartTime; 00130 unsigned short derivedStartTime = TCNT; 00131 00132 /* Generate the derived variables from the core variables based on settings */ 00133 generateDerivedVars(); 00134 00135 RuntimeVars.genDerivedVarsRuntime = TCNT - derivedStartTime; 00136 unsigned short calcsStartTime = TCNT; 00137 00138 /* Perform the calculations TODO possibly move this to the software interrupt if it makes sense to do so */ 00139 calculateFuelAndIgnition(); 00140 00141 RuntimeVars.calcsRuntime = TCNT - calcsStartTime; 00142 /* Record the runtime of all the math total */ 00143 RuntimeVars.mathTotalRuntime = TCNT - mathStartTime; 00144 00145 RuntimeVars.mathSumRuntime = RuntimeVars.calcsRuntime + RuntimeVars.genCoreVarsRuntime + RuntimeVars.genDerivedVarsRuntime; 00146 00147 ATOMIC_START(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00148 /* Atomic block to ensure that outputBank and outputBank Offsets match */ 00149 00150 /* Switch banks to the latest data */ 00151 if(injectorMainPulseWidthsMath == injectorMainPulseWidths1){ 00152 currentDwellMath = ¤tDwell0; 00153 currentDwellRealtime = ¤tDwell1; 00154 injectorMainPulseWidthsMath = injectorMainPulseWidths0; 00155 injectorMainPulseWidthsRealtime = injectorMainPulseWidths1; 00156 injectorStagedPulseWidthsMath = injectorStagedPulseWidths0; 00157 injectorStagedPulseWidthsRealtime = injectorStagedPulseWidths1; 00158 }else{ 00159 currentDwellMath = ¤tDwell1; 00160 currentDwellRealtime = ¤tDwell0; 00161 injectorMainPulseWidthsMath = injectorMainPulseWidths1; 00162 injectorMainPulseWidthsRealtime = injectorMainPulseWidths0; 00163 injectorStagedPulseWidthsMath = injectorStagedPulseWidths1; 00164 injectorStagedPulseWidthsRealtime = injectorStagedPulseWidths0; 00165 } 00166 00167 ATOMIC_END(); /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 00168 }else{ 00169 /* In the event that no calcs are required, sleep a little before returning to retry. */ 00170 sleepMicro(RuntimeVars.mathTotalRuntime); // not doing this will cause the ISR lockouts to run for too high a proportion of the time 00171 /* Using 0.8 ticks as micros so it will run for a little longer than the math did */ 00172 } 00173 00174 00175 if(!(TXBufferInUseFlags)){ 00176 // unsigned short logTimeBuffer = Clocks.realTimeClockTenths; 00177 /* If the flag for com packet processing is set and the TX buffer is available process the data! */ 00178 if(RXStateFlags & RX_READY_TO_PROCESS){ 00179 /* Clear the flag */ 00180 RXStateFlags &= RX_CLEAR_READY_TO_PROCESS; 00181 00182 /* Handle the incoming packet */ 00183 decodePacketAndRespond(); 00184 }else if(ShouldSendLog){//(lastTime != logTimeBuffer) && (lastCalcCount != Counters.calculationsPerformed)){ 00185 00186 /* send asynchronous data log if required */ 00187 if(asyncDatalogType!= asyncDatalogOff){ 00188 switch (asyncDatalogType) { 00189 case asyncDatalogBasic: 00190 { 00191 /* Flag that we are transmitting! */ 00192 TXBufferInUseFlags |= COM_SET_SCI0_INTERFACE_ID; 00193 // SCI0 only for now... 00194 00195 // headers including length... *length = configuredBasicDatalogLength; 00196 TXBufferCurrentPositionHandler = (unsigned char*)&TXBuffer; 00197 00198 /* Initialised here such that override is possible */ 00199 TXBufferCurrentPositionSCI0 = (unsigned char*)&TXBuffer; 00200 TXBufferCurrentPositionCAN0 = (unsigned char*)&TXBuffer; 00201 00202 /* Set the flags : firmware, no ack, no addrs, has length */ 00203 *TXBufferCurrentPositionHandler = HEADER_HAS_LENGTH; 00204 TXBufferCurrentPositionHandler++; 00205 00206 /* Set the payload ID */ 00207 *((unsigned short*)TXBufferCurrentPositionHandler) = responseBasicDatalog; 00208 TXBufferCurrentPositionHandler += 2; 00209 00210 /* Set the length */ 00211 *((unsigned short*)TXBufferCurrentPositionHandler) = configuredBasicDatalogLength; 00212 TXBufferCurrentPositionHandler += 2; 00213 00214 /* populate data log */ 00215 populateBasicDatalog(); 00216 checksumAndSend(); 00217 break; 00218 } 00219 case asyncDatalogConfig: 00220 { 00221 // TODO 00222 break; 00223 } 00224 case asyncDatalogTrigger: 00225 { 00226 // TODO 00227 break; 00228 } 00229 case asyncDatalogADC: 00230 { 00231 // TODO 00232 break; 00233 } 00234 case asyncDatalogCircBuf: 00235 { 00236 // TODO 00237 break; 00238 } 00239 case asyncDatalogCircCAS: 00240 { 00241 // TODO 00242 break; 00243 } 00244 case asyncDatalogLogic: 00245 { 00246 // TODO 00247 break; 00248 } 00249 } 00250 } 00251 //ShouldSendLog = FALSE; 00252 // // mechanism to ensure we send once per clock tick without doing it in the RTC section. 00253 // lastTime = logTimeBuffer; 00254 // // mechanism to ensure we only send something if the data has been updated 00255 // lastCalcCount = Counters.calculationsPerformed; 00256 } 00257 } 00258 // on once per cycle for main loop heart beat (J0) 00259 PORTJ ^= 0x01; 00260 00261 00262 // debug... 00263 if(SCI0CR2 & SCICR2_RX_ENABLE){ 00264 PORTK |= BIT2; 00265 }else{ 00266 PORTK &= NBIT2; 00267 } 00268 00269 if(SCI0CR2 & SCICR2_RX_ISR_ENABLE){ 00270 PORTK |= BIT3; 00271 }else{ 00272 PORTK &= NBIT3; 00273 } 00274 00275 // PWM experimentation 00276 adjustPWM(); 00277 } 00278 }