First Generation DSM EPROM Editing
Last Update: 1/15/05
Injector Size Compensation (Global)
This page in intended to be a guide so that all of the current information about the DSM EPROM can be presented in a clear manner such that anyone who wishes can do their own rom editing. The majority of this information comes from the findings of the DSM-ECU list, which can be found at http://autos.groups.yahoo.com/group/dsm-ecu/.
Before you begin, read through these general notes to get an idea for what is happening, and what you need to do in order to have desirable results.
The 1g DSM EPROM ECU uses a 28 pin EPROM and a processor based on the Motorola 68HC11, but with additional opcodes. As such, there is no program that can fully disassemble the entire code. Important sections have been done, but since everything has to be looked over and edited the process is very tedious.
All of the information and addresses below are based on the E931 EPROM, which comes in the 91+ turbo manual transmission cars. A lot of the code and the general information may still apply to other variations, but there are no guarantees.
The code will be on a 32k chip, with approximately the first half of it blank. This is the proper way to burn a chip, and as such the addresses will apply to that setup. These addresses apply if you load the memory into a hex editor; keep in mind that for the processor, the EPROM chip begins at C000 and ends at FFFF.
Need to contact me? Click here to send me an e-mail
Address: 727A
The processor compares (CPX) the value stored at this address to the current engine speed, in order to determine whether or not to cut the fuel and spark. If we want to raise the rev limiter, we will lower the value at this address according to the following formula:
Rev Limit = 3750000 / X
Such that X is the decimal value of the two bytes at 727A and 727B.
7000 – 0218
7500 – 01F4
7600 – 01ED
7800 – 01E1
8000 – 01D5
8200 – 01C9
8500 – 01B9
The code in the area of the rev limiter will look as follows:
01 45 8C 01 F4 24 05 03
Address: 7EC0-7EC1
The base idle speed is contained within a map found at the addresses 7EC0 and 7EC1. The idle speed at operating temperature is:
Idle Speed = X * 8
Such that X is the decimal value of each of the two bytes (they will be the same).
750 – 5F
768 – 60
775 – 61
800 – 64
850 – 6A
900 – 70
950 - 77
The code in that area will look as follows:
08 0A 0C 60 60 80 93 A3 B3 C0 D3
Note that since GVR-4's have a higher base idle speed, they will have the two "60" bytes replaced with "66."
Address: 559A
Fuel cut is initiated when the calculated airflow goes over a set value, which is set at the address 559A. By increasing this to the maximum value possible (FF) fuel cut will be pushed off.
Another, possibly better, solution is to change the code in that area so that the ECU doesn't cut fuel regardless of the status of the airflow. This can be done by changing the "24" at 559B (which is a BCC code, or a branch when the airflow is greater than the value of 559A) to "21," which is a simple branch never code.
The code in the area looks like this:
02 D6 57 C1 A0 24 05 C6 28
Address: 599F
The injector compensation is a global fuel control value located in the one byte at 599F. It works simply by correcting the injector pulsewidth for whatever size injectors the ECU is programmed for; this is a linear multiplier. In order to reduce the pulsewidth for larger injectors, you want to reduce this location. If you double the injectors size, you cut this in half, etc.
Here are some sample settings:
Size - Decimal - Hex
450 – 74d – 4A
510 – 65d – 41
550 – 61d – 3D
600 – 56d – 38
650 – 51d – 33
660 – 50d - 32
700 – 48d – 30
750 – 44d – 2C
800 – 42d – 2A
850 – 39d – 27
The code around the compensation byte looks like this:
05 05 05 05 DD 5C C6 4A BD EB 6A FD
This code is from the E931 ECU, but it seems as though other ECU's (Mirage, JDM) have a very similar structure.
Address: 7CE7 - 7CED
The injector deadtime map compares the deadtime of the fuel injectors to the battery voltage. The first byte of the map is 4.7 volts, the second point is 7.0 volts, then 9.34v, 11.68v, 14.0v, 16.35v, and 18.7v. The decimal value of each byte refers to the deadtime of the injectors, divided by 24 microseconds.
The stock map is "A9 58 30 23 1B 17 13"
If you wanted to add 200 microseconds of deadtime, you would add 8 to each of the values on the map, since 200 / 24 = 8.
For 550's, you want about 150-175 us more deadtime. 660's will be above 200, usually around 225 or 250. However, these settings will vary from car to car, and between different types of injectors.
Address: 7B6E - 7B82
The MAF compensation map is what the ECU refers to in order to correct the airflow signal coming in from the mass airflow meter. This code also allows you to install a 2g MAF and have the ECU compensate for it properly, or to compensate for hacked MAFs, or aftermarket MAFs that do not have quite the same airflow curve as the stocker.
The stock MAS compensation code is:
5B 5B 59 59 60 65 6C 6E 6E 6F 73 76 7A 81 82 84 87 85 7F 7A 7F
This will vary if the car is a GVR-4, for example, because they have a slightly different MAF.
The MAF compensation code is essential a correction map, based on airflow. The airflow (Hz) points for each of the values are as follows:
0, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300, 400, 500, 600, 800, 1000, 1200, 1400, 1600.
So, for example, if you wanted to increase the airflow signal from zero to 75Hz input by 20%, you would increase the first 4 values in the map by 20%.
Since one of the most popular changes is from a 1g MAF to a 2g MAF, this is how you want to change the code:
First, the map needs to be changed to:
85 85 A8 B6 BE C3 C8 CC D0 D4 D7 DA DC E3 E6 E8 EB EA EA E8 E7
NEXT, you need to change another byte the serves as a multiplier. This byte is located at the address 5669, and the stock value at this point is "64" hex. For a 2g MAS, change that to "40" hex.
In addition, in order to make sure the timing and fuel maps still line up, you need to change the value at 549A from "5E86" (1g) or "62B9" (GVR-4), to the 2g value which is "7A03."
Address: 7C3F - 7CE6
The fuel map at the above address is a fuel enrichment for open-loop operation. When you go into open loop, the ECU goes to the table and finds the correct value based on engine speed and load (airflow / rev). Then, it multiplies the pulsewidth by the value in that box, and then divides by 80h (128 decimal). As such, if the value in the box is 80h, then there will be no fuel compensation and the A/F ratio will still be 14.7:1. If the value in the box is FF (256 decimal) then the overall multiplier will be 2 (256/128) and there will be twice as much fuel, for an A/F ratio of 7.35:1.
The rpm axis on the fuel map begins at 500 rpm, and increases in 500 rpm increments to 7000 rpm (500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000).
The load points are the same as listed below for the timing map.
Address: 7D48 - 7E07
The timing map is broken down into 12 airflow levels, and 16 rpm breakpoints. The first byte, 7D48, is the lowest airflow level at 750 rpm, and the next byte is the lowest airflow level at 1000 rpm, and so on and so fourth. The engine speed values for the map are as follows:
750, 1000, 1250, 1500, 1750, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000.
The other "axis" of the timing map is load, based on airflow per engine revolution. In stock form, this goes up to 2.06 grams of airflow per engine revolution, but the slope is not exactly linear. The values of the load axis are as follows:
0.25, 0.38, 0.50, 0.63, 0.75, 0.94, 1.13, 1.50, 1.69, 1.88, 2.06.
The value of each byte is simply the timing advance (total timing assuming base is 5 degrees BTDC) plus 10 decimal, converted to hex. Thus, to convert from the ECU code to advance, you convert to decimal and then subtract 10.
A solution has been devised, which will allows anyone with a 1g EPROM ECU to run timing and fuel maps that have twice the load range than the stock maps; the stock maps are easily maxxed out at around 15 psi of boost, meaning that car running more than that are running on the highest airflow level all of the time.
This modification is actually fairly easy, but due to the fact that it requires full replacement of the maps (the replacement maps are included), a separate guide has been written to make this possible. You can reach this guide here.
(http://users.wpi.edu/~ktarry/dsmtech/Extended_Map_Guide.zip)
For a simple stutterbox, you can use the following code. This code will jump from the stock rev limiter to an unused part of the chip, where it will then check to see if the car is moving. If the car is stopped, you get a stutterbox, and if the car is moving then you get the regular rev limiter. This means you do not need a clutch switch.
At the stock rev limiter location (7279), you replace the three bytes that were "8C 01 F4" with "BD CF 50." Then, you go up to the line that starts with 4F50, and add the following code:
"96 C6 81 75 22 04 8C 01 F4 39 8C 02 EE 39"
This is how the code works:
7279: BD CF50 JSR 4F50; Instead of stock rev limiter CPX, jump to 4F50
4F50: 96 C6 LDAA L00C6; Load speed sensor to accumulator A
4F52: 81 75 CMPA $0075; Compare speed sensor to 75h (check if car is moving)
4F54: 22 04 BHI 4F5A; If car is stopped, skip next instruction (go to 4F5A)
4F56: 8C 01F4 CPX $01F4; 7500 rpm rev limiter
4F59: 39 RTS; If car is NOT stopped (moving), go back to stock code, no stutter
4F5A: 8C 02EE CPX $02EE; 5000 rpm stutter if car is stopped
4F5D: 39 RTS; Return to 4F59, which returns to stock code
Stutterbox with No Lift to Shift (NLTS)
Instead of using the simple stutterbox code above, you can use slightly more complex code in order to have both stutterbox and no lift to shift.
You will use the same values at 7279 as above, but just for clarity:
7279: BD CF50 JSR 4F50; Instead of stock rev limiter CPX, jump to 4F50
Then, at 4F50, you will want to use the following code:
4F50 96 C6 LCAA L00C6 ; load speed sensor into accum. A 4F52 81 75 CMPA $0075 ; test if car is moving 4F54 23 04 BLS ; if car is moving skip next 4 4F56 8C 03 A9 CPX $02EE ; car is stopped launch stutter (5000 rpm) 4F59 39 RTS ; return from subroutine 4F5A 96 06 LDAA L0006 ; load clutch bit into accum. A 4F5C 85 20 BITA $0020 ; accumulate with 0020h 4F5E 27 04 BEQ ; if clutch is in go to NLTS 4F60 8C 01 F4 CPX $01F4 ; clutch is up stock rev limiter 4F63 39 RTS ; return from subroutine 4F64 8C 02 AA CPX $02AA ; NLTS stutter RPM (5500 rpm) 4F67 39 RTS ; return from subroutine
Note that you can change the stutter, NLTS, and rev limiter speeds, using the formula found in the rev limiter section (here).
Thanks to Dan Loncher to helping to develop and test this code.
The stock code contains a feature which has been nicknamed the "octane value." Basically, the if the ECU sees a knock sum over 5, it reduces the maximum amount of timing advance you can have. It saves this in long term memory, and it can only go away of you have less than 3 knock sum, in which case it will taper away slowly.
If you use good gas and keep track of what it happening with the car, then there is no reason to keep this feature. It is mainly designed as a protection against something happening to the car (such as using 87 octane fuel, or something breaking) so that the ECU can reduce the timing level to help keep stuff from blowing up. All TMO chips set the octane to the maximum possible each time you started the car, this code just goes a step beyond that and gives you maximum octane all the time.
The octane corrections start at address 5B9D. Starting with this byte, use the following code:
"86 FF 97 52 7E DB F3"
The code works as follows:
5B9D: 86 FF LDAA $00FF; Load 255d (max) to A
5B9F: 97 52 STAA L0052; Store 255d (FFh) to octane (mem address 52)
5BA1: 7E DBF3 JMP DBF3; Jump to DBF3 (skip octane calculations, go to timing start)
Note that this renders the rest of the code between 5BA4 and 5BF3 useless; you can use it for other features if you wish.
UPDATE: Jeff B. on DSM-ECU uses the following simple method to update the octane (to 255, the max) on every start:
"Just
change the byte at $D0B5 from $2C to $28. This bumps the
warmboot address back 4 bytes to $D0DE which resets the
octane byte
to 255 during a coldboot. now it will reset octane on a cold
or warm
boot."
If you don't want to mess around with the timing code, this is a better option.
High Speed Closed Loop
Address: 7BDC - 7BDD, 7BE6-7BE7
There addresses refer to the last two bytes on two seperate 10 byte maps. The first map is a map of airflow per rev values, in 500 rpm intervals. As such, the last two values (4500 and 5000 rpm) have a value of zero, and the ECU will go into open loop at that point. By changing the cutoff point (raising it), you can have the car stay in closed loop.
The second map is throttle position, in the same 500 rpm intervals.
It has been suggested (Jeff O.) that you not only raise the two last bytes from zero, but that you also increase the last value on the stock map so that it is higher like the rest of the values.
Update: If you want to know the values in the map, the formulas to calculate them are really easy.
For the throttle position, the value in the map can be converted to decimal, and then divided by 255. For example, if the map value is 80, that converts to 128 decimal, which divided by 255 is 0.50. That means that 80h is equal to 50% throttle.
The airflow per rev map can be converted to grams of airflow per engine revolution, by converting the values to decimal and then dividing by 128. For example, a map value of "A0" converts to 160 decimal, which when divided by 128 is equal to 1.25. Therefore, A0 in the map is equal to 1.25 grams of airflow per engine revolution.
Increased MAF Hz Logging Range
As you all know, the 1g datalogger is limited to being able to see only 1606 MAF Hz; this is not due to a limitation of the MAF or of the ECU, but simply a limitation due to the amount of data that the ECU can transfer to the logger.
There is a small amount of code that can be changed slightly, so that you can datalog up to 3212 Hz (double the stock range). If this is done, there are modified versions of the MMCd datalogging program that support this option, or you can just mentally multiply the airflow on your normal logger by 2 to see the true value.
Two bytes need to be changed for this to work correctly. First, at 53DA, there is a byte with the value "B4." If you change that value to "B3," the airflow will be divided in half before it is sent to the logger, doubling your logging range.
Second of all, you need to change the "low airflow check" code at 732A from "08" to "04," to reflect the fact that the airflow is now half of what it used to be.
So, "B3" is stored at 53DA, and "04" is stored at 732A.
Removal of Airflow Per Rev / IPW Cap
For reasons unbeknownst to me, the stock ECU code contains a segment which caps the airflow per rev (and therefore the injector pulsewidth). This section seems to have no purpose, so ECU tuners have been eliminating it
The code responsible for this is located from 73A6 to 73B5, and can simply be No-op'd. In order words, replace all of the bytes from 73A6 to 73B5 with the hex value "01."
For reference, these values are as follows:
D6 A0 4F 05 05 05 87 A2 11 04 1D 8D 24 02 DD 8D