|
I've spent quite a bit of time digging into the functions that control injection and ignition, so I thought I'd share a summary. The speed is impressive... when the engine is doing 6000 rpm = 100 revs/second = 3600 crankshaft teeth/second which means 0.3 of a millisecond between every crankshaft position sensor signal, and every one of those 0.3 milliseconds, the ECU executes a bunch of instructions.
Anyway, here goes...
Background info - angles are generally stored as degrees or 32bit values equal to degrees x 2^16. So 0x02D00000 = 720 degrees. - time is stored in a mix of microseconds (things like 'Total Timing' we're familiar with), quarter microseconds (things like crankshaft time), and Quadruple microseconds (things like injection and ignition downcounters)
Crankshaft, Camshaft and Cylinder positions - The ATU registers are set so an interrupt (CMI10B) is generated every time the crankshaft positioning sensor detects a tooth. This is every 10 degrees (except for some gaps). - The crankshaft has some gaps in the teeth that are 30 degrees wide. These are used by the ECU logic to figure out exactly where the crankshaft is in its rotation. To do this, an interrupt (OSI8O) is set up to occur after 20 degrees of rotation. - By identifying these gaps, and whether they occur in isolation, or sequentially, the ECU determines the crankshaft position. This is tracked via 36 x 10 degrees 'crankshaft position numbers' from 0x00 to 0x23. Position 0x00 is 10 degrees BTDC of Cylinder 0. - Another interrupt (ICI0B) is set up to track the Camshaft positioning sensor. The ECU logic checks that there are 2 camshaft signals (one rotation) for every 2 crank rotations. The logic also sets a flag when within 50 degrees of a cam signal. - Because there are two crank cycles in each full combustion cycle, the logic tracks the position of the crankshaft via 24 x 30 degrees 'cylinder position numbers' from 0x00 to 0x17 - From the crank position and the flag that is set within 50 degrees of a cam signal, the ECU figures out where the crank is in its 720 degree cycle and sets the correct cylinder position. Cylinder position 0x00 starts at 10 degrees BTDC of Cylinder 0 and ends at 10 degrees ATDC of Cylinder 0. - On certain crank positions (determined by a table in ROM, happens to be every third third crank position or every cylinder position), the ECU does the detailed injection / ignition calculations. The ECU also updates Engine Speed which is calculated from the average of the last 6 x 30 degree rotations of the crankshaft. - On certain cylinder positions (determined by a table in ROM, happens to be TDC positions, or every 180 degrees), the ECU does other calculations including updating updating Latency and Dwell.
Relevant ECU Operations every Cylinder Position - the ECU checks if the position is a TDC position and sets up OCR2G and GR2G as the start and termination registers for a 20 degree rotation of the crankshaft. A downcounter DCNT8O is used and when terminated it generates the OSI8O interrupt. This allows the ECU to figure out the crankshaft orientation as described above. - for each cylinder, the Degrees to Injection (DTIn - described below) is reduced by 30 degrees to reflect the crank having turned 30 degrees. If the DTIn is less than 35 degrees, the ECU sets GR1A-D (start timing for injection) as crankshaft time plus the time it will take to rotate through DTIn at current crankshaft speed. The downcounter DNCT8A-D is set to the Pulse Width plus Latency. And interrupts OSI8A-D are set to occur when the relevant downcounter hits zero. There is logic to deal with complex situations where the time to start injecting has already passed, or if the downcount is already underway etc. - for each cylinder, the Degrees to Ignition (DTIg) is calculated as the firing TDC (0 or 180 degrees) less total timing less crank angle. Crank angle is determined as above. The ECU sets OCR2A-D (start time for current to ignition) as crankshaft time plus the time it takes to rotate through DTIg at current crankshaft speed less the Ignition Dwell. GR2A-D (end time for current to ignition) is set to crankshaft time plus the time it takes to rotate through DTIg. Downcounters DCNT8I-L are set to a large number which has no function other than effectively being a flag that down count is underway. There is logic to deal with complex situations where the crank has already passed the point at which current to the spark plug should have started. - there are functions to initialise and update the 'Injection Table' and 'Ignition Table' in RAM (below). These functions also deal with transitions between cranking/not cranking and individual cylinders being turned on/off, and whether the transition is allowed based on whether the cylinder is beyond a certain angle threshold (ie) is it too far gone in the cycle to change right now, or should the change wait until next cycle.
Relevant ECU Operations on every TDC Position - Latency is looked up based on Battery Voltage. DTIn is calculated for each cylinder as the TDC position less crank angle. Crank angle is determined as cylinder position x 30 degrees - 10 degrees. The 10 degree offset is required because cylinder position x 30 degrees is offset from crank position by 10 degrees. - The Dwell is looked up based on Engine Speed and Battery Voltage.
RAM locations There are a bunch of tables in RAM that store various info. These are described below in address order. Most of the data moves too fast to log, so this is all based on reviewing the ECU logic. Some of the flags are quite complex, so I haven't figured them all out. I've used the addresses from my ROM, but they will be different for each ROM.
0xFFFF4C9C - Injector Latency (from Lookup)
0xFFFF4CA0 - Base of 4 x 24 byte table for controlling Injection Registers. Each 24 byte table is for each cylinder 0,1,2,3. Addresses for cylinder 0 below. 0xFFFF4CA0 - 4 bytes - Injector Pulse Width 0xFFFF4CA4 - 4 bytes - Degrees to Injection (DTIn) 0xFFFF4CA8 - 4 bytes - Time that injector is on as a proportion of 180 degrees 0xFFFF4CAC - 4 bytes - Injector Pulse Width 0xFFFF4CB0 - 2 bytes - Timing for start of injection 0xFFFF4CB2 - 1 byte - Flag that is set to 0 when downcounter ready (?) 0xFFFF4CB3 - 1 byte - Flag that is set to 0 when downcounter is underway (?) 0xFFFF4CB4 - 1 byte - Flag that is set to 1 when OSI8A-D are enabled to reset GR1A-D and DCNT8A-D (?) 0xFFFF4CB5 - 3 bytes - unused the above is then repeated 3 times
0xFFFF4D04 - Base of 4 x 8 byte table for controlling Ignition Registers. Each 8 byte table is for each cylinder 0,1,2,3 0xFFFF4D04 - 4 bytes - Ignition Point Angle 0xFFFF4D08 - 1 byte - Flag - unknown 0xFFFF4D09 - 1 byte - Flag that is set to 1 when OCR2A-D GR2A-D DCNT8I-L have been reset 0xFFFF4D0A - 1 byte - Flag that is set to 1 when GR2A-D (termination) has been set 0xFFFF4D0B - 1 byte - unused the above is then repeated 3 times
0xFFFF4D24 - Base of 4 x 4 byte table for additional dwell time if required. Each 4 byte table is for each cylinder 0,1,2,3 0xFFFF4D24 - 4 bytes - Set to 0. If nonzero it becomes additional dwell time. the above is then repeated 3 times
0xFFFF4D34 - Ignition Dwell (from Lookup)
0xFFFF4FB0 - Base of 24 byte table for temporary storage of the cylinder position and cylinder number that are currently being processed by the ECU. 0xFFFF4FB0 - 4 bytes - cylinder position number 0xFFFF4FB4 - 4 bytes - cylinder position number 0xFFFF4FB8 - 1 byte - index that is used to store next cylinder position in either of the above locations - values of 0 or 1 0xFFFF4FB9 - 1 byte - index that is used to access next cylinder position in either of the above locations - values of 0 or 1 0xFFFF4FBA - 2 bytes - unused 0xFFFF4FBC - 4 bytes - Cylinder number 0xFFFF4FC0 - 4 bytes - Cylinder number 0xFFFF4FC4 - 1 byte - index that is used to store cylinder number in either of the above locations - values of 0 or 1 0xFFFF4FC5 - 1 byte - index that is used to access next cylinder number in either of the above locations - values of 0 or 1 0xFFFF4FC6 - 2 bytes - unused
0xFFFF6658 - Base of 4 x 40 byte table - 'Injection Table' with data to manage injection of each cylinder. The logic allows for multiple cylinders per 'bank'. Each 40 byte table consists of the first 16 bytes relating to the 'bank', and then groups of 24 bytes for each cylinder on that bank. Of course, in a 4 cylinder engine like I'm dealing with, there is only 1 cylinder per bank (hence, below I only talk about cylinders). 0xFFFF6658 - 1 byte - Flag for cranking or not - 0x00 if cranking, 0x01 if not cranking 0xFFFF6659 - 1 byte - Flag for whether ignition of this cylinder is currently on - 0x00 is on, 0x01 is off 0xFFFF665A - 1 byte - Flag - unknown - values of 0, 1 or 2 0xFFFF665B - 1 byte - Flag - unknown - values of 0, 1 0xFFFF665C - 2 bytes - Counter - number of 180 degree revs required until this cylinder gets to TDC 0xFFFF665D - 1 byte - unused 0xFFFF665E - 1 byte - Flag for cranking or not - 0x00 if not cranking, 0x01 if cranking 0xFFFF665F - 1 byte - Flag - unknown 0xFFFF6660 - 4 bytes - TDC angle for the cylinder - set to 0, 360, 180, 540 for cyls 0 to 3 0xFFFF6664 - 4 bytes - Cylinder number 0, 1, 2, 3 (this is actually 'bank' number, which is why there is another entry for Cylinder number below) 0xFFFF6668 - Base of the 24 bytes for each cylinder in the 'bank' 0xFFFF6668 - 1 byte - Cylinder number 0, 1, 2, 3 0xFFFF6669 - 1 byte - Unknown flag 0xFFFF666C - 4 bytes - Injector Pulse Width 0xFFFF6670 - 4 bytes - Injector Pulse Width in quarter microsecs 0xFFFF6674 - 4 bytes - a threshold angle - not sure, but appears to be threshold within which changes to cranking status or firing status are disallowed 0xFFFF6678 - 4 bytes - a threshold angle - not sure, but appears to be threshold within which changes to cranking status or firing status are disallowed 0xFFFF667C - 1 byte - Flag - unknown the above is then repeated 3 times
0xFFFF6A3C - Base of 2 x 28 byte table - 'Ignition Table' with data to manage ignition of each firing group of cylinders. Each 28 byte table is for a 'firing group' of cylinders that fire at the same crank orientation (but don't all neccessarily fire each rotation). The first 12 bytes relate to the 'firing group', and the following 14 bytes hold the data for the next cylinder to fire from this group. 0xFFFF6A3C - 1 byte - Flag for cranking or not - 0x00 if cranking, 0x01 if not cranking 0xFFFF6A3D - 1 byte - unknown 0xFFFF6A3E - 1 byte - unknown 0xFFFF6A3F - 1 byte - unused 0xFFFF6A40 - 2 bytes - the firing TDC position for this group - 0 or 180 degrees 0xFFFF6A42 - 2 bytes - Flag - unknown 0xFFFF6A44 - 1 byte - firing group number - 0 or 1 0xFFFF6A45 - 1 byte - 'cylinder index' to determine which cylinder to fire - 0 when crank is on its first 360 degree rotation, 1 when crank is on its second 360 degree rotation 0xFFFF6A46 - 2 bytes - unused 0xFFFF6A48 - 1 byte - cylinder number - from applying 'cylinder index' above 0xFFFF6A49 - 1 byte - cylinder number for bitmask - from applying 'cylinder index' above, used to apply correct bitmask for this cylinder to the cylinder on/off firing override byte 0xFFFF6A4A - 2 bytes - mini-table of cylinder numbers to which the index from 0xFFFF6A45 is applied to give the cylinder number that is stored in 0xFFFF6A48. Values of 0, 0 for first 'firing group' and 2, 3 for second 'firing group'. 0xFFFF6A4C - 2 bytes - mini-table of cylinder numbers to which the index from 0xFFFF6A45 is applied to give the cylinder number that is stored in 0xFFFF6A49. Values of 0, 1 for first 'firing group' and 2, 2 for second 'firing group'. 0xFFFF6A4E - 1 byte - Flag - unknown 0xFFFF6A4F - 1 byte - Flag - set to 1 if this 'firing group' is on (no override) 0xFFFF6A50 - 4 bytes - Total Timing for next cylinder to fire in milliseconds 0xFFFF6A54 - 4 bytes - Total Timing for next cylinder to fire in milliseconds the above is then repeated once
How is any of this useful? Aside from understanding how injection/ignition works in gritty detail, it can provide a means of locating the Tables for Injector Latency and Ignition Dwell. I've tested this on a couple of 4 cylinder Subaru ROMs and it seems to work.
A way to locate your Injector Latency Lookup Table 1. Search the whole ROM for hex values 02 D0 00 00 00 64 00 00 (these are two threshold angles - 720 and 100 degrees). There will be two locations. Choose the second one. 2. Go forward 12 addresses from the location that holds the first byte above (02) 3. This will be a 4 byte address for a function, follow this address into the function 4. This function should have a bsr operation to another function. Go into that function. 5. This function should have 3 jsr operations to other functions. Go into the second of these functions 6. This will be a function that returns a RAM location that is your Injector Latency RAM address. 7. Go to the RAM address for Injector Latency and follow the XRef that writes to the Injector Latency RAM address. 8. This Xref will be a function in which the Injector Latency is looked up from a Table Address. This will be your Injector Latency Table.
A way to locate your Ignition Dwell Lookup Table 1. Search the whole ROM for hex values 01 2C 00 00 00 00 00 00 (these are two threshold angles - 300 and 0 degrees) 2. Go forward 12 addresses from the location that holds the first byte above (01) 3. This will be a 4 byte address for a function, follow this address into the function 4. This function should have 3 jsr operations to other functions. Go into the second of these functions 5. This function should do 4 x shll (or 2 x shll2) operations on a RAM value. This RAM value is your Injector Dwell stored in RAM 6. Go to the RAM address for Injector Dwell and follow the XRef that writes to the Injector Dwell RAM address. 7. This Xref will be a function in which the Injector Dwell is looked up from a Table Address. This will be your Ignition Dwell Table.
|