Ducati 748/996 engine timeline:

Constants:
max spark advance BTDC = 63.5 degrees
max spark advance ATDC = 15 degrees
crank trigger wheel has 46 teeth with two missing
each crank trigger tooth is 7.5 cam degrees
each crank trigger tooth is 15 crank degrees
max injector duration is $7D00 (64mS) so even though H and V window shows all crank wheel trigger teeth the H & V windows will only be all crank wheel trigger teeth when engine RPM is in upper revs (available injection time <= injector duration)


In events with two letters (i.e. FH, PR, C1, etc.) the event happens at the first letter.
In events with three letters (i.e. VBE, HBC, etc.) the event happens at the middle letter.
If two events occupy the same crank trigger tooth then the events are completed in top to bottom order.
When engine is stopped or considered not running then see Note 3
all values are in decimal except if preceded with $ (then value is in hex)
Note 4 has some values that I don't understand and need to figure out
Need to add timing windows of when coils can charge (dwell time)
CurrentRevs is the time (in 2uSs) it took the engine to complete 90 degrees of cam rotation (180 degrees of crank rotation)
engine RPM == CurrentRevs (they are the same thing)
Need to add Note regarding how accelerator pump value is calculated




Crank trigger tooth count:


  1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48
  |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
																						       XXXXXXXX
                     VBE                     HBC                     VTE                     HTC                     VBC                     HBE                     VTC                     HTE
                                              C1                             IIIIIIIIIIIIIIIIIIIIII                   C2                             IIIIIIIIIIIIIIIIIIIIII
  VD                                      FH                          S2                                          FV
  S1                                      PR                                              R                       PR                                              R
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
      CR                      SR                      CR                      SR                      CR                      SR                      CR                      SR




Legend:
X = missing tooth
VBE = Vertical BDC exhaust
HBC = Horizontal BDC compression
VTE = Vertical TDC exhaust
HTC = Horizontal TDC compression
VBC = Vertical BDC compression
HBE = Horizontal BDC exhaust
VTC = Vertical TDC compression
HTE = Horizontal TDC exhaust
C1 = start calculating coil 1 (when to start charging coil and when to fire)
C2 = start calculating coil 2 (when to start charging coil and when to fire)
S1 = create shadow copy of Coil1 values
S2 = create shadow copy of Coil2 values
I = ignition window (when spark plug can fire)
H = horizontal fuel window
V = vertical fuel window
FV = forces vertical injector off (ensures it's off). Set InjectorFlags bit 3 (VertInjectorOffTimePending). Clears Flag11 bit 6 (Accel_Pump_Vertical_Injector_Enabled). Clears Flag05 bit 4 (HorizInjectorActive). Checks vertical injector for failure (if found in failure then forces it off). Sets InjectorFlags bit 7 (?).  If Flag16 bit 7 set then check rev limiters and calculate injection time (see Note 2). If Flag06 bit 1 (EnableInjectors_RPM_OK) set and If InjectorFlags bit 3 (VertInjectorOffTimePending) set then check to see if need to turn on vertical injector
FH = forces horizontal injector off (ensures it's off). Set InjectorFlags bit 1 (HorizInjectorOffTimePending). Clears Flag11 bit 4 (Accel_Pump_Horizontal_Injector_Enabled). Sets Flag05 bit 4 (HorizInjectorActive). Checks horizontal injector for failure (if found in failure then forces it off). Sets InjectorFlags bit 7 (?). If Flag16 bit 7 set then check rev limiters and calculate injection time (see Note 2). If Flag06 bit 1 (EnableInjectors_RPM_OK) set and If InjectorFlags bit 2 (HorizInjectorOffTimePending) set then check to see if need to turn on horizontal injector
PR = pre-calculate engine RPM (store IC3 value to appropriate injector)
R = calculate engine RPM (current IC3 - stored IC3)
VD = check set/clear variable dwell time flag (based on engine RPM). If Flag18 bit 0 (Variable_Dwell_Time) clear and engine RPM <= 2000 RPM then set Flag18 bit 0 (Variable_Dwell_Time). If Flag18 bit 0 (Variable_Dwell_Time) set and engine RPM >= 3000 RPM then clear Flag18 bit 0 (Variable_Dwell_Time). Check for crank trigger pickup error. If error found then see Note 1
CR = clear rev counter bit (for analog tach)
SR = set rev counter bit (for analog tach)


Note 1:
Pickup error found: Flag17 bit 4 (Pickup_Sensor_OK) cleared. Flag06 bit 4 cleared (?). Flag18 bit 0 (Variable_Dwell_Time) set. Increments pickup fault count.


Note 2:
When checking rev limiters and calculating injection time:
- if the TPS is closed then injectors are forced off and rev limiters are not checked (function returns after setting both injectors off). Function returns.
- current engine RPM is used to determine if exceeding rev limiter
- if engine RPM found to exceed rev limiter then Flag06 bit 1 cleared (EnableInjectors_RPM_OK) and function returns
- if engine RPM > 7003 RPM then engine RPM - TimingMapValue2 (see Note 6) = v1. If v1 < 0 then v1 = 0 else v1 *= 4. v1 -= current injector (horizontal or vertical) duration. if v1 < 0 then v1 = 0. v2 = current free running timer value - PR (IC3 value stored for current injector) - v1. If v2 > 0 then turn on the injector in 20uS else negate v2. v2 -= 15. if v2 < 0 then turn on the injector in 20uS else v2 = v1 + PR (IC3 value stored for current injector) + 18. Store v2 to injector output compare so injector turns on in v2 time.
- if engine RPM <= 7003 RPM then:
-- Flag06 bit 1 cleared (EnableInjectors_RPM_OK). If Flag18 bit 0 (Variable_Dwell_Time) set then:
--- If Revs_e (see Note 4) > $A then:
---- calculate total injection time and remaining time in crank degrees. v1 = remaining time in crank degrees. If v1 < $F (15 crank degrees for every tooth of crank trigger wheel) and InjectorFlags bit 7 (?) set and ((Flag05 bit 4 (HorizInjectorActive) set then turn on horizontal injector in 20uS) or (Flag05 bit 4 (HorizInjectorActive) clear then turn on vertical injector in 20uS)). If v1 >= $F then integer divide v1 by $F. Result is v2. Set Flag06 bit 1 (EnableInjectors_RPM_OK). If InjectorFlags bit 7 (?) clear then jump to Check_Fire_Injectors else:
----- if Flag05 bit 4 (HorizInjectorActive) set then v3 = Horizontal_BDC_Compression_Minus_1_Tooth + v2. If v3 >= 46 then v3 -= 46. v3 -= 2. If v3 <= 2 then v3 = 46. v3 is the crank trigger count when the horizontal injector will be told turn on in 20uS.
----- if Flag05 bit 4 (HorizInjectorActive) clear then v3 = Vertical_BDC_Compression_Minus_1_Tooth + v2. If v3 >= 46 then v3 -= 46. v3 -= 2. If v3 <= 2 then v3 = 46. v3 is the crank trigger count when the vertical injector will be told turn on in 20uS.
--- If Revs_e (see Note 4) <= $A then v2 = 40 and:
Set Flag06 bit 1 (EnableInjectors_RPM_OK). If InjectorFlags bit 7 (?) clear then jump to Check_Fire_Injectors else:
----- if Flag05 bit 4 (HorizInjectorActive) set then v3 = Horizontal_BDC_Compression_Minus_1_Tooth + v2. If v3 >= 46 then v3 -= 46. v3 -= 2. If v3 <= 2 then v3 = 46. v3 is the crank trigger count when the horizontal injector will be told turn on in 20uS.
----- if Flag05 bit 4 (HorizInjectorActive) clear then v3 = Vertical_BDC_Compression_Minus_1_Tooth + v2. If v3 >= 46 then v3 -= 46. v3 -= 2. If v3 <= 2 then v3 = 46. v3 is the crank trigger count when the vertical injector will be told turn on in 20uS.
-- If Flag18 bit 0 (Variable_Dwell_Time) clear and:
----- InjectorFlags bit 7 (?) set then calculate total injection time and remaining time in crank degrees. Calculate wait time (in 2uSs). Set output compare for injector to fire in x time or if need be fire injector in 20uS.
----- InjectorFlags bit 7 (?) clear then if either InjectorFlags bit 1 (HorizInjectorOffTimePending) or bit 3 (VertInjectorOffTimePending) set then calculate total injection time and remaining time in crank degrees. Calculate wait time (in 2uSs). Ensure injector is off. Set output compare to turn injector back on in x time or in 20uS if need be. Jump to Check_For_Horizontal_Accel_Pump.


Note 3:
engine stopped or considered not running: Flag18 bit 0 (Variable_Dwell_Time) set. Engine RPM set to $FFFF. Coil dwell time running set to first value in Dwell_Time_Table_Running. Coil dwell time starting set to first value in Dwell_Time_Table_Starting. Coil1 and Coil2 dwell times set to coil dwell time starting * $28. Starting pulse countdown set to $3.


Note 4:
calculation of Revs_e (this calculation is done in the main loop): if engine RPM <= 229 RPM then Revs_e = $0 else v1 = $E4E2 and Y = $B ($B signifies 12 crank trigger teeth for every 90 degrees of crank movement. $E4E2 signifies ???). v1 is integer divided by Y. If carry set then Revs_e = $FF. If carry not set then quotient is stored in v2 and remainder of integer division is fractional divided (fdiv) by engine RPM. Quotient is placed in v1. (Loop) Y is decremented. If Y == 0 then Revs_e = MSB of v2 else logical shift left v1 (bit 7 placed in carry flag). Rotate left LSB of v2 (carry flag placed in bit 0 and bit 7 placed in carry flag). Rotate left MSB of v2 (carry flag placed in bit 0 and bit 7 placed in carry flag). If carry clear then jump back to (Loop) else Revs_e = $FF.


Note 5:
Main loop code: constantly computing all the sensor values and checking the sensors for failures. Also computing fuel and spark advance for each cylinder (based on engine RPM). Based on setting of some flags can also check rev limiters and calculate injection time (see Note 2).


Note 6:
TimingMapValue2 calculation:
ACCB = value from TimingMap table using RPM_SparkMap values for the table lookup. ACCA = LSB of NumberOf2uSsPerCrankDegree. ACCD = ACCA * ACCB. TimingMapValue2 = ACCD.