Simple.c File Reference

Reads any signal that is once per cylinder. More...

#include "inc/freeEMS.h"
#include "inc/interrupts.h"
#include "inc/utils.h"

Include dependency graph for Simple.c:

Go to the source code of this file.

Defines

#define ticksPerMinute   75000000

Functions

void PrimaryRPMISR ()
void SecondaryRPMISR ()
 Use the rising and falling edges...................


Detailed Description

Reads any signal that is once per cylinder.

This file contains the two interrupt service routines required for to build cleanly. However, only the first one is used due to the simple nature of it.

The functional ISR just blindly injects fuel for every input it receives. Thus a perfectly clean input is absolutely essential at this time.

Supported engines include: B230F

Author:
Fred Cooke
Note:
Even though I ran my US road trip car on this exact code, I don't recommend it unless you REALLY know what you are doing!

Definition in file Simple.c.


Define Documentation

#define ticksPerMinute   75000000

Referenced by PrimaryRPMISR().


Function Documentation

void PrimaryRPMISR ( void   ) 

Primary RPM ISR

Schedule events : Blindly start fuel pulses for each and every input pulse.

Sample ADCs : Grab a unified set of ADC readings at one time in a consistent crank location to eliminate engine cycle dependent noise. Set flag stating that New pulse, advance, etc should be calculated.

Author:
Fred Cooke
Warning:
These are for testing and demonstration only, not suitable for driving with just yet.
Todo:
TODO make this code more general and robust such that it can be used for real simple applications

Todo:
TODO discard narrow ones! test for tooth width and tooth period the width should be based on how the hardware is setup. IE the LM1815 is adjusted to have a pulse output of a particular width. This noise filter should be matched to that width as should the hardware filter.

Definition at line 68 of file Simple.c.

References ADCArrays, CALC_FUEL_IGN, Clocks, coreStatusA, Counters, engineCyclePeriod, injectorMainControlRegisters, injectorMainEnableMasks, injectorMainEndTimes, injectorMainOnMasks, injectorMainStartTimesHolding, injectorMainTimeRegisters, injectorMinimumPulseWidth, injectorSwitchOffCodeTime, ISRLatencyVars, lastPrimaryPulseTimeStamp, LONGHALF, masterPulseWidth, mathSampleTimeStampRecord, PORTJ, PRIMARY_SYNC, ISRLatencyVar::primaryInputLatency, RuntimeVar::primaryInputLeadingRuntime, RuntimeVar::primaryInputTrailingRuntime, primaryLeadingEdgeTimeStamp, Counter::primaryTeethSeen, PTIT, RPMRecord, RuntimeVars, sampleEachADC(), selfSetTimer, Counter::syncedADCreadings, TC0, TCNT, TFLG, TFLGOF, ticksPerMinute, TIE, timeBetweenSuccessivePrimaryPulses, LongTime::timeLong, Clock::timeoutADCreadingClock, timerExtensionClock, LongTime::timeShorts, totalAngleAfterReferenceInjection, and trailingEdgeSecondaryRPMInputCodeTime.

