Resolving Modbus TCP/IP Connection Errors on S7-300 CPU 315-PN/DP

David Krause18 min read
ModbusSiemensTroubleshooting
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

Resolving Modbus TCP/IP Connection Errors on S7-300 CPU 315-PN/DP

When integrating a Siemens S7-300 CPU 315-2 PN/DP as a Modbus TCP client, the most common commissioning failure is a stalled connection where the CONN_ESTABLISHED output of the MODBUSPN function block never goes TRUE and the status word reports a non-zero error code. This technical reference walks through the field-diagnosed root causes behind the recurring W#16#A006 and W#16#A090 error codes returned by FB102 from the Siemens "Modbus TCP PN" library, and provides a step-by-step recovery procedure verified against the library's shared and instance data block architecture. Engineers commissioning similar topologies with WinCC Flexible Runtime, TIA Portal HMI panels, or a third-party Modbus server (such as mod_rssim32) will find the same diagnosis workflow applicable.

Field context. The error codes discussed here come from a documented commissioning case where the PLC was the Modbus client (192.168.1.1) and a WinCC Flexible Runtime instance was the Modbus server (192.168.1.252:502). After the server was swapped for mod_rssim32, communication succeeded — confirming that the root fault was on the client side (unparameterized data ranges) and not the server.

1. Problem Description and Symptom Matrix

The observed failure mode is consistent across reported incidents:

  • The S7-300 CPU 315-2 PN/DP downloads and starts in RUN without an SF (System Fault) LED indication.
  • The MODBUSPN block is called cyclically in OB1, but CONN_ESTABLISHED remains FALSE.
  • The transient outputs ERROR, STATUS_MODBUS, and STATUS_CONN toggle every cycle and are difficult to read in the VAT table.
  • The latched outputs in the shared DB1 "CONTROL_DAT" (Save_STATUS_MODBUS, Save_STATUS_CONN) hold a stable non-zero WORD value.
  • The TCP connection on port 502 is not visible in netstat on the server side, or it is opened and immediately reset by the client.

The status words reported in the field were:

Output Symbolic Name Value (W#16#) Meaning
STATUS_MODBUS Modbus protocol status 0xA006 The runtime data range does not match any area defined in DB2.
STATUS_CONN Connection status 0x0000 No connection-level error in this cycle (transient).
STATUS_FUNC Internal function status 0x0000 Block internal handler idle.

The earlier state (before the data block was corrected) showed STATUS_MODBUS = W#16#A090 with STATUS_CONN = W#16#0000, which is a typical "no matching request" or "send buffer empty" transient reported while the data areas are still unconfigured.

2. System Architecture and Required Components

The standard Modbus TCP client architecture for an S7-300 PN-CPU uses these components:

Component Type / Catalog No. Role
CPU 315-2 PN/DP 6ES7 315-2EH14-0AB0 (typical) Modbus TCP client (master)
Modbus TCP PN library Siemens entry ID 22660304 ("Modbus TCP PN" for S7-300/S7-400) Provides FB102 MODBUSPN and DB1 CONTROL_DAT
STEP 7 V5.5 / V5.6 Programming environment Library integration, NetPro configuration
Modbus server WinCC Flexible RT, Modbus Organization specification compliant tool, or mod_rssim32 Provides holding registers / coils
Ethernet network Industrial switch or direct crossover TCP/IP transport, port 502

The IP plan used in the reference case was:

  • PLC (Modbus client): 192.168.1.1 / 255.255.255.0
  • Modbus server (WinCC Flex RT or mod_rssim32): 192.168.1.252 / 255.255.255.0
  • TCP port: 502 (default Modbus TCP, do not change unless the server mandates it)

Verify the IP configuration is reachable from the PLC by using a PING from the S7-300 online diagnostics (or by opening an Ethernet commissioning tool in the same subnet). A failed ARP or routing layer is the most common root cause of STATUS_CONN = W#16#80C4 errors that mimic an A006 in early diagnostic snapshots.

3. The MODBUSPN Function Block (FB102)

MODBUSPN is the multi-instance-capable client FB that opens a TCP connection to one configured Modbus server, polls a list of data areas, and writes the decoded values into the configured instance DB. The block exposes both transient and latched status outputs:

I/O Name Direction Notes
ENQ_ENR Enquiry / Enable Request Input (BOOL) Rising edge triggers a Modbus transaction; in cyclic mode, hold TRUE for repeated polling.
DATA_TYPE Modbus data type Input (INT) 1 = coils, 2 = discrete inputs, 3 = holding registers, 4 = input registers.
START_ADDRESS Modbus start address Input (INT/DWORD) Zero-based Modbus address (holding register 0 = address 0 in the block call).
LENGTH Number of elements Input (INT) Bit count for type 1/2; word count for type 3/4.
WRITE_READ Write or read operation Input (BOOL) FALSE = read, TRUE = write.
WRITE_DATA Pointer to write buffer Input (ANY) Source buffer when WRITE_READ = TRUE.
CONN_ESTABLISHED Connection established Output (BOOL) TRUE only when the TCP connection to the server is up.
ERROR Error flag Output (BOOL) TRUE for one cycle when a fault occurs.
STATUS_MODBUS Modbus status Output (WORD) Valid for 1 cycle; latched into Save_STATUS_MODBUS in DB1.
STATUS_CONN Connection status Output (WORD) Same latching behavior as above.

The block requires a multi-instance DB (e.g., DB102) that holds the per-connection parameters. The shared DB1 "CONTROL_DAT" holds the centralized, latched status values plus the list of available data ranges that the block can match against a runtime request.

4. Data Block Architecture: DB1 CONTROL_DAT and the Instance DB

The "Modbus TCP PN" library uses two data blocks that engineers frequently confuse:

  • DB1 "CONTROL_DAT" — A shared, single-instance data block referenced by every MODBUSPN call. It contains the latched status words and the runtime control structures. It is created automatically when the library FBs are inserted into the project, and the symbolic name CONTROL_DAT is reserved.
  • Instance DB (e.g., DB2, DB102) — A user-named, per-connection instance that holds up to 8 data ranges (DATA_TYPE_1..8, DB_1..8, START_1..8, END_1..8, ACCESS_1..8). The wizard populates this DB with the data area definitions.

A typical CONTROL_DAT structure includes:

DATA_BLOCK "CONTROL_DAT"
TITLE = 'Modbus TCP PN Control Data'
AUTHOR : SIEMENS
FAMILY : MODBUSPN
VERSION : 1.0
  STRUCT
    Save_STATUS_MODBUS : WORD;   // Latched last STATUS_MODBUS
    Save_STATUS_CONN   : WORD;   // Latched last STATUS_CONN
    ...                       // Additional latched diagnostic fields
  END_STRUCT;
END_DATA_BLOCK

The instance DB has the eight "data range" slots. For a read of 10 holding registers starting at Modbus address 0 into PLC data block A, the slot values would be:

Field Value (hex) Value (dec) Meaning
data_type_1 0x0003 3 Holding register (function code 0x03)
db_1 0x000A 10 Target DB number (DB10)
start_1 0x0000 0 Target DB word offset 0
end_1 0x0064 100 Target DB word offset 100
access_1 0x0001 1 Read access

The eight slots allow eight non-overlapping address windows per connection. If the same physical connection must poll more than eight ranges, add a second MODBUSPN instance with a new instance DB and a new connection ID.

5. Error Code Reference for FB102 MODBUSPN

The status words are organized in ranges. The two codes relevant to this case are listed in the table below, alongside the other codes most often encountered in commissioning:

W#16# Source Meaning First-Action
0xA006 STATUS_MODBUS The runtime request (DATA_TYPE, START_ADDRESS, LENGTH) does not match any of the 8 data areas defined in the instance DB. Open the instance DB and verify all eight data-type/db/start/end fields are populated and the runtime request fits inside one of the windows.
0xA090 STATUS_MODBUS No active request pending — typically a transient state when the FB is called but the previous request has not been completed or no ENQ_ENR edge has been seen. Verify ENQ_ENR logic (rising edge for triggered mode, TRUE for cyclic) and that the OB1 cycle is running.
0x0000 STATUS_CONN No connection-level error in this cycle. Inspect Save_STATUS_CONN in DB1 for latched history.
0x80C4 STATUS_CONN TCP connection could not be established (server unreachable, wrong IP, or port blocked). Ping the server, verify the IP/port in NetPro, and check the firewall on the server PC.
0x8186 STATUS_CONN Connection ID in use by another block or duplicate instance. Check the connection ID assigned in NetPro and ensure it is unique within the project.
Read this carefully. STATUS_MODBUS, STATUS_CONN, and the ERROR flag are valid for a single CPU cycle. Reading them with a VAT or watch table will almost always show 0x0000 because the OB1 scan moves past the FB before the engineer can refresh. Always read the latched copies in DB1: CONTROL_DAT.Save_STATUS_MODBUS and CONTROL_DAT.Save_STATUS_CONN.

6. Root Cause Analysis: W#16#A006

The most frequent root cause of a stalled commissioning is the 0xA006 code, which is returned when the runtime request is valid in shape but does not match a configured data range. In the documented case, the runtime inputs were all zero:

  • DATA_TYPE = 0 — invalid; the FB will not even start a Modbus transaction.
  • START_ADDRESS = 0 — would map to Modbus register 0 if a type were selected, but with type 0 no match is found.
  • LENGTH = 0 — zero elements cannot be encoded in a Modbus PDU.

Because data_type_1..8 in the instance DB were also unconfigured (or because the wizard was never run), the FB's internal matcher found no candidate window and returned 0xA006. CONN_ESTABLISHED never goes TRUE because the FB does not attempt to open the TCP connection until at least one valid request has been queued and acknowledged.

The fix is twofold:

  1. Populate the instance DB with at least one valid data range. The simplest valid configuration is one read of 10 holding registers starting at address 0, stored in DB10 starting at word 0:
    data_type_1 = 3        // holding register
    db_1       = W#16#A    // DB10
    start_1    = 0
    end_1      = 100       // generous upper bound (>= requested length)
  2. Pass runtime values to the FB call that match the configured range:
    // In OB1 / cyclic call
       CALL FB102, DB102
         ENQ_ENR      := TRUE;          // cyclic polling
         DATA_TYPE    := 3;              // holding register
         START_ADDRESS:= 0;
         LENGTH       := 10;
         WRITE_READ   := FALSE;
         WRITE_DATA   := ;
         CONN_ESTABLISHED := M100.0;
         ERROR        := M100.1;
         STATUS_MODBUS:= MW102;
         STATUS_CONN  := MW104;

7. Root Cause Analysis: W#16#A090

The 0xA090 code is the FB's "idle / no pending request" state. It is reported when:

  • The FB has finished a previous transaction and no new ENQ_ENR edge has been detected.
  • The runtime parameters are zero, so the FB's request sequencer cannot build a PDU and immediately returns to idle.
  • The connection is being established and no Modbus request has been issued yet.

The 0xA090 is rarely a fault on its own. It is a status — when combined with CONN_ESTABLISHED = TRUE and zero latched errors, it means the FB is healthy and waiting. When combined with 0xA006 it is a secondary symptom of unparameterized data ranges.

8. Step-by-Step Resolution Procedure

Follow the procedure below to recover from a stalled MODBUSPN commissioning. Each step is independently verifiable so the engineer can localize the failure at the first sign of trouble.

8.1 Prerequisites

  • STEP 7 V5.5 SPx or V5.6 installed with the "Modbus TCP PN" library entry.
  • CPU 315-2 PN/DP with firmware ≥ V3.2 (earlier firmwares have known issues with TCP keep-alive; consult the CPU manual for the exact firmware matrix).
  • Modbus server reachable on the configured IP and port 502.
  • Ethernet commissioning cable and PG/PC with TCP/IP connectivity to the PLC subnet.

8.2 Configure the TCP Connection in NetPro

  1. Open HW Config, mark the CPU 315-2 PN/DP, and click "Properties" on the PN interface.
  2. Set the IP address (192.168.1.1) and subnet mask (255.255.255.0). Disable router if no gateway is needed.
  3. Open NetPro. Right-click the CPU → "Insert New Connection" → "TCP connection".
  4. Set the partner IP to 192.168.1.252 and the partner port to 502. Note the local connection ID assigned by NetPro (e.g., 1). This ID must match the ID input of the MODBUSPN instance.
  5. Compile and download the hardware configuration. The connection will not be opened at runtime until the FB requests it.

8.3 Install and Open the "Modbus TCP PN" Library

  1. SIMATIC Manager → File → Open → Library → "Modbus TCP PN".
  2. Copy FB102 (MODBUSPN) and DB1 (CONTROL_DAT) into the master program (S7 program → Blocks).
  3. If the project already has a DB1 with a different definition, rename the library DB1 to DB100 (or any unused number) and update the CONTROL_DAT symbol accordingly. Be sure the symbol name CONTROL_DAT points to the new DB number.

8.4 Generate the Instance DB and Configure Data Ranges

  1. Drag FB102 into OB1. When prompted, accept the default instance DB (e.g., DB102).
  2. Open the instance DB and fill in the data ranges. The fastest path is to use the bundled wizard: right-click the FB call → "Modbus TCP PN → Wizard" and follow the prompts.
  3. For the case at hand, configure one read range:
    DATA_TYPE_1 := 3        ; holding register
    DB_1        := W#16#A   ; DB10
    START_1     := 0
    END_1       := 100
    ACCESS_1    := 1        ; read

8.5 Wire the FB Call

  1. In OB1, connect the FB inputs as shown in Section 6.
  2. For cyclic polling, tie ENQ_ENR := TRUE. For event-driven polling, use a flag that pulses once per scan or once per N scans.
  3. Download all blocks to the CPU and place the CPU in RUN.

8.6 Monitor Status Words

  1. Open a VAT and watch DB102.Save_STATUS_MODBUS and DB102.Save_STATUS_CONN (or, in the shared DB1, "CONTROL_DAT".Save_STATUS_MODBUS / Save_STATUS_CONN).
  2. Watch DB102.CONN_ESTABLISHED. It must transition to TRUE within a few seconds if the server is reachable.
  3. Force the data type / start / length runtime inputs to non-zero and re-observe.

9. Verifying CONN_ESTABLISHED and Status Latching

The verification procedure proves that all four layers of the FB are healthy:

  1. TCP transport — Open a command prompt on the server and run netstat -an | findstr :502. A line in ESTABLISHED state confirms the TCP connection is up.
  2. Connection resource — In NetPro online view, the connection ID assigned to the FB shows state "established".
  3. Modbus transaction — CONN_ESTABLISHED = TRUE, ERROR = FALSE, and Save_STATUS_MODBUS = 0x0000 after the first poll cycle.
  4. Data quality — Set a known value in the server (e.g., holding register 0 = 0x1234) and verify that DB10.DBW0 in the PLC reflects the same value after the first poll.

For a triggered mode (single shot per ENQ_ENR rising edge), the cycle is:

CPU cycle n:   ENQ_ENR ↑ (rising edge)
              FB builds Modbus PDU, opens TCP if needed
CPU cycle n+1: Send pending, CONN_ESTABLISHED may be FALSE
CPU cycle n+k: Response received, data written, ERROR = TRUE for 1 cycle
              Save_STATUS_MODBUS = 0x0000 (success) or 0xAxxx (fault)
CPU cycle n+k+1: ERROR = FALSE, ENQ_ENR ignored until next rising edge

10. Using mod_rssim32 as a Test Server

The mod_rssim32 utility is a lightweight Windows Modbus server that supports holding registers, input registers, coils, and discrete inputs with a simple grid editor. It is ideal for verifying an S7-300 client without depending on a real HMI or PLC server.

  1. Download mod_rssim32 and run it on a PC in the same subnet (192.168.1.252).
  2. Set "Connection → Port" to 502.
  3. Set "File → New → Holding Registers" and define a small range (e.g., 100 registers starting at 0).
  4. Click "Listen" — the green status indicator confirms the TCP port is bound.
  5. From the PLC, trigger the FB. Within 1-2 poll cycles, the values written into the server's grid should appear in the configured instance DB target range, and vice versa for write tests.

Why does swapping from WinCC Flexible Runtime to mod_rssim32 "fix" the problem? In the documented case, the underlying fault (unconfigured DB2 ranges causing 0xA006) was on the client side. WinCC Flexible Runtime's Modbus TCP/IP driver was the original target, but the engineer's diagnostic workflow was slowed by WinCC's own commissioning screens. mod_rssim32 provides a minimal, transparent server that lets the engineer isolate client behavior from server behavior. Once the client parameters are correct, the same program will talk to WinCC Flexible Runtime, a third-party SCADA, or a real PLC server.

Firewall and PC binding. When using a Windows-based Modbus server, disable or open port 502 in the Windows Firewall. Bind the server to 0.0.0.0 (all interfaces) when in doubt — some servers default to the loopback adapter and reject Ethernet traffic from the PLC.

11. Preventive Checklist and Field Notes

Use this checklist for any new MODBUSPN deployment to avoid the A006/A090 stall:

  1. Verify NetPro connection ID matches the FB's ID input exactly.
  2. Run the wizard and confirm at least one DATA_TYPE_n, DB_n, START_n, END_n tuple is non-zero.
  3. Confirm the runtime DATA_TYPE, START_ADDRESS, LENGTH are non-zero and fit inside one configured range.
  4. Confirm the target DB exists and is large enough for end_n - start_n words.
  5. Always monitor CONTROL_DAT.Save_STATUS_MODBUS and Save_STATUS_CONN, not the transient outputs.
  6. Ping the server from the PLC's online diagnostics before any Modbus transaction.
  7. For cyclic polling, keep ENQ_ENR := TRUE; for event-driven polling, ensure the trigger is a single-scan pulse.
  8. When in doubt, swap to mod_rssim32 on a known-good PC to isolate client vs. server faults.
  9. Document the IP, port, connection ID, and data type tuples in a commissioning sheet before live operation.

12. Common Pitfalls and Edge Cases

  • Off-by-one in the Modbus address space. Modbus holding register 40001 in many SCADA tools is address 0 at the protocol level. Sending START_ADDRESS = 1 when the tool expects 0 silently reads the wrong register.
  • Big-endian / little-endian byte order. Modbus is big-endian on the wire; the MODBUSPN block handles word swap automatically for INT and REAL but does not byte-swap within a word. If the application uses byte-granularity values, account for the byte order explicitly.
  • Multiple instances sharing DB1. Two FBs sharing the same CONTROL_DAT is correct, but the latched status words reflect the last FB to update. To trace one instance, add an internal copy of STATUS_MODBUS inside the instance DB and set it on a rising edge of ERROR.
  • CPU 315-2 PN/DP firmware < V3.2. Older firmware revisions may drop the TCP connection after the configured keep-alive interval. Either upgrade the firmware or call the FB more frequently than the keep-alive timer.
  • Multiple connections to the same server. A single MODBUSPN instance opens exactly one TCP connection. To poll additional ranges on the same server, use additional instances each with their own connection ID and instance DB.

13. Related Diagnostics: STATUS_CONN Latching Patterns

The latched Save_STATUS_CONN value is the best indicator of whether the FB is reaching the transport layer at all. The typical patterns are:

Save_STATUS_CONN Interpretation Action
0x0000 No connection error in the last cycle. Healthy. If CONN_ESTABLISHED is still FALSE, the issue is at the Modbus request level (see Save_STATUS_MODBUS).
0x80C4 TCP connection could not be established. Ping the server, verify the IP in NetPro, check the firewall on the server side.
0x8186 Connection ID conflict. Check the connection ID in NetPro and confirm no other resource uses it.
0x80A1 Connection aborted by the server. Check the server log for protocol violations. Most often a function code mismatch or an out-of-range register request.

Documented field evidence shows that a Save_STATUS_CONN = 0x0000 with a persistent Save_STATUS_MODBUS = 0xA006 is the signature of the unconfigured-data-range failure. Conversely, a non-zero Save_STATUS_CONN with a non-zero Save_STATUS_MODBUS usually points to a wiring / network / firewall problem rather than a parameterization problem.

14. Reference: Standard Modbus Data Type Codes

DATA_TYPE Modbus Function Code Access Address Unit
1 0x01 / 0x05 / 0x0F Coil (read / write single / write multiple) Bit index
2 0x02 Discrete input (read-only) Bit index
3 0x03 / 0x06 / 0x10 Holding register (read / write single / write multiple) Word index
4 0x04 Input register (read-only) Word index

The MODBUSPN block accepts the DATA_TYPE as an integer (1..4) at runtime. Pair it with the matching data_type_n field in the instance DB or the request will be rejected with 0xA006.

15. Summary and Recovery Flow

The recovery flow for the documented A006/A090 commissioning stall is:

[FB102 called in OB1]
        |
        v
[Is CONN_ESTABLISHED TRUE?]----No--->[Check Save_STATUS_CONN]
        |                                   |
        Yes                                0x0000 -> client-side fault
        v                                   |
[Is Save_STATUS_MODBUS = 0x0000?]         0x80C4 -> ping/NetPro/firewall
        |
        No --> 0xA006 -> populate DB2 data ranges and re-call
        |
        Yes -> communication healthy

For the engineer on the plant floor, the fastest path to a working client is therefore: run the FB wizard, populate DATA_TYPE_1..8, DB_1..8, START_1..8, END_1..8, and pass non-zero matching values to the FB at runtime. Once CONN_ESTABLISHED transitions to TRUE and Save_STATUS_MODBUS settles at 0x0000, the Modbus TCP client is fully commissioned.

FAQ

What does W#16#A006 mean on FB102 MODBUSPN?

It means the runtime request — defined by the FB inputs DATA_TYPE, START_ADDRESS, and LENGTH — does not match any of the eight data areas configured in the instance DB (typically DB2 or DB102). Populate the instance DB fields DATA_TYPE_n, DB_n, START_n, END_n with valid values and pass non-zero matching runtime parameters to the FB.

Why is CONN_ESTABLISHED still FALSE even though STATUS_CONN is 0x0000?

Because STATUS_CONN is valid for one CPU cycle and the FB does not open the TCP connection until a valid Modbus request is queued. With an A006 error, the FB never reaches the connection-open step. Fix the data range configuration (Section 8.4) and CONN_ESTABLISHED will transition to TRUE once a valid transaction is initiated.

Where do I find the latched STATUS_MODBUS and STATUS_CONN values?

Open the shared DB1 "CONTROL_DAT". The fields Save_STATUS_MODBUS and Save_STATUS_CONN hold the latched last values. Reading the FB outputs directly with a watch table or VAT almost always shows 0x0000 because the status is valid for one OB1 cycle only.

Can I poll more than eight data ranges with one MODBUSPN instance?

No. Each instance supports exactly eight data area slots (DATA_TYPE_1..8). To poll more ranges on the same server, create a second MODBUSPN instance with its own instance DB and a unique connection ID in NetPro. Both instances share the same DB1 CONTROL_DAT for latched status.

Does mod_rssim32 work the same as WinCC Flexible Runtime as a Modbus server?

Functionally, yes — both implement the standard Modbus TCP/IP protocol on port 502. mod_rssim32 is a minimal, transparent server that is useful for client-side commissioning because it strips away the HMI configuration layer. Once the S7-300 client is verified against mod_rssim32, the same configuration will communicate with WinCC Flexible Runtime, a third-party SCADA, or any compliant Modbus TCP server.

What is the difference between STATUS_CONN 0x80C4 and STATUS_MODBUS 0xA006?

STATUS_CONN 0x80C4 is a transport-layer error: the TCP connection to the server could not be established (wrong IP, blocked port, or unreachable host). STATUS_MODBUS 0xA006 is an application-layer error: the TCP layer is fine, but the FB's request parameters do not match any configured data area in the instance DB. Diagnose 0x80C4 with network tools (ping, netstat, firewall); diagnose 0xA006 by inspecting the instance DB and runtime FB inputs.

Back to blog