Arduino LIN using software Serial

Hello everyone ! I have read various projects regarding this in the forum, but all where closed so i had to make a new topic.

I am trying to use an Arduino to just sniff, the LIN bus of my vehicle's ( opel insignia) HVAC system

As many people have suggested, i have made a simple voltage divider to downscale the 12 to 5v , and just use the software serial to receive and dump the bytes received.
currently i am facing two issues:

The LIN frame consists of a break (14+bits) , and a sync field (fixed value of 0x55)

  • i cant seem to understand how to detect this break on the serial line. most people argue that it dosent even show up in the serial buffer since it dosnet have start and end characters , so you just have to look for a zero.

-no matter if i try 9600 or 19200 baud, i cant seem to be able to receive a byte 0x55 ...

i do receive repeating patterns , and i have managed to correlate some changes in this patterns, to changes on my HVAC controls.

Anyone has any previous experience with this ?
i am not posting any code because i am looking for a more generic guidance..
all the libraries i have found are based on a transceiver IC which is a road i would be happy to go with, but i dont have access to any such chips currently here , and i would like to have an idea of what i am doing before ordering .

thanks!

No experience. Anything useful in arduino lin bus - Google Search ?

Do you see 0x55 in the data that you receive? I would start by checking that.

It will indeed not show up in the serial buffer. You can detect a falling edge on the receive pin, next detect the rising edge and measure the time between them. At 9600 baud, it should be longer than 14 * 1000000 / 9600 microseconds.

Once you know that the break is finished, you can do the detection of 0x55.

char ch = Serial1.read();
if(ch == 0x55)
{
  possible start of LIN packet
  read the rest of the LIN packet
}

Above for a board with a secondary UART; else you will have to use software serial.

thanks for the reply !
yes, i have done allot of research in googling prior to posting !

Sadly no, i never see the 0x55 value. i see many others , but never this one . even if i just leave it there to receive, and look for a 0x55, it will never show up !

but if the break dosent show in the serial, and since the protocol says that the first byte after the break, is always 0x55, shouldent i be seeing this value, even without specifically looking for the break ??

i will try your suggestion though ! i have also tried different baudrates (All of them actually) , but to no avail

i actually tried the following which i guess is the lamest way ever to detect a pulse :

while (digitalRead(LinPin) == 1){} //detect a falling edge
  micro_fall = micros();
  while (digitalRead(LinPin) == 0){} //detect a rising edge
  micro_rise = micros();
  pulse_dur = micro_rise - micro_fall;

  // 4 ,8 , 80 , 280 ,360,800
  if (pulse_dur > 700){
    LINBusSerial.begin(9600);
    b  = LINBusSerial.read();
    LINBusSerial.flush();
    Serial.print("found a pulse of duration: ");
    Serial.println(pulse_dur);
    Serial.print("and received :");
    Serial.println(b,HEX);
  }

i found various pulse durations but the biggest one was at ~800micros,
which is almost in track with the 14 * 1000000 / 19200 for 19Kbps

but with that , i still get as first byte, usually something like 0x26, or 0x80 ..

which are also the most common bytes, if i just read the serial, without looking for the break

Would a Can bus shield also work for the Lin bus and take care of all this ??

That should be in setup() and unconditional.

After that, I would write a simple loop() that just reads the LINBus (no break detection).

