A CAN bus monitor

10 May

A CAN bus monitor: This is a very simple demonstration on communicating using a CAN bus. We simply connect two TINIs as CAN devices using a short length of twisted-pair wire. We will be running a simple CAN activity monitor on one TINI and a simple CAN message sender on the other. This is just to get our feet wet with the TINI CAN API. The program is well commented, so there is not much need to explain it line by line. But there are a few things that are worth noting:

• The CAN bus controller needs to be configured before the enableController() method is invoked. Any changes to the CAN controller (like timing parameters) after it has been enabled will be ignored.

• The CAN message ID global mask needs to be set (set11BitGlobalIDMask or set28BitGlobalIDMask) and enabled (setMessageCenterMessageIDMaskEnable) for each message center or each CAN message center you wish to use needs to be configured to use an arbitration ID (set29BitMessageCenterArbitrationID or set11 Bit Message Center ArbitrationID).

Figure 12-18: A TINI CAN network

import com.dalsemi.comm.*;
import com.dalsemi.system.*;
public class CanBusViewer {
static CanBus myCanBus;
static int KILL_ID=0×666;
// utility method for making the output look nice
static String justifytext( String str, int dir, int width ) {
String padding = “
if (dir<0) { // left
str = str + padding.substring( 0,width );
}
if (dir>0) { // right
str = padding.substring( 0,width-str.length() ) + str;
}
return( str.substring(0,width) );
}
static void main( String args[] )
{
System.out.println( “CAN Bus Viewer” );
System.out.println( “Configuring CANBUS0 for receiving.” );
try {
// Create a new CanBus object
myCanBus = new CanBus( CanBus.CANBUS0 );
// Set up the CANBUS speed (125 Kbps)
myCanBus.setBaudRatePrescaler( 7 );
myCanBus.setTSEG1( 13 );
myCanBus.setTSEG2( 7 );
myCanBus.setSynchronizationJumpWidth( 1 );
myCanBus.enableController();
System.out.println( “Enabling Message Center 1.” );
myCanBus.setMessageCenterRXMode( 1 );
myCanBus.setMessageCenterRXMode( 2 );
myCanBus.setMessageCenterRXMode( 3 );
myCanBus.setMessageCenterRXMode( 4 );
System.out.println( “Setting up filtering.”);
// filtering
myCanBus.setMessageCenterMessageIDMaskEnable( 1, false );
myCanBus.setMessageCenterMessageIDMaskEnable( 2, false );
myCanBus.setMessageCenterMessageIDMaskEnable( 3, true );
myCanBus.setMessageCenterMessageIDMaskEnable( 4, true );
// Look for all addresses
myCanBus.set11BitGlobalIDMask(0xFFFFFFFF);
myCanBus.set29BitGlobalIDMask(0xFFFFFFFF);
// need this so that MC1 will look for 29 bit addresses
myCanBus.set11BitMessageCenterArbitrationID( 1, 0×00 );
myCanBus.set11BitMessageCenterArbitrationID( 2, 0×222 );
myCanBus.set29BitMessageCenterArbitrationID( 3, 0×01432520 );
myCanBus.set11BitMessageCenterArbitrationID( 4, 0×00 );
// Enable Message Centers
myCanBus.enableMessageCenter( 1 );
myCanBus.enableMessageCenter( 2 );
myCanBus.enableMessageCenter( 3 );
myCanBus.enableMessageCenter( 4 );
catch( Exception e) {
System.out.println( e );
System.out.println( “Monitoring CANBUS0” );
CanFrame myFrame = new CanFrame();
byte[] data = new byte[8];
boolean done=false;                                                      // loop till done
int loops=0;                                                             // loops done so far
int maxloops=20;                                                         // max loops allowed
while( !done) {
loops++;
try {
myCanBus.receive( myFrame );
}
catch (Exception e) {
System.out.println( e );
}
if (myFrame.getID()==0) {
loops—;
continue;
}
System.out.print( “Frame “ );
System.out.print( justifytext( Integer.toString(loops)+”,” , 1, 3 ) );
System.out.print( “ ID 0x” );
System.out.print(
justifytext(Integer.toHexString(myFrame.getID())+”,”,-1,8));
if (myFrame.getExtendedID()) {
System.out.print( “ extended” );
} else {
System.out.print( “ standard” );
}
System.out.print( “, MC “ + myFrame.getMessageCenter() );
if (myFrame.getRemoteFrameRequest() ) {
System.out.print( “, Remote Frame Request” );
}
System.out.print( “ “ );
if (myFrame.getID()==KILL_ID) {
System.out.print( “, kill frame” );
done=true;
}
else {
System.out.print( “, “ + myFrame.getLength() );
System.out.print( “ bytes: “ );
System.out.print( ByteUtils.toHexString( myFrame.getData(),
0, myFrame.getLength(), ‘ ‘ ));
}
System.out.println( );
if (loops>=maxloops) done=true;
}
try {
myCanBus.close();
}
catch( Exception e ) {
System.out.println( “Error in closing…” );
System.out.println( e );
}
System.exit(0);
}
}

You can compile and run CanBusViewer.tini on the TINI controller that will be the receiver for our simple CAN test (it doesn’t matter which of the two TINIs).

Notice how to set the CAN speed for this device:
myCanBus.setBaudRatePrescaler( 7 );
myCanBus.setTSEG1( 13 );
myCanBus.setTSEG2( 7 );
myCanBus.setSynchronizationJumpWidth( 1 );

The device that is sending frames will need to use the same settings. To change the speed at which your CAN bus monitor (and any TINI CAN device) communicates, you will need to set these values as a set. Refer to Table 12-3 for different baud rates (the Synchronization Jump Width will be 1 for all of these speeds). After the baud rate is set we can enable the CAN controller:

myCanBus.enableController();

We enable the global masks to let the CAN processor accept all 11-bit and all 29-bit message IDs:

myCanBus.set11BitGlobalIDMask(0xFFFF);
myCanBus.set29BitGlobalIDMask(0xFFFFFFFF);

We then configure four message centers for receiving frames. First, each is set in the receive (RX) mode. Then different filters are configured. Finally, each message center is enabled. All changes in the arbitration ID and mask enable must be done when the message center is not enabled.

Here message center 1 is configured so that an incoming frame ID must be an 11-bit ID frame and match an arbitration ID of 0×00. Message masking is disabled so the frame ID must match the arbitration ID.

myCanBus.setMessageCenterRXMode( 1 );
myCanBus.setMessageCenterMessageIDMaskEnable( 1, false );
myCanBus.set11BitMessageCenterArbitrationID( 1, 0×00 );
myCanBus.enableMessageCenter( 1 );

Here message center 2 is configured so that an incoming frame ID must be an 11-bit ID frame and match an arbitration ID 0×22.

myCanBus.setMessageCenterRXMode( 2 );
myCanBus.setMessageCenterMessageIDMaskEnable( 2, false );
myCanBus.set11BitMessageCenterArbitrationID( 2, 0×222 );
myCanBus.enableMessageCenter( 2 );

Here message center 3 is configured so that an incoming frame ID must be a 29-bit ID frame and match the arbitration ID of 0×01432520. But, since masking is enabled and the global mask is set to 0xFFFFFFFF (match all bits), then this message center will receive all 29-bit ID frames (regardless of the arbitration ID).

myCanBus.setMessageCenterRXMode( 3 );
myCanBus.setMessageCenterMessageIDMaskEnable( 3, true );
myCanBus.set29BitMessageCenterArbitrationID( 3, 0×01432520 );
myCanBus.enableMessageCenter( 3 );

Here message center 4 is configured so that an incoming frame ID must be an 11-bit ID frame and match the arbitration ID of 0×000. But, since masking is enabled and the global mask is set to 0×0FFF (match all bits), then this message center will receive all 29-bit ID frames (regardless of the arbitration ID).

myCanBus.setMessageCenterRXMode( 4 );
myCanBus.setMessageCenterMessageIDMaskEnable( 4, true );
myCanBus.set11BitMessageCenterArbitrationID( 4, 0×00 );
myCanBus.enableMessageCenter( 4 );

Incoming frames are processed in a loop. Each frame is received with:
myCanBus.receive( myFrame );

We then take apart the frame using various methods in the CanFrame class and display this information so we can see what is going on.

Compile CanBusViewer.java:
C:\> cd src
C:\> javac -bootclasspath %TINI_HOME%\bin\tiniclasses.jar -d ..\bin
CanBusViewer.java
C:\> cd ..
C:\> java -classpath %TINI_HOME%\bin\tini.jar;. BuildDependency
-p                                                                             %TINI_HOME%\bin\owapi_dependencies_TINI.jar
-f bin
-x                                                                             %TINI_HOME%\bin\owapi_dep.txt
-o bin\CanBusViewer.tini
-d %TINI_HOME%\bin\tini.db

Once this program is up and running on TINI, then next we need to send data out to the CAN bus. We will use the next simple program to do just that. The data sent is nothing meaningful (except that the first byte indicates the number of the frame, so we can see which frames made it to the CAN monitor program), and we use a number of different methods for sending CAN frames so we can see how they work and what the differences are.

The program is rather obvious in what it does, but there are a few things here we should also note.

•  We try 10 methods or variations on methods from the com.dalsemi.comm.CanBus class to send frames on the CAN bus. Some will be successful and some will not. You should carefully examine the program and the program output so that you see which CAN frames were generated with which methods.

•  Each test is in its own try/catch block so we can see the error messages from each attempt and  all 10 tests will be executed even if previous methods throw an exception.

Listing 12-2: CanSendTest
import com.dalsemi.comm.*;
import com.dalsemi.system.*;


public class CanSendTest {
// We store our CAN messages is the data array
static CanBus myCanBus;
static CanFrame myFrame1 = new CanFrame();
static int delay = 100;
static void main( String args[] )
{
System.out.println( “CAN SendTest” );
try {
// Create a new CanBus object
myCanBus = new CanBus( CanBus.CANBUS0 );
// Set up the CANBUS speed (125 Kbps)
myCanBus.setBaudRatePrescaler( 7 );
myCanBus.setTSEG1( 13 );
myCanBus.setTSEG2( 7 );
myCanBus.setSynchronizationJumpWidth( 1 );
myCanBus.setTransmitQueueLimit(1);
myCanBus.enableController();
// Set up messagecenter 1
myCanBus.setMessageCenterTXMode( 1 );
myCanBus.enableMessageCenter( 1 );
}
catch( Exception e ) {
System.out.println( e );
}
// just some data for a frame to send
byte[] data= { 0×00,0×03,0×01,0×04,0×01,0×05,0×09,0×02 };
try {
System.out.println( “ 1: sendDataFrame, standard, ID 0×0432” );
data[0] = (byte) 0×01;
myCanBus.sendDataFrame( 0×0432, false, data );
}
catch( Exception e ) { System.out.println( e ); }
TINIOS.sleepProcess( delay );
try {
System.out.println( “ 2: sendDataFrame, extended, ID 0×01432520” );
data[0] = (byte) 0×02;
myCanBus.sendDataFrame( 0×01432520, true, data );
}
catch( Exception e ) { System.out.println( e ); }
TINIOS.sleepProcess( delay );
try {
System.out.println( “ 3: sendFrame, standard, ID 0×0543” );
data[0] = (byte) 0×03;
myFrame1.setData( data );
myFrame1.setLength( 8 );
myFrame1.setID( 0×0543 );
myFrame1.setMessageCenter( 1 );
myFrame1.setRemoteFrameRequest( false );
myFrame1.setExtendedID( false );
myCanBus.sendFrame( myFrame1 );
}
catch( Exception e ) { System.out.println( e ); }
TINIOS.sleepProcess( delay );
try {
System.out.println( “  4: sendFrame,  standard, fewer bytes, ID 0×0543” );
data[0] = (byte) 0×04;
myFrame1.setData( data );
myFrame1.setLength( 4 );
myCanBus.sendFrame( myFrame1 );
}
catch( Exception e ) { System.out.println( e ); }
TINIOS.sleepProcess( delay );
try {
System.out.println( “ 5: sendFrame, extended, ID 0×01543210” );
data[0] = (byte) 0×05;
myFrame1.setData( data );
myFrame1.setLength( 8 );
myFrame1.setID( 0×01543210 );
myFrame1.setExtendedID( true );
myCanBus.sendFrame( myFrame1 );
}
catch( Exception e ) { System.out.println( e ); }
TINIOS.sleepProcess( delay );
try {
System.out.println( “  6: sendRemoteFrameRequest, standard, ID 0×123”  );
data[0] = (byte) 0×06;
myCanBus.sendRemoteFrameRequest( 0×0123, false, data );
}
catch( Exception e ) { System.out.println( e ); }
TINIOS.sleepProcess( delay );
try {
System.out.println( “ 7: sendFrame, RTR, standard, ID 0×0543” );
data[0] = (byte) 0×07;
myFrame1.setData( data );
myFrame1.setLength( 8 );
myFrame1.setID( 0×0543 );
myFrame1.setMessageCenter( 1 );
myFrame1.setRemoteFrameRequest( true );
myFrame1.setExtendedID( false );
myCanBus.sendFrame( myFrame1 );
}
catch( Exception e ) { System.out.println( e ); }
TINIOS.sleepProcess( delay );
try {
System.out.println( “ 8: sendDataFrame, standard, ID 0×0432” );
data[0] = (byte) 0×08;
myCanBus.sendDataFrame( 0×0432, false, data );
}
catch( Exception e ) { System.out.println( e ); }
TINIOS.sleepProcess( delay );
try {
System.out.println( “ 9: autoAnswerRemoteFrameRequest,
standard, ID 0×0111” );
data[0] = (byte) 0×09;
myCanBus.autoAnswerRemoteFrameRequest( 1, 0×0111, data );
}
catch( Exception e ) { System.out.println( e ); }
TINIOS.sleepProcess( delay );
try {
System.out.println( “10: sendDataFrame, standard, ID 0×0222” );
data[0] = (byte) 0×10;
myCanBus.sendDataFrame( 0×0222, false, data );
}
catch( Exception e ) { System.out.println( e ); }
TINIOS.sleepProcess( delay );
try {
myCanBus.close();
}
catch( Exception e ) { System.out.println( e ); }
System.exit(0);
}
}

Compile this program:
C:\> cd src
C:\> javac -bootclasspath %TINI_HOME%\bin\tiniclasses.jar -d ..\bin
CanSendTest.java
C:\> cd ..

C:\> java -classpath %TINI_HOME%\bin\tini.jar;. BuildDependency
-p                                                                %TINI_HOME%\bin\owapi_dependencies_TINI.jar
-f bin
-x                                                                %TINI_HOME%\bin\owapi_dep.txt
-o bin\CanSendTest.tini
-d %TINI_HOME%\bin\tini.db

FTP CanSendTest.tini to your other TINI in our simple CAN network and run it. Examine the output of these two programs (remember to start running CanBusViewer.tini before you start running CanSendTest.tini or you might miss a few frames). In this case there are a few differences between the versions of the TINI API.

This is the output of CanSendTest running TINI API 1.02d

TINI1 /> java CanSendTest.tini
CAN SendTest
1: sendDataFrame, standard, ID 0×0432
2: sendDataFrame, extended, ID 0×01432520
3: sendFrame, standard, ID 0×0543
4: sendFrame, standard, fewer bytes, ID 0×0543
5: sendFrame, extended, ID 0×01543210
6: sendRemoteFrameRequest, standard, ID 0×123
com.dalsemi.comm.CanBusException: failed in send -920933632
7: sendFrame, RTR, standard, ID 0×0543
com.dalsemi.comm.CanBusException: failed in send -920933888
8: sendDataFrame, standard, ID 0×0432
9: autoAnswerRemoteFrameRequest, standard, ID 0×0111
com.dalsemi.comm.CanBusException: Don’t use
CanBus:autoAnswerRemoteFrameRequest()
10: sendDataFrame, standard, ID 0×0222

Note at this point that we got an exception when using the following methods:
myCanBus.autoAnswerRemoteFrameRequest( 1, 0×0111, data );
myCanBus.sendRemoteFrameRequest( 0×0123, false, data );
myFrame1.setRemoteFrameRequest( true );
myCanBus.sendFrame( myFrame1 );

Apparently these methods (anything to do with Remove Frame Requests) have not been implemented in this version of the API.

Now let’s look at what the CanBusViewer.tini program received:

TINI2 /> java CanBusViewer.tini
CAN Bus Viewer
Configuring CANBUS0 for receiving.
Enabling Message Center 1.
Setting up filtering.

Isn’t that interesting! Our CAN test program sent 10 frames but our CAN monitor only received 7 CAN frames. This is where the first byte in the data field comes in handy. That byte corresponds to the number of the frame that was sent so we can see which methods worked and which didn’t. To get the most benefit from this example, you should examine the output of the CanSenTest program and compare this with the output of the CanBusViewer program. Then go and find the section of code that generated each frame in the CanSendTest program. Each frame was sent with a slightly different method or different frame ID, so you can see how they appear on the CAN bus and how the message centers filter the frames. It is also worth noting two errors you are likely to see and what they mean (particularly if you are NOT sending extended ID message frames and you are NOT sending remote frame requests).

•  If the receiver is not listening (as in there are no receivers) or the CAN bus is not connected properly, you will get an exception indicating there was NO_ACKNOWLEDGEMENT

com.dalsemi.comm.CanBusException: Send Failed: No Ack

•  If the CAN transceiver is not connected properly to TINI or is not powered then you will see an exception indicating that the CAN controller noticed that the CAN bus was in a state other than what it expected:
com.dalsemi.comm.CanBusException: Send Failed: Bit Zero

Random Posts

Comments are closed.