Quandary: Software Layout of Registers

I am laying out register definitions for an RTU based slave device. Previously, I would leave holes in my Modbus address map for registers that spanned more than one 16-bit word. For example, for two floating point registers (32 bits each), I might define the following (note that Modbus Addr 11 is undefined):

<pre>
Modbus Addr: 10, Register Type: float, Register Name: sensor_1
Modbus Addr: 12, Register Type: float, Register Name: sensor_2
</pre>

But since my slave device is controlling what gets returned in response to the master's request, leaving a hole isn't necessary:

<pre>
Modbus Addr: 10, Register Type: float, Register Name: sensor_1
Modbus Addr: 11, Register Type: float, Register Name: sensor_2
</pre>

The slave device would have no trouble returning the floating point value for sensor_1 when requested on address 10, nor the floating point value for sensor_2 when requested on address 11.

Though not immediately intuitive, I don't see any problem with this approach, and it would let me compact the register addresses.

<b>The question:</b> Is this "compressed" approach idiomatically acceptable? Or do slave implementations always allocate unused registers to reflect the number of words actually spanned?
 
Though it might work for some slaves there are slaves that will have problems with this approach.

If you take a look at the modbus manual "http://modbus.org/docs/PI_MBUS_300.pdf" you will see modbus register are 16 bit registers. A request from the master requests a number of registers and the response from the slave will be a number of bytes. In many modbus devices succeeding registers can contain integers, bytes, floats, long floats, ... and it is up to slave to extract the correct data. So register 1 can contain an integer value, register 2 a 4 byte floating point, register 3 will be 2 bytes of the previous floating point, ...

Look at modbus as a 16 bit register communication protocol. Whatever is in those 16 bit registers depends on the device.

If you want to access the registers in your example in one request you have to use "Read holding register: 03", Starting address: 10, No. of registers: 4. The slave will respond with 8 bytes of data.
If your second request the master uses "Read holding register: 03", Starting address: 10, No. of registers: 2. The slave will respond with 4 bytes of data which is not correct.
 
>Though it might work for some slaves there are slaves that
>will have problems with this approach.

I totally understand and agree with your answer, but you missed an important detail: I am implementing the code for a modbus slave, not a master, so I can guarantee proper behavior.

Given that, my original question stands: is there any violation in the spec or common sense that prevents this "overlapping" approach?

(I should have mentioned that my original motivation for this is that it would reduce the size of my dispatch table in the slave, always a consideration for embedded devices!)
 
The short answer:

In order for most Modbus masters to be able to communicate with your slave implementation, you must make each floating point value (32-bits) span two registers (16-bits each).

The long answer:

Your description of "holes" in your address map is not actually how it works:

>Previously, I would leave holes in my Modbus address map for registers that spanned more than one 16-bit word.
>For example, for two floating point registers (32 bits each), I might define the following (note that Modbus Addr 11 is undefined):<pre>
> Modbus Addr: 10, Register Type: float, Register Name: sensor_1
> Modbus Addr: 12, Register Type: float, Register Name: sensor_2
</pre>
In reality, you are mapping your registers as follows:<pre>
Modbus Addr: 10, Least-significant word (16-bits) of sensor_1's 32-bit float value
Modbus Addr: 11, Most-significant word (16-bits) of sensor_1's 32-bit float value
Modbus Addr: 12, Least-significant word (16-bits) of sensor_2's 32-bit float value
Modbus Addr: 13, Most-significant word (16-bits) of sensor_2's 32-bit float value</pre>
Using the mapping above, a Modbus master would read 4 registers to receive 8 bytes of data containing your 2 float values. It is common for Modbus masters to support combining two registers together and interpret the value as a 32-bit float.

In your "compressed" approach, however, a Modbus master would read only 2 registers, but still needs to receive 8 bytes of data containing your 2 float values. In this approach, you have redefined what a Modbus register is by requiring it to be 32 bits instead of 16 bits. While there are Modbus masters out there that do support this (Enron/Daniels Modbus), they are rare.
 
If the device does not use 16 bit register addressing, it is not Modbus. Call it something else.

There are no 'holes' in your original Modbus map. There's data in those so-called 'holes; the remaining 16 bits of a 32 bit floating point value, in your example registers 11 and 13.

A master/client would not use one of those 'hole' registers as a starting address, but your 'hole' register addresses are needed to make sense out of a Modbus map.

There are thousands of guys like me who fully expect to find what you call 'holes' in Modbus maps where there are floating point values or long integers. Take away the "holes" and the implication is that the data is 16 bit integer data, not 32 bit floating point or 32 bit any format.

Stick with the way you're done it in the past.

Your revised addressing is likely to fail with conventional Modbus master/clients because Function Code 03's poll format uses the register starting address and a requested number of registers, which will always be 16 bit registers (because it's real Modbus). If your revised-non-Modbus-mode slave replies with twice the number of 16 bit registers as requested the master/client will choke on the reply. Try your revised scheme out with some of the freebie master/clients out there and see how it fares.
 
Top