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.
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
MODBUSPNblock is called cyclically in OB1, butCONN_ESTABLISHEDremainsFALSE. - The transient outputs
ERROR,STATUS_MODBUS, andSTATUS_CONNtoggle 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
netstaton 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
MODBUSPNcall. 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 nameCONTROL_DATis 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. |
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:
- 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) - 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_ENRedge 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
- Open HW Config, mark the CPU 315-2 PN/DP, and click "Properties" on the PN interface.
- Set the IP address (192.168.1.1) and subnet mask (255.255.255.0). Disable router if no gateway is needed.
- Open NetPro. Right-click the CPU → "Insert New Connection" → "TCP connection".
- 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
IDinput of theMODBUSPNinstance. - 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
- SIMATIC Manager → File → Open → Library → "Modbus TCP PN".
- Copy FB102 (
MODBUSPN) and DB1 (CONTROL_DAT) into the master program (S7 program → Blocks). - 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_DATsymbol accordingly. Be sure the symbol nameCONTROL_DATpoints to the new DB number.
8.4 Generate the Instance DB and Configure Data Ranges
- Drag FB102 into OB1. When prompted, accept the default instance DB (e.g., DB102).
- 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.
- 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
- In OB1, connect the FB inputs as shown in Section 6.
- For cyclic polling, tie
ENQ_ENR := TRUE. For event-driven polling, use a flag that pulses once per scan or once per N scans. - Download all blocks to the CPU and place the CPU in RUN.
8.6 Monitor Status Words
- Open a VAT and watch
DB102.Save_STATUS_MODBUSandDB102.Save_STATUS_CONN(or, in the shared DB1,"CONTROL_DAT".Save_STATUS_MODBUS/Save_STATUS_CONN). - Watch
DB102.CONN_ESTABLISHED. It must transition to TRUE within a few seconds if the server is reachable. - 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:
-
TCP transport — Open a command prompt on the server and run
netstat -an | findstr :502. A line inESTABLISHEDstate confirms the TCP connection is up. - Connection resource — In NetPro online view, the connection ID assigned to the FB shows state "established".
-
Modbus transaction —
CONN_ESTABLISHED = TRUE,ERROR = FALSE, andSave_STATUS_MODBUS = 0x0000after the first poll cycle. - 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.
- Download
mod_rssim32and run it on a PC in the same subnet (192.168.1.252). - Set "Connection → Port" to 502.
- Set "File → New → Holding Registers" and define a small range (e.g., 100 registers starting at 0).
- Click "Listen" — the green status indicator confirms the TCP port is bound.
- 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.
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:
- Verify NetPro connection ID matches the FB's
IDinput exactly. - Run the wizard and confirm at least one
DATA_TYPE_n,DB_n,START_n,END_ntuple is non-zero. - Confirm the runtime
DATA_TYPE,START_ADDRESS,LENGTHare non-zero and fit inside one configured range. - Confirm the target DB exists and is large enough for
end_n - start_nwords. - Always monitor
CONTROL_DAT.Save_STATUS_MODBUSandSave_STATUS_CONN, not the transient outputs. - Ping the server from the PLC's online diagnostics before any Modbus transaction.
- For cyclic polling, keep
ENQ_ENR := TRUE; for event-driven polling, ensure the trigger is a single-scan pulse. - When in doubt, swap to
mod_rssim32on a known-good PC to isolate client vs. server faults. - 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 = 1when the tool expects 0 silently reads the wrong register. -
Big-endian / little-endian byte order. Modbus is big-endian on the wire; the
MODBUSPNblock 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_DATis correct, but the latched status words reflect the last FB to update. To trace one instance, add an internal copy ofSTATUS_MODBUSinside the instance DB and set it on a rising edge ofERROR. - 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
MODBUSPNinstance 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.