CAN Network Reverse Engineering | Creating DBC | iMiEV

Mitsubishi i-MiEV Forum

Help Support Mitsubishi i-MiEV Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.

Mathias V

New member
Joined
Jan 22, 2025
Messages
2
Hi everyone!

I'm currently reverse engineering the CAN network of a Mitsubishi iMiEV (aka Citroën C-Zero and Peugeot iOn) and trying to make a DBC. As you know, this is quite time-consuming, so I would like to share the information I find. This is still a work in progress. When finished I will share all my findings together with a full DBC!

Note: All messages on CAN 1 (VCU, radio, combination meter, EPS...) also appear in CAN 2 (inverter, DC-DC, A/C...) and vice versa.

- When the ignition is not on, CAN 1 and CAN 2 do not send the same data. Does anyone know anything about this?
- Does anyone have useful information to avoid double work?


Hexadecimal numbers are preceded by ‘0x’, otherwise they are decimal. All formulas are in decimal. Everything is read MSB first.
A 'B' represents a byte, a 'b' represents a bit.
Note: constants can also be a variable that did not change during logging → example: no charging in our log → constant is not necessarily a heartbeat!
IDcommentsformula
0x101always constant → B0 = 0x04

heartbeat? → no, would be key status
0x119B5 increases by value 1 every so often
B6 increases by 1 value with each frame.
B7 no idea

I suspect a kind of timer, can also be a complicated heartbeat.
0x149clear correlation with driving
B2: constant 0
B3: constant 0xFF
B6: increases from 0 to 0xF → index? → explains the erratic behavior of B0, B4, B7

