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:
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.