Reverse Engineering ME7.4.4 as a stand alone ECU

Bosch Motronic etc ECUs and PCMs
BennVenn
Posts: 492
Joined: Fri Mar 04, 2016 10:35 am
cars: R33 GTST, '60 Vw Bug, Express (4G63T), GW X200
Location: Windellama, NSW
Contact:

Reverse Engineering ME7.4.4 as a stand alone ECU

Post by BennVenn »

The ME7.4.4 is a 19yr old Bosch ECU controlled by a C167 MCU @ 24mhz. It is 16-bit, has 24bit address space, built in single cycle hardware division and multiplication.

The ECU contains 512kbytes of Flash ROM, 32kbytes of SRAM, 2kbyte SPI EEPROM, a few kbytes of internal SRAM, a whole bunch of timers/counters, can controllers, Serial ports and other peripherals targeted towards engine management.

They were found in Peugeot's and Citroen's but more importantly, there are hundreds if not thousands stockpiled in China available from USD$35 shipped, with second hand units found on ebay for around $25. ECU connectors with 30cm pigtails are also available new on aliexpress for ~$50 shipped. The seller is happy to provide any length loom attached to the plugs. This is the same ECU found in holden Barina's except they are not hybrid ceramic and instead are built on a real PCB without all the silicone goo inside.

Internally the ECU contains:

2 ignition coil drivers (for a 4cyl wasted spark application). There are other variants of ME7.4 that are almost identical internally with a 3rd or 4th coil driver for 6/8cyl engines. You can also use the logic level outputs to drive 'smart' coils.
The coil drivers have camshaft phase detection which can detect which of the wasted spark side is under compression and which is on the exhaust stroke eliminating the need of a cam sensor.
2 Variable reluctance channels (ME7 firmware uses a 60+2 crank trigger)
Injector driver IC (4 channel, plus a bunch of low side high current drivers)
H-bridge driver (for drive by wire throttle bodies, IAC etc, with extra low side current drivers)
CANbus driver IC
K-line serial comms
A proprietary Bosch ASIC containing a fully programmable Knock Detection IC with adjustable center freq, bandwidth, gain, window angle, integrator etc, and 16ADC channels.

The plan is to reverse engineer the ECU enough to get custom code running and eventually speed density with real time tuning.

Communicating to the ECU: A K-tag can be used to read/write the Flash, EEPROM and read out the internal boot rom. I've coded up a small program to make use of the C167's bootloader mode which can read/erase/write the 512kbyte Flash, but also execute code directly out of RAM. This is using a cheap $10 VAG-KKL K-line obd2 reader. You could solder directly to TTL serial TX and RX test pads on the PCB and achieve the same for ~$3.

Toolchains: IDA pro can decompile the stock ROM(s), Keil C166 can compile C or ASM to run on these ECU's. Datasheets are available for the C167 and the only current unknown is the 30380 ASIC (Knock + ADC IC) which I'm part way through reverse engineering.

There are no schematics for the ECU, no datasheets for any of the custom Bosch IC's though they're not needed for spark/injector control. Only for the ADC / Knock IC.

If there's any interest in this I'll keep the thread updated with any progress. I've currently got the logic analyser connected up to the 30380 to try capture some traffic to see how init and ADC reads are done. So far no luck so I'm going back to IDApro to find the functions involved. An interrupt line is connected directly between the two and I've found the Interrupt handler which reads and writes to the 30380 but so far no Init or ADC code. I believe this function is purely Knock detection.
User avatar
Gareth
Posts: 2540
Joined: Fri Mar 14, 2014 8:37 pm
Location: Bacchus Marsh, Vic

Re: Reverse Engineering ME7.4.4 as a stand alone ECU

Post by Gareth »

Will be watching with interest :thumbup:
According to chemistry, alcohol is a solution...
BennVenn
Posts: 492
Joined: Fri Mar 04, 2016 10:35 am
cars: R33 GTST, '60 Vw Bug, Express (4G63T), GW X200
Location: Windellama, NSW
Contact:

Re: Reverse Engineering ME7.4.4 as a stand alone ECU

Post by BennVenn »

attached are two pics, the 0ohm jumper resistor sets the boot mode. As shown it'll boot from the internal MaskROM (can be used but not ideal). Moving the resistor down to the pads below it will tell the CPU to boot from the 512kbyte external Flash (Much more convenient)

The other pic is showing the bootstrap pin. When this is logic 0v at system power up or after a reset signal is asserted, the CPU will jump to its internal boostrap code. This pin is shared with the Flash data line so best not to short it to ground, rather a 1k resistor to gnd will do the trick.

The bootstrap code works roughly like this:

It listens for the PC to send a 0x00 byte (at any baud, 8n1). Once it receives the bit it configures its serial port to match the PC's baud and will send back 0xC5 (MCU ID). It'll then wait for exactly 32 bytes of data over the serial port, storing it at location 0xFA60. Once 32 bytes are received it will jump to 0xFA60 and execute the code.

The first 32 bytes I send is a secondary bootloader which will transfer a larger payload into RAM and jump to that. This second payload I've coded in some basic memory read/write/flash erase/flash write commands. You can do all this through a serial terminal but a small C app i've coded makes it faster and automated. My C code will then erase the Flash and write a file called Stage3.bin into flash from 0x000000. The ECU will then boot your code from Flash at the next power cycle or reset signal.
Attachments
InkedBootROMJumper_LI.jpg
InkedBootPin_LI.jpg
BennVenn
Posts: 492
Joined: Fri Mar 04, 2016 10:35 am
cars: R33 GTST, '60 Vw Bug, Express (4G63T), GW X200
Location: Windellama, NSW
Contact:

Re: Reverse Engineering ME7.4.4 as a stand alone ECU

Post by BennVenn »

A little more progress. I found some similar ECU schematics, most of the routing appears to be the same across the ME7 C167 ECU's which is nice.

I've got some code running on the Flash now however once we release the external CPU reset (the CPU can generate its own reset output for peripheral devices), the Knock IC issues a system reset approx 100mS later. I guess there's a watchdog in there too.

I've captured 5 seconds of data to the knock IC and decoded the first 500mS or so which should include the watchdog reset. Here's what I've found:

There are regular writes at address 0x38, 0x3E and 0x44 with bytes 0xE0, 0x0F, 0x09 every few mS which could be a request for ADC sampling or maybe the watchdog servicing, maybe both. I'll write some code to replicate this and try identify exactly what is what.

Also, Flash CE is connected to A19 which means the flash is always active on the lower 512kbytes of every consecutive megabyte. This is likely so the flash is available before the BUSCON and ADDRESS registers are configured. This also means we need to map the SRAM into an upper 512kbyte region somewhere in the 16mbyte address space. SRAM /CE is tied to CPU /CE1. The Knock ASIC is tied to CPU /CE2. Both the Knock IC and the SRAM need to be mapped where the Flash isn't.

