Skip to content

Note

Why a Modbus point reads the wrong register

A Modbus point that is off by one, or reads half a number, is almost never a protocol problem. It is an addressing convention and a data type, and both are choices made at point creation.

  • Modbus
  • Integration
  • Station engineering

Written

Four groups, and the address that identifies them

Everything a Modbus device exposes falls into one of four groups, and the leading digit of the address the vendor publishes is what tells them apart.

GroupAddress conventionAccess
Coils00000 – 0nnnn, or 0x Single-bit digital outputs. Read and write.
Inputs (status)10000 – 1nnnn, or 1x Single-bit digital inputs. Read only.
Input registers30000 – 3nnnn, or 3x 16-bit values the device collects from the field. Read only.
Holding registers40000 – 4nnnn, or 4x 16-bit general-purpose values. Read and write.

A device is under no obligation to implement all four. A meter may have holding registers and nothing else.

The off-by-one

Decimal and hex addressing on the wire is zero-based: the first item in a group is item 0. So holding register 108 is addressed as 107 decimal, or 006B hex. Vendor documentation, meanwhile, almost always lists a five-digit Modbus address starting at 40001 — which is one-based.

Those two conventions differ by exactly one, which is why the symptom is a point that reads a plausible but wrong value rather than a fault. Coil Modbus 109 is decimal 108 and hex 6C. Read the neighbouring register of a meter and you get a number, just not the one on the label.

Set Address Format to Modbus and the problem disappears. You then type the vendor's address exactly as printed, with no arithmetic. On read-only client points it also saves setting Reg Type at all — the leading numeral does it, 3 for input registers and 4 for holding registers. For coils the driver ignores leading zeros, so 00109 and 109 are the same address.

The data type is a second, separate decision

Modbus does not describe its own payloads. The protocol moves 16-bit registers; what those registers mean is entirely the vendor's choice, and the only place it is written down is their documentation. Get it wrong and the point still polls happily.

Data TypeRegistersRange
Integer1 Unsigned 16-bit, 0 – 65,535. The default on a newly created point, and the usual reason a negative temperature reads as 65,000-something.
Signed Integer1 −32,768 – 32,767. Sometimes called a short.
Float2 consecutive 32-bit single precision, with three byte-order schemes to choose from (3-2-1-0, 1-0-3-2 or 0-1-2-3). The property default is 3-2-1-0.
Long2 consecutive Signed 32-bit. Same byte-order choice as float.
Double4 consecutive 64-bit double precision. Present in 4.15; the JACE target here runs 4.14, where it should be confirmed against that station's own enumeration.
Long 64-bit4 consecutive Signed 64-bit, with eight byte-order options, defaulting to 7-6-5-4-3-2-1-0. Present in 4.15.

Two things follow from the multi-register types. The first is that byte order is configured at the device, or globally at the network — so one wrong setting scrambles every float on that device at once, which at least makes it obvious. The second is that a float consumes the register you addressed and the next one, so point counts and address planning have to allow for it.

Writes round before they go out. Integer and Signed Integer round to the nearest whole number and clamp to their range; Long and Long 64-bit round; Float and Double do not round at all. A write of 20.6 to an integer holding register arrives as 21, and nothing reports that it was changed.

Bit-packed registers

Vendors routinely pack several unrelated values into one 16-bit register. The driver handles this with bit-level proxy extensions — NumericBits and EnumBits variants — where several points share the same Data Address and differ only in Beginning Bit and Number Bits.

A meter's tariff configuration is the classic case: one holding register where bits 8–15 hold the tariff number, bits 2–7 the start hour and bits 0–1 the start quarter-hour. Three points, one address, three bit windows. Reading that register as a plain integer produces a large meaningless number, which is what usually gets reported as "the meter is sending rubbish".

There is no discovery

Unlike most drivers, the Modbus point manager has no learn mode: no Discover button, no Discovered and Database panes. The protocol carries no self-description, so there is nothing to discover. Every point is created by hand from the vendor's register map.

What the New Points window does give you is Number To Add, which creates consecutively addressed points from a starting address in one go. Since devices normally address related data consecutively, that covers most of a register map in a handful of operations.

