FreeEMS  0.2.0-SNAPSHOT-285-g028e24c
MissingTeeth-Either-XminusY.c
Go to the documentation of this file.
1 /* FreeEMS - the open source engine management system
2  *
3  * Copyright 2011-2014 Fred Cooke
4  *
5  * This file is part of the FreeEMS project.
6  *
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.
11  *
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.
16  *
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/
19  *
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!
22  *
23  * Thank you for choosing FreeEMS to run your engine!
24  */
25 
26 
27 /** @file
28  *
29  * @ingroup interruptHandlers
30  * @ingroup enginePositionRPMDecoders
31  *
32  * @brief Missing teeth, M-N, with or without cam sync, configured externally
33  *
34  * This file is generic, and built as an include with multiple headers
35  * containing the parameters required to make it function.
36  *
37  * Documentation on how this decoder was designed & written is available here:
38  *
39  * http://forum.diyefi.org/viewtopic.php?f=56&t=1340
40  */
41 
42 
43 // Some simple checks here, more thorough checks where the arrays are generated, if not using that code, this will still complain.
44 #ifndef TOTAL_TEETH
45 #error "Total number of teeth not defined!"
46 #endif
47 #ifndef MISSING_TEETH
48 #error "Number of missing teeth not defined!"
49 #endif
50 #ifndef NUMBER_OF_WHEEL_EVENTS
51 #error "Number of wheel events not defined"
52 #endif
53 
54 
56 unsigned long lastInterEventPeriod;
58 
59 
61  TCTL4 = 0x01; /* Capture on rising edge of T0 only, capture off for 1,2,3 */
62 }
63 
64 
66  NumberOfTwinMatchedPairs = 0; // Var for one more opportunity to sync :-)
67 }
68 
69 
70 void PrimaryRPMISR(void) {
71  /* Clear the interrupt flag for this input compare channel */
72  TFLG = 0x01;
74 
75  /* Save all relevant available data here */
76  unsigned short edgeTimeStamp = TC0; /* Save the edge time stamp */
77  unsigned char PTITCurrentState = PTIT; /* Save the values on port T regardless of the state of DDRT */
78 
80 
82 
83  /* Install the low word */
84  timeStamp.timeShorts[1] = edgeTimeStamp;
85  /* Find out what our timer value means and put it in the high word */
86  if(TFLGOF && !(edgeTimeStamp & 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
87  timeStamp.timeShorts[0] = timerExtensionClock + 1;
88  }else{
89  timeStamp.timeShorts[0] = timerExtensionClock;
90  }
91  unsigned long thisEventTimeStamp = timeStamp.timeLong;
92 
93  if(PTITCurrentState & 0x01){
94  // Calc this period
95  unsigned char lastEvent = 0;
96  unsigned long thisInterEventPeriod = 0;
97  unsigned char initialOkToSchedule = KeyUserDebugs.decoderFlags & OK_TO_SCHEDULE;
99  thisInterEventPeriod = thisEventTimeStamp - lastEventTimeStamp;
100 
101  if((KeyUserDebugs.decoderFlags & LAST_PERIOD_VALID) && !initialOkToSchedule){// If it's OK to schedule, skip this and get on with it!
102  unsigned long larger;
103  unsigned long smaller;
104  unsigned char thisLargerThanLast;
105  if(thisInterEventPeriod > lastInterEventPeriod){
106  larger = thisInterEventPeriod;
107  smaller = lastInterEventPeriod;
108  thisLargerThanLast = 1;
109  }else{
110  larger = lastInterEventPeriod;
111  smaller = thisInterEventPeriod;
112  thisLargerThanLast = 0;
113  }
114  lastInterEventPeriod = thisInterEventPeriod;
115 
116  // Calculate tolerance, then add and subtract it from whatever required
117  unsigned long tolerance = (smaller * MISSING_TEETH * fixedConfigs2.decoderSettings.missingToothTolerance) / 4096;
118  // div by 4k = fairly high minimum RPM for low teeth wheels
119  // perhaps provide some options for different tolerance on different types of expected widths
120  // the wide one on larger missing counts has more time to get to a higher RPM and needs a wider tolerance
121  // possible options: different percent of smaller for each type, different percent and based on ideal w/b instead of smaller
122  // Another option that keeps the 25% tolerance as the correct amount for any missing count is to simply take the percentage of
123  // the smaller component and multiply by the number of missing teeth! This can be a flash config flag option or possibly rpm thresholded
124  // it could be done on a per level basis too.
125  unsigned long idealWide = 0;
126  unsigned long idealBackward = 0;
127  if(larger < (smaller + tolerance)){ // has to be first to be most efficient
128  matches.pairs.thisPair = MatchedPair; // same period, roughly
129  }else{
130  idealWide = smaller * (MISSING_TEETH + 1); // has to be second to be most efficient
131  if((larger < (idealWide + tolerance)) && (larger > (idealWide - tolerance))){
132  if(thisLargerThanLast){
133  matches.pairs.thisPair = NarrowWide;
134  }else{
135  matches.pairs.thisPair = WideNarrow;
136  }
137  }else{ // We're not in good shape...
138  idealBackward = ((smaller * (MISSING_TEETH + 2)) / 2); // this leads to further code running later, so should come next
139  if((larger < (idealBackward + tolerance)) && (larger > (idealBackward - tolerance))){
140  if(thisLargerThanLast){
141  matches.pairs.thisPair = NarrowBackward;
142  }else{
143  matches.pairs.thisPair = BackwardNarrow;
144  }
145  }else if(larger > (idealWide + tolerance)){ // We're in very bad shape...
146  if(thisLargerThanLast){
148  return;
149  }else{
151  return;
152  }
153  }else{ // Fell between the cracks, not matched, settings very tight, therefore was in two possible places on either side of (N+2)/2.
155  return;
156  }
157  }
158  }
159 
160  // This all needs a little more complexity for cam only/crank only/crank + cam sync use, hard coded to crank only for now
161  if(KeyUserDebugs.decoderFlags & LAST_MATCH_VALID){ // If we have enough data
162  if(KeyUserDebugs.decoderFlags & CONFIGURED_SYNC){
163  lastEvent = KeyUserDebugs.currentEvent;
167  }
168 
169  if((KeyUserDebugs.currentEvent == 0) && (matches.pattern != MatchedPairNarrowWide)){ // First event after gap
171  return;
172  }else if((KeyUserDebugs.currentEvent == 1) && (matches.pattern != NarrowWideWideNarrow)){ // Second event after gap
174  return;
175  }else if((KeyUserDebugs.currentEvent == 2) && (matches.pattern != WideNarrowMatchedPair)){ // Third event after gap
177  return;
178  }else if((KeyUserDebugs.currentEvent > 2) && (matches.pattern != MatchedPairMatchedPair)){ // All other events should be preceeded by two matched pairs
180  return;
181  }else{ // Add a confirmation if necessary
182  SET_SYNC_LEVEL_TO(CONFIGURED_SYNC);
183  }
184  }else{
185  if(matches.pattern == MatchedPairMatchedPair){ // | small | small | small | - All periods match, could be anywhere, unless...
187  // Because this method REQUIRES 4 evenly spaced teeth to work, it's only available to 5-1 or greater wheels.
188  if((NUMBER_OF_WHEEL_EVENTS > 3) && (NumberOfTwinMatchedPairs == (NUMBER_OF_WHEEL_EVENTS - 3))){ // This can't find a match until it's on it's fourth execution
189  // This will match repeatedly then un-sync on next cycle if tolerance is set too high
190  KeyUserDebugs.currentEvent = NUMBER_OF_WHEEL_EVENTS - 1; // Zero indexed
191  lastEvent = KeyUserDebugs.currentEvent - 1;
192  SET_SYNC_LEVEL_TO(CONFIGURED_SYNC); // Probability of this = (N + 1) / M
193  // Sample RPM and ADCs here on the basis of cylinders and revolutions
194  // IE, sample RPM once (total teeth (inc missing) per engine cycle / cyls) events have passed
195  // And, do it from the last matching tooth, and do that on every tooth
196  // So have a buffer of time stamps, which would take a LOT of RAM, hmmm, perhaps just wait.
197  // Missing teeth users are clearly not fussed about fast starting anyway
198  // And once sync is gained good readings can be taken without excess memory usage
199  }else if((NUMBER_OF_WHEEL_EVENTS > 3) && (NumberOfTwinMatchedPairs > (NUMBER_OF_WHEEL_EVENTS - 3))){ // More matched pairs than possible with config
201  return;
202  } // else fall through to wait.
203  }else if(matches.pattern == MatchedPairNarrowWide){ // | small | small | BIG | Last tooth is first tooth after missing - ((M-N)-3)/M = common
205  lastEvent = NUMBER_OF_WHEEL_EVENTS - 1; // Zero indexed
206  SET_SYNC_LEVEL_TO(CONFIGURED_SYNC);
207  }else if(matches.pattern == NarrowWideWideNarrow){ // | small | BIG | small | Last tooth is second tooth after missing - 1/M
209  lastEvent = 0;
210  SET_SYNC_LEVEL_TO(CONFIGURED_SYNC);
211  }else if(matches.pattern == WideNarrowMatchedPair){ // | BIG | small | small | Last tooth is third tooth after missing - 1/M
213  lastEvent = 1;
214  SET_SYNC_LEVEL_TO(CONFIGURED_SYNC);
215  }else{
216  resetToNonRunningState(matches.pattern); // Where they are defined individually in the error file! Beautiful!!
217  return;
218  }
219  }
220  }
221  // Stash the pair description for next time
222  matches.pairs.lastPair = matches.pairs.thisPair;
223  }
224  }
225 
226  unsigned short thisTicksPerDegree = 0;
227  if(KeyUserDebugs.decoderFlags & CONFIGURED_SYNC){
228 
229  if(initialOkToSchedule){ // Only do this if not done above
230  lastEvent = KeyUserDebugs.currentEvent;
234  }
235  }
236 
237  unsigned short thisAngle = 0;
238  if(KeyUserDebugs.currentEvent == 0){
239  thisAngle = eventAngles[KeyUserDebugs.currentEvent] + angleOfSingleIteration - eventAngles[lastEvent] ; // Optimisable... leave readable for now! :-p J/K learn from this...
240  }else{
241  thisAngle = eventAngles[KeyUserDebugs.currentEvent] - eventAngles[lastEvent];
242  }
243  thisTicksPerDegree = (unsigned short)((ticks_per_degree_multiplier * thisInterEventPeriod) / thisAngle); // with current scale range for 60/12000rpm is largest ticks per degree = 3472, smallest = 17 with largish error
244 
246  unsigned short ratioBetweenThisAndLast = (unsigned short)(((unsigned long)lastTicksPerDegree * 1000) / thisTicksPerDegree);
247  KeyUserDebugs.inputEventTimeTolerance = ratioBetweenThisAndLast;
250  return;
251  }else if(ratioBetweenThisAndLast < fixedConfigs2.decoderSettings.accelerationInputEventTimeTolerance){
253  return;
254  }
255  }
256 
257  if(initialOkToSchedule){ // Skip one execution
258  SCHEDULE_ECT_OUTPUTS();
259  }
260 
262 
263  // sample adcs and record rpm here after scheduling
264  *ticksPerDegreeRecord = thisTicksPerDegree;
265 
268 
269  // Set flag to say calc required
271 
272  // Reset the clock for reading timeout
274  }
275 
276  OUTPUT_COARSE_BBS();
277 
281  }else{
283  lastInterEventPeriod = thisInterEventPeriod;
284  }
285  lastTicksPerDegree = thisTicksPerDegree;
286  }
287  // Always
288  lastEventTimeStamp = thisEventTimeStamp;
290  }else{
291  // do checking for width variance too, perhaps optionally.
292  }
294 }
295 
296 
297 #include "../inc/defaultSecondaryRPMISR.c"