LearnSCADA

Part II · Chapter 4

The Modbus Frame

A frame is one complete message as it appears on the wire: a definite string of bytes with a beginning, a middle, and an end. Its design is tidy: a small core that never changes, inside a thin wrapper that changes with the transport.

By the end of this chapter you can

  • Separate any frame into its PDU (function code + data) and its ADU wrapper.
  • Apply the big-endian rule to addresses, quantities, and register values.
  • Explain the per-request limits, such as 125 registers, and build a request frame by hand.

So far requests and responses have been ideas. To send one, you must lay its parts out as bytes in a specific order. This chapter defines that layout. Learn the core once, learn the two wrappers, and you can read any Modbus frame.

The core: the protocol data unit

At the center of every Modbus message is the protocol data unit, or PDU. It has just two parts: a one-byte function code and a data field of zero or more bytes. The function code names the operation, exactly as in Part I. The data field carries whatever that operation needs: a starting address and quantity for a read, an address and value for a write, the returned values in a response.

Function code (1 byte) Data field (0 or more bytes)
03function 00 00start address 00 04quantity

The PDU is deliberately ignorant of how it will travel. It holds no device address and no error check; those belong to the wrapper. That's what lets the identical PDU ride a serial line one day and an Ethernet network the next. The PDU is capped at 253 bytes, a limit inherited from the earliest serial frames, and every transport respects it. It's the part you'll spend the most time reading, because it's where the meaning lives.

The wrapper: the application data unit

To deliver a PDU, a transport wraps it into an application data unit, or ADU. The ADU adds the two things a bare PDU lacks: a way to say which device the message concerns, and a way to check it arrived intact. In the classic serial form, that's a one-byte address in front and a two-byte error check behind: address, function code, data, error check.

Building the serial ADU. First the PDU appears alone: function code 03 and data 00 00 00 04, at most 253 bytes. Then the address byte 01 slides in front of it and the two-byte error check 44 09 slides in behind it, forming the complete serial frame of at most 256 bytes. ADU: address + PDU + error check (≤ 256 bytes) 01 address to whom? 44 09 error check arrived intact? 03 00 00 00 04 function data PDU: function + data (≤ 253 bytes)
The serial application data unit. A one-byte address goes in front of the PDU and a two-byte error check behind it, producing a complete frame ready for the wire.

Notice the clean separation: the PDU answers "what should happen"; the wrapper answers "to whom" and "did it arrive safely." The wrapper is thin, so Modbus overhead is tiny: just three extra bytes on a serial line. The largest serial ADU is therefore 256 bytes: 1 address byte + up to 253 PDU bytes + 2 error-check bytes. That number is why no single read can return unlimited data, as you'll see shortly.

Two wrappers, one core

Modbus TCP wraps the same PDU differently. Instead of an address byte and a trailing checksum, it puts a seven-byte header in front and adds no checksum, because the Ethernet and TCP layers already make sure data arrives correct and in order. That header, the MBAP header (dissected in Chapter 7), carries an identifier so a client can match responses to requests, a length, and the unit address. For now, the point is the symmetry: serial and TCP are two envelopes around one identical letter.

The same PDU in both transports. The serial frame is 01, then the PDU 03 00 00 00 04, then CRC 44 09. A copy of the PDU moves down unchanged into the TCP row, and the seven-byte MBAP header 00 01 00 00 00 06 01 slides in front of it, with no checksum after. A highlight shows the two PDUs are byte-for-byte identical. SERIAL (RTU) 8 bytes TCP 12 bytes 01 03 00 00 00 04 44 09 03 00 00 00 04 00 01 00 00 00 06 01 address in front, CRC behind 7-byte MBAP header in front, no checksum byte-for-byte identical
The same PDU in both transports. The serial frame brackets it with an address and a CRC; the TCP frame prefixes a seven-byte header and omits the checksum. The highlighted core is byte-for-byte identical.

That's why the course can treat function codes (Chapter 8) separately from transports (Chapters 5–7). A "read holding registers" PDU is the same handful of bytes whether it arrives over RS-485 or Ethernet. Once you can build and read a PDU, switching transports means changing only the bytes around it, never the bytes inside it.

Byte order: most significant first

One rule about how numbers are laid out must be absorbed before you read any frame, because getting it wrong corrupts every multi-byte value. Modbus is big-endian: when a value needs more than one byte, the most significant byte is sent first. A register holding 0x1A2B travels as 1A then 2B. Addresses and quantities follow the same rule: a starting address of 100 (0x0064) is sent as 00 then 64.

