Category Archives: J2534

Diesel ECU Patch v2

Patched the CAN-handler responsible for the SSM2-Read-Addresses (A8) command. Now we’ve got high-speed full RAM access.
Euro4 stock ROMs prevent RAM access (0xFF**** addresses) via CAN (ISO15765 actually). Previously we had to resort to slow SSM2 via Serial protocol.

The static screenshot does not really tell the difference though. This Linux application can do both modes. Speed in comparison is like this: logging roughly 120 items using SSM2 via CAN updates all values fluently – no noticable delay. In serial mode, it takes multiple seconds for a single refresh – really major difference!

Planned: Implementing CAN block read command for even more performance e.g. quick RAM snapshots. Either command “A0” like SSM2 via Serial or Extended OBD-II mode 0x23 (stock Euro5 diesels have this), or both.

Openport 2.0 Bugs

Update: Bugs are confirmed, probably all Tactrix driver versions are affected. Forcing driver to behave according to J2534 specs resulted in Subaru reflash tool working perfectly.
We are looking into other devices, might have some alternatives soon.

Tactrix Openport 2.0 device/driver has some bugs. Got latest EcuFlash 1.43.3252 Beta from http://www.evoscan.com/free-ecu-rom-downloads as it usually includes latest J2534 driver. After EcuFlash doing firmware update (without the app asking first + can’t go back?) PassThruReadVersion (www.drewtech.com) command yields:

Firmware = 1.11.3209
DLL = 1.00.3147 Sep  3 2010 00:17:29
API = 04.04

Wrote a little unit test, in C# because it’s less work than C/C++. See code comments.


using System;
using J2534;
using NUnit.Framework;

[TestFixture()]
public class TestJ2534
{
	IPassThruV0404 ipt;
	PassThruStatus status;
	int deviceID;

	[SetUp]
	public void Setup ()
	{
		ipt = new J2534.Device.OpenPort20Dll ();
		status = ipt.PassThruOpen (null, out deviceID);
		Assert.AreEqual (PassThruStatus.STATUS_NOERROR, status, "PassThruOpen");
	}

	[TearDown]
	public void TearDown ()
	{
		if (ipt != null)
			ipt.PassThruClose (deviceID);
	}

	[Test()]
	public void TestCase_INVALID_DEVICE_ID ()
	{
		string firmwareVersion, dllVersion, apiVersion;

		// correct way
		status = ipt.PassThruReadVersion (deviceID, out firmwareVersion, out dllVersion, out apiVersion);
		Assert.AreEqual (PassThruStatus.STATUS_NOERROR, status, "PassThruReadVersion");

		// deliberately causing ERR_INVALID_DEVICE_ID
		int deviceID_wrong = 999;
		status = ipt.PassThruReadVersion (deviceID_wrong, out firmwareVersion, out dllVersion, out apiVersion);
		Assert.AreEqual (PassThruStatus.ERR_INVALID_DEVICE_ID, status, "PassThruReadVersion using wrong deviceID");
		// Expected: 0x1A = ERR_INVALID_DEVICE_ID
		// Tactrix Openport 2.0 --> PassThruStatus: 0x20 = (undefined) !!!
	}

	[Test()]
	public void TestCase_ERR_BUFFER_EMPTY ()
	{
		int channelID;
		status = ipt.PassThruConnect (deviceID, PassThruProtocol.CAN, PassThruConnectFlags.None, PassThruBaudRate.Rate500000, out channelID);
		Assert.AreEqual (PassThruStatus.STATUS_NOERROR, status, "PassThruConnect");

		// deliberately trying to read
		PassThruMsg msg;
		status = ipt.PassThruReadMsg (channelID, out msg, 1000);
		Assert.AreEqual (PassThruStatus.ERR_BUFFER_EMPTY, status, "PassThruReadMsg");
		// Expected: 0x10 = ERR_BUFFER_EMPTY
		// Tactrix Openport 2.0 --> PassThruStatus: 0x9 = ERR_TIMEOUT !!!
	}
}

Test result, MonoDevelop screenshot:

AFAIK none of our apps hit above bugs but others might! For example there are reports indicating official Subaru stock reflash tool FlashWrite (http://techinfo.subaru.com/static/specialTool.html, see “J2534 Reprogramming”) won’t work using OP2.0 (CAN Subarus at least), while app works fine using other J2534 devices. Applications could hit any J2534 issue, especially the ERR_BUFFER_EMPTY one. With commercial software, such problems can be show-stoppers. AFAIK at least one of those bugs has been reported to Tactrix back in 2010, still not fixed…

Manual Serial Connection Tutorial

Abstract

Describes how to use free open source Drew Tech Tool for J2534 in order to setup a SSM2 via Serial connection to the engine control unit (ECU). Diesel or petrol ECU model does not matter. Once set up, one can send and receive messages without any additional software, no programming skills necessary.

IMPORTANT: Interface hardware that comes with J2534 driver is required!
Unfortunately, many cheap devices don’t come with J2534 drivers.

I am using Tactrix OpenPort 2.0 in this example.

Drew Technologies has good infos regarding J2534 on their site: http://www.drewtech.com/support/passthru.html

Content

Drew Tech Tool Software installation

Basically it is a generic tool, uses J2534 API under the hood, supports many protocols.

Visit http://www.drewtech.com/downloads/index.html
In category “SUPPORT APPLICATIONS” look for “J2534-1 Bus Analysis Tool” (not sure why they chose this link text), download and install Windows installer file:
Drew Technologies Tool for J2534-1 API v1.07.msi (9 MB)
License is GPLv2+, besides executable binaries the msi also includes Visual Basic source code.

Step 1: Select Device, Open

Tab “Connect”, top left frame.
Note: If you see text like “No information found in the registry” and buttons are disabled, close the app and use “Run as administrator” method!
Select desired hardware interface, should be recognized if your J2534-device had been installed correctly.
Path to DLL is just for info, lists the J2534 driver DLL location.
Click button “Load DLL”

Top right frame. Click button “Open” (API call PassThruOpen)

After “Open” the tool automatically does a PassThruReadVersion to retrieve version information, displays the results in bottom left frame.

Step 2: Protocol Properties

Bottom right frame.

Select ISO9141, ISO14230 would also work, they use the same physical layer (K-Line, OBDII pin 7).
Check baudrate and connect flags. Screenshot shows needed values which are defaults.
We need 4,800 baud which is Subaru SSM2 specific.
Connect Flags, right click for helper dialog.

Setting flag ISO9141_NO_CHECKSUM is important (0x200, bit 9). Since SSM2 is not a standard protocol, we have to turn off automatic checksumming by the device.

ISO9141_K_LINE_ONLY (0x1000, bit 12) can also be set, it’s not required though. I have tested Connect Flags 0x200 and 0x1200 working.

Click button “Connect” (PassThruConnect).
By the way, the statusbar shows latest command result, should be OK. You can also look into tab “Results” which displays a full log of all commands done so far.

Step 3: Config

Tab “Config”. Entries show current settings, the tool has already requested this info (PassThruIoctl GET_CONFIG).
Not important, but I usually work with LOOPBACK=OFF, don’t want to receive loopback messages from the interface device, I know what data I have sent anyway. Might be useful for debugging in case of troubles though.
LOOPBACK: 0 = OFF, 1 = ON
Click button “Set”
Tool does PassThruIoctl SET_CONFIG, then GET_CONFIG to display actual values.

Step 4: Filters

Tab “Filters”.
Very important – without a filter set up you won’t receive any response, the device would ignore anything received from the control unit.
Fasted way is clicking button Create “Pass All” Filter which fills in the needed data automatically.

Mask: 00
Pattern: 00
Filter: Pass

This filter instructs the interface device to let all incoming messages pass through. Without a pass filter, J2534 specs require blocking everything by default.

Don’t forget to click “Apply”, to acually set the filter (PassThruStartMsgFilter).

Step 5: Messages

Tab “Messages”. Now that everything has been set up we can try to communicate with the control unit.
Top right button column.
“Rate” entry: Specifies delay time in milliseconds for automatic read-message (PassThruReadMsgs) polling. Since we type and send messages manually, fast polling makes no sense. I recommend 1000 = 1 second or more. Otherwise the log in tab “Results” will grow fast, making it harder to use.
Click “Start” (toggles to “Stop”) button to run or stop the automatic read loop. Must be started in order to display received messages. Can be started later, the interface device will store (a limited amount of) incoming messages anyway.

Message content

Scratch Pad entry: type message to be sent as hex bytes in here.
IMPORTANT: You must provide valid checksum (last byte) or ECU won’t respond!

Tx flags: None (0)

Once ready, click button “Send” (PassThruWriteMsgs). On Openport 2.0 device there should be green (send) and red LEDs (receive) flashing shortly.

SSM2 via Serial examples

For protocol details see page SSM2 via Serial.
SSM2Init-Request to ECU usually is: 80 10 F0 01 BF 40
SSM2Init-Request to TCU usually is: 80 18 F0 01 BF 48

SSM2-Init response from a diesel ECU:

Step 6: Disconnect protocol

Tab “Connect”
Bottom right frame, click button “Disconnect” (PassThruDisconnect, current channel). You could set up a new/different protocol.

Step 7: Close connection

Tab “Connect”
Inside top right frame, press button “Close” (PassThruClose). PassThruClose also disconnects all open channels in case you did not do this already. Now you can quit the application or select a different J2534-device and start all over.

Manual ISO15765 Connection Tutorial

Abstract

Describes how to use free open source Drew Tech Tool for J2534 in order to setup a ISO 15765-2 / ISO TP connection to the engine control unit (ECU). Diesel or petrol ECU model does not matter. Once set up, one can send and receive messages without any additional software, no programming skills necessary.

IMPORTANT: CAN/ISO15765 capable interface hardware plus J2534 driver is required!

I am using Tactrix OpenPort 2.0 in this example.

ISO15765 is a convenient transport layer on top of raw CAN. Basically it allows larger message data, not limited to 8 bytes of raw CAN. Under the hood it uses raw CAN, multiple of such raw frames if needed. All modern Subaru ECUs seem to support this protocol as it is being used for OBDII, SSM2 via CAN and the new Euro5 (diesel) diagnostic protocol.

Drew Technologies has good infos regarding J2534 on their site: http://www.drewtech.com/support/passthru.html

Unfortunately, some cheap devices don’t come with J2534 drivers although they can handle CAN/ISO15765. Using these requires proprietary commands, meaning special software support.

Content

Drew Tech Tool Software installation

Basically it is a generic tool, uses J2534 API under the hood, supports many protocols.

Visit http://www.drewtech.com/downloads/index.html
In category “SUPPORT APPLICATIONS” look for “J2534-1 Bus Analysis Tool” (not sure why they chose this link text), download and install Windows installer file:
Drew Technologies Tool for J2534-1 API v1.07.msi (9 MB)
License is GPLv2+, besides executable binaries the msi also includes Visual Basic source code.

Step 1: Select Device, Open

Tab “Connect”, top left frame.
Note: If you see text like “No information found in the registry” and buttons are disabled, close the app and use “Run as administrator” method!
Select desired hardware interface, should be recognized if your J2534-device had been installed correctly.
Path to DLL is just for info, lists the J2534 driver DLL location.
Click button “Load DLL”

Top right frame. Click button “Open” (API call PassThruOpen)

After “Open” the tool automatically does a PassThruReadVersion to retrieve version information, displays the results in bottom left frame.

Step 2: Protocol Properties

Bottom right frame.

Select ISO15765.
Check baudrate and connect flags. Screenshot shows needed values which are defaults.
We need 500,000 baud (Subaru uses 500 kbit/s on high speed CAN bus).
For ISO15765 we don’t need special connect flags, therefore hexadecimal 0x0 = zero = all bits are zero.
Click button “Connect” (PassThruConnect).
By the way, the statusbar shows latest command result, should be OK. You can also look into tab “Results” which displays a full log of all commands done so far.

Step 3: Config

Tab “Config”. Entries show current settings, the tool has already requested this info (PassThruIoctl GET_CONFIG).
Not important, but I usually work with LOOPBACK=OFF, don’t want to receive loopback messages from the interface device, I know what data I have sent anyway. Might be useful for debugging in case of troubles though.
LOOPBACK: 0 = OFF, 1 = ON
Click button “Set”
Tool does PassThruIoctl SET_CONFIG, then GET_CONFIG to display actual values.

Step 4: Filters

Tab “Filters”.
Very important – without a filter set up you won’t receive any response, the device would ignore anything received from the control unit.
For ISO15765 a flow control filter is needed which specifies CAN-IDs. Standard CAN-IDs use 4 bytes each.

Mask: FF FF FF FF, means device should check first 4 bytes which make up required CAN-ID. Independent of following CAN-IDs

Pattern: Target CAN-ID. Standard ECU CAN-ID is 0x7E8 → 00 00 07 E8, TCU would be 0x7E9

Flow Control: Tester/interface device CAN-ID. ECU 0x7E8 usually listens to 0x7E0 → 00 00 07 E0.

Filter: set type to “Flow”


For ISO15765 we also need additional message flags (Tx Flags). Put cursor inside Tx Flags entry, right click and click “edit flags” to get helper dialog, see below.
Turn on ISO15765_FRAME_PAD and click button “Set”, resulting in value 0x40 (bit 6 set). You could also just type in 0x40 in the entry. Later when sending messages, this same flag is needed on each message, too.

Don’t forget to click “Apply”, see picture before, to acually set the filter (PassThruStartMsgFilter).

Step 5: Messages

Tab “Messages”. Now that everything has been set up we can try to communicate with the control unit.
Top right button column.
“Rate” entry: Specifies delay time in milliseconds for automatic read-message (PassThruReadMsgs) polling. Since we type and send messages manually, fast polling makes no sense. I recommend 1000 = 1 second or more. Otherwise the log in tab “Results” will grow fast, making it harder to use.
Click “Start” (toggles to “Stop”) button to run or stop the automatic read loop. Must be started in order to display received messages. Can be started later, the interface device will store (a limited amount of) incoming messages anyway.

Message content

IMPORTANT: Tx flags (entry to the left of msg scratch pad): Constant, same as in flow control earlier,0x40 = ISO15765_FRAME_PAD.

Scratch Pad entry: type message to be sent as hex bytes in here.
IMPORTANT: First 4 bytes have to match tester CAN-ID, the one specified in flow control filter. Here: 00 00 07 E0.
After those CAN-ID bytes, the actual message content follows. So 5th byte = 1st payload byte is sort of command byte. ‘AA’ is SSM2Init-Request via CAN, ‘A8’ means read-(SSM2)-address etc.

Once ready, click button “Send” (PassThruWriteMsgs). On OP2.0 device there should be green (send) and red LEDs (receive) flashing shortly.

SSM2 via CAN examples

For protocol details see page SSM2 via CAN.

Example in following screenshot shows SSM2-Init-request, with response received from a diesel ECU.

Success response command byte = request command byte + 0x40 (bit 6). Examples: AA → EA, A8 → E8 etc.

There are additional status messages containing CAN-ID bytes that prepend the actual response data msg (last one). These indicate that the msg had been sent and an incoming (multi-frame) msg transfer had commenced.

Cleared received msg list, doing command ‘A8’, reading SSM2 address 0x000008 = Coolant Temp. (x-40 [°C])

Response data byte is 0x40 = decimal 64, – 40 → 24 °C coolant temperature.

Error response example: Last msg sent was A8 00 00 03 50 meaning read SSM2 address 0x350. Diesel ECUs so far only support SSM2viaCAN addresses 0x000000 ≤ x ≤ 0x00034F. Since 0x350 is already outside allowed range we get an error msg. As seen in screenshot, Negative Response Code (NRC, sort of error code) for this error type is 0x12 obviously.

If you read SSM2 addresses which have no supported effect, depending on car model and ECU ROM, e.g. 0x300, you should get data byte ‘FF’, so no error code.

Step 6: Disconnect protocol

Tab “Connect”
Bottom right frame, click button “Disconnect” (PassThruDisconnect, current channel). You could set up a new/different protocol.

Step 7: Close connection

Tab “Connect”
Inside top right frame, press button “Close” (PassThruClose). PassThruClose also disconnects all open channels in case you did not do this already. Now you can quit the application or select a different J2534-device and start all over.

SSM2 Benchmark – Serial vs. CAN

Purpose

Measuring maximum sampling speed.

SSM2 Request Content

SSM2 Address(es) Name
0x000008 Coolant Temperature
0x00000D Manifold Absolute Pressure
0x00000E
0x00000F
Engine Speed
0x000010 Vehicle Speed

→ 4 paramaters, 5 data bytes to request in total

Test conditions

  • Reading above five SSM2 addresses using a single ‘A8’ request message in a tight loop.
  • There’s no result data processing at all, except response packet validation (header and checksum). Of course this is unrealistic but this is meant for measuring maximum possible sampling speed.
  • Messages are being created on the fly by the (rather efficient) library code so they’re not being cached. Not caching the send-message should have negligible effect. Very likely native well optimized C++ code probably won’t be noticeably faster, especially on the slow serial protocol.
  • The benchmark program is a console application, preventing any GUI overhead. No progress output or anything within the loop.
  • Languages used were both F# and C# running on Linux (Mono 2.8.0) and Windows (Microsoft.NET 4.0)
  • Benchmark runtime: 60 seconds for each mode.
  • Car engine not running.
  • SSM2 via Serial: standard 4800 baud. Request message: 80 10 F0 11 A8 00 00 00 08 00 00 0D 00 00 0E 00 00 0F 00 00 10 7B
  • SSM2 via CAN (ISO 15765) : 500 kbit. Request message: 00 00 07 E0 A8 00 00 00 08 00 00 0D 00 00 0E 00 00 0F 00 00 10

Results

Tests were performed on a 2009 Forester 2.0 Turbo Diesel.
OBD-II interface used was Tactrix Openport 2.0 with latest firmware.

Protocol Response messages within 60 seconds runtime Samplerate [samples/second]
SSM2 via Serial 313 5.22
SSM2 via CAN 5991 99.85

→ CAN speed improvement = 5991/313 = 19.14 times faster.

Benchmarks written in C# vs. F# and running these on Linux vs. Windows did not make any performance difference which is good. Laptop (medium speed, dual core) never had maximum CPU utilization.
All response messages were valid, there haven’t been any errors as usual.

Benchmark Code F# Version

This is the non-optimized F# version. Results compared to well coded C# showed no performance differences.
Used libraries will be open-sourced in the future. Public APIs need improvement, for F# use cases in particular, we’re just lacking developers to get everything done.


#light

open System
open System.Collections.Generic
open Subaru
open Subaru.SSM2

type Benchmark (ipt : J2534.IPassThruV0404, device : Device) =

  member b.Run(mode : ConnectionMode, secondsToRun : int) =
    printfn "Benchmark ConnectionMode = %s | secondsToRun = %d" (mode.ToString()) secondsToRun  
    if secondsToRun < 0 || secondsToRun > 3600 then
      failwith "secondsToRun out of range"

    let mutable count = 0    
    use conn = Ssm2Connection.Create(ipt, mode, device)
    if not (conn.Open()) then
      failwith "Could not open connection!"
    else
      let addresses = [|0x8; 0xD; 0xE; 0xF; 0x10 |]        // int[] array
      
      let millisecondsToRun = int64(1000 * secondsToRun)
      let sw = System.Diagnostics.Stopwatch.StartNew()
      while sw.ElapsedMilliseconds < millisecondsToRun do
        addresses |> conn.ReadAddresses |> ignore
        count <- count + 1         
      sw.Stop()
    
      let sampleRate = float count / (0.001 * float sw.ElapsedMilliseconds)    
      printfn "Elapsed = %s | Count = %d | Samplerate = %f" (sw.Elapsed.ToString()) count sampleRate
    count

do
  Console.WriteLine("SSM2 Benchmark in F#")  
  let seconds = 60

  use passThruDevice = new J2534.Device.OpenPort20Dll()  
  let bm = new Benchmark(passThruDevice, Device.EngineControlUnit)
    // run shortly to JIT (just-in-time) compile any required code
  bm.Run(ConnectionMode.SSM2viaSerial, 1) |> ignore
  bm.Run(ConnectionMode.SSM2viaCAN, 1) |> ignore
    // now the real tests
  let countSerial = bm.Run(ConnectionMode.SSM2viaSerial, seconds)
  let countCan = bm.Run(ConnectionMode.SSM2viaCAN, seconds)
  
  let factor = float countCan / float countSerial
  printfn "CAN/Serial speed factor = %f" factor
  ()

SSM2 via CAN

Link to page: SSM2 via CAN