A gap in the map is a fault, not a null. Requesting a range that includes an unimplemented address makes the device return an illegal-data-address exception for the whole request. If holding registers stop at 40015, a read of 40003–40015 is fine and a read of 40003–40017 fails entirely — so one over-reaching point can take out a block of good ones.

When a point goes to fault

Open the point and read ProxyExt > Fault Cause. It normally contains the Modbus exception verbatim, such as Read fault: illegal data address. That string distinguishes the three failures people conflate: the address does not exist, the device is not answering at all, and the address exists but the data type is wrong — only the first two produce a fault.

When the register prefix contradicts the function list

A register sheet can disagree with itself, and Niagara will believe the half you typed in. Two lines from the same document: a header saying Functions: 3, and a register list whose first column reads 30001, 30003, 30005. The first line says holding registers. The second line, read the way the Modbus convention says to read it, says input registers.

That matters here because the Modbus address format infers the register type from the leading digit rather than asking you — a 3 gives input registers and function 4, a 4 gives holding registers and function 3. Type the documented 30001 and the station issues function 4 at a device that implements only function 3. Correct wiring, correct baud rate, correct slave address, and every point in fault with an illegal-function or illegal-data-address exception.

The tell is that the failure survives every wiring check, which is where the day goes. Before touching the cable, create one point the other way — the same parameter as a holding register — and see whether it reads. If it does, the sheet's prefix is decorative and its function line is the truth.

The same document usually carries a third number, an offset instruction of the form add 1 for function 3. That is the one-based rule described above, written from the vendor's side, and it is only unambiguous if the sheet says which of its own columns to add it to. When it does not, there are two candidate entries rather than one, and trying both is faster than reasoning about it.

The counter that rolls over

Energy totals are the registers most likely to be mapped and least likely to be mapped completely. A meter that reports kWh as a 32-bit float commonly rolls that value back to zero at 99999 and keeps the number of rollovers in a separate one-register integer, documented somewhere below the headline table. The true total is the float plus the counter times the rollover point.

Map only the headline register and nothing looks wrong. The point reads, the units are right, the trend is a sensible line. Then one night the meter rolls, and the history shows a single sample dropping from 99999 to near zero. Anything that consumes the difference between samples — a delta, a totaliser, a kWh-per-day calculation, a bill — sees one enormous negative consumption and then carries on as if nothing happened. Alarm logic built on that point will have fired, or worse, will not have.

The fix is cheap if you know before commissioning: bring in the rollover counter as its own point, and expose the corrected total as a single derived value so that everything downstream — history, alarms, dashboards — reads the corrected one and nobody has the choice of the raw one. It is expensive afterwards, because the wrong numbers are already in history and history behind a point cannot be recalculated into a different shape.

Worth asking of any meter before the point tree is built: what does this value do at its maximum, and where is the register that says how many times it has been there.

Serving data as a slave

Running the station as a Modbus server is the mirror image, and adds one rule worth knowing before you start: every server point must fall inside a declared register range or it sits in fault.

The four range tables — coils, status, holding registers, input registers — each arrive from the palette enabled, with a starting address offset of 1 and a size of 64. A holding-register range with starting address 250 and size 75 covers Modbus 40250 to 40324 — seventy-five registers, not seventy-six, because the range runs from the starting address for size registers inclusive. You can add further ranges, or disable one entirely so that a master querying it gets an exception response, which is occasionally the honest answer.

Do not overlap ranges. Any given address should appear in exactly one range entry. Overlapping entries are accepted at configuration time and misbehave later.

The order that avoids all of this

  1. Get the vendor's register map first, with data types and byte order. Without it you are guessing, and Modbus rewards guessing with plausible numbers.
  2. Set Address Format to Modbus before creating a single point, so the documented addresses go in unmodified.
  3. Create one point of each data type and prove it against a known value on the device display before bulk-adding the rest.
  4. Set byte order at the device once, and check a float reads sensibly, rather than discovering it on commissioning day.
  5. Group consecutive points deliberately, so device polls can fetch them in single messages instead of one request per point.

Sources

Where this is written down

Related

Where this comes up in the work

More notes

Other things worth writing down

Next step

Tell us the version, the hardware, and what it has to do.

You will get a written scope back, and a clear answer on whether we are the right team for it. If the honest answer is that you do not need us, you will get that instead.