#include "inc/freeEMS.h"
#include "inc/interrupts.h"
#include "inc/utils.h"
#include "inc/commsISRs.h"
#include "inc/enginePositionISRs.h"
Include dependency graph for enginePositionISRs.c:
Go to the source code of this file.
Defines | |
#define | ENGINEPOSITIONISRS_C |
Functions | |
void | PrimaryRPMISR (void) |
void | SecondaryRPMISR (void) |
#define ENGINEPOSITIONISRS_C |
Definition at line 24 of file enginePositionISRs.c.
void PrimaryRPMISR | ( | void | ) |
Definition at line 48 of file enginePositionISRs.c.
References ADCArrays, CALC_FUEL_IGN, CLEAR_PRIMARY_SYNC, Clocks, fixedConfig::combustionEventsPerEngineCycle, fixedConfig::coreSettingsA, coreStatusA, Counters, DWELL_ENABLE, dwellQueueLength, engineCyclePeriod, fixedConfigs, IGNITION_ENABLE, ignitionQueueLength, injectorMainControlRegisters, injectorMainEnableMasks, injectorMainEndTimes, injectorMainOnMasks, injectorMainPulseWidths, injectorMainStartTimesHolding, injectorMainTimeRegisters, injectorMinimumPulseWidth, injectorSwitchOffCodeTime, ISRLatencyVars, lastPrimaryPulseTimeStamp, LONGHALF, Counter::lostCrankSyncCounter, masterPulseWidth, ISRLatencyVar::mathSampleTimeStamp, nextDwellChannel, nextIgnitionChannel, PITCE, PITCNT0, PITCNT1, PITINTE, PITLD0, PITLD1, PITTF, PORTJ, PRIMARY_POLARITY, PRIMARY_SYNC, ISRLatencyVar::primaryInputLatency, RuntimeVar::primaryInputLeadingRuntime, RuntimeVar::primaryInputTrailingRuntime, primaryLeadingEdgeTimeStamp, primaryPulsesPerSecondaryPulse, Counter::primaryTeethCounter, primaryTeethDroppedFromLackOfSync, PTIT, queuedDwellOffsets, queuedIgnitionOffsets, recordADCBank, RPM, RuntimeVars, sampleLoopADC(), selfSetTimer, Counter::syncedADCreadingCounter, TC0, TCNT, TFLG, TFLGOF, ticksPerCycleAtOneRPMx2, TIE, timeBetweenSuccessivePrimaryPulses, timeBetweenSuccessivePrimaryPulsesBuffer, LongTime::timeLong, Clock::timeoutADCreadingClock, timerExtensionClock, LongTime::timeShorts, totalAngleAfterReferenceInjection, and trailingEdgeSecondaryRPMInputCodeTime.
00049 { 00050 /* Clear the interrupt flag for this input compare channel */ 00051 TFLG = 0x01; 00052 00053 /* Save all relevant available data here */ 00054 unsigned short codeStartTimeStamp = TCNT; /* Save the current timer count */ 00055 unsigned short edgeTimeStamp = TC0; /* Save the edge time stamp */ 00056 unsigned char PTITCurrentState = PTIT; /* Save the values on port T regardless of the state of DDRT */ 00057 // unsigned short PORTS_BACurrentState = PORTS_BA; /* Save ignition output state */ 00058 00059 /* Calculate the latency in ticks */ 00060 ISRLatencyVars.primaryInputLatency = codeStartTimeStamp - edgeTimeStamp; 00061 00062 // TODO discard narrow ones! test for tooth width and tooth period 00063 00064 /* Set up edges as per config */ 00065 unsigned char risingEdge; 00066 if(fixedConfigs.coreSettingsA & PRIMARY_POLARITY){ 00067 risingEdge = PTITCurrentState & 0x01; 00068 }else{ 00069 risingEdge = !(PTITCurrentState & 0x01); 00070 } 00071 00072 if(risingEdge){ 00073 /* Echo input condition on J7 */ 00074 PORTJ |= 0x80; 00075 00076 // increment crank pulses TODO this needs to be wrapped in tooth period and width checking 00077 primaryPulsesPerSecondaryPulse++; 00078 00079 // calculate rough rpm (this will be wrong when the var is used correctly) 00080 RPM[recordADCBank] = ticksPerCycleAtOneRPMx2 / engineCyclePeriod; /* 0.8us ticks, 150mil = 2 x 60 seconds, times rpm scale factor of 2 */ 00081 00082 // don't run until the second trigger has come in and the period is correct (VERY temporary) 00083 if(!(coreStatusA & PRIMARY_SYNC)){ 00084 primaryTeethDroppedFromLackOfSync++; 00085 return; 00086 } 00087 00088 LongTime timeStamp; 00089 00090 /* Install the low word */ 00091 timeStamp.timeShorts[1] = edgeTimeStamp; 00092 /* Find out what our timer value means and put it in the high word */ 00093 if(TFLGOF && !(edgeTimeStamp & 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */ 00094 timeStamp.timeShorts[0] = timerExtensionClock + 1; 00095 }else{ 00096 timeStamp.timeShorts[0] = timerExtensionClock; 00097 } 00098 00099 // temporary data from inputs 00100 primaryLeadingEdgeTimeStamp = edgeTimeStamp; 00101 timeBetweenSuccessivePrimaryPulses = lastPrimaryPulseTimeStamp - primaryLeadingEdgeTimeStamp; 00102 lastPrimaryPulseTimeStamp = primaryLeadingEdgeTimeStamp; 00103 timeBetweenSuccessivePrimaryPulsesBuffer = (timeBetweenSuccessivePrimaryPulses >> 1) + (timeBetweenSuccessivePrimaryPulsesBuffer >> 1); 00104 00105 // TODO make scheduling either fixed from boot with a limited range, OR preferrably if its practical scheduled on the fly to allow arbitrary advance and retard of both fuel and ignition. 00106 00107 /* Check for loss of sync by too high a count */ 00108 if(primaryPulsesPerSecondaryPulse > 12){ 00109 /* Increment the lost sync count */ 00110 Counters.lostCrankSyncCounter++; 00111 00112 /* Clear synced status */ 00113 coreStatusA &= CLEAR_PRIMARY_SYNC; 00114 00115 /* Reset the count of teeth */ 00116 primaryPulsesPerSecondaryPulse = 0; 00117 00118 /* Get the hell out of here before we do something bad */ 00119 return; 00120 } 00121 00122 // CAUTION came to me lying in bed half asleep idea : 00123 00124 // TODO move tooth selection to the calc loop in main such that this routine just iterates through an array of events and schedules those that are destined for this tooth. 00125 00126 // if ign enabled 00127 // iterate through ignition first, schedule all of those 00128 // iterate through dwell next, schedule all of those 00129 // if fuel enabled 00130 // iterate through main fuel next, schedule all of those 00131 // if staging enabled and required 00132 // iterate through staged fuel last, 00133 00134 // TODO should make for a clean compact scheduling implementation. the fuel code doesn't care when/how it has started in the past, and hopefully ign will be the same. 00135 00136 // this will be done with an array and per tooth check in future 00137 if((primaryPulsesPerSecondaryPulse % 2) == 0){ 00138 00139 // TODO sample ADCs on teeth other than that used by the scheduler in order to minimise peak run time and get clean signals 00140 sampleLoopADC(&ADCArrays); 00141 Counters.syncedADCreadingCounter++; 00142 ISRLatencyVars.mathSampleTimeStamp[recordADCBank] = TCNT; 00143 00144 /* Set flag to say calc required */ 00145 coreStatusA |= CALC_FUEL_IGN; 00146 00147 /* Reset the clock for reading timeout */ 00148 Clocks.timeoutADCreadingClock = 0; 00149 00150 if(masterPulseWidth > injectorMinimumPulseWidth){ // use reference PW to decide. spark needs moving outside this area though TODO 00151 /* Determine if half the cycle is bigger than short-max */ 00152 unsigned short maxAngleAfter; 00153 if((engineCyclePeriod >> 1) > 0xFFFF){ 00154 maxAngleAfter = 0xFFFF; 00155 }else{ 00156 maxAngleAfter = (unsigned short)(engineCyclePeriod >> 1); 00157 } 00158 00159 /* Check advance to ensure it is less than 1/2 of the previous engine cycle and more than codetime away */ 00160 unsigned short advance; 00161 if(totalAngleAfterReferenceInjection > maxAngleAfter){ // if too big, make it max 00162 advance = maxAngleAfter; 00163 }else if(totalAngleAfterReferenceInjection < trailingEdgeSecondaryRPMInputCodeTime){ // if too small, make it min 00164 advance = trailingEdgeSecondaryRPMInputCodeTime; 00165 }else{ // else use it as is 00166 advance = totalAngleAfterReferenceInjection; 00167 } 00168 00169 // determine the long and short start times 00170 unsigned short startTime = primaryLeadingEdgeTimeStamp + advance; 00171 unsigned long startTimeLong = timeStamp.timeLong + advance; 00172 00173 /* Determine the channels to schedule */ 00174 unsigned char fuelChannel = (primaryPulsesPerSecondaryPulse / 2) - 1; 00175 unsigned char ignitionChannel = (primaryPulsesPerSecondaryPulse / 2) - 1; 00176 00177 if(fuelChannel > 5 || ignitionChannel > 5){ 00178 // send("bad fuel : "); 00179 // sendUC(fuelChannel); 00180 // send("bad ign : "); 00181 // sendUC(ignitionChannel); 00182 return; 00183 } 00184 00185 // determine whether or not to reschedule 00186 unsigned char reschedule = 0; 00187 unsigned long diff = startTimeLong - (injectorMainEndTimes[fuelChannel] + injectorSwitchOffCodeTime); 00188 if(diff > LONGHALF){ 00189 reschedule = 1; // http://www.diyefi.org/forum/viewtopic.php?f=8&t=57&p=861#p861 00190 } 00191 00192 // schedule the appropriate channel 00193 if(!(*injectorMainControlRegisters[fuelChannel] & injectorMainEnableMasks[fuelChannel]) || reschedule){ /* If the timer isn't still running, or if its set too long, set it to start again at the right time soon */ 00194 *injectorMainControlRegisters[fuelChannel] |= injectorMainEnableMasks[fuelChannel]; 00195 *injectorMainTimeRegisters[fuelChannel] = startTime; 00196 TIE |= injectorMainOnMasks[fuelChannel]; 00197 TFLG = injectorMainOnMasks[fuelChannel]; 00198 }else{ 00199 injectorMainStartTimesHolding[fuelChannel] = startTime; 00200 selfSetTimer |= injectorMainOnMasks[fuelChannel]; // setup a bit to let the timer interrupt know to set its own new start from a var 00201 } 00202 00203 // TODO advance/retard/dwell numbers all need range checking etc done. some of this should be done in the calculator section, and some here. currently none is done at all and for that reason, this will not work in a real system yet, if it works at all. 00204 // as do array indexs here and in the ISRs... 00205 00206 00207 // TODO implement mechanism for dropping a cylinder in event of over queueing or spark cut/round robin 00208 // important as ignition sequence disrupted when this occurs as it stands. 00209 00210 // TODO check queue length checks to ensure we dont count up to somewhere we can never count down from. This could be causing the hanging long phenomina 00211 00212 // DWELL 00213 00214 // If dwell is not currently enabled, set it all up 00215 if(!(PITCE & DWELL_ENABLE)){ 00216 /* Schedule Dwell event (do this first because it comes earliest. */ 00217 // set the channel to fire 00218 nextDwellChannel = ignitionChannel; 00219 00220 // set the time 00221 PITLD0 = advance; 00222 // PITLD0 = ignitionAdvances[ignitionChannel + outputBankIgnitionOffset] - currentDwell[outputBank]; BAD for various reasons! 00223 00224 // clear the flags first as they apparently become set any old time whether enabled or not. 00225 PITTF |= DWELL_ENABLE; 00226 00227 // turn on the ints 00228 PITINTE |= DWELL_ENABLE; 00229 00230 // clear the flags first as they apparently become set any old time whether enabled or not. 00231 PITTF |= DWELL_ENABLE; 00232 00233 // enable channels 00234 PITCE |= DWELL_ENABLE; 00235 }else if(dwellQueueLength == 0){ 00236 // load time offset such that next period is correct 00237 PITLD0 = (advance - PITCNT0); 00238 00239 // increment queue length 00240 dwellQueueLength++; 00241 }else if(dwellQueueLength > fixedConfigs.combustionEventsPerEngineCycle){ //TODO sensible figures here for array index OOBE 00242 // do nothing, or increment a counter or something similar. 00243 }else{ 00244 unsigned short sumOfDwells = PITLD0; 00245 // add up the prequeued time periods 00246 00247 // queue = 1 pitld is all 00248 // queue = 2 one from 0 index of array AND pitld 00249 00250 unsigned char index = 0; 00251 while(index < (dwellQueueLength -1)){ 00252 sumOfDwells += queuedDwellOffsets[index]; 00253 index++; 00254 } 00255 // for(index = 0;index < (dwellQueueLength -1);index++){ // is this right? 00256 // sumOfDwells += queuedDwellOffsets[index]; 00257 // } 00258 00259 // store time offset in appropriate array location 00260 queuedDwellOffsets[dwellQueueLength - 1] = advance - (PITCNT0 + sumOfDwells); 00261 00262 // increment queue length from one or more 00263 dwellQueueLength++; 00264 } 00265 00266 // IGNITION experimental stuff 00267 00268 // If ignition is not currently enabled, set it all up 00269 if(!(PITCE & IGNITION_ENABLE)){ 00270 /* Schedule Ignition event (do this first because it comes earliest. */ 00271 // set the channel to fire 00272 nextIgnitionChannel = ignitionChannel; 00273 00274 // figure out the time to set the delay reg to 00275 PITLD1 = advance + injectorMainPulseWidths[fuelChannel]; 00276 // PITLD1 = ignitionAdvances[ignitionChannel + outputBankIgnitionOffset]; 00277 00278 // clear the flags first as they apparently become set any old time whether enabled or not. 00279 PITTF |= IGNITION_ENABLE; 00280 00281 // turn on the ints 00282 PITINTE |= IGNITION_ENABLE; 00283 00284 // clear the flags first as they apparently become set any old time whether enabled or not. 00285 PITTF |= IGNITION_ENABLE; 00286 00287 // enable channels 00288 PITCE |= IGNITION_ENABLE; 00289 }else if(ignitionQueueLength == 0){ 00290 // load timer register 00291 PITLD1 = ((advance + injectorMainPulseWidths[fuelChannel]) - PITCNT1); 00292 00293 // increment to 1 00294 ignitionQueueLength++; 00295 }else if(ignitionQueueLength > fixedConfigs.combustionEventsPerEngineCycle){ //TODO sensible figures here for array index OOBE 00296 // do nothing, or increment a counter or something similar. 00297 }else{ 00298 unsigned short sumOfIgnitions = PITLD1; 00299 // add up the prequeued time periods 00300 00301 // queue = 1 pitld is all 00302 // queue = 2 one from 0 index of array AND pitld 00303 00304 00305 unsigned char index = 0; 00306 while(index < (ignitionQueueLength - 1)){ 00307 sumOfIgnitions += queuedIgnitionOffsets[index]; 00308 index++; 00309 } 00310 // for(index = 0;index < (ignitionQueueLength -1);index++){ // is this right? 00311 // sumOfIgnitions += queuedIgnitionOffsets[index]; 00312 // } 00313 00314 // store time offset in appropriate array location 00315 queuedIgnitionOffsets[ignitionQueueLength - 1] = advance - (PITCNT1 + sumOfIgnitions); 00316 00317 // increment from 1 or more 00318 ignitionQueueLength++; 00319 } 00320 } 00321 } 00322 RuntimeVars.primaryInputLeadingRuntime = TCNT - codeStartTimeStamp; 00323 }else{ 00324 PORTJ &= 0x7F; 00325 RuntimeVars.primaryInputTrailingRuntime = TCNT - codeStartTimeStamp; 00326 } 00327 00328 Counters.primaryTeethCounter++; 00329 // suss out rpm and accurate TDC reference 00330 00331 // if you say it quick, it doesn't sound like much : 00332 // schedule fuel and ign based on spark cut and fuel cut and timing vars and status vars config vars 00333 }
Here is the call graph for this function:
void SecondaryRPMISR | ( | void | ) |
Definition at line 335 of file enginePositionISRs.c.
References CLEAR_PRIMARY_SYNC, fixedConfig::coreSettingsA, coreStatusA, Counters, engineCyclePeriod, fixedConfigs, ISRLatencyVars, lastSecondaryOddTimeStamp, Counter::lostCrankSyncCounter, PORTJ, PORTM, PRIMARY_SYNC, primaryPulsesPerSecondaryPulse, primaryPulsesPerSecondaryPulseBuffer, PTIT, RuntimeVars, SECONDARY_POLARITY, ISRLatencyVar::secondaryInputLatency, RuntimeVar::secondaryInputLeadingRuntime, RuntimeVar::secondaryInputTrailingRuntime, Counter::secondaryTeethCounter, TC1, TCNT, TFLG, TFLGOF, LongTime::timeLong, timerExtensionClock, and LongTime::timeShorts.
00336 { 00337 /* Clear the interrupt flag for this input compare channel */ 00338 TFLG = 0x02; 00339 00340 /* Save all relevant available data here */ 00341 unsigned short codeStartTimeStamp = TCNT; /* Save the current timer count */ 00342 unsigned short edgeTimeStamp = TC1; /* Save the timestamp */ 00343 unsigned char PTITCurrentState = PTIT; /* Save the values on port T regardless of the state of DDRT */ 00344 // unsigned short PORTS_BACurrentState = PORTS_BA; /* Save ignition output state */ 00345 00346 /* Calculate the latency in ticks */ 00347 ISRLatencyVars.secondaryInputLatency = codeStartTimeStamp - edgeTimeStamp; 00348 00349 // TODO discard narrow ones! test for tooth width and tooth period 00350 00351 /* Set up edges as per config */ 00352 unsigned char risingEdge; 00353 if(fixedConfigs.coreSettingsA & SECONDARY_POLARITY){ 00354 risingEdge = PTITCurrentState & 0x02; 00355 }else{ 00356 risingEdge = !(PTITCurrentState & 0x02); 00357 } 00358 00359 if(risingEdge){ 00360 // echo input condition 00361 PORTJ |= 0x40; 00362 00363 // display the crank pulses 00364 PORTM = (char)primaryPulsesPerSecondaryPulseBuffer; 00365 00366 primaryPulsesPerSecondaryPulseBuffer = primaryPulsesPerSecondaryPulse; 00367 primaryPulsesPerSecondaryPulse = 0; 00368 00369 // if we didn't get the right number of pulses drop sync and start over 00370 if((primaryPulsesPerSecondaryPulseBuffer != 12) && (coreStatusA & PRIMARY_SYNC)){ 00371 coreStatusA &= CLEAR_PRIMARY_SYNC; 00372 Counters.lostCrankSyncCounter++; 00373 } 00374 00375 LongTime timeStamp; 00376 00377 /* Install the low word */ 00378 timeStamp.timeShorts[1] = edgeTimeStamp; 00379 /* Find out what our timer value means and put it in the high word */ 00380 if(TFLGOF && !(edgeTimeStamp & 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */ 00381 timeStamp.timeShorts[0] = timerExtensionClock + 1; 00382 }else{ 00383 timeStamp.timeShorts[0] = timerExtensionClock; 00384 } 00385 00386 // get the data we actually want 00387 engineCyclePeriod = 2 * (timeStamp.timeLong - lastSecondaryOddTimeStamp); // save the engine cycle period 00388 lastSecondaryOddTimeStamp = timeStamp.timeLong; // save this stamp for next time round 00389 00390 // Because this is our only reference, each time we get this pulse, we know where we are at (simple mode so far) 00391 coreStatusA |= PRIMARY_SYNC; 00392 RuntimeVars.secondaryInputLeadingRuntime = TCNT - codeStartTimeStamp; 00393 }else{ 00394 PORTJ &= 0xBF; 00395 RuntimeVars.secondaryInputTrailingRuntime = TCNT - codeStartTimeStamp; 00396 } 00397 00398 Counters.secondaryTeethCounter++; 00399 // suss out phase/engine cycle reference showing which bank we are on 00400 00401 /* If the flag is not cleared at the beginning then the interrupt gets rescheduled while it is running, hence it can't be done at the end of the ISR */ 00402 }