Pages: 1 2 3 [4] 5
Print
Author Topic: Another hex dump interpretation  (Read 6888 times)
log1call
*
Offline Offline

Posts: 62


View Profile
« Reply #45 on: January 22, 2009, 03:04:32 AM »

Just reporting in.  I did about two hours this afternoon reading and going through my hex dump following your steps and trying to learn what some of the commands in the instructions do. Plenty more to learn still so will keep you posted.
               Cheers, Brett.

P.S.  I liked "findstr 102e Sub-* | findstr seb"  now you are talking!
Logged
log1call
*
Offline Offline

Posts: 62


View Profile
« Reply #46 on: January 25, 2009, 08:33:11 PM »

Hi Phil,
          I'm still here but getting less confident by the day that I am ever going to understand this.
 
 I have followed through all you have written and have seen that your reasoning has worked with the tps. I have been trying to get some insights to how this works in a generic sort of a way to find other parameters but so far it seems to me that only a lot of prior knowledge of programming lets you know what step to take next.

 Back on page three you wrote...
"Now lets look for the code that sets an error. We'll start with an easy one, the TPS.

From the table in the previous post, you can see that the TPS error flag is bit 4 of 4042. We count bit numbers from right to left, starting at zero.

00000000 (00)   00010000 (10)   00000000 (00)   31   Throttle Sensor

To find the subroutine that sets this flag do the following:

findstr 4042 Sub-*

This gives a list of all the subroutines that access address 4042. Somewhere in the list you will find:

Sub-9E69.txt:009E8A    0C424010      seb     #0x10, 0x4042
Sub-9E69.txt:009E93    1C424010      clb     #0x10, 0x4042

The "seb" instruction means SEt Bits (to 1). the "clb" instruction means CLear Bits (to 0). The #0x10 is the hex code for the TPS error bit in the table. So we have found that subroutine 9E69 turns the TPS error flag on and off. The location for the TPS parameter will probably be somewhere in that subroutine."
 
 But when I ran that search I found sub 9df7 refering to #0x10, 0x4042 and using the seb and clb commands as well. So, is there some reason to choose the 9e69, the one that referances the A/D? Surely if we follow the first.. 9df7, it must eventualy lead to the A/D as well?  Since it sets the CE code for the TPS?

I have done all that you have suggested so far, but I am still confused how you choose which subs to explore and which ones are irrelevant.

 If you are willing Phil, could we try and follow through another example? Hopefully I will start to see how the logic is being applied as I come to understand more about the programming practices.

 Also Phil, a thought I had... I suppose you already know it but, just in case... the fuel mixture is adjusted by temperature, tps, revs and it also has another factor introduced somewhere that takes into account the speed you open the throttle at. It is to overcome airflow lag between the butterfly and the MAF. Had you heard of that?


Logged
b3lha
*
Offline Offline

Posts: 198



View Profile WWW
« Reply #47 on: January 26, 2009, 05:04:35 AM »

findstr 4042 Sub-*

This gives a list of all the subroutines that access address 4042. Somewhere in the list you will find:

Sub-9E69.txt:009E8A    0C424010      seb     #0x10, 0x4042
Sub-9E69.txt:009E93    1C424010      clb     #0x10, 0x4042

The "seb" instruction means SEt Bits (to 1). the "clb" instruction means CLear Bits (to 0). The #0x10 is the hex code for the TPS error bit in the table. So we have found that subroutine 9E69 turns the TPS error flag on and off. The location for the TPS parameter will probably be somewhere in that subroutine."
 But when I ran that search I found sub 9df7 refering to #0x10, 0x4042 and using the seb and clb commands as well. So, is there some reason to choose the 9e69, the one that referances the A/D? Surely if we follow the first.. 9df7, it must eventualy lead to the A/D as well?  Since it sets the CE code for the TPS?
I think you may have misread your screen. Sub-9E69 is the only one that contains "seb #0x10, 0x4042". The subroutine you found Sub-9DF7 contains "seb #0x01, 0x4042". That is the temperature sensor error flag.  Smiley
If you are willing Phil, could we try and follow through another example? Hopefully I will start to see how the logic is being applied as I come to understand more about the programming practices.
Yeah. I'll go through a few more this week.
Also Phil, a thought I had... I suppose you already know it but, just in case... the fuel mixture is adjusted by temperature, tps, revs and it also has another factor introduced somewhere that takes into account the speed you open the throttle at. It is to overcome airflow lag between the butterfly and the MAF. Had you heard of that?
Yeah, I've seen something like that. IIRC The ECU reads the TPS several times a second at fixed time intervals. It stores the last few values in a table so that it can work out the rate of change.

As far as I know, the ECU works out a base value for the fuel mixture. Then there are lots of adjustments that get made to it for one reason or another. I don't think anybody except Subaru knows what they all are.
« Last Edit: January 26, 2009, 09:10:51 AM by b3lha » Logged

See my Subaru ECU and TCU website.
http://www.alcyone.org.uk/ssm
b3lha
*
Offline Offline

Posts: 198



View Profile WWW
« Reply #48 on: January 26, 2009, 09:55:50 AM »

Once we have found a parameter, it is a good idea to mark it with a comment everywhere it appears in the code. This makes the code a little easier to read.

Code:
00F175    AE5140        ldx     0x4051 ; Throttle Position
00F178    EC9A42        cpx     0x429a
00F17B    9003          bcc     0xf180

For this you need a search and replace tool. I suggest that you download "grepwin" from http://code.google.com/p/grepwin

Refer to the attached screenshot:

Search in: H:\SVX\Brett
Type in the path of the directory where you are keeping your Sub-nnnn.txt files.

