Wednesday, September 11, 2019

J1939 CAN bus and the Thomson Electak HD

For awhile I wanted to see if the standard CAN bus chip set and Arduino programs could interface with J1939 CAN bus.  I was betting it could but wanted to prove it.  I got the opportunity to borrow an industrial actuator that utilized J1939 protocol.  It is an Thomson Electrak HD actuator with the CAN bus option.  Here is a link to the product page of the one I used. (link)  It was part number HD24B045-0150CNO2MNS.


After a little research it appears J1939 uses the same physical layer (wiring, pulses etc.) as the standard automotive high speed CAN bus network.  Which meant the hardware should work.  But would the standard Arduino programs be able to decode the data stream?  Long story short.  Yes it can.

The hardware I used was an Arduino mega with a can bus shield based on the MCP2515 and MCP2551 chip set.  This is pretty typical for Arduino CAN bus shields.  Like the spark fun or seeed studio shields which I’ve used in the past.  Though the shield I used for this project was one I had previously put together from components.  And of course, I included two 120 ohm terminating resistors.

First thing I found trying to read the data stream was that the baud rate of the Thomson HD actuator was 250 kbps.  After some looking it appears that J1939 may support both 250 and 500 kbps.  But perhaps 250 kbps is more popular.  Either way once I set the baud rate to 250 kbps I could capture a CAN data stream for a few seconds every time the unit was powered up.

Decoding the Actuators feedback message

J1939 uses extended ID format.  Most of the CAN streams I’ve messed with were standard ID format.  But the extended format is not a problem and it just shows as a longer ID.  I had downloaded the instruction manual for the actuator and it specified what the data was in the message packets.  But it assumed one has in-depth knowledge of J1939.  Which I didn’t.  I wasn’t sure if the data was big endian or little endian or what.  And how that would work with the Arduino CAN shield software.  Best way to know is to look at sample the data.  Which I did.

Turns out the bytes of the message ID come out in the correct order.  But the data bytes need to be reversed.  Guess that would be the byte order is little endian.  Or in other words, the first byte received is the smallest value in the message.  If writing the bytes down as they come out we'd do it from right to left instead of left to right.  The order of the bits within each byte was standard order.    Probably easier to see with an example.


Say we get the CAN message from the actuator of:  ID: 19EFFF13,   Data: DD 01 80 01 C1 FF FF

Decoding the ID
  • The first 2 bytes: 0x19EF is a combination of a few things.  But in this case it tells us it's the feedback message from the actuator. (Priority 6 and PDU of 0x01EF00)
  • The third byte: 0xFF is the destination address.  FF is a broadcast message.
  • The last byte: 0x13 is the source ID.  In this case the address of the actuator.
Decoding the Data bytes

Once the bit and byte order were sorted out setting up a program to read and decode the messages was just a matter of extracting and combining the right bits and conversion factors as described in the actuator’s instruction manual.  Below is a visual showing how the bytes are decoded (click to see it bigger).

Yes the Arduino with a CAN shield can read the J1939 can bus data.  But can it talk to the actuator and make it move? 

Sending Commands to the actuator:

Between the actuators instruction manual and some J1939 info I found on the net, came to the conclusion that the ID needed to command the actuator would be 18EFxxyy.  The xx being the actuators address (default is 0x13) and yy being the address of my sending device.  The address of the sending device looked like it could be anything except the highest couple of values.  I chose 0xAA for my controller address.  The resulting ID for my command message was then 0x18EF13AA.  Now for data bytes.

Similar to decoding the feedback message.  Creating the command message was done in a simlar manner.  In the command message there are several attributes to be chosen.  I’ll give a brief description of each.
  • The position desired for the actuator to move to.  Any value could be chosen between zero and it’s maximum stroke.  But it turned out it needed to be a greater than about 2mm to 5mm from it’s current position for it to actually make a move. 
  • The maximum current the actuator is allowed to use.  This value had to be in the range 1 Amp to the maximum amp draw rating of the actuator.  If not in this range the actuator would respond with an error.  And if more current was used during a move then the value set here, the actuator would throw an error and stop.  Found it best to just set this value to the Max value for the unit. In my case 12.5 Amps and leave it be.  But this could be a trick feature if trying to do some load limiting logic.
  • Speed desired.  This value could be from 20% to 100%.  This was a fun one to play with.  Changing it could make the actuator move fast or slow.  I even tried changing the speed while it was already moving. And that worked too.
  • Motion enable.  This flag has to be 1 for the actuator to move.  Really the only reason to set it to zero is to clear errors or if just sending a message to keep the actuator awake and not wanting to risk moving it.
 The following image shows how the values are converted to the data bytes. (click to see it bigger)
 

