Subaru and Arduino: SSM1 protocol. Handshake

Initial data




A board called Carduino Nano v7 came to me recently. And somehow it suddenly coincided that at about the same time on the panel of my car, I was surprised to find a burning Check Engine light. “This is not without reason,” I thought, and went deeper into the search. It turned out that errors can be read without additional devices - self-diagnosis in Foresters is very simple and accessible to anyone. And then here is the Arduino? And despite the fact that a direct consequence of the search for diagnostic information was the discovery of the existence of such a funny thing as the Subaru Select Monitorversion 1, the protocol support of which (funny thing) is equipped with old Subaru cars, even before the K-line appeared in them. It is to these cars that my Forester belongs. So I got a mischievous thought - to implement some kind of on-board computer on the Arduino. I saw similar projects with an appeal to the K-line, but with SSM1 - only a couple of videos on YouTube, no specifics. Therefore, you have to do everything yourself.

SSM1 Protocol Summary


Baud rate 1953 baud (1953-8 E 1). The computer takes a command to read data and begins to pour in response data from the requested address until it receives a command to stop. To write data to an address, you must first read the data at the same address. To request an ECU identifier, you must first read the data from any address.

Teams




In response to data read and write commands, the following data packet comes in:


And again Forester


Despite the fact that my car has an OBD2 connector, it has the complete absence of a “K-line” contact.

  • Pin 4 - Body Ground
  • Pin 5 - Signal Ground
  • Pin 6 - CAN-High Line, J-2284
  • Pin 7 - K-line diagnostics (ISO 9141-2 and ISO / DIS 14230-4)
  • Pin 9 - SSM Clock
  • Pin 11 - SSM Clock
  • Pin 12 - SSM to ECM - data line from the SSM dealer diagnostic tool to the computer
  • Pin 13 - ECM to SSM - data line from the computer to the SSM dealer diagnostic tool
  • Pin 14 - CAN-Low Line, J-2284
  • Pin 15 - Diagnostic L-Line (ISO 9141-2 and ISO / DIS 14230-4)
  • Pin 16 - +12 battery power

In the connector of my car involved 4 contacts - 4,5,12,13 and 16.

One, two, three, four, five - we begin to pair


The donor for the OBD2 connector was the ELM327 adapter, purchased from the Chinese brothers, but absolutely useless for my Forester. An autopsy showed that almost all the legs, except those that are needed, are soldered for use in the ELM itself. In order not to burn the ports on the arduino, we will connect the legs with data (12 and 13) through the resistors - I used 240 Ohm resistors. We connect the earth to both legs with the earth (4 and 5). Arduino will be powered by the cigarette lighter via a USB adapter.

So, we use 3 wires:


In theory, it would be possible to stop on this, sew a sketch of type Arduino

void setup()
	{
	    pinMode(0, INPUT);
	    pinMode(1, OUTPUT);
	}
	void loop() 
	{
	}
	

and by connecting the Arduino to the laptop, use it like a regular USB-Subaru lanyard with programs like EvoScan and SelectMonitor. But the main idea was precisely the on-board computer, so let's continue.

Compose a sketch


Since the word “handshake” is taken out in the title of this article, we restrict ourselves to the handshake between Forester and Arduino - we will read the ROM ID of the car. In order to limit ourselves to the already assembled design, we read the ROM ID we read through by the built-in Arduino LED, designating 1 as a long flash and 0 as two short flashes.

So, according to the actions:
  1. Set the UART exchange mode 1953-8E1
  2. For 3 seconds, turn on the LED
  3. We extinguish the LED and wait 2 seconds
  4. Request ROM ID
  5. We flush ROM ID with the built-in Arduino LED

I had to google a little more how to explain to Arduino that I needed parity, and, as a result, I got this sketch:

int led = 13;
void setup()  {
  byte romid[3];
  // Устанавливаем скорость обмена
  Serial.begin(1953);
  // Включаем контроль четности: Even Parity
  UCSR0C = ( UCSR0C & ~_BV(UPM00) | _BV(UPM01) ); 
  pinMode(led, OUTPUT);
  // Зажигаем светодиод на 3 секунды
  digitalWrite(led, HIGH);
  delay(3000);
  // Гасим светодиод и ждем 2 секунды
  digitalWrite(led, LOW); 
  delay(2000);
  if (ECU_GetROMID(romid))  // Если ROM ID все-таки прочитали,
  {
    for (int i=0;i<3;i++) {
      show_byte(romid[i]);  // То промигаем его светодиодом
    }
  }
}
void loop() {
  // а здесь нам ничего не надо
}
void show_byte(byte b) {
  for (int i=7;i>=0;i--) {
    if (bitRead(b,i)==1) {     
      digitalWrite(led, HIGH);
      delay(1000);
      digitalWrite(led, LOW);
      delay(1000);
    } else {
      digitalWrite(led, HIGH);
      delay(300);
      digitalWrite(led, LOW);
      delay(200);
      digitalWrite(led, HIGH);
      delay(300);
      digitalWrite(led, LOW);
      delay(1200);
    }
  }
}
void ECU_Stop() {
  byte txbuf[4]={0x12,0x00,0x00,0x00};
  Serial.write(txbuf[0]);
  Serial.write(txbuf[1]);
  Serial.write(txbuf[2]);
  Serial.write(txbuf[3]);
  delay(50);
  Serial.flush();
}
boolean ECU_GetROMID(byte * buffer) {
  char readCmd[4] ={0x78,0x00,0x00,0x00};
  char romidCmd[4]={0x00,0x46,0x48,0x49};
  char romid[3]   ={0};
  ECU_Stop();
  Serial.write(readCmd[0]);
  Serial.write(readCmd[1]);
  Serial.write(readCmd[2]);
  Serial.write(readCmd[3]);
  int retries = 0;
  while (retries<8) {
    int nbytes = Serial.readBytes(romid,3);
    if ((nbytes == 3) && (romid[0]!=0x00))
      break;
    Serial.write(romidCmd[0]);
    Serial.write(romidCmd[1]);
    Serial.write(romidCmd[2]);
    Serial.write(romidCmd[3]);
    ++retries;
  }
  ECU_Stop();
  buffer[0] = romid[0];
  buffer[1] = romid[1];
  buffer[2] = romid[2];
  if (romid[0] == 0x00) {
    return false;
  }
  return true;
}


Result


Fill this sketch into Arduino, get down into the car, plug in the OBD2 connector, turn on the ignition, turn on the power to the Arduino and ... start driving the zeros and ones into the phone, because we took nothing with us. Arduino cheerfully missed the combination for me 1010 0011 0000 0001 0001 0111, which in translation into universal means 0xA30117- this is the ROM ID of my Forester. “Well hello 0xA30117! My name is Roman. ”

Afterword


Unfortunately, for most vehicles with SSM1 support, at best, only 18 addresses of important parameters are known - such as battery voltage, engine speed and more. Therefore, the work is still an unplowed field - reading a memory dump, searching for addresses with errors, etc. Well - there is still something to strive for ...

Materials used


SSM1 protocol information SSM1
discussion, RS232-SSM1 and USB-SSM1 adapter circuit information

Also popular now: