AN0502: Connecting your GUI as a Modbus Slave


Required Reading

Before proceeding with this applications note, ensure you have reviewed the following: For more information on Modbus, consult this list of resources.

Binding the Protocol to the Hardware

The first step in connecting as a Modbus slave device is to create a link node in the Resources area. In SHIPTide, go to the Resources area and right click on the “links” section and add a new link node. This node will bind the Modbus slave protocol to a physical communications channel, so set up this new link node with properties like this:
Creating the new Modbus Slave link
Each channel in a platform may only be bound once to a single protocol. For example, UART0 can only be bound to a single protocol (e.g. MODBUS_SLAVE_RTU).

Creating One or More Virtual Slave Devices

Within a given link, there may be one or more linkset nodes. Each linkset encompasses all the traffic between two endpoints in a link. On the slave side of master/slave protocols (for example the MODBUS_SLAVE_RTU), the GUI may be responding as one or more Modbus slaves. Even though the protocol is running on a single physical communications channel (e.g. UART0), each linkset within the link can act as one of a number of independent virtual slaves. Adding two linksets to our prior example might look like this:
Example link with two linksets
In this example GUI, our SIM is acting as a Modbus slave attached to UART0, potentially one of many other Modbus slave devices on the physical network. This physical network (aka channel) could be, for instance, a multi-drop RS485 network with many slaves of which our SIM is only one. Our GUI, because it has the two linksets at ID #1 and #13 created, will respond as if it were two of those slaves on the network.

Adding Shared Link Variables

The SHIP GUI communicates with a remote network device using the concept of link variables. These are variables who’s values are shared, nearly automatically, across the communications link. One party must own the actual true value of the variable, other parties on the network merely need to get copies of the latest value in order to display, react, control, or otherwise act on that value. For example, if a device on a network has a motor RPM sensor, that device “owns” that value – perhaps represented as a 16-bit signed (for motor direction) RPM value. Other devices on the network that need to know that motor’s RPM need to somehow get access to that devices “RPM variable” periodically. A SHIP GUI, for example, may need to update a value on the screen showing the motor RPM every second or even more frequently. These shared network variables are represented in your SHIP GUI each as linkvar nodes describing these shared network variables within a given linkset. The linkvar properties available depend on the protocol selected. The following are normal properties of a linkvar:
Property Name Description
name A unique variable name within the linkset
datatype The data type of this link variable; may be limited depending on the protocols
address Most protocols require each variable to have a unique address/location/id number assigned
direction Most protocols need to understand if this is an input or output variable
enabled Defaults to true, but can be set false in SHIPTide. Only enabled variables participate in polling (if applicable).
The direction can be a bit confusing: it is always with respect to SHIPEngine and the GUI. So an output direction means the data is supplied by SHIPEngine to the device across the network on the remote end of the linkset, regardless of whether the linkset is a master or slave in a master/slave environment. Similarly, an input direction means that the data is coming into the variable from the remote end of the linkset. Remember that “in” and “out” are with respect to your GUI in SHIPEngine. The datatypes are protocol dependent, and, in the Modbus case, may be limited to the basic Modbus data types of Boolean and Short. Expanding the example above with four linkvars looks like this:
Example linkset with four link variables (linkvars)
Our example here is, perhaps, a hypothetical GUI controlling a pump. Our GUI (in a Sail script) could turn on the pump by setting the pumpOnRequest output Boolean linkvar to “true”. Since Modbus masters poll their slaves, the next time the master polls slave #1 address 0x4000 (“pumpOnRequest”, a Boolean), it will read a “true” at that shared variable location, indicating to the master (the pump) to turn on. It may also poll slave #1 address 0x2000 (“pumpRPMRequest”, a Short) to determine the requested RPM before turning the pump on. It may continue to poll these two locations to watch for a request to stop the pump or change the RPM. Also, as the pump turns on and off, and its actual RPM changes, it may send those values to slave#1 address 0x4001 (“pumpOn”, a Boolean) and 0x2002 (“pumpRPM”, a Short) respectively. Note that just because the GUI “requests” that a remote device performs some action does not mean the remote device actually does it. The GUI (in a Sail script) might request the pump turn on, but it may not happen for whatever reason (the pump is overheated, for example). Timeouts and other mechanisms can be done in the GUI to watch for these conditions. A good practice is to have visual indicators on the GUI reflect the actual remote state, rather than the requested state. For example, an RPM reading in the GUI should reflect the value of “pumpRPM”, not “pumpRPMRequest”.

AN0500: Using Modbus in SHIP – A Step-by-Step Tutorial


First Steps: SHIP Communications Concept

You’ll want to review the Communications in SHIP Overview first to get acquainted with the how communications work via link, linksets, and linkvars within SHIPTide projects. These same concepts are used for the various protocols supported in SHIP, including Modbus.

You’ll also want to review the Modbus protocol itself and some more specifics about how it’s used in SHIP.

Function Codes

As described in the Modbus protocol, each “command” issued by the master to the slave (and each response from the slave) has a command (or “function”) code: a single byte that uniquely identifies the command (or response to the command) type.

The function code used for messages by SHIPEngine depends on the configuration of each individual link and how its linkvar’s are setup. Here are two tables showing how the datatype/direction used when defining a linkvar maps to the Modbus protocol data concepts and function codes used depending on if the SIM is acting as a master or slave.

Standard Function Codes

When your GUI configures a link as a Modbus Master link (or as a Slave and receiving Master commands), the following standard Master function codes are used by the underlying communications engine in SHIPEngine to issue (or recognize) Master commands:

SHIP Modbus Master Used Function Code Table
SHIP DatatypeDirectionReadRead MultipleWriteWrite MultipleModbus Type
BooleanInput0x02N/AN/AN/ADiscrete Input
ShortInput0x04N/AN/AN/AInput Register
ShortOutput0x03N/A0x06N/AHolding Register

