Resolving S7-300 Modbus TCP I/O Mapping Issues on 315-2 PN/DP

David Krause17 min read
S7-300SiemensTroubleshooting
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

1. Problem Statement

An Siemens S7-300 CPU 315-2 PN/DP (firmware V3.2.3) is configured as a Modbus TCP server using a third-party Modbus/TCP library. A WinCC Flexible runtime acts as the Modbus TCP client. Communication succeeds: the client can read and write the Modbus-mapped data blocks (DB) on the PLC without protocol errors. However, the physical inputs and outputs of the S7-300 do not reflect the Modbus traffic, and the physical I/O does not write back into the Modbus data areas either.

Symptom summary:

  • Modbus client writes a coil → the corresponding bit in DB14 changes, but the LED on the digital output module does not change state and the load does not energize.
  • Modbus client reads a discrete input → the corresponding bit in DB15 always returns the value last written by the program, not the actual level on the digital input module.
  • Modbus client reads an input register → the word in DB13 returns the application value, not the converted value of the analog input module.
  • No protocol errors are generated. Save_Done_NDR is TRUE, Save_STATUS_MODBUS = 16#A090, Save_STATUS_CONN = 16#A100 / 16#7002, Count_Error stays at zero.

The behavior described is a classic S7-300 Modbus data-routing problem, not a protocol problem.

2. Environment and Configuration

The relevant hardware and software stack for this case is:

Component Part / Version Notes
CPU 6ES7315-2EH14-0AB0 (315-2 PN/DP) Firmware V3.2.3, integrated PROFINET interface used as Modbus TCP server
DI module 6ES7321-1BL00-0AA0 (DI 32xDC24V) Slot 4, I-address area 0…3 (IB0…IB3)
DO module 6ES7322-1BL00-0AA0 (DO 32xDC24V/0.5A) Slot 5, Q-address area 4…7 (QB4&hellpaceQB7)
AI module 6ES7331-7KF02-0AB0 (AI 8x16Bit) Slot 6, I-address area 288…303 (PEW288…PEW302, PQW288 unused for output)
Modbus/TCP library IT4Industry Modbus/TCP PN CPU trial library, FB102 (MODBUSPN) Acts as the Modbus server; exchanges data only with a single configured DB
HMI / client WinCC Flexible 2008 SP5, RT on PC Configured as Modbus TCP master, connected to the PN interface IP:502
Programming STEP 7 V5.5 + SP4 Project with OB1, OB100, DB13…DB15, FB102 and its instance DB

Modbus data area mapping declared in the example project (kept by the user, addresses re-mapped to the actual slot addresses of the project):

Modbus area Function codes DB Bit / word range in DB Mapped S7-300 I/O
Discrete Inputs FC2 (Read Discrete Inputs) DB15 (BOOL array) Bits 0…31 (word 0…1) IB0…IB3 (DI 32xDC24V)
Coils FC1, FC5, FC15 DB14 (BOOL array) Bits 32…63 (word 2…3) QB4…QB7 (DO 32xDC24V/0.5A)
Input Registers FC4 (Read Input Registers) DB13 (INT array) Words 0x120…0x12F (288…303) PEW288…PEW302 (AI 8x16Bit)
Holding Registers FC3, FC6, FC16 DB12 (INT array) Words 0…511 Internal, no physical I/O

The mapping in the table is declarative only. The IT4Industry Modbus/TCP FB does not perform any implicit move between the S7 process image and the Modbus data block; it only reads and writes the DB. The user must populate the data exchange in user code.

3. Root Cause Analysis

The MODBUSPN FB (FB102) implements a Modbus TCP server that is decoupled from the S7 process image. It exchanges a data image that the integrator must keep in step with the real I/O. When the program is written as a "DB-only" implementation, the Modbus traffic stays inside the DB and never reaches the periphery. This is the exact situation visible in the symptom list.

Three architectural facts have to be respected to make the link work:

  1. Digital outputs (coils) must be written to the process image of outputs, not just to a DB. The simplest path is to copy the relevant word(s) of DB14 to the peripheral output area (e.g. QB4) in OB1, or to PQW addresses if a module is configured outside the process image.
  2. Digital inputs (discrete inputs) must be read from the process image of inputs, not from a DB. The bit that the client reads for "input 0" must be the current value of I0.0, not a static bit in DB15. The user has to copy the process image into the DB before the FB executes, or the FB has to be configured with the input I-address as the data source.
  3. Analog input registers (input registers) must be read from the peripheral input area, not from a DB. For an SM 331 placed at the slot of PEW 288, the AI conversion value is refreshed by the module every basic cycle and is read using L PEW 288 / T DBW .... Analog outputs (holding registers intended for outputs) must be written with L DBW ... / T PQW ....

