— Efficient Binary Communication

(Module 2 · Modbus Serial Protocols — The Original Workhorses)

Goal of this chapter Make you 100 % confident with every bit, byte, gap, and CRC that flows across a Modbus RTU bus so you can design, capture, decode, and optimise real-world networks without trial-and-error.


Quick Navigation

§TopicDepth Markers
5.1Why choose RTU?Context & pros/cons
5.2Frame anatomyDetailed field-by-field tables
5.3Timing lawT1.5 & T3.5 mathematics, oscilloscope patterns
5.4CRC-16 explainedPolynomial theory → byte-code
5.5Worked hex walkthroughFrom request to normal & exception replies
5.6Throughput mathsMax poll rate vs baud, byte-stuffing trade-off
5.7Robust design patternsBuffer sizing, exception handling, grouping reads
5.8Field diagnostics & pitfalls“Ghost frames”, bus contention, false CRCs

(Diagram placeholders appear as [Fig-5-x]; code blocks as Listing x.)


5.1 Why Choose RTU?

AttributeRTUASCIITCP
Efficiency11 bits/byte binary22 ASCII hex chars for same dataFramed in TCP/IP
Overhead≈ 40 % of ASCII2× more bytes per registerEthernet header 38 B
Human readabilityLowHighMedium (Wireshark)
Timing criticalYesYes but looserNo (handled by sockets)

Rule of thumb If you control the wire (RS-485) and need maximum nodes/km/baud, always pick RTU.


5.2 RTU Frame Anatomy — Byte-by-Byte

OrderFieldLengthDescriptionEndianness
Slave Address1 B1 – 247 (0 = broadcast)
Function Code1 B01–06, 15, 16, 23…
PDU DataN BStart addr, qty, payloadBig-endian words, little-endian bytes
CRC-162 BLo byte first, then HiLittle-endian

[Fig-5-1] Two-row timeline: TX bytes (client) top, RX bytes (server) bottom; CRC highlighted.

Tip Always transmit CRC-Lo before CRC-Hi. Mixing order causes “CRC error” even though bytes are mathematically correct.

5.2.1 Data Field Layout for Popular Function Codes

FCNameRequest Data BytesResponse Data Bytes
03Read Holding RegsStartHi StartLo QtyHi QtyLoByteCnt (RegHi RegLo)…
06Write Single RegRegHi RegLo ValHi ValLoEcho of request
16Write Multiple RegsStartHi StartLo QtyHi QtyLo ByteCnt (data…)Echo start+qty

(Detailed PDU diagrams per FC in Appendix A2.)


5.3 Timing Law — The T1.5 / T3.5 Doctrine

RTU has no start/stop tokens; silence gates each frame.

SymbolFormulaExample @ 9600 bit/sExample @ 115200 bit/s
Tchar11 bits ÷ Baud1.146 ms95.6 µs
T1.51.5 × Tchar1.72 ms143 µs
T3.53.5 × Tchar4.01 ms335 µs

If the idle gap ≥ T3.5, a receiver must treat the next byte as the start of a new frame.

[Fig-5-2] Oscilloscope screenshot showing 9600-bit/s telegram, highlight 3.5-char gap.

Pitfall PC COM ports with FIFO buffers often block-burst bytes, hiding the T3.5 gap. Use Win32 Serial API COMMTIMEOUTS or Linux termios VMIN/VTIME to guarantee flush.

5.3.1 Framing State Machine (Pseudo-code)

if idle_time ≥ T3.5:
    state = COLLECT
    frame.clear()

on_byte(b):
    frame.append(b)
    if idle_time > T1.5:
        error("Inter-char gap")  # discard

5.4 CRC-16 — Math From First Principles

Polynomial: 0xA001 (reverse of 0x8005). Initial value: 0xFFFF.

5.4.1 Algorithm in 6 Steps

  1. Init CRC = 0xFFFF.
  2. XOR CRC low-byte with incoming byte.
  3. For 8 bits:
    3 a. If (CRC & 0x0001) ⇒ CRC = (CRC >> 1) ⊕ 0xA001
    3 b. else CRC >>= 1
  4. Repeat step 2–3 for every byte in Addr…Data.
  5. Final CRC Lo = CRC & 0xFF, CRC Hi = CRC >> 8.
  6. Append to frame Lo first.

Listing 1 Python (no tables):

def crc16(data: bytes) -> bytes:
    crc = 0xFFFF
    for ch in data:
        crc ^= ch
        for _ in range(8):
            if crc & 0x0001:
                crc = (crc >> 1) ^ 0xA001
            else:
                crc >>= 1
    return bytes([crc & 0xFF, crc >> 8])

