Fire, Fire, When to Fire....

    Well this is one was a good one.  While trying to figure out how the code was supposed to work I came across a routine that looked like its purpose was to detect the narrow pulse coming from the distributor.  This narrow shutter pulse is supposed to signal the code when number one cylinder is firing so that the program can synchronize the firing of the injectors at a point in time before the intake valve opens.  Well I struggled with this routine for quite a while and never could make any sense out of.  More I worked on the code the more convinced I was that this was the narrow pulse detector.  I new the relationship and timing of the edges that the ignition trigger was feeding the code so I feed in some numbers and it seemed to never detect the number one cylinder.  I must have spent close to a week fussing with this area of code to no end (this was before I realized that there were numerous oversights in the code and I was still believing that is was always correct).  Finally got to a point where I needed to prove one way or another if it worked or not.  Went to the car and setup the scope so one channel triggered off of the #1 ignition wire and the other channel off of the #1 injector.  I didn't know what the relationship was going to be between them but I knew it should be fixed.  Fired up the car and setup the triggering to view what was happening.  The plug would fire and some time before it the injector would.  Turned off the motor and fired it up again and the injector firing happened at a different time during the rotation !  Did it again and the injectors were firing someplace else !  Well I guess I had my answer.  The routine did not work at all.  Darn frustrating.  After I finished the first pass on commenting the code and got it to assemble correctly I ran it on my simulator.  If you look at its display you can see a colored line with a lot of 'ppp''eee''iiii''ccc' displayed.  These represent the Power, Exhaust, Intake, and Compression cycles of the number one cylinder.  The start of the blue bar just below it is when the #1 injector fires and how long this bar is represents how many crank degrees it is spraying.  This made it very easy to visualize what was going on.  Sometimes the injector would fire well before the intake would open, sometimes well after it closed, sometimes while it was closing.  I don't think that the exact time when the injectors fire is super critical.  Look at all the motors that fire the injectors in batch mode (4 at a time) or the ones that are spraying 100% of the time.  They all work.  But what all of these other systems have in common that this one does not is that they fire consistently.  How do you tune this thing if one time when you start the motor it is firing 90 degrees before the intake opens and the next time it is spraying on a half open or closing valve.
    Now all I had to was fix it.  At first I approached this as if there was one small error that made it not work.  I made flow charts and fed numbers in to find the single error.  No Go !  Well maybe someone screwed up and got the edges backwards.  Some mis-communication between software tech and mechanical tech that got the duty cycle of the shutter wheel  backwards.  I fed in these timing numbers... Still No Go.  It just didn't work at all.  One set of numbers I never fed in was the duty cycle of the physical shutter wheel.  There is another uncertainly here because the Hall Effect Sensor does not change state when the edge of a shutter paddle is at is 50% point.  Check out the Ignition Trigger waveforms.
    What we have to do here is detect the narrow pulse out of a group of wider ones.  You can't use the timing counts directly because they are always changing so we need to look at the difference of duty cycles of the pulses to detect the narrow one.  A little ground work on how the distributor trigger handler works (or at least key to this discussion) are in order.  The pulse train coming from the distributor is fed into the 68HC11's IC1 (Input Capture 1) interrupt handler.  This interrupt is setup to detect edges only, both rising and falling, coming from the hall effect switch in the distributor.  The rising edge is the actual ignition timing event.  When this edge is comes through, the handler will continue setting up a variety of events, like setting up the timer to file the coil for the next cylinder. The negative going edge is used to determine the total time period and the ratio of high to low.  So when an edge arrives the handler grabs the current count from the main system timer.  The XTAL in this unit is running at 8 MHz which put the CPU's internal 'E' clock at 2 MHz (everything in the 68HC11 is referenced to the 'E' Clock).  The main system timer's prescaler is set to four (4) which gives us a frequency of 500 KHz.  What this means that each tic of the main system timer is 2us.  After some initial verification, like what edge was just detected, the distributor handler takes these system timer count values and further divides them by four (4) and from this point on all calculations are done in 8us units (our system timer counts divided by four).  This is done to keep low RPM timer counts, which can be very large, 16 bit integers of a more manageable size.  There are other calculation done with these numbers and if they were kept their original size they would overflow normal 16 bit arithmetic (more than 16 bit math takes more time to deal with).

These are the key stash going into the number one detector routine:

The duty cycle of the pulse train going into the handler is: Note that the width of the narrow pulse is about 75% of a non number one pulse.

