Modbus in Niagara 4: register offsets, word order and data types
Reading the wrong register, or getting 2.4e-41 instead of 230 V? How to translate a manufacturer's Modbus map into Niagara points that read the right value first time.
Modbus is simple on paper: numbered registers, a handful of function codes, no discovery. In practice almost every Modbus integration problem comes down to three things: which register the map really means, how a value is spread across registers, and how it’s scaled.
This guide walks through all three with Niagara 4 in mind, using an energy meter as the example because meters are where most integrators meet Modbus first.
The four data tables
Modbus devices expose four tables. The manufacturer’s map should tell you which one each value lives in.
| Table | Prefix in “Modbus notation” | Size | Access | Read function | Write function |
|---|---|---|---|---|---|
| Coils | 0xxxx | 1 bit | Read/write | 01 | 05 (single), 15 (multiple) |
| Discrete inputs | 1xxxx | 1 bit | Read only | 02 | – |
| Input registers | 3xxxx | 16 bit | Read only | 04 | – |
| Holding registers | 4xxxx | 16 bit | Read/write | 03 | 06 (single), 16 (multiple) |
Many devices put everything in holding registers, even read-only measurements. Others split measurements into input registers. If a value reads as zero or returns an “illegal data address” exception, the first question is whether you’re reading the right table.
Problem 1: the off-by-one register
On the wire, Modbus addresses start at 0. But maps are written in at least three styles:
- Modbus notation: “40001” means holding register, protocol address 0. Some maps use six digits, “400001”, for the same thing.
- One-based register numbers: “Holding register 1” also means protocol address 0.
- Zero-based protocol addresses: “Address 0x0000” or “address 0” means exactly that.
So a map that says “Voltage L1 – register 1” and one that says “Voltage L1 – address 0” are describing the same register, and a map saying “address 1” is describing the next one.
Niagara’s Modbus point configuration lets you enter the address in more than one format, such as plain decimal, hex, or five-digit Modbus style. Check which format the field is set to before you type a number in. The same digits point at different registers in each format.
Quick test for off-by-one: if a value looks plausible but wrong (a frequency of 0, or a voltage showing in the current field), move the address by one in each direction. If one of them gives a sensible reading, the map and your address format disagreed by one.
Problem 2: 32-bit values and word order
A Modbus register holds 16 bits. Anything bigger, a 32-bit integer, a 32-bit float, or a 64-bit energy total, is spread across consecutive registers. The standard doesn’t say which register comes first, so manufacturers disagree.
Take 230.0 V stored as an IEEE 754 32-bit float. Its hex value is 0x43660000, which a meter sends as two registers:
| Order | Register n | Register n+1 | What Niagara shows if it expects high word first |
|---|---|---|---|
| High word first (“big-endian”, ABCD) | 0x4366 |
0x0000 |
230.0 ✔ |
| Low word first (“word swapped”, CDAB) | 0x0000 |
0x4366 |
2.4 × 10⁻⁴¹ ✘ |
That tiny number is the giveaway. If a float reads as something like 2.4E-41, 0, or an absurdly large value, the word order is almost certainly swapped. Rarer devices also swap the bytes inside each register (BADC or DCBA orders).
In Niagara, set the data type on each proxy point (for example float, or signed/unsigned 32-bit), and check the device’s byte order settings for floats and longs. Fix the order once at the device level when every value on the device uses the same convention. That’s usually the case.
A few other things to watch:
- Start on an even register? Some maps list a float at register 40001 and the next at 40003. If you’re reading odd values, check you haven’t started on the second half of a pair.
- 64-bit energy totals. Some meters provide kWh as a 64-bit integer across four registers, others as two 32-bit values (a high and a low part) or a float. Read the map’s notes carefully: a total that “rolls over” at 65,535 or 4,294,967,295 means you’re only reading part of it.
- Signed vs unsigned. Power that should be −2.1 kW but shows 65,515 is a signed value being read as unsigned.
Problem 3: scaling
Many devices send integers with an implied decimal point, so the map says something like “temperature, °C × 10”. A reading of 215 means 21.5 °C.
In Niagara, use the proxy extension’s conversion (a linear conversion with a scale of 0.1 in this example) and set the point’s facets for units and decimal places. Do the scaling in the point, not in logic downstream. That way histories, alarms and graphics all see the real engineering value.
Some meters also use a scale factor register: the value and a separate exponent or multiplier (for example “×10^n”). If readings are out by exactly 10, 100 or 1,000, look for a scale register in the map.
Reading the exception codes
When a device rejects a request it returns an exception code. Niagara will show the point or device in fault; the code tells you why.
| Code | Name | Usual cause |
|---|---|---|
| 01 | Illegal function | Reading the wrong table (e.g. input registers on a device that only has holding registers) |
| 02 | Illegal data address | Register doesn’t exist, off-by-one, or a poll block spanning a gap in the map |
| 03 | Illegal data value | Writing a value outside the allowed range, or requesting too many registers at once |
| 04 | Server device failure | The device couldn’t complete the request; check the device itself |
| 06 | Server device busy | The device is busy; slow the poll rate |
| 0A / 0B | Gateway path unavailable / target failed to respond | A Modbus TCP gateway can’t reach the serial device behind it |
That 02 on a poll block is worth knowing. Drivers group neighbouring registers into one request for efficiency (a read can cover up to 125 registers). Some devices reject the whole request if any register in the range is undefined. If several valid-looking points fail together, try splitting them so the request doesn’t cross a gap.
Modbus TCP and RTU basics that catch people out
Modbus TCP
- Default port is TCP 502.
- The unit ID matters for gateways: it’s the serial address of the device behind the gateway. Direct TCP devices often ignore it or expect 1 or 255.
- Many small devices accept only one or two TCP connections. If a meter works from your laptop but not from the station (or the other way round), something else may already be connected.
Modbus RTU (RS-485)
- Every device on the trunk needs the same baud rate, parity and stop bits, and a unique address from 1 to 247.
- Terminate both ends of the trunk, and make sure the network is biased once (by the master or a bias module).
- Manufacturers disagree about which line is “A” and which is “B”. If nothing responds and everything else checks out, swapping the pair at one device is a legitimate test.
A workflow that works
- Get the exact map for the device’s firmware version.
- Confirm comms with a single, simple register (a serial number or a fixed value) before adding anything else.
- Add one value of each data type and get the address format, word order and scaling right.
- Only then add the rest of the points, grouped so poll requests don’t cross gaps.
- Set facets, histories and alarms on the scaled engineering values.
Summary
Most Modbus problems are an off-by-one address, the wrong word order for 32-bit values, or missing scaling. Check the address format in Niagara, recognise the tell-tale “tiny float” of a word swap, scale in the point’s conversion, and read the exception code instead of guessing.