To command the actuator with the above settings I’d send ID:
18EF13AA with Data A1 42 1F 15 00 00 00.

Attempting to send different values I found that I’d often get error flags in the actuator feedback message and at times the actuator wouldn’t move.  To clear the error messages I’d have to send a command message with valid parameters and the motion flag set to “0”.  Then I could go back to trying sending the message with the move flag set to “1” to move it.  After playing with it for a bit I found a setup that would work and keep everything happy. 

Here are the basics of what I found keeps everything happy

The parameters must be within the proper ranges in the command message.
  • Amps: between 1 and the max amps for the unit.  (Suggest setting the amps to the max of the unit.)
  • Position: From 0 mm to the max stroke of the unit (150 mm  in my case).
  • Speed: Between 20% and 100%
Don’t let the actuator fall asleep unintentionally
  • The actuator requires constant bus traffic to stay awake (destination FF or the actuator’s address)
  • If the actuator falls asleep and then receives a message it will go through Address claim procedure again.
  • Sending a command message every 2s or less will keep it awake.
Reply to the address claim messages (ID: 18EEFF13, Data: 01 00 60 44 00 FF 00 80)
  • When the actuator wakes or is powered up it sends and address claim message. If it is not followed by an command message within 400 ms an overload flag will automatically set.  Then the error will have to be cleared before the actuator can move.
  • Seems the best practice is to reply to all address claims from the actuator immediately with an command message.  Then keep sending a valid command message every 2s or less.  Probably a good idea to set motion flag zero on initial responses to ensure no movement is made unexpectedly.  And as a bonus the message will clear any errors if there were any.
  • The standard address claim message from the actuator is ID: 18EEFF13, Data: 01 00 60 44 00 FF 00 80.  The last byte of the ID could change if there are address conflicts or if the actuator is hardwired to a different address.  But the data bytes of the address claim are ALWAYS the same.  I set up my program to look for those data bytes and then take the last byte of the ID in that message as the address for the actuator.  Then used that address to form the ID of the commands sent to the actuator.  Oh and I have the Arduino reply to the address claim message with a command with motion set to zero right after getting the claim message. 
Using the above I could get the actuator to power up or wake up perfectly every time.  No errors or problems.

Conclusion

This was an interesting and fun little project.  With the CAN interface it was really easy to run the actuator with the Arduino.  And the variable speed feature was way cool.  Made me want to build something with one.  Maybe an Arduino controlled solar tracker?  I dunno.

If there is interest in the full Arduino code drop me a comment.  If there is enough interest I’ll take the time to clean it up a bit and post it.

Wednesday, September 19, 2018

2011 Chevy Volt Bus systems

Last week I bought a 2011 Chevy Volt.  Was wanting an EV and after comparing the used EV's on the market we went with the Volt.  I've owned cars for about 30 years and this is the FIRST GM car I've ever owned.  I've done a bit of GM bus work for engine swaps (I did own a GM LS1 V8 but I put it in a BMW).  But now I'm a bit more interested in how things work.  In looking for bus diagrams I was having some difficulty.  And I found 2 OBDII ports in my car.  After some time with a repair manual I drew up these diagrams.  Perhaps they will be helpful to someone.  They will be for me.



Expect the diagrams would also apply to the Opel Ampera

Tuesday, March 20, 2018

Arduino interface options for Class2Serial or J1850 VPW


A VPW transceiver would be the ideal interface.  But sadly the J1850 VPW spec is not being used in any large production products anymore.  And all the transceivers are obsoleted.  At least I couldn't find one for sale.  Looks like we are all left with making our own interface.

In the previous post I discussed a method for receiving the VPW signal using a voltage divider and how one might go about selecting the best resistance.  But there is more than one way to setp down the voltage of the VPW signal to match the Arduino.  In this post I'll discuss several methods that might be used.  But the voltage divider is very simple and seems to work quite well.

For transmitting there are also several choices.  The VPW output from GM ECU was measured to be about 7.1V.  to make a signal with the same voltage we will need to step up the Arduino pulse signal.  But wait.  As shown in the previous post the high trigger voltage spec for VPW is 4.25V.  The Arduino can output this voltage.  And the Arduino output is a square wave so where it is measured on the pulse won't matter.  Something as simple as a diode between the Arduino output pin and the VPW line could even work.   But other more sophisticated methods utilize optocouplers or MOSFET's and comparators.  Like always there is more than one way to solve a problem.