The status values observed in the project confirm the protocol layer is healthy and point the diagnostic away from communication and towards the I/O glue logic:

Tag Connected Not connected Interpretation
Licence (License_Ok) FALSE TRUE Trial license expired — confirm with IT4Industry vendor. The library still runs in trial mode, but functional restriction applies to a single connection / limited time.
Busy TRUE TRUE FB is processing.
Connection Established (EstdConn) TRUE FALSE TCP connection to the client is up.
Done_NDR FALSE FALSE Snapshot is misleading: DONE_NDR is only TRUE for one OB1 cycle. The Save_Done_NDR latch proves requests are arriving.
Error FALSE FALSE No Modbus exception has been generated.
STATUS_MODBUS 16#A090 16#A090 Internal status "no Modbus request processed in this cycle" — see Siemens IT4Industry FB102 status table. Different from a Modbus exception code.
STATUS_CONN (TCON status) 16#A100 / 7002 16#A100 / 7002 Ẃ? A100 indicates an active TCP connection; 7002 is the TCON output when no connection is currently established, both normal in the "connected" vs. "not connected" state.

Because the counters Count_Done and Count_Error behave correctly, the TCP link on port 502 is open and the FB is replying. The bug is therefore not on the network, the firewall or the FB itself — it is in the data glue between the DB and the process image.

Important: A static value of 16#A090 in STATUS_MODBUS does not mean "error" for the IT4Industry FB. It is the "no result in this cycle" code. Always read Error + STATUS_MODBUS in the same OB1 cycle, otherwise you will miss a real Modbus exception (1…255).

4. Diagnostic Procedure

Use the following sequence to confirm the data glue is the problem and to gather the values you need to fix it.

  1. Open the VAT "Modbus_Status" online and force the following tags to TRUE for one OB1 cycle after the client writes a coil:
    • Save_Done_NDR — latches TRUE when a request was processed without error.
    • Save_Error — latches TRUE if a Modbus exception occurred; pair with Save_STATUS_MODBUS in the same cycle.
  2. Watch Count_Done and Count_Error. A rising Count_Done with steady Count_Error confirms that the client request is reaching the FB. If Count_Done is steady, the problem is on the network side (firewall, IP, port 502 closed, wrong PN interface selected).
  3. Open the cross-reference for DB14 / DB15 / DB13 in STEP 7 (V5.5: Options → Reference Data → Display). Verify that each DB has at least one "W" access from OB1 (or another OB) that touches the I/O area. If the cross-reference shows only the FB102 access, the DB is isolated and the bug is confirmed.
  4. Open HW Config and write down the actual I-addresses of the DI, DO and AI modules. The slot and the I-address can be edited independently; the I-address is what the user program uses.
  5. Check the OB1 scan time and the process image partition in HW Config (object properties of the CPU → "Cycle/Clock Memory" tab). The OB1 PAE/PAA refresh is what makes the inputs read by FB102 reflect the real world.
  6. Verify the Modbus client configuration in WinCC Flexible: the "PLC address" on each tag must equal the bit / word offset the FB is set to use, not the slot address of the module. With the mapping table in section 2, the discrete input "0" is DB15.DBX0.0 — in WinCC it must be addressed as 0x0001 (bit 0 of word 0), and not as "I0.0".

5. Solution: Wire the DB to the Process Image

There are three equivalent ways to keep the IT4Industry Modbus/TCP data block in step with the real I/O. Pick one and document it in the OB1 cycle to keep the timing deterministic.

5.1 Option A — Direct I/O moves in OB1 (simplest)

Add the following STL to OB1 before the FB102 call (network 1) to refresh the DB from the periphery, and the following lines after the FB102 call (network 3) to push the DB back to the periphery. The I/O addresses come from HW Config; the DB offsets come from the FB102 configuration dialog.

// --- Network 1: refresh DB15 (discrete inputs) and DB13 (input registers) ---
L     IB 0
T     DB15.DBB 0          // first byte of discrete inputs
L     IB 1
T     DB15.DBB 1
L     IB 2
T     DB15.DBB 2
L     IB 3
T     DB15.DBB 3

L     PEW 288             // AI0 raw value, refreshed every OB1 cycle
T     DB13.DBW 120        // matches the word 0x120 declared in the example
L     PEW 290
T     DB13.DBW 122
L     PEW 292
T     DB13.DBW 124
L     PEW 294
T     DB13.DBW 126
L     PEW 296
T     DB13.DBW 128
L     PEW 298
T     DB13.DBW 130
L     PEW 300
T     DB13.DBW 132
L     PEW 302
T     DB13.DBW 134

// --- Network 2: FB102 (MODBUSPN) call ---
CALL  FB102, DB102
   ... // parameters as in the example

// --- Network 3: write DB14 (coils) back to the DO process image ---
L     DB14.DBD 2           // bits 32..63 = word 2 and word 3 of DB14
T     QD 4

This pattern guarantees that the FB102 sees the freshest input image and that the coil writes from the client land in the PAE on the very same OB1 cycle.

5.2 Option B — SFC14 / SFC15 (DPRD_DAT / DPWR_DAT) for consistent data

If the I/O is on a DP slave or PN device rather than the local rack, the process image is updated by SFC14 / SFC15 (consistent reading and writing of a DP / PROFINET slot). The pattern is:

// Read 4 bytes of DI from a DP slave at logical address 0
CALL SFC 14   // DPRD_DAT
   LADDR    := W#16#0
   RET_VAL  := MW 100
   RECORD   := P#DB15.DBX0.0 BYTE 4

// Write 4 bytes of DO to a DP slave at logical address 4
CALL SFC 15   // DPWR_DAT
   LADDR    := W#16#4
   RECORD   := P#DB14.DBX2.0 BYTE 4   // word 2..3 of DB14 = coils 32..63
   RET_VAL  := MW 102

SFC14 / SFC15 give a consistent snapshot regardless of OB1 scan jitter, which is the recommended pattern for S7-300 / S7-400 Modbus-to-DP bridging.

5.3 Option C — Reconfigure the FB102 data pointer

If the FB exposes a DATA_PTR or AREA_PTR input (some library versions do), point it directly at the process image. Example:

// FB102 input "AREA_PTR" := P#I 0.0 BYTE 4   // discrete inputs
// FB102 input "AREA_PTR_OUT" := P#Q 4.0 BYTE 4 // coils

This avoids the user code but ties the Modbus area 1:1 to the slot addresses of the I/O modules. The FB then does not need DB15/DB14 for those areas at all.

Safety warning: Mapping a Modbus coil 1:1 to a digital output on an S7-300 is a write-through operation. Any client on the network can energize the output at any time. If the output is driving a machine where a state change creates a hazard, gate the coil write through a permissive (e.g. Q4.0 := DB14.DBX32.0 AND DB20.DBX0.0) or move the safety-rated output to a fail-safe module on PROFIsafe.

6. Solution: Correct the WinCC Flexible Modbus Address Mapping

The WinCC Flexible side also has to be corrected. The HMI never sees the slot addresses directly; it only sees the bits/words in the Modbus data block. A coil that the integrator wants to be Q4.0 must be addressed as the coil number that points to DB14.DBX32.0. With the example project default (coils start at 0x0020 in the FB), Q4.0 is the first coil and Q7.7 is the last one. The corresponding WinCC tag table is therefore:

WinCC tag PLC area Address Data type Length
DO_bit_00 Coil 0x0001 ("0.0" in many WinCC drivers) BOOL 1 bit
DO_bit_31 Coil 0x0020 BOOL 1 bit
DI_bit_00 Discrete Input 1x0001 BOOL 1 bit
DI_bit_31 Discrete Input 1x0020 BOOL 1 bit
AI_word_00 Input Register 3x0121 (1-based, word 0x120 + 1) INT 1 word
AI_word_07 Input Register 3x0128 INT 1 word
HR_word_00 Holding Register 4x0001 INT 1 word

Because Modbus is 1-based for register references but 0-based for bit references, the conversion to the S7 word offset is: word_index_in_DB = (Modbus_address − 1) for registers, bit_index_in_DB = Modbus_address − 1 for coils and discrete inputs. Any mismatch here produces the "data in DB, no reaction on the wire" symptom.

7. Verification

  1. Coil write test: From the WinCC Flexible screen, toggle DO_bit_00. The LED on the 6ES7322-1BL00 module at the corresponding terminal must change state within one OB1 cycle. Save_Done_NDR latches TRUE; Count_Done increments.
  2. Coil read-back test: With the output forced to TRUE (e.g. bridging the output terminal to 24 V or commanding the output via STEP 7 variable table), the client must read TRUE. This confirms the write is leaving the PLC, not just the DB.
  3. Discrete input test: Apply 24 V to the first input terminal. DB15.DBX0.0 in the VAT must be TRUE; the HMI tag DI_bit_00 must read TRUE. If the value is always FALSE, the OB1 move IB0 → DB15.DBB0 is missing or the I-address in HW Config is wrong.
  4. Analog input test: Apply 10 V to the first AI channel. The word at PEW288 must show the corresponding 16-bit value (27648 at full scale for a ±10 V input). DB13.DBW120 must mirror it; the HMI tag AI_word_00 must read the same value.
  5. Error counter test: Disconnect the PC Ethernet cable. EstdConn must go FALSE; STATUS_CONN must switch to 16#7002. Reconnect within 60 s: EstdConn must return to TRUE; Count_Done resumes; Count_Error remains at its previous value (no spurious exceptions).
  6. Watchdog sanity: With a 100 ms periodic client poll, OB1 scan time must stay under 50 ms to avoid the typical Modbus timeout. Use OB1_PREV_CYCLE to log the worst-case scan time in a DB.

8. Status and Exception Code Reference

Use the following compact table as a decoding aid when reading the saved STATUS_MODBUS / STATUS_CONN values in a VAT. The 16#A090 / 16#A100 / 16#7002 codes observed in the project are all non-error, but the surrounding codes are commonly triggered by mis-mapping the FB data pointer.

Code Source Meaning Action
16#A090 MODBUSPN (FB102) STATUS_MODBUS No Modbus request processed in this cycle No action; this is the idle code
16#A100 TCON (status of the active connection) Connection established No action; indicates a working TCP link
W#16#7002 STATUS_CONN / TCON No connection present; waiting for client No action; normal when client is offline
W#16#7000 STATUS_CONN / TCON Connection being established Wait; if permanent, check IP / port / firewall
W#16#80C4 TCON Temporary communications error — partner not reachable Check cabling and IP / subnet of the PN interface
W#16#80A7 TCON Port already in use (TCP 502 bound twice) Check for a second Modbus server on the same interface
Modbus 1 (Illegal Function) Modbus exception Function code not implemented by the FB Check that the client uses FC1 / FC2 / FC3 / FC4 / FC5 / FC6 / FC15 / FC16 only
Modbus 2 (Illegal Data Address) Modbus exception Address outside the configured DB range Re-check the DATA_PTR and the "Offset" parameter of FB102
Modbus 3 (Illegal Data Value) Modbus exception Quantity / length field not supported Limit the client to the size configured in the FB
Modbus 4 (Slave Device Failure) Modbus exception Internal processing error in the FB Check RET_VAL and STATUS_CONN in the same cycle
Modbus 6 (Slave Device Busy) Modbus exception Previous request still being processed Increase the inter-frame delay on the client
TCP Port 502 blocked Firewall / Windows / SCADA Client can ping the CPU but the TCP handshake fails Open TCP/502 inbound on the host firewall; on the CPU, check the integrated firewall (security ≥ V4.4)

9. Common Side Issues and Field-Proven Caveats

  • Trial license on the IT4Industry FB. The trial runs for a limited time and may degrade to a single connection. Plan a license purchase or migrate to the Siemens Modbus/TCP library part of the Modbus/TCP PN CPU package.
  • Process image size. By default the S7-300 process image is 128 bytes for inputs and 128 bytes for outputs. Analog input modules often sit above 128. If the AI is outside the process image, OB1 will not refresh the I-address; the program must use L PEW 288 directly. This is exactly the case here (AI at 288…303).
  • WinCC Flexible and the S7 driver. WinCC Flexible can use a "SIMATIC S7" channel to the S7-300 or a "Modbus TCP" channel. They are mutually exclusive on the same tag. The integrator must pick the Modbus TCP channel to be consistent with the FB and the FB's Coil/Register offsets.
  • Endianness on the analog registers. Modbus TCP is big-endian on the wire; the IT4Industry library expects S7 INT/REAL layout (little-endian on the wire). The library handles the byte swap, but custom bit-packed coil data in FC15 (Write Multiple Coils) does not — keep coil quantities at multiples of 8 and at multiples of 16 words for register data.
  • Cyclic vs. on-change polling. Coils are best polled cyclically; analog input registers can be polled on change only. In WinCC Flexible this means "Acquire: cyclic continuous" for the coils and "Acquire: on change" for the AI tags, with a non-zero limit to avoid losing transitions.
  • Time-of-day, scan time and request rate. The IT4Industry trial FB processes one request per OB1 cycle. If the client bursts 30 requests/s with a 200 ms OB1, 5 of them will be dropped and counted as "no response". The Modbus client must be configured to limit the request rate to 1 per OB1 cycle, or the OB1 cycle time must be brought down.

10. Preventive Checklist for Future Projects

  1. Lock the Modbus ↔ S7 mapping in a single OB1 network pair (refresh-in / push-out) and place it in the project standards. Document the DB offset for every coil and register.
  2. Reserve a VAT with the four "Save_…" tags so that every support call can copy the values into a single email and start the diagnosis in five minutes.
  3. Configure the WinCC Flexible Modbus driver with the same "Base offset" as the FB. Most communication failures on S7-300 are an off-by-one in the register base.
  4. Use SFC14 / SFC15 for every DP/PN slave that holds more than 4 bytes of consistent I/O. Direct PAB/PAW access does not give a consistent image and can produce "bit flips" inside one 16-bit coil group.
  5. On the PC side, open TCP/502 inbound in Windows Firewall (or any third-party firewall) and document the exception in the commissioning report. A closed port 502 is the single most common cause of "client sees the CPU, FB counters stay flat".
  6. Schedule the OB1 cycle time budget in HW Config and set a cyclic interrupt (OB35) to poll the analog input module if the I/O is critical. The OB35 should be prioritized above OB1 for input refresh and below OB1 for output drive, otherwise a slow OB1 will gate the entire Modbus server.

Why does my Modbus TCP write to a coil update the DB but not the digital output on my S7-300?

The Modbus/TCP FB (e.g. IT4Industry FB102) only reads and writes a configured DB. The user program must copy the relevant bytes of that DB to the PAE / PAA in OB1 (for example L DB14.DBD 2 / T QD 4). Without that move, the output module never sees the coil change.

What does STATUS_MODBUS = 16#A090 mean on the MODBUSPN FB?

It is the "no Modbus request processed in this OB1 cycle" idle code, not a Modbus exception. Always read the Error and STATUS_MODBUS tags in the same cycle, or use the Save_Error / Save_STATUS_MODBUS latches provided by the example project.

My Modbus client pings the CPU but Count_Done stays flat. What is wrong?

Almost always TCP port 502 is blocked on the host firewall, on the network, or by the integrated CPU firewall on firmware V4.4 and newer. Open TCP/502 inbound on the Windows side and verify the connection with telnet <CPU_IP> 502. The CPU will not generate any error code for a SYN that never reaches the application.

How do I read an SM 331 AI module with I-address 288 from a Modbus input register?

Use L PEW 288 / T DB13.DBW 120 in OB1 before the FB call (or point the FB to P#PEW 288.0 WORD 8 if the FB supports an area pointer). The default S7-300 process image is 128 bytes, so an AI module at 288 will not be refreshed by the OB1 PAE update and the user must use the peripheral access directly.

What WinCC Flexible address should I use to read Q4.0 as a Modbus coil?

It depends on the coil base offset configured in FB102. With the IT4Industry example starting coils at word 2 (bit 32 in the DB), Q4.0 is Modbus coil address 0x0001, and Q4.7 is 0x0008. Re-check the FB configuration and the WinCC Flexible tag before assuming the data is in a different bit.

Can I use SFC14 / SFC15 instead of the OB1 moves?

Yes, and it is the recommended pattern when the I/O sits on a DP or PROFINET slave. SFC14 (DPRD_DAT) reads a consistent slot, SFC15 (DPWR_DAT) writes one. Point the RECORD parameter at the relevant slice of the Modbus DB so that the FB still sees a Modbus data area but the I/O is read/written consistently.

Back to blog