If you’ve followed the last few posts, you’ll have noticed they all circle the same idea. Reading the EEPROM, pulling apart the boost maps, working out how the ECU decides which tune to run. Every one of those is about the same thing underneath: changing the numbers Bosch already put in the firmware.
And you can get a long way doing exactly that. More boost, more timing, more fuel. It’s all in there as tables, and if you know where to look and what you’re doing, you can rewrite them. That’s what a remap is.
But there’s a ceiling to it. You can only change values that already exist. If the factory never programmed a particular behaviour, there’s no table to edit and no number to turn up. You’re redecorating the house Bosch built. You can’t add a room.
This post is about adding a room.
Editing tables vs. writing code
The FLASH inside the MEG1.1 isn’t just a pile of tables. It’s a full program, the actual machine code that runs the engine and the gearbox, makes every decision and reads every sensor. The tables are the data that program reads. A remap changes the data. It leaves the program itself completely untouched.
To go further, you have to get inside the program and change what it does, not just the numbers it reads. That means reading the raw machine code the processor runs, understanding it, and then writing your own code to sit alongside it. That’s a very different job to remapping.
None of this is new (except where it is)
I want to be straight about something before I go on, because it matters.
Injecting custom code into a Bosch ECU is not something I’ve invented. On the popular platforms it’s very well-trodden ground, and people have been doing it for years. The results out there are genuinely impressive: selectable launch control RPM you dial in with the traction control button, flat-foot shifting, anti-lag, custom gauge outputs, all sorts. Whole communities exist around the more common ECUs, with mature tools and shared knowledge, and if you drive something popular you can more or less buy this stuff off the shelf.
The MEG1.1 is not one of those ECUs.
As I’ve said on here before, it only ever went in the Roadster and the 450 Fortwo, so almost none of that work has been done. There’s no community picking it apart, no shared definitions, no off-the-shelf custom code. The techniques are well understood in general. Nobody has applied them to this particular ECU. That’s the gap I’ve been working in, and it means starting from a blank sheet.
You don’t get handed the keys
Here’s the part people underestimate.
When you load the firmware into a disassembler, you don’t get source code back. You get a reconstruction, and a rough one. Every function comes out with a name like FUN_0741ea. Every variable is something like DAT_00f9e4. There are no comments, no labels, no structure, nothing telling you what any of it is for. Bosch’s engineers had all of that when they wrote it. You get none of it. You get half a megabyte of logic with the names filed off.
So the real work isn’t running the tool. It’s interpreting what comes out, and there’s an enormous amount of it. You work out what a routine does by what it touches: which sensors it reads, which values it writes, what it does with them, and which other routines call it. You build the picture one function at a time, by hand.
And the C166 makes you fight for it. The chip uses memory paging, which means the same physical location can appear at a completely different address in the listing depending on which memory page the code assumed at the time. Two labels that look totally unrelated turn out to be the same map, and you only realise it once you understand the paging well enough to see through it. Get that wrong and you’ll chase your tail for hours convinced a routine is reading something it isn’t.
It gets worse. A lot of the maps aren’t read directly at all. Bosch passes them through a single generic interpolation routine that gets handed a little descriptor, basically a note saying “here’s the map, here’s its RPM axis, here’s its load axis.” Because the map is never read by a direct memory access, it never shows up as a label anywhere in the listing. You can search the entire disassembly for it and find nothing. To pin it down you have to find the interpolator, find the descriptors being fed into it, and work backwards to figure out which map is which.
The one lifeline in all of this is the calibration side. Years of earlier work went into the XDF and the translated definitions, so I know a lot of parameters by name, address and value from that side of the fence. If I can find where the code reads one of those known addresses, I can use it to work out what the surrounding routine is actually for. You triangulate the code against the calibration until the picture comes together.
Even then you get it wrong. Plenty of times I’ve convinced myself a routine does one thing, written it up, and then found evidence later that said the opposite and had to throw the theory out and start again. That’s just the job. Anyone who tells you they read one of these things like a book is having you on.
Code caves: room to work
Once you can actually read the thing, a very useful fact falls out of it.
The 512KB of FLASH isn’t full. There are regions of the chip Bosch never used, blank erased space just sitting there. In reverse-engineering circles these get called code caves: unused pockets of memory where you can tuck your own routines without disturbing a single byte of the factory code.
The trick is getting the ECU to actually run what you put there. The way that works is a detour. You find a spot in the factory code, redirect it to jump into your custom routine in the cave, let your code do its thing, and then hand control back so the original code carries on none the wiser. Done properly, the car behaves exactly as standard everywhere except the one place you’ve chosen to change, and does something completely new at that one place.
Once you can do that, you’re no longer limited to what Bosch programmed.
What I’m working towards: launch control
The clearest example, and the one I’ve put the most time into, is a proper launch control.
Anyone who’s driven a Roadster off the line knows the automated clutch does its own gentle thing and there’s not much you can do about it. There’s no factory launch mode. You can’t hold the car on the brake, build boost, and drop it. The ECU simply won’t let you.
Except it almost will.
Buried in the firmware is dormant scaffolding for a feature Bosch called race start. It’s genuinely in the code. There’s even a calibration value named APWRS, which decodes to “race-start accelerator pedal threshold,” alongside a launch RPM target and a launch clutch parameter. The machinery is there. It’s just not wired up to anything you can reach from the driver’s seat, and the factory logic around it means it never actually fires in normal use.
So the job is to take Bosch’s own dormant race-start machinery and use custom code to arm it the way a launch control should work. The behaviour I’m aiming for is the obvious one:
- Hold the brake, select first, and floor the throttle.
- The clutch stays open and the engine climbs to a set RPM and holds there, sitting ready.
- Lift off the brake and the clutch engages hard, and you’re gone.
The RPM it holds at and how aggressively the clutch bites would both be adjustable, and because the arming is driven off the brake, ordinary driving stays completely standard. The car runs the factory code byte-for-byte until the exact moment you ask it not to.
Now the honest part, because I don’t do it any other way on this blog. This is not finished. It’s a work in progress. The design is done and the code is written, but I do not have a clean, proven, working result in the car yet. The ECU has factory interventions that actively work against holding the car on the brake against the throttle, and it has misfire and monitoring logic that has to be handled or the car throws itself into a fault. Wrestling all of that into line is exactly where the effort is going right now. When I’ve got it working properly and repeatably, you’ll read about it here first.
And one caution regardless of how well it ends up working. Holding an engine on the limiter with an ignition cut is hard on a catalytic converter. It’s a competition tool, not something for a road car with a cat you care about. This is development and track territory and I treat it that way.
Where else this goes
Launch control is the headline because it’s easy to feel, but it’s really just one use of the underlying capability. Once you can run your own code on the MEG, a lot of doors open.
One I’ve been working on is talking to the ECU over CAN, feeding a live RPM signal into the running MEG over the bus. It’s useful when the MEG is sharing duties with a standalone and the two need to agree on what the engine’s actually doing. Like the launch control, it’s still on the bench rather than signed off, but it’s promising.
Another long-term project is getting the MEG to run the engine completely standalone, with no piggyback and no second ECU. That means understanding how it works out load from the pressure sensor and opening that path up for more boost than the factory sensor can even measure. That work is very much in progress, and I’ll be honest, there are parts of the load path I’m still tracing through the decompile. More on that when I’m sure of it rather than when I’m guessing.
And then there’s the gearbox. Regular readers know this is the white whale. The gearbox is run by the same firmware, and being able to change how it behaves rather than just what values it uses is a big part of why I started down this road in the first place.
The honest bit
None of this is a product you download and flash. It’s bespoke, per-car, still-being-developed work, and some of it is at the frontier of what’s known about this ECU. I’m sharing the what, and how it works, because I think it’s genuinely interesting and because I’d rather the Roadster community understood what these little ECUs are actually capable of. The exact how, the addresses and the code and the patches, is the part that’s taken years, and that stays between me and the cars I do it on.
If any of this is useful to you, or you’ve been poking at the MEG yourself and found something I haven’t, get in touch. The more of us who understand these things, the better off every Roadster on the road is.
As always, big thanks to Mike Bailey at 223D Developmental, whose Brabus has done more than its fair share of test-mule duty, and to Andrew at Smart Automotive for pushing this along with me.
More to follow…
Tom South Australia WhatsApp: +61 401 723 903
4 responses to “The Next Step: Custom Code”
Hi! Could you please tell me if you have any information about the chip used in the ECU? I mean, which SoC is used — is it the Infineon C167CR-LM?
Unfortunately, my original ECU has some minor mechanical damage caused by an improper repair by the previous owner, and the chip’s marking is difficult to read, so I’m unable to identify it
LikeLike
The chip is an infineon SAK-C167CR-LM.
Easiest way to repair these is to just get another donor one off eBay (all MEG1.1 are the same) then swap the eeprom chip and reflash the flash with the appropriate map
LikeLike
Also, do you have any information about the firmware architecture? Specifically, I’m interested in whether there are any assumptions or clues regarding the RTOS being used.
Since this ECU was released around the time AUTOSAR was being introduced, and considering the software development cycle, I’m inclined to assume that it was actually developed in the pre-AUTOSAR era. Therefore, it’s also possible that the firmware runs directly on bare metal, although I consider that highly unlikely
LikeLike
What’s here is static allocation with the C167’s interrupt controller doing the arbitration in hardware, 16 priority levels and 4 group levels, no software scheduler required.
Reset is similarly bare: set the Context Pointer, call an init routine, reti. No OS startup, no task table.
The evidence leans toward bare metal, or at most a very thin cyclic dispatcher driven by a timer interrupt.
LikeLike