Remapping the Rover MEMS 2J and Land Rover Td5 MSB ECUs

Download Link: https://andrewrevill.co.uk/Downloads/MEMSTools.zip

After many months of development work, I have recently completed a major upgrade to my MEMS Tools suite. This now fully supports reading / writing / remapping of the Rover MEMS 2J and Land Rover Td5 MSB ECUs. These ECUs were previous not writeable over OBDII. With a small modification to the ECU itself, they become readable and writeable using MEMS3 Mapper with programming and customisation functionality almost exactly equivalent to MEMS3.

Overview

The previous version of my tools suite was known as MEMS3 Tools, comprised of the MEMS Flasher application for reading and writing ECUs and the MEMS3 Mapper application for remapping work, supporting custom firmware patches such as dual map with live switching. Later versions of MEMS3 Tools included limited support for MEMS 2J and Td5 MSB. They provided all of the usual maintenance and servicing tools (similar to the Rover T4 system), allowed the ECU ROM to be read and dumped to a file, and also allowed the ECU map to be read and displayed, however the map display was achieved by converting the map into a MEMS3 format and the map could not be meaningfully edited and could not be written back to the ECU.

The new version of my tools suite is known as MEMS Mapper and has EU2, EU3 and EU4 versions of all of the main applications. So, we have MEMS3 Flasher EU2, MEMS3 Flasher EU3, MEMS3 Flasher EU4, MEMS3 Mapper EU2, MEMS3 Mapper EU3 and MEMS3 Mapper EU4. The EU4 versions of the applications support the MG TF LE500 NAC N-Series ECUs. The EU3 versions of the applications are the “general purposes” versions and support the Rover MEMS3 and the Land Rover Td5 NNN ECUs as before as well as providing basic (live diagnostics and data, maintenance and servicing) support for MEMS 1.9 / 1.6 / 1.3 and 1.2 (as for the earlier MEMS3 Tools releases).

The new EU2 versions of the applications support the Rover MEMS 2J and Land Rover Td5 MSB ECUs, which are no longer covered by the EU3 versions. The EU2 versions provide full native support and work with the EU2 ECUs in almost exactly the same way as the EU3 versions work with the Rover MEMS3 and Land Rover Td5 NNN ECUs. They correctly reflect and understand the memory maps of the EU2 ECUs. Maps can be read, edited and written (with small modifications to the ECUs as described below). Most of the familiar custom functionality provided by the earlier MEMS3 Tools is now supported on the EU2 ECUs using MEMS Mapper EU2 application, including:

 

Nearly everything works exactly the same as on MEMS3 with MEMS Mapper E3. One small difference is that in EU2 ECUs the map (and sometimes maps, as there can be two maps as supplied from the factory) is at an arbitrary address within the same ROM sector as the firmware; for this reason, the firmware and map cannot be read from and written to the ECU separately as with MEMS3, but are always written together as a single operation. There is only one checksum and verification procedure in the ECU which covers both the firmware and the maps.

Architectural Changes

When I compared the EU2 architecture of the Rover MEMS 2J and Land Rover Td5 MSB ECUs with their EU3 descendants the Rover MEMS3 and Land Rover Td5 NNN, it was clear that there were two basic problems which would need to be overcome in order to render the EU2 ECUs fully remappable:

  1. The ROM chips used in the EU2 ECUs (AT27C1024) were One-Time-Programmable. They were flashed with the firmware and map at the factory and could not then be erased or rewritten.
  2. There was no separate boot loader. The EU3 ECUs has EEPROM chips that were divided into sectors and where individual sectors could be erased leaving other sectors intact. This allowed one or more sectors to be allocated to a boot loader program which was independent of the main firmware and was able to facilitate programming of the firmware and map. This allowed the firmware to be erased under the control of the boot loader, leaving the boot loader intact and able to communicate to load a new firmware.

For point (1), after some research I came to the conclusion that there was one single EEPROM device type which met the following requirements:

This was the AT29C1024. It’s a less well-known and less-used chip than the AT27C1024. It is now obsolete from the manufacturer Atmel (as are most of the chips of that vintage) but still readily available by the thousand from Chinese obsolete silicon specialists selling through e.g. AliExpress. Not many of the bench chip programming tools support it, but the XGecu T56 does, with a suitable PLCC44 to DIP44 adapter. It is a drop-in replacement for the AT27C1024 in this application. It can be programmed in-circuit with the available 5V supplies only. In addition, it has a very granular sector structure, with each block of 256 bytes (128 words in 16-bit mode) being a separately erasable and writable sector or page.

