SSM2 via CAN

After some detailed reverse engineering of diesel ROMs, Subaru Diesel Crew is first (2010-10-23) in publishing protocol details – enjoy!
RomRaider started to support this protocol 2013-03-24 (v0.5.6 RC6).

This protocol is supported on Subaru Diesel Euro 4/5 as well as petrol models. As this protocol is based on CAN, old non-CAN petrol models will not work.

You’ll need a CAN/ISO15765 capable hardware interface to plug into the OBDII port. Typically SAE J2534 compliant devices support the needed ISO15765 protocol Cheap serial converter devices without an included processor won’t work (K-/L-Line only, e.g. Tactrix OpenPort 1.3 series).

An affordable CAN-device is the Tactrix OpenPort 2.0. SSM2 via CAN has been tested extensively on such a device. Its onboard firmware can also do standalone logging (to memory card, no PC attached) using either SSM2 serial or SSM via CAN mode.

CAN pros: Much faster than standard 4800 baud SSM2 via serial (SSM2 Benchmark – Serial vs. CAN).

Cons: Cannot get RAM addresses (stock ROM software prevents this)

The following brief overview assumes basic J2534 knowledge at least! There’s some guidance in this tutorial: Manual ISO15765 Connection Tutorial.

Connection Settings

Protocol: ISO15765 (6)

Baudrate: 500000

PassThruConnect-Flags: None

For all PassThruMsgs including the PassThruFilter use PassThruMsg-TxFlags: ISO15765_FRAME_PAD (0x40, bit 6 set)


FilterType: FlowControl (3)

00 00 07 E8
(CAN ID of ECU is 0x7E8)

00 00 07 E0
(CAN ID of tester is 0x7E0)

PassThruMsg-TxFlags for all three: ISO15765_FRAME_PAD (0x40, bit 6 set)


Basically these very similar compared to SSM2 via serial line communication. Once connected, SSM2 via CAN is even easier – no need to calculate checksum and length bytes.

Be aware that you’ll get one or two incoming status messages to be read/skipped after sending a message to the ECU:

  1. 00 00 07 E0
    (Tester CAN ID) with RxStatus=9 (=TX_DONE (bit 3) | TX_MSG_TYPE (bit 0))
  2. 00 00 07 E8
    (CAN ID of sender = ECU) when DataSize of following incoming data msg ≥ 12, RxStatus=2 (=START_OF_MSG (bit 1)) to indicate ISO 15765-2 segmented message.

The actual data response packet follows those status messages, so expect 2 or 3 incoming messages to be read in total.

Request Init Data

<CAN ID Tester> AA
Request init from engine control unit for example:
00 00 07 E0 AA
<CAN ID ECU> EA <SSMID[3]> <ROMID[5]> <CapabilityBytes[..]>
Expect total DataSize=109 on Euro4 diesel vehicles. Then minus 5 header bytes (till incl. “EA”) result in 104 payload bytes, consisting of SSMID[3], ROMID[5] and CapabilityBytes[96].

Read SSM2 Address(es)

<CAN ID Tester> A8 00 <Address1[3]> <Address2[3]> ...
Note: Mode byte (after A8) must be 00 – fast poll not supported unlike SSM via Serial.
Request single address, 0x000008 for example:
00 00 07 E0 A8 00 00 00 08
Note: the zero byte after A8 is a padding byte and probably has no effect. Same as in serial SSM2. Just like with serial SSM2 you can request multiple addresses at once by adding more SSM addresses (3 bytes each).

Example: DPF Regeneration Count

Need to request two bytes, addresses 0x00029D and 0x00029E, which make up this Diesel parameter.
x [-] = A*256+B like SSM2 0x00029D; tracks fully completed regenerations only
x: response payload data as 16 bit unsigned integer (uint16), big endian; alternative view: A = high (first) byte, B = low (second) byte
00 00 07 E0 A8 00 00 02 9D 00 02 9E
Example respose:
00 00 07 E8 E8 01 23
→ SSM data bytes are "01 23"
→ x = 0x0123 = decimal 291; → result = 291 regenerations
Alternative view by handling individual bytes: → A = 0x01; B = 0x23 → result = 0x01 * 0x100 + 0x23 = decimal 1 * 256 + 35 = 291

Responses indicating an error

<CAN ID ECU> 7F A8 12
means address error. Usually happens when wanted address ≥ 0x000350 which inevitably includes RAM-Addresses (0xFF????).

Note: Default ROMs all seem to have this “< 0x000350” condition built in. However if you can pull and flash the ROM, you could modify/patch it in order to remove that limitation.
<CAN ID ECU> 7F A8 13
means packet format error e.g. message length does not match expected length. Length should always be: HeaderBytes[6] + n * SSMAddress[3]. In other words such A8-requests must have DataSizes 9, 12, 15, …

Write SSM2 Address

<CAN ID Tester> B8 <Address[3]> <Data[1]>
Seems to be very limited: Only address 0x000060 (clear memory, reset ECU …) is allowed? Anyone has a ROM that accepts more addresses?
Write byte 0x01 into address 0x000060 for example:
00 00 07 E0 B8 00 00 60 01

Responses indicating an error

<CAN ID ECU> 7F B8 22
means address not allowed.
<CAN ID ECU> 7F B8 13
means packet format error/length mismatch. You can only write a single byte with the B8 command.


17 responses to “SSM2 via CAN

  1. My ECU also does not accept writing to any address except 0x60.


  2. I’m really having trouble understanding something here. The SSM2 init packet, 00 00 07 E8 AA is this sent as a normal CAN message to ID 0x7E8 (the ECU), so the payload of a standard CAN message is “00 00 07 E8 AA” 5 bytes?

    Can you share any basic Arduino code that would get the ECU to reply to its init request, because I just cannot make it work 😦

    (sorry repost due to bad email address)


    • Hi, never used Arduino, not sure if this helps:
      For J2534 API, first 4 bytes are CAN-ID which will consumed by device/driver. In mentioned SSM2 init message, single byte “AA” is actual message payload.
      Using other APIs like ELM327, once setup, you just send requests like “AA” and get actual response payload from ECU.


      • Thanks mate. This was what I was trying, and getting no response so I started to think I was reading this page wrong.

        I can confirm I see CAN messages – I don’t get all of the CAN messages that this site shows coming from older models.. If I do a long term sample, I see these ID’s on the CAN bus.


        – I can confirm I get responses from ECU if I make OBD-II requests.
        – Ignition is on, and engine running.
        – I just never get a response from 0x7E0.


        // normal OBD-II request for RPM to 0x7DF
        // Sending OBD-II.
        w 00 00 07 DF 02 01
        r 7E8,4,41,C,18,1D,0,0,0, // RPM is returned in bytes 3 and 4 ok

        // normal OBD-II Extended request for RPM to 0x7DF
        // Sending OBD-II Extended.
        w 00 00 07 DF 03 22 11 22
        r 7E8,3,7F,22,31,0,0,0,0, // error response, ok, can’t request RPM from OBD Extended

        // Sending SSM2 init to 0x7E0
        w 00 00 07 E0 AA

        // Sending SSM2 init to 0x7DF (worth a try?)
        Sending SSM2 init
        w 00 00 07 DF AA

        // Send a standard OBD-II request direct to ECU?
        Sending OBD-II.
        w 00 00 07 E0 02 01
        … // no response.

        I have a 2015 XT Forester (petrol). It would also appear that the SSM used for this model is now SSM3 and/or SSM4
        Either, it never responds in this model forester, or the address ID has changed? Thoughts?


      • To query an ECU, you, the tester device, have to use CAN-IDs 0x7DF or 0x7E0.
        Wikipedia: OBD-II PIDs
        Engine control unit listens to those IDs and should respond using ID 0x7E8.
        In tester vs. ECU communication the ID can be interpreted as sort of source address.
        On the CAN bus, e.g. listening to default traffic, IDs or content usually don’t tell source and/or destination, one has to know or figure that out. Any control unit firmware decides upon IDs which frames to read, often through CAN-capable chip configuration (hardware filters), and also sends own frames. All IDs must be unique on the same bus, each representing a specific proprietary content so listeners know how to interpret that data.
        See also Wikipedia: CAN_bus.


      • Ok, but isn’t that what I’m doing ?


  3. You need to add the length byte:
    To get the ECU ID via SSM over CAN
    07 E0 01 AA

    To get the OBD-II PID MAP:
    07 DF 02 01 00


  4. To Iain – It’s actually ISO 15762-2 – see

    Most of this article seems to assume that whatever API you’re using (such as the J5234 one) handles 15765-2 (aka ISO-TP) encapsulation and flow control for you. If you’re implementing this on an Arduino, you probably need to implement ISO-TP yourself.

    A few additional observations from a MY2009 USDM Outback 2.5i:
    The ECU will not respond unless an ISO-TP CAN frame is padded to 8 bytes with 0x00, if the frame is shorter than 8 bytes – this includes OBDII requests. Note that the ISO-TP length field is the length of actual data NOT including the padding needed to get to a full frame.
    For a multiframe response, such as the response to a 0xAA query, the first response frame from the ECU needs to be answered with a flow control frame, or the ECU will not continue. The simplest one, assuming your receiver can handle the maximum rate from the ECU, is [0x30 0x0 0x0 0x0 0x0 0x0 0x0 0x0] (Again, have to pad to 8 bytes, or at least I assume you do since everything else needs padding, even though only the first 3 bytes matter)

    I can’t share Arduino code since I’m using a PiCAN2 on a Raspberry Pi. I’m currently using the pyvit library – but be warned, it’s ISO-TP implementation needs some SERIOUS fixup. (I’ll be sending some pull requests to the author later this week with fixes.)


  5. Hi Guys
    I can connect with my Subaru Outback diesel euro 5 – vin JF1BRDLZ4BG086147 – by torque pro and I can see rews, coolant and others standard data but nothing about DPF temperature, regeneration, pression and oil diluitation ratio or amount.
    I tried also with PID but no response.
    Any idea about unlock these sensor?
    Thanks a lot

    Liked by 1 person

    • Hi, parameter IDs like ROMID will work for every Euro 5/6 model. If you can’t get any mode 22 request to work, check your interface hardware for i.e. fake ELM chip problem (these only support limited functionality like standard OBD-II = mode 1).


      • Does it mean I nave ti buy an other ELM327? Which better forma my car (italiano model)?
        Thank you so much, very great site


      • How I can check the interface hardware (tinxi® Scanner Tester OBD2) fake ELM chip problem and how I can solve this issue?


      • Just realized, you are posting on page “SSM2 via CAN”. If your car really is Euro 5, then mode 22 as on page Extended OBD-II is preferred ECU protocol.
        Don’t know your specific device, there are too many of these.
        As for testing ELM327 interface, connecting to it via terminal app (phone or PC) would be ideal. For bluetooth device I had used an Android app something like Bluetooth terminal. I also did this on Linux PC successfully but requires more skills.
        Tips and advice for using ELM327 interfaces. There might be better info and tutorials on the web, try searching…
        Once you have working connection to the device, you can type in ELM commands and see responses.

        Most basic command:
        example response: ELM327 v1.3a
        If above works, I’ll be able to provide further commands, how to set up protocol for ECU and do OBD requests for final results.


  6. Hi, I found these information:
    – Standard OBD: European EOBD
    – ID Calibration: JE5F231A
    – OBD Protocol: ISO15765-4CAN11/500
    – ELM327 v2.1
    I’ve tried also to put CSV on custom PIDs but Torque doesn’t read the file.
    It’s strange because some value is read and has the same number of PID like csv file. For example on “my” Torque the Coolant Temperature PID is [05]. Maybe I have to set header OBD and don’t leave “auto”?


    • Yes, OBD mode 1 PID 05 is coolant temp. and is supported on all models. Your ROM also supports mode 22 PID 0005, should be same scaling and result. Mode 1 is preferred for items available as mode 1 – more generic and shorter.
      (Transport) protocol ISO15765-4 CAN 500 kbit as you have listed is correct which is why OBD mode 1 is working. Therefore, ECU should respond to both OBD mode 1 and mode 22 messages. Not sure what “header” means for Torque.
      mode 1, coolant temp: 01 05
      mode 22, coolant temp: 22 00 05


  7. Hi everybody.
    Hi would like to understand how a software called ActiveOBD for android is capable to get many data out of TCU, like CVT oil life, CVT oil temperature, gear ratio and more…, but I can’t do it with torque or similar.
    I did a sniff of the data the program was sending and receiving from my OBD2 adapter. But I can’t figure out how it works with TCU. Can anybody help me please?
    Here attached the data from sniffer.


    ELM327 v1.3a






    ELM327 v1.3a

    OBDLink MX WiFi r2.3
















    • Hi!
      I would think the Torque app should be flexible enough to set up the CAN-ID for TCU.
      If you read through documentation of ELM AT and OBDLink STN commands, it’s simple. The messages itself are independent of interface API (J2534, ELM etc.).
      In your example, it configures protocol 6 which is ISO 15765-4 CAN (11 bit ID, 500 kbaud). Then queries ECU using SSM via CAN.
      SSMID A3 10 0F = must be petrol, perhaps 2.0XT DIT
      ROMID 92 44 5C 70 07
      It does the same for TCU, judging by SSMID it looks like it’s Lineartronic (CVT).
      Not doing much more with it, it switches back to ECU.
      Last item: OBD mode 1, requesting PID 5C, Engine Oil Temp., answer is 0x63 – 40 = 59 °C

      The real intellectual property is in definitions – available parameters and how to interpret raw bytes. Personally, I probably won’t publish more Subaru specific PIDs, simply because it is serious work and I have done a lot for free already. For standard OBD items there’s Wikipedia…


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.