Reading/Writing/Flashing the Rover MEMS3 ECU
Download Link: http://andrewrevill.co.uk/Downloads/MEMS3Tools.zip
A while back a wrote an article on cloning the Rover MEMS3 ECU http://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.
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: http://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Ē.
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.
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: http://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.
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.
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.
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.
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.
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
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.
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;
† I: Integer;
† 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
† for I:=I DownTo 1 do
††††† 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;
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.
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.
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.
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 ...