Resolving MB_Client Multi-Instance Errors on S7-1200 Modbus TCP

David Krause13 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

Problem Overview

Calling the same S7-1200 Modbus TCP function block (FB) twice from OB1 in TIA Portal V14 produces one of two visible failure modes:

  • Output overwrite: Both call sites display the same response data, and the second call overwrites the first call's tags before the application can read them.
  • Error 80A3: Active connection resource already exists. The MB_CLIENT returns STATUS = 16#80A3 when the FB is reorganized as a multi-instance block inside a wrapper FB and a second instance is opened against the same remote IP and port.

Both symptoms have the same root cause: global resources shared between the two calls. The MB_CLIENT FB reads its connection state, request buffer, and internal handshake bits from a single instance data block; when two calls share the same DB (or, worse, share absolute M-bits or OB-tag globals), the runtime cannot tell them apart. The S7-1200 CPU does not duplicate the TCP connection resources, so the second CONNECT primitive collides with the first.

Root Cause Analysis

How MB_CLIENT Manages State

The MB_CLIENT instruction is an FB published in the Siemens Modbus TCP library (instruction library "Communication Processor and Modbus TCP"). It encapsulates the open user communication blocks (TCON, TSEND, TRCV, TDISCON) plus a small state machine that:

  1. Resolves the TCON_IP_V4 connection descriptor.
  2. Transitions REQ rising edges into a Modbus PDU.
  3. Demultiplexes the incoming PDU back to the configured MB_MODE / MB_DATA_ADDR pair.
  4. Exposes DONE, BUSY, ERROR, and STATUS.

All of this state lives in the instance DB that TIA Portal generates when the FB is dropped onto a network. If you call the same FB symbol from two networks and the compiler emits a single instance DB, both calls operate on the same memory and the active job gets clobbered. The symptom is the output-overwrite case described in the original report.

Why Error 80A3 Appears After Multi-Instance Conversion

When the engineer converts the wrapper FB to a multi-instance block (i.e., declares the MB_CLIENT as a STAT variable inside the parent FB), TIA Portal still generates a DB per parent FB call. Each parent-instance gets its own MB_CLIENT instance DB, which means each call attempts to open its own TCP connection. The S7-1200 user-communication stack rejects the second TCON with status word W#16#80A3 (Connection already established) because:

  • The connection descriptor uses the same RemoteAddress / RemotePort.
  • The connection descriptor uses the same ID field (the TCON connection ID).

Per the Siemens S7-1200 system manual, the connection ID is a 16-bit identifier unique within the CPU project. Reusing it for two simultaneously-open TCP sockets to the same partner is rejected by the communication resource manager.

Status (hex) Meaning (S7-1200 Open User Communication)
80A1 Connection establishment in progress
80A2 Connection cannot be established (partner not reachable)
80A3 Connection already established to the same partner with same connection ID
80A4 Connection terminated by remote
80A7 Connection terminated by CPU (resource issue)
80B4 Connection ID already in use

Hidden Cause: Globals Inside the FB

The expert response in the field report flags a second, often-overlooked issue: any reference to global M-bits, inputs/outputs, or OB1 temporary tags inside the FB body destroys re-entrancy. Modbus TCP FBs that read or write %M0.0 directly cannot be safely instantiated twice, because both calls will toggle the same bit. Re-entrancy must rely entirely on the instance DB (variables declared in VAR / STAT sections).

Engineering rule: Every static element of an FB intended for multiple instantiation must live in VAR_TEMP (when truly per-call), VAR_STAT (when persistent across calls), or the auto-generated instance DB. Never reference %M, %I, %Q, or shared DB absolute addresses from inside an FB that you intend to instantiate more than once.

Solution Architectures

Three patterns solve the problem. Choose based on whether you need true parallel polling or can serialize the requests.

Pattern A: Sequential Requests on a Single Shared MB_CLIENT Instance

Per the official TIA Portal "Example MB_CLIENT 1: Multiple requests with a common TCP connection" documentation, multiple Modbus client requests can be sent over the same TCP connection by reusing the same instance DB, connection ID, and remote port. Only one request is active at a time; the application triggers REQ when the previous job is complete. This is the lowest-overhead solution and is the recommended default.

Implementation in LAD:

  1. Drop one MB_CLIENT FB into OB1; accept the auto-generated instance DB (e.g., MB_CLIENT_DB).
  2. Create two input structures (REQ1, REQ2) that share the same FB instance but feed different MB_MODE / MB_DATA_ADDR values.
  3. In OB1, use a small state machine that asserts REQ for request 1, waits for DONE, copies the result, then asserts REQ for request 2.

Sample ST fragment showing the state machine:

// Cyclic OB1 segment
IF "mbState" = 0 THEN
    "mbClient".REQ := TRUE;
    "mbClient".MB_MODE := 1;          // Read Coils
    "mbClient".MB_DATA_ADDR := 0;     // Coil 0
    "mbClient".MB_DATA_LEN := 1;
    IF "mbClient".DONE THEN
        "coil0Value" := "mbClient".MB_DATA_BUF[1];
        "mbState" := 1;
    ELSIF "mbClient".ERROR THEN
        "mbState" := 99;              // Error handler
    END_IF;
ELSIF "mbState" = 1 THEN
    "mbClient".REQ := TRUE;
    "mbClient".MB_MODE := 1;
    "mbClient".MB_DATA_ADDR := 16;    // Coil 16
    "mbClient".MB_DATA_LEN := 1;
    IF "mbClient".DONE THEN
        "coil16Value" := "mbClient".MB_DATA_BUF[1];
        "mbState" := 0;
    ELSIF "mbClient".ERROR THEN
        "mbState" := 99;
    END_IF;
END_IF;
"mbClient".REQ := FALSE;
Critical detail: TIA Portal evaluates FB inputs on every cycle. Pulse REQ for one cycle only and reset it before the next state transition, otherwise the FB treats the request as continuous and re-issues the PDU on every scan.

Pattern B: Two Separate MB_CLIENT Instances with Unique Connection IDs

Use this when the application needs to keep both TCP sockets live (for example, one against a primary PLC and one against a redundant partner, or two independent slaves on different IPs). Each instance requires:

Parameter Instance A Instance B
Connection ID 1 2
Remote IP 192.168.0.10 192.168.0.11
Remote Port 502 502
Local Port 0 (any) 0 (any)
Connection Type TCP (active) TCP (active)
Instance DB MB_CLIENT_DB_1 MB_CLIENT_DB_2

Configure the connection descriptors in the TCON_IP_V4 DB before downloading. The S7-1200 supports up to 16 active Open User Communication connections on CPU firmware 4.x; the exact maximum depends on the CPU order number and is documented in the S7-1200 System Manual.

Pattern C: Multi-Instance DB Inside a Wrapper FB

If the goal is to ship a "Modbus read coil" toolbox FB that the user drops into OB1 multiple times, package MB_CLIENT as a static member of a wrapper FB. Each call site generates a new instance DB for the wrapper, which in turn allocates a new MB_CLIENT instance DB internally.

FUNCTION_BLOCK "FB_ModbusReadCoil"
VAR
    mbClient : MB_CLIENT;          // Static; multi-instance
    lastDone : BOOL;               // Per-instance latches
    lastError : BOOL;
    lastStatus : WORD;
END_VAR
BEGIN
    mbClient(REQ := REQ_IN,
             DISCONNECT := FALSE,
             MB_MODE := 1,
             MB_DATA_ADDR := ADDR_IN,
             MB_DATA_LEN := 1,
             CONNECT := CONNECT_DESC,
             MB_DATA_BUF := DATA_BUF);
    
    IF mbClient.DONE THEN
        DONE_OUT := TRUE;
        lastDone := TRUE;
    END_IF;
    IF mbClient.ERROR THEN
        ERROR_OUT := TRUE;
        lastError := TRUE;
    END_IF;
    STATUS_OUT := mbClient.STATUS;
END_FUNCTION_BLOCK

Call it twice in OB1:

"instReadCoil_0"(REQ_IN := req0,
                ADDR_IN := 0,
                CONNECT_DESC := connDesc0,
                DONE_OUT => done0,
                ERROR_OUT => err0,
                STATUS_OUT => stat0);

"instReadCoil_1"(REQ_IN := req1,
                ADDR_IN := 16,
                CONNECT_DESC := connDesc1,
                DONE_OUT => done1,
                ERROR_OUT => err1,
                STATUS_OUT => stat1);

For Pattern C, each instance must still receive a unique connection ID in its connDesc. The wrapper does not absolve the underlying TCP socket uniqueness rule.

Step-by-Step Fix for Error 80A3

Prerequisites

  • STEP 7 Basic / TIA Portal V14 SP1 or later (V16 recommended for current firmware targets).
  • S7-1200 CPU with firmware 4.2 or later (firmware 4.4 required for some Modbus library updates).
  • Modbus TCP instruction library installed: Instructions → Communication → Communication Processor → MODBUS TCP.
  • Reachable partner on TCP port 502 (or user-defined).

