What does it do:
1) OEM narrowbands are used to get richness measurements but don't apply AFR correction all the time
2) when driving, mainly when cruising, the (calculated) injection times are not corrected by the narrowbands (it's equivalent to have the lambda sensors removed or disabled)
3) in idle, correction applies (purpose is to target 14.7 AFR whatever the idle state is (A/C on or off)
4) Balancing of engine banks injection times is done (mainly when cruising), purpose is to target the same AFR ratios on both banks (I crosscheck this using my widebands). Basically in a VG30DETT, driver side (exhaust) is always a bit leaner (exhaust) ) than passenger side. Cyclinders 1/3/5 have a fuel pressure drop compared to cylinders 2/4/6.
5) AFR correction tables are extended in rpm range and TP load range. Basically, this gives you some indications of lean spots.
6) Consult registers table is modified to be able to track the correction factors (I use Nistune to log that).
Attached file for source and patch bin file (only changed locations are different of 0xFF).
Code: Select all
flags EQU 0x0040
sio_flags1 EQU 0x0041
sio_flags EQU 0x0043
act_mask2 EQU 0x00DD
flags6 EQU 0x0055
engine_temp_initial EQU 0x145D
engine_temp EQU 0x140C
sflag1_copy EQU 0x00D2
afr_var42 EQU 0x16A5
afr_var24 EQU 0x16A7
afr_bank2_coef EQU 0x149F
afr_bank1_coef EQU 0x14A1
inj_tot_latency EQU 0x1430
acc_coefx100 EQU 0x14B5
inj_bb1 EQU 0x1413 14
inj_bb2 EQU 0x1415 16
afr_bank1_max EQU 0x1435 ; ...
afr_bank2_max EQU 0x1437
speed EQU 0x1407
mul16_D_X EQU 0x8000
mul16_D_P1 EQU 0x8002
mul16_A_P1 EQU 0x802C
interp_16 EQU 0x80EF
afr_const24 EQU 0xFEE7
afr_const50 EQU 0xFEE8
fb_control EQU 0xFF91
AFR_min_coef: EQU 0xF407
AFR_max_coef: EQU 0xF408
rpm EQU 0x140A 0B
rpm_ref EQU 0x164D
maf EQU 0x1408 09
lambda_left EQU 0x15DA
lambda_right EQU 0x15D9
battery EQU 0x0092
throttle1 EQU 0x14A7
fuel_temp EQU 0x1428
digital1 EQU 0x153C
inj_bbb2 EQU 0x156E 6F
inj_bbb1 EQU 0x1570 71
ign_timing EQU 0x1410
idle_air EQU 0x14E1
afr_left EQU 0x1625
afr_right EQU 0x1626
afr_learn_left EQU 0x1623
afr_learn_right EQU 0x1624
digital2 EQU 0x00F0
digital3 EQU 0x00F1
mr_fc_mnt EQU 0x153D
tp_filt EQU 0x148C
tp EQU 0x1417 18
tp1 EQU 0x151F 20
timing_offset2 EQU 0x1614 15
knock_value EQU 0x1610 11
ram2_checksum EQU 0x16A0
off_372 EQU 0x16A1 A2
word_398 EQU 0x16DE DF
cnt_counter5 EQU 0x147F
inj_counter2 EQU 0x147A
byte_6135 EQU 0xFF02
byte_6136 EQU 0xFF04
rpm_d4_lo EQU 0x146A
rpm_lo EQU 0x144A
tp2 EQU 0x1505
inj_pulse_coef EQU 0x142E 2F
inj_b1 EQU 0x1456
inj_b2 EQU 0x1458
inj_flags EQU 0x0051
flags3 EQU 0x0056
inj_bank1 EQU 0x004D
inj_bank2 EQU 0x004F
inj_global_mask EQU 0x005C
warmup_counter EQU 0x1432
engine_temp2 EQU 0x00B6
inj_temp_coef EQU 0x1431
inj_temp_coef_map EQU 0xFE20
byte_6134 EQU 0xFF82
afr_bank1_map EQU 0x1700
afr_flags_left EQU 0x0053
afr_flags_right EQU 0x00CE
afr_flags EQU 0x00D1
afr_flags1 EQU 0x00CF
afr_var20 EQU 0x15CF
afr_var31 EQU 0x149C
afr_counter4 EQU 0x1440
afr_counter7 EQU 0x00B4
afr_counter10 EQU 0x1406
; ************ New variables ***************
; inj_base ==> inj_bb1 ==> inj_b1
inj_base EQU 0x15BE BF
inj_bb1_nocorrect EQU 0x15C0 C1
inj_bb2_nocorrect EQU 0x15C2 C3
inj_b1_temp EQU 0x15C4 C5 ; temporary values in inj_knock_enrichment
inj_b2_temp EQU 0x15C6 C7
inj_b1_nocorrect EQU 0x15C8 C9
inj_b2_nocorrect EQU 0x15CA CB
inj_b1_balance EQU 0x16EE EF
inj_b2_balance EQU 0x16F6 F7
; ************ New defines ***************
AFRmeasure_warm EQU 50+25 25°C
AFRmeasure_cold EQU 50+50 50°C
AFRcorrect_thres EQU 50+150 150 °C (150°C means never)
engine_temp_initial_thres EQU 50+10 10°C
max_TP_AFR_correction EQU 85 TP
; ******************************************
org 0x0000
fcb 0xFF dummy
; ******************************************
PATCHS
; ******************************************
org afr_const24
fcb AFRmeasure_cold
org afr_const50
fcb AFRmeasure_warm
org fb_control
fcb AFRcorrect_thres
org AFR_min_coef
fcb 90 Minimum AFR coef
org AFR_max_coef
fcb 110 Maximum AFR coef
org 0x8FAD
jsr reset_afr_learn_maps
org 0x9514
jsr reset_afr_learn_maps
; ******************************************
org 0xFBA0
afr_tp_scale fcb 5,8,11,15,19,23,27,32
org 0xFBA8
afr_rpm_scale fcb 16,24,40,48,56,64,76,88 800,1200,2000,2400,2800,3200,3800,4400
; to be able to log afr, "knock variables" are migrated to inj_bbbX
org 0xEA00
register_table
fdb rpm ; Register 0 ; Register 0
fdb rpm+1 ; Register 1
; fdb rpm_ref ; Register 2
; fdb rpm_ref+1 ; Register 3
fdb inj_b1_balance
fdb inj_b2_balance
; fdb maf ; Register 4
; fdb maf+1 ; Register 5
fdb afr_bank2_coef
fdb afr_bank1_coef
fdb $FFFF
fdb $FFFF
fdb engine_temp ; Register 8
; fdb lambda_left ; Register 9
; fdb lambda_right ; Register A
fdb afr_bank1_max
fdb afr_bank2_max
fdb speed ; Register B
fdb battery ; Register C
fdb throttle1 ; Register D
fdb $FFFF
; fdb fuel_temp ; Register F
fdb timing_offset2 ; instantaneous knock on accel
fdb $FFFF
fdb $FFFF
fdb $FFFF
fdb digital1 ; Register 13
fdb inj_bbb2 ; Register 14
fdb inj_bbb2+1 ; Register 15
fdb ign_timing ; Register 16
; fdb idle_air ; Register 17 AAC valve
fdb knock_value ; continuous knock detected in gear
fdb $FFFF
fdb $FFFF
fdb afr_left ; Register 1A
fdb afr_right ; Register 1B
fdb afr_learn_left ; Register 1C
fdb afr_learn_right ; Register 1D
fdb digital2 ; Register 1E
fdb digital3 ; Register 1F
fdb $FFFF
fdb mr_fc_mnt ; Register 21
fdb inj_bbb1 ; Register 22
fdb inj_bbb1+1 ; Register 23
fdb $FFFF
fdb $FFFF
; fdb $FFFF
; fdb $FFFF
fdb tp1 tp1 is real tp from AFM calculation, without any correction (e.g. ttpmin,ttpmax)
fdb tp1+1
org 0xEA50
activation_table
fdb $101
; ****** in afr_control_compute ************************************
org 0x8C05
loc_537
tim %1,flags6 ; Bit 0: throttle switch (1=idle)
; Bit 1: high octane
; Bit 2: neutral switch(1=neutral)
; Bit 3: power steering switch (1=on)
; Bit 4: A/C switch (1=on)
; Bit 7: gear engaged and high gear
; (...)
org 0x8C2E
loc_540 ; ...
ldaa engine_temp_initial ; Initial engine temp+50 (°C)
ldab engine_temp ; Engine temp+50 (°C)
cmpa #engine_temp_initial_thres
bcc loc_5991
cmpb afr_const24 ; warm start closed loop temp (above which we go into closed loop after a warm start)
bcs loc_537
bra loc_5992
org 0x8C3F
loc_5991 ; ...
; cmpb fb_control ; O2 sensor "ready" time (after warmup? seconds? minutes?)
; fb_control is now used in inj_adjust_banks
cmpb afr_const50 ; O2 sensor "ready" time (after warmup? seconds? minutes?)
bcs loc_537 ; ...
org 0x8C44
loc_5992
tim %10000,sflag1_copy ; Static value: %11001001
; ******************************************
org 0x916C
loc_638 ; ...
tim %1,flags6 ; Bit 0: throttle switch (1=idle)
; Bit 1: high octane
; Bit 2: neutral switch(1=neutral)
; Bit 3: power steering switch (1=on)
; Bit 4: A/C switch (1=on)
; Bit 7: gear engaged and high gear
; (...)
org 0x9195
loc_641 ; ...
ldaa engine_temp_initial ; Initial engine temp+50 (°C)
ldab engine_temp ; Engine temp+50 (°C)
cmpa #engine_temp_initial_thres
bcc loc_6067
cmpb afr_const24 ; warm start closed loop temp (above which we go into closed loop after a warm start)
bcs loc_638
bra loc_6068
org 0x91A6
loc_6067 ; ...
; cmpb fb_control ; O2 sensor "ready" time (after warmup? seconds? minutes?)
; fb_control is now used in inj_adjust_banks
cmpb afr_const50 ; O2 sensor "ready" time (after warmup? seconds? minutes?)
bcs loc_638
org 0x91AB
loc_6068 ; ...
tim %10000,sflag1_copy ; Static value: %11001001
; ******************************************
org 0x97F2
jsr inj_compute_banks
org 0x845F
jsr inj_knock_enrichment
org 0x8462
jsr inj_compute_output
org 0x97FD
jsr inj_compute_warm
org 0x9807
jsr inj_compute_cold
; ******************************************
END_PATCHS
; ******************************************
org 0xFFFF
fcb 0xFF dummy, just to reach 0xFFFF size
; --------------------------------------------------------------------------------------------------
org 0xE380
inj_compute_banks ; ...
tst inj_counter2
beq icb_1
dec inj_counter2
bra icb_6
icb_1: ; ...
ldab byte_6135 ; Static value: 110
tim %100,afr_flags_left
beq icb_2
subb #5 ; B=105
icb_2: ; ...
cmpb engine_temp ; Engine temp+50 (°C)
bcc icb_7
ldab #60
tim %100,afr_flags_left
beq icb_3
addb #4
icb_3: ; ...
cmpb rpm_d4_lo ; rpm_div_4_lo=lo(Engine speed/50)
bcs icb_7
ldab byte_6136
beq icb_5
tim %100,afr_flags_left
bne icb_4
addb #16
icb_4: ; ...
cmpb rpm_lo ; rpm_lo=min(rpm,255)
bcc icb_7
icb_5: ; ...
tim %100,afr_flags_left
bne icb_6
oim %100,afr_flags_left
ldaa #$32
staa inj_counter2
icb_6: ; ...
ldx tp_filt ; Filtered tp
bra icb_8
icb_7: ; ...
aim %11111011,afr_flags_left
ldx tp
icb_8: ; ...
stx tp2
ldd inj_pulse_coef
jsr mul16_D_X ; P1=D=D*X
xgdx
stx inj_base
; Compute bank 1 ---------------------------------------------------
tim %1,flags6 ; Bit 0: throttle switch (1=idle)
; Bit 1: high octane
; Bit 2: neutral switch(1=neutral)
; Bit 3: power steering switch (1=on)
; Bit 4: A/C switch (1=on)
; Bit 7: gear engaged and high gear
beq icb_11
ldd afr_var42
bra icb_12
icb_11: ; ...
ldd afr_bank2_coef
icb_12: ; ...
staa afr_learn_right
addd afr_bank1_max
sbca #100
jsr mul16_D_P1 ; P1=D=D*P1
addb inj_tot_latency
adca #0
addd acc_coefx100
std inj_bb1
; Compute bank 2 ---------------------------------------------------
tim %1,flags6 ; Bit 0: throttle switch (1=idle)
; Bit 1: high octane
; Bit 2: neutral switch(1=neutral)
; Bit 3: power steering switch (1=on)
; Bit 4: A/C switch (1=on)
; Bit 7: gear engaged and high gear
beq icb_21
ldd afr_var24
bra icb_22
icb_21: ; ...
ldd afr_bank1_coef
icb_22: ; ...
staa afr_learn_left
addd afr_bank2_max
sbca #100
jsr mul16_D_X ; P1=D=D*X
addb inj_tot_latency
adca #0
addd acc_coefx100
std inj_bb2
#if 1
; Compute bank 1 with no closed loop correction but light correction for banks balancing --------------
; we don't perform this light correction in idle to avoid any side-effect (e.g. cold startup)
tim %1,flags6 ; Bit 0: throttle switch (1=idle)
; Bit 1: high octane
; Bit 2: neutral switch(1=neutral)
; Bit 3: power steering switch (1=on)
; Bit 4: A/C switch (1=on)
; Bit 7: gear engaged and high gear
beq icb_26
icb_25
ldd #0x6400 ; if idle or conditions not met
ldx inj_base
jsr mul16_D_X ; P1=D=D*X
addb inj_tot_latency
adca #0
addd acc_coefx100
std inj_bb1_nocorrect
std inj_bb2_nocorrect
bra icb_40
icb_26
ldaa afr_bank2_coef
suba #0x64
adda afr_bank1_max
suba #0x64
ldab afr_bank1_coef
subb #0x64
addb afr_bank2_max
subb #0x64
sba ; A-B -> A
bpl icb_30
nega
cmpa #5
bls icb_28
ldaa #5
icb_28
clrb
adda #0x64
std inj_b2_balance
ldaa #0x64
std inj_b1_balance
bra icb_35
icb_30
cmpa #5
bls icb_32
ldaa #5
icb_32
clrb
adda #0x64
std inj_b1_balance
ldaa #0x64
std inj_b2_balance
icb_35
ldd inj_b1_balance
cmpa inj_b2_balance ; balancing is meaningful only if driver side leaner than passenger side
bcs icb_25
ldx inj_base
jsr mul16_D_X ; P1=D=D*X
addb inj_tot_latency
adca #0
addd acc_coefx100
std inj_bb1_nocorrect
ldd inj_b2_balance
jsr mul16_D_X ; P1=D=D*X
addb inj_tot_latency
adca #0
addd acc_coefx100
std inj_bb2_nocorrect
ldaa inj_b1_balance ; if values are equal, we reset them as a marker in the log
eora inj_b2_balance
beq icb_40
rts
icb_40
clr inj_b1_balance
clr inj_b2_balance
rts
#else
; Compute bank 1&2 with no correction ---------------------------------------------------
ldd #0x6400
ldx inj_base
jsr mul16_D_X ; P1=D=D*X
addb inj_tot_latency
adca #0
addd acc_coefx100
std inj_bb1_nocorrect
std inj_bb2_nocorrect
rts
#endif
; End of function inj_compute_banks
; --------------------------------------------------------------------------------------------------
org 0xE500
inj_knock_enrichment: ; ...
tim %10,flags6 ; Bit 0: throttle switch (1=idle)
; Bit 1: high octane
; Bit 2: neutral switch(1=neutral)
; Bit 3: power steering switch (1=on)
; Bit 4: A/C switch (1=on)
; Bit 7: gear engaged and high gear
bne ike_1
; Cylinder bank 1 ----------------------------------------------------------
ldd inj_bb1
;lsld
asld
subb inj_tot_latency
sbca #0
std inj_b1_temp
; Cylinder bank 2 ----------------------------------------------------------
ldd inj_bb2
;lsld
asld
subb inj_tot_latency
sbca #0
std inj_b2_temp
aim %11101111,inj_flags
bra ike_2
ike_1: ; ...
oim %10000,inj_flags
ldd inj_bb1
std inj_b1_temp
ldd inj_bb2
std inj_b2_temp
ike_2
ldd inj_b1_temp ; store corrected values
std inj_b1
ldd inj_b2_temp
std inj_b2
; AFR not corrected values calculation
tim %10,flags6 ; Bit 0: throttle switch (1=idle)
; Bit 1: high octane
; Bit 2: neutral switch(1=neutral)
; Bit 3: power steering switch (1=on)
; Bit 4: A/C switch (1=on)
; Bit 7: gear engaged and high gear
bne ike_5
; Cylinder bank 1 ----------------------------------------------------------
ldd inj_bb1_nocorrect
;lsld
asld
subb inj_tot_latency
sbca #0
std inj_b1_nocorrect
; Cylinder bank 2 ----------------------------------------------------------
ldd inj_bb2_nocorrect
;lsld
asld
subb inj_tot_latency
sbca #0
std inj_b2_nocorrect
aim %11101111,inj_flags
rts
ike_5: ; ...
oim %10000,inj_flags
ldd inj_bb1_nocorrect
std inj_b1_nocorrect
ldd inj_bb2_nocorrect
std inj_b2_nocorrect
rts
; End of function inj_knock_enrichment
; --------------------------------------------------------------------------------------------------
org 0xE580
inj_compute_output:
; in idle, we apply the AFR corrected values to target 14.7 only if real idle conditions are met
tim %1,flags6 ; Bit 0: throttle switch (1=idle)
; Bit 1: high octane
; Bit 2: neutral switch(1=neutral)
; Bit 3: power steering switch (1=on)
; Bit 4: A/C switch (1=on)
; Bit 7: gear engaged and high gear
beq ico_00
ldaa speed ; in real idle only if speed=0
bne ico_10
ldaa warmup_counter ; corrected values only if warmup_counter expired (0xFF)
coma
beq ico_02
bra ico_10
ico_00
ldaa engine_temp ; when driving, is temp threshold ok for correction ?
cmpa fb_control
bcs ico_10
ldaa tp1 ; when driving, is TP below TP threshold ?
cmpa #max_TP_AFR_correction
bcc ico_10
; Working with the corrected values here
ico_02
tim %100,flags3 ; Bit 0: PORT5 bit 4 inverted, if 0 then injection cut
; Bit 2: Activated once every 2 IRQ2
; Bit 3: Compute main maps
; Bit 6: Activated once every 10 IRQ2
; Bit 7: IRQ2 interrupt active
beq ico_4
tim %1,flags3 ; Bit 0: PORT5 bit 4 inverted, if 0 then injection cut
; Bit 2: Activated once every 2 IRQ2
; Bit 3: Compute main maps
; Bit 6: Activated once every 10 IRQ2
; Bit 7: IRQ2 interrupt active
beq ico_1
ldd #1
ldx #1
bra ico_3
ico_1: ; ...
ldd inj_b1
ldx inj_b2
lsrd
lsrd
addd inj_b1
xgdx
lsrd
lsrd
addd inj_b2
sei
tim %10000,inj_flags
bne ico_2
aim %11011111,inj_flags
bra ico_3
ico_2: ; ...
oim %100000,inj_flags
ico_3: ; ...
std inj_bank2
stx inj_bank1
ico_4: ; ...
cli
ldaa inj_global_mask
anda %10101
cmpa %10101
bne ico_5
clra
ldab inj_tot_latency
bra ico_6
ico_5: ; ...
ldd inj_b1
ico_6: ; ...
std inj_bbb1
ldaa inj_global_mask
anda %101010
cmpa %101010
bne ico_7
clra
ldab inj_tot_latency
bra ico_8
ico_7: ; ...
ldd inj_b2
ico_8: ; ...
std inj_bbb2
rts
; Working with the NOT corrected values here
ico_10:
tim %100,flags3 ; Bit 0: PORT5 bit 4 inverted, if 0 then injection cut
; Bit 2: Activated once every 2 IRQ2
; Bit 3: Compute main maps
; Bit 6: Activated once every 10 IRQ2
; Bit 7: IRQ2 interrupt active
beq ico_44
tim %1,flags3 ; Bit 0: PORT5 bit 4 inverted, if 0 then injection cut
; Bit 2: Activated once every 2 IRQ2
; Bit 3: Compute main maps
; Bit 6: Activated once every 10 IRQ2
; Bit 7: IRQ2 interrupt active
beq ico_11
ldd #1
ldx #1
bra ico_33
ico_11: ; ...
ldd inj_b1_nocorrect
ldx inj_b2_nocorrect
lsrd
lsrd
addd inj_b1_nocorrect
xgdx
lsrd
lsrd
addd inj_b2_nocorrect
sei
tim %10000,inj_flags
bne ico_22
aim %11011111,inj_flags
bra ico_33
ico_22: ; ...
oim %100000,inj_flags
ico_33: ; ...
std inj_bank2
stx inj_bank1
ico_44: ; ...
cli
ldaa inj_global_mask
anda %10101
cmpa %10101
bne ico_55
clra
ldab inj_tot_latency
bra ico_66
ico_55: ; ...
ldd inj_b1_nocorrect
ico_66: ; ...
std inj_bbb1
ldaa inj_global_mask
anda %101010
cmpa %101010
bne ico_77
clra
ldab inj_tot_latency
bra ico_88
ico_77: ; ...
ldd inj_b2_nocorrect
ico_88: ; ...
std inj_bbb2
rts
; End of function inj_compute_output
; --------------------------------------------------------------------------------------------------
org 0xE680
inj_compute_warm: ; ...
tim %1,inj_flags
bne icg_1
clr warmup_counter
oim %1,inj_flags
icg_1: ; ...
ldx tp
ldd inj_pulse_coef
jsr mul16_D_X ; P1=D=D*X
ldaa #130
jsr mul16_A_P1 ; P1=D=A*(P1+P2/256)
addb inj_tot_latency
adca #0
addd acc_coefx100
std inj_bb1
std inj_bb2
std inj_bb1_nocorrect
std inj_bb2_nocorrect
rts
; End of function inj_compute_warm
; --------------------------------------------------------------------------------------------------
org 0xE700
inj_compute_cold: ; ...
ldaa engine_temp2 ; engine_temp*1.6+0.5
ldx #inj_temp_coef_map
jsr interp_16 ; X=table adress
; A=value to look up
;
; A=output value
staa inj_temp_coef
ldab rpm_lo ; rpm_lo=min(rpm,255)
cmpb #12
bls ice_3
cmpb #48
bcc ice_1
subb #12
ldaa #6
mul
negb
bra ice_2
ice_1: ; ...
ldab byte_6134
ice_2: ; ...
ldaa inj_temp_coef
mul
staa inj_temp_coef
ice_3: ; ...
ldab warmup_counter
subb #10
bls ice_4
ldaa #20
mul
negb
addb #100
bra ice_5
ice_4: ; ...
ldab #100
ice_5: ; ...
ldaa inj_temp_coef
mul
xgdx
cpx inj_bb1
bcs ice_6
stx inj_bb1
stx inj_bb1_nocorrect
ice_6: ; ...
cpx inj_bb2
bcs ice_7
stx inj_bb2
stx inj_bb2_nocorrect
ice_7: ; ...
rts
; End of function inj_compute_cold
; --------------------------------------------------------------------------------------------------
org 0xE780
reset_afr_learn_maps
ldd #$6400
std afr_var42
std afr_var24
ldx #afr_bank1_map
loc_6115: ; ...
std 0,x
inx
inx
cpx #afr_bank1_map+0x100
bne loc_6115
rts
org 0xE7F0 to check potential overlap with the tpu_param_1 table
******************************
VERSION fcc 'AFR v16.4_0'