Search for: (^.*0x4051.*$)
This is what programmers call a regular expression (regex). Ignore the brackets for a moment. The first part "^" means "start of line". The next bit ".*" means "anything". The "0x4051" is the variable that we are searching for. The next ".*" means "anything" and the "$" means "end of line". In other words, we are searching for "start of line" "anything" "0x4051" "anything" "end of line". The idea is that the search field should match the whole line, not just the 0x4051.

Replace with: \1 ; Throttle Position
The first bit "\1" refers to whatever was matched by the regex inside the brackets in the "Search For" above. In other words, the whole line containing 0x4051. The next bit is our comment " ; Throttle Position". The program will search for "the line containing 0x4051" and replace it with "the line containing 0x4051" followed by " ; Throttle Position". ie. It will append the comment to the line.

Files which match: Sub-*.txt
We only want to carry out the work on the Sub-nnnn.txt files.

Then you click the "Replace" button to add the comments for you. If you do a findstr on 0x4051 then you should be able to see the comments in every subroutine where it is referenced.

Code:
H:\SVX\Brett>findstr 0x4051 Sub-*
Sub-EFAE.txt:00EFE6    EC5140        cpx     0x4051 ; Throttle Position
Sub-A06A.txt:00A094    ED5140        sbc     ax, 0x4051 ; Throttle Position
Sub-F170.txt:00F175    AE5140        ldx     0x4051 ; Throttle Position
Sub-DFEA.txt:00DFEA    AE5140        ldx     0x4051 ; Call target from E0F0 ; Throttle Position
Sub-DFEA.txt:00E042    8D5140        sta     ax, 0x4051 ; Throttle Position
Sub-DFEA.txt:00E0EC    8E5140        stx     0x4051 ; Throttle Position
Sub-9E69-Test-TPS.txt:009E6E    ED5140        sbc     ax, 0x4051 ; Throttle Position

You don't really have to understand how the regex pattern matching works, just follow the same pattern as the example.

We can do a similar thing for the subroutine call. It looks like the only purpose of Sub-9E69 is to test the TPS. So let's mark it as such in the code.

Code:
009CF3    20C49D        jsr     0x9dc4
009CF6    20F79D        jsr     0x9df7
009CF9    20699E        jsr     0x9e69 ; Test TPS
009CFC    20989E        jsr     0x9e98
009CFF    20329F        jsr     0x9f32

Exactly the same as before, but this time:
Search for: (^.*0x9E69.*$)
Replace with: \1 ; Test TPS

Also, let's rename "Sub-9E69.txt" to "Sub-9E69-Test-TPS.txt"

« Last Edit: January 26, 2009, 10:05:18 AM by b3lha » Logged

See my Subaru ECU and TCU website.
http://www.alcyone.org.uk/ssm
log1call
*
Offline Offline

Posts: 62


View Profile
« Reply #49 on: January 26, 2009, 07:30:20 PM »

Hi Phil,
         that would be just like me to misread things... even after,(or perhaps because), I had read it a dozen times.

 I have tried a bit of parsing before using a program called windmill and some other serial port eavesdropping software... trying to log the results of the VWRX software before logging was supported, so I'm sort of aware of the concept of regular expression.

 I was thinking of remarking some of the files but wasn't sure if that would cause a problem. Now I'll have remarks everywhere!

I will get that program you said and try the renaming excercise.
 

 You said Phil...
 "As far as I know, the ECU works out a base value for the fuel mixture. Then there are lots of adjustments that get made to it for one reason or another. I don't think anybody except Subaru knows what they all are."
 As I understand it...  The base values are in the map, in rom. The ecu monitors engine temp, intake air temp, revs, air-flow and throttle position to calculate an adjustment factor,(called long term adjustment), which they apply to the base map. They then write the adjusted basemap to ram.  Then they use the O2 sensor reading as a factor(what we measure as A/F), to apply to the ram map to set the IPW. If the O2 adjustment factor gets beyond a certain limit, they rewrite the ram map to bring the O2 adjustment factor back to zero,(This is called short term fuel adjustment).
 Somewhere in there subaru also carry out that other adjustment based on the speed of change of throttle valve angle.
 I have never seen it written where that last adjustment fits in but, all the other maps and adjustment factors are pretty much standard for all newish cars.
                                                                                 Cheers, Brett.
Logged
b3lha
*
Offline Offline

Posts: 198



View Profile WWW
« Reply #50 on: January 27, 2009, 07:59:11 AM »

Right, lets find some more parameters.

Picking an easy one again: Atmospheric Pressure

First we find the subroutine that sets the atmospheric pressure sensor error bit: bit 4 (0x10) of 0x4041.
Code:
H:\SVX\Brett>findstr 0x4041 Sub-* | findstr seb | findstr 10
Sub-9F32.txt:009F73    0C414010      seb     #0x10, 0x4041

Then we have a look at Sub-9F32. It looks very similar to the TPS subroutine we looked at before:

Code:
009F32    3C4A80020F    bbc     #0x02, 0x804a, 0x9f46           ; Call target from 9CFF
009F37    78            sei
009F38    2C30420808    bbs     #0x08, 0x4230, 0x9f45
009F3D    AD3342        lda     al, 0x4233
009F40    CDC688        cmp     al, 0x88c6
009F43    B002          bcs     0x9f47
009F45    58            cli                                     ; Branch target from 9F38
009F46    60            rts                                     ; Branch target from 9F32
In the first section of code we have some preconditions that must be met before the sensor is tested. BBC means Branch if Bit Clear. The instruction at 9F32 checks bit 1 (0x02) of 0x804A. If that bit is a zero then the program jumps to 9F46 which is an RTS instruction (exit from the subroutine). Address 804A is in the ROM, it is a constant, set when the ECU chip is programmed. It is probably a switch that specifies whether this ECU is fitted with an atmospheric pressure sensor. Let's have a look at 0x804A:

