Bit bang 5 baud with BS2 (on OBD2 ISO 9141)

n00bn00b Posts: 5
edited March 2012 in BASIC Stamp Vote Up0Vote Down
Hi all,

This is my first time posting on the forum. I've used the BS2 since 2005 but have not really done a lot with serial communication using SERIN and SEROUT (other than simple LCD displays).

Now I've got a new fun project which is to interface with the OBD2 connector in my Honda Civic. The difficulty right now lies in initializing the ECU, which requires transmitting HEX 33 at 5 baud.

According to the Stamp manual, the baudmode for the SEROUT command for 5 baud (assume 8 bit no parity inverted) would be 199980 which exceeds 65535, so that won't work. So, I thought I would manually create and time bits via the HIGH and LOW commands (which I later found out is called bit-banging), but I'm not confident that the timing is right and I don't have a scope to verify the signal. PULSOUT will not work either, as the bit length is 200ms (max is 131.07ms on the BS2)

I am using a MAX222 line driver to get the outputs up to RS-232 voltage, so the bit bang is sent through this chip, which probably makes things more tricky. So far I have not been able to get a response from the car's ECU... Though there could be other things wrong, does anyone have experience bit-banging at a super low speed like 5 baud? I'd be interested in knowing if there is a better method to pull this off. Thanks everyone!!!

