Electronic – modbus register address vs. register number; absolute address vs. offset

addressingmodbus

I'm developing a Modbus Slave device, and I'm having a little trouble understanding how to name/address my registers.

Let's say I have 2 Discrete Inputs and 2 Input registers. From Modicon standard, the Discrete Inputs will have register number 10001 and 10002, while the Input registers have 30001 and 30002.
Reading here and there, it looks like these will translate to register addresses 10000, 10001 and 30000, 30001.

Now, how to access these registers? What will be passed in the Modbus message starting address field? This is my firmware and can do whatever I want, but what is the standard? (this is what I don't understand)

I see 2 options:

  • absolute address approach: if the user wants to read the first Input register he'll send 30000 in the starting address field; from firmware side, I know it is an Input register both from the function code and from the register address itself, and I know it's the first one since I received exactly the address of the first one
  • offset approach: if the user wants to read the first Input register he'll send 0 as starting register; from firmware side, I know it is an Input register from the function code, and I will look for the first Input register since I received a 0 offset

The first approach seems more reasonable for me, since it avoids registers access errors;

  • absolute address approach: if the user sends a read Input register function code for address 10000 I will answer with an error code; maybe the user wanted to read an Input register, but sent the wrong address, or maybe he wanted to read a Discrete Input but sent the wrong function code; better notify him with an error than send a data that he'll probably misuse
  • offset approach: if the user sends a read Input register function code for address 0 I will answer with the data; but what if he wanted to read a Discrete Input but sent the wrong function code? Dumb him, ok. But since the same starting address can refer to 2 data types (or more, if there are Coils and holding Registers, too), I'll also feel a little guilty

Besides my preferences, I have a "real case scenario" that support the offset approach. I've interfaced my device with a gateway that translate the Modbus to another fieldbus protocol. To configure this gateway I need to define the Modbus addresses that will be periodically read/write. I need to use 6-digits addresses. So, in the example above, the 2 Input registers will be 300001 and 300002, and the 2 Discrete Inputs will be 100001 and 100002. From firmware side, for both data types I receive 0 and 1 as starting addresses, so the second approach (starting address indicates the offset) is used.

Again, is there any standard way to approach the Modbus addressing?

Best Answer

About a decade ago, I've written a simple Modbus library for Linux. Apologies for the self-promotion. @Ron Beyer: at the time, I never heard of extended addressing - at the level od Modbus requests, the base and count are always unsigned 16bit types, and : the low-level addresses riding inside the Modbus request frames are always zero-based, starting literally from zero. At the framing level of Modbus addressing, the "object type" is encoded in the Modbus function: discrete inputs, coils, input registers, holding registers. And, the address space in that low-level frame always starts at 0. Thus, theoretically, if you only ever speak the low-level addresses, you can have 64k discrete inputs, and 64k coils, and 64k input registers, and 64k holding registers - at the low level, they are parallel address spaces. You can have a coil #2 and an input register #2 and they are two different objects, no ambiguity in their addressing/access.

Then there's the "upper layer of addressing" (anyone know the official name?), where you have e.g. 10001 to be the first discrete input, and 40001 the first holding register. I.e. this "uniform upper layer address space" has the Modbus object types identified by base offsets - and, the counting system is one-based.

If you need to convert between the upper-layer and lower-layer addresses, you need to subtract that nominal type-specific base offset and handle "off by one" (like Pascal to C array element counting/indexing).

As Ron Beyer has said, reality can be a mess.

Some vendors speak the raw framing-level zero-based register addresses, other vendors speak the upper-layer "uniform" addresses. Typically, I would expect vendors of "distributed I/O endpoint gadgets with Modbus support" to speak the raw register addresses. Versus: documentation to PLC programming, OPC servers or SCADA might speak the upper, more abstract "uniform address space". But especially with cheap SE Asian Modbus-capable slave gadgets, the documentation is often unclear about what layer it speaks (still chances are that anything above 10000 means the "upper" layer) and I've even seen broken implementations that had the "off by one" wrong for the layer they were speaking. And, you often do not know whether to ask for input vs. holding registers, or discrete inputs vs. coils, when reading = sometimes either works and the address spaces in fact overlap... If unsure, proceed by cautious trial and error.

Actually... the vendor's documentation on any sensors, actuators, drives etc. with Modbus capability tends to focus on its "business domain" = mechanical dimensions, power supply range, physical performance properties, ramps/curves, physical unit scales and encoding, environmental conditions, handling safety precautions, a vocabulary index, a legal disclaimer, a list of ordering codes, a global list of local service contacts... and the darn map of Modbus regiters, which is the first thing you need as an integrator (even at a pre-sales stage), being the only thing you cannot possibly figure out based on common sense, that tends to be buried somewhere real deep :-) and poorly annotated/explained. The best guarded secret.

Just kidding. It's actually getting better through the years.

EDIT: I've just noticed your notes about 1-based addresses above 64k, and a gateway device that converts between two fieldbusses.

I have met gateways by the HMS Corp of Sweden that can speak several protocols, including Modbus. These boxes tend to have their internal proprietary memory space and organization, and the native fieldbus-specific objects or address spaces get mapped into the internal uniform memory space. Understandably, that mapping is more or less freely configurable, and the resulting internal datapoint map is definitely custom or proprietary - there's not much point in asking for a standard in such hybrid devices.