Fuel logic documentation

Talk and Tech about turbocharged 924/944/968 cars
User avatar
johnb
Posts: 363
Joined: Thu Jul 08, 2021 5:57 am
Has thanked: 121 times
Been thanked: 93 times
whalenlg wrote: Mon Aug 31, 2026 11:32 pm
Tom wrote: Sun Aug 30, 2026 8:10 pm I'll run it on my DME next week, as I'll have my hands full with other things this week. That's a great discovery -- love it. I guess the benefit is to ensure at least one of the pulses is close to intake valve opening -- wonder if one could smooth out the idle by keeping that active at low rpms... May have to try that once I get my car back from the paint shop.

Perhaps others already knew this, but I discovered this weekend that the factory BIN has a UART serial stream with RPM, load, commanded fuel, AFM, coolant, IAT, battery voltage, and other RAM variables -- at 1E53. It requires a handshake to enable (which I disabled for testing) and seems quite hackable to spit out whatever data you might want (including variables, etc). I was able to connect to it this afternoon and pick up the data stream. I assume it was the port for the original Bosch diagnostic equipment, at is also includes an ability to adjust injector pulses and timing. :shifty:
I found these a few weeks back and put it in my dashboard....
Screenshot 2026-08-31 at 11.25.32 PM.png

KLR has a failure status byte (33h) - there's an additional 1-1 code that occurs but isn't documented anywhere...I've seen it when there are back to back knocks or when one of the power supplies was below tolerance. There's no UART on the 8048, so these codes must be blipped out to LEDs via firmware.
Screenshot 2026-08-31 at 11.25.32 PM.png
The 1-1 code is not a real blink code. It's set if at least one cylinder has had the max timing retard (controlled by the map at 925). It's not set if there's an existing blink code in 33h, and it shouldn't trigger limp mode from my understanding. The logic is at F5C. At F65/F67, we check for this value in 33h and don't jump to the limp mode code if its there.

It gets cleared in the knock detection routine if the throttle goes below a certain position. That's the only position I know of where it's read, so ultimately it doesn't seem to serve any purpose. There is code in there to reduce boost if timing reduction has hit the max value, but I don't think it depends on this 33h code. So my best guess is that either it once was used for this, and they changed the approach, or maybe at one time hitting a certain knock threshold *did* trigger a blink code, but they ended up going a different way.

The thing I was thinking of for diagnostic is the routine at 336 - my notes have it labeled as an unused diagnostic routine, but I can't remember what I based that on.

I *really* need to revisit the KLR stuff, reading some of my old "explanations" I realize I had a lot to learn about how to write code walkthroughs lol.

#41

User avatar
whalenlg
Posts: 441
Joined: Mon Jul 05, 2021 8:58 am
Has thanked: 8 times
Been thanked: 119 times
johnb wrote: Tue Sep 01, 2026 6:14 am
whalenlg wrote: Mon Aug 31, 2026 11:32 pm
Tom wrote: Sun Aug 30, 2026 8:10 pm I'll run it on my DME next week, as I'll have my hands full with other things this week. That's a great discovery -- love it. I guess the benefit is to ensure at least one of the pulses is close to intake valve opening -- wonder if one could smooth out the idle by keeping that active at low rpms... May have to try that once I get my car back from the paint shop.

Perhaps others already knew this, but I discovered this weekend that the factory BIN has a UART serial stream with RPM, load, commanded fuel, AFM, coolant, IAT, battery voltage, and other RAM variables -- at 1E53. It requires a handshake to enable (which I disabled for testing) and seems quite hackable to spit out whatever data you might want (including variables, etc). I was able to connect to it this afternoon and pick up the data stream. I assume it was the port for the original Bosch diagnostic equipment, at is also includes an ability to adjust injector pulses and timing. :shifty:
I found these a few weeks back and put it in my dashboard....
Screenshot 2026-08-31 at 11.25.32 PM.png

KLR has a failure status byte (33h) - there's an additional 1-1 code that occurs but isn't documented anywhere...I've seen it when there are back to back knocks or when one of the power supplies was below tolerance. There's no UART on the 8048, so these codes must be blipped out to LEDs via firmware.
Screenshot 2026-08-31 at 11.25.32 PM.png
The 1-1 code is not a real blink code. It's set if at least one cylinder has had the max timing retard (controlled by the map at 925). It's not set if there's an existing blink code in 33h, and it shouldn't trigger limp mode from my understanding. The logic is at F5C. At F65/F67, we check for this value in 33h and don't jump to the limp mode code if its there.

It gets cleared in the knock detection routine if the throttle goes below a certain position. That's the only position I know of where it's read, so ultimately it doesn't seem to serve any purpose. There is code in there to reduce boost if timing reduction has hit the max value, but I don't think it depends on this 33h code. So my best guess is that either it once was used for this, and they changed the approach, or maybe at one time hitting a certain knock threshold *did* trigger a blink code, but they ended up going a different way.

The thing I was thinking of for diagnostic is the routine at 336 - my notes have it labeled as an unused diagnostic routine, but I can't remember what I based that on.

I *really* need to revisit the KLR stuff, reading some of my old "explanations" I realize I had a lot to learn about how to write code walkthroughs lol.
The 1st time I saw it was when one of the input ranges was off. Now I see it as described above - when 2nd consecutive knock is applied to the same cylinder and the retard value goes from 9h to 18h. 33 gets set about the same time. I also the 11 code in 33h when I short the knock sensor to ground (which results in a lot of false knock events). I'll try ramping down the RPMS to see if it clears.
336 is definitely firing in my simulation. I do see the instruction at 37a firing that is a movx @r1,a which is doing external writes. I see writes of 00 to address 80 and FF to address 87 so far.
1986 951 - Silicon Valley

#42

User avatar
whalenlg
Posts: 441
Joined: Mon Jul 05, 2021 8:58 am
Has thanked: 8 times
Been thanked: 119 times
whalenlg wrote: Tue Sep 01, 2026 11:39 am I'll try ramping down the RPMS to see if it clears.
Yes - the 1-1 code clears somewhere around 1000 rpm
1986 951 - Silicon Valley

#43

User avatar
johnb
Posts: 363
Joined: Thu Jul 08, 2021 5:57 am
Has thanked: 121 times
Been thanked: 93 times
Some big updates.

I compiled a master memory map of all the variables, flags, constants and maps from all the code walkthroughs I've done: https://jhnbyrn.github.io/951-KLR-PAGES ... y_map.html