00068                     {
00069     /* Clear the interrupt flag for this input compare channel */
00070     TFLG = 0x01;
00071 
00072     /* Save all relevant available data here */
00073     unsigned short codeStartTimeStamp = TCNT;       /* Save the current timer count */
00074     unsigned short edgeTimeStamp = TC0;             /* Save the edge time stamp */
00075     unsigned char PTITCurrentState = PTIT;          /* Save the values on port T regardless of the state of DDRT */
00076 
00077     // set as synced for volvo always as loss of sync not actually possible
00078     coreStatusA |= PRIMARY_SYNC;
00079 
00080     /* Calculate the latency in ticks */
00081     ISRLatencyVars.primaryInputLatency = codeStartTimeStamp - edgeTimeStamp;
00082 
00083     if(PTITCurrentState & 0x01){
00084         /* Echo input condition on J7 */
00085         PORTJ |= 0x80;
00086 
00087         Counters.primaryTeethSeen++;
00088 
00089         LongTime timeStamp;
00090 
00091         /* Install the low word */
00092         timeStamp.timeShorts[1] = edgeTimeStamp;
00093         /* Find out what our timer value means and put it in the high word */
00094         if(TFLGOF && !(edgeTimeStamp & 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
00095             timeStamp.timeShorts[0] = timerExtensionClock + 1;
00096         }else{
00097             timeStamp.timeShorts[0] = timerExtensionClock;
00098         }
00099 
00100         // temporary data from inputs
00101         primaryLeadingEdgeTimeStamp = timeStamp.timeLong;
00102         timeBetweenSuccessivePrimaryPulses = primaryLeadingEdgeTimeStamp - lastPrimaryPulseTimeStamp;
00103         lastPrimaryPulseTimeStamp = primaryLeadingEdgeTimeStamp;
00104 
00105 #define ticksPerMinute   75000000 // this is correct.
00106 
00107         *RPMRecord = (unsigned short) (ticksPerMinute / timeBetweenSuccessivePrimaryPulses);
00108 
00109         // TODO sample ADCs on teeth other than that used by the scheduler in order to minimise peak run time and get clean signals
00110         sampleEachADC(ADCArrays);
00111         Counters.syncedADCreadings++;
00112         *mathSampleTimeStampRecord = TCNT;
00113 
00114         /* Set flag to say calc required */
00115         coreStatusA |= CALC_FUEL_IGN;
00116 
00117         /* Reset the clock for reading timeout */
00118         Clocks.timeoutADCreadingClock = 0;
00119 
00120         if(masterPulseWidth > injectorMinimumPulseWidth){ // use reference PW to decide. spark needs moving outside this area though TODO
00121             /* Determine if half the cycle is bigger than short-max */
00122             unsigned short maxAngleAfter;
00123             if((engineCyclePeriod >> 1) > 0xFFFF){
00124                 maxAngleAfter = 0xFFFF;
00125             }else{
00126                 maxAngleAfter = (unsigned short)(engineCyclePeriod >> 1);
00127             }
00128 
00129             /* Check advance to ensure it is less than 1/2 of the previous engine cycle and more than codetime away */
00130             unsigned short advance;
00131             if(totalAngleAfterReferenceInjection > maxAngleAfter){ // if too big, make it max
00132                 advance = maxAngleAfter;
00133             }else if(totalAngleAfterReferenceInjection < trailingEdgeSecondaryRPMInputCodeTime){ // if too small, make it min
00134                 advance = trailingEdgeSecondaryRPMInputCodeTime;
00135             }else{ // else use it as is
00136                 advance = totalAngleAfterReferenceInjection;
00137             }
00138 
00139             // determine the long and short start times
00140             unsigned short startTime = edgeTimeStamp + advance;
00141             unsigned long startTimeLong = timeStamp.timeLong + advance;
00142 
00143             /* Determine the channels to schedule */
00144             unsigned char fuelChannel = 0;//(primaryPulsesPerSecondaryPulse / 2) - 1;
00145 
00146             // determine whether or not to reschedule
00147             unsigned char reschedule = 0;
00148             unsigned long diff = startTimeLong - (injectorMainEndTimes[fuelChannel] + injectorSwitchOffCodeTime);
00149             if(diff > LONGHALF){
00150                 reschedule = 1; // http://www.diyefi.org/forum/viewtopic.php?f=8&t=57&p=861#p861
00151             }
00152 
00153             // schedule the appropriate channel
00154             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 */
00155                 *injectorMainControlRegisters[fuelChannel] |= injectorMainEnableMasks[fuelChannel];
00156                 *injectorMainTimeRegisters[fuelChannel] = startTime;
00157                 TIE |= injectorMainOnMasks[fuelChannel];
00158                 TFLG = injectorMainOnMasks[fuelChannel];
00159             }else{
00160                 injectorMainStartTimesHolding[fuelChannel] = startTime;
00161                 selfSetTimer |= injectorMainOnMasks[fuelChannel]; // setup a bit to let the timer interrupt know to set its own new start from a var
00162             }
00163         }
00164         RuntimeVars.primaryInputLeadingRuntime = TCNT - codeStartTimeStamp;
00165     }else{
00166         PORTJ &= 0x7F;
00167         RuntimeVars.primaryInputTrailingRuntime = TCNT - codeStartTimeStamp;
00168     }
00169 }