00008040   80 00 32 00 68 03 9C 02 80 01 01 30 09 8D 30 00

The value of 804A is 01. That's 00000001 in binary. The value of bit 1 IS zero. Therefore this subroutine will ALWAYS exit immediately without ever testing the sensor or setting the error code.

We can conclude that this ECU probably doesn't have an atmospheric pressure sensor, despite having the CE code in its error table. If it does have one then it doesn't test it, so presumably it doesn't use it.

Subaru probably use the same ECU program in several different markets. In some markets (USA) they fit an atmospheric pressure sensor and switch on bit 1 of 804A. In other markets (NZ, Japan), they omit the sensor and turn the switch off.

Not much point continuing to look for this parameter, but Just for the hell of it, let's see if we can find out what the address would be if the ECU supported it. The rest of the first block are more preconditions that must be met to get us into the second block where the test is done. I've added some comments for you.
Code:
009F47    58            cli                                     ; Branch target from 9F43
009F48    AE3142        ldx     0x4231 ; Get sensor reading
009F4B    EC1E8C        cpx     0x8c1e ; compare to lower limit
009F4E    9005          bcc     0x9f55 ; if less goto 9f55
009F50    EC208C        cpx     0x8c20 ; compare to upper limit
009F53    9011          bcc     0x9f66 ; if less goto 9f66
009F55    A25342        ldx     #0x4253                         ; Branch target from 9F4E
009F58    20DFA3        jsr     0xa3df ; Add 1 to counter at X
009F5B    CD228C        cmp     al, 0x8c22 ; Compare counter to threshold
009F5E    900E          bcc     0x9f6e ; if lower goto 9f6e
009F60    0C514204      seb     #0x04, 0x4251 ; set bit 2 of 4251
009F64    8008          bra     0x9f6e ; goto 9f6e
We recognise the call to 0xA3DF from the TPS subroutine. This means "add 1 to counter at X". We should comment that with grepwin: Search for "(^.*0xA3DF.*$)" and replace with "\1 ; Add 1 to counter at X". Also, rename the file Sub-A3DF.txt to Sub-A3DF-Add-1-to-counter-at-X.txt

Presumably it works in the same way at the TPS: The counter at 0x4253 is counting the number of bad results from the pressure sensor. When it passes the threshold at 0x8c22, the error flag will be set. It's a pretty safe assumption that the atmospheric pressure is at 0x4231 and the acceptable limits are at 8c1e and 8c20.
Code:
009F66    9C534200      ldm     #0x00, 0x4253 ; reset counter to zero                  ; Branch target from 9F53
009F6A    1C514204      clb     #0x04, 0x4251 ; clear bit 2 of 4251
009F6E    3C51420705    bbc     #0x07, 0x4251, 0x9f78           ; Branch target from 9F5E, Branch target from 9F64
009F73    0C414010      seb     #0x10, 0x4041 ; set Atmos error flag
009F77    60            rts

009F78    1C414010      clb     #0x10, 0x4041 ; clear Atmos error flag   ; Branch target from 9F6E
009F7C    60            rts
I think this needs a little explantion. If we get a bad reading and the error count is greater than the threshold, it sets bit 2 of 4251. On the other hand, if we get a good reading, it clears the error counter and bit 2 of 4251.
But the line that decides whether the Atmos error flag gets set or cleared is at 9F6E.
Code:
009F6E    3C51420705    bbc     #0x07, 0x4251, 0x9f78
Branch if Bits Clear #0x07 of 0x4251.
The 0x07 in binary is 00000111. So, if bits 0,1 and 2 of 4251 are zero then it will goto 9f78, which clears the atmos error flag. But If any of the bits are one then it will continue to 9f73 and set the atmos error flag. We know that bit 2 gets set by the code at 9f60 as I described earlier, but there is nothing here to set bits 0 or 1. There is probably something elsewhere in the ECU that sets these bits.

I'm not going to investigate that at present because we found what we came here for. We know that this ECU doesn't use the Atmospheric Pressure Sensor and we know that if it did then the 16-bit value would be at 4231.

Let's see if there is an 8 bit equivalent to 4231.

Code:
H:\SVX\Brett>findstr 0x4231 Sub*
Sub-E3B9.txt:00E3D3    8D3142        sta     ax, 0x4231
Sub-E3B9.txt:00E4EC    6D3142        adc     ax, 0x4231
Sub-E3B9.txt:00E4F3    8D3142        sta     ax, 0x4231
Sub-E3B9.txt:00E4F9    890D3142      mpy     0x4231
Sub-9F32.txt:009F48    AE3142        ldx     0x4231
Sub-E3B9 contains a store instruction for address 4231 (actually it contains two!).
Code:
00E3B9    342008FC      bbc     #0x08, dp + 0x20, 0xe3b9        ; Call target from DCEA, Read from A/D control register, Branch target from E3B9
00E3BD    2C4A800216    bbs     #0x02, 0x804a, 0xe3d8
00E3C2    D8            clm                                     ; m:0 x:0
00E3C3    A522          lda     ax, dp + 0x22                   ; Read from A/D successive approximation register
00E3C5    3C4A800C0008  bbc     #0x000c, 0x804a, 0xe3d3
00E3CB    3C3880FF0002  bbc     #0x00ff, 0x8038, 0xe3d3
00E3D1    8087          bra     0xe35a