Big-endian byte order. A sender's register holds 0x1A2B: high byte 1A, low byte 2B. The high byte 1A travels along the wire first and lands in the receiver's first slot; the low byte 2B follows into the second slot. The receiver reassembles 0x1A2B, which is 6699. Below, address 100, hex 0064, is sent as 00 then 64. Sender: register = 0x1A2B Receiver 1A 2B high byte (MSB) low byte (LSB) wire → (time order) 1st byte 2nd byte 1A 2B 0x1A2B = 6699 ✓ Same rule everywhere: start address 100 = 0x0064 → sent as 00 then 64
Big-endian order. The sixteen-bit value 0x1A2B goes on the wire high byte 0x1A first, then low byte 0x2B. Every register, address, and quantity in a frame follows this rule.

"High byte first" is consistent throughout the core protocol, and it makes Modbus pleasant to read by hand: you meet the most significant part of every number first, just as you'd write it. Byte order only gets genuinely tricky when a device packs a value wider than sixteen bits across two registers, because then it must also decide which register comes first, and not all devices agree. That wrinkle gets its own treatment in Chapter 14. Within a single register, the rule is simply high byte first.

How big can a frame be?

Because the PDU is capped at 253 bytes, every operation has a natural ceiling on how much it can move in one request. The limits aren't arbitrary; they fall straight out of the frame size, and knowing them keeps you from sending a request the device must reject.

QuantityLimit per request
Read coils or discrete inputs2000 bits
Read holding or input registers125 registers
Write multiple coils1968 bits
Write multiple registers123 registers
PDU size (function + data)253 bytes
Serial ADU size (with address + CRC)256 bytes

The one that surprises people is 125 registers per read. It follows from the byte budget of the response PDU, which must carry the function code, a byte count, and two bytes per register:

PDU maximum253 bytes
− function code1 byte
− byte count1 byte
left for register data251 bytes
÷ 2 bytes per register125.5 → 125 registers

The write limit works the same way: a write-multiple-registers request spends 1 byte on the function code, 2 on the start address, 2 on the quantity, and 1 on the byte count, leaving 247 bytes, room for 123 registers. So if you need 300 registers from a device, you can't ask for them all at once: break the job into chunks of 125 or fewer and stitch the results together. Many client libraries do this for you, but knowing why the limit exists keeps the behavior from being a mystery.

A frame, byte by byte

Now make it concrete with the course's running example: a serial request to read four holding registers, starting at address 0, from unit 1. That's function code 0x03. Lay down the parts in order (address, function code, starting address, quantity) and append the error check:

BytesFieldMeaning
01AddressUnit address 1
03Function codeRead Holding Registers
00 00Start addressAddress 0 (big-endian)
00 04QuantityRead 4 registers (big-endian)
44 09CRCError check (low byte first)
Address Function code Data CRC PDU
01address 03function 00start hi 00start lo 00qty hi 04qty lo 44CRC lo 09CRC hi

Read left to right and the whole frame is 01 03 00 00 00 04 44 09: eight bytes. The middle five, 03 00 00 00 04, are the PDU. Strip the leading address and trailing CRC and that's exactly what would ride inside a TCP frame instead. Every field is where the rules say: the address selects the server, the function code names the operation, start and quantity are big-endian sixteen-bit numbers, and the CRC closes the frame. (The CRC itself is sent low byte first, the one exception to the big-endian rule; Chapter 5 explains why when it builds the CRC.)

Try it: RTU frame builder

Address Function Data CRC PDU

You can now read the skeleton of any Modbus frame. What remains is the specifics of the serial wrapper: how that CRC is really computed, and the timing that marks where one frame ends and the next begins. That's Modbus RTU, the subject of Chapter 5.

Check your understanding

1. What does a PDU contain?

The PDU is just function code + data. The unit address and error check (or MBAP header) belong to the ADU wrapper.

2. A register holds 0x1A2B. In what order do its bytes go on the wire?

Modbus is big-endian: the most significant byte goes first, on every transport.

3. Why can one read return at most 125 registers?

The response PDU must fit in 253 bytes. After the function code and byte count, 251 bytes remain: 125 registers of 2 bytes each.

4. In the frame 01 03 00 00 00 04 44 09, which bytes would ride unchanged inside a Modbus TCP frame?

Strip the leading address (01) and trailing CRC (44 09). The PDU, 03 00 00 00 04, is identical in TCP.