To download NI software, including the products shown below, visit ni.com/downloads.
J1939 is a set of SAE standards that is built on top of CAN (Controller Area Network). Part of the standard defines how to deconstruct, transfer and reassemble CAN messages larger than 8 bytes. The J1939 standard calls this process Transport Protocol. This example shows how to implement this using LabVIEW and NI-CAN products.
J1939 is set of SAE standards commonly used in diesel-powered applications for communication and diagnostics between application components. The J1939 standard is defined in multiple documents corresponding to five of the seven OSI layers. J1939-11 defines the physical layer, J1939-21 defines the data link and transport layer, J1939-31 defines the network layer, and J1939-71/73 defines the application layer. J1939-81 describes network management.
The goal of this document is not to explain all these standards in detail. For this, please consult the SAE standards. Instead, we will look at the construction and transmission of messages as defined by J1939-21 using NI-CAN and supported hardware.
J1939 messages are built on top of CAN 2.0b and make specific use of extended frames. Extended frames use a 29-bit identifier instead of the common 11-bit identifier. J1939-21 defines fields within this 29-bit identifier as shown below.
Figure 1. J1939 29-bit Identifier Fields
The first three bits are the priority field. This field sets the message’s priority on the network and helps ensure messages with higher importance are sent/received before lower priority messages. Zero is the highest priority.
The next bit is reserved for future use. This field should be set to zero.
The next bit is the Data Page field. This is used to expand the maximum number of possible messages.
The next eight bits make up the Protocol Data Unit Format (PDU F) field. This is used to determine if the message is intended for a specific device on the network or if the message is intended for the entire network. If the value of PDU F is less than 240, the message is meant for a specific device. If the value is 240 or greater, the message is intended for all devices.
The next eight bits make up the Protocol Data Unit Specific (PDU S) field. The definition of this field is based on value of the PDU F field. If PDU F is intended for a specific device (less than 239), PDU S is interpreted as the address of that specific device. In this case, the PDU S field is referred to as the Destination Address field. This format is referred to as PDU 1. If PDU F is intended for all devices (greater than or equal to 240), PDU S is interpreted as a Group Extension field. This group extension is used to increase the number of possible broadcast messages. This format is referred to as a PDU 2.
Both formats are described below in picture form.
Figure 2. PDU 1 Format
Figure 3. PDU 2 Format
The last eight bits identify the address of the device that transmitted the current message. This is known as the Source Address Field.
On standard CAN networks, identifiers are used to uniquely define each message. This concept exists within J1939 as well. Because the priority and source address fields can change, they are not used for this purpose. This leaves the reserve, data page, PDU F and PDU S fields. This new combination of fields is referred to as the Parameter Group Number (PGN). Each message in J1939 must have its own unique PGN. The J1939-71 standard is responsible for assigning these unique PGNs to standard messages.
Each device on the network has to have a unique address ranging from 0 to 254. These addresses are mainly used for PDU 1 messages and requests. In most cases, these addresses are static and pre-defined by the user. However, the J1939-81 standard does define a method of dynamic addressing.
Although J1939 uses the PDU F field mainly to specify if the message is PDU 1 or PDU 2, there are a few special values set aside for features like requests, dynamic addressing, and transport protocol. These values override the greater than/less than rules for PDU 1 and PDU 2 formats. Requests are used as an example below.
Figure 4. Request PGN
Notice in this example that PDU Format is set to 234. Normally, this would be handled as a PDU 1. However, because this is a special message, the device knows to handle the message differently. In this specific case, it knows it has to respond to the originator of the request in a particular format as defined by the J1939-21 standard.
The J1939 standard allows single messages to have more than eight bytes of data, however, the CAN specification only supports eight byte data transfers. Therefore, the message must be sent in multiple packets. J1939-21 defines how to package, send and reassemble these messages within the constraints of the CAN specification. J1939-21 calls this transport protocol and specifies two types The first is Broadcast Announcement Message (BAM) which is similar to PDU 2 in that it is intended for the entire network. The second is called Connection Mode and is similar to PDU 1 in that it is intended for a specific device.
Both transports protocols work in a similar fashion. They use two special messages to facilitate these multi-packet transfers. The first is known as a Transport Protocol Connection Management message (TP.CM). The data in a TP.CM message contains connection commands (also called Control Byte), the PGN identifier of the multi-packet message and information about how to reconstruct the message. The second is called a Transport Protocol Data Transfer message (TP.DT). The data of a TP.DT message contains a sequence number in the first byte and uses the remaining seven bytes for the data of the multi-packet message.
As mentioned above, Broadcast Announcement Messages are intended for the entire network. Therefore, no handshaking with other devices is required. The originating device first sends a TP.CM message with a control byte BAM (32). Next the originator starts sending all the data through the TP.DT messages until all the data has been sent. Below is an example to show the flow of a BAM message. Here, PGN 65260 is 20 bytes and is being transferred via BAM in 3 TP.DT packets.
Figure 5. BAM Data Transfer Example
Connection Mode is a peer to peer transfer. Therefore, handshaking and message acknowledgements are used to guarantee successful data transfer. First, the originating devices sends a TP.CM message with a control byte Request to Send (16). This is the originator asking the receiver if it is capable of receiving data. The receiver can then respond in various ways but normally it is with a TP.CM message containing control byte Clear to Send (17). The data of the TP.CM Clear to Send message contains the current sequence number to transfer as well as the number of TP.DT packets allowed. The originator then sends TP.DT messages starting at the sequence requested and stops after reaching the number of TP.DT messages allowed. This process continues until all the data is transferred. The receiving device then has to send a TP.CM message with control byte EndofMsgACK (19) confirming that all the data was successfully received. Here is an example to illustrate a typical Connection Mode message. Here PGN 65259 is a 27 byte message requiring 4 TP.DT messages.
Figure 6. Connection Mode Data Transfer Example
Note: It is acceptable to send a TP.CM Clear to Send message indicating that zero packets can be transferred. This doesn’t mean the connection is invalid. Instead it means the receiving device isn’t ready for the data. It is also acceptable to send a TP.CM Clear to Send message with a sequence number that has already been sent. This is often used when the receiver thinks the previous TP.DT messages were corrupt.
This example is named J1939 NI CAN Frame Example.vi and it is located in the
Examples\NI CAN Frame Example folder. It uses NI PCI/PXI CAN hardware and the NI CAN Frame API to show an implementation of reading and writing transport protocol messages. The example code abstracts the packetization, transmission and reconstruction of these messages from the user such that there is no difference in the reading/writing of messages greater than eight bytes and messages of eight bytes or less.
The front panel of this example contains four sections and is pictured below.
Figure 7. J1939 NI CAN Frame Example Front Panel
The first is labeled Setup. In this section, the user can select the NI-CAN port, set the baud rate (J1939 is typically 250k) and set the device address. These setting need to be entered before running the example.
The next section is labeled Control and Monitoring. This section is used for stopping the VI and viewing any errors that occur.
To the right of these sections is the Output section. Once the program is running, this section is used to send messages. The user enters the appropriate information into the Data to Send cluster and selects Send Message?. The Data array can be more than eight bytes. If it is, the VI will automatically transfer the message over the network using the correct transport protocol type, abstracting any difference between eight byte (or less) messages and messages greater than eight bytes. This will be discussed in more detail below.
The last section is labeled Input. This contains the CAN Frame cluster. This cluster is where new incoming messages are displayed. This does not include messages like requests, address claims, and transport protocol messages. It only includes data messages. If a data message is greater than eight bytes and is transferred over transport protocol, it will be reconstructed in software (discussed below). Once this reconstruction occurs, the message will be displayed like any other standard message.
The block diagram of this example can be broken into four sections. These sections are Initialization, Writing Messages, Reading Messages, and Code Cleanup.
Initialization in this example consists of configuring the CAN port, opening the CAN port, and initializing our J1939 code. For the J1939 specific code, this means creating multiple queue references, clearing any previously used memory and setting the current device address.
Figure 8. J1939 NI CAN Frame Example Initialization
The writing messages section contains three loops. These loops are discussed below.
The first loop is the Cmd Loop and it is pictured below.
Figure 9. Cmd Loop
This loop is controlled from the front panel. When the button Send Message? is selected, Data to Send is placed on the Process Outgoing queue to be read in the second loop (discussed below). To the user, this is all you have to do to output a message. The example will automatically use the correct transport protocol if a message over eight bytes is sent. If you want to output messages from anywhere else in the program, the process is the same. Simply queue that message on Process Outgoing and the example program will take care of the rest.
The second loop is called Process Outgoing Messages and is picture below.
Figure 10. Process Outgoing Messages Loop
This loop contains two J1939 VIs. The first is called J1939 Process Outgoing Messages. This VI first reads all messages off the Process Outgoing queue. Then, it determines if the message is eight bytes or less. If it is, it queues the message to the third loop (discussed below). However, if the message is greater than eight bytes, the VI determines if the message requires BAM or Connection Mode to transfer. It then opens the appropriate transport protocol connection locally and queues the messages necessary to open that connection on the network to the third loop.
The second VI is called J1939 Check Outgoing TP Timeouts. It is responsible for checking if any of the open transport protocol connections are able to transfer data packets (TP.DT messages). If any of these packets can be transferred, they are queued to the third loop.
The third loop is named Output Processed Outgoing Messages and is pictured below.
Figure 11. Output Processed Outgoing Messages Loop
This loop simply reads any messages on the queue from the second loop and outputs them on the CAN port. This queue is named Processed Outgoing.
The reading messages section contains two loops. These loops are discussed below.
The first loop is called Process Incoming Messages and is pictured below.
Figure 12. Process Incoming Messages Loop
This loop first checks if there are any messages on the CAN port. If messages exist, those messages are read and passed to a VI called J1939 Process Incoming Messages. This VI processes one CAN Frame at a time. It first filters out any messages that aren't intended for the device. Then, if the message is intended for the device, it determines the message type. If the message is a standard PDU 1 or PDU 2 message, it is queued to the second loop (discussed below).
In the case that the message is a transport protocol message, it determines if the message is for a message being generated or received by the device and handles it appropriately. It also waits until all messages are received and reassembled for a specific PGN before queuing the completed message to the second loop. The user will never see any of the transport protocol messages, just the finished message.
For other special messages, like requests, address claiming, etc. there are just stubs that don't currently do anything. These stubs could be implemented such that more J1939 features are available but that will be the responsibility of the user and outside of the scope of this example.
The second loop is called Read Processed Incoming Messages and is pictured below.
Figure 13. Read Processed Incoming Messages Loop
The loop returns completed messages. Every message will be in the same format, even if the message was received via a form of transport protocol. The only difference is the data will be over eight bytes. From here, you can process the message.
In this example, the last thing we do is close the NI-CAN reference. No clean up is necessary for the J1939 code. This section is pictured below.
Figure 14 J1939 NI CAN Frame Example Code Clean Up
This example is named J1939 cRIO Example.vi. It shows how to implement the reading and writing of transport protocol messages on CompactRIO. This example functions in the same way as the NI-CAN example discussed above. There are no difference in terms of the J1939 specific code. However, there are some differences between the examples at the top level due to the different platforms being used. These differences are discussed below.
Note: To open this VI, first open the project named J1939 cRIO Example Project.lvproj that resides in the
Examples\cRIO FPGA Example folder. Once the project is open, expand the RT CompactRIO Target inside and double click on the J1939 cRIO Example VI.
The targeting of a CompactRIO requires the use of the LabVIEW Project. Our project is called J1939 cRIO Example Project and is pictured below.
Figure 15. J1939 cRIO Example Project
The project contains configuration information about our CompactRIO. This includes information like IP address, FPGA target type and IO modules. Note the NI 9853 High Speed CAN module in slot 1 of our FPGA Target. This is what we are using to read and write our CAN Messages.
Also, notice that there are two VIs in this project. One is under the RT CompactRIO Target and is called J1939 cRIO Example.vi. This is our top level VI. The other VI is under FPGA Target and is called J1939 cRIO Example_FPGA Main. This VI is responsible for reading and writing CAN messages. It is started and controlled by our top level VI.
Last, take notice of the two DMA channels named CAN Outgoing and CAN Incoming. These two channels are used to transfer CAN messages between the cRIO and FPGA programs.
The front panel of the cRIO reference example is the same in function as the NI-CAN example above. The only difference is that the baud rate and CAN Port aren't available as setup parameters. These parameters have to be set using the LabVIEW project. By default, this example uses port 0 of a NI 9853 in slot 1 with a 250k baud rate. Please consult your module documentation and LabVIEW help for more details on setting these parameters.
The block diagram can be broken into the same four sections as the NI-CAN example. Only the differences will be discussed. For additional information, please review the sections above.
The differences in the cRIO example initialization section are hardware specific only. Instead of initializing our NI-CAN hardware and Frame API, we initialize and start our FPGA VI (J1939 cRIO Example_FPGA Main). This is pictured below.
Figure 16 J1939 cRIO Example Initialization
The writing of messages happens on the FPGA Target when using a CompactRIO. This requires two VIs, one running on the FPGA and one running on the CompactRIO controller. It also requires a mechanism for transferring data between these two VIs. These are discussed below.
Writing messages on the CompactRIO has three loops just as the NI CAN example above. The only loop that is different is the Output Processed Outgoing Messages Loop displayed below.
Figure 17. Output Processed Outgoing Messages Loop
This loop still reads from the Processed Outgoing queue but instead of outputting a CAN message to the NI CAN Frame driver, it writes it to a DMA FIFO called CAN Outgoing. This DMA FIFO sends the data to the VI running on the FPGA.
In the FPGA code, there is a loop called Write to CAN Module Loop, pictured below.
Figure 18. Write to CAN Module Loop
This loop reads from the DMA FIFO and constructs a CAN Message. It then sends this message to the CAN Port.
Reading messages with the CompactRIO example are broken into two pieces. One piece runs on the CompactRIO controller and the other runs on the FPGA Target. These are discussed below.
When we read a CAN message on CompactRIO, we actually need to start with the FPGA code. The FPGA VI contains a second loop called Read CAN Module Loop and it is pictured below.
Figure 19. Read CAN Module Loop
In this loop, we check for any new messages. If none are available, we timeout and do nothing. If messages are available, we send the data into the DMA FIFO named CAN Incoming. This sends the message up to the host.
On the CompactRIO side, we read any new messages sent on CAN Incoming in the Process Incoming Messages Loop, shown below.
Figure 20. Process Incoming Messages Loop
When a message is received, we format it to a standard CAN cluster and pass it to the J1939 Process Incoming Messages.vi. At this point, this loop is exactly the same as the NI CAN Frame example above.
The rest of the code for reading messages is the same as described above.
The only difference is the code cleanup section is that we close the FPGA reference instead of the NI-CAN reference.
Figure 21. J1939 cRIO Example Code Clean Up
This example is named J1939 NI-XNET Frame Example.vi and it is located at
Examples\NI-XNET Frame Example folder. It uses NI-XNET PCI/PXI CAN hardware and the NI-XNET API to show an implementation of reading and writing transport protocol messages. The example code abstracts the packetization, transmission and reconstruction of these messages from the user such that there is no difference in the reading/writing of messages greater than eight bytes and messages of eight bytes or less.
The front panel of the NI-XNET reference example is the same in function as the NI-CAN example above. The only difference is the frame cluster uses the NI-XNET CAN frame cluster instead of the NI-CAN frame cluster. The other difference is that the CAN port can be selected with an IO Control. The IO control automatically detects which CAN ports are available on your system.
The NI-XNET example is very similar to the NI-CAN example, so we will only show the main differences here.
Initialization in this example consists of creating an NI-XNET input stream session using IO Control from the front panel to select the CAN port. The input stream session will enable us to read every frame off the bus. We also need to set the baudrate for our session. We also initialize our J1939 code. For the J1939 specific code, this means creating multiple queue references, clearing any previously used memory and setting the current device address.
Figure 22. NI-XNET Example Initialization
The only difference in the NI-XNET Example (from the NI-CAN example) is how we actually output the messages on the bus, using the Output Processed Outgoing Messages Loop.
In this loop, we convert the frames from the J1939 format to the NI-XNET frame format and write them to the bus.
Figure 23. NI-XNET Output Processed Outgoing Messages Loop
This loop first checks if there are any messages on the CAN port. If messages exist, those messages are read and passed to a VI called J1939 Process Incoming Messages. This is very similar to the NI-CAN version.
Figure 24. NI-XNET Process Incoming Messages Loop
If you are using NI-CAN Series 2 hardware or CompactRIO CAN Products (NI 9852 and NI-9853) modules:
Examples\NI CAN Frame Example.
If you are using NI-XNET hardware (NI-851x):
This reference application was created by the NI Systems Engineering group.
Application Software: LabVIEW Development System 8.6
Hardware Group: CAN
Example code from the Example Code Exchange in the NI Community is licensed with the MIT license.