Procedure

  1. Audit the FB body. Open the FB in question and use Find → Find in code to search for any absolute address (%M, %I, %Q, DB with hard index). Replace each with an IN_OUT, STAT, or TEMP variable of the FB.
  2. Confirm the instance DB layout. Right-click the MB_CLIENT symbol in OB1, choose Properties → Information, and note the instance DB number. In the project tree, right-click Program blocks → Show block structure to verify only one instance DB exists per FB symbol.
  3. Decide on Pattern A, B, or C. Pick sequential sharing if both requests target the same Modbus server. Pick unique instances if requests go to different servers or you need concurrent sockets.
  4. For Pattern A: Create a small cyclic state machine that toggles between two MB_MODE / MB_DATA_ADDR combinations against one FB instance. Confirm both coils update at half the per-request scan rate (acceptable for most polling applications).
  5. For Pattern B: Add a second MB_CLIENT call. TIA Portal will create MB_CLIENT_DB_2 automatically. Open the new instance's CONNECT parameter and assign ConnectionID := 2, unique RemoteAddress, and matching RemotePort.
  6. For Pattern C: Verify each instance of the wrapper FB compiles to its own DB. In the project tree, the Program blocks folder should show one DB per instance (e.g., DB_FB_ModbusReadCoil_1, DB_FB_ModbusReadCoil_2). Confirm in the call environment that the CONNECT_DESC input for each call uses a unique ConnectionID.
  7. Download to the CPU with Stop → Download → Run. TIA Portal will reset retained tags; acknowledge the prompt.
  8. Go online and add the instance DBs to a watch table. Force REQ := TRUE for one cycle and observe STATUS returning 16#0000 on success or the standard Modbus exception codes on failure.

Verification

After applying one of the three patterns, verify the fix with the following checks:

Check Expected Result Method
MB_CLIENT.STATUS after each request 16#0000 on success; 16#80A3 must NOT recur Watch table on the instance DB
Independent coil values coil0Value and coil16Value differ when targets differ Watch table or HMI tag
Connection resource count Online → Diagnostics → Connection resources shows one (Pattern A) or two (Patterns B/C) active TCP entries Online diagnostics
Cycle time impact No more than ~5-10 ms per Modbus transaction added per cycle Online → Diagnostics → Cycle time
Behavior under partner failure Status transitions to 16#80A2 then 16#80A4; auto-reconnects on partner recovery Disconnect partner switch, observe

Troubleshooting Matrix

Observed Symptom Likely Cause Correction
Both call sites show the same output Single instance DB shared by both calls; one call clobbers the other Use Pattern A with state machine, or Pattern B/C with unique instance DBs
STATUS = 16#80A3 Duplicate connection ID or duplicate TCP socket to same partner Assign unique ConnectionID per instance; verify with online connection diagnostics
STATUS = 16#80A2 after download Partner not reachable, firewall blocking TCP/502, wrong IP Ping partner from CPU web server; check PLC → Security → Firewall settings; verify port number
STATUS = 16#8380 Modbus exception code from slave (illegal function or address) Verify MB_MODE / MB_DATA_ADDR are valid for the slave; cross-check with Modbus poll tool
STATUS = 16#80B4 Connection ID collision with another open user communication block Search project for duplicate ConnectionID values across TCON, TSEND, TRCV, MB_CLIENT, MB_SERVER
Second call never completes FB body uses global M-bits; the second instance toggles the same bits as the first Refactor FB to use only instance DB variables for all internal state
DONE never asserts REQ held high continuously; FB waits for falling edge before completing the handshake Pulse REQ for one OB1 cycle; reset before next state
Intermittent timeout on Pattern B CPU reached maximum Open User Communication resource count Reduce concurrent connections; consult CPU-specific resource table in the S7-1200 System Manual

Modbus TCP Library Compatibility Notes

The Modbus TCP instruction library ships with several revisions; check the version installed via Project → Libraries → Show library versions:

Library / Instruction Version CPU Firmware Min. Behavior Notes
MB_CLIENT v1.0 (V11-V13) 3.0 No multi-instance support; only static DBs
MB_CLIENT v2.0 (V14) 4.0 Multi-instance capable; connection resource reporting added
MB_CLIENT v3.0 (V15.1+) 4.2 Improved STATUS granularity; better disconnect handling
MB_CLIENT v4.x (V16+) 4.4 Symmetric connection descriptor; cert handling for secure Modbus variants

Projects created in TIA V14 with v2.0 of the MB_CLIENT library benefit from multi-instance support, which is the cleanest path for Pattern C. Older V11/V12 projects often need to be migrated and re-compiled against the newer instruction versions to gain the same capabilities.