For point (2) it was clear I was going to have to write a stand-alone boot loader from scratch. So that’s what I did! It’s written directly in 68000/CPU32 assembly language and occasional binary machine code. It supports standard ISO14230 / KWP2000 communications (with a subset of the full protocol message set implemented as required, but following all standards for initialisations, message formatting, timings, timeouts etc.) as for the standard EU2 and EU3 firmwares, meaning that the PC end could talk to an ECU in the same way without having to know if it was running the boot loader, a stock firmware, or a firmware running under the boot loader. The standard firmwares need a small number of modifications patching in, described in detail later in this article, but MEMS Mapper EU2 is able to apply all of these patches automatically on writing. The memory layout is modified to place the boot loader vector table at the start of the EEPROM where the firmware vector table would normally reside, meaning that the ECU initially boots up into the boot loader and this can then decide whether or not to jump into the firmware. See Boot Loader Technical Details below for further information.

ECU Modifications

Both the Rover MEMS 2J and Land Rover Td5 ECUs need to me modified slightly to meet the architectural requirements described above. The modifications required are described in the following articles. These articles also ship with MEMS Tools and can be displayed as help from the ECU information dialog within the MEMS Mapper EU2 application:

Using MEMS Mapper EU2

Reading maps from unmodified ECUs, reading and writing maps from and to modified ECUs, editing of maps and the installation of firmware patches all proceed almost identically to using the MEMS Mapper EU3 with a MEMS3 ECU.

The MEMS2 Mapper EU2 main window is also almost identical to the familiar MEMS Mapper EU3 main window:

Click Read to read the firmware and map from an ECU (either a stock EU2 ECU or a modified remappable ECU, they behave identically under Mapper EU2 when reading).

Click Yes. There is no separate option to read Firmware & Map or just Map as in MEMS Mapper EU3. Thay are always read together under EU2. EU2 ECUs only support 1x Speed reading and writing, so there are no speed options (the K-Line appears to be much more heavily filtered and higher Baud rates are filtered out as noise). A successful read will be confirmed with an About Project dialog and the map and firmware data will be displayed as show below:

Once you have read the ECU you can save the file, edit tables, edit scalars etc. freely as in MEMS Mapper EU3.

When you are ready to write the modified file back to the ECU (only for modified remappable ECUs, this WILL NOT WORK for a stock EU2 ECU), click Write.

If the file was read from a stock ECU, it will need to be patched for compatibility with the boot loader. MEMS Mapper EU2 can apply all of the required patches automatically on write. It will normally be able to find all of the patch addresses and all of the check boxes should show a green tick (don’t worry if ROM Mount in RAM Subroutine Found at: is blank, this is optional as it is found in some firmwares, particularly Land Rover Td5 MSB firmwares, and is only patched where present – other ECUs use a different method for mounting the ROM chip which does not need to be patched). If the file has already been patched, or was ready from a modified remappable ECU, this dialog will not be displayed. To patch the firmware, click Patch.

Again, you only have the option to write the Firmware & Map together under EU2. EU2 ECUs only support 1x Speed reading and writing, so there are no speed options (the K-Line appears to be much more heavily filtered and higher Baud rates are filtered out as noise). The other write options do carry over from MEMS Mapper EU3 though, so you have the option of clearing adaptation, automatically verifying that the ECU has been written correctly, clearing diagnostic information and learning the immobiliser code.

Where an EU2 ECU contains two maps natively (from the factory, not because of the installation of a map switch patch) then writing a file with different map addresses can result in an invalid map offset being stored. This may cause the ECU to select an arbitrary map, or even the internal NOSELECT map (which is just a default to allow the ECU to run when no proper engine management map is selected). For this reason, by default, on writing to the ECU, the first / default map is explicitly selected. If you want to select a different map after writing, use Tools | ECU Tools | EU2 Map Selection from the menu.

A successful write will be confirmed with an About ECU dialog as shown below:

Immobiliser Delete

One request I often get is to delete the immobiliser functionality on a MEMS 2J. This can be done easily on a modified remappable ECU with MEMS Mapper EU2.

Read the ECU, edit the immobiliser delete flag in the project and then write it back to the ECU.

