Demystifying Modbus Function Codes

12 min read

Dec 13, 2018 2:00:00 PM


With the wide range of devices that use Modbus for their communication protocol, you'll find many different interpretations, terminology and labels with respect to how to access different types of data in those devices.  Sometimes a device manual might only refer to the supported Modbus function codes and the range of offsets available for those function codes.

In this blog post, I will step through the specifics of Modbus function codes and how they pertain to addressing, and how they affect what addresses to use in TOP Server for Wonderware applications.

In my previous blog post Demystifying Modbus Register Addressing, I discussed how confusing Modbus addressing can be due to how different device manufacturers describe their implementations in their device manuals.  I know some of you who read that post were looking for a little more depth on how specific Modbus function codes come into play.

So, in this post, I'm going to discuss the Modbus functions codes that TOP Server uses to read and write the different types of Modbus memory addresses and how they correspond to the actual addresses your client is requesting, using TOP Server for Wonderware applications as an example.

Modbus Function Codes Supported by TOP Server

A function code (FC) in Modbus is a specific code used in a Modbus request to tell the Modbus slave device what type of memory (i.e. holding registers, input coils, etc) to access and what action to perform on that memory (i.e. reading or writing).  The following table lists the specific Modbus function codes used for communicating by all of the Modbus drivers included in the TOP Server Modbus Suite:

TOP Server supports all common Modbus Function CodesDepending on which type of address (holding register, internal register, input coil or output coil) you are reading or writing from your client application, that will determine which specific function code the TOP Server Modbus driver will use in the actual protocol request to your device.

There are also some special settings in the TOP Server Modbus drivers that allow for more flexibility for different Modbus implementations in a device that we will cover shortly.

And, though we won't go into the specifics in this post, Modbus flexibility in TOP Server goes even further with support for Modbus-variants in specific non-standard drivers such as Enron Modbus, OMNI Flow, Lufkin ELAM, Honeywell UDC, and even Yaskawa Memobus-based drivers.

Get Your TOP Server Free Trial Now

How Modbus Function Codes Correspond to Addressing

As we covered last time, when we're talking about the Modbus protocol and addressing particular locations of data (or types of memory), there are generally four different types of Modbus addresses:

  1. Holding Registers – 16-bit (Analog) addresses with read/write access (4xxxxx)

  2. Internal Registers – 16-bit (Analog) addresses with read only access (3xxxxx)

  3. Input Coils – 1-bit (Boolean) addresses with read only access (1xxxxx)

  4. Output Coils – 1-bit (Boolean) addresses with read/write access (0xxxxx)

We also discussed last time how a lot of device documentation doesn't always provide detailed listings of Modbus addresses in terms of the type of address such as 4xxxxx or Holding Register.

So, since we're talking in more depth about Modbus function codes, it is essential that we talk about Modbus addresses in terms of the type of memory a particular address is and whether or not it can be read from and written to or only read from.

Both of those factors determine which Modbus function code will be used in sending a request to a device.  Let's discuss each function code and the corresponding address and function it performs:

  • Modbus Function Code 1 (Hex 0x01)

    This function code is used by TOP Server when requesting a read of one or more (up to 2000 at a time) output coils or 0xxxxx type discrete/boolean addresses.

    Output coils are read/write access - you'll see support for Function Codes 5 and 15 a further down the list.

  • Modbus Function Code 2 (Hex 0x02)

    This function code is used by TOP Server when requesting a read of one of more (up to 2000 at a time) input coils or 1xxxxx type discrete/boolean addresses.

    Input coils are read-only in a Modbus device, so you'll notice there is no function code designated for writing to a 1xxxxx type address.

  • Modbus Function Code 3 (Hex 0x03)

    This function code is used by TOP Server when requesting a read of one or more (up to 125 at a time) holding registers or 4xxxxx type analog addresses.

    It is also possible to access individual bits within holding registers using function code 3 by simply appending a .x syntax at the end where x represents the bit within the register you wish to read (i.e. 400001.0 would access Bit 0 in Holding Register Offset 1).

    Because holding registers are the most commonly supported type of memory in most Modbus-capable devices, Modbus function code 3 is probably the most widely used function code.

    And holding registers are read/write access - so you'll see support for Function Codes 6 and 16 further down the list.

  • Modbus Function Code 4 (Hex 0x04)

    This function code is used by TOP Server when requesting a read of one or more (up to 125 at a time) internal registers or 3xxxxx type analog addresses.

    As with holding registers, it is also possible to access individual bits within internal registers using function code 4 *u,e, 300004.2 would access Bit 2 in Internal Register Offset 1) - keep reading for information later on one vs. zero based bit addressing within registers.

    As with input coils, internal registers are read-only in a Modbus device, so you won't see a function code designated for writes to 3xxxxx type addresses.

    NOTE:  Yes, in case you noticed, FC 3 is used to access 4xxxxx addresses and FC 4 is used to access 3xxxxx addresses, just as FC 1 accesses 0xxxxx and FC 2 accesses 1xxxxx addresses - those are NOT typographical errors.

  • Modbus Function Code 5 (Hex 0x05)

    This function code is used by TOP Server when writing to a single output coil (0xxxxx) - also referred to as "forcing" a coil.

  • Modbus Function Code 6 (Hex 0x06)

    This function code is used by TOP Server when writing to a single holding register (4xxxxx) - also referred to as "presetting" a register.

  • Modbus Function Code 15 (Hex 0x0F)

    This function code is used by TOP Server when writing to (forcing) multiple output coils (0xxxxx).  Now it's not uncommon for some devices to only support FC 15 for both single and multiple writes to output coils.

    To address such situations, TOP Server Modbus drivers have a special setting in the device settings for disabling "Modbus Function 05" - when disabled, the driver will only use FC 15 for all writes to output coils.

    Using Modbus Function Code 15 Only in TOP Server

  • Modbus Function Code 16 (Hex 0x10)

    This function code is used by TOP Server when writing to (presetting) multiple holding registers (4xxxxx). As with FC 15, it's not uncommon for device manufacturers to only support FC 16 for both single and multiple writes to holding registers - it's a cheaper implementation to only have to add support for one vs. two function codes.

    There is a setting in TOP Server Modbus drivers for this situation, as well, that allows you to disable "Modbus Function 06" such that, when disabled, the driver will only use FC 16 for all writes to holding registers.

    Using Modbus Function Code 16 Only in TOP Server

  • Modbus Function Code 22 (Hex 0x16)

    This function is specifically used for bit writes within holding registers (4xxxxx) in a single transaction - it is disabled by default in the Modbus driver device properties in TOP Server because many Modbus devices don't support FC 22, choosing instead to support an alternative method.

    The alternative method, which is the default and most common method, is to perform a Read/Modify/Write operation for the bit within the holding register.

    In this method, when a client application requests a write for a holding register bit, the following occurs:

    • TOP Server will perform an FC 3 read of the entire register

    • The driver then modifies only the bit in question (which changes the overall value of the 16-bit value of that holding register)

    • The modified 16-bit value is then written back to the Modbus slave device using FC 6 or 16 (depending on what your device supports and what is enabled per the special settings described a moment ago).

    As you have probably guessed, there is some risk with this common method, especially if holding register values in your Modbus device are frequently changing - performing a Read/Modify/Write operation could conceivably change bits to an incorrect state if they had previously changed in the time it takes for the operation to complete.

    For instance, let's say we're performing a read/modify/write operation on Bit 1 of 400001.  If Bit 2 was "on" at the start of the operation but had switched to "off" prior to the write, it would be turned "on" again incorrectly.

    FC 22 is designed to avoid that risk by simply modifying individual bits in holding registers directly, leaving the surrounding bits untouched.  The problem is that FC 22 can only be used if the actual Modbus slave device has implemented support for FC 22, which frequently is not the case.

    So make sure to confirm if your device actually supports FC 22 or not - if so, you can enable "Holding Register Bit Writes" in the device properties of Modbus drivers in the TOP Server.

    Using Modbus Function Code 22 For Holding Register Bit Writes in TOP Server

So, the function determines which type of memory is being accessed and whether it is a read or write operation.  But function codes work together with other information in a Modbus request, including what is referred to as an offset.

How Offset Addressing works with Modbus Function Codes

TOP Server Modbus Suite drivers support the following address ranges for the different memory types:

  • Holding Registers – 400001- 465536

  • Internal Registers – 300001- 365536

  • Input Coils – 100001- 165536

  • Output Coils – 000001- 065536

So we support Offsets 1 to 65,536 for all memory types.  But what is an offset?

The way I typically explain offsets is that you have to look at the first digit of an address (i.e. 4, 3, 1 or 0) as telling the driver which type of memory to access.  Everything after the first digit is the offset - the specific memory address that you're interested in within that memory type.

This is why, as we covered in more detail in the previous blog post, an address of 4001, 40001 and 400001 are all the same - they are all requesting holding register offset 1 (and, as we covered earlier, a read request would be using Modbus function code 3 and write requests might be using Modbus function code 6 or 16, depending on your settings and what your Modbus slave device supports).

Modbus Holding Register Offsets
Modbus Document Says: TOP Server Says it Supports:
4 001 4 00001
4 0001 4 00001

The Modbus function code and the offset work together in a Modbus request to tell the device a specific piece of information that should be returned or modified.

What is Modbus Zero-Based vs One-Based Addressing?

One final subtlety that is important when discussing offset-based Modbus addressing is whether a device supports zero or one-based addressing.  Originally, zero-based addressing was the intended implementation with Modbus.  But, as time progressed and Modbus, as an open protocol, was so widely adopted, a concept known as one-based addressed was adopted by certain device manufacturers.

Zero-based addressing involves the first offset of a memory type starting at zero.  So, for instance, if you were requesting holding register 400001, the actual Modbus protocol request would be FC 3 for offset 0.  And 400002 would request FC 3 for offset 1, and so on.

As you can imagine, that could be quite confusing.  So some manufacturers adopted an implementation called one-based addressing.  With one-based addressing, the offset is aligned with the actual address request.  For instance, if you request holding register 1, the request still uses FC 3 but for offset 1.  And 400002 would request FC 3 for offset 2, and so on.  It is much more "user-friendly".

Table - Modbus Zero vs One Based Addressing

However, because there are some devices that support zero-based and some devices that support one-based addressing, it is important to be aware of this.  TOP Server Modbus drivers have a configurable setting for specifying which implementation your Modbus slave device supports.

Using Modbus One-Based Addressing in TOP Server

The default setting for "Zero-Based Addressing" is enabled, since that is the Modbus specification default.  Switching this setting to disabled will result in the driver using one-based addressing.  Always make sure you're using the correct setting as to not do so means the value being displayed could be for the wrong address in your device.

For example, if you read a value for 400001 and it's the "wrong" value compared to what you're expecting, look to see if it is the value of the register next to 400001.  If so, you need to swap from one to zero-based addressing (or vice versa).

Additionally, there is one-based or zero-based bit addressing.  By default, TOP Server Modbus drivers support zero-based bit addressing, as well, since it is the Modbus specification default.  This means that bits are addressed from 0 to 15.

One-based bit addressing means that bits are addressed from 1-16 - again, what feels more natural to a human counting 16 bits.  And, again, TOP Server Modbus drivers have a configurable setting for that, based on what your device supports.

Using Modbus One-Based Bit Addressing in TOP Server

As with offset addressing, the bit addressing method selected in TOP Server must match what your device supports - otherwise, if incorrect, the bit values you will be accessing will be for the wrong bits.  The setting should be left enabled for 0-15 bit access or should be disabled for 1-16 bit access.

Always consult the manufacturer's documentation or speak with the manufacturer to determine which method they support.  If you notice a bit is "on" but should be "off" (or vice versa), you may need to switch this setting.

As you can see, Modbus has a lot of quirks being such a well-established and widely used open protocol.  A flexible Modbus master such as TOP Server provides a range of configurable settings (including swapping Byte, Word and Dword ordering, which will be covered in a future post) to work with the widest range of Modbus slave implementations regardless of manufacturer for the greatest compatible.

Don't forget to subscribe to our blog to find out about the latest updates to TOP Server and for other useful tutorials and resources as well as take a look at our other Modbus related Technical Blog posts.

Ready to put TOP Server's flexible Modbus drivers to work with your own Modbus devices?

Get Your TOP Server Free Trial Now

Kevin Rutherford
Written by Kevin Rutherford

Software Toolbox Technical Blog

We're engineers like you, so this blog focuses on "How to" appnotes, videos, tech team tips, product update announcements, user case studies, and other technical updates.  Subscribe to updates below. Your feedback and questions on posts are always welcomed - just use the area at the bottom of any post.

Subscribe to our Blog

Recent Posts

Posts by Topic

See all