```cpp
if(LINBusSerial.available()!=0)
{
  byte b = LINBusSerial.read();
  Serial.println(b, HEX);
}

Set the Serial (not LINBusSerial) baudrate to e.g. 115200 (and adjust serial monitor).
Maybe you already tried it, but are there any 0x55 in there?
// Edit
You did try it; so what are the results (show them in code tags). Any chance that the bus is inverted?
// end edit

This is useless for a receiver; it flushes the output buffer, not the input buffer. Try below instead of the flush().

while(LINBusSerial.available()!=0)
{
  LINBUsSerial.read();
}

hammy , well it could ,as would a LIN shield, but as i sed i am trying to figure a way to work without

well , that was my initial attempt figuring that since no one mentions anything more special, that would be it. but unfortunately i never see this 0x55 character...

quite literally the code you wrote :

setup(){
    LINBusSerial.begin(9600);
}

loop(){
  if(LINBusSerial.available()!=0)
  {
    byte b = LINBusSerial.read();
    Serial.println(b, HEX);
 }
}

i have tried with all the baud rates, from 300 to up to 115200 but haven't seen 0x55 ever..

hey so today i tried this:
modified the arduino to work a bit like logic analyzer with the following code

int LinPin  = 2;  


void setup() {
  Serial.begin(115200);
  pinMode(LinPin,INPUT);
}

unsigned long micro_fall;
unsigned long micro_rise;
unsigned long pulse_dur ;

#define tsize 1024
bool val[tsize];
void loop() {

  while (digitalRead(LinPin) == 1){} //detect a falling edge
  micro_fall = micros();
  while (digitalRead(LinPin) == 0){} //detect a rising edge
  micro_rise = micros();
  pulse_dur = micro_rise - micro_fall;

  if (pulse_dur>700){
    for (int i = 0 ; i <tsize ; i++){
      val[i] = digitalRead(LinPin);
    }
    
    for (int i = 0 ; i <tsize ; i++){
      Serial.println(val[i]);
    }
    while(1){}

  }
}

I worked with the assumption that each digitalRead costs ~5 microseconds.
saddly arduino dosent have that much space so i was limited to just ~1500 measurments, and this is why i tried to measure what happens after the "pause".

plotting them i get something like this :

  1. it definetly shows a 10101010 pattern , (0x55) , as LIN is supposed to... so why my serial read does not read that but instead something else? >_>
    this pattern is irelevant of my , assuming 5micros delay.

  2. measuring the bit duration, i get ~100microsec per bit , which is in track for the 9600baud rate...
    but my pause is ~800micros , which is in track for the 19200 Baud rate... but maybe my assumption for the 5micros is wrong.

any ideas ? :stuck_out_tongue:

technically yes, but its the master who does that. i just want to sniff the packets send and received by the master.

so in baud 9600, on small hex dump:

serial enabled succesfully!
28
FD
0
95
D4
80
80
80
80
80
80
80
80
8B
0
95
F5
80
80
80
80
8A
0
95
B6
98
3F
4
80
80
88
EA
0
95
D4
80
80
80
80
80
80
80
80
8B
0
95
F5
80
80
80
80
8A
0
95
B6
98
3F
4
80
80
88
EA
0
95
D4
80
80
80
80
80
80
80
80
8B
0
95
F5
80
80
80
80
8A
0
95
B6
98
3F
4

the most prominent value is "0x80" , which in bin is 10000000

Sorry - I just deleted my post before I noticed you had replied ( as I re read and saw you were just sniffing the bus on an active system ) , so my message was irrelevant .

so , in whatever logic analyzer i look, i see ~9600 baud, and i also see this 0x55 value.
but not on serial of arduino..
So i am starting to think that maybe i got an electrical issue ?

i have used a voltage divider, with rather high values (R1 10K and R2 6K) to scale down the car voltage to 5v . Issue is , car voltage is not stable, so i cant be presciese with this values.. my osciloscope shows ~3.5 - 4 V on the arduino side.

I couldent use lower values , becouse then the cars LIN would turn-off, propably becouse of overcurrent ??

maybe these high values effect high times, and/or slopes ?? any ideas on that ? unfortunately on this wiring part i have no clue

hey !
so some progress, in case someone bumps here in the future :

my main issue, was that the Baud rate that my car used , was not a standarized one..
for instance baud of 9600 requires bittime of 104uS.

but following LIN protocol to the letter, and using the SYNC byte to calculate the baudrate, at least in my car , resulted in bittime of 95uS !!

apart from that, i still havent figured out how could the software library deal with the syncbreak
(13ccs of LOW in line). i ended up writing some polling based serial library .
after that i started seeing some stuff that made sense!

do you guys know if i can set a completely custom baud rate for the software serial library ?