Click Tools | Wizards | Immobiliser Delete (Map Flag) from the menu.



Check the Delete Immobiliser Functionality box and click OK.

Alternatively, you may edit the scalar Immobiliser Delete Flag from 0 to 1 in the Scalars tab by hand.

Dual Map Switching Patches

Using MEMS Mapper EU2, Rover MEMS 2J and Land Rover TD5 MSB ECUs can now be configured to switch between two separate maps. The switching can be live with the engine running, even under load. The engine will not even cough or hesitate when switching.

Select Tools | ECU Tools | Install Map Switch Patch from the menu, the select which available input pin you want to use.

Different ECUs and different cars use different inputs, so a different selection of inputs may be available on each car. Choose an input pin which does not have a wire connected to it on your ECU. For help with identifying the relevant pins and how to wire a switch to each one, select Connector Pinouts, Wiring Diagrams & Installation Instructions from the menu as shown above. The help information is also available through the following links:

On ECUs which contains two native maps from the factory, the map switch patch will switch between them. On ECUs which contain only a single native map, the map switch patch will install a second alternate map. To switch between the two maps in a project with more than one map (natively, or through the installation of a map switch patch), select Tools | Project Tools | Switch Maps or press Ctrl-P.

Boot Loader Technical Details

The following information is for those who are interested to read the technical details. You don’t need to know or understand any of this to use the tool, it’s just background information.

The key to adding a boot loader to the ECU was to rearrange the memory map in such a way that ECU would boot straight into the boot loader code, which could then hand over to the firmware code when it needed to do so, without requiring wholesale modifications to the firmware code. This meant that the firmware code could not be relocated. But the first 1024 bytes of the firmware consist of a vector table, which contains the addresses of all of the firmwares exception and interrupt handlers. The first two entries in the vector table hold the initial stack pointer and the initial program counter (address of the main entry point to the firmware program). The ECU boots after a reset with System Integration Module register values such that the ROM chip is mounted at address $000000 and it reads the initial SP and PC from there, so I needed to be able to place my own vectors there to force the ECU to boot into the boot loader.

When booting up, one of the first jobs the firmware normally does is to remount the ROM from address $000000 to address $100000. This allows it to place RAM at $0000, which allows RAM to be addressed with word addressing mode which makes the firmware code more compact and efficient. In doing so, it needs to tell the processor that the vector table has moved. It does this by settings a Vector base Register (VBR) to the new address of the vector table at $100000. All access to the vector table is for interrupt and exception handler addresses is then done relative to the address in VBR. The VBR is only ever assigned once during the firmware startup process. By patching that one instruction, I could move the firmware vector table to a new address and point the VBR to it and the firmware would run completely normally, oblivious to the change. I was then able to place the vector table for the boot loader in the original location. That contained the correct initial SP and PC for the boot loader.

This required that the boundary between the boot loader vectors and the firmware code at $100400 was a sector boundary of the EEPROM chip in order to allow the firmware to be erased without touching the boot loader. Luckily the AT29C1024 has 256-byte sectors and every multiple of $100 is a sector boundary, so the boot loader vectors occupy the first 4 sectors exactly.

At the very top end of the ROM address space, in an area that is always unused in all stock EU2 ECUs (the ROM chips are larger than the firmware and maps combined, even when two maps plus NOSELECT are present), I then allocated 6kB to the boot loader code at $11E800-$11FFFF.

Immediately before this at $11E400-$11E7FF I placed the relocated firmware vector table.

This left the largest possible single block of contiguous free space between the end of the NOSELECT map and the start of the firmware vector for use by custom patches. It meant that the ROM sectors allocated to firmware formed one contiguous block from $100400-$11E800 and this could be erased without touching either of the boot loader areas which consisted of the sectors $100000-$$1003FF (vectors) and $11E800-$11FFFF (code).

When MEMS Mapper EU2 detects that a project has been patched for compatibility with the boot loader, it blocks out the boot loader address ranges and does not write them to the ECU. Furthermore, it insists that they contain only $FF bytes before allowing the project to be written to the ECU (see Checksum Technical Details below). When reading an ECU, MEMS Mapper EU2 checks on completion whether the project has been patched for compatibility with the boot loader and if so, it discards the data read in the boot loader address ranges.

I had previously developed a full background, interrupt-driven communications system in 68000 assembly language for use in custom RAM agents on MEMS3. Because code size was critical in this application due to available RAM limitations, this was not fully ISO14230 compliant. For the boot loader I really needed a communications suite that would support a subset of the ISO14230 message set, but it needed to support those messages and behave in all other ways identically to the firmware implementation of ISO14230. This would allow MEMS Mapper EU2 to communicate with an ECU without having to know in advance whether it was running firmware or just the boot loader. It would also allow the ECU to switch seamlessly between the firmware and the boot loader when a Programming diagnostic session was requested with no change in communications protocol required. So, I upgraded my existing library to allow it to be assembled with an ISO_COMPATIBLE directive. When this directive was not specified, the library behaved as before and was compatible with the existing RAM agents and other existing use cases. When this directive was specified, the following main changes were implemented:

With these changes, the custom communications library in the boot loader in ISO mode appeared identical to the firmware when in communication with MEMS Mapper EU2. However, only the subset of the standard ISO messages required to support the boot loader function were then implemented in the boot loader code alongside some custom messages as described in the table below:

Ident

Service

Status

Description

Comments

SVC_DIAGNOSTIC_SESSION_CONTROL

$10

ISO14230

Used to start General (Firmware) or Programming (Boot Loader) diagnostic sessions.

The firmware is patched such that requesting a Programming session using this service resets the ECU into the boot loader which then sends the message response.

SVC_ECU_RESET

$11

ISO14230

Use to reset the ECU.

 

SVC_READ_ECU_IDENTIFICATION

$1A

ISO14230

Used to read the part ECU part number.

The firmware implementation provides for additional identification information but the boot loader only needs to support the part number.

SVC_READ_DATA_BY_LOCAL_IDENTIFIER

$21

ISO14230

Used to read one of a defined set of live data records from the ECU.

The boot loader only implements specific fields within a subset of the records as required. It returns the Firmware ID (16-byte format) field in record $0E, the Firmware ID (8-byte format) and Main Map ID in record $32 and the Boot ID in record $33.

SVC_READ_MEMORY_BY_ADDRESS

$23

ISO14230

Used to read a block of memory from the ECU.

 

SVC_SECURITY_ACCESS

$27

ISO14230

Used to implement a seed-key security access algorithm.

The boot loader does not actually require seed-key security, but needs to handle the messages for compatibility as the firmware does require it. The boot loader always replies with $0000 “already authorised or authorisation not required”.

SVC_REQUEST_DOWNLOAD

$34

ISO14230

Used to request to write a block of memory to the ECU.

 

SVC_TRANSFER_DATA

$36

ISO14230

Used to transfer data when writing to the ECU.

 

SVC_REQUEST_TRANSFER_EXIT

$37

ISO14230

Used to end a transfer of data when writing to the ECU.

 

SVC_CUSTOM_ERASE_FIRMWARE

$91

CUSTOM

Used to erase the firmware.

Routines such as this would normally be implements with service $31 SVC_START_ROUTINE_BY_LOCAL_ID. This would however require extensive firmware patching so separate custom messages are used instead.

SVC_CUSTOM_ERASE_SERIAL

$93

CUSTOM

Used to erase the serial EEPROM.

As above.

SVC_CUSTOM_PROTECT_SERIAL

$94

CUSTOM

Used to restore write protection of the serial EEPROM after writing.

As above.

SVC_CUSTOM_READ_SERIAL

$95

CUSTOM

Used to read data from the serial EEPROM.

As above.

SVC_CUSTOM_WRITE_SERIAL

$96

CUSTOM

Used to write data to the serial EEPROM.

As above.

SVC_CUSTOM_APPLY_VERIFICATIONS

$97

CUSTOM

Used to request that the ECU internally verifies the checksums after writing and applies the verification word if correct.

As above.

SVC_CUSTOM_UPDATE_BOOT

$98

CUSTOM

Used to trigger the internal process of updating the boot loader once the new boot loader has been written to the firmware areas and verified.

As above.

SVC_CUSTOM_READ_ENCRYPTION_KEY

$A2

CUSTOM

Used to read the encryption key from the ECU.

As above.

 

Checksum Technical Details