Assuming that the motor was turning at 1000 RPM, which would give us a total period count of 1875,  the below displays the relationships of the pulse edges and stashes, also puts some numbers to them.

    You can see that the total period is 1,875 counts with a non number one duty cycle of 55% (1031 & 844 counts) and a number one duty cycle of about 41% (773 & 1102 counts). There is a bit extra going on in this routine, mostly to adjust signs, but it all boils down to comparing the difference between the high period vs the low period.  The difference of the duty cycle of each type (normal and numbering).  So the following is important:     So the code tries to fit the pulse width deltas into a known window.  I think it was trying to pick a value some where above 10% and less than 18% so if it was below this value it is non number one pulse and if it was above it was a number one.  I wish I could show a flow chart here because this would be so much easier to visualize but it is so broken in multiple places that a flow chart makes no sense (believe me because I did a flow chart on this trying to figure it out).  Any way one of the problems it has is with the test value it comes up with.  It calculates a certain percentage of the total period to determine this threshold value.     If we calculate what this value is for our above example we end up with a value of 87.  This is 4.64% of the total period.  Later this value is multiplied by two to test if the current delta duty cycle is number one duty cycle or not.  Well if we take this 4.64% times two we end up with 9.28%.  Clearly this is never going to work when the normal delta is 10% and the number one is 18%.  We need a value between the two not outside both of them !
    Another problem area is in the way it determines what kind of duty cycle we are dealing with.  The stash at L003A is used to normalize the previous pulse width deltas to zero.  So what is attempted is to work down through this routine to you get a value that is just the difference of the current duty cycle to the previous one then start testing it against the calculated 10% value.  This testing process was adding the calculated 10% value to the difference and branching to the correct duty cycle handler.  Kind of a moving window test.  Well the fact that they are using addition makes no sense.  Even when you correct the test value it always makes the wrong decisions.  They should be subtractions to make this type of search work.  There was also some tests that never made any sense at all that I had to take out.

So this is basically what I had to do to make it work with the shutter wheel supplied...

Below is a simplified flow chart of how it works now.  The sign tests and changes are omitted....

    Well after I applied my corrections the code would always bring the injectors into sync within several revolutions of the motor.  Below is the modified code.  Just take the 'mis3x' conditional assembly code to get it to work....

;
; The following must be used to detect the number one cylinder being fired.
;  The distributor shutter for number one is 75% the width of all the others.
;  There is one slight problem, the darn routine does NOT work.  Spent over
;  a week trying to figure it out.  Even simulated it and couldn't get it to
;  work.  Finally put a scope on the car.  One channel triggering off the
;  number one ignition wire and the the other on the number injector.  Every
;  time I fired up the engine the phase would be different between the two !
; The duty cycle of a normal period is 55% (55% high, 45% low).
;
mis3:   ldy     L004aw          ; get the time the trigger pulse was low
        ldd     L003e           ; get current timing period
;
; Compute a percentage of the total period.
; What we have here is  L004aw = (PW/32 + PW/16) / 2       ~4.6%
; This seems too narrow when later we try to determine if the difference between
; low and high periods (which is 10% of the total period) to a number that is
; ~9.2% calculated.  Most of the time it does not detect a normal duty cycle
; and bails.  I think if I increase this to say 5.5~ then it should work
; better.
;
        lsrd                    ; / 2
        lsrd                    ; / 4
        lsrd                    ; / 8
        lsrd                    ; / 16
        std     L004aw          ; hold in work stash
        lsrd                    ; / 32
        addd    L004aw
        lsrd
        std     L004aw          ; L004a = timing event * ~.0467
;
; purposed..........................
;
        if      mis3x
        lsrd                    ; 6.9% total PW
        lsrd                    ; if stopped here we'd have 5.7% of pulse width
;       lsrd                    ; if stopped here we'd have 5.1% of pulse width
        addd    L004aw
        std     L004aw
        endif
; .................................
        ldd     L003a
        bpl     L8dd7           ; positive now
        coma                    ; change signs
        negb
        sbca    #$ff
        subd    L004aw          ; is L003a < 5% of the Timing Period ?
        bcs     L8ddf
        ldd     L004aw
        coma                    ; make a positive number
        negb
        sbca    #$ff
        std     L003a
        bra     L8ddf
;
L8dd7:  subd    L004aw
        bcs     L8ddf
        ldd     L004aw
        std     L003a
