Configuring Modbus TCP/IP on S7-1500 with MB_CLIENT in TIA Portal

David Krause12 min read
SiemensTIA PortalTutorial / How-to
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

Overview

The S7-1500 CPU family communicates natively over PROFINET and standard TCP/IP but does not include a Modbus TCP server/client in the system firmware of every CPU variant. To integrate a Modbus TCP/IP device (instrument, drive, third-party controller, legacy SCADA) into a S7-1500 project, Siemens provides two function blocks in the global library Communication > Others > MODBUS TCP:

  • MB_CLIENT (FB 1084) — S7-1500 acts as a Modbus TCP client and polls a remote server.
  • MB_SERVER (FB 1085) — S7-1500 acts as a Modbus TCP server and answers requests from a remote client.

Both blocks use ISO-on-TCP / TCP connections (connection type 16#0B = 0x0B for TCP) and operate exclusively through the PN interface of the CPU. They replace the older S7-300/S7-400 FB 5 / FB 7 approach. The official reference application note "Modbus/TCP with instructions MB_CLIENT and MB_SERVER" is published as entry 102020340 on the Siemens Industry Online Support portal.

Note: Modbus TCP uses TCP port 502 (server listens on 502; clients use an ephemeral source port). The S7-1500 active connection establishment and TSEND_C/TRCV_C blocks are not required — MB_CLIENT/MB_SERVER internally handle the open/close, send, and receive on a single connection.

Architecture and Topology

Three reference topologies are typical:

  1. S7-1500 client → third-party server (instrument, drive, Eurotherm nanodac, panel meter, Energy meter). The CPU opens one TCP connection per remote server and issues cyclic read/write requests.
  2. External client → S7-1500 server (SCADA, HMI, Modicon M340, third-party gateway). Up to n clients can connect simultaneously; each requires its own MB_SERVER instance and a separate connection ID.
  3. S7-1500 client ↔ S7-1500/S7-1200 server for back-to-back data exchange. S7-1500 typically uses MB_CLIENT, S7-1200/1500 exposes a Modbus server through MB_SERVER (S7-1200 uses the same FB numbers as 1500: FB 1084/1085 in the TIA "ModbusTCP" library).

Each MB_CLIENT requires a unique connection ID and a unique instance DB. Each MB_SERVER instance can serve multiple clients on the same listen port, but the CPU maintains one internal data pool (the Modbus mapping area) shared by all connections.

Prerequisites

  • TIA Portal V15.1, V16, V17, V18, or V19 with installed "SIMATIC ModbusTCP" library. The library ships with STEP 7 and can be opened from Options > Manage Library or by drag-and-drop from the project tree under Libraries > Global Libraries > Communication > MODBUS TCP.
  • S7-1500 CPU with PROFINET interface (e.g. CPU 1511-1 PN, 1513-1 PN, 1515-2 PN, 1516-3 PN/DP, 1518-4 PN/DP). All standard PN CPUs from firmware V1.5 onward are supported; some compact CPUs (CPU 1511C, 1512C) also support Modbus TCP through the integrated PN port.
  • Firmware: CPU firmware ≥ V1.8 recommended for V17/V18 libraries. TIA Portal will warn if a library version is newer than the CPU's firmware supports.
  • IP plan: S7-1500 CPU in subnet with the Modbus server, e.g. 192.168.0.10/24 (client) → 192.168.0.20/24 (server). Keep the client and server on the same subnet or route via Layer-3 with permissive firewall rules on port 502.
  • Number of connections: the S7-1500 CPU has a maximum number of open communication resources (system resource 1 = PG/OP/HMI; 2..n = open user connections). S7-1500 supports 64–256 user connections depending on CPU type. MB_CLIENT and MB_SERVER each consume one connection resource per remote partner.

Installing the Modbus TCP Library

  1. Open the TIA Portal project.
  2. In the project tree, expand Libraries > Global Libraries.
  3. Open the library Communication > MODBUS TCP (TIA V17/18: folder ModbusTCP containing types MB_CLIENT, MB_SERVER, MB_RED_CLIENT, and the Modbus_Comm_DB global DB).
  4. Drag MB_CLIENT (FB 1084), MB_SERVER (FB 1085), and the included Modbus_Comm_DB into the Program blocks folder of the S7-1500 CPU.
  5. If the library version is newer than your CPU firmware, TIA Portal flags the FB as "library newer than CPU supports". Either upgrade the CPU firmware, or open the library in a matching TIA version and use an older FB revision (V1.0/V1.2/V2.0 are backward compatible for the same FB number).
Note: The DB that backs the MB_SERVER Modbus mapping area is generated automatically the first time the block compiles. Do not delete it; its structure (Coils, Discrete Inputs, Holding Registers, Input Registers) is determined by the configured HR_Start_Offset, DR_Start_Offset, CR_Start_Offset, IR_Start_Offset, and length parameters.

Hardware Configuration: PROFINET Interface

  1. In Devices & Networks, select the S7-1500 CPU and open Properties > PROFINET interface [X1].
  2. Assign the IP address, subnet mask, and (if required) router address. Example: IP 192.168.0.10, mask 255.255.255.0.
  3. Under Time-of-day synchronization you can leave defaults. Ensure Use router is disabled unless Modbus server is on a different subnet.
  4. No additional IO device or Modbus partner needs to be configured — MB_CLIENT/MB_SERVER use free TCP connections, not PROFINET IO ARs.

Configuring the Connection (LADDR / Connection_ID)

MB_CLIENT and MB_SERVER manage their own connection through the system resource LADDR (referenced indirectly). You do not create an explicit TSEND_C / TRCV_C connection. Instead, the block derives the connection from CONNECT input (a TCON_IP_V4 struct) and the unique ID.

Input Data type Description Typical value
REQ BOOL Start a single Modbus transaction when rising edge Pulse from a clock generator or call condition
DISCONNECT BOOL Close the TCP connection on a rising edge Fault reset or maintenance flag
CONNECT TCON_IP_V4 Remote server IP, remote port, local port, connection type See struct below
MB_MODE USINT 0 = read, 1 = write 0 for read holding registers
MB_DATA_ADDR UINT Modbus starting address 40001 (HR 1), 30001 (IR 1), 10001 (DI 1), 1 (Coil 1)
MB_DATA_LEN UINT Number of elements to read/write 1..125 for registers, 1..2000 for coils
MB_DATA_PTR VARIANT Pointer to a DB / tag in the data area P#DB100.DBX0.0 BYTE 100
DONE BOOL Last request completed without error Use as a one-shot
BUSY BOOL Request in progress (do not retrigger) Hold for re-trigger logic
ERROR BOOL Last request failed Combine with STATUS evaluation
STATUS WORD Detailed status / error code See error table
CONNECT_ID CONN_OUC Unique connection ID for this instance 1, 2, 3, ...

Default TCON_IP_V4 parameters for a TCP connection (binary constants):

  • InterfaceId = 16#0000_0001 (PN interface X1, port 1)
  • ID = 16#0000_0001 (must match the CONNECT_ID you configure)
  • ConnectionType = 16#0B (TCP)
  • ActiveEstablished = TRUE (MB_CLIENT is always the active opener)
  • RemoteAddress = IP4 address of server, e.g. 192.168.0.20 (in Siemens syntax: RemoteAddress[1]=192, [2]=168, [3]=0, [4]=20)
  • RemotePort = 502 (Modbus TCP server port)
  • LocalPort = 0 (use ephemeral port — set to 0 unless a firewall requires a specific port)
Caution: ActiveEstablished = TRUE is required for MB_CLIENT. For MB_SERVER, the same struct is used but ActiveEstablished = FALSE (server passively listens). Failure to set ActiveEstablished correctly is a common cause of STATUS = W#16#80C7 errors.

MB_CLIENT: Reading Holding Registers (Function Code 3)

To read 10 holding registers starting at Modbus address 40001 from a server at 192.168.0.20:

  1. Create a global DB, e.g. DB100 "ModbusData", with an array of 20 bytes: tags: ARRAY[0..19] OF BYTE;
  2. Insert a new FB/FC or use OB1 to call MB_CLIENT. In TIA Portal: Add new block > FB > SCL.
  3. Declare the following IN/OUT variables:
VAR
    REQ_Pulse       : BOOL;     // one-shot trigger, e.g. clock 0.5s
    BusyFlag        : BOOL;
    DoneFlag        : BOOL;
    ErrorFlag       : BOOL;
    StatusWord      : WORD;
    MB_Mode         : USINT := 0;   // 0 = read
    MB_DataAddr     : UINT  := 40001;
    MB_DataLen      : UINT  := 10;
    Connect         : TCON_IP_V4;
    ConnectId       : CONN_OUC := 1;
END_VAR
  1. Fill the Connect struct in OB1 startup or in an INIT block:
// Static IP parameters for the remote server
Connect.InterfaceId       := 16#0000_0001;   // CPU PN port
Connect.ID                := ConnectId;     // 1
Connect.ConnectionType    := 16#000B;       // TCP
Connect.ActiveEstablished := TRUE;          // client side
Connect.RemoteAddress[1]  := 192;
Connect.RemoteAddress[2]  := 168;
Connect.RemoteAddress[3]  := 0;
Connect.RemoteAddress[4]  := 20;
Connect.RemotePort        := 502;
Connect.LocalPort         := 0;             // OS-assigned
  1. Call the block in cyclic OB1 (or OB30/OB35 if you want deterministic polling):
// Retrigger only when previous request is complete
IF NOT "MB_Client_1".Busy THEN
    "MB_Client_1".REQ := REQ_Pulse;
END_IF;

"MB_Client_1"(
    REQ              := REQ_Pulse,
    DISCONNECT       := FALSE,
    CONNECT          := Connect,
    MB_MODE          := MB_Mode,
    MB_DATA_ADDR     := MB_DataAddr,
    MB_DATA_LEN      := MB_DataLen,
    MB_DATA_PTR      := P#DB100.DBX0.0 BYTE 20,
    CONNECT_ID       := ConnectId,
    DONE             => DoneFlag,
    BUSY             => BusyFlag,
    ERROR            => ErrorFlag,
    STATUS           => StatusWord
);

Each call with REQ rising edge issues one read. For cyclic polling, generate a 1-second pulse on REQ_Pulse using a clock bit (e.g. Clock_1Hz in OB35 with cyclic interrupt 1000 ms) and gate it with NOT BUSY to avoid overlapping requests.

MB_CLIENT: Writing a Single Coil (Function Code 5)

To set coil 1 (Modbus address 0, write single coil):

// In a dedicated FC "WriteSingleCoil"
MB_Mode    := 1;            // 1 = write
MB_DataAddr := 0;           // coil 0 (0-based)
MB_DataLen  := 1;           // 1 element
// For coils, MB_DATA_PTR must point to a BOOL or BYTE buffer
MB_DataPtr := P#DB101.DBX0.0 BOOL;  // DB101.Byte0 bit 0 = coil state

For Function Code 15 (write multiple coils), set MB_DATA_LEN up to 2000 and use a BYTE array of length ⌈len/8⌉.

MB_SERVER: Exposing S7-1500 Data as Modbus

Insert MB_SERVER (FB 1085) in OB1 and assign its instance DB. Configure the static control bits and offsets:

Input Meaning Default
HR_Start_Offset Holding register base in Modbus address space 0
DR_Start_Offset Discrete input base 0
CR_Start_Offset Coil base 0
IR_Start_Offset Input register base 0
HR_Length / DR_Length / CR_Length / IR_Length Length of the area (0 = disabled) 0..2000 / 0..2000 / 0..2000 / 0..2000
UNIT_ID Modbus unit identifier (1..247; 255 = ignore) 255
CONNECT Passive listen — LocalPort = 502, RemotePort = 0 Same TCON_IP_V4

The server-side connection is opened passively — the S7-1500 listens for incoming connections on the local port. ActiveEstablished = FALSE, LocalPort = 502.

Note: The mapping area backing MB_SERVER is the instance DB of MB_SERVER. If you need to expose a process DB to the Modbus client, you must copy data from MB_SERVER's instance DB to your process DB. Some libraries expose a Modbus_Comm_DB with arrays of BOOL, INT, REAL for coils, holding registers, etc.

Error Codes and STATUS Diagnostics

The STATUS output returns extended diagnostic information. Common values (Siemens W#16# format):

STATUS Meaning Action
16#0000 No error —
16#7000 No request active Normal idle state
16#7001 First call with REQ, busy Wait for DONE / ERROR
16#7002 Subsequent call, busy Wait
16#80C7 Connection not established / partner not reachable Check IP, subnet, port, firewall, CPU PN cable
16#80C8 Connection aborted by remote Server closed; check server health
16#8181 Wrong data length or data pointer Check MB_DATA_LEN vs MB_DATA_PTR size
16#8182 Data pointer invalid (area length mismatch) Re-check variant pointer
16#8183 Connection ID already in use Use unique CONNECT_ID per instance
16#8184 Connection type not TCP Set ConnectionType = 16#0B
16#8185 ActiveEstablished flag inconsistent Set TRUE for client, FALSE for server
16#8186 CONNECT_ID out of range Use 1..64 (CPU-dependent)
16#8187 Local/remote port zero not allowed Server: LocalPort = 502; Client: RemotePort = 502
16#8188 Data type and function code mismatch e.g. INT for register, BOOL for coil
16#8381 Modbus exception code 0x01 (illegal function) Server does not support this FC
16#8382 Modbus exception 0x02 (illegal data address) Address outside server map
16#8383 Modbus exception 0x03 (illegal data value) Length exceeds server map
16#8384 Modbus exception 0x04 (server device failure) Server-side fault; check server status
16#8388 Modbus exception 0x08 (memory parity error) Server memory fault
16#80A1 Internal resource exhaustion Reduce number of open connections

For full lists, refer to the FB 1084 / FB 1085 online help inside TIA Portal and the Siemens FAQ 94766380.

Wiring Multiple Servers (Multi-Client, Multi-Connection)

For a star topology with three instruments (M1, M2, M3), use three MB_CLIENT instances, three instance DBs, three unique CONNECT_ID values (1, 2, 3), and three Connect structs. Poll them sequentially with a state machine to avoid overlapping REQ pulses on a single CPU scan.

CASE State OF
    0:  // idle, send M1 request
        MB_DataAddr := 40001;
        MB_DataLen  := 10;
        Connect.RemoteAddress[4] := 20; // 192.168.0.20
        REQ := TRUE; State := 1;
    1:  // wait for done / error
        IF DONE THEN REQ := FALSE; State := 2; END_IF;
        IF ERROR THEN REQ := FALSE; LogError(); State := 2; END_IF;
    2:  // ... move to M2, etc.
END_CASE;

Commissioning and Verification

  1. Download the project to the S7-1500 CPU and put the CPU in RUN.
  2. Open Online & Diagnostics > Connection diagnostics on the PN interface. Confirm the TCP connection to 192.168.0.20:502 is shown as established.
  3. In the Watch table, force REQ = TRUE for one scan and observe BUSY rise, then DONE rise with STATUS = 0. The MB_DATA_PTR area should show fresh values.
  4. From a PC, run a Modbus TCP master simulator (e.g. Modbus Poll, qModMaster, or Wireshark with the modbus dissector) against the S7-1500 MB_SERVER and verify the holding register area.
  5. Use Wireshark on the network with filter tcp.port==502 && ip.addr==192.168.0.20 to capture MBAP + PDU frames. Expected transaction ID, protocol ID 0x0000, length 6+n, unit ID, function code, then register data.

Troubleshooting Matrix

Symptom STATUS Likely cause Action
BUSY never clears 16#7002 / 16#80C7 Server unreachable Ping remote; check PROFINET port LEDs; verify firewall
ERROR rises on every request 16#8181 MB_DATA_LEN > available bytes in MB_DATA_PTR Resize target DB or reduce length
Values zero / not updating 16#0000 / DONE=TRUE Endian mismatch or wrong offset Verify register order: HR 40001 is address 0; HR 40010 is address 9
Intermittent drops 16#80C8 Watchdog / TCP keep-alive Reduce polling rate, add DISCONNECT/RECONNECT logic
Only first transaction works 16#8183 Two blocks share a CONNECT_ID Use unique IDs
STATUS = 0, but data wrong 16#0000 Function code mismatch (FC 3 vs FC 4) Use FC 4 (Input Registers) for read-only words; FC 3 (Holding) for R/W
Modbus exception from server 16#8381..0x84 Server has no data at that address Check server Modbus map register list

Performance and Timing

Typical cycle for one MB_CLIENT transaction on an S7-1516-3 PN/DP (firmware V2.9):

  • Connect establishment (first poll): 20–80 ms
  • Reuse existing connection: 3–10 ms per transaction
  • 10 holding registers: ~4 ms
  • 125 holding registers (max): ~10 ms

For high-rate polling, use OB35 (cyclic interrupt) at 10–50 ms and add a watchdog timeout (e.g. error raised if no DONE within 2 OB35 cycles).

FAQ

Which function blocks do I need for Modbus TCP on an S7-1500?

Use MB_CLIENT (FB 1084) when the S7-1500 is the client polling a remote Modbus server, and MB_SERVER (FB 1085) when the S7-1500 exposes a Modbus server to a remote client. Both are found in the global library Communication > MODBUS TCP in TIA Portal V15.1 and later.

Why does MB_CLIENT return STATUS 16#80C7 and never complete?

This means the TCP connection cannot be established. Verify the remote server IP, that port 502 is open and not blocked by a firewall, that the S7-1500 PROFINET interface has a valid IP in the same subnet, and that ConnectionType = 16#0B with ActiveEstablished = TRUE.

How do I read Modbus holding register 40001..40010 into the S7-1500?

Set MB_MODE = 0, MB_DATA_ADDR = 40001 (or 0 in some libraries that use zero-based addressing — check your FB version), MB_DATA_LEN = 10, and point MB_DATA_PTR to a DB area large enough (≥ 20 bytes for 10 INT registers). Trigger with a one-shot REQ pulse and gate it with NOT BUSY.

Can MB_SERVER handle multiple simultaneous Modbus clients?

Yes, but each TCP connection consumes one open user connection resource on the S7-1500 CPU. The Modbus mapping data (coils, holding registers) is shared across all clients. For a typical CPU 1515-2 PN, you can have dozens of clients up to the connection-resource limit (64–128 open connections depending on CPU).

Do I still need TSEND_C / TRCV_C for Modbus TCP?

No. MB_CLIENT and MB_SERVER handle the TCP open/close, send, and receive internally. Manually combining TSEND_C with a Modbus parser is the legacy approach from S7-300 / S7-400 days and is not recommended for S7-1500.

Back to blog