I'm also surprised I was able to get the username "n00b" on the forums... who would have guessed?



  • 8 Comments sorted by Date Added Votes
  • Mike GreenMike Green Posts: 22,601
    edited March 2012 Vote Up0Vote Down
    Have a look at this website for information on BS2 statement timings. Use the "app-notes" link at the bottom of the page. You should be able to bit-bang at 5 Baud. Post your program and a schematic of your connections. That'll help us help you.
  • n00bn00b Posts: 5
    edited March 2012 Vote Up0Vote Down
    Thanks so much for the info. I will have a read through it and see if I can make some changes to my timing. Here's my code at the moment, before any timing adjustments.

    I'll post a schematic soon with labels. One thing to note is I eliminated the capacitor between pin 5 and 6 on the MAX222 in order to "fake" the output of the chip to 0v/+12v logic. Otherwise, it would follow the +/-12v typical RS-232 logic. This choice is based on other OBD2 ISO 9141-2 interpreting chips which don't seem to go negative voltage. This change seems to have no effect when talking between two MAX222 chips (can send and receive data fine at 10400 baud), but I can't tell if the OBD2 interface likes this or not.

    At this time I'd like to only get feedback on the timing for a 5 baud bit bang... my wiring and voltage levels could have other problems.

    I just don't want to take the easy road out and get an ELM323... If there's a way to initialize the ECU with a BS2 bit bang, I aim to figure it out! Thanks everyone.
    '' {$STAMP BS2}' {$PBASIC 2.5}
    'This program is designed to initialize a 2000 Honda Civic DX FI-ECU.
    'The message sent to the ECU should be HEX 33 (Binary is "00110011") on K line at 5 baud assuming 8 bit no parity inverted
    'The message received by the stamp should be HEX 55 at 10400 baud (8 bits no parity true) which I calculate as baudmode=76
    'MAX222 inverts signal so that is why I use "true" on the polarity
    'It appears from various searches on the internet that ISO9141-2 standard runs on 0v logic high and +12v logic low.
    'pin 2 is BS2 TTL signal being output to MAX222
    'pin 5 is BS2 TTL signal being input from MAX222
    serData VAR Byte                      'define serdata
    LOW 2                                 'set output low to prepare ECU (+12v is logic low)
    PAUSE 6000                            'wait 6 sec for ECU to reset
    DEBUG "Start init sequence...",CR
    HIGH 2                                'start bit 200ms   (Logic high, 0v)
    PAUSE 200
    LOW 2                                 'make output low for 400ms   (Logic low, +12v)
    PAUSE 400
    HIGH 2                                'make output high for 400ms   (Logic high, 0v)
    PAUSE 400
    LOW 2                                 'make output low for 400ms      (Logic low, +12v)
    PAUSE 400
    HIGH 2                                'make output high for 400ms     (Logic high, 0v)
    PAUSE 400
    LOW 2                                 'Stop bit 200ms (Logic low, +12v)
    PAUSE 200
    HIGH 2                                'Make RS-232 output low to prevent collisions
    SERIN 5,76,5000,nodata,[serdata]      'receive 1 byte data on K line within 5 seconds
                                          'should only take up to 300ms to receive according to ISO standards
    DEBUG ? serdata,CR                    'display received data
    nodata:                               'SERIN timeout loop
    DEBUG "no data",CR
  • PJAllenPJAllen Banned Posts: 5,065
    edited March 2012 Vote Up0Vote Down
    Given 5 bps, so that's 200ms/bit.
    Your Start bit is 200ms, your data bits high/low are 400ms ea., and your Stop bit is 200ms.
    Ordinarily, a Start bit takes the same time as a data bit, likewise a Stop bit though they can range up to 1.5 bit times.
    So, I think that your data bits should be 200ms (too).
  • n00bn00b Posts: 5
    edited March 2012 Vote Up0Vote Down
    I thought about this a little more and decided to give a old standby transistor a try at switching. It ended up working. I basically followed the schematic on using TTL input to the base. The bit bang works as is (no special timing needed)

    I think the problem with my setup was the MAX222 simply is not supplying the right voltages for the ISO9141 protocol (0v, +12v). I still plan on posting all the code and (new) schematics once I get a chance. Thanks everyone!!!
  • Tracy AllenTracy Allen Posts: 6,197
    edited March 2012 Vote Up0Vote Down
    PJ, he is using 400 to transmit 2 bits at a time, least significant bit first.
    $33 = $00110011
    The byte is transmitted lsb first as:
    111111111101100110011111111111111 '
    My question has to do with what the program does after the stop bit
    [SIZE=1][FONT=courier new]HIGH 2   'Make RS-232 output low to prevent collisions[/FONT][/SIZE]
    Usually the RS232 line stays in the STOP state after transmitting a byte. Is there something different about the ECU? This instruction puts the line in the START or BREAK state. You have,
    1111111111011001100100000000000000000 ' <--BREAK!

  • n00bn00b Posts: 5
    edited March 2012 Vote Up0Vote Down
    You're right, that was also a flaw in my program. I have to keep reminding myself that the ISO9141 bus idles at +12V = logic 0. I'll post an update later tonight to show what the new program and schematic looks like.
  • n00bn00b Posts: 5
    edited March 2012 Vote Up0Vote Down
    Been busy this weekend and finally got communication working well between the BS2 and ISO 9141 bus. Here's the code I ended up with, for everyone's future reference and benefit. The schematic for the circuit is basically same as the one on, and it's pretty obvious how it works (works like any other transistor...). My pin 2 (used for serout) goes to the transistor base, and pin 5 (used for serin) senses voltage on the K-line (through a 22k ohm resistor, as the basic stamp manual suggests). I did not have an L-line on my ECU, so I didn't have to worry about it.
    ' {$STAMP BS2}' {$PBASIC 2.5}
    'This program is designed to initialize a 2000 Honda Civic DX FI-ECU, and read mode 01, PID 00 (Lists the PIDs supported for the ECU)
    'Pin 2 high means ECU logic low 0.2v
    'Pin 2 low mean ECU logic high +12v
    serData VAR Byte(3)                      'define serdata as array of 3 bytes
    confirm VAR Byte                         'define confirm as byte
    senddata VAR Byte(5)                     'define senddata as array of 5 bytes
    recdata VAR Byte(8)                     'define recdata as array of 5 bytes
    LOW 2                                 'ECU idles at logic high +12v
                                          'so, set TTL LOW to idle ECU at 12v
                                          'as a result pin 5 is sensing 12V
    PAUSE 5000                            'If K-line senses 12V for over 5 sec, it requires re-initialization (per ISO standard)
    DEBUG "Start init sequence...",CR
    HIGH 2                                'start bit, make output high for 200ms   (ECU low, 0.2v)
    PAUSE 200
    LOW 2                                 'make output low for 400ms   (ECU high, +12v)
    PAUSE 400
    HIGH 2                                'make output high for 400ms   (ECU low, 0.2v)
    PAUSE 400
    LOW 2                                 'make output low for 400ms      (ECU high, +12v)
    PAUSE 400
    HIGH 2                                'make output high for 400ms     (ECU low, 0.2v)
    PAUSE 400
    LOW 2                                 'Stop bit, make output low 200ms (ECU high, +12v)
    PAUSE 200
    DEBUG "waiting...",CR
    SERIN 5,76,5000,nodata,[STR serdata\3]      'receive 3 bytes data on K line
    DEBUG HEX serdata(0),CR                    'display received data (hex 55)
    DEBUG HEX serdata(1),CR                    'display received data (hex 08)
    DEBUG HEX serdata(2),CR                    'display received data (hex 08)
    PAUSE 40                                   'pause 25-50ms before sending next byte (per ISO standard)
    SEROUT 2,16460,[$F7]                       'send hex F7 (inverse of 08)
    DEBUG "waiting...",CR
    SERIN 5,76,5000,nodata,[confirm]           'ECU should send confirmation within 25-50ms
    DEBUG HEX confirm,CR                       'display received data (hex CC)
    pidrequest:                                'loop to request valid PIDs for the ECU
    PAUSE 20                                   'must transmit any requests within 55ms-5 seconds (per ISO standard)
                                               'I found I can actually transmit within 20ms... go figure
    DEBUG "Ask for PIDs...",CR
    SEROUT 2,16460,[$68]                       'Transmit 68 6A F1 01 00 C4
    SEROUT 2,16460,[$6A]                       'It turns out no pause is necessary between bytes, despite what I read on other sites.
    SEROUT 2,16460,[$F1]                       'Previously I was trying a FOR...NEXT loop, but this did not work for some reason.
    SEROUT 2,16460,[$01]                       'Using 6 serout statements is the only way I could get a response from the ECU.
    SEROUT 2,16460,[$00]
    SEROUT 2,16460,[$C4]
    DEBUG "Receive PIDs...",CR
    SERIN 5,76,5000,nodata,[STR recdata\8]     'Receive 8 bytes of data
    DEBUG HEX recdata(0),CR                    'display received data (hex 48)
    DEBUG HEX recdata(1),CR                    'display received data (hex 6B)
    DEBUG HEX recdata(2),CR                    'display received data (hex 0E)
    DEBUG HEX recdata(3),CR                    'display received data (hex 41)
    DEBUG HEX recdata(4),CR                    'display received data (hex 00)
    DEBUG HEX recdata(5),CR                    'display received data (hex BE)
    DEBUG HEX recdata(6),CR                    'display received data (hex 3E)
    DEBUG HEX recdata(7),CR                    'display received data (hex B8)
    nodata:                               'SERIN timeout loop
    DEBUG "no data",CR


    So, lessons learned? First, I had to remember which way the bits are inverting (or not inverting), depending on if I was sending or receiving a message. That was confusing at the beginning. Second, timing is everything (not having a method of flow control or a very finite idea of the ECU timing was frustrating).

    One weird thing... the checksum byte returned (B8) doesn't seem to be correct. Adding up bytes 0-6 gives 510, so I think the checksum byte should be 510-255 = 255 (FF). I need to do a little more work to figure that out.

    The other disappointment is that only a handful of PIDs are supported for my car (2000 Civic DX). The only somewhat interesting parameter I can read in real time is throttle position sensor. I was hoping to get more things like MAF, intake temperature, etc., but it appears such data is not output by this ECU (I'm sure I can get it if I tap into enough of the wires and use a A/D converter, but that wasn't what I had in mind).

    Anyway, I'm just glad I got it working. There did not seem to be any solid "how-to" on Parallax forums for reading OBD2 data, so I'm glad I could share my findings with everyone. I hope other people expand on this topic and post some of their own projects!
    500 x 450 - 48K
  • hi,

    can everyone helm me to convert BS2 code to C / arduino code?

    I have same case, but I do not familiar with BS2

    thank you everyone

    BR from java island
Sign In or Register to comment.