;
; At this point abs(L003A) < 5% Timing Period
; Its value is either the calculated one or 5% limited.....
;
L8ddf:  rol     L004bw          ; L004aw = 10% Timing Period
        rol     L004aw
        xgdy                    ; D = Period_Low
        subd    L0036           ; less the time when the input was high
        subd    L003a           ; less accumulator
        pshb                    ; D = Period_Low - Period_High - L003a
        psha
        puly                    ; save in IY
;
; D and IY = the difference between the Period_low and Period_Hi - L003a
;
        bmi     L8e03           ; The High period is shorter than the low so
;                               ;  it can not be the #1 shutter.....
;
        subd    L004aw          ; is Duty Cycle difference < 10% Timing Period ?
        bcs     L8e0b           ; yes - not narrow pulse
;
; Just loose the next two lines, don't know what they except screw things up...
;
        if      not mis3x
        subd    L0036           ; less the time when the input was high
        bcc     L8e50           ; unknown pulse - clear flags
        endif
;
; The next two addd's should be subd's.......
;
        if      mis3x
        subd    L004aw          ; less 10% Timing Period
        else
        addd    L004aw          ; plus 10% Timing Period
        endif
;
        bcs     L8e43           ; Narrow pulse detected
;
        if      mis3x
        subd    L004aw          ; less 10% Timing Period
        else
        addd    L004aw          ; plus 10% more
        endif
;
        bcs     L8e43           ; Narrow Pulse
;
        if      mis3x
        bra     clear_3a        ; unknown - clr accumulator and start again
        else
        bra     L8e50           ; unknown pulse - clear flags
        endif
;
; It is not the #1 shutter.  If the difference between hi/low is less than
;  10% of the total period then we don't know where we are at.
;
L8e03:  coma                    ; change signs
        negb
        sbca    #$ff
        subd    L004aw          ; is Duty Cycle difference < 10% Timing Period ?
;
        if      mis3x
        bcc     clear_3a        ; unknown - clr accumulator and start again
        else
        bcc     L8e50           ; yes - don't know where we are at then
        endif
;
L8e0b:  xgdy                    ; get the difference between pulses back
;
; 25% of delta-L003a
;
        asra                    ; divide by two but preserve the sign on the
        rorb                    ;  ....number
        asra                    ; / 4
        rorb
        addd    L003a           ; plus what was there already
        std     L003a           ; stash new accumulator
;
; At this point we have a non-narrow duty cycle detected
;
        bset    L005b %00000001       ; signal non-number one found
        brclr   L005b %00000010 L8e40 ; didn't find #1 last time - just continue
        bclr    L005b %00000010       ; clear #1 found last time flag
        brset   L005b %00010000 L8e2d ; check if we are in sync now
        bset    L005b %00010000       ; signal in sync for the first time
;
; To set the sequencer we have had to detect a non-narrow (#1) pulse, then
;  the narrow #8 pulse, followed immediately with another confirmed non-narrow
;  pulse (#4).  So when we set this we have just hit TDC #4.....
;
L8e26:  ldaa    #$02            ; set the sequencer to #4
        staa    L0044           ; reset firing order sequencer now
        jmp     L8eab           ; read ADC and continue
;
L8e2d:  ldab    L0044           ; get the current sequence value
        cmpb    #$02            ; are we still in sync (#4) ?
        bne     L8e39           ; nope - clear in sync bit and wait for next
        bset    L005b %00001000 ; signal that we are in sync
        jmp     L8eab           ; read ADC and continue
;
L8e39:  brclr   L005b %00001000 L8e26 ; need to sync up now
        bclr    L005b %00001000 ; signal out of sync
L8e40:  jmp     L8eab           ; read ADC and continue
;
L8e43:  brclr   L005b %00000001 L8e50 ; didn't get a normal pulse last time
        bclr    L005b %00000001 ; clear normal pulse found
        bset    L005b %00000010 ; signal narrow pulse found
        jmp     L8eab           ; read ADC and continue
;
; If we got here then couldn't determine if it was a narrow pulse or a wide one
;
        if      mis3x
clear_3a:
        ldd     #0              ; clear the accumulator so bad data in it won't
        std     L003a           ; stop us from ever synching again.......
        endif
;
L8e50:  bclr    L005b %00000011 ; clear pulse type found flags
        bra     L8eab           ; read ADC and continue
;
; ----------------------------------------------------------------------------
;