Reading/Writing/Flashing the Rover MEMS3 ECU
Download
Link: https://andrewrevill.co.uk/Downloads/MEMS3Tools.zip
A while back a wrote an article on cloning the
Rover MEMS3 ECU https://andrewrevill.co.uk/MEMS3Cloning.htm.
This process was fairly involved and invasive. It involved dismantling the ECU,
removing the memory chips and reprogramming.
Since then I’ve been working on cracking the process of flashing full maps
and firmware to the MEMS3 ECU without any disassembly. I wanted to be able to
copy the full firmware and maps from one ECU to another in a simple way through
the OBDII port only, similar to the way that well-known mapping specialists do.
This goes well beyond the map reading and writing capabilities of tools like
Galletto as it allows the full operating firmware of the ECU to be cloned.
It’s taken me about a year of chipping away at it … but I’ve finally got
something robust and useable. I’ve written a little MEMS3 Flasher application
that allows ECUs to be read and written very simply.
This allows you to clone the complete firmware and map from any MEMS3 ECU
to any other with the same part number or compatible hardware. So for example
you can make a backup copy of Supersport ECU by cloning it onto a standard
Rover ECU cheap off eBay.
This works with standard tunes and modified remaps too.
Hardware Required
One objective I set myself was that no expensive hardware should be
required. In order to use my flasher, the only thing you need (other than a
Windows laptop with a USB port to run it on) is a VAG-COM diagnostic cable such
is this: https://www.ebay.co.uk/itm/USB-Cable-VAG-COM-KKL-409-1-Auto-Scanner-Scan-For-Car-Seat-Diagnostic-Tools-BT/223941245849?hash=item3423f03b99:g:ddcAAOSwnT5eYeD5.
Any similar OBDII cable described as a VAG COM KKL 409.1 cable or similar
should work fine. These are widely available very cheaply on eBay. Depending on
the drivers that come with the cable it will either install into your system as
an FTDI Direct device, a Windows COM serial port or both. Avoid cables that
claim to have an ELM327 chip as these are a completely different interface, and
Galletto flasher cables as these seem to have the FTDI chips programmed
differently.
The MEMS3 Flasher Tool
This is a simple Windows EXE, no installation required. All you need to do
is plug the cable into the laptop and the car and run the program and it’s
ready to go. You can download a ZIP of the EXE file here: https://andrewrevill.co.uk/Downloads/MEMS3Flasher.zip.
What Does It Do?
I’ve kept it simple from a user perspective. The temptation was to fill it
with fancy features but I decided that simplicity was in order. As the user
sees it, it has a simple job to do; read and write ECUs and allow the data to
be saved and loaded to and from files. It needs to do that one job really well.
It works like a classic EPROM programmer. You click “Read” to read the data
from an ECU into a memory buffer, “Write” to write the current memory buffer
out to an ECU. You click “Save” to save the current memory buffer to a file and
“Load” to load previously saved data. That’s about it really!
It specifically supports the MEMS3 family of ECUs only, so there’s no
selection or configuration required. Just plug and play.
Some other programming tools like Galletto 1260 do allow you to do
something similar with the map data. I’ll go into it in more detail below but
this is of limited use as each map is built to work with a particular version
of the ECU firmware, of which there are many. This tool allows the full
firmware and map to be transferred between ECUs, meaning you don’t have to
worry about compatibility. And Galletto doesn’t cross-check the firmware
version compatibility (mine does) so lets you flash incompatible maps (mine
doesn’t) … and it often doesn’t seem to be able to recover the ECU if you do,
leaving it “bricked”.
Instructions
Basic instructions for using the software are as follows:
INSTALLING THE FTDI CABLE
1. Follow any instructions
that come with the cable to install the appropriate drivers on your system.
READING FROM AN ECU
1. Connect to the ECU. WARNING:
Do not turn on the ignition yet! Plug the FTDI cable into the OBDII port on the
car and into a USB port on the laptop. The ECU seems to check whether there’s
anything connected when it powers on and if not, after that it refuses to talk.
So it’s important to get everything connected first. If not, you will need to
either turn the ignition off for something like 10 minutes to allow the ECU to
fully power down, briefly disconnect the smaller of the two ECU plugs to
interrupt the power and force a reset, or briefly pull the 30A ECU fuse from the
fuse box.
2. Run the MEMS3 Flasher
Application.
You should see a window like this:
3. Select the OBDII
Connection.
Select the OBDII cable using the combo boxes at the top of the window. It
should show up as either an FTDI Direct Device or COM Serial Port (or both, in
which case it should work fine whichever option you select). You can also
select the OBDII protocol at this stage it required.
4. Turn On the Ignition.
5. Check Your
Connection. Click the About button. The
application will connect to the ECU and display the VIN, Part Number, Part Variant,
Firmware ID and Map ID as shown below. If it doesn’t work first time, try
turning the ignition off and on again and then repeating. The ECU can be a bit
temperamental sometimes!
6. Read the ECU. Click
the Read button. You should be presented with a dialog like the one shown
below:
You can choose to read the full firmware (contains the operating software of
the ECU), coding (contains the VIN and Part Variant) and the map (contains the
various tables with the configuration parameters for the engine) or just the
map. If you only read the map, you will be able to write this back to any ECU
with the same firmware version only. If you read the firmware and map, you will
be able to write this back to any compatible ECU. Due to the fairly low serial
data speeds used by the protocols supported by the ECU, reading the map alone
takes about 22 seconds and performing a full read of the ECU takes about 4
minutes 19 seconds.
Once the read is complete the system displays a dialog confirming the VIN,
Part Variant, Firmware ID (if these were read) and Map ID for the data in the
internal buffer. These should match the data originally displayed for the ECU.
The messages are all protected by checksums and the protocols I have
implemented include several layers of error checking and recovery so the data should
match in every case. If the transfer is interrupted, you should see that the
Resume button becomes enabled. This will allow you to resume and complete the
read, even if the ECU has been shut down in the meantime.
After reading the ECU, the internal buffer data is displayed in hexadecimal
form as show below.
7. Save the Data to a
File. You don't have to save it to a file before writing it back to another
ECU but it makes sense to save a copy. Click the Save button. You will be
prompted for a file name to save the data as a .BIN file (raw binary data).
There are several file formats supported but the default "MEMS3 Flasher
192KB" file format should be fine. The different file formats are
discussed further below.
WRITING TO AN ECU
1. Open a File. If
you are moving straight on to writing to a new ECU, you can skip this step.
However if you return to it at a later data, connect to the ECU, run the MEMS3
Flasher application, turn on the ignition and check your connection exactly as
described in instruction (1) to (4) previously, then click the Open button and
select the file you saved previously.
2. Write the ECU. This
is very similar to reading an ECU. Click the Write button. You should be
presented with a dialog like the one shown below. Again you can choose to write
the full firmware and map or just the map alone. If you choose to write just
the map, the application will check the firmware in the ECU to make sure it is
the same version as the one the map is compiled for and will refuse to write an
incompatible map to the ECU.
There are a few extra options when writing:
a) Clear Adaptations. This
will clear any fueling adaptations in the ECU, as they may not be appropriate
with a modified map. The ECU will readapt over a couple of hundred miles of
mixed driving. During this time the emissions and fuel economy may not be as
good as they normally are as the fueling may be slightly incorrect.
b) Automatically verify ECU
on successful write. This will cause the application to perform a read of the
ECU once the data has been written, to confirm that the data now in the ECU
matches that in the buffer. This is a bit of a "belt and braces"
solution as the ECU appears to verify internally that each block is written
correctly as received and the communications use checksums to allow the ECU to
confirm that each message received is as it was sent, so other than for
failures of the software or very unlucky corruptions that leave the checksums
unchanged, the data transfer should be reliable. For peace of mind though, I
normally verify after writing.
c) Clear diagnostic information. This option only applies when writing the
firmware. Because I can't be sure that the format used for storing information
in the working non-volatile memory of the ECU is identical or compatible
between firmware versions, by default the application clears any diagnostic
information. The ECU will then continue to log new diagnostic information for
any current faults.
d) Learn immobiliser code. Again this only applies when writing the
firmware. Again, as I cannot guarantee that the format used for storing the
immobiliser code will always be compatible between firmware versions, by
default the application clears the immobiliser coding and tells the ECU to
re-learn it from the immobiliser. The ECU will then be free-running initially
but the first time it sees the immobiliser disarmed it will learn the code and
again be paired with that immobiliser.
Due to the fairly low serial data speeds used by the protocols supported by
the ECU, writing the map alone takes about 24 seconds to write and 22 second to
verify, so 46 seconds in total. Performing a full write of the ECU takes about
3 minutes 44 seconds to write and 4 minutes 19 seconds to verify, so just over
8 minutes in total. The ECU will reboot at the end of the write, you will hear
the fuel pump priming as though the car ignition was just turned on.
Try not to interrupt the process of writing to the ECU as the ECU will not
run the engine with only a partial firmware or map. As for reading, if the
transfer is interrupted, you should see that the Resume button becomes enabled.
This will allow you to resume and complete the write in most cases. See the
section on Robustness & Risks below.
License & Warranty
I’ve decided to release the executable into the public domain. Feel free to
copy it, share it use, distribute it, give it to your mates, do what you want
with it. You can even sell copies if you can find somebody daft enough to pay
for something that I’m giving out free! I just want it out there as a tool that
people can use if they need it. I think it’s pretty robust but it’s probably
not perfect, feel free to let me know if you find anything wrong, there’s an
email link in the top right hand corner. I’ll try to fix things that get found
and keep it maintained but I’m not offering any kind of warranty or guaranteed
service level though. This has been and will always be a side project for me.
Source Code
The application is developed in Delphi 10.3, Community Edition. At the
moment I’m not releasing the full source code but if anyone really wants to
know how it works and has a need for parts of the code I’ll happily share.
On Bench or In Car?
The application has been written to allow the ECU to be reflashed in the
car through the OBDII port. You could also use a simple bench testing harness
such as the one I described here: https://andrewrevill.co.uk/KeyProgrammer.htm.
Doing it in the car is the easiest and means that you don’t need to buy or
build expensive hardware. It also pretty much guarantees a reliable power supply.
I’ve done most of my development work on the bench then tested on my car.
File Formats
The MEMS3 flasher loads and saves binary files with .BIN extensions. It
supports a number of different types of binary files and it recognises the type
of file from the file size. The following types are supported:
·
Flasher Files - 196,606 Bytes (192kB - 2 unreadable bytes) - These are the
native file format for the application and contain the full firmware and map.
·
Firmware Files - 172,032 Bytes (168kB) - These contain only the firmware
with no map.
·
Map Files - 16,382 Bytes (16kB - 2 unreadable bytes) - These contain only
the map.
·
EEPROM Files - 262,144 Bytes - These contain the full boot loader, firmware
and map. They are files obtained by reading the EEPROM chip on an EEPROM read
off the board as I did in my original article. Because of the way the
microcontroller addresses 16-bit memory, each pair of bytes in this kind of
file is exchanged.
In normal use, you would probably only need to use the normal Flasher files.
See the section on the Memory Map below for more information about the memory
areas covered by these file formats.
Hardware Compatibility
There is no check on whether the firmware you are flashing is compatible
with the actual ECU you’re flashing it to. The firmwares don’t seem to contain
hardware part numbers to cross-check. I guess that’s something that was managed
by Rover’s TestBook system originally.
MEMS3 is a modular architecture (that’s what the first “M” stands for).
This means the basic core ECU is common across a wide range of models, but ECUs
with different part numbers either do or don’t have a number of additional
hardware and software modules installed. For example, looking the circuit
boards, there are chips that are only present in VVC ECUs and there are other
chips such as a CAN controller which are only present in ECUs for use with
automatic gearboxes.
Each ECU has a part number starting with NNN… and a part variant starting
with NNW…
I think the NNN code relates to the physical hardware and the NNW to the
firmware installed. From all the testing I’ve done, you should be safe to copy
between ECUs with the same NNN number. In actual fact there is more flexibility
than this; for example the early MGF Trophy 160 ECU NNN000100 and the later MG
TF 160 ECU NNN000160 look to be identical hardware to me, and I’ve had no
problems copying firmware and maps between them. But if you stick using ECUs
with the same NNN part number you should be safe.
I’ve played with what happens if you flash incompatible firmware on an ECU.
I flashed VVC 160 firmware and maps onto a Freelander ECU just to see what
happened. The answer is that it worked surprisingly well! Nothing horrible
happened, the engine VVC engine started and ran fairly normally, it probably wouldn’t
have run the engine very well under load as the map would have been wrong and
it wouldn’t have controlled the VVC solenoids, it logged a few faults with the
VVC system (which was missing!) but other than that it ran the ignition and
injection happily enough and more to the point, it was still happy to
communicate so I was able to just flash the original Freelander firmware and
map back on and it was all happy again.
Robustness & Risks
Whilst developing this, I built myself a couple of heavily modified test-mule
ECUs. One of the things I did was to replace the main EEPROM memory chip with a
socket, so I could plug the chip in and out easily. It was a bit fiddly and I
had to carefully trim the sockets to fit around some small surface mount
components close to the chip but it worked well.
This allowed me to look on the PC what I was actually doing to the memory contents,
but the main idea was that if and when something went wrong and I “bricked” the
ECU (i.e. got it so messed up that it would no longer communicate well enough
to allow me to put it back again) I could easily reprogram it on the EEPROM
programmer.
In the whole time I have been developing this, during which I must have
flashed eight or nine different ECUs of various types a hundred times or more,
I have to say I only “bricked” one once, and that was when I was first writing
the code that allowed writing to recover after being cancelled or experiencing
an error; I mistakenly carried on writing the data from where it left off but
started again at the beginning of the EEPROM chip, which obviously just made a
complete mess.
Since releasing the tool I’ve put a lot of work into fail-safety. In my
initial write up I voiced some concerns over possible risks of “bricking” an
ECU if a write failed. Since then, I’m pretty sure I’ve come up with a
fail-safe write procedure which on paper and in practice should not run the
risk of leaving the ECU in a “bricked” condition. Although I wouldn’t recommend
it, you can now interrupt any process at any point and the ECU will be left in
a condition where it will still boot up safely ready for you to repeat the
operation. I have repeatedly tried to “brick” an ECU with the latest code by
doing all of the following many times, at many different points in the process,
both during full firmware write and map updates, without any problems:
With the latest code, none of these have been able to induce any serious
issues at all. In the worst case (in fact in pretty much every case) you just
need to turn the ignition off and on again to reset the ECU, then make sure
everything is connected up again and repeat the write operation. The ECU will
be left in a state where it won’t run the engine (until you repeat the write
operation) but it will drop back into its boot loader code and communicate with
the mapping application, waiting for programming instructions.
The research required to get this write cost me many “bricked” ECUs along
the way, but as I say I had modified a couple of ECUs with sockets for the
EEPROM chips allowing me to remove them and recover them in a stand-alone
programmer each time. I am now confident enough in the code that I have
reversed all the modification on my ECUs and put them back to standard with
permanently soldered EEPROM chips. I do not anticipate “bricking” any more ECUs
- and if I didn’t have the self-belief and confidence to use it on standard
ECUs then how could I expect others to?
I’ve built multiple layers of error recovery into the software. If the ECU
rejects any messages or sends inappropriate or corrupted responses (which can
be caused by noise pickup on the power supply or communication lines) the
software repeats the message or takes other recovery action as necessary. If
the ECU stops responding altogether it attempts to reboot it and continue. Even
if it gets into a state where you need to power the ECU off and on again to get
it talking again, you should just be able to hit the “Resume” button and it
will pick up where it left off, whether reading or writing.
NB: Turning off the ignition may not be enough to power off the ECU.
Normally the ECU continues to run for some minutes after the ignition is turned
off. In a Rover it would be monitoring engine bay temperatures and running the
fans. If the ECU functionality is compromised, it may even continue to run
indefinitely. If you want to be sure to power the ECU off fully, either pull
the 30A ECU fuse for a couple of seconds or briefly remove the smaller of the
two connectors from the ECU by sliding the lock outwards.
For some reason the ECU is quite flaky whilst reading data, every now and
again it seems to just ignore a message or respond with complete gibberish. My
code works around all of this the vast majority of the time and from the user
end you wouldn’t know it was happening (there’s a little red “Retry” icon at
the bottom of the screen that flashes each time it has to recover from an error
just to give an idea of when it’s having problems, but that’s all you see).
Luckily it seems to be rock solid whilst writing. I’m not 100% sure why, I
think some of it is because in a programming diagnostic session it drops back
into the boot loader code and isn’t trying to run engine management at the same
time (more information below). One way or another, the good news is that whilst
actually making changes to the memory contents it really does seem to be robust
and reliable and everything goes to plan if it isn’t externally interrupted.
Errors, Cancel & Resume
Whenever it is working on a long running process, such as reading from or
writing to the ECU, there’s a “Cancel” button enabled. You can click this to
cancel the operation. As mentioned above, I really wouldn’t cancel a write part
way through unless there was an emergency, it will leave the ECU in a
non-running state and there’s a small risk of it being too unhappy to be
recoverable. Cancelling a read or verify at any time is fine. And any time you
cancel a read, write or verify there’s a “Resume” button enabled which allows
you to pick up where you left off. This is robust an
reliable, even if the ECU has been shut down or rebooted in the meantime. The
“Resume” button will also pick up an operation that stopped because of an
error. So for example if the ECU just stopped responding half way through a
long read, you can reset it and resume without starting again.
Supply Voltage
Sites on the Internet seem to suggest that you should never try to reflash
any ECU at anything other than 13.5V. This obviously precludes flashing the ECU
in the car, as you can’t do it with the engine running and the battery voltage
alone will be well below that. The memory chip itself needs 12V on some pins
whilst flashing, I’m not sure if this is internally generated or whether it
just uses the external supply, but I’ve tested flashing ECUs with supply
voltages from 10.8V to 14.0V and it was fine. If you’re flashing it in the car,
so long as the battery is reasonably healthy it should be happy.
OK SO THAT’S ABOUT AS FAR AS YOU NEED TO GO IF YOU JUST WANT TO USE THE
TOOL, THE REST IS THE GEEKY BIT ABOUT HOW IT ALL WORKS INSIDE!
Cracking this has been an interesting challenge for me, to say the least.
It’s been a slow process of unpicking a web of connections. Usually cracking
one part leads to further understanding which unlocks the next part.
There’s no specific documentation of MEMS3 that I could find. To some
extent it does adhere to common standards, but not fully. It’s all the places
where it deviates from any common standard or where there is no standard which
proved most challenging.
I’ve had to work all of these things out from first principles and
intuition. The information below is based on my own research and is correct to
the best of my knowledge, but I’m just finding my own way through things so it
may or may not be absolutely accurate. I've will probably have used different
terminology and described things from a different perspective to that of people
who may have been involved with MG Rover development. I haven’t covered all of
the details or this would turn into a very long read, just some of the more
interesting key points.
A lot of the development work has proceeded by making working hypotheses
and then testing these on ECUs. I many cases they have proved to be
misunderstandings and some of my current state of understanding may not be
absolutely correct but it has formed the basis of a working model of the ECU
which has allowed me to achieve my current objectives.
Some of the methods I've used include:
·
Sniffing protocols. I've used various different techniques to sniff the messages sent between
other tools and the ECU.
·
Disassembling ROM code. I've disassembled code inside the ECU EEPROM and code in other tools which were
able to talk to the ECU to find out how things were done. In particular this
was necessary in cracking the seed-key security mechanism. See the Seed Key
Algorithm section
below.
·
Modified development ECUs. I added various features into a number of ECUs including socketed EEPROM
chips and multi-protocol data loggers to record the communications with the ECU
under various different conditions. I used data loggers based on the SparkFun
OpenLog device but I rewrote some very specific Arduino code for them to allow
them to log a lot of details of the ECU communications, timing etc.
·
MEMS3 Terminal. Along the way I developed my own terminal application which was capable of interception,
logging and decoding communications with the ECU. This was also capable of
reading and decoding the log files from the development ECUs described above.
It also allowed me to key in messages and talk to the ECU directly.
·
Modified FTD2XX.dll. A lot of tools which are capable of communicating with
the ECU use hardware based on the FTDI chipset (as does my application). As
these are always compiled Windows executables it's very hard to see what they
are doing internally. But I found that the FTDI driver DLL was a convenient
weak point to attack. Basically I wrote my own version of the DLL. It didn't do
a lot, it just declared all of the same functions as
the original DLL, loaded the original DLL in the background and passed all of
the function calls straight through. But that meant that I was able to add code
to any of my wrapper function to log calls and results. I was also able to add
an inter-process communication pipeline to the terminal program described
above, meaning that all communications with any FTDI devices system-wide would
be reported to and decoded by the terminal in real time. It even allowed me to
intercept specific calls and modify them. But the most interesting thing it did
was to allow me to load any other tool which could communicate with the ECU in
my debugger (by debugging the DLL, with the tool I wanted to debug set as the
host process). This meant I could set breakpoints on calls and then work
through what it was doing at the time, what it would do with the value returned
etc.
Protocols
The communication protocols used by the ECU are very similar to a number of
standard but it doesn't seem to adhere to any of the strictly. I seems to support at least three different protocols.
1. ISO 9141-2. This is
mostly used for communications with OBDII scanners. It operates at a speed of
10400 baud with a specific "slow-initialisation" signal used to start
communications.
2. A native protocol which
uses a lot of KWP2000-type messages but a different addressing scheme. This
operates at a speed of 9600 baud. It has similarities with protocols used by
BMW at the time. There is no particular out-of-band initialisation signal. My
guess is this is the protocol primarily used for commination with the Rover
Testbook suite of internal diagnostic tools. I have referred to it as
"Rover BMW 9600 Baud" in my application. When the ECU first boots up,
in the absence of any special initialisation signal, this is the protocol it
uses.
3. ISO 14230-2 / KWP2000.
This protocol seems to adhere more closely to the standards. It operates at a
speed of 10400 baud with "fast-initialisation" signal used to start
communications. Once the ECU has received the initialisation signal for this
protocol, there is no way to switch back to the native protocol other than
resetting the ECU.
In practice I found that either the native protocol or ISO 14230-2 worked
well for reading or writing. The ECU seemed to support all required operation
under both protocols both when running the firmware code or
when dropped back into the boot loader. The usual ISO 9141-2 however seemed
less reliable and I had some difficulty generating an acceptable "slow
initialisation" signal over the FTDI cable. Despite using bit-blatting
techniques and confirming with an oscilloscope that the signal and start of
communications seemed to be exactly the same as those generated by OBDII
scanner, it seemed to be unreliable and the signal was often not recognised.
Once I realised that the ECU supported everything I
needed in either of the other two protocols I decided not to waste any more
effort in ISO 9141-2, which is no longer supported by my tool.
Memory Map
MEMS3 uses a 29F200 EEPROM chip. Specifically it uses an AMD
AM29F200BT-90SE variant. This is mapped into externally accessible address
space (as seen by OBDII) at base address $100000, meaning that the different
sectors of the EEPROM appear at the addresses shown below.
Sector Size Address Range Used For
SA0 64KB $100000 - $10FFFF Boot
Loader
SA1 64KB $110000 - $11FFFF Firmware
SA2 64KB $120000 - $12FFFF
SA3 32KB $130000 - $137FFF
SA4 8KB $138000 - $139FFF
SA5 8KB $13A000 - $13BFFF Coding
SA6 16KB $13C000 - $13FFFF Map
Each sector of the EEPROM can only be erased as a whole. Without erase a
sector (which sets every byte to $FF or binary 11111111, logical 1's can only
be programmed to logical 0's and not the other way around, so it is not really
possible to write arbitrary data to a sector without erasing the data in the
area to be written first, and this means erasing the whole sector.
Interestingly the "BT" in the chip designation means "Boot Block
at Top" - so the small 16KB sector SA6 at the top of memory is intended to
hold boot loader code, which would be a small application whose sole job is to
communicate with some external tool to allow the contents of the rest of the
EEPROM to be loaded. In MEMS3, this sector SA6 is used for the map data which
it relatively small and the bottom 64KB sector SA0 is used to the boot loader
code. The next 4 sectors SA-SA4, 64KB + 64KB + 32KB + 8KB = 168KB are used for
the firmware code. The next 8KB sector SA5 is used for what I have called
Coding - this basically includes the VIN code and the Part Variant. Of the 8KB
available this sector, only 14 bytes (VIN) plus 6 bytes (Part Variant) appear
to be used.
As far as I can tell the ECU only provides routines to erase the firmware
and map sectors. So the boot loader code is permanent and cannot be changed
without corrupting it. This makes sense as the boot loader code is what is
executing when loading firmware or map data; overwriting the boot loader while
it was running would not make sense. The same is true of the Coding data, so it
is not possible to write a new VIN code or Part Variant code to the ECU. This
is probably for security, the original VIN number being indelibly written to
the ECU. The other possibility of course is just that I haven't been able to
track down the routines to erase the coding data. This doesn't seem to be a
significant restriction, as any version of the boot loader seems to work
happily with my tool and will load any firmware version. The boot loader code
isn't involved in running the engine at all, so once the firmware has been
loaded and is running the older boot loader is irrelevant, and the VIN and Part
Variant code are informational only.
The boot loader version on an ECU seems to be consistent across ECUs with
the same part number. So for example an early VVC ECU NNN000100 will always have
boot loader version BOOTP030 and a later VVC ECU NNN000160 will always have
boot loader version BOOTP033.
Runtime & Adaptations
Runtime data such as DTCs, adaptations and immobiliser coding are stored in
a separate 93C66 serial EEPROM chip. This doesn't appear to be externally
addressable; it doesn't appear as memory addresses mapped into the memory space
accessible to OBDII commands. I believe data here will be read and written
using higher level OBDII commands used to request diagnostic information, or to
request or set data by local identifiers. I haven't been able to track all of
these down, but I have managed to provide workarounds which seem to be
perfectly adequate. So for example when writing a new map I clear the existing
adaptation and when writing new firmware I clear the immobiliser coding and
allow the ECU to re-learn the code from the immobiliser. I haven't had any
issues using these workarounds in testing.
Checksums
The firmware and map areas of the EEPROM are protected by checksums. This allows
the ECU to verify that any data loaded has not been corrupted during transfer.
It also prevents anyone who doesn’t know the checksum algorithm from being able
to modify the data.
The idea is that some mathematical operation is performed across all the
bytes in the area covered by the checksum to give a number, which is then
stored in the data. The ECU is then able to perform the same mathematical
operation on the data in its memory and compare the number it gets to the
number stored. If they are the same, the data is assumed to be unmodified. If
they ae not the same, the data must have been modified and is rejected.
Checksums are traditionally added to the end of a data block, so the first
place I looked was the last two bytes of each block, but in each case these
just contained $FF, $FF indicating unused space at the end of the block.
I tried various different checksum algorithms but nothing matched; the main
issue I had was working out which bytes in the data were the checksum. Then I tried
just adding up all of the numbers in the block, first as 8-bit bytes and then
as 16-bit words, and a pattern emerged across the ECUs. For any given block
(i.e. firmware or map), the answer was the same in every ECU I looked at.
So for example, for the firmware area, the 16-bit sum of the 86,016 16-bit
words (high byte first) at hexadecimal addresses $110000/1 to $139FFE/F is
always equal to $04FB.
This gave me the checksum algorithm. Somewhere in the block there are two
checksum bytes which get to $04FB minus the sum of all of the other pairs of
bytes. There’s no way to work out which two bytes, as if you think about it
EVERY pair of bytes will be equal to $04FB minus the sum of all of the others.
But it doesn’t matter, because I’m also free to adjust any two bytes I chose.
At the end of each block there is a large amount of unused space as the
contents of the blocks are quite a lot smaller than the EEPROM segments
allocated to them. So I can rely on the fact that the last few bytes of the
block will be unused and safely replace two of the with
$04FB minus the sum of all of the others and the rule will be satisfied.
I’ve tried modifying data and correcting the checksums in this way and the
ECU happily accepts the new firmwares and maps.
My application now checks the checksums for the firmware and map on loading
a file, saving a file or writing to the ECU and offers
to correct them automatically if they are incorrect. On writing to the ECU it
checks them, offers to correct them and refuses to write to the ECU if they are
not corrected, as the ECU would not run with incorrect checksums.
Seed Key Algorithm
The ECU is protected by a seed key security system. When you want to gain
security access, the ECU gives you a 16-bit number called the seed. You have to
perform a (secret) operation on this to work out the corresponding key, and
give that back to the ECU. The idea is that only Rover know the details of the
operation to be performed and, like a good hash function, the output numbers
give very little clue as to the calculation. So you can’t for example record a
programming session and make a note of the key used, because next time the seed
will be different and an entirely different key will be required.
To work this out I had to reverse engineer it by disassembling machine code
routines in the ROM and in other programming tools.
As MG Rover are now long gone, I don’t have any moral qualms about
publishing the seed key algorithm that I discovered, without which you cannot
unlock and maintain our ECUs. Here it is in full, written in Pascal (I used
Delphi for the development of the application which is Pascal based). You could
code it in any language you like. It takes a 16-bit seed and returns the corresponding 16-bit
key:
function SeedToKey(ASeed: Word): Word;
var
I: Integer;
begin
Result:=0;
I:=1;
if Odd(ASeed shr 15) then
Inc(I, 8);
if Odd(ASeed shr 7) then
Inc(I, 4);
if Odd(ASeed shr 4) then
Inc(I, 2);
if Odd(ASeed) then
Inc(I);
for I:=I DownTo 1 do
begin
Result:=(((ASeed shr 1) and $FFFE)
or Ord(not(Odd(ASeed shr 13) and
Odd(ASeed shr 3))))
and $7FFF;
if Odd(ASeed shr 9) xor Odd(ASeed
shr 8) xor Odd(ASeed shr 2) xor Odd(ASeed shr 1) then
Result:=Result or $8000;
ASeed:=Result;
end;
end;
Boot Mode, Diagnostic Sessions
One thing which originally puzzled me was how to get the ECU into boot mode
to allow the firmware to be overwritten. I was originally assuming that there
was some combination of voltages applied to pins when booting which caused the
ECU to enter boot mode and run the boot loader code rather than the main
firmware, but in the end the answer was a lot more simple and convenient; there
are a number of different "Diagnostic Session" types that you can
request, and combined with the right security privileges, requesting a
programming diagnostic session exits the firmware and runs the ECU in the boot
loader code. You can recognise that the ECU is in boot mode because although
communications with the ECU remain normal, none of the engine management
functions are running. The fuel pump doesn’t prime, the IACV doesn't chatter as
it usually does and the engine will not run.
Routines
The ECU has number of pre-defined routines in EEPROM that you can execute
with a command to "start routine by local ID". Some of these routines
execute quickly and return a positive or negative result almost immediately.
Some of them however execute for several seconds, such as the main firmware
EEPROM erase routine. These return a pending result immediately and a further
positive or negative result on completion. Figuring out the IDs and parameters
required for these routines was one of the challenges of cracking this.
Maps
The upper 16KB sector of the EEPROM contains the tune file or map. This
consists largely of a number of tables. These are generally referred to as 2D
or 3D tables, although more correctly these are 1D or 2D arrays of numbers (the
third dimension being the axis on which the actual table numbers are plotted on
a 2D line or 3D surface chart). Even for the same firmware version, the
addresses of the maps in memory vary between different ECUs and map files. The
main firmware locates each table by looking up the address in a master table
index. This master table index varies in address in different firmware versions
and I can't find any kind of "index of indexes" that points to it, so
my guess is the index address is just a constant baked into the firmware code
at compile time. The index however easily located as it sits alone above
everything else towards the top of the map file address space, so any block of
valid table addresses which follows an unused block of $FF space will be the
master table index.
Most of the rest of the map space consists of tables in the same format,
stacked one after another with no gaps between them. Oddly however not all of
these tables are pointed to by the master index. Most of the unindexed tables
seem to contain junk data such all zeros. My guess is that these tables are not
used by the firmware as it has no way to address them directly (it could be
that there are a number of tables used as a set, which always follow each other
in memory, and so the ECU only needs to be able to index the first one and then
walk along them as there are no gaps, but I doubt it looking at the contents of
the unindexed tables. Quite why the unused tables are still there but not
indexed I have no idea, it must be a quirk of the original map compiler used by
Rover.
Future Plans
I'd like to build up a library of Caterham maps, especially the
"special editions" such as Supersport ECUs. This would allow any of
these ECUs to be recreated using stock cheap MEMS3 ECUs off eBay. I would
backup complete firmwares in the library as I believe this would also cover any
special cases where the firmware may have been specifically modified, such as
they code in a Supersport ECU which repurposes the air conditioning clutch
output as a shift light.
My ultimate goal is to make the MEMS3 ECU properly remappable. To be
honest, by the time I've got round to writing this up I've pretty much already
done it. I've already got full control of the target AFRs, open/closed loop
control, fueling adjustments, ignition timing, overrun pop and crackly, idle
air control valve and rev limiter. On VVC engines I've also got control of the
VVC mechanism sorted. I think I've pretty much covered all of the key
parameters you would want to adjust when remapping the ECU for a modified
engine.
I've already been able to adjust all of these parameters consistently and
flash the modified maps back to my car with the expected results (rev limited
to 3K it did feel a bit sad!).
The mapping application is a lot more comprehensive, complicated and
flexible but is built on top of the flasher tool described in this post. I'm
still working on tracking down more parameters and I need to put some finishing
polishing touches to my remap application and there will be another write-up
soon, but here's a teaser ...