But let's take a step back.  When I first wanted to connect the VPW to the Arduino I didn't find many choices.  One popular way was with the ELM327.  I obtained an ELM327 clone and connected it to the Arduino (this video was done with an ELM327 clone between the VPW bus and the Arduino).  While it did work it was limiting in many ways.  I wanted a less filtered access to the bus.

More searching found this example: http://www.nerdkits.com/videos/obdii/
Their circuit uses an optocoupler for both input and and output.  They reference another project which uses a voltage divider for receive and transistors for send.  And the ELM327 suggested circuit also uses divider/transistor setup.

The Nerdkits also has some code posted for capturing the VPW pulses.  This is more along the lines of what I was looking for.  But as usual this code didn't compile on our setup and had some limitations.  But it was a good starting point.  We reworked the code to suit our application.  More about the software later.  For now back to the circuit design.

More to come on this topic Later.  Out of time to type.

Monday, March 19, 2018

Class2Serial or J1850 VPW Pulse Measuring

 Capturing a VPW Class2 Serial pulse


In attempting to make an Arduino interface I found a few interesting things.  Perhaps these are obvious to many others but for me they weren't.  The first thing to know is that the Pulse from the GM ECU (at least an older LS1 style ECU) is NOT square.

Above is a trace of an Oscilloscope reading I took of the actual Class2Serial output signal from a GM ECU.  Note that the pulse is not square.  It looks more like a symmetrical saw tooth that's been truncated.  This is important to know.  Because in non-square waves where the voltage the pulse is measured at will provide different pulse lengths.
On this graph I put an orange line down low.  If measuring the pulse widths here you can see the widths would not be per the specifications.   See the lines I've added to the first pulse. In VPW the up AND down pulses are measured.  That means that if not measuring at the mid point, the pulse going up will not measure the same length as the pulse coming down.  This will give 2 different pulse widths measured for the physically same pulse width.  On the diagram above I've added lines and labels to two short pulses.  If measured at the orange line it produces two very different pulse widths for the same width pulse.  One being up and the other being down.

  
The graph above is showing timer values of a data stream from an ECU as captured by an Arduino mega.  Notice the double peak of times.  This is due to not measuring the times at the mid point of the wave.  

The upper limit for J1850 spec VPW is 4.25V and the Lower is 3.50V.    To get rid of the double peak we need the upper and lower limits of the VPW spec to equal the upper and lower limits for the Arduino triggers.  Reading the Arduino spec sheets it appears that the Arduino upper and lower trigger points should be 3.0V and 1.5V respectively.  Measuring an Arduino mega using digital read we measured the upper and lower limits to be 2.18V and 2.16V.  Interesting.  We then tested again using interrupts.  Interrupts is how we normally capture the wave.  This resulted in 2.15 V upper and 2.12 lower.  Specs are great but I'll go with the actual measurements.

Since we plan to capture the pulse using interrupts we will use the upper and lower voltages for that.  We want to get the VPW trigger voltages down to the Arduino trigger voltages. 
Or in other words:
4.25V --> 2.15 V
3.50V --> 2.12 V

A simple voltage divider could do this for us.  Using a 10K resistor for the first resistor (from the high voltage side) the 2nd resistor would be 10.2K and 15.3K:
4.25V --> 2.15 V -->10.2K
3.50V --> 2.12 V -->15.3K
Having a separate circuit for both the up pulse and down pulse would be possible but is likely not needed.  We could just average the 2 resistors.  This gives us 12.7 K.   Alternatively we could take the mid point voltage of the VPW (3.875V) and Arduno (2.135V) that gives is 12.25 K
 4.25V --> 2.15 V -->10.2K
3.875V --> 2.135 V -->12.25K
 3.50V --> 2.12 V -->15.3K

Theory is great and all but how does this all work out in real life?  Below is a graph of the timings vs various resistors.  10K being the first resistor in the voltage divider.  Then the resistor listed on the graph as the second.
 
The 22K resistor has a distinct double peak.  the 13k, 12k and 11k results are all basically on top of each other.  This all appears to match up closely with the theoretical.  

In reality we started with the actual results and then worked backwards to explain why the 13k-11k resistor worked the best.  Either way I suggest using 10k-12K voltage divider.  So far it appears to work very well.  If using a device with different toggle voltages recalculate in a similar manner what the resistor for those voltages should be.