When your GUI configures a link as a Modbus Slave, (or as a Master and expecting a Slave response), the following standard function codes are used by the underlying communications engine in SHIPEngine to issue (or recognize) Slave commands:

SHIP Modbus Slave Response Function Code Table
SHIP DatatypeDirectionReadRead MultipleWriteWrite MultipleModbus Type
BooleanInput0x020x02N/AN/ADiscrete Input(s)
ShortInput0x040x04N/AN/AInput Register(s)
ShortOutput0x030x030x060x10Holding Register(s)

Extended Function Codes

While the above only deals with standard Modbus datatypes, SHIP also supports the transfer of Integer and Float types via both (a) a standard approach using the write/read multiple functions and (b) the Daniel/Enron modbus extensions approach using those functions in a different way. For more information, see:

SHIP also support String and even generic Buffer transfers via custom function codes and payload formats


Setting up the SIM as a Modbus Master or Slave

On the GUI side, you set a Modbus link in SHIPTide, the GUI Development tool.

To create a Modbus link you create a link node in the resources area and “bind” that link to a communications port (e.g. UART0 or USB_CDC). The link node also has all the properties to configure the Modbus protocol specifics, including choosing Master or Slave mode, ASCII or RTU, and which (if any) extensions are enabled.

There are two application notes that deal specifically with the basics of setting up and using the SIM as a Modbus Master or Slave:


Example Projects

There are two example projects in the .zip file attached to this Application Note: one for ASCII Master and one for ASCII slave. Download the .zip and unpack it; install the project of your choice to a directory on your PC. Launch SHIPTide and open the project.

Defaults in the Examples

The SubProtocol: ASCII

The projects come configured for Modbus ASCII. It is easy to modify them for RTU mode by changing the link node property from ASCII to RTU in SHIPTide, but ASCII mode can be very helpful in debugging. It is also better “framed” than RTU mode, as every ASCII message starts with a “:” and synchronization is easier.

The Comms Link: USB CDC

The example projects are also set up to use USB CDC as the communications link, making it easy to connect the SIM to a PC and (using a terminal program) see the traffic coming out of the SIM. You can even use the Modbus simulators such as at [1] for standard mode commands to simulate the device side on your PC. You can easily change the binding of the link to (say) a UART by changing the link node properties.

The Platform

Check the platform the example project is configured for using the Project->Change Platform/Variant menu and set the example to the platform you are using.

The Projects in Detail

The ASCII Master demo has 4 buttons to interact with. The buttons and their descriptions are listed below. • “SEND COIL” : Sends out a Modbus RTU set coil packet to slave ID 0x01 at address 0x0003. Value sent flips from 0 to 1 repeatedly. • “SEND HOLDING REGISTER” : Sends out a Modbus RTU set holding register packet to slave ID 0x01 at address 0x0000. Value sent increments with each press. • “MANUAL SLAVE POLL” : Triggers a single polling sequence on addresses 0x0000, 0x0001, 0x0003, 0x0004 at slave ID 0x01. • “AUTO POLLING ENABLED”/ “AUTO POLLING DISABLED” : Enables auto polling of addresses 0x0000, 0x0001, 0x0003, 0x0004 at slave ID 0x01 every 1/10th of a second.

Additionally, there are various fields in the table below the buttons showing what data (not full packet contents) had last been sent or received as a result of a polling/sends.

The ASCII Slave demo is basically setup to be driven and polled by the ASCII Master demo and has a few buttons to interact with polled values and display values sent to it.

When either are loaded onto your SIM, you should be able (assuming drivers installed etc) to plug it in via USB to your PC and verify you see a device labelled “Serious CDC/ACM Device (COM#)” in the “Ports (COM & LPT)” section of your device manager.

If you connect to that COM port via a terminal application like Tera Term VT you can then receive and send packets manually via ASCII. Same could be done with literal bytes if switched to RTU, but ASCII is far easier.

Our SIMs connect as a composite device with VID 0x25D8, PID 0x0051 where the first interface is a vendor class interface that purely is used for SHIPBridge communications and the second interface is CDC/ACM which is what you’ll be targeting just like the terminal application.

What About on the Other End of the Wire? Free Modbus Stacks

If you’re looking for a free adaptable Modbus stack, the site includes several off-the-shelf examples in C you can easily port to your specific MCU. Even if you don’t start with that code, Modbus is a very simple protocol so writing a small bit of code to handle the particular function codes you want to use in the end is not very challenging, especially if you implement a Modbus Slave on your side of the wire. The Master is a bit trickier, so generally you’ll want to use the Master mode in the GUI if you can.

Alternatives to Modbus

Modbus is easy, cheap, and straightforward. It also allows multiple slaves. But Modbus is polled, and not all that rich when it comes to data types and communications flexibility.

See Protocols for a list of other protocols supported in SHIP.


AN0503: SHIPTide – Setting up a Modbus Master Link

Ways of Connecting

Back to Back SIMs over UART or RS485/422
If you copy the project and modify it to be the “slave” side without the need for the polling timer, you can now use two SIMs back-to-back!

Using the UART, connect power and RX<-TX, TX->RX. On Gen5 SIMs (SIMx52, SIMx62) you can use crosswire RS485 by connecting the two grounds and wiring AB to YZ back to back on the two SIMs — make sure you have Half Duplexand Termination selected on both ends.

Single Ended to a Terminal
You can also just use the project and connect to a PLC or external Modbus slave device over UART or RS485. The SIMx52 and SIMx62 Technical Reference Manuals (TRMs) on the portal have detailed instruction on how to connect the RS4xx port.