00E3D3    8D3142        sta     ax, 0x4231                      ; Branch target from E3C5, Branch target from E3CB
00E3D6    F8            sem                                     ; m:1 x:0
00E3D7    60            rts
At E3BD it checks whether bit 1 of 804A is set, a similar check to the one at the start of Sub-9F32-Test-Atmos. In the case of your ECU, the bit is zero, so it continues and reads the A/D converter. Then it checks bits 2 and 3 (0x0c=00001100) of 804A. These bits are also zero in your ECU so it goes to E3D3 and stores the value that it read from the ADC in 4231 then it exits (rts). Your ECU reads the ADC for the atmos sensor and it stores the voltage at 4231. We do not even know for sure whether there is a pressure sensor connected to the ADC. But we know from the findstr above that the value 4231 is not used anywhere else in the ECU.

Just to continue the exercise, IF the ECU did have a pressure sensor, what would be the 8 bit equivalent to 4231 for datalogging? Further down the code we see this:

Code:
0E4E9    A522          lda     ax, dp + 0x22                   ; Read from A/D successive approximation register
00E4EB    18            clc                                     ; Branch target from E4F1
00E4EC    6D3142        adc     ax, 0x4231
00E4EF    6A            ror     ax
00E4F0    CA            dex
00E4F1    D0F8          bne     0xe4eb
00E4F3    8D3142        sta     ax, 0x4231                      ; Branch target from E4DF

This reads the voltage from the ADC, adds it to the stored value and divides by two (ror ax). It is taking the average of the current reading and the previous reading to reduce the effect of any minor fluctuations. Then we see this:
Code:
00E4F6    A9F401        lda     ax, #0x01f4
00E4F9    890D3142      mpy     0x4231
00E4FD    42C90001      cmp     bx, #0x0100
00E501    B017          bcs     0xe51a
00E503    8D1A40        sta     ax, 0x401a
00E506    F8            sem                                     ; m:1 x:0
00E507    428D1C40      sta     bl, 0x401c
00E50B    D8            clm                                     ; m:0 x:0
00E50C    AD1B40        lda     ax, 0x401b
00E50F    38            sec
00E510    E92C01        sbc     ax, #0x012c
00E513    B008          bcs     0xe51d
00E515    A90000        lda     ax, #0x0000
00E518    8003          bra     0xe51d
00E51A    A9FFFF        lda     ax, #0xffff                     ; Branch target from E501
00E51D    8D0242        sta     ax, 0x4202                      ; Branch target from E513, Branch target from E518
00E520    4A            lsr     ax
00E521    4A            lsr     ax
00E522    4A            lsr     ax
00E523    C90001        cmp     ax, #0x0100
00E526    9003          bcc     0xe52b
00E528    A9FFFF        lda     ax, #0xffff
00E52B    F8            sem                                     ; m:1 x:0, Branch target from E526
00E52C    8D3D42        sta     al, 0x423d
00E52F    8D1544        sta     al, 0x4415       
This appears to be applying some kind of formula to the voltage read from the sensor. Multiply by 500 (=0x1f4), Subtract 300 (=0x12c). Presumably converting the sensor voltage into psi, bar, mmHg, Pa or some other unit of pressure. This gets stored as a 16bit value at 4202. Then that gets divided by 8 (three lsr instructions) and stored as an 8bit value at 423d and 4415. The Select Monitor would query one of these addresses to get the atmospheric pressure if this ECU supported it.

So that's everything related to the atmospheric pressure reading. Not supported by this particular ECU, but on a very similar ECU, you might find:

16 bit atmospheric pressure sensor voltage at 4231
16 bit pressure at 4202
8 bit pressure at 4415

We might as well rename Sub-9F32.txt to Sub-9F32-Test-Atmos.txt and comment the call to it with grepwin:
"(^.*0x9F32.*$)" to "\1 ; Test Atmospheric Pressure Sensor".

We could do the same with Sub-E3B9 to something like "Read-Atmos".
« Last Edit: January 27, 2009, 08:14:19 AM by b3lha » Logged

See my Subaru ECU and TCU website.
http://www.alcyone.org.uk/ssm
log1call
*
Offline Offline

Posts: 62


View Profile
« Reply #51 on: January 29, 2009, 01:36:51 AM »

Hi Phil,
        Well it looks like a few of my addresses must be wrong!

 I've just worked my way through those processes and I'm finding it a bit easier to understand the program.
 
I still have a huge problem with..
"Let's have a look at 0x804A:

00008040   80 00 32 00 68 03 9C 02 80 01 01 30 09 8D 30 00

The value of 804A is 01. That's 00000001 in binary. The value of bit 1 IS zero. Therefore this subroutine will ALWAYS exit immediately without ever testing the sensor or setting the error code."

I have to sit there and read and reread that, then I'm still not sure I have it. I will reread the whole lot a couple of more times though.

At least I'm beguining to understand the program instructions a bit now. Sometimes, I even understand it right!
Logged
b3lha
*
Offline Offline

Posts: 198



View Profile WWW
« Reply #52 on: January 29, 2009, 04:27:16 AM »

I still have a huge problem with..
"Let's have a look at 0x804A:

00008040   80 00 32 00 68 03 9C 02 80 01 01 30 09 8D 30 00

The value of 804A is 01. That's 00000001 in binary. The value of bit 1 IS zero. Therefore this subroutine will ALWAYS exit immediately without ever testing the sensor or setting the error code."

Let me try and explain it better:

804A is the byte I have highlighted in bold: 00008040   80 00 32 00 68 03 9C 02 80 01 01 30 09 8D 30 00

The value of 804A is 01 in hexadecimal or 00000001 in binary.

Bit 1 is the bit I have highlighted in bold: 00000001. Bits are numbered from right to left starting from zero.

