1 /* FreeEMS - the open source engine management system
3 * Copyright 2011-2012 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 enginePositionRPMDecoders
31 * To facilitate testing of output circuits and physical hardware such as
32 * injectors and coils on the bench or in the car.
34 * This "decoder" is intended to generate an output pattern that allows various
35 * testing to occur without any external stimulus. This is useful for scheduler
36 * testing, injector testing, output hardware testing, coil testing, etc. This
37 * will be the only decoder that will be usable with just a cpu and comms interface.
39 * @todo TODO setup the timer registers as required.
43 #define DECODER_IMPLEMENTATION_C
44 #define DECODER_MAX_CODE_TIME 66 // TODO measure reality
45 #define NUMBER_OF_REAL_EVENTS 1 // no events really...
46 #define NUMBER_OF_VIRTUAL_EVENTS 1 // no events really...
49 #include "../inc/freeEMS.h"
50 #include "../inc/interrupts.h"
51 #include "../inc/decoderInterface.h"
52 #include "inc/BenchTest.h"
55 // Setup the timer interrupts as internal timers only triggered by a serial call that returns if this isn't the decoder.
56 void decoderInitPreliminary(){
57 // Configure 0 and 1 as outputs, but decouple them from the interrupts
58 TIOS
= 0xFF; // All outputs
60 // Disable capture when in IC mode.
61 TCTL4
= 0x00; // TODO Unrequired, remove.
63 // Leave configured to not toggle the pin at all (0,0)
64 // Std behaviour, no change required
66 // Disable interrupts, to be enabled by a serial trigger
71 void perDecoderReset(){} // Nothing special to reset for this code
74 const unsigned short eventAngles
[] = {0}; // no events really...
75 const unsigned char eventValidForCrankSync
[] = {0}; // no events really...
78 /* Fire from serial, then repeat X revolutions or seconds or whatever and trigger Z outputs of various types etc
80 * Possible modes of repetition:
87 DEBUG_TURN_PIN_ON(DECODER_BENCHMARKS
, BIT0
, PORTB
);
89 unsigned short edgeTimeStamp
= TC0
;
91 /* Reset the clock for reading timeout */
92 Clocks
.timeoutADCreadingClock
= 0;
94 // call sched output with args
96 /* Install the low word */
97 timeStamp
.timeShorts
[1] = edgeTimeStamp
;
98 /* Find out what our timer value means and put it in the high word */
99 if(TFLGOF
&& !(edgeTimeStamp
& 0x8000)){ /* see 10.3.5 paragraph 4 of 68hc11 ref manual for details */
100 timeStamp
.timeShorts
[0] = timerExtensionClock
+ 1;
102 timeStamp
.timeShorts
[0] = timerExtensionClock
;
105 unsigned char shouldFire
= 1;
106 // unsigned long localPeriod = 0; // mutlifire or busy wait, if doing this, check last period for some min, and if too small, shrink second to last and increase last
107 // unsigned short localPeriod = 0; // normal mode
108 if(testMode
== TEST_MODE_ITERATIONS
){
109 KeyUserDebugs
.currentEvent
++;
110 if(KeyUserDebugs
.currentEvent
== testEventsPerCycle
){
111 KeyUserDebugs
.currentEvent
= 0;
112 testNumberOfCycles
--;
113 if(testNumberOfCycles
== 0){
114 // Disable the interrupt again, to be enabled by a serial trigger
116 coreStatusA
&= CLEAR_BENCH_TEST_ON
;
121 // TODO make this more sophisticated
122 TC0
+= testTicksPerEvent
;
123 }else if(testMode
== TEST_MODE_DODGY_MISSING_TOOTH
){
124 KeyUserDebugs
.currentEvent
++;
125 if(KeyUserDebugs
.currentEvent
== testEventsPerCycle
){
126 KeyUserDebugs
.currentEvent
= 0;
127 testNumberOfCycles
--;
128 if(testNumberOfCycles
== 0){
129 // Disable the interrupt again, to be enabled by a serial trigger
131 coreStatusA
&= CLEAR_BENCH_TEST_ON
;
136 // Grab updated time period
137 testTicksPerEvent
= CoreVars
->RPM
;
139 // Output the sync pulse only once per "engine cycle"
140 if(KeyUserDebugs
.currentEvent
== 0){
141 // Schedule the cam pulse
142 outputEventDelayFinalPeriod
[1] = 3*(testTicksPerEvent
/4);
143 outputEventPulseWidthsMath
[1] = testTicksPerEvent
;
144 outputEventInputEventNumbers
[1] = KeyUserDebugs
.currentEvent
;
146 outputEventInputEventNumbers
[1] = 0xFF;
149 // Generate crank strength signal
150 unsigned char fakeCurrentEvent
= 0;
151 if(KeyUserDebugs
.currentEvent
>= (testEventsPerCycle
/2)){
152 fakeCurrentEvent
= KeyUserDebugs
.currentEvent
- (testEventsPerCycle
/2);
154 fakeCurrentEvent
= KeyUserDebugs
.currentEvent
;
157 // Schedule the main teeth, or not
158 if(fakeCurrentEvent
< testNumberOfMissing
){
159 outputEventInputEventNumbers
[0] = 0xFF;
161 outputEventDelayFinalPeriod
[0] = decoderMaxCodeTime
;
162 outputEventInputEventNumbers
[0] = KeyUserDebugs
.currentEvent
;
164 unsigned short singleWidth
= testTicksPerEvent
/2;
165 // See if this is the last one before the gap
166 if((KeyUserDebugs
.currentEvent
== ((testEventsPerCycle
/ 2) - 1)) || (KeyUserDebugs
.currentEvent
== (testEventsPerCycle
- 1))){
167 // Migrate this to a safeMultiply() inline function
168 unsigned long wideWideWidth
= (unsigned long)singleWidth
* (testNumberOfMissing
+ 1);
169 if(wideWideWidth
< SHORTMAX
){
170 outputEventPulseWidthsMath
[0] = (unsigned short)wideWideWidth
;
172 outputEventPulseWidthsMath
[0] = SHORTMAX
;
175 outputEventPulseWidthsMath
[0] = singleWidth
;
179 TC0
+= testTicksPerEvent
;
180 }else if(testMode
== TEST_MODE_REVOLUTIONS
){
181 // sub modes of different patterns, use scheduler for this by setting the ADC array up and probing/triggering/touching/poking/starting/
182 // switch statement for selecting different const arrays of angles, use busy wait, or multiple interrupt to do larger gaps for lower rpms/coarse events
183 // perhaps accept the pattern in the input packet and busy wait on some "run completed" flag before returning and freeing the buffer.
184 // TEMP de-configure timers and leave shouldFire zeroed.
186 }else if(testMode
== TEST_MODE_TIME_UNITS_SECONDS
){
187 // reset all timer modes for first time around, then check for timer >= requested value, check appropriate units of time, obviously...
188 // TEMP de-configure timers and leave shouldFire zeroed.
190 }else if(testMode
== TEST_MODE_TIME_UNITS_MINUTES
){
192 // TEMP de-configure timers and leave shouldFire zeroed.
194 }else if(testMode
== TEST_MODE_TIME_UNITS_HOURS
){
196 // TEMP de-configure timers and leave shouldFire zeroed.
199 // de-configure timers and leave shouldFire zeroed.
204 // configuration for multiple periods setup here?
207 unsigned char channel
;
208 for(channel
= 0;channel
< 6;channel
++){
209 if(KeyUserDebugs
.currentEvent
== outputEventInputEventNumbers
[channel
]){
210 schedulePortTPin(channel
, timeStamp
);
214 DEBUG_TURN_PIN_OFF(DECODER_BENCHMARKS
, NBIT0
, PORTB
);
218 #include "inc/defaultSecondaryRPMISR.c"