B1: yaw sensor
B5: yaw sensor
0x156B0, B1, B2, B3: constant 0
B4: could be an index (increases per value of 2)
B5: no idea, not a measurement
B6: could be an index from 0x10 to 0x1F → explains jagged graph of B7
0x200B0: constant 0
B1: constant 0x03
B2-3: RPM wheel front left
B4-5: RPM wheel front right
B6: constant 0xFF
B7: constant 0xFF
RPM = (value * 0.5) - 24576
(RPM = (value * 0x0.8) - 0x6000)
0x208B0: constant 0
B1: constant 0x20
B2: constant 0x60
B3: brake pedal → bias = 0, scale = 0.39216 (= 100/255) → full press = 100% (not
sure, further testing needed)
B4-5: wheel speed rear right
B6-7: speed wheel rear left
pedal % = TO BE MEASURED
0x210B0: constant 0
B1: constant 1
B2: accelerator pedal
B3: is 0 or 0x80 → strong correlation with B2
B4: twice 00, then twice 0x80
B5: constant 0
B6: constant 0
pedal % = value * 0.4
(full press = 0xFA = 250 → 100%)
0x212B4b4-7-B5 → very strong correlation with current/voltage traction battery
0x215B0-1: just under speed and always positive
I suspect actual speed, 0x412 (is then for combimeter (speed slightly higher and
always integers)

B2–3: bias = –20, scale = 0x0.0A (rough estimate!) → distance traveled since start?
B4–5: bias = –20, scale = 0x0.0A (rough estimate!) → distance traveled since start? →
deviates more and more under B2–3 → left/right?

B6: constant 0
B7: constant 0
km/h = value * 0.0078125
(0.0078125 = 0x0.02)

km = (value * 0.0390625) - 20 → rough estimate
(0.0390625 = 0x0.0A)
0x231B0: constant 0
B1: constant 0
B2: constant 0
B3: constant 0
B4b1: brake pedal switch (you can also view per byte)
B5: constant 0
B6: constant 0
B7: constant 0
1 = on
0 = off
0x236B0–1: steering wheel position
B2–3: EPS → is this the torque across the steering wheel (in that case →
find data of 2nd sensor) or is it the voltage across the steering servo?
B4b0–3 adds from 0x0 to 0xF
B5: constant 0
B6: constant 0
B7: no idea
steering wheel % = (value * 0.078125) - 320
steering wheel angle = TO BE MEASURED
0x285B1–B2b2–7: acceleration
no idea for the rest
0x286B0: constant 0
B1: constant 0
B2: constant 0
B3: gear selection? → only difference in signal at the start and end of the ride
B4: constant 0
B5: constant 0
B6: constant 0
B7: constant 0
0x288B0–B1b2–7: acceleration (corresponds exactly to the same bits in 0x285)
B2–3: motor RPM → with the same scale and bias it is close to the motor RPM of 0x298
B4: very similar to current through traction battery BUT less accurate
B5: constant 0
B6: constant 0
B7: only change at the end of the ride?
0x298B6–7: motor RPM according to online sources
B0, B1, B2, B3: clear measurement results, of what?
B5: constant 0
RPM = (value * 1) - 10000 → according to online sources
0x29Athe following sequence is repeated:
AD_4nXe6nHzN0N1x5EHCOuzwrb0uIxK2cNP0pcEUG5EUktz41ZaG0eI7nZagfrja6mcWosD2INNF0DuEApvACVub2CfxOVK2dnjH3EOYvZGkH5tALJEhIjH-I3XPjsvqg181ociC1nSK

index for information in another frame?
or heartbeat?
0x2F2B0: clear measurement result, of what?
B1: constant 0
B2: constant 0x03
0x300everything constant besides:
B4: is 0x07 or 0x87 i.e. B4b4-7 is also constant
0x308completely constant
probably heartbeat
0x325completely constant
probably heartbeat
0x346B0–1: very similar to current through traction battery → maybe current through
motor alone? Or vice versa?
Note: Short peaks in the middle of stopping to enter the road:
AD_4nXckj2kv9G2pva1dGlsoA4DCnzYvMrj1yu5Wf4qDRDSvmcWCoX_cxVTGMPRKGbMqnaatpv7CI9x7A4eyN2cilC906OmQVKOjIHtoOMY0t5nt_fLaxFofk3aV34kFFh46PufXE1mkMQ

B2: constant 0x5D
B3: constant 0x20
B4: constant 0x0
B5: constant 0
B6: constant 0
B7: bias = 0, scale = 1 → range according to online sources → possible because
in general the graph is decreasing, some strange jumps?
0x373B0b0–6: bias = 3, scale = 0.01 → max cell voltage according to online sources
B1b0–6: bias = 3, scale = 0.01 → min cell voltage according to online sources
B2–3: bias = -328, scale = 0.01 → traction battery current according to online sources
B4–5: bias = 0, scale = 0.1 → traction battery voltage according to online sources
B6–7: constant 0016
0x374B0 and B1: have something to do with battery SOC (online sources contradict).
Process B0-1? Or would B0 and B1 each refer to specific number of modules?

B2 constant 0
B3 constant 0
B6 constant 0x31
B7 constant 0
0x375completely constant
probably heartbeat
0x384B0–1: AC according to online sources
B3: current to 12V battery according to online sources
B4: heating according to online sources
rest: no idea, probably also something to do with AC
AC = value * 0.001 → according to online sources

12V current = value * 0.01 → according to online sources
0x385B1: change at the end of the ride (like 0x384)
rest: constant 0
0x3A4B0b0: 1 = AC on, 0 = AC off
B0b1: 1 = recirculation on, 0 = recirculation off
B0b2: 1 = MAX btn on, 0 = MAX btn off
B0b5-7: bias = 0, scale = 1 → heating level
B1b0-3: bias = 0, scale = 1 → vent direction 1 or 2 = face, 3 = legs + face,
4 or 5 = legs, 6 = legs + windshield, 7 or 8 or 9 = windshield
B1b5-7: bias = 0, scale = 12.5 → fan speed

everything according to online sources, not entirely sure, further testing needed
0x408whole message constant 0

Thanks for your help!
 
Thanks for your help!
PID 149:
Rotation = (PID[5] * 256 + PID[4] - 32934) / 32.934;

PID 200:
if (PID[2] < 255)
Speed1 = (PID[2] * 256 + PID[3] - 49152) / 19.0;
if (PID[4] < 255)
Speed2 = (PID[4] * 256 + PID[5] - 49152) / 19.0;

PID 208:
Brake = PID[3];
if (PID[4] < 255)
Speed3 = (PID[4] * 256 + PID[5] - 49152) / 19.0;
if (PID[6] < 255)
Speed4 = (PID[6] * 256 + PID[7] - 49152) / 19.0;

PID 210:
Pedal = 100 * PID[2] / 256.0;

PID 215:
When PID[0] < 255
Speed0 = (256 * PID[0] + PID[1]) / 128.0;

PID 231:
BrakeOn = PID[4];

PID 236:
Steering = (PID[0] * 256 + PID[1] - 4096) / 30.0;

PID 285:
Acceleration = ((PID[0] * 256 + PID[1]) - 2000) / 400.0;
calcGear(PID);

PID 286:
When PID[3] > 0 AirSensor = PID[3] - 50.0;

PID 298:
RPM = PID[6] * 256 + PID[7] - 10000;
MotorTemp0 = PID[0] - 50;
MotorTemp1 = PID[1] - 50;
MotorTemp2 = PID[2] - 50;
MotorTemp3 = PID[3] - 50;

PID 6FA:
calcVIN(PID);

PID 346:
RRshown = PID[7];
if (RangeUnits.equals(miles))
RestRange = KmPerMile * PID[7];
else RestRange = PID[7];

PID 373:
BatVmaxCell = (PID[0] + 210) / 100.0;
BatVminCell = (PID[1] + 210) / 100.0;
Amps = (PID[2] * 256 + PID[3] - 32768) / 100.0;
if (Amps < 200 && Amps > -200)
Amps = -Amps;
AmpsCal = -(Amps + 0.68);

if (PID[4] > 9)
BatterytotalVolts = (PID[4] * 256 + PID[5]) / 10.0;
Watts = AmpsCal * Volts;

PID 374:
if (PID[0] > 10) SoC1 = (PID[0] - 10.0) / 2.0;
if (PID[1] > 10) SoC2 = (PID[1] - 10.0) / 2.0;
BatTmax = (PID[4] - 50.0);
BatTmin = (PID[5] - 50.0);
if (PID[6] > 0) CapAh = PID[6] / 2.0;

PID 384:
when (PID[0] < 255)
Amps = (PID[0] * 256 + PID[1]) / 1000.0;
when (PID[0] >= 255)
if (On.in() == 1 && (_Fan.in() > 0 || _Max.in() > 0))
Amps = 1;

Watts = Amps * Volts;
12vAmps = PID[3] / 100.0;
12vWatts = 12vAmps * Volts;
h_Amps = PID[4] / 10.0;
h_Watts = h_Amps * Volts;

PID 389:
ChargeVDC = 2 * (PID[0] + 0.5);
ChargeVAC = PID[1];
ChargeADC = PID[2] / 10.0;
ChargeTemp1 = PID[3] - 50.0;
ChargeTemp2 = PID[4] - 50.0;
ChargeAAC = PID[6] / 10.0;

PID 3A4:
calcAir(PID);

PID 412:
SpdShown = PID[1];
if (PID[2] < 255)
OdoShown = 256 * (256 * PID[2] + PID[3]) + PID[4];
if (i_OdoUnits.equals(miles)) Odo = KmPerMile * OdoShown;
else Odo = OdoShown;
if (PID[0] == 254) KeyOn = 1;
else KeyOn = 0;

PID 418:
if (PID[0] < 255)
Gear = PID[0];
PID 418 contains the gear shifter position.
The first byte (B0) translated to ASCII is the gear shifter position. The rest (B1-B7) just seem like constants.
0x50: P 80 : P
0x52: R 82 : R
0x4E: N 78 : N
0x44: D 68 : D
0x83: B 131: B
0x32: C 50 : C


PID 424:
calcLights(PID);
calcRearDefrost(PID);
calcWipers(PID);

PID 696:
if (PID[2] > 0 && PID[2] < 7)
MotorA = (256 * PID[2] + PID[3] - 500) / 20.0;
if (MotorA < 0) MotorA = 0;
if (PID[6] > 37 && PID[6] < 40)
RegA = (256 * PID[6] + PID[7] - 10000) / 5.0;
else
RegA = 0;


PID 697:
QuickCharge = PID[0];
QCprocent = PID[1];
QCAmps = PID[2];

PID 6E1:
PID 6E2:
PID 6E3:
PID 6E4:
cellsData = true;// 2.1 + (256 * b4 + b5)/200
calcCells(PID); // 2.1 + (256 * b6 + b7)/200

PID 762:
if (PID[0] == 36)
if (PID[3] > 0 || PID[4] > 0)
BMUCapAh = (PID[3] * 256 + PID[4]) / 10.0;
if (PID[5] > 0 || PID[6] > 0)
BMURemAh = (PID[5] * 256 + PID[6]) / 10.0;
if (BMUCapAh > 0)
BMUSoC = 100 * BMURemAh / BMUCapAh;
 
I have a Peugeot Partner EV, master bms and traction control units are inside the car, under the driver seat, both units are marked Mitsubishi, CAN traffic (values and addresses) is the same of iMiev until their CAN line arrive to another device (I still never found where and what) and out of this line the original Mitsubishi traffic dispare.
I suppose the body computer or another device have the function to make possible the communication between two CAN BUS network wich don't use the same protocol.
So all bms data are available in Peugeot standard diagnostic but with different adresses.
It seems Peugeot instead to develop a own traction chain from zéro preferred to buy a whole block from Mitsubishi (good choice I think).
It was enough to realise a "CAN traslator" to make two different systems in communication
 
Hello Mathias, great project. I am preparing to do similar in order to try to run the imiev propulsion system without various components - steering column, wheel speed sensors, abs, a/c, G+yaw rate sensor, eps... The plan, is to try to capture 'straight ahead' messages and proportional wheel speed messages to inject into the canbus as required to keep the propulsion system happy enough to behave just like a good old fashioned engine. I don't know if this will be possible. Anyone who thinks not should probably tell me now and save a whole lot of pain :).

So to start with, does this look like a correct interpretation of the two canbus schematics from the ru database?

canbus combined.jpg

As in they are all part of the same network? At least when the ignition is on following Mathias comment on all messages visible on both systems only when ignition on? And all accessible from obd2 socket pins 6 and 14 (with ignition on)?

As such, all I'd need to start logging and potentially injecting would be something like this: arduino uno canbus shield on an Uno, connected to an obd2 cable etc?

Mathias, I'd like to say yeah, I'll help... but whilst I will be with you in spirit, I will be mostly a hinderance as this is a little (lot) outside my comfort zone. Of course if you are willing to help me get up to speed, then I may be able to reduce your workload, maybe, a little, maybe. :cool:
 
That diagram is helpful to show how the EV-ECU is the gateway device between two CAN Busses.

But it is missing two other CAN Buss, namely the Battery Pack Buss between the BMU and the Traction Pack (CMU Boards on all the cell modules). And the CAN between the DC Quick Charging and the EV-ECU.
 
Thanks Kiev, yes, luckily I hope that I won't have to disturb those two.

And Mickey, there is indeed the will, but whilst that is all it took when I was a youth, there are now other responsabilités, so the question is will I write my will before getting this done? :)

318iev seemed to be doing well, but then dropped off the face of the planet.
 
I don't see a site linked. So is the imiev into a bmw guy the same as he who did the electric tractor conversion? (Ive been planning to put my spare Nissan leaf power plant into a broken mini digger one day). If so then he's definitely still alive, just not communicating with old project stuff, shame, he seems mighty capable.
 
Back
Top