Getting Modbus RTU Through a Serial Device Server Without Dropping Frames
Commissioning a serial-to-Ethernet device server carrying Modbus RTU: operating mode, packing timers, TCP framing, idle timeouts and half-duplex control.
A device server is not just a longer cable
A serial-to-Ethernet device server, also called a terminal server or serial gateway, moves an RS-232 or RS-485 port across the network. Sites reach for one when the SCADA node is far from a legacy RTU meter, drive, or protection relay, or when a shared serial multidrop must be read from more than one place.
The trap is treating the box as a transparent extension cord. It is not. The device server buffers bytes, decides when to push them onto TCP, and may re-order the timing that Modbus RTU depends on. A link that looks perfect on a bench, with one request at a time, can drop frames the moment the SCADA driver polls quickly or the bus carries traffic from a second master.
Commissioning should separate the same layers as a direct serial link, plus one more:
- The RS-485 or RS-232 wiring can carry a clean signal.
- The serial settings match on every device.
- The device server framing preserves Modbus RTU message boundaries.
- The SCADA driver reaches the right serial port through the right TCP path.
Do not start by tuning SCADA timeouts. Prove each layer in order.
Pick the operating mode before anything else
Device servers usually offer several modes, and the mode changes how the box handles Modbus framing.
| Mode | What it does | When to use |
|---|---|---|
| Raw TCP socket | Passes serial bytes over a TCP connection with no protocol awareness | SCADA driver speaks Modbus RTU and manages framing itself |
| RealCOM / virtual COM | Presents the remote port as a local COM port on the SCADA node | Legacy driver that only opens a COM port, no native TCP support |
| Modbus gateway | Converts Modbus TCP on the network side to Modbus RTU on the serial side | SCADA polls Modbus TCP and the field device is RTU |
| UDP | Connectionless datagrams | Rare for Modbus, avoid unless a vendor requires it |
The common mistake is running a raw TCP socket while the SCADA driver is configured for Modbus TCP, or the reverse. In Modbus gateway mode the box adds and strips the MBAP header and unit ID for you. In raw TCP mode it does not, and the driver must be set to Modbus RTU over TCP, sometimes called RTU-over-TCP or encapsulated RTU. These are not interchangeable. Confirm which one the box is doing and which one the driver expects before touching anything else.
Packing and force-transmit timers decide framing
Modbus RTU marks the end of a frame with a silent gap of at least 3.5 character times, and forbids a gap longer than 1.5 character times inside a frame. That is §2.5.1.1 of the Modbus over Serial Line Specification and Implementation Guide V1.02, and the numbers fall straight out of the baud rate. One 8N1 character is 11 bits, so at 9600 baud a character takes 1.15 ms, t1.5 is 1.7 ms and t3.5 is 4.0 ms. Above 19200 baud the same clause stops scaling and fixes them: 750 µs for t1.5, 1.750 ms for t3.5. On a real serial line the UART sees that gap. A device server in raw or virtual COM mode does not automatically preserve it. Instead it collects incoming serial bytes and forwards them based on its own rules, usually:
- A packing timer, sometimes called delimiter or force-transmit timer, that flushes buffered bytes after a small idle period.
- A packing length that flushes when a byte count is reached.
- An optional delimiter character that flushes on a specific byte.
If the packing timer is too long, the box merges a response and the start of the next request into one TCP payload, and the driver sees a corrupted frame. If it is too short, a single Modbus response is split across several TCP segments, and a strict driver rejects it.
Commissioning values to set and record:
- Force-transmit or packing timer, tuned so one Modbus response leaves as one payload. Work from t3.5 at the configured baud — 4.0 ms at 9600, 1.750 ms at 115200 — and remember a box with 1 ms setting granularity cannot express the fast end of that range.
- Packing length disabled, or set to at least 256 bytes. The RTU frame is capped at 256 bytes (a 253-byte PDU plus address and CRC), and the largest legal holding-register read — 125 registers, function 0x03 — answers with 1 + 1 + 1 + 250 + 2 = 255 bytes. A packing length of 128 splits that response every time; 256 or higher cannot.
- Delimiter flush disabled unless the vendor recommends it for Modbus.
In pure Modbus gateway mode the box understands frames and this matters less, because it parses complete RTU messages before converting. In raw and virtual COM mode it matters a lot. When in doubt, prefer Modbus gateway mode for RTU field devices, because it removes the framing guesswork.
TCP idle timeout and reconnection
TCP is a stream, and either end can hold a connection open for a long time. Two settings decide how the link recovers after a fault.
- TCP idle timeout on the device server. If the box closes idle connections aggressively, a slow poll group can be dropped between requests. If it never closes them, a crashed SCADA session leaves a stale connection that blocks a reconnect, especially on boxes that allow only one connection per port.
- Keepalive. Enable TCP keepalive so a half-open connection, caused by a cable pull or a node reboot, is detected and cleared rather than lingering. Then change the interval, because the default will not help you. RFC 1122 §4.2.3.6 says a keepalive timer must default to no less than two hours, and Linux obeys it:
tcp_keepalive_time7200 s, thentcp_keepalive_probes9 spaced bytcp_keepalive_intvl75 s, so roughly 7875 s before the socket is declared dead. A serial poll loop needs that in tens of seconds.
Field checks:
- Note how many simultaneous TCP connections the port allows.
- Pull the network cable mid-poll and confirm the SCADA driver reconnects within the expected time.
- Reboot the SCADA node and confirm the old connection is released so the new one can attach.
- Confirm the box does not close the connection during the slowest normal poll interval.
A frequent field symptom is good communication for minutes, then a stall until a manual driver restart. That is often a stale connection plus a single-connection port, not a wiring fault.
One serial bus, more than one master
A tempting reason to install a device server is to let two systems read the same multidrop, for example SCADA and a separate energy dashboard. Modbus RTU has no arbitration for two masters on one bus. If both send at once, frames collide.
Some device servers offer a request queue or serial command scheduling that serializes requests from multiple TCP connections onto one serial line. This can work, but it changes timing and adds latency. Treat it as a real design decision, not a free feature.
If you must share the bus:
- Prefer a box that explicitly serializes multi-master access and documents the behavior.
- Keep the total request rate well under what the slowest slave tolerates.
- Watch for timeout and CRC counters rising when both masters are active.
- Consider giving each system its own poll schedule rather than letting them free-run.
If sharing is not required, give SCADA sole ownership of the serial line and pull the second reader onto a separate port or gateway.
Half-duplex RS-485 direction control
Two-wire RS-485 is half-duplex. The device server must enable its transmitter only while sending, then release the line so the slave can answer. Boxes handle this with automatic direction control, and it is usually reliable, but two things go wrong in the field.
- If the box holds the transmitter enabled slightly too long after sending, it steps on the start of the slave's response. This looks like intermittent no-reply or CRC errors that worsen at higher baud rates. The budget is a number you can work out: a compliant slave waits t3.5 before answering, so at 9600 baud the box has about 4.0 ms to drop its transmitter, and at 115200 baud it has the fixed 1.750 ms. Same box, same setting, under half the margin. That is why the errors arrive with the baud rate rather than with the wiring.
- If fail-safe biasing is missing, the line floats between transmissions and the box may see noise as a partial frame. Biasing and termination belong to the physical bus, not to the box: TIA/EIA-485-A allows 32 unit loads on a segment and wants 120 Ω at each end, and no device server setting rescues a bus that breaks either.
Field checks:
- Confirm the port is set for 2-wire RS-485, not 4-wire or RS-232, matching the wiring.
- Verify termination and fail-safe biasing on the physical bus, exactly as for a direct RTU link.
- If errors climb with baud rate, drop the rate and see whether they clear, which points at turnaround timing rather than addressing.
Unit ID and register base still apply
Moving a serial link onto the network does not change Modbus addressing, and two classic mismatches survive the trip.
- Unit ID, also called slave address. In Modbus gateway mode, confirm whether the box maps a TCP unit ID straight through to the serial slave address or requires a translation table. A mismatch here answers, or fails to answer, the wrong device. The unit ID is one byte of the 7-byte MBAP header, and the serial side only uses 1 to 247 — 0 is broadcast, and 248 to 255 are reserved. A Modbus TCP client with no serial sub-network behind it is told to send 0xFF, so a driver sitting on its 0xFF default plus a gateway that forwards the byte verbatim gives you silence with nothing wrong on the bus.
- Register base convention. The field device, the test tool, and the SCADA driver must agree on whether a holding register is addressed as 40001 style or zero-based. On the wire a holding register is a 16-bit zero-based address, 0x0000 to 0xFFFF; the 40001 in the vendor manual is documentation for address 0x0000. A device server does not fix a base-address disagreement, it just carries the wrong request faithfully — and being off by one reads the register next door, which returns a plausible number and survives commissioning.
Commissioning sequence
Work from the field device outward, so each new layer is added only after the previous one is proven.
- Prove the serial link locally. Connect a laptop directly to the RS-485 or RS-232 port with a known tool and read one documented register.
- Configure the device server serial port to match the field device exactly: baud rate, parity, data bits, stop bits, and 2-wire or 4-wire mode.
- Choose the operating mode deliberately: Modbus gateway for RTU field devices, or raw TCP with an RTU-over-TCP driver if required.
- Set force-transmit and idle timeouts, and enable TCP keepalive.
- From the SCADA node, read the same single register through the box.
- Add the full poll list and run it long enough to gather timeout and CRC counters.
- Test recovery: pull the network cable, reboot the SCADA node, and confirm clean reconnection each time.
Common failure modes
Works with one register, corrupts on fast polling
The packing or force-transmit timer is merging or splitting frames. Tune it, or switch to Modbus gateway mode so the box parses complete RTU messages.
Good for minutes, then stalls until a driver restart
A stale TCP connection on a single-connection port. Enable keepalive, adjust idle timeout, and confirm the box releases connections after a SCADA reboot.
Random no-reply that worsens at higher baud
RS-485 turnaround timing in the device server, or missing biasing and termination. Confirm 2-wire direction control and the physical bus health, then reduce baud rate to test.
Answers come from the wrong device
Unit ID mapping in gateway mode, or a duplicate slave address on the shared bus. Check the translation table and the field addresses.
Two systems on one bus, rising errors
Two masters with no serialization. Use a box that queues requests, or separate the readers.
Evidence to keep
Leave enough for the next engineer to reproduce the setup without reverse-engineering the box:
- Device server IP, port numbers, and operating mode per serial port.
- Serial settings and 2-wire or 4-wire selection.
- Force-transmit, idle timeout, and keepalive settings.
- Unit ID mapping or translation table if used.
- The t3.5 you computed for the configured baud, next to the force-transmit value you actually set.
- Baseline timeout and CRC counters after a stable run.
- Reconnection test results for cable pull and SCADA reboot.
One last thing before you sign off: the packing timer and the RS-485 turnaround are exactly the two settings a bench test never exercises, because a bench test polls one slave slowly. Load the real poll list at the real rate, let it run for an hour, and watch the CRC and timeout counters. That is where a device server hides the problems that a transparent-cable mindset walks right past.