A bit about mapping on the C167: it's pretty flexible with 5 /CS channels, each can be assigned a memory address and range, 8bit or 16bit, multiplexed or demultiplexed. So you could put external memory into any address space you like - except for what they've done with the Flash CS pin (I've found there is a resistor jumper just like the bootmode jumper so you can change from A19, to /CS0 - pretty neat!)

Packet 1:
W:02:00
W:26:4A
W:2A:FF
W:2B:FF

Packet2:
R:22:FF

Packet3:
W:30:00
W:32:04

Packet4:
W:34:04

Packet5:
W:3A:C0
W:38:E0
W:40:0F
W:3F:0F
W:46:0F
W:44:0F
W:30:00
W:32:00
W:34:20
R:59:FF
R:58:F0
W:64:00
W:5E:04
R:5A:C0
W:54:01
W:55:00
W:56:00
W:52:02

Packet6:
W:38:E0
R:3C:C0
W:3E:0F
R:42:0F
W:44:0F
R:48:0F
R:22:FF

Packet7:
W:34:24

Packet8:
R:22:FF

Packet9:
W:38:E0
R:3C:C0
W:3E:0F
R:42:0F
W:44:0F
R:48:0F

Packet10:
W:3A:C0
W:38:E0
W:40:09
W:3E:0F
W:46:09
W:44:09
R:5A:40
W:60:08

Packet11:
R:22:FF

Packet12:
W:38:E0
R:3C:C0
W:3E:0F
R:42:09
W:44:09
R:48:09

Packet13:
W:3A:C0
W:38:E0
W:40:09
W:3E:0F
W46:09
W:44:09
R:5A:00
Attachments
ME75 (1).ZIP
(6.57 MiB) Downloaded 173 times
KnockAsic.JPG
BennVenn
Posts: 492
Joined: Fri Mar 04, 2016 10:35 am
cars: R33 GTST, '60 Vw Bug, Express (4G63T), GW X200
Location: Windellama, NSW
Contact:

Re: Reverse Engineering ME7.4.4 as a stand alone ECU

Post by BennVenn »

The ASIC wasn't responsible directly for the reset loop...

There's a small 16pin IC, turns out its a 68hc05 MCU. It expects a constant stream of pulses from the main CPU. These pulses vary in width and are generated by a pseudo random number generator coded into the C167 CPU. The seed is always the same at reset so you could capture a long series of pulse widths to recreate the stream, or recreate the PRNG in code. If any of these pulse widths are incorrect, it'll reset the ECU. We've already got a watchdog timer inside the C167 so I'm probably going to disable this for now and revisit the external watchdog later. To disable, lift Pin1 and tie to ground. This is the 68hc05's reset pin and holding this low will float all outputs with a weak pull-up, and keep the system from resetting.

My code is now growing in size so I spent a little time optimizing my flash uploader code. It's still limited by 19200bps serial but 2kbytes is taking about a second. I should probably set up the CANbus registers and use that for high speed flash uploading. It's still a rather slow Flash IC so probably not required just yet.
BennVenn
Posts: 492
Joined: Fri Mar 04, 2016 10:35 am
cars: R33 GTST, '60 Vw Bug, Express (4G63T), GW X200
Location: Windellama, NSW
Contact:

Re: Reverse Engineering ME7.4.4 as a stand alone ECU

Post by BennVenn »

Reverse engineering the security module...

There is a small 16pin MCU attached to the ASIC but also generating an IO enable signal for the Hbridge and coil drivers. It is this IC that issues a reset request to the ASIC, which then issues a System Reset signal resetting the ECU. It does this 100ms after a response to its challenge isn't received. If an invalid response is received, it will instantly issue a reset. This was a fun one to crack!

It works like this:

The CPU and the security IC (I'll call a watchdog) is connected by a single data line (Port 2.5). It is connected as open collector with a weak pull up so both watchdog and CPU can pull the line low.

It is the low pulse duration that contains the challenge and response. The high pulse width is simply 20mS minus pulsewidth, maintaining a 50hz data rate.

The protocol works like this:

CPU-Init1, WDT_Query1, CPU-Init2, WDT_Query2, CPU-Response1, WDT_Query3, CPU-Response2, WDT_Query4, CPU_Response3 etc....

It continues indefinitely. The Queries are 1 of 16 unique pulse widths. The responses are paired to the query. Every 16th response must be invalid as an extra bit of comfort that the CPU is still executing code correctly. A correct response on the 16th query will = an incorrect response. Internally to the WDT there is a counter of correct responses. It maxes out at 8. If you issue the wrong response, it will decrement the counter and ask the same query. So you get up to 8 wrong replies before a full system reset, or reply correctly to the 16th query 8 times and a reset.

There is a fairly large window of what is accepted as a pulsewidth. 0.2mS or so variation is OK it seems.

CPU-Init1 pulse width = 4.81484mS
CPU-Init2 pulse width = 5.68516mS

The responses to the 16 challenges are as follows:

//calculate the appropriate response to the WDT's query
//8.44534mS > 7.7576
// 8.86936 >> 5.99528
// 4.22638 >> 8.15802
// 4.74308 >> 6.65572
// 6.9078 >> 4.29354
// 9.30801 >> 4.55406
// 6.56086 >> 4.81456
// 8.03452 >> 5.68488
// 6.2243 >> 7.0065
// 5.01306 >> 5.38508
// 5.5979 >> 8.56748
// 4.48566 >> 5.0945
// 7.26654 >> 6.31584
// 5.29926 >> 8.99806
// 5.902 >> 9.4388
// 7.6425 >> 7.37702
ResponseCounter++;
if (ResponseCounter==16){ //we need to send a bad response every 16th to keep it happy
ResponseCounter=0;
WDTResponse=7.208mS;
}

I'm using CC5 and T2 and this code is all running in interrupt driven functions so there is no main code intervention needed. Interrupt priority can be low.

We're now no longer stuck in a reset loop, and we can enable IO drivers.

Next up the ASIC.
BennVenn
Posts: 492
Joined: Fri Mar 04, 2016 10:35 am
cars: R33 GTST, '60 Vw Bug, Express (4G63T), GW X200
Location: Windellama, NSW
Contact:

Re: Reverse Engineering ME7.4.4 as a stand alone ECU

Post by BennVenn »

The ASIC wasn't as big of a problem as I thought - Although it does have 16ADC channels, ~24 IO channels, almost none of them are used and are all tied to gnd or vcc. All the ASIC appears to do is control the system Reset signal, and the knock detection. Simulating crank and other sensors on the bench, the CPU issues the knock window on an IO pin and reads the knock value from a register. There is also an IO signal from the ASIC to the CPU when the knock surpasses a configurable threshold so its more or less set and forget until it detects knock. You set the bandpass / filter and all that stuff during the init and that's about it. I'll need to look more into this init code to see what does what.

I've written a bit of code to send the ADC channels back over serial to see what is what. Here's what I've found so far:

/*
adc channel 0 = MAP / MAF (0-5v)
adc channel 1 = Throttle Blade Position 1 (0-5v)
adc channel 2 =
adc channel 3 = Throttle Blade Position 2 (0-5v)
adc channel 4 =
adc channel 5 = Battery Voltage [0...17V], 1Inc = 0.067V
adc channel 6 = Upstream O2 sensor (0-2v approx)
adc channel 7 = Downstream O2 sensor (0-2v approx)
adc channel 8 = Pedal input 1 (0-5v)
adc channel 9 = Pedal input 2(0-5v)
adc channel 10 = Coolant Temp (Resistive)
adc channel 11 =
adc channel 12 =
adc channel 13 = Intake Air Temp (Resistive)
adc channel 14 =
adc channel 15 =

*/

These are all the analog signals that are on the peugeot / Citroen wiring diagram. There are more ADC channels that are sampling pins on the ecu connector so we have more ADC's for wideband, oil pressure, coolant pressure etc. We've also got outputs for drive-by-wire, wastegate actuator solenoids, intake runner flaps, VVT( though no secondary VR input for a VVT pid loop, we do have an extra hall input signal intended for vehicle speed) We also have canbus hardware in the ECU we could use to read/control other actuators, dash clusters etc.

I've coded up the main ECU framework, all interrupt driven so it takes very little CPU processing in the main thread. So far we have:

- security module communications complete
- all ADC channels auto updated in an array ready for use
- Injector code finished, just call the injector you want to fire with a pulsewidth and it'll fire for the duration you've requested.
- Spark code finished, same as injector firing, call the function with dwell and it'll do the rest.
- Basic Serial handling finished.

to do - write some trigger wheel decoding code, calculate angles and set up timers to trigger coils and injectors at requested angles. Once that is done, the rest is fuel and spark calculation based on lookup tables. Simple stuff.

I'll upload my code to github for anyone else wanting to play around with these ecu's.
User avatar
antus
Site Admin
Posts: 8497
Joined: Sat Feb 28, 2009 8:34 pm
cars: TX Gemini 2L Twincam
TX Gemini SR20 18psi
Datsun 1200 Ute
Subaru Blitzen '06 EZ30 4th gen, 3.0R Spec B
Contact:

Re: Reverse Engineering ME7.4.4 as a stand alone ECU

Post by antus »

Good work. Nothing to add, but watching with interest :thumbup:
Have you read the FAQ? For lots of information and links to significant threads see here: http://pcmhacking.net/forums/viewtopic.php?f=7&t=1396
BennVenn
Posts: 492
Joined: Fri Mar 04, 2016 10:35 am
cars: R33 GTST, '60 Vw Bug, Express (4G63T), GW X200
Location: Windellama, NSW
Contact:

Re: Reverse Engineering ME7.4.4 as a stand alone ECU

Post by BennVenn »

4mSdwell_183deg.png
A little more work, trigger wheel decoding added. It's fairly configurable, you can set the tooth count, missing teeth, and degrees per teeth and it'll work out the rest.

Ign and inj timing is tested too, attached is the coil firing for the requested 4mS dwell at 183deg btdc. I'll need to code up a function which converts dwell duration to angle so the end of the ign event lands exactly on 183deg. I'll probably use two separate timer channels, one to trigger the dwell and one to fire the coil incase the engine is increasing or decreasing RPM during the cycle.

I've decided on 0.5degree timing resolution. The limitation is at higher RPM (7000+), and the timers resolution. Right now at 10,000RPM we're off by 1/4 of a degree vs requested which is acceptable. If you're never running it up that high, you can change a variable which sets the resolution and run down to 0.1deg resolution. Given there is very little performance difference in a degree of timing, 0.5 is where I'll keep it.

I've also started on 2d and 3d interpolation and it's converting GM style MAP sensor ADC values into KPa using lookup tables.

ClaudeAI has helped me code much of this and while Claude isn't perfect, its sooooo far ahead of the others. He has a very good understanding of ECU's, the C167 MCU, C and ASM. You can upload files to him so I sent him a 10min logic analyser capture of the Watchdog protocol and with a few hours of back and forward we got to the bottom of it. Being able to parse millions of data points in seconds saved me what could have been weeks to work out. He can also disassemble binaires and tell you what unknown functions do, to a fairly good degree. Definitely recommended if you're working on reverse engineering!
BennVenn
Posts: 492
Joined: Fri Mar 04, 2016 10:35 am
cars: R33 GTST, '60 Vw Bug, Express (4G63T), GW X200
Location: Windellama, NSW
Contact:

Re: Reverse Engineering ME7.4.4 as a stand alone ECU

Post by BennVenn »

Updates!

I've put a 36-1 wheel on my pulsar (still need to weld up a bracket for the VR sensor), bench tested 36-1 code, coil dwell, timing control, all seems fine.

I've put another 10hrs or so into the firmware, setting up k-line comms with the PC, can erase and write flash without having to use boot mode, read and write the eeprom, all the things that are essential for real time tuning. Had to dig deeper into the security IC to learn how to disable it through software as during flash erase/write the CPU effectively can't execute the security code. That's all done!

This ME7 ECU doesn't have a stepper motor driver for the GM style IAC but it does have an unpopulated footprint for a quad low side driver IC, so I'll repurpose that and fit a stepper driver module. It has the 4 high current traces to the ecu connector which are ideal along with 4 CPU IO lines routed out nicely. I was considering swapping out the 32kbyte SRAM with 128kbytes, and might still if we run out of RAM for the RT side of things. The less modifications to the ECU, the more user friendly if anyone else chooses to use these ECU's. 128kbytes would allow shadowing a 64k Flash sector in RAM which simplifies re-writing flash sectors and also real time tuning.

I've started on a TunerProRT plugin for both Emulation and DAQ and that is coming along slowly.

I think the hardware side of things (reverse engineering) is all done, all that is really left is the TunerPro connectivity and then coding up some basic speed-density code.

These ECU's are clearly set up for drive by wire but with the addition of the stepper motor driver module they should be OK to run just about any 4cyl, or any 6 or 8 cylinder with 'smart' coils.
Post Reply