Simple.c File Reference

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

#include "inc/freeEMS.h"
#include "inc/interrupts.h"
#include "inc/DecoderInterface.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 possibly add code to make sure we are in divide mode, if not error out
Todo:
TODO fill in or remove the else
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 69 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.

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

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 178 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.

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

Generated on Sat Oct 16 21:29:20 2010 for FreeEMS by  doxygen 1.6.3