The first line of the Sub-9f32  is
009F32    3C4A80020F    bbc     #0x02, 0x804a, 0x9f46

BBC means Branch if Bit Clear.
#0x02 is 00000010 in binary. This tells the BBC instruction which bit of 804a to inspect. It will inspect the bit that is set to 1 and ignore the others that are set to zero. This means we are only interested in bit 1 of 804A.
0x804A is the address that we are inspecting.
0x9F46 is the address to jump to.

So, the instruction looks at the value of 804A, inspects bit 1 to see if it is 0 or 1. If it is 0 then it jumps to 9f46 which is an RTS instruction (exit). So the rest of the subroutine is never processed.

Logged

See my Subaru ECU and TCU website.
http://www.alcyone.org.uk/ssm
log1call
*
Offline Offline

Posts: 62


View Profile
« Reply #53 on: January 29, 2009, 03:38:00 PM »

Ha, yes Phil, I get it in theory... but not in practice. When I read it though I don't click that the #0x02 needs to be interperated into binary. I presume you know that because it's one of the syntax rules of the programming language? I'll pick it up.

I've had a bit more success trying to read and understand what the code means. I read it and try to work it out before I read your explanation which normaly comes at the bottom. That's a good way to lay it out phil, and your explanations are very good too.

 I'll keep reading.
   
Logged
b3lha
*
Offline Offline

Posts: 198



View Profile WWW
« Reply #54 on: February 02, 2009, 10:23:53 AM »

Just to make things a bit more interesting, I'll take a break from tracing the error codes and show you what the fuel map looks like. It's quite easy to find it by just browsing through the data with your hex editor. 16 lines of 16 bytes all with a value somewhere around 0x80.

Code:
00008120   7D 7D 7D 7D 7E 7F 80 80 80 80 80 80 80 80 80 80   }}}}~...........
00008130   7D 7D 7D 7E 80 82 81 80 81 81 7F 7F 7F 7F 7F 7F   }}}~............
00008140   7F 80 80 80 80 7F 80 7F 7F 80 7F 7E 7E 7E 7E 7E   ...........~~~~~
00008150   7E 7E 7E 7F 7F 7F 7E 7E 7F 7F 7F 7F 7F 7F 7F 7F   ~~~...~~........
00008160   7F 7F 7F 7E 7D 7C 7D 7E 7F 7F 7F 7E 7E 7E 7E 7E   ...~}|}~...~~~~~
00008170   7E 7E 7E 7D 7C 7C 7C 7D 7E 7E 7E 7E 7E 7E 7E 7E   ~~~}|||}~~~~~~~~
00008180   7D 7D 7D 7D 7C 7D 7D 7D 7E 7E 7E 7D 7D 7D 7E 7E   }}}}|}}}~~~}}}~~
00008190   7C 7C 7C 7C 7B 7B 7B 7C 7D 7D 7D 7D 7D 7D 7D 7D   ||||{{{|}}}}}}}}
000081A0   7C 7C 7C 7C 7C 7C 7C 7C 7D 7D 7E 7E 7D 7C 7C 7C   ||||||||}}~~}|||
000081B0   7E 7E 7E 7D 7C 7C 7D 7E 7F 7E 7E 7D 7D 7C 7C 7C   ~~~}||}~.~~}}|||
000081C0   7E 7E 7E 7D 7C 7D 7D 7E 7F 7F 7E 7E 7E 7E 7E 7E   ~~~}|}}~..~~~~~~
000081D0   7E 7E 7E 7E 7E 7F 7F 7F 7F 80 7F 7F 7E 7E 7E 7E   ~~~~~.......~~~~
000081E0   7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7E 7E 7E 7E   ............~~~~
000081F0   7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7E 7E 7E 7E   ............~~~~
00008200   80 80 80 80 80 80 80 80 80 80 80 7F 7F 7F 7F 7F   ................
00008210   80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80   ................
On most, maybe ALL, Subaru JECS OBD1 ECUs, the fuel map is stored at location 0x8120.
Now let's look at the subroutine that processes the map. First search for references to 8120.
Code:
H:\SVX\Brett>findstr 8120 Sub-*
Sub-AE89.txt:00AEAC    A22081        ldx     #0x8120    ; Branch target from AE8C
Sub-AE89 is the only one we find.
Code:
00AEAC    A22081        ldx     #0x8120                         ; Branch target from AE8C
00AEAF    8E8C40        stx     0x408c
00AEB2    A20081        ldx     #0x8100
00AEB5    8E8E40        stx     0x408e
00AEB8    A21081        ldx     #0x8110
00AEBB    8E9040        stx     0x4090
00AEBE    AE7C40        ldx     0x407c
00AEC1    8E9440        stx     0x4094
00AEC4    D8            clm                                     ; m:0 x:0
00AEC5    AD6E41        lda     ax, 0x416e
00AEC8    0A            asl     ax
00AEC9    0A            asl     ax
00AECA    0A            asl     ax
00AECB    8D9240        sta     ax, 0x4092
00AECE    F8            sem                                     ; m:1 x:0
00AECF    208793        jsr     0x9387
00AED2    8DBE43        sta     al, 0x43be                      ; Branch target from AEAA
The "jsr 0x9387" is the most important part. Sub-9387 is a general subroutine for doing lookups on 16x16 maps. I spent a very late night reverse engineering it a couple of years ago. All the Subaru JECS OBD1 ECUs seem to have this piece of code. The address varies but it's always one of the first subroutines. You don't need to know how it works, just as long as you can recognise what it is when you see it.

Sub-9387 is called from several places in the ECU program to lookup values from several different maps. So clearly, the programmer needs to pass parameters to the subroutine to tell it which map he wants to look at. That's what is going on here.