Standards Reference

Modbus TCP behavior is defined by:

  • MODBUS Messaging on TCP/IP Implementation Guide V1.0b — specifies port 502 as the well-known Modbus port and PDU/ADU framing rules. Available from the Modbus Organization.
  • IEC 61158 (Industrial Communications) — referenced by Siemens for the underlying TCP transport, though Modbus TCP is not a CIP/EtherNet/IP protocol.
  • RFC 793 (TCP) and RFC 791 (IP) — define the transport layer used by every Modbus TCP connection. Siemens does not alter these; the S7-1200 follows standard TCP state transitions.

Connection-ID semantics are Siemens-specific and not part of the Modbus standard; they live in the S7-1200 communication resource manager and are documented per the SIMATIC S7-1200 Programmable Controller System Manual.

Edge Cases and Field-Proven Caveats

  • Firewall default: CPU firmware 4.x ships with the built-in firewall enabled in "Advanced" mode. TCP port 502 inbound is blocked by default; you must create an explicit rule for the partner IP range.
  • Partner reset: When the partner PLC powers cycles, MB_CLIENT transitions through 16#80A2, then 16#80A4, then auto-reconnects on the next REQ. Do not call DISCONNECT manually unless intentionally tearing the socket down.
  • Cycle-time budget: Each Modbus TCP transaction typically consumes 10-25 ms on a 1214C/1215C CPU depending on scan load. Pattern A doubles the effective poll latency compared to a single-instance single-request application; budget accordingly.
  • Watchdog risk on long DBs: If the user wraps the entire MB_CLIENT inside an FB with extensive ST logic, the resulting instance DB can exceed 1 KB. Watch the CPU's online memory budget; small CPUs (CPU 1211C, CPU 1212C) have tighter work-memory limits than 1215C and 1217C.
  • Symbolic vs. absolute addressing: When copying the wrapper FB, always use Copy → Paste with reference disabled, so TIA Portal generates a fresh instance DB. A reference-pasted FB will share the original DB and reintroduce the original symptom.

Frequently Asked Questions

What does Modbus TCP error 80A3 mean on an S7-1200?

Error 16#80A3 indicates the CPU's open-user-communication resource manager detected an attempt to open a TCP connection that is already active for the same partner and connection ID. For MB_CLIENT this typically means two FB instances are trying to share the same connection descriptor. Fix it by assigning a unique ConnectionID (and ideally a unique RemoteAddress) to each instance, or by collapsing the requests onto one shared instance using a sequential state machine.

Can I call the same MB_CLIENT FB twice from OB1 without creating two instance DBs?

Yes, but only if both calls cooperate via a single instance DB and a state machine. The official TIA Portal example "MB_CLIENT 1: Multiple requests with a common TCP connection" documents this pattern: same instance DB, same connection ID, same remote port, but only one REQ pulse at a time. Trying to run both REQ lines simultaneously against a single instance DB will overwrite the output tags because the FB stores its handshake state internally.

How many Modbus TCP connections can an S7-1200 CPU hold open?

The exact maximum depends on the CPU order number and firmware version. The SIMATIC S7-1200 System Manual lists the supported number of Open User Communication connections per CPU; CPU 1214C/DC/DC/DC with firmware 4.4 supports up to 16 concurrent connections including HMI, PG, and user connections. Verify the actual number in the manual for your specific CPU part number before scaling up.

Does using a multi-instance DB inside a wrapper FB prevent error 80A3?

No. Multi-instance only ensures each call of the wrapper FB gets its own MB_CLIENT instance DB. The TCP-layer conflict on the connection ID still applies: each instance must carry a distinct ConnectionID in its TCON_IP_V4 descriptor. Multi-instance solves the data-clobber symptom, not the connection-resource collision.

Why does my MB_CLIENT status show 16#8380 instead of a Siemens error?

Status 16#8380 means MB_CLIENT received a valid TCP response but the Modbus slave returned an exception PDU (function code with the high bit set, e.g., 0x81 instead of 0x01). The actual exception code (1-4) is encoded in the first byte of MB_DATA_BUF. Check whether the requested coil address exists in the slave's Modbus map and that MB_MODE matches the slave's expected function code.

Can I use MB_CLIENT and MB_SERVER on the same S7-1200 at the same time?

Yes, as long as the total number of active Open User Communication connections stays within the CPU's resource limit. MB_SERVER occupies one connection descriptor for inbound TCP/502 traffic. Use the Online → Diagnostics → Connection resources view in TIA Portal to confirm headroom before commissioning.

Back to blog