Here’s my code for testing K-line for ISO 14230 fast initialization. It’s quite simple and really is no use for anything at this point. I’m hoping to advance this piece of code but currently I’m busied by studies and work all along with my family life. It first lights up some LEDs (using only the 5 LEDs, without RGB-LED because I had to mod my M2 a bit after accidentally using a bit too short cable and cracking up the micro-USB port). I’m hoping to buy a new M2 with the ESP32 at some point in order to work better without the hassle with cables.
But to come to the code here’s how it works. It contains four extra functions, two for serial communications, one for initializing with the fast initialization and one for creating a checksum. This code worked with my car to establish a connection and then send a message I really can’t remember what it is. It’s been quite a while since I wrote the code so I can’t remember which command I used but it should show how it typically works to communicate over ISO-14230. I once had some code that established the connection and then terminated it for it wasn’t required to keep up the communication any longer than that for securing the proper working of the code. I was able to receive a stop communication positive response.
The start communication request is sent first by triggering the K-line LOW for 25 ms, then HIGH for 25ms and then sending the start communication request (0xC1, 0x33, 0xF1, 0x81, checksum) (checksum calculated with online calculator: 0x9A, but for communications the checksum created by the code did work well). Currently it only checks the checksum and is forced to skip it if it’s wrong. What it checks is the fourth byte which is the positive response. According to the ISO14230-2 the fifth byte is the response byte but according to the ISO14230-4 the OBD communications shall not use the additional length byte (normally the fourth byte).
Also remember the requirement of the two functions which change the way the serial pins are used. They are REQUIRED for M2 to work properly because of the way the processor was built. You won’t be able to start serial communications if you won’t trigger the pins.
If someone wishes to learn more about ISO14230 communications I may be able to help for I have a copy of these documents. I hope someone will find some time to further improve the K-line communication on the M2. I will try to find some time on some point but currently I’m too occupied by other things. If someone needs help I can try to find the time to read the forum and help as much as I can. I hope someone tries out the sketch because then we can confirm it works on cars with fast initialization.
The code could be extended with functionality for 5 baud initialization as well but that would need quite a bit of modification for the code. Easiest way would be to edit the OBD9141 library’s initialization function because it already works. Only that I can’t confirm whether it works or not on a car because I don’t have a vehicle to test it on. If someone needs that I can try to build a working initialization sequence but it will require someone who has a car that uses slow initialization. If you are not sure whether your car uses ISO9141 or ISO14230 but have a K-line connection you could try OBD9141 and this sketch to try initialization. If it works on neither it could be the 5 baud initialization quite near the OBD9141 initialization sequence only with different key codes. If that happens to you you may feel free to contact me for a working sketch. Debugging sketch will be really simple by modifying the OBD9141 code so it’ll be a fast debug process. I can’t build a complete one for communication because I’m not a “real” programmer. I understand how code works in some manner and am able to build my own but I really don’t have enough of education for building a whole library with code simple enough. I’d be glad if I could help someone out.
#include <Arduino.h>
#define DEBUG
int KLineBaudrate = 10400;
byte stopCommunicationRequest[8] = {0xC1, 0x33, 0xF1, 0x82};
void setup() {
pinMode(DS7_RED, OUTPUT);
analogWrite(DS7_RED, 2500);
pinMode(PS_J1850_9141, OUTPUT);
digitalWrite(PS_J1850_9141, HIGH);
pinMode(LIN_KSLP, OUTPUT);
digitalWrite(LIN_KSLP, HIGH);
pinMode(LIN_KRX, INPUT);
digitalWrite(LIN_KRX, HIGH);
pinMode(LIN_KTX, OUTPUT);
digitalWrite(LIN_KTX, HIGH);
pinMode(LIN_LSLP, OUTPUT);
digitalWrite(LIN_LSLP, HIGH);
pinMode(LIN_LTX, OUTPUT);
digitalWrite(LIN_LTX, HIGH);
pinMode(DS2, OUTPUT);
digitalWrite(DS2, HIGH);
pinMode(DS3, OUTPUT);
digitalWrite(DS3, HIGH);
pinMode(DS4, OUTPUT);
digitalWrite(DS4, HIGH);
pinMode(DS5, OUTPUT);
digitalWrite(DS5, HIGH);
pinMode(DS6, OUTPUT);
digitalWrite(DS6, HIGH);
#ifdef DEBUG
SerialUSB.begin(19200);
while(!SerialUSB);
SerialUSB.println("Beginning program!");
#endif
}
void loop() {
digitalWrite(DS2, LOW);
bool initialized = 0;
if (initialized == 0){
initialized = KLineInitializeFast();
}
while (initialized){
// Looping after initialization
byte buf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
digitalWrite(DS6, LOW);
delay(50);
Serial1.write(0xC2);
Serial1.write(0x33);
Serial1.write(0xF1);
Serial1.write(0x01);
Serial1.write(0x0D);
Serial1.write(0xF4);
delay(5);
Serial1.readBytes(buf, 6);
for (int i = 0; i < 6; i++){
buf[i] = 0x00;
}
Serial1.setTimeout(50);
Serial1.readBytes(buf, 8);
for (int i = 0; i < 8; i++){
SerialUSB.print(buf[i], HEX);
SerialUSB.print(" ");
}
SerialUSB.println();
delay(2000);
for (int i = 0; i < 4; i++){
Serial1.write(stopCommunicationRequest[i]);
}
Serial1.write(createChecksum(stopCommunicationRequest, 4));
delay(5);
Serial1.readBytes(buf, 5);
for (int i = 0; i < 5; i++){
buf[i] = 0x00;
}
Serial1.setTimeout(50);
Serial1.readBytes(buf, 8);
for (int i = 0; i < 8; i++){
SerialUSB.print(buf[i], HEX);
SerialUSB.print(" ");
}
SerialUSB.println();
delay(2000);
}
#ifdef DEBUG
SerialUSB.println();
SerialUSB.println();
SerialUSB.println();
#endif
digitalWrite(DS2, HIGH);
digitalWrite(DS3, HIGH);
digitalWrite(DS4, HIGH);
digitalWrite(DS5, HIGH);
digitalWrite(DS6, HIGH);
}
bool KLineInitializeFast(){
digitalWrite(DS4, LOW);
#ifdef DEBUG
SerialUSB.println("Fast Initialization.");
#endif
byte buf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
KLineBaudrate = 10400;
digitalWrite(LIN_KTX, HIGH);
digitalWrite(LIN_LTX, HIGH);
#ifdef DEBUG
SerialUSB.println("Delaying...");
#endif
delay(300); // Must delay the W5min time (300 ms)
#ifdef DEBUG
SerialUSB.println("Sending the initialization sequence, then the StartCommunication request.");
#endif
digitalWrite(LIN_KTX, LOW);
digitalWrite(LIN_LTX, LOW);
delay(25);
digitalWrite(LIN_KTX, HIGH);
digitalWrite(LIN_LTX, HIGH);
delay(25);
KLineBeginSerial(KLineBaudrate);
Serial1.write(0xC1);
Serial1.write(0x33);
Serial1.write(0xF1);
Serial1.write(0x81);
uint8_t forChecksum[4] = {0xC1, 0x33, 0xF1, 0x81};
Serial1.write(createChecksum(forChecksum, 4));
SerialUSB.print("Checksum to send: ");
SerialUSB.println(createChecksum(forChecksum, 4), HEX);
delay(5);
Serial1.readBytes(buf, 5);
for (int i = 0; i < 8; i++){
buf[i] = 0x00;
}
Serial1.setTimeout(50);
Serial1.readBytes(buf, 8);
#ifdef DEBUG
for (int i = 0; i < 8; i++){
SerialUSB.print(buf[i], HEX);
SerialUSB.print(" ");
}
SerialUSB.println();
SerialUSB.print("Checksum created: ");
SerialUSB.println(createChecksum(buf, 7), HEX);
#endif
if (buf[6] == createChecksum(buf, 6)){
if (buf[3] == 0xC1){
return 1;
}
} else{
if (buf[3] == 0xC1){
return 1;
}
}
return 0;
}
void KLineBeginSerial(unsigned int baudrate){
g_APinDescription[LIN_KRX].pPort -> PIO_PDR = g_APinDescription[LIN_KRX].ulPin;
g_APinDescription[LIN_KTX].pPort -> PIO_PDR = g_APinDescription[LIN_KTX].ulPin;
Serial1.begin(baudrate);
}
void KLineEndSerial(){
g_APinDescription[LIN_KRX].pPort -> PIO_PER = g_APinDescription[LIN_KRX].ulPin;
g_APinDescription[LIN_KTX].pPort -> PIO_PER = g_APinDescription[LIN_KTX].ulPin;
Serial1.end();
}
uint8_t createChecksum(uint8_t message[8], int lengthOfMessage){
uint8_t checksum = 0;
for (int i = 0; i < lengthOfMessage; i++){
checksum += message[i];
}
return checksum;
}