Let's go through that starting from the top, a couple of lines at a time.
Code:
00AEAC    A22081        ldx     #0x8120                         ; Branch target from AE8C
00AEAF    8E8C40        stx     0x408c
0x8120 is the address of the start of the map. Sub-9387 looks for the address of the map in 0x408c.
Code:
00AEB2    A20081        ldx     #0x8100
00AEB5    8E8E40        stx     0x408e

00008100   0C 10 14 1C 24 28 30 38 44 50 58 64 74 80 88 90
0x8100 is the address of the X scale of the map. Sub-9387 looks for the address of the X-scale in 408e.
Code:
00AEB8    A21081        ldx     #0x8110
00AEBB    8E9040        stx     0x4090
0x8110 is the address of the Y scale of the map. Sub-9387 looks for the address of the Y-scale in 4090.
Code:
00AEBE    AE7C40        ldx     0x407c
00AEC1    8E9440        stx     0x4094

00008110   05 07 09 0B 0E 11 14 16 18 1A 1C 1E 21 24 28 2C
Sub-9387 expects to find the X value in 4094. Notice there is no hash (#) on this one. It's storing the value from address 407c, not the literal value "407c". The X value on the fuel map is "RPM", so we know that 0x407c is an internal value for RPM and we can follow that later to find the select monitor parameter for RPM.
Code:
00AEC5    AD6E41        lda     ax, 0x416e
00AEC8    0A            asl     ax
00AEC9    0A            asl     ax
00AECA    0A            asl     ax
00AECB    8D9240        sta     ax, 0x4092
Sub-9387 expects to find the Y value in 4092. Notice again there is no hash (#) on this one. It's loading the value from address 416e into AX. Then it shifts it left 3 places (multiply by 8 ). Then it stores in in 4092.
The Y value on the fuel map is "Engine Load", so we know that 0x416e is an internal value for Load and we can follow that later to find the select monitor parameter for Load.
Code:
00AECF    208793        jsr     0x9387
00AED2    8DBE43        sta     al, 0x43be                      ; Branch target from AEAA
Having setup the values for "Map Address", "X Scale Address", "Y Scale Address", "X value" and "Y value", the code makes a call to Sub-9387 and then stores the return value in 0x43be. The return value is the "Z value"  from the map.

I've converted the numbers to decimal and copied them into an excel spreadsheet (attached). The top table in the sheet is the raw data. You can see the RPM scale (8100-810F) going down the side from cell A4 to A19 and the Load scale (8110-811F) going across the top from B3 to Q3. Then you can see the data values from 8120 to 812F in the first row, 8130-813F in the next row, etc.

When calculating the injector pulse width, the ECU will look up the RPM row and the Load column of the table and take the value where they meet. It will interpolate between the cells too.

Below that I've made a copy with updated scales. I think the RPM value at 407c is rpm/50, so I've multiplied the RPM scale by 50 to make it more readable. Similarly, I think the Load value at 416e is half of the select monitor load value so I've multiplied that by 2.

As for converting the Z value to an AFR. I'm not sure how to do that and it's not really necessary. The value 0x80 (128 decimal) represents a stoichiometric mix 14.7:1. But in the real world, a wideband O2 sensor might not necessarily get exactly the same reading. A tuner once told me that the best way is to decide what you want the AFR to be and then tweak the table values up and down until you get that reading on your wideband.

Several formulas have been suggested such as AFR=14.7/(z/128) or AFR=14.7+((z-128)/4). But I'm not sure that either of these is correct. I've read that the fuel map is actually an adjustment map. The ECU works out the pulse width for a 14.7 and then adds a bit or subtracts a bit based on the value from this map. Once I figure out the exact formula I'll be posting all the details on my website.

Anyway, that's what the fuel map looks like, and we've found a trail to the RPM and Load parameters too. I'll search for them tomorrow. Also, I said that Sub-9387 is used to look at several 16x16 maps, so we can find those maps by looking for calls to Sub-9387:

Code:
H:\SVX\Brett>findstr 9387 Sub-*
Sub-AE89.txt:00AECF    208793        jsr     0x9387
Sub-AEE3.txt:00AF05    208793        jsr     0x9387
Sub-B557.txt:00B57C    208793        jsr     0x9387
Sub-B557.txt:00B59E    208793        jsr     0x9387

Sub-AE89 is the fuel map at 8120, that we've been looking at.
Sub-AEE3 is a map at 87A0. It looks similar to the fuel map. We'll have to investigate that one and see if we can figure out what it is.
Sub-B557 looks up two maps, one at 8500 and one at 9200. I'm fairly sure that these are the base timing and maximum advance maps.

« Last Edit: February 03, 2009, 05:12:11 AM by b3lha » Logged

See my Subaru ECU and TCU website.
http://www.alcyone.org.uk/ssm
b3lha
*
Offline Offline

Posts: 198



View Profile WWW
« Reply #55 on: February 04, 2009, 09:59:01 AM »

Following on from my previous post.

We found 407C is an internal value for RPM. But it is a 16 bit value and we need an 8 bit value for the Select Monitor.

I said that the X scale on the fuel map is RPM / 50. The map lookup subroutine takes the X value from 4094 and divides it by 4 before comparing it to the scale. That means the value of 407C is four times (rpm / 50 ) = (rpm/12.5).

We want (RPM / 25) for the select monitor, so we are looking for (407C / 2).

Code:
findstr 407c Sub-*
....
Sub-EA43.txt:00EA94    8D7C40        sta     ax, 0x407c
....

Lots of matches, because RPM is the most commonly referenced variable in the ECU. The important one is in Sub-EA43 because it is a STore instruction, not a LoaD instruction. It is where the value of 407c is calculated.

Code:
.....
00EA6A    42A90400      lda     bx, #0x0004
00EA6E    A9E093        lda     ax, #0x93e0
00EA71    892D1A40      div     0x401a
.....

From EA43 to EA71 we see the calculations for working out RPM. An interesting figure to note here is 0x000493E0 (300000 in decimal). I haven't studied the calculations in detail, but I suspect that the ECU has a timer running at 300Khz and that is used together with the pulse count from the crank sensor to determine the rpm.
 
The next interesting bit is here:
Code:
00EA76    AE8440        ldx     0x4084
00EA79    8E8640        stx     0x4086
00EA7C    AE8240        ldx     0x4082
00EA7F    8E8440        stx     0x4084
00EA82    AE8040        ldx     0x4080
00EA85    8E8240        stx     0x4082
00EA88    AE7E40        ldx     0x407e
00EA8B    8E8040        stx     0x4080
00EA8E    8D7E40        sta     ax, 0x407e
Notice it is moving the value of 4084 to 4086. Then the value of 4082 to 4084. Then 4080 to 4082. Then 407E to 4080. Finally storing AX in 407E. This is RPM history. The program is storing the last 5 values of RPM in locations 407e to 4086 (each value is 2 bytes long). This bit of code is shunting the previous values up the list and inserting the new value at the bottom.

Code:
00EA92    4A            lsr     ax                         ; Divide by 2
00EA93    4A            lsr     ax                         ; Divide by 2 again
00EA94    8D7C40        sta     ax, 0x407c     ; Store at 407c
00EA97    AA            tax                                ; transfer AX to X register
00EA98    C9FF00        cmp     ax, #0x00ff    ; compare AX to 0x00FF
00EA9B    9003          bcc     0xeaa0              ; if less goto EAA0
00EA9D    A9FF00        lda     ax, #0x00ff     ; set AX to 0xFF
00EAA0    F8            sem
00EAA1    8D8A40        sta     al, 0x408a      ; store AL (8 bits) at 408A
Here we see the raw RPM value gets divided by 4 and stored as a 16 bit value in 407C. Then it gets stored as an 8 bit value in 408A. If the value is too large to fit in 8 bits then it stores 0xFF instead. That is the largest value that can fit in 8 bits. So 408A is an 8 bit representation of 407C (RPM / 12.5).
Code:
00EAA4    D8            clm                                     ; m:0 x:0
00EAA5    8A            txa                                      ; Transfer X to AX
00EAA6    4A            lsr     ax                              ; Divide AX by 2
00EAA7    C9FF00        cmp     ax, #0x00ff         ; If AX > 0x00FF set it to 00FF
00EAAA    9003          bcc     0xeaaf
00EAAC    A9FF00        lda     ax, #0x00ff
00EAAF    F8            sem                                     ; m:1 x:0, Branch target from EAAA
00EAB0    8D8940        sta     al, 0x4089            ; Store AL (8 bits) at 4089
00EAB3    8DBC43        sta     al, 0x43bc            ; and 43BC.
Above we see the program retrieve the value of AX that it stored in the X register at EA97 further above. This value is equal to the value stored at 407C (RPM/12.5). The program divides it by two, and stores the result at 4089 and 43bc. This value is RPM/25. You could probably use either of these for the select monitor parameter.
Code:
00EAB6    D8            clm                                     ; m:0 x:0
00EAB7    8A            txa
00EAB8    4A            lsr     ax
00EAB9    4A            lsr     ax
00EABA    C9FF00        cmp     ax, #0x00ff
00EABD    9003          bcc     0xeac2
00EABF    A9FF00        lda     ax, #0x00ff
00EAC2    F8            sem                                     ; m:1 x:0, Branch target from EABD
00EAC3    8D8840        sta     al, 0x4088
Finally, we see the same code again, but with two right shifts, divide by 4. Therefore address 4088 holds (RPM / 50).

All these parameters are heavily used throughout the program, so commenting them with wingrep is a good idea. You could also rename Sub-EA43 as Sub-Ea43-calculate-RPM and comment the jsr call to it too.
« Last Edit: February 04, 2009, 10:03:49 AM by b3lha » Logged

See my Subaru ECU and TCU website.
http://www.alcyone.org.uk/ssm
b3lha
*
Offline Offline

Posts: 198



View Profile WWW
« Reply #56 on: February 04, 2009, 10:40:29 AM »

When looking at the fuel map, I said that the internal value for load was at 416E.

The program shifts the value left 3 bits before writing it to 4092 (Y-value). But the map lookup subroutine 9387 does not actually use the 16 bit value at address 4092. It takes an 8 bit value from address 4093.

Imagine the internal load value at is 00FF = 00000000 11111111 in binary. But on a "little endian" computer like this one, the first byte 416E holds 11111111 and the next byte 416F holds 00000000.

The program transfers this to AX and shifts it left 3 bits and writes it to 4092. So the value of AX is 07F8 = 00000111 11111000 in binary. But when it is stored little-endian, address 4092 contains = 11111000 and address 4093 contains 00000111.

The end result is that the Load value that is compared against the map scale is 00000111. This is equivalent to taking the load value in 416E and dividing it by 32 (five right shifts). So "map load" = "internal load" / 32. I said earlier that the "map load" was half of the "select monitor load". So we can conclude that the "select monitor load" = "internal load" / 16.

Let's find the calculation for the "internal load".

Code:
findstr 416e Sub-*
.....
Sub-E6A2.txt:00E750    8D6E41        sta     ax, 0x416e
.....
Sub-E6A2 contains the store instruction for address 416E. Down at the bottom of the code, we see this:

Code:
00E750    8D6E41        sta     ax, 0x416e                      ; Store internal load at 416E
00E753    4A            lsr     ax                                         ; Divide by 16 (four right shifts)
00E754    4A            lsr     ax
00E755    4A            lsr     ax
00E756    4A            lsr     ax
00E757    F8            sem
00E758    8DAA43        sta     al, 0x43aa                      ; Store at 43AA and 42DD
00E75B    8DDD42        sta     al, 0x42dd
00E75E    60            rts
Wasn't that easy? You can use 43AA or 42DD for the "select monitor load".
You can also comment it and rename the subroutine to Sub-E6A2-Calculate-Load.txt
etc.etc.
Logged

See my Subaru ECU and TCU website.
http://www.alcyone.org.uk/ssm
log1call
*
Offline Offline

Posts: 62


View Profile
« Reply #57 on: February 04, 2009, 03:38:49 PM »

Phew, "easy", Phil, I don't think so.
There seem to be leaps in your reasoning that I still can not quite follow. Well I can understand the reasoning but not always what made you decide to look for one particular thing rather than some other. I dare say you are trying several different possibilities in your head looking for the one to follow up on, the one that might be easiest or most likely sometimes, the one we must have othertimes. I know I do diagnosing like that.

 Once I understand more I dare say the leaps will seem more logical. My understandings of how it all works are only from the end result so I am always trying to resolve your reasoning with what I am used to seeing as a behaviour, which may be counter productive for me.
 
Your explanations are very good and I can understand them as I read through but to really feel confident I have learnt it I need to do it for myself and in a couple of different instances, which I have been doing as I get a chance. I have to admit though that I am falling behind a little due to being too busy to manage more than a short spell at a time at it. I really need to sit down for a couple of hours minimum and work at it to get it to sink in. Unfortunatly I'm a single dad (with teenagers), self employed mechanic, that repairs computers, and has a forest and rural property to maintain.

I'm following along doing as you do here, and I'm going off on side branches here and there that you point out, just to see if I can interperate it and to practice the commands and syntax etc.

Anyway, thanks for all your efforts. I hope you are keeping time aside for that baby of yours because they grow up all too soon, make the most of them while they are young I say. It's a subject I'm knowledgable on Phil... my wife died when the boys were two and four respectivley!
                                                                                                Regards, Brett.

Logged
b3lha
*
Offline Offline

Posts: 198



View Profile WWW
« Reply #58 on: February 05, 2009, 05:48:30 AM »

Phew, "easy", Phil, I don't think so.
There seem to be leaps in your reasoning that I still can not quite follow. Well I can understand the reasoning but not always what made you decide to look for one particular thing rather than some other. I dare say you are trying several different possibilities in your head looking for the one to follow up on, the one that might be easiest or most likely sometimes, the one we must have othertimes. I know I do diagnosing like that.

 Once I understand more I dare say the leaps will seem more logical. My understandings of how it all works are only from the end result so I am always trying to resolve your reasoning with what I am used to seeing as a behaviour, which may be counter productive for me.
 
Your explanations are very good and I can understand them as I read through but to really feel confident I have learnt it I need to do it for myself and in a couple of different instances, which I have been doing as I get a chance. I have to admit though that I am falling behind a little due to being too busy to manage more than a short spell at a time at it. I really need to sit down for a couple of hours minimum and work at it to get it to sink in. Unfortunatly I'm a single dad (with teenagers), self employed mechanic, that repairs computers, and has a forest and rural property to maintain.

I'm following along doing as you do here, and I'm going off on side branches here and there that you point out, just to see if I can interperate it and to practice the commands and syntax etc.

Anyway, thanks for all your efforts. I hope you are keeping time aside for that baby of yours because they grow up all too soon, make the most of them while they are young I say. It's a subject I'm knowledgable on Phil... my wife died when the boys were two and four respectivley!
                                                                                                Regards, Brett.
Thanks for the feedback.

There are sure to be things that I gloss over because they seem obvious to me, that probably aren't so obvious to you. Just the same as when somebody brings you a car making a funny noise. You quickly figure out what is wrong with it because you know what to look at - and what not to look at. Some of the diagnosis happens subconciously and you don't necessarily notice that you are doing it.

Plus I make lots of mistakes too. I proof read everything after posting it and edit multiple times. So be sure to query anything that doesn't make sense. I'd like these threads to eventually be like a tutorial for people who want to crack their ECU but don't know where to start.

I know what you mean about time, this stuff is really time intensive and there are never enough hours in the day. All credit to you for managing to bring up two kids on your own. I'm surprised you have any time at all. I never really knew the true meaning of "busy" until my daughter was born. But she's the sweetest happiest little girl you could ever meet.

When you've got your head around what we've done so far, try to find the MAF reading. Explain what you are doing as you go along and I'll help if you get stuck. Unfortunately it's a little more complex than the ones we've done so far, because the same subroutine calculates two parameters "MAF Sensor Voltage" and "Mass Airflow". But once you find that subroutine there are only a few addresses to choose from.
Logged

See my Subaru ECU and TCU website.
http://www.alcyone.org.uk/ssm
log1call
*
Offline Offline

Posts: 62


View Profile
« Reply #59 on: February 05, 2009, 11:26:21 PM »

Ha, yes, ok Phil, I will have a look for the MAF. I will try and keep on track.

I start working through what you've shown me so far but keep following off on other jumps to see where they go and then I get lost.

I also end up reading what the others are doing too and get side tracked there. Me bad!

Kids are great but they aren't little for long. Enjoy them while you can.
Logged
Pages: 1 2 3 [4] 5
Print
Jump to: