Troubleshooting S7-1200 MB_CLIENT Modbus TCP Input Register Read

David Krause15 min read
S7-1200SiemensTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Troubleshooting S7-1200 MB_CLIENT: Resolving Modbus TCP Input Register Read Failure

When an S7-1200 PLC communicates with a third-party Modbus TCP server (such as a heat-pump gateway module, energy meter, inverter, or robot controller), the MB_CLIENT instruction must be configured to a tighter set of rules than many engineers expect. One of the most common field failures is the PLC returning successful-looking status codes (7005, 7006) yet never updating the destination tags. This article walks through the root cause, the precise parameter that must be changed, and the supporting diagnostics that confirm the fix.

1. Problem Description

A heat-pump control module exposes its telemetry as a Modbus TCP server on a fixed IP address and the standard Modbus TCP port 502. The PLC is configured as a Modbus TCP client and polls a single input register every cycle:

  • CPU: SIMATIC S7-1200 (any firmware that includes the MB_CLIENT instruction, i.e., firmware V4.0 and later; instructions also ship with the "Modbus TCP" library for V4.x and the TIA Portal Modbus library for V13 SP1+).
  • Function code target: 0x04 (Read Input Registers).
  • Modbus address: 30001 (the first input register of the heat pump's register map).
  • Connection: passive connection from the S7-1200 to the heat-pump gateway IP, port 502.
  • Mode: 0 (single read, single write per call).
  • Data length: 1 register, mapped to a 16-bit INT tag.

When the MB_CLIENT block is executed, the connection establishes without an error: status output 7005 (sending request) is followed by 7006 (receiving response) on every cycle. Despite the clean handshake, the destination tag never updates. A separate Modbus master running on a PC (LabVIEW or QModMaster) reads the same register, the same address, and the same function code and obtains the correct value. This asymmetry is the diagnostic fingerprint of an S7-1200 Modbus TCP configuration error, not a wiring or gateway fault.

2. System Architecture

The system consists of three nodes on a single Ethernet segment:

  1. Heat-pump gateway module – embedded Modbus TCP server. The vendor documentation lists register 30001 as the first 16-bit input register (function code 0x04).
  2. SIMATIC S7-1200 CPU – Modbus TCP client. The CPU is the active connection initiator; it must open the TCP session to port 502 of the gateway.
  3. Engineering / diagnostic PC – used to validate the register map with a third-party Modbus master (LabVIEW, QModMaster, Modbus Poll, etc.) before bringing the PLC online.

Modbus TCP/IP itself is a thin encapsulation of classic Modbus over TCP, with a fixed destination port (502) and a 7-byte MBAP (Modbus Application Protocol) header prepended to the standard Modbus PDU. The MBAP header contains a Transaction Identifier, Protocol Identifier (always 0x0000 for Modbus), Length, and the Unit Identifier. The Unit Identifier is the field that is at the heart of this failure mode.

3. MB_CLIENT Block – Required Parameters

The MB_CLIENT instruction block is found in the TIA Portal library under Communication > Other > MODBUS TCP (or in the SIMATIC Modbus TCP library for older projects). The block has the following pinout, and each pin must be reviewed whenever a read silently fails:

Pin Direction Data Type Function Common Field Value
REQ Input BOOL Rising edge triggers a new transaction Toggle from a cyclic clock or function call
DISCONNECT Input BOOL Forces the TCP connection closed FALSE in normal operation
CONNECT Input TCON_IP_V4 Connection description (IP, port, local TSAP, remote TSAP) Remote IP = heat-pump module; Remote port = 502
MB_MODE Input USINT 0 = read, 1 = write, 2 = write multiple 0 (read)
MB_DATA_ADDR Input UINT Starting Modbus address (0-based for Siemens; mapping covered in §5) 30001 (0-based: 0 or 1 depending on register family)
MB_DATA_LEN Input UINT Number of registers / bits / coils 1 (single 16-bit input register)
MB_DATA_PTR InOut VARIANT Pointer to the data area (must be a standard tag, not a DB element of an optimized block) Tag "RegisterValue" of type INT
MB_UNIT_ID Input USINT Modbus Unit Identifier (slave address). 0xFF for pure Modbus TCP, but most gateways require 1 1
DONE Output BOOL TRUE for one cycle on successful completion Monitor in HMI / logic
BUSY Output BOOL TRUE while transaction is in progress FALSE = idle
ERROR Output BOOL TRUE if the last transaction failed Latch with a marker
STATUS Output WORD Detailed error / state code 7005, 7006 = active; 0 = idle success
CONNECT_ID Input UDINT Unique connection identifier across all MB_CLIENTs 1, 2, 3…

Critical: The MB_DATA_PTR must point to a tag declared in a standard (non-optimized) data block or a global PLC tag. If the source DB has been switched to "optimized" access, the MB_CLIENT returns STATUS = 818B or similar access errors.

4. Modbus TCP/IP Fundamentals

Modbus TCP carries the classic Modbus PDU inside a TCP segment. A full request frame is structured as:

[MBAP Header — 7 bytes][Function Code — 1 byte][Data — N bytes]
  | Transaction ID (2) |
  | Protocol ID = 0x0000 (2) |
  | Length (2) |
  | Unit ID (1) |

The relevant constants are:

  • Port: 502 (IANA-assigned, reserved for Modbus TCP). The heat-pump gateway listens on this port.
  • Protocol ID: 0x0000 for Modbus; anything else is rejected.
  • Unit Identifier (Unit ID): For Modbus TCP, the MBAP header is the equivalent of the RTU slave address. 0xFF (255) is reserved for "no slave address used" (pure Modbus TCP), but many Modbus TCP gateways are actually Modbus RTU devices behind an Ethernet-to-serial converter, and they will reject anything other than 1–247.

The function code for reading input registers is 0x04. The data address field is zero-based in the wire protocol but most Modbus documentation uses the human-friendly 1-based numbering shown below:

Register Class Function Code Modicon 5-Digit Address Wire Address (0-based) Access
Coil 01, 05, 15 00001–09999 0x0000–0xFFFE Read/Write
Discrete Input 02 10001–19999 0x0000–0xFFFE Read-only
Holding Register 03, 06, 16 40001–49999 0x0000–0xFFFE Read/Write
Input Register 04 30001–39999 0x0000–0xFFFE Read-only

5. Siemens Modbus Address Mapping – The "Mystifying" Part

The MB_DATA_ADDR pin on MB_CLIENT does not accept the 5-digit Modicon address. It expects the zero-based offset within the chosen register class. The mapping is:

Register Class Mode Parameter Modicon Address MB_DATA_ADDR Value Resulting Function Code
Coil (read) MB_MODE = 0 00001 0 0x01
Coil (read) MB_MODE = 0 00100 99 0x01
Discrete Input (read) MB_MODE = 0 10001 0 0x02
Holding Register (read) MB_MODE = 0 40001 0 0x03
Holding Register (read) MB_MODE = 0 40100 99 0x03
Input Register (read) MB_MODE = 0 30001 0 0x04
Input Register (read) MB_MODE = 0 30050 49 0x04

To read input register 30001, MB_DATA_ADDR = 0 with MB_MODE = 0 issues function code 0x04. To read 30050, use MB_DATA_ADDR = 49. The Siemens documentation rarely explains this offset rule, which is the source of the confusion described in the problem statement: a third-party master shows the read is on function code 0x04 (input registers), but the Siemens manual only shows how to populate MB_DATA_ADDR for coils and holding registers. The mapping is implicit in the example offsets rather than spelled out in a table.

To verify, capture the outgoing TCP stream with Wireshark (filter tcp.port == 502). The request from the S7-1200 should contain function code 0x04 with starting address 0x0000 for the first input register. If the captured frame shows 0x03, the wrong register class is being targeted.

6. Root Cause: MB_UNIT_ID Default Behaviour

The MB_CLIENT instruction's MB_UNIT_ID input is initialized to 0xFF (255) in most TIA Portal versions. This is the correct value for a pure Modbus TCP server (e.g., a modern PLC, an instrument with native Modbus TCP, or Universal Robots' controller). However, when the heat-pump gateway module is an Ethernet-to-serial converter that bridges Modbus TCP to an internal Modbus RTU bus, the Unit ID is treated as the RTU slave address. Many of these gateways ignore or refuse requests where the Unit ID is 255.

Symptoms of an incorrect Unit ID are very specific:

  • No ERROR output – the TCP layer succeeds.
  • Status word cycles 7005 → 7006 every transaction.
  • Data never changes – the gateway either discards the request, or returns a Modbus exception code 0x0A (Gateway Path Unavailable) or 0x0B (Gateway Target No Response) that the Siemens stack treats as a "silent" read (no exception is propagated because the request never reached a real Modbus device).

This matches the observed behaviour exactly: the engineer reported that 7005 (sending) and 7006 (receiving) cycle indefinitely with no error, but the 16-bit INT variable is never updated.

7. Status Code Reference

The STATUS output of MB_CLIENT is only valid for one scan after BUSY goes FALSE, so it must be latched in a flag word as soon as the transaction completes. A partial reference table:

Status (Hex) Status (Dec) Meaning Action
0x0000 0 Idle, no error None
0x7000 28672 Wait, no active job Trigger REQ
0x7001 28673 Wait for connection establishment Check network / IP / port
0x7002 28674 Wait for connection confirmation Check CONNECT data block
0x7003 28675 Wait for partner to connect Server side, not client
0x7004 28676 Initializing Transient
0x7005 28677 Sending request Normal in-flight state
0x7006 28678 Receiving response Normal in-flight state
0x7007 28679 Disconnection in progress Transient
0x80C8 32968 Server returned Modbus exception 0x08 (Memory Parity) Check register address validity
0x80C9 32969 Server returned Modbus exception 0x09 (Gateway Path) Confirm MB_UNIT_ID and gateway routing
0x80CA 32970 Server returned Modbus exception 0x0A (Gateway No Response) Check downstream RTU device on gateway
0x818B 33163 Data pointer references optimized DB Switch DB to standard access
0x8380 33664 Length error in data area Verify MB_DATA_LEN ≤ buffer size

To capture these transients, latch the STATUS value into a retentive word on every falling edge of BUSY:

// Latch last MB_CLIENT status on transaction end
IF #MB_CLIENT_Instance.BUSY AND NOT #BusyPrev THEN
    // BUSY just went true - nothing to capture yet
END_IF;
IF NOT #MB_CLIENT_Instance.BUSY AND #BusyPrev THEN
    // BUSY just went false - status is final for this transaction
    #LastStatus := #MB_CLIENT_Instance.STATUS;
    #LastError  := #MB_CLIENT_Instance.ERROR;
END_IF;
#BusyPrev := #MB_CLIENT_Instance.BUSY;

8. Step-by-Step Fix

  1. Open the DB or FB that owns the MB_CLIENT call. Locate the instance DB generated for the block (e.g., MB_CLIENT_DB) or the static instance inside an FB.
  2. Identify the MB_UNIT_ID input pin on the block call. In TIA Portal V13 SP1 through V18, this is an IN pin of type USINT with a default of 255.
  3. Wire a constant or tag of value 1 to MB_UNIT_ID. If the heat-pump gateway expects a different RTU slave address, substitute the value documented in the gateway's register map (typically 1–247).
  4. Recompile and download the program to the S7-1200. TIA Portal will warn if a constant is unbound, but the block will accept the literal.
  5. Watch the destination tag. The 16-bit INT tied to MB_DATA_PTR will populate within two scan cycles (one to send, one to receive).
  6. Verify STATUS latches to 0x0000 on the next successful read and that BUSY toggles cleanly.

Minimum-variable ladder representation of the call (for documentation; use STL/SCL in real projects):

// --- Modbus TCP client call (SCL) ---
"MB_CLIENT_DB".REQ                := #TriggerPulse;
"MB_CLIENT_DB".DISCONNECT         := FALSE;
"MB_CLIENT_DB".CONNECT            := "HeatPump_Connect";   // TCON_IP_V4
"MB_CLIENT_DB".MB_MODE            := 0;                    // Read
"MB_CLIENT_DB".MB_DATA_ADDR       := 0;                    // Input register 30001
"MB_CLIENT_DB".MB_DATA_LEN        := 1;                    // 1 register
"MB_CLIENT_DB".MB_DATA_PTR        := "DB_Modbus".InputReg1;
"MB_CLIENT_DB".MB_UNIT_ID         := 1;                    // *** FIX ***
"MB_CLIENT_DB".CONNECT_ID         := 1;

9. Verification

After applying the fix, validate from three perspectives:

  1. PLC side – In the watch table, add the MB_DATA_PTR tag, the STATUS word, and the ERROR bit. The tag should update each cycle that REQ is pulsed; STATUS should latch to 0; ERROR should remain FALSE.
  2. Network side – Run Wireshark on a span port or use the PLC's online diagnostics to confirm the request frame carries:
    • Unit ID = 0x01
    • Function code = 0x04
    • Starting address = 0x0000
    • Quantity = 0x0001
    The response must echo the transaction ID and carry function code 0x04 with one register of payload.
  3. Heat-pump side – If the gateway has a status LED or web interface, confirm the slave port activity is shown. A flashing "RX/TX" per cycle confirms the request reached the downstream RTU device.

10. Common Pitfalls and Best Practices

Beyond the Unit ID fix, several recurring issues appear in the field when commissioning Modbus TCP on S7-1200:

  • Optimized DB access: MB_DATA_PTR cannot point to an optimized data block. Either change the DB to "standard" access (right-click the DB > Properties > Attributes) or use a global PLC tag.
  • Byte-swap on 32-bit values: Modbus registers are big-endian 16-bit words. When the heat pump returns 32-bit floating-point values, the two 16-bit words arrive in big-endian order; the S7-1200 will load them into successive bytes in the same order, so a manual swap is required (use SWAP or the WordToDoubleWord trick).
  • Byte-swap on 32-bit INT: If the destination is a DINT, the two 16-bit words end up in the wrong order; a single SWAP on the assembled 32-bit value corrects it.
  • Connection limits: An S7-1200 supports up to 8 simultaneous Modbus TCP connections (CPU-dependent; check the CPU manual for the exact number of open user connections). Each unique CONNECT_ID consumes a slot.
  • Keep-alive on firewalls: Industrial firewalls often drop idle TCP sessions after 5–30 minutes. A poll interval of 1 second or less keeps the session warm; otherwise, plan a reconnect routine.
  • Port number not 502: Some heat-pump vendors use a non-standard port (e.g., 5020, 503, or 8899) and may still call it "Modbus TCP." Wireshark on the gateway IP will reveal the listening port.
  • Polling rate vs. server capacity: A heat pump's small embedded Modbus TCP stack often tolerates no more than 1–2 requests per second across multiple clients. Do not loop MB_CLIENT at OB1 priority; use a clock-bit or a periodic timer to slow the rate to a respectful 500 ms – 2 s.

Safety note: Modbus TCP carries no authentication or encryption. If the heat-pump module is on a shared plant network, segment it with a managed switch ACL or a router. Treat any value read from a non-authenticated Modbus device as untrusted input, especially if it is fed back to a safety-relevant controller.

11. Diagnostic Decision Matrix