Here is the call graph for this function:

void SecondaryRPMISR ( void   ) 

Use the rising and falling edges...................

Secondary RPM ISR

Unused in this decoder.

Todo:
TODO discard narrow ones! test for tooth width and tooth period the width should be based on how the hardware is setup. IE the LM1815 is adjusted to have a pulse output of a particular width. This noise filter should be matched to that width as should the hardware filter.

Definition at line 176 of file Simple.c.

References Counters, ISRLatencyVars, lastSecondaryPulseLeadingTimeStamp, lastSecondaryPulseTrailingTimeStamp, lengthOfSecondaryLowPulses, PORTJ, PTIT, ISRLatencyVar::secondaryInputLatency, Counter::secondaryTeethSeen, TC1, TCNT, TFLG, TFLGOF, LongTime::timeLong, timerExtensionClock, and LongTime::timeShorts.

00176                       {
00177     /* Clear the interrupt flag for this input compare channel */
00178     TFLG = 0x02;
00179 
00180     /* Save all relevant available data here */
00181     unsigned short codeStartTimeStamp = TCNT;       /* Save the current timer count */
00182     unsigned short edgeTimeStamp = TC1;             /* Save the timestamp */
00183     unsigned char PTITCurrentState = PTIT;          /* Save the values on port T regardless of the state of DDRT */
00184 //  unsigned short PORTS_BACurrentState = PORTS_BA; /* Save ignition output state */
00185 
00186     /* Calculate the latency in ticks */
00187     ISRLatencyVars.secondaryInputLatency = codeStartTimeStamp - edgeTimeStamp;
00188 
00195     LongTime timeStamp;
00196 
00197     /* Install the low word */
00198     timeStamp.timeShorts[1] = edgeTimeStamp;
00199     /* Find out what our timer value means and put it in the high word */
00200     if(TFLGOF && !(edgeTimeStamp & 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
00201         timeStamp.timeShorts[0] = timerExtensionClock + 1;
00202     }else{
00203         timeStamp.timeShorts[0] = timerExtensionClock;
00204     }
00205 
00206     /* The LM1815 variable reluctance sensor amplifier allows the output to be
00207      * pulled high starting at the center of a tooth. So, what we see as the
00208      * start of a tooth is actually the centre of a physical tooth. Because
00209      * tooth shape, profile and spacing may vary this is the only reliable edge
00210      * for us to schedule from, hence the trailing edge code is very simple.
00211      */
00212     if(PTITCurrentState & 0x02){
00213         // echo input condition
00214         PORTJ |= 0x40;
00215 
00216         Counters.secondaryTeethSeen++;
00217 
00218         /* leading code
00219          *
00220          * subtract lastTrailing from currentLeading
00221          * record currentLeading as lastLeading
00222          *
00223          * record pw as highDuration
00224          */
00225         lengthOfSecondaryLowPulses = timeStamp.timeLong - lastSecondaryPulseTrailingTimeStamp;
00226         lastSecondaryPulseLeadingTimeStamp = timeStamp.timeLong;
00227     }else{
00228 
00229         /* trailing code
00230          *
00231          * subtract lastLeading from currentTrailing
00232          * record currentTrailing as lastTrailing
00233          *
00234          * record pw as lowDuration
00235          */
00236 //      lengthOfSecondaryHighPulses = timeStamp.timeLong - lastSecondaryPulseLeadingTimeStamp;
00237         lastSecondaryPulseTrailingTimeStamp = timeStamp.timeLong;
00238 
00239         PORTJ &= 0xBF;
00240     }
00241 }


Generated on Wed May 26 03:59:56 2010 for FreeEMS by  doxygen 1.5.6