1 /* FreeEMS - the open source engine management system
3 * Copyright 2011-2013 Fred Cooke
5 * This file is part of the FreeEMS project.
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.
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.
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/
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!
23 * Thank you for choosing FreeEMS to run your engine!
29 * @ingroup interruptHandlers
30 * @ingroup enginePositionRPMDecoders
32 * @brief For evenly spaced teeth on the cam or crank with a single second input.
34 * Fill out a data reverse header and include this file. Sync is provided by the
35 * second input allowing a sequential and/or COP/CNP setup to be used.
37 * VR edition with only one edge used!
41 void decoderInitPreliminary(){
42 // Set PT0 and PT1 to only capture on rising
43 TCTL4
= 0x05; // 0000 0101 Capture rising edges only on PT0&1
46 void perDecoderReset(){} // Nothing special to reset for this code
50 /* Clear the interrupt flag for this input compare channel */
52 DEBUG_TURN_PIN_ON(DECODER_BENCHMARKS
, BIT0
, PORTB
);
54 /* Save all relevant available data here */
55 unsigned short edgeTimeStamp
= TC0
; /* Save the edge time stamp */
56 unsigned char PTITCurrentState
= PTIT
; /* Save the values on port T regardless of the state of DDRT */
58 // Prevent main from clearing values before sync is obtained!
59 Clocks
.timeoutADCreadingClock
= 0;
61 KeyUserDebugs
.primaryTeethSeen
++;
64 /* Install the low word */
65 timeStamp
.timeShorts
[1] = edgeTimeStamp
;
66 /* Find out what our timer value means and put it in the high word */
67 if(TFLGOF
&& !(edgeTimeStamp
& 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
68 timeStamp
.timeShorts
[0] = timerExtensionClock
+ 1;
70 timeStamp
.timeShorts
[0] = timerExtensionClock
;
72 unsigned long thisEventTimeStamp
= timeStamp
.timeLong
;
74 unsigned long thisInterEventPeriod
= 0;
75 unsigned short thisTicksPerDegree
= 0;
76 if(KeyUserDebugs
.decoderFlags
& LAST_TIMESTAMP_VALID
){
77 thisInterEventPeriod
= thisEventTimeStamp
- lastPrimaryEventTimeStamp
;
78 thisTicksPerDegree
= (unsigned short)((ticks_per_degree_multiplier
* thisInterEventPeriod
) / eventAngles
[1]); // with current scale range for 60/12000rpm is largest ticks per degree = 3472, smallest = 17 with largish error
81 if(KeyUserDebugs
.decoderFlags
& CONFIGURED_SYNC
){
82 KeyUserDebugs
.currentEvent
++;
83 if(KeyUserDebugs
.currentEvent
== numberOfRealEvents
){
84 resetToNonRunningState(COUNT_OF_EVENTS_IMPOSSIBLY_HIGH_NOISE
);
86 }// Can never be greater than without a code error or genuine noise issue, so give it a miss as we can not guarantee where we are now.
88 if(KeyUserDebugs
.decoderFlags
& LAST_PERIOD_VALID
){
89 unsigned short ratioBetweenThisAndLast
= (unsigned short)(((unsigned long)lastPrimaryTicksPerDegree
* 1000) / thisTicksPerDegree
);
90 KeyUserDebugs
.inputEventTimeTolerance
= ratioBetweenThisAndLast
;
91 if(ratioBetweenThisAndLast
> fixedConfigs2
.decoderSettings
.decelerationInputEventTimeTolerance
){
92 resetToNonRunningState(PRIMARY_EVENT_ARRIVED_TOO_LATE
);
94 }else if(ratioBetweenThisAndLast
< fixedConfigs2
.decoderSettings
.accelerationInputEventTimeTolerance
){
95 resetToNonRunningState(PRIMARY_EVENT_ARRIVED_TOO_EARLY
);
98 if(PTITCurrentState
& 0x01){
99 // TODO Calculate RPM from last primaryLeadingEdgeTimeStamp
101 // TODO Calculate RPM from last primaryTrailingEdgeTimeStamp
104 }/*else*/ if(KeyUserDebugs
.decoderFlags
& LAST_TIMESTAMP_VALID
){ // TODO temp for testing just do rpm this way, fill above out later.
105 *ticksPerDegreeRecord
= thisTicksPerDegree
;
106 sampleEachADC(ADCBuffers
);
107 Counters
.syncedADCreadings
++;
109 // Set flag to say calc required
110 coreStatusA
|= CALC_FUEL_IGN
;
112 // Reset the clock for reading timeout
113 Clocks
.timeoutADCreadingClock
= 0;
116 // for now, sample always and see what we get result wise...
117 // if((currentEvent % 6) == 0){
118 // sampleEachADC(ADCBuffers);
119 // Counters.syncedADCreadings++;
121 // // Set flag to say calc required
122 // coreStatusA |= CALC_FUEL_IGN;
124 // // Reset the clock for reading timeout
125 // Clocks.timeoutADCreadingClock = 0;
128 SCHEDULE_ECT_OUTPUTS();
133 // do these always at first, and use them with a single 30 degree angle for the first cut
134 if(KeyUserDebugs
.decoderFlags
& LAST_TIMESTAMP_VALID
){
135 lastPrimaryTicksPerDegree
= thisTicksPerDegree
;
136 KeyUserDebugs
.decoderFlags
|= LAST_PERIOD_VALID
;
139 lastPrimaryEventTimeStamp
= thisEventTimeStamp
;
140 KeyUserDebugs
.decoderFlags
|= LAST_TIMESTAMP_VALID
;
142 DEBUG_TURN_PIN_OFF(DECODER_BENCHMARKS
, NBIT0
, PORTB
);
146 void SecondaryRPMISR(){
147 /* Clear the interrupt flag for this input compare channel */
149 DEBUG_TURN_PIN_ON(DECODER_BENCHMARKS
, BIT1
, PORTB
);
151 /* Save all relevant available data here */
152 unsigned short edgeTimeStamp
= TC1
; /* Save the timestamp */
153 // unsigned char PTITCurrentState = PTIT; /* Save the values on port T regardless of the state of DDRT */
155 KeyUserDebugs
.secondaryTeethSeen
++;
158 /* Install the low word */
159 timeStamp
.timeShorts
[1] = edgeTimeStamp
;
160 /* Find out what our timer value means and put it in the high word */
161 if(TFLGOF
&& !(edgeTimeStamp
& 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
162 timeStamp
.timeShorts
[0] = timerExtensionClock
+ 1;
164 timeStamp
.timeShorts
[0] = timerExtensionClock
;
166 unsigned long thisEventTimeStamp
= timeStamp
.timeLong
;
168 unsigned long thisInterEventPeriod
= 0;
169 if(KeyUserDebugs
.decoderFlags
& LAST_TIMESTAMP_VALID
){
170 thisInterEventPeriod
= thisEventTimeStamp
- lastSecondaryEventTimeStamp
;
173 // This sets currentEvent to 255 such that when the primary ISR runs it is rolled over to zero!
174 if(KeyUserDebugs
.decoderFlags
& CONFIGURED_SYNC
){
175 // If sync not confirmed, register sync point. Must be before the count checks, otherwise loss of sync would result in sync being redeclared.
176 if(!(KeyUserDebugs
.decoderFlags
& OK_TO_SCHEDULE
)){
177 SET_SYNC_LEVEL_TO(CONFIGURED_SYNC
);
180 /* If the count is less than 23, then we know that the electrical pulse that triggered
181 * this ISR execution was almost certainly in error and it is NOT valid to stay in sync.
183 * If the count is greater than 24, then we know that an electrical noise pulse triggered
184 * the other interrupt in between and was missed by the time period checks (unlikely, but
185 * possible) and that, therefore, there could have been a noise pulse on this input too,
186 * and therefore we don't really know where we are.
188 * In the case where the count is exactly 24 we can only rely on the time period checks in
189 * the other ISR, which should be sufficient unless poorly setup by a user with too wide
190 * of a tolerance level.
192 * There is zero point adding relative timing checks to this ISR because by nature, the
193 * other N teeth have already checked out good timing wise and therefore the average also
194 * does. Thus if we did check, for it to ever fail it would need to be tighter, and in
195 * reality it must be more loose due to the larger possible variation over the much much
198 if(KeyUserDebugs
.currentEvent
< (numberOfRealEvents
- 1)){
199 resetToNonRunningState(COUNT_OF_EVENTS_IMPOSSIBLY_LOW_NOISE
);
200 }else if(KeyUserDebugs
.currentEvent
> (numberOfRealEvents
-1)){
201 resetToNonRunningState(COUNT_OF_EVENTS_IMPOSSIBLY_HIGH_NOISE
);
202 } // ELSE do nothing, and be happy :-)
203 }else{ // If sync not found, register first sync point, as this is our reference point.
204 SET_SYNC_LEVEL_TO(CONFIGURED_SYNC
);
207 KeyUserDebugs
.currentEvent
= 0xFF; // TODO reset always, and catch noise induced errors below, this behaviour (now some lines above) may be bad/not fussy enough, or could be good, depending upon determinate nature of the inter event timing between primary and secondary, or not, perhaps move "lose sync or correct sync" as a configuration variable
209 DEBUG_TURN_PIN_OFF(DECODER_BENCHMARKS
, NBIT1
, PORTB
);