Symptom STATUS / ERROR Most Likely Cause Fix
Toggles 7005 / 7006 forever, data never updates No error MB_UNIT_ID wrong (0xFF instead of 1) Set MB_UNIT_ID = 1
ERROR = TRUE, STATUS = 80C8 Modbus exception 08 Invalid register address (vendor uses 1-based, not 0-based, or vice-versa) Subtract/add 1 from MB_DATA_ADDR
ERROR = TRUE, STATUS = 80C9 Modbus exception 09 Gateway cannot route the request (Unit ID does not match downstream device) Set MB_UNIT_ID to the actual RTU slave address
ERROR = TRUE, STATUS = 80CA Modbus exception 0A Downstream RTU device is offline Check wiring, baud rate, parity, slave address on the RTU side
ERROR = TRUE, STATUS = 818B Data pointer invalid MB_DATA_PTR points to optimized DB Switch DB to standard access
ERROR = TRUE, STATUS = 8380 Length error MB_DATA_LEN greater than available data area Resize data area or reduce length
Connection never establishes STATUS = 7001 / 7002 / W#16#80C1 IP / port wrong, firewall blocking, or partner not listening on 502 Ping partner, telnet partner 502, check router ACLs
Values read are swapped (e.g., 32-bit DINT has high/low words reversed) No error Modbus big-endian vs. S7 little-endian Apply SWAP after assembling the 32-bit value

12. Cross-Platform Notes

Other Modbus TCP clients (Moxa MGate series gateways, Universal Robots controller, ProSoft Technology radio gateways) interpret the Unit ID according to the same MBAP standard. When using a Moxa MGate as a Modbus TCP master in a Siemens-to-Modbus-RTU bridge, set the Moxa port's "Slave ID" to match the value placed in MB_UNIT_ID. Universal Robots' Modbus TCP server, in contrast, expects Unit ID 255 in pure Modbus TCP mode and may also use port 502 — see the official Universal Robots documentation for the register map.

ProSoft Technology's Modbus TCP gateway products (e.g., the PTQ family and the RadioLinx RLX-FH radios) follow the same Unit ID rule: the value is preserved across the TCP/RTU boundary unless the gateway is configured to "ignore Unit ID," in which case it forwards requests to a fixed downstream address. Always check the gateway's configuration page.

References (Manufacturer Manuals & Standards)

FAQ

Why does the S7-1200 MB_CLIENT return no error and yet never update the destination tag?

The TCP layer completes successfully (status cycles 7005 / 7006) but the Modbus request is dropped at the gateway because the Unit Identifier in the MBAP header is wrong. Most heat-pump gateways bridge Modbus TCP to Modbus RTU and require MB_UNIT_ID = 1; the Siemens default of 255 is rejected silently. Set MB_UNIT_ID to the downstream RTU slave address.

What is the correct value for MB_DATA_ADDR when the vendor's register is 30001?

Siemens MB_CLIENT uses a 0-based offset within the register class. For input register 30001, set MB_DATA_ADDR = 0; for 30050, set it to 49. The function code (0x04 for input registers) is selected automatically by the combination of MB_MODE and the address range.

How do I capture the transient STATUS value of MB_CLIENT?

Latch the STATUS word into a retentive tag on the falling edge of BUSY. Because STATUS is only valid for one scan after the transaction ends, an un-latched read will almost always see 0. A five-line snippet using a BusyPrev flag is shown in §7.

Why does Wireshark show the request with function code 0x04 but the data still does not update?

Wireshark only confirms the wire-level frame, not the gateway's response. If the gateway returns a Modbus exception (0x0A, "Gateway Target No Response"), the Siemens stack may treat it as a silent no-op. The captured Unit ID byte reveals the real cause: it should match the downstream RTU slave address, typically 1.

Is port 502 mandatory for Modbus TCP?

Port 502 is the IANA-assigned standard for Modbus TCP, but vendors may run the same protocol on alternative ports. If a heat-pump gateway listens on, for example, 5020 or 8899, TIA Portal's TCON_IP_V4 structure must be edited to point to the actual RemotePort value.

Back to blog