Bench-test Compare against value 0xC5C4 for the sample frame 01 03 00 00 00 06.

[Fig-5-3] Bit-level animation: LSB shift and XOR tap.


5.5 Full Hex Walk-Through

5.5.1 Request — Read 6 Holding Regs From Slave 17

FieldHexMeaning
Address110x11 = 17
Function03Read Holding Registers
Start00 0040001 (0-based)
Qty00 066 regs
CRCC5 C4← calculated

Raw: 11 03 00 00 00 06 C5 C4

5.5.2 Normal Response (6 Regs)

11 03 0C 00 64 00 C8 01 2C 01 90 02 58 6F E1

Byte-count 0x0C = 12 data bytes.

5.5.3 Exception Response (Illegal Address)

11 83 02 C0 F1

Function 0x03 → 0x83; Exception 02.

ExceptionTypical root cause
01 Illegal FunctionSlave firmware doesn’t support FC
02 Illegal AddressRegister outside map
03 Illegal ValueQuantity=0 or too large
04 Slave FailureInternal self-test error

5.6 Throughput Mathematics

5.6.1 Frame Length Formula

Lbytes=1_Addr+1_FC+N_Data+2_CRCL_{\text{bytes}} = 1\_{\text{Addr}} + 1\_{\text{FC}} + N\_{\text{Data}} + 2\_{\text{CRC}}

Total time (worst-case including gaps): Ttotal=(Lbytes×11+3.5×11)/BaudT_\text{total} = (L_{\text{bytes}} \times 11 + 3.5 \times 11) / Baud

Example: Read 60 regs (FC03, data cost = 4 request + 125 reply bytes) @ 38 400 Bd → ≈ 41 ms round-trip → 1 450 regs/s.

5.6.2 Optimisation Levers

  1. Group registers into max 125 per poll.
  2. Use higher baud; most modern transceivers stable at 115 200 Bd across < 300 m with Cat-5e.
  3. Cut turn-around delay in slave firmware (timer between last RX and first TX).
  4. Limit exception retries; 3 faulty slaves can halve bus capacity.

5.7 Robust Implementation Patterns

LayerPatternBenefit
ApplicationIdempotent writes – compare reg before writeAvoids needless traffic
TransportSliding transaction IDs (TCP)Overlap requests without race conditions
Serial driverDMA-driven TX-EnableEliminates jitter > 1 bit
SchedulerLeast-recently-polled firstFairness across 100+ slaves
Error recoveryExponential backoff per slaveSick node ≠ bus paralysis

5.8 Field Diagnostics & Classic Pitfalls

SymptomLikely causeQuick test
Random CRC errorsIncorrect bias / terminationScope idle line: V_AB must be > +200 mV
Slave answers wrong FCByte mis-alignment (missing start)Check T3.5 gap @ master TX
Frames echoed to selfTX-Enable stuck high (fail-safe)Measure DE pin; should drop after last stop-bit
“No response” after 32 nodesBus loading (32 UL limit)Switch to 1/8 UL transceivers or segment with repeater

Ghost frames Noise on unterminated stubs often mimics Mark→Space transition → slave sees phantom start; fix layout before rewriting code.


Key Takeaways

  1. RTU = fastest, leanest Modbus flavour; byte-dense frames plus CRC-16 integrity.
  2. T1.5 / T3.5 gaps are protocol law—calculate from baud, verify on scope.
  3. Little-endian CRC, big-endian data; never swap them.
  4. Throughput = baud × grouping factor − overhead; measure, then optimise.
  5. 80 % of “CRC errors” trace back to wiring & timing, not code.

Assets to Produce Before Publication

IDVisualNotes
Fig-5-1RTU frame colour-codedAddr / FC / Data / CRC
Fig-5-2Scope timing 9600 BdMark 1.5 & 3.5 char
Fig-5-3CRC bit-shift animationEducational gif
Fig-5-4Throughput vs baud graph9.6 k, 19.2 k, 115 k

Up Next

Chapter 6 — Modbus ASCII: Human-Readable Communication will show how the same PDU survives dial-up modems, radio links, and teletype consoles—handy when you must debug with nothing but a serial terminal.

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts

Chapter 24 – Modbus in Action

— Six Field-Proven Case Studies across Industry (Module 8 · Real-World Applications & the Future of Modbus) Chapter goals See the protocol outside textbooks. We examine six production deployments—each in…

Chapter 25 – Modbus ⇆ IIoT / Industry 4.0

— Bridging Brown-field Data to Cloud-Native Platforms (Module 8 · Real-World Applications & the Future of Modbus) Learning objectives Explain how Modbus’ request/response model co-exists with publish/subscribe (MQTT, AMQP) and…