/OBD9141

A class to read an ISO 9141-2 port found in OBD-II ports.

Primary LanguageC++MIT LicenseMIT

OBD9141

This is a library to read data from the OBD-II port through the K-line pin using either ISO 9141-2 or ISO 14230-2 (KWP).

There are numerous projects which read data from the diagnostic port and display or record this. However, I found that most of these projects either use an ELM327 chip or the communication code is interwoven with the rest of the program. This makes it hard to extract the communication parts for use in another project.

The goal of the library is to provide a simple class which handles the communication with the port. Additionally a second class has been created which can simulate responses for testing purposes.

Usage

The code has been developed using Teensy 3, the K-line transceiver IC's used were during the development were the MC33290, SN65HVDA100 and SN65HVDA195. All three transceiver IC's worked without problems when the typical application circuit from the datasheet was used. The OBD9141 class itself has been tested on one Kia car build in 2004.

For the Teensy 3.x or LC versions it is recommended to use one of the HardwareSerial ports. For use with Arduino the AltSoftSerial library is used by default. The example reader_softserial was tested with an Arduino UNO. The KWP functionality of this library was verified to work on a Teensy 3.5.

A minimal example of how to use the SN65HVDA195 chip mentioned is given by the following schematic: Schematic of circuit using SN65HVDA195

The EN pin can either be connected to a pin on the microcontroller or just pulled high in order to always enable the chip.

In the logic folder are some recordings made with a Saleae logic analyzer, these show the state of the K-line pin using either a Bluetooth OBD-II reader or this library, these might be useful when developing your own hardware. All timing parameters can be tweaked from the header file, by tuning these parameters, performance of up to 20 requests per second has been achieved (on the same car, 6 readings per second was the maximum with the Bluetooth dongle).

Three examples are given in the example folder. The reader and simulator examples are to be used with a hardware serial port. The reader_softserial example shows how to use it with the AltSoftSerial library. For more information on how to use the library, refer to to the header files.

Timing

Several parameters related to timing are given by the specification, some others are beyond our influence. To understand how a request works, lets consider the case the 0x0D PID is requested, this represents the vehicle's speed. Timing diagram of a request

Requesting the value of a PID consists of two phases, the first is the request phase the second the response.

In the first phase, the bytes necessary for the request are written on the Tx line, according to the specification there should be a 5 millisecond delay between each symbol. The duration of this delay is defined by INTERSYMBOL_WAIT. It is possible that the ECU still discerns the bytes correctly when this delay is lowered.

The transceiver IC puts the waveform seen on the Tx line on the K-line. However, a echo of this waveform is also provided as output of the transceiver IC and is seen on the Rx of the serial port. Because this is not part of the response we have to deal with this echo. This is done by using the readBytes method to read the same number of bytes as were sent during the request. The timeout used for this read is given by (REQUEST_ECHO_TIMEOUT_MS * sent_len + WAIT_FOR_ECHO_TIMEOUT) milliseconds, where sent_len is the number of bytes sent in the request. Because the serial port used should contain a hardware buffer, very little time is spent in this readBytes call, as all the bytes from the echo should already be available and the function returns when the requested number of bytes has been read.

After the echo has been read, the waiting game begins as we wait for the ECU to answer. According to the specification this is atleast 30 milliseconds, this duration (which is the major part of a request duration) is something that cannot be influenced. The timeout set to read the response is given by (REQUEST_ANSWER_MS_PER_BYTE * ret_len + WAIT_FOR_REQUEST_ANSWER_TIMEOUT) milliseconds, ret_len represents the number of bytes expected from the ECU. Because this number is known beforehand the readBytes method can be used. According to the specification the ECU should also pause between sending the bytes, but this is not necessarily the case.

The number of bytes to be received for each phase is known beforehand so the readBytes method can be used; it ensures that we stop reading immediately after the expected amount has been read. The main impact on the performance is given by the time the ECU takes to send a response and the INTERSYMBOL_WAIT between the bytes sent on the bus. There is no delay parameter for the minimum duration between two requests, that is up to the user.

Trouble codes

The library supports reading diagnostic trouble codes from the ECU (the ones associated to the malfunction indicator light). This was made possible with extensive testing by Produmann, under issue #9.

Contrary to reading the normal OBD PID's, when trouble codes are read from the ECU the length of the answer is not known beforehand. To accomodate this a method is implemented that handles a variable length request to the ECU. In this variable length response, each trouble code is represented by two bytes. These two bytes can then be retrieved from the buffer and converted into a human readable trouble code with letter and 4 digits (for example P0113), which can then be printed to the serial port. An example on how to read the diagnostic trouble codes is available, see readDTC. Increasing the buffer size OBD9141_BUFFER_SIZE in the header file may be necessary to accomodate the response from the ECU.

The following trouble-code related modes are supported: Reading stored trouble codes (mode 0x03), clearing trouble codes (mode 0x04) and reading pending trouble codes (mode 0x07).

ISO 14230-2 (KWP)

The ISO 14230-2 protocol uses the same physical layer as 9141-2, the support for this protocol was developed under issue #11. If initKWP() is called instead of init() the KWP protocol is used for all requests onward. The provided functionality should be the same regardless of the protocol used. A sketch that just tests the KWP functionality is available readerKWP.

License

MIT License, see LICENSE.md.

Copyright (c) 2015 Ivor Wanders