OBDII fast init detection

I am developing an OBDII simulator using an Uno so that I can use as a test system to develop another Uno to read the OBDII data from the simulator before plugging it into a vehicle.

This is my first Uno project and I am fine with all the serial comms but I am struggling to find out how to detect what is known as the fastinit sequence for OBDII.

The fastinit sequence consists of bringing the serial tx line high for a period > 300ms then low for 25ms and then high again for 25ms, at which point the vehicle OBD is awake and switches to 10400 baud.

In my tester code I can send the fastinit sequence like so but my question is how would I detect this fastinit sequence in my simulator?

Reading around the topic I think the solution involves adding an interrupt handler to the RX pin and then

  • check that the RX pin is HI (according to spec pin should idle HI)
  • and then wait for it to change LO and check that the elapsed time > 300ms
  • and then wait for it to change HI and check that 25ms has elapsed
  • and then wait for 25ms and check it is still HI and switch 10400 bause
include <SoftwareSerial.h>

#define K_IN   8
#define K_OUT  9

SoftwareSerial obdSerial(K_IN, K_OUT);

byte initStep = 0;
unsigned long initTime = 0;

setup() {
    initStep = 0;
    initTime = 0;
}

loop() {}
    unsigned long currentTime = millis();

    switch (initStep) {
        case 0: 
            initTime = currentTime + 300;
            initStep++;
            break;
        case 1:
            if (currentTime >= initTime) {
                digitalWrite(K_OUT, HIGH);
                initTime = currentTime + 300;
                initStep++;
            }
            break;
        case 2:
        case 3:
            if (currentTime >= initTime) {
                digitalWrite(K_OUT, (initStep == 2 ? LOW : HIGH));
                initTime = currentTime + 25;
                initStep++;
            }
            break;
        case 4:
            if (currentTime >= initTime) {
                // switch now to 10400 baud
                obdSerial.begin(10400);
            }
            break;
    }
}

This is my first Arduino project and I am find with all the serial comms but the one thing I cannot figure out is how to detect what is called the facinit sequence in my simulator.

The fastinit / wakeup sequence consists of bringing the serial tx line high for a period > 300ms then low for 25ms and then high again for 25ms. At which point the OBD is awake and switches to 10400 baud.

The code to simulate this from the OBD Tool side is shown below. Now I can read the TX line from the OBD simulator side and then check it after so many ms to see if it is maintaining the signal, but it could go up and down in the meantime. I believe there is a mechanism to detect a change in signals but I cannot figure it out

Reading around the topic I think the solution involves adding an interrupt handler to the RX pin

The SoftwareSerial class already has an interrupt handler on the RX pin. It really sounds to me like you need a lower level (i.e. the SoftwareSerial level) plan to read the OBDII data.

PaulS:
The SoftwareSerial class already has an interrupt handler on the RX pin. It really sounds to me like you need a lower level (i.e. the SoftwareSerial level) plan to read the OBDII data.

I think you are right … I was thinking something like this might be on the right path … does it look plausible or am I missing your point?

#define RX_PIN 9

byte init_state= 0;
long last_change = 0;

setup() {
    init_state= 0;
    last_change = millis();
    attachInterrupt(RX_PIN, handle_interrupt, CHANGE);
}

loop() {
    if (init_state == 3) {
        // fastinit has completed
    }
}

void handle_interrupt() {
    bool pin = digitalRead(RX_PIN);
    long delta = millis() - last_change
    if (init_state == 0 && delta > 300 && pin == 0) {
        // pin went from HI > LO after 300ms
        init_state = 1;
        last_change == millis();
    }
    if (init_state == 1 && diff >= 24 && diff <= 26 && pin == 1) {
        // pin went from LO > HI after 25ms
        init_state = 2;
        last_change = millis();
    }
    if (init_state == 1 && diff >= 24 && diff <= 26 && pin == 1) {
        // pin went from HI> LO after 25ms
        init_state = 3;
        last_change = millis();
        obdSerial.begin(10400);
    }
  



}

I can read the OBDII data fine after the fastinit handshake when it is just doing serial command at 10400 baud.

What I want to be able to do is detect the fastinit sequence in the simulator where no data is being transmitted (so there is no baud rate) but the RX pins is being held high for greater than 300ms then LO for 25ms and then HI for 25ms.

All ECUs which are initialised must use a baud rate of 10400 baud for initialisation and communication. The tester transmits a Wake up Pattern (WuP) on “K- and L-Line” synchronously. The pattern begins after an idle time on “K-line” with a low time of T iniL . The tester transmits the first bit of the StartCommunication service after a time of t WuP following the first falling edge.

So no data is being transmitted it is just a sequnce of HI / LO values on the RX ping with specific timings, because of this I cannot use Serial.available()

I thought there might be a way to detect a change in the signal on the RX pin and then I could use the millis() function and some sort of state engine to see if the pattern of changes matches the fastinit sequence within a few ms.

Specifically I am referring to the Wakeup pattern in my original post.

does it look plausible

To me? To the compiler? Or, to the Arduino? Only one of them really matters.

PaulS: To me? To the compiler? Or, to the Arduino? Only one of them really matters.

Hmm ... I guess I was hoping that someone might chip in and say "Nope that's not gonna work, or here's a better idea", but in retrospect I should probably just try it and see if it works.

I have just read further and the attachInterrupt call can only be used on the hardware serial on an Uno :) which I think will make development harder since I planned to use the USB serial for debugging output.

I will dig further and just report actual issues rather than "Would this work?" type questions.

Thanks

I have just read further and the attachInterrupt call can only be used on the hardware serial on an Uno

What? attachInterrupt() defines what function to call when the appropriate event happens on an external interrupt pin. The hardware serial pins are not external interrupt pins.

On the other hand, pin 9 isn't either. You will need to use pin change interrupts (there is a library for that), not attachInterrupt().

What? attachInterrupt() defines what function to call when the appropriate event happens on an external interrupt pin. The hardware serial pins are not external interrupt pins.

Oops :)

Thanks Paul, I did read the docs for attachInterrupt() but somehow I misread the hardware serial TX and RX pins as 2 and 3, probably from too many years soldering cabling for Wyse50 terminals with RS232/DB25 plugs :)

So according to the docs pins 2 and 3 are available for interrupts on an UNO and I could use the CHANGE mode to detect the fastinit sequence on one these pins. Then when I have detected the the fastinit sequence I can then configure the pins with softserial to communicate at 10400 baud.

So according to the docs pins 2 and 3 are available for interrupts on an UNO and I could use the CHANGE mode to detect the fastinit sequence on one these pins. Then when I have detected the the fastinit sequence I can then configure the pins with softserial to communicate at 10400 baud.

That might work. Try it and see.