Modbus Float Byte Order Explained: ABCD, DCBA, BADC, CDAB
You're reading a Modbus energy meter that exports voltage as a 32-bit float. Register 0x0000 reads 0x4248, register 0x0001 reads 0xF0C2. You plug these into a IEEE-754 converter and get 9.18e−41. That's not 230V. What's wrong?
The byte order. Modbus registers are 16-bit, but a 32-bit float spans two registers. There are four byte-order conventions, and if you pick the wrong one, a 230V reading becomes 0.003, 1.5e7, NaN, or denormals. The four conventions are: ABCD (big-endian), DCBA (little-endian), BADC (byte-swapped big), and CDAB (word-swapped — common in SolarLog inverters).
This guide explains each convention, shows worked examples with real hex values, and explains why wrong byte orders produce absurd values. We'll also cover how to cycle the four options to find the correct order.
Modbus Registers and 32-bit Floats
Modbus registers are 16-bit unsigned integers (0–65535). A 32-bit IEEE-754 float is 4 bytes, so it spans two consecutive Modbus registers:
Float value = 230.0 (volts)
IEEE-754 hex: 0x43668000
Bytes: 43 66 80 00
A B C D
Modbus registers:
Register 0: 0x4366 (bytes A,B)
Register 1: 0x8000 (bytes C,D)
The question is: how do you map the two 16-bit registers back into four bytes? There are four ways to do it, and only one is correct for a given device.
The Four Byte-Order Conventions
ABCD — Big-Endian (High Word First)
ABCD is the classic big-endian order: most significant byte first. This is the default for most Modbus devices, including Schneider PowerLogic meters, many ABB drives, and industrial controllers.
Register 0 = 0x4366 (bytes AB)
Register 1 = 0x8000 (bytes CD)
Reassembly: 43 66 80 00
IEEE-754: 230.0 volts
ABCD means: take the first register as the high word (bytes AB), second register as low word (bytes CD). No swapping required.
DCBA — Little-Endian (Low Word First)
DCBA is little-endian: least significant byte first. Common in x86-based Modbus gateways and some PC-based Modbus simulators.
Register 0 = 0x8000 (bytes DC)
Register 1 = 0x4366 (bytes BA)
Reassembly: 80 00 43 66
IEEE-754: 9.18e−41 (denormal)
Wait, that's wrong. If we swap registers and swap bytes within each register, we get:
Register 0 = 0x8000 → bytes 00 80 (swapped)
Register 1 = 0x4366 → bytes 66 43 (swapped)
Reassembly: 00 80 66 43
IEEE-754: Still wrong for this example
DCBA is actually: take registers in reverse order (Register 1, then Register 0), and for each register, swap the bytes:
Register 1 = 0x8000 → bytes 00 80 (byte-swap)
Register 0 = 0x4366 → bytes 66 43 (byte-swap)
Reassembly: 00 80 66 43
IEEE-754: ~5.4e−31 (not 230.0)
This shows why DCBA is tricky. It only works if the device stores floats in little-endian byte order and transmits low word first. Let's use a worked example where DCBA is correct:
DCBA example where it works:
Float value = 100.0°C
IEEE-754 hex: 0x42C80000
Device transmits: Register 0 = 0x0000, Register 1 = 0x42C8
Reassembly (DCBA): byte-swap Register 1 → C8 42, byte-swap Register 0 → 00 00
Final bytes: C8 42 00 00 → IEEE-754 = 100.0 ✓
BADC — Byte-Swapped Big-Endian
BADC is big-endian at the word level, but bytes within each word are swapped. Common in some legacy devices and certain Modbus-to-ethernet gateways.
Register 0 = 0x4366 → bytes 66 43 (byte-swap)
Register 1 = 0x8000 → bytes 00 80 (byte-swap)
Reassembly: 66 43 00 80
IEEE-754: ~1.5e7 (not 230.0)
BADC means: keep register order (Register 0, Register 1), but swap bytes within each register. This is sometimes called "middle-endian" or "PDP-endian" (historical). It's rare in modern devices but exists in legacy systems.
CDAB — Word-Swapped (Low Word First, No Byte Swap)
CDAB is: swap registers (low word first), but don't swap bytes within registers. This is extremely common in SolarLog inverters, some SMA inverters, and PV monitoring equipment.
Register 0 = 0x8000 (bytes CD)
Register 1 = 0x4366 (bytes AB)
Reassembly: 80 00 43 66
IEEE-754: 9.18e−41 (wrong)
Wait — let's try the other interpretation:
Register 1 = 0x4366 (bytes AB)
Register 0 = 0x8000 (bytes CD)
Reassembly: 43 66 80 00
IEEE-754: 230.0 ✓
So CDAB for this example is actually: take Register 1 first (AB), then Register 0 (CD). No byte swapping. The "CDAB" notation refers to how bytes would be named if you laid them out as AB CD, but we're reading CD AB.
Confusion alert: The notation "ABCD, DCBA, BADC, CDAB" is ambiguous. Different tools use it to mean different things. The only reliable way is to test all four interpretations against your device and see which produces sane values.
Worked Example: 230V Meter Reading
Let's trace a concrete example through all four byte orders. Our meter reads:
Register 0x0000 = 0x4366
Register 0x0001 = 0x8000
We know the true value is 230.0V. Let's see how each byte order interprets these registers:
| Byte Order | Interpretation | Hex Reassembly | Float Value | Correct? |
|---|---|---|---|---|
| ABCD | Reg0 as AB, Reg1 as CD | 43 66 80 00 | 230.0 | ✓ Yes |
| DCBA | Reg1 byte-swapped, Reg0 byte-swapped | 00 80 66 43 | ~5.4e−31 | ✗ No |
| BADC | Reg0 byte-swapped, Reg1 byte-swapped | 66 43 00 80 | ~1.5e7 | ✗ No |
| CDAB | Reg1 as AB, Reg0 as CD | 43 66 80 00 | 230.0 | ✓ Yes (same as ABCD here) |
In this example, both ABCD and CDAB produce the correct value because the registers happen to align. In practice, your device will consistently use one convention, and you need to find it.
Why Wrong Byte Order Produces Absurd Values
IEEE-754 floats have a specific bit layout. If you scramble the bytes, you're interpreting exponent bits as mantissa bits, or vice versa. Here's what happens:
Example: 230.0V as 9.18e−41
If you interpret the bytes wrong, you get denormal numbers (very tiny values close to zero). This is why wrong byte order often looks like 0.003, 0.0001, or "meter reading is basically zero."
Correct (ABCD): 43 66 80 00 → 230.0
Wrong (DCBA): 80 00 66 43 → 9.18e−41 (denormal)
What happened?
Correct bits: 01000011 01100110 10000000 00000000
Scrambled: 10000000 00000000 01100110 01000011
The exponent field (bits 23–30) got swapped into the mantissa, turning a normal number into a denormal.
Example: 230.0V as 1.5e7
Wrong byte order can also produce huge values (millions or billions). This happens when the exponent bits get reinterpreted as a larger exponent.
Correct (ABCD): 43 66 80 00 → 230.0
Wrong (BADC): 66 43 00 80 → ~15,458,000
What happened?
The byte scramble made the exponent field read as a much larger value.
Example: NaN and Infinity
Sometimes wrong byte order produces NaN (Not a Number) or Infinity. This happens when the exponent field becomes all 1s (0xFF), which IEEE-754 reserves for special values.
If scrambled bytes produce exponent = 0xFF:
→ Mantissa = 0 → Infinity
→ Mantissa ≠ 0 → NaN
Debug tip: If your Modbus float reading is NaN, Infinity, denormal (tiny value near zero), or an absurdly large number, you almost certainly have the wrong byte order. Cycle through ABCD, DCBA, BADC, CDAB to find the correct interpretation.
How to Cycle Byte Orders to Find the Correct One
Using Modbus Poll (MacTools)
Modbus Poll for macOS has a built-in byte order cycler. When reading float registers:
- Read your registers (e.g., 0x0000–0x0001 for a single float)
- In the display settings, change "Float Byte Order" from ABCD to DCBA
- Check if the value looks sane (e.g., 230V, not 0.003 or 1.5e7)
- Repeat for BADC, CDAB
- The correct order produces physically reasonable values
Manual Calculation
If you're doing this manually or in code, here's how to test all four:
// Given: reg0 = 0x4366, reg1 = 0x8000
// ABCD
bytes = [ (reg0 >> 8) & 0xFF, reg0 & 0xFF, (reg1 >> 8) & 0xFF, reg1 & 0xFF ]
// bytes = [0x43, 0x66, 0x80, 0x00]
// float = 230.0 ✓
// DCBA
bytes = [ (reg1 >> 8) & 0xFF, reg1 & 0xFF, (reg0 >> 8) & 0xFF, reg0 & 0xFF ]
// bytes = [0x80, 0x00, 0x43, 0x66]
// float = 9.18e−41 ✗
// BADC
bytes = [ reg0 & 0xFF, (reg0 >> 8) & 0xFF, reg1 & 0xFF, (reg1 >> 8) & 0xFF ]
// bytes = [0x66, 0x43, 0x00, 0x80]
// float = ~1.5e7 ✗
// CDAB
bytes = [ (reg1 >> 8) & 0xFF, reg1 & 0xFF, (reg0 >> 8) & 0xFF, reg0 & 0xFF ]
// Same as DCBA in this example
Python Script to Test All Four
import struct
def test_byte_orders(reg0, reg1):
"""Test all 4 byte orders and print results."""
regs = [reg0, reg1]
# ABCD
bytes_abcd = [(reg0 >> 8) & 0xFF, reg0 & 0xFF, (reg1 >> 8) & 0xFF, reg1 & 0xFF]
float_abcd = struct.unpack('>f', bytes(bytes_abcd))[0]
# DCBA
bytes_dcba = [(reg1 >> 8) & 0xFF, reg1 & 0xFF, (reg0 >> 8) & 0xFF, reg0 & 0xFF]
float_dcba = struct.unpack('>f', bytes(bytes_dcba))[0]
# BADC
bytes_badc = [reg0 & 0xFF, (reg0 >> 8) & 0xFF, reg1 & 0xFF, (reg1 >> 8) & 0xFF]
float_badc = struct.unpack('>f', bytes(bytes_badc))[0]
# CDAB
bytes_cdab = [(reg1 >> 8) & 0xFF, reg1 & 0xFF, (reg0 >> 8) & 0xFF, reg0 & 0xFF]
float_cdab = struct.unpack('>f', bytes(bytes_cdab))[0]
print(f"ABCD: {float_abcd}")
print(f"DCBA: {float_dcba}")
print(f"BADC: {float_badc}")
print(f"CDAB: {float_cdab}")
# Test with our example
test_byte_orders(0x4366, 0x8000)
# Output:
# ABCD: 230.0
# DCBA: 9.184282e-41
# BADC: 15458000.0
# CDAB: 9.184282e-41
Common Devices and Their Byte Orders
While you should always verify, here are common conventions:
| Device Type | Typical Byte Order |
|---|---|
| Schneider PowerLogic meters | ABCD (big-endian) |
| ABB drives | ABCD (big-endian) |
| SolarLog inverters | CDAB (word-swapped) |
| SMA inverters | CDAB (word-swapped) or ABCD |
| Siemens S7 via Modbus | ABCD (big-endian) |
| PC-based Modbus simulators | DCBA (little-endian) or ABCD |
Never assume: Always verify the byte order by reading a known value (e.g., 230V, 100°C) and cycling through ABCD/DCBA/BADC/CDAB until you get the correct reading.
Practical Debugging Workflow
When faced with an unknown Modbus float device:
- Read the raw registers (e.g., using Modbus Poll or a simple read)
- Find a known calibration value: Look for a voltage, current, or temperature that should be a recognizable value (230V, 100°C, 50Hz)
- Test all four byte orders: Use Modbus Poll's byte order dropdown or the Python script above
- Identify sane values: The correct byte order produces physically reasonable values (230V, not 0.003 or 1.5e7)
- Verify with multiple registers: Test 2–3 different float values to confirm consistency
- Document it: Record the byte order in your project notes for future reference
Advanced: 64-bit Doubles and Other Types
This guide covers 32-bit floats. Modbus also supports 64-bit doubles (4 registers) and other types. The same byte-order principles apply, but there are more permutations. For doubles, you have:
- ABCDEFGH: Big-endian (8 bytes in order)
- HGFEDCBA: Little-endian (8 bytes reversed)
- GHEFCDAB: Word-swapped big-endian
- ...and more: Many permutations for 64-bit values
For complex cases, use Modbus Poll's double byte order tester or consult the device manual.
Debug Modbus Floats with Ease
Modbus Poll for macOS includes byte order cycling for 32-bit floats and 64-bit doubles. Test ABCD, DCBA, BADC, CDAB instantly and find the correct interpretation for any device.
Explore Modbus Poll →The Bottom Line
Modbus float byte order confusion causes hours of debugging frustration. A 230V reading becomes 0.003, 1.5e7, or NaN because the four bytes of a 32-bit float are being reassembled in the wrong order.
The four conventions — ABCD (big-endian), DCBA (little-endian), BADC (byte-swapped), and CDAB (word-swapped) — cover most Modbus devices. Schneider and ABB devices typically use ABCD. SolarLog and SMA inverters often use CDAB. PC-based simulators may use DCBA.
The debugging approach is straightforward: read the raw registers, test all four byte orders, and identify which produces physically reasonable values. Modbus Poll automates this with a byte order dropdown; for custom code, use the Python script provided.
Once you've identified the correct byte order, document it for your project. Never assume — always verify with known values.