1 /* FreeEMS - the open source engine management system
3 * Copyright 2008, 2009, 2010, 2011 Fred Cooke, Jared Harvey
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 * @brief Injector ISR shared code
31 * This code is identical between all 6 channels, and thus we only want one
32 * copy of it. The X in each macro will be replaced with the number that is
33 * appropriate for the channel it is being used for at the time.
35 * Each channel performs the following actions
37 * - 1 Clear its interrupt flag
38 * - 2 Record its start time
39 * - 3 Measure and record its latency
40 * - 4 Check to see if its just turned on
41 * - 4.1 Copy the channels pulse width to a local variable
42 * - 4.2 Determine the minimum pulse width based on code run time const and latency
43 * - 4.3 Clamp used pulsewidth inside min and max
44 * - 4.4 If used pulse width is larger than the current period of the engines cycle flag as always on
45 * - 4.5 Set the action to turn off
46 * - 4.6 Increment the time by pulse width
47 * - 4.7 If staging required, either, switch them on and sched to turn off, or sched to turn on
48 * - 5 Else it has just turned off
49 * - 5.1 If staged channel is still on, turn it off
50 * - 5.2 If(self schedule flagged) schedule the next start
51 * - 5.3 Else disable itself
52 * - 6 Calculate and record code run time
55 * @see injectionISRs.c
59 // Courtesy of Dave Cramer
60 #define INJECTOR_MAIN_ON_MASK (BIT2<<INJECTOR_CHANNEL_NUMBER)
62 /** A template function for ECT injector/coil operation.
64 * Note, this function does not exist in the binary, only in source and the
65 * Doxygen docs. In contrast the 6 real ones only exist in binary and not the
66 * source or Doxygen docs, hence if you want to look at the source, this is the
70 /* Clear the interrupt flag for this channel */
71 TFLG
= INJECTOR_MAIN_ON_MASK
;
73 /* Record the current time as start time */
74 unsigned short TCNTStart
= TCNT
;
76 DEBUG_TURN_PIN_ON(DECODER_BENCHMARKS
, BIT2
, PORTB
);
78 /* Record the edge time stamp from the IC register */
79 unsigned short edgeTimeStamp
= *injectorMainTimeRegisters
[INJECTOR_CHANNEL_NUMBER
];
81 /* If rising edge triggered this */
82 if(PTIT
& INJECTOR_MAIN_ON_MASK
){ // Stuff for switch on time
84 /* Find out what max and min for pulse width are */
85 unsigned short localPulseWidth
= outputEventPulseWidthsRealtime
[INJECTOR_CHANNEL_NUMBER
];
86 unsigned short localMinimumPulseWidth
= injectorSwitchOnCodeTime
+ injectorCodeLatencies
[INJECTOR_CHANNEL_NUMBER
];
88 /** @todo TODO *maybe* instead of checking min and increasing pulse, just force it straight off if diff between start and now+const is greater than desired pulsewidth */
90 /* Ensure we dont go under minimum pulsewidth */
91 if(localPulseWidth
< localMinimumPulseWidth
){
92 localPulseWidth
= localMinimumPulseWidth
;
93 }/* else{ just use the value } */
97 /* Install the low word */
98 timeStamp
.timeShorts
[1] = edgeTimeStamp
;
99 /* Find out what our timer value means and put it in the high word */
100 if(TFLGOF
&& !(edgeTimeStamp
& 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
101 timeStamp
.timeShorts
[0] = timerExtensionClock
+ 1;
103 timeStamp
.timeShorts
[0] = timerExtensionClock
;
106 // store the end time for use in the scheduler
107 injectorMainEndTimes
[INJECTOR_CHANNEL_NUMBER
] = timeStamp
.timeLong
+ localPulseWidth
;
109 /* Set the action for compare to switch off FIRST or it might inadvertently PWM the injector during opening... */
110 *injectorMainControlRegisters
[INJECTOR_CHANNEL_NUMBER
] &= injectorMainGoLowMasks
[INJECTOR_CHANNEL_NUMBER
];
112 /* Set the time to turn off again */
113 *injectorMainTimeRegisters
[INJECTOR_CHANNEL_NUMBER
] += localPulseWidth
;
115 /* This is the point we actually want the time to, but because the code is so simple, it can't help but be a nice short time */
117 Counters
.injectorSwitchOns
++;
119 /* Calculate and store code run time */
120 injectorCodeOpenRuntimes
[INJECTOR_CHANNEL_NUMBER
] = TCNT
- TCNTStart
;
121 }else{ // Stuff for switch off time and repeat timer time.
122 if(!(*injectorMainControlRegisters
[INJECTOR_CHANNEL_NUMBER
] & injectorMainEnableMasks
[INJECTOR_CHANNEL_NUMBER
])){ // set to no action
123 if(outputEventExtendNumberOfRepeatsRealtime
[INJECTOR_CHANNEL_NUMBER
] > 0){
124 *injectorMainTimeRegisters
[INJECTOR_CHANNEL_NUMBER
] += outputEventExtendRepeatPeriodRealtime
[INJECTOR_CHANNEL_NUMBER
];
125 outputEventExtendNumberOfRepeatsRealtime
[INJECTOR_CHANNEL_NUMBER
]--;
126 Counters
.injectorTimerExtensions
++;
128 *injectorMainControlRegisters
[INJECTOR_CHANNEL_NUMBER
] |= injectorMainEnableMasks
[INJECTOR_CHANNEL_NUMBER
];
129 *injectorMainTimeRegisters
[INJECTOR_CHANNEL_NUMBER
] += outputEventDelayFinalPeriodRealtime
[INJECTOR_CHANNEL_NUMBER
];
130 // this is already set from the decoder, we're just delaying use of it: outputEventPulseWidthsRealtime[INJECTOR_CHANNEL_NUMBER]
131 Counters
.injectorTimerExtensionFinals
++;
133 }else{ // if set to off action (implicit)
134 /* Set the action for compare to switch on and the time to next start time, clear the self timer flag */
135 if(selfSetTimer
& INJECTOR_MAIN_ON_MASK
){
136 if(outputEventExtendNumberOfRepeatsHolding
[INJECTOR_CHANNEL_NUMBER
] > 0){
137 *injectorMainControlRegisters
[INJECTOR_CHANNEL_NUMBER
] &= injectorMainDisableMasks
[INJECTOR_CHANNEL_NUMBER
];
138 outputEventExtendNumberOfRepeatsRealtime
[INJECTOR_CHANNEL_NUMBER
] = outputEventExtendNumberOfRepeatsHolding
[INJECTOR_CHANNEL_NUMBER
];
139 outputEventExtendRepeatPeriodRealtime
[INJECTOR_CHANNEL_NUMBER
] = outputEventExtendRepeatPeriodHolding
[INJECTOR_CHANNEL_NUMBER
];
140 outputEventDelayFinalPeriodRealtime
[INJECTOR_CHANNEL_NUMBER
] = outputEventDelayFinalPeriodHolding
[INJECTOR_CHANNEL_NUMBER
];
141 Counters
.injectorSelfScheduleExtensions
++;
143 *injectorMainControlRegisters
[INJECTOR_CHANNEL_NUMBER
] |= injectorMainGoHighMasks
[INJECTOR_CHANNEL_NUMBER
];
144 Counters
.injectorSelfSchedules
++;
146 *injectorMainTimeRegisters
[INJECTOR_CHANNEL_NUMBER
] += injectorMainStartOffsetHolding
[INJECTOR_CHANNEL_NUMBER
];
147 outputEventPulseWidthsRealtime
[INJECTOR_CHANNEL_NUMBER
] = outputEventPulseWidthsHolding
[INJECTOR_CHANNEL_NUMBER
];
148 selfSetTimer
&= injectorMainOffMasks
[INJECTOR_CHANNEL_NUMBER
];
150 // Disable interrupts and actions incase the period from this end to the next start is long (saves cpu)
151 TIE
&= injectorMainOffMasks
[INJECTOR_CHANNEL_NUMBER
];
152 *injectorMainControlRegisters
[INJECTOR_CHANNEL_NUMBER
] &= injectorMainDisableMasks
[INJECTOR_CHANNEL_NUMBER
];
153 Counters
.injectorSwitchOffs
++;
156 /* Calculate and store code run time */
157 injectorCodeCloseRuntimes
[INJECTOR_CHANNEL_NUMBER
] = TCNT
- TCNTStart
;
159 /* Calculate and store the latency based on compare time and start time */
160 injectorCodeLatencies
[INJECTOR_CHANNEL_NUMBER
] = TCNTStart
- edgeTimeStamp
;
162 DEBUG_TURN_PIN_OFF(DECODER_BENCHMARKS
, NBIT2
, PORTB
);