(I did use Claude to gather these from the articles I wrote, but so far I haven't been able to spot any errors - please let me know if you do).

None of these are speculative unless it says so - they are linked to the detailed explanations of where they're used.

I also updated all the code walkthroughs with similar sections in the appendices, listing the variables and maps etc. I gave up on trying to mark these as input or output though, I just couldn't find a way to do that that wouldn't be misleading.

Finally, I added a few more explanations with companion code walkthroughs:

* post ignition routine (where final fuel corrections are made and injectors are fired, among other things): https://jhnbyrn.github.io/951-KLR-PAGES ... rview.html

* fuel cutoffs (how fuel is cut off for overload/coasting and how this ties in with timing): https://jhnbyrn.github.io/951-KLR-PAGES ... rview.html

This pretty much covers everything fuel-related as far as I know, and most timing stuff too. I will still write something to give a higher level overview of the whole timing calculation process, since it's not trivial and I have mostly just covered the details in separate places.

There's still more interesting things to document, but I think all the hard stuff is captured now. The presentation could be improved but I don't think we're missing any details.

#44

User avatar
whalenlg
Posts: 441
Joined: Mon Jul 05, 2021 8:58 am
Has thanked: 8 times
Been thanked: 119 times
Hi John - Here are a few others in my notes...
mem addr:
15 ADC_Ch5 (ground - DME pin 28)
16 ADC_TPS
1D bank3_R5 used in extint1_handler
29 diag_index Used for indexing table of RAM addresses to send from and receive to during diagnostics
2A wdog_timer Software watchdog timer
38 3C_prescaler
39 3D_prescaler
3A 3E_prescaler
3B 3F_prescaler
40 TL1_high_reload
43 TH1_high_reload
7A probably used as sequence number, written and read during diagnostics
Bit addresses
20.1 Startup bit 1 - at startup phase, a locally used init flag
22.7 17 Time1FlagLowIdle bit 7 - timer 1 flag: set at start of low idle speed positioner pulse
23.7 1F TXDLambdaDiag bit 7 - 1= TXD used for lambda diag
25.2 2A MapLookFail bit 2 - 1= map lookup failed
25.3 2B DiagNotSet bit 3 - 1= diagnostics mode not set, =0 when mode has been selected
P1.2 92 DMERelay
P1.3 93 P1.3
P1.4 94 IdleSpeed
P1.5 95 KLROut
1986 951 - Silicon Valley

#45

User avatar
johnb
Posts: 363
Joined: Thu Jul 08, 2021 5:57 am
Has thanked: 121 times
Been thanked: 93 times
whalenlg wrote: Fri Sep 04, 2026 4:12 pm Hi John - Here are a few others in my notes...
mem addr:
15 ADC_Ch5 (ground - DME pin 28)
16 ADC_TPS
1D bank3_R5 used in extint1_handler
29 diag_index Used for indexing table of RAM addresses to send from and receive to during diagnostics
2A wdog_timer Software watchdog timer
38 3C_prescaler
39 3D_prescaler
3A 3E_prescaler
3B 3F_prescaler
40 TL1_high_reload
43 TH1_high_reload
7A probably used as sequence number, written and read during diagnostics
Bit addresses
20.1 Startup bit 1 - at startup phase, a locally used init flag
22.7 17 Time1FlagLowIdle bit 7 - timer 1 flag: set at start of low idle speed positioner pulse
23.7 1F TXDLambdaDiag bit 7 - 1= TXD used for lambda diag
25.2 2A MapLookFail bit 2 - 1= map lookup failed
25.3 2B DiagNotSet bit 3 - 1= diagnostics mode not set, =0 when mode has been selected
P1.2 92 DMERelay
P1.3 93 P1.3
P1.4 94 IdleSpeed
P1.5 95 KLROut
Thanks!

I've got the counter prescalers as 33h-36h, that's where they are in the 28 pin image I'm using. They're listed along with the lambda timer reload values. I have 38-3B listed as idle stabilizer constants.

The others I'll add when I can. You've highlighted an important thing here which is that I have never properly documented the 8051 port pin and ADC channel assignments, so that's going on my list.

#46

User avatar
whalenlg
Posts: 441
Joined: Mon Jul 05, 2021 8:58 am
Has thanked: 8 times
Been thanked: 119 times
Thanks - the next step I have for my environment is to create unique ID pneumonics for each byte, bit and constants/tables. Here's a sample of what claude does with the data for byte locations:

10h AFM_RAW raw AFM wiper value, from the ADC
11h SYS_VOLTAGE system voltage, from the ADC
12h IAT_NTC1 intake air temperature (NTC I), from the ADC
13h COOLANT_NTC2 coolant temperature (NTC II), from the ADC
14h ALT_REGION_ADC altitude sensor / region coding input, from the ADC
15h RESERVED_15H undefined/unknown
16h RESERVED_16H undefined/unknown
17h FQS_POSITION FQS switch position, from the ADC
18h LAMBDA_STEP_UNCHANGED lambda correction step, condition unchanged (Map 62 or 65)
19h LAMBDA_STEP_TO_LEAN lambda correction step, changed to lean (Map 63 or 66)
1Ah LAMBDA_STEP_TO_NOTLEAN lambda correction step, changed to not-lean (Map 64 or 67)
1Bh LAMBDA_CORR_HI lambda correction factor, high byte
1Ch LAMBDA_CORR_LO lambda correction factor, low byte

bits:
20h.0 ISV_FLARE_VARIANT ISV flare variant: 0 = return to idle, 1 = startup
20h.1 RESERVED_20H_1 undefined/unknown
20h.2 ISV_RPM_ERR_SIGN ISV idle rpm error sign: 1 = rpm too high, 0 = rpm too low
20h.2 LAMBDA_COND_CURRENT *reused for lambda:* current condition, 0 = lean, 1 = not lean
20h.3 ISV_INT_BLOCK_POS blocks integration when a positive ISV correction is clamped
20h.4 ISV_INT_BLOCK_NEG blocks integration when a negative ISV correction is clamped, or when load is below the Map 87 value
20h.5 ISV_PWM_OVF_SIGN ISV PWM correction overflow sign (which way to clamp)
20h.6 ISV_FLARE_NEEDED an idle flare is needed on return to idle
20h.7 LAMBDA_ENABLE master enable for closed loop lambda control; only set on US (cat/O2) cars
1986 951 - Silicon Valley

#47

Post Reply