The ECU’s internal firmware code calculates checksums over the entire ROM space from $100000-$11FFFF. MEMS Mapper EU2 does not process the areas allocated to the boot loader but needs to be able to verify the checksum. It needs to be able to process the checksum for the firmware independent of the contents of the boot loader areas which it is not aware of. The conflict can be resolved if the checksum for the boot loader areas alone is always arranged to be the same as the checksum of the same space filled with $FF bytes. In this case, MEMS Mapper EU2 can calculate the checksum of the whole ROM with no boot loader and the ECU can calculate the checksum of the whole ROM with a boot loader and the answers will agree. When producing new versions of the custom boot loader files, the release process I have developed corrects the checksum of the boot loader areas to ensure that the above condition is always satisfied.

Firmware Patch Technical Details

When writing to an ECU, MEMS Mapper EU2 will check whether the patched for compatibility with the boot loader have already been applied (in the case of a project read from a modified remappable ECU, or after selecting Tools| Wizards | (Firmware) Boot Loader Compatibility from the menu). If not, it will apply the patches automatically. The following changes are patched onto a stock firmware:

Rover MEMS 2J ECUs take a rather dirty approach:

        0000070c 20 7c 00        movea.l    #0x10071a,A0          ; Sets up the address of the first instruction to be executed after the

                 10 07 1a                                         ;   after the ROM is relocated, using its NEW address, in register A0.

        00000712 31 fc 10        move.w     #0x1005,(CSBARBT).w   ; Set CSBARBT (Chip Select Base Address Register Boot ROM) to relocate

                 05 fa 48                                         ;   the ROM to $100000.


        00000718 4e d0           jmp        (A0)                  ; This instruction no longer exists at this address! But it is a single

                                                                  ;   word instruction and this relies on the bus prefetch; the CPU will

                                                                  ;   have ready this instruction ahead of time and still executes it.

                                                                  ;   This jumps to the next instruction at the NEW address to continue.


        0010071a 31 fc 00        move.w     #0x0,(TRAMBAR).w      ; This is the first instruction executed at the NEW address.

                 00 fb 04

This is quite a nasty trick but it seems to work. It relies on the fact that the CPU32 core will already have executed the next bus cycled and pre-fetched the next pipeline instruction when it executes the CSBARBT assignment to relocate the ROM. So even though the jmp (a0) will no longer be there at address $000718 (it will have been relocated to $100718), the CPU will not notice and it will still be executed correctly. This instruction is a jump to the next instruction at reh relocated address $10071A and execution then continues normally from this point.

Land Rover Td5 MSB ECUs take a much cleaner if slightly more long-winded approach:

        00100458 70 07           moveq      #0x7,D0               ; Number of words in subroutine in ROM.

        0010045a 20 7c 00        movea.l    #0x300000,A0          ; Address of location in RAM.

                 30 00 00

        00100460 22 7c 00        movea.l    #0x55c,A1             ; Address of subroutine in ROM.

                 00 05 5c

                             LAB_00100466

        00100466 30 d9           move.w     (A1),(A0)             ; Copy subroutine from ROM to location in RAM.

        00100468 51 c8 ff fc     dbf        D0w,LAB_00100466


        0010046c 4e b9 00        jsr        SUB_00300000.l        ; Execute subroutine in RAM.

                 30 00 00

Then later on, this is the subroutine in ROM which gets copied to RAM and executed:

        0010055c 06 97 00        addi.l     #0x100000,(SP)        ; Adjust the return address on the stack by $100000 to allow for the ROM moving.

                 10 00 00

        00100562 31 fc 10        move.w     #0x1004,(CSBARBT).w   ; Set CSBARBT (Chip Select Base Address Register Boot ROM) to relocate

                 05 fa 48                                         ;   the ROM to $100000.


        00100568 4e 75           rts                              ; Return to the adjusted return address in ROM (at the NEW address).

This ensures that the CPU is executing code in RAM as the ROM is relocated. This does not require any cache prefetch tricks.

While the FIRST method is completely compatible with the boot loader, the second method is unfortunately not. In order for the boot loader to execute correctly, it also needs to remount the ROM chip when it starts up. The registers used to control the ROM base address can only be written to ONCE after the CPU resets, so it is critical that the boot loader initialised them exactly as the firmware will want them, as the firmware will be unable to relocate the ROM again when it starts. So, by the time this firmware startup code executes under the boot loader, the ROM is already located at $100000 instead of $000000. But the subroutine executed in RAM makes the assumption that the ROM base address will change by exactly $100000 and adds this offset to the return address on the stack. This will not work if the ROM does not in fact move.

In reality, under the boot loader, this whole piece of code is not required and so the RAM subroutine call is patched out.