Problem Summary
A Modbus TCP client (PC-based SCADA or test application) writes successfully to a Siemens SIMATIC S7-1500 (CPU 1512F-1 PN) using Modbus function code 06 (Write Single Register, 0x06) but consistently receives a response payload of 0 when it issues function code 04 (Read Input Registers, 0x04) against the same address range. The S7-1500 is the Modbus server (the device that responds). The migration path is from a legacy ET 200S IM151-8F CPU with an open Modbus/TCP solution to the standard S7-1500 library instruction MB_SERVER running on firmware V2.1. The legacy project used two distinct data blocks (DB10 for writes, DB11 for reads), and the PC master application cannot be rewritten because its address map is fixed and the source is no longer maintainable.
The failure pattern is repeatable: any 0x04 request, regardless of starting address, returns a value of 0. The same request re-issued as 0x03 (Read Holding Registers) returns the correct data. The diagnosis is therefore not a network problem, not a CPU protection level problem, and not a licensing problem. It is a memory-map configuration issue inherent to MB_SERVER on the S7-1500 firmware line in use.
Modbus Register Model Refresher
The Modbus Application Protocol (Modbus Organization) defines four discrete address spaces. The leading digit of the user-visible address is implicit in the function code and is stripped before the request is presented to the server.
| Function Code(s) | Modbus Address Prefix | Data Type | Name |
|---|---|---|---|
| 01, 05, 15 | 0xxxxx | Boolean (bit) | Coils |
| 02 | 1xxxxx | Boolean (bit) | Discrete Inputs |
| 03, 06, 16, 23 | 4xxxxx | 16-bit word | Holding Registers |
| 04 | 3xxxxx | 16-bit word | Input Registers |
When a master issues a request against address 40001 with FC 06, the request is for Holding Register 1. When the same master issues a request against address 30001 with FC 04, the request is for Input Register 1. A strict Modbus server maps these to two different physical memories. A permissive server may map both function codes to the same memory. The behavior of the S7-1500 MB_SERVER falls between these two extremes depending on firmware version, as detailed below.
Reference: modbustools.com Modbus protocol reference; Beijer Electronics Modbus interface documentation (GL-997X series).
Root Cause: MB_SERVER Memory Map in S7-1500 FW 2.1
The MB_SERVER instruction shipped with TIA Portal V13 through V15 for S7-1500 CPUs (firmware V1.8 through V2.5) exposes a single data area parameter, MB_HOLD_REG, which serves as the source/destination for all data-oriented function codes except FC 04. On the legacy IM151-8F with the open Modbus/TCP solution, the user-defined code split read and write traffic into two DBs explicitly. The standard S7-1500 MB_SERVER does not.
On the CPU 1512F-1 PN with firmware V2.1, the FC 04 (Read Input Registers) handler in MB_SERVER reads from a memory region that is conceptually distinct from MB_HOLD_REG. In the older S7-1200 implementation, FC 04 reads from the process image input area (%IW). On S7-1500 with firmware V1.8 - V2.5, the implementation differs: the input register area is hard-wired inside the instruction and is not exposed as a configurable pointer. The data block the user assigned to MB_HOLD_REG is therefore inaccessible to FC 04 reads.
The result is the symptom reported: FC 06 writes to MB_HOLD_REG succeed (the data is visible in the DB), but FC 04 reads return 0 because the FC 04 source is a different memory region, not the user DB.
MB_SERVER instruction does not expose a separate input register DB parameter. There is no configuration switch in the V2.1 instruction that maps FC 04 reads to a user DB. The user cannot resolve this from the property page alone.Affected Firmware and Instruction Comparison
| TIA Portal Version | S7-1500 Firmware | Modbus Server Instruction | FC 04 Source | FC 03/06/16 Source |
|---|---|---|---|---|
| V13 - V15 | 1.8 - 2.5 | MB_SERVER (legacy) | Fixed input register area, not user-configurable | MB_HOLD_REG (user DB) |
| V15.1 | 2.6 | MODBUS_SERVER (new) | MB_INPUT_REG_PTR (optional, user DB) | MB_HOLDING_REG_PTR (optional, user DB) |
| V16 - V18 | 2.8 - 2.9 | MODBUS_SERVER | MB_INPUT_REG_PTR | MB_HOLDING_REG_PTR |
The MODBUS_SERVER instruction was introduced for S7-1500 in TIA Portal V15.1 with firmware V2.6. It provides three independent data area pointers: one for the input register space (FC 04), one for the holding register and coil space (FC 01/02/03/05/06/15/16/23), and a length parameter. This is the architectural change that resolves the FC 04 read issue without modifying the master.
Solution A: Upgrade to MODBUS_SERVER (Recommended)
Prerequisites
- TIA Portal V15.1 Update 3 or later (V16, V17, or V18 strongly recommended for current Siemens support)
- S7-1500 CPU 1512F-1 PN firmware V2.6 or later; V2.9 is the current shipping release for the 1512F-1 PN
- STEP 7 Safety Advanced is required only if the F-CPU safety program is in use; the standard MODBUS_SERVER instruction does not require Safety
- Read/write access to the project file (.ap15_1 or later) and the SD card or onboard flash of the CPU
- The master application unchanged
Step-by-Step Configuration
- Confirm firmware version. In TIA Portal, right-click the CPU in the device tree, choose Online → Diagnostics → Module Information, and read the firmware version under the General tab. If the version is below V2.6, schedule a firmware update through Siemens Industry Online Support before proceeding.
- Update CPU firmware if required. Right-click the CPU, choose Online → Diagnostics → Update Firmware. Select the target firmware file (.upd) and confirm. The CPU performs an automatic restart after the update.
-
Remove the existing MB_SERVER call. In the program blocks folder, open the cyclic OB (typically OB1) and delete the call to
MB_SERVER. The instance DB can be deleted or left in place; it will be unreferenced. -
Insert MODBUS_SERVER. In the project tree, navigate to Instructions → Communication → MODBUS TCP. Drag the
MODBUS_SERVERinstruction into OB1. The instruction is contained in the global library; an SCL or LAD/FBD view is acceptable. -
Create the connection DB.
MODBUS_SERVERrequires a connection description of typeTCON_IP_V4. Double-click theCONNECTinput to open the connection wizard. Set the interface to the PROFINET port of the CPU, leave the partner unspecified (server-side passive open), and use port 502. -
Set the connection ID. The
MB_IDparameter must be unique across all Modbus instructions in the CPU (both client and server). Any value in the range 1 - 247 is valid. Document the value in the project. -
Configure the data area pointers. Two pointer inputs control memory mapping:
-
MB_HOLDING_REG_PTR→ pointer to a DB for FC 01/02/03/05/06/15/16/23 traffic. The first 4 bytes of this DB also serve the bit-oriented (coil) function codes; words above address 0 serve the word-oriented function codes. -
MB_INPUT_REG_PTR→ pointer to a DB for FC 04 traffic. The DB must contain only word-sized data; bit areas are not applicable to FC 04.
MB_HOLDING_REG_PTRto DB10 andMB_INPUT_REG_PTRto DB11. -
-
Set the data length.
MB_DATA_LENspecifies the byte length of the data area. The instruction computes the maximum register count from the DB lengths. Recommended initial value: 1000 bytes for each area, sufficient for most installations. -
Wire the status outputs. Connect
NDR(new data received),DR(data read),ERROR, andSTATUSto tags or DB fields for online monitoring.STATUSreturns a 16-bit code; non-zero values indicate Modbus exceptions (1 = illegal function, 2 = illegal data address, 3 = illegal data value, 4 = slave device failure) or Siemens-specific protocol errors. -
Compile and download. Compile the program blocks, then download to the CPU. Verify in the watch table that
MODBUS_SERVERis being called every cycle and thatERRORremains 0.
Sample SCL Implementation
// In OB1 or a cyclic OB
"modbus_server_db"(
MODE := 1, // 1 = TCP, 2 = UDP
MB_ID := 1, // unique connection ID
CONNECT := "modbus_tcp_connection", // TCON_IP_V4 DB
IP_PORT := 502, // IANA Modbus port
MB_HOLDING_REG_PTR := "DB10", // holding + coils
MB_INPUT_REG_PTR := "DB11", // input registers (FC 04)
MB_DATA_LEN := 200, // bytes per area
NDR => "tag_NDR",
DR => "tag_DR",
ERROR => "tag_ERROR",
STATUS => "tag_STATUS"
);
Sample Ladder Implementation
DB_VAR_INST.MODBUS_SERVER
|--MODE--|-----------( ) |
| 1 | |
|MB_ID---| |
| 1 | |
|CONN----| |
|"conn" | STATUS->tag_STATUS ERROR->tag_ERROR
|PORT----| |
| 502 | |
|HR_PTR--| |
|"DB10" | |
|IR_PTR--| |
|"DB11" | |
|LEN-----| |
| 200 | |
The MODBUS_SERVER instruction must be called in a cyclic OB (OB1 or any OB with a defined cycle time). The Siemens instruction background is non-blocking; the call returns immediately and the actual protocol processing occurs in the CPU firmware task.
Solution B: Modify the Master to Use FC 03
If a firmware upgrade is not feasible (the CPU is in long-term operation, the firmware update is blocked by the plant's change management, or the 1512F-1 PN is below V2.6 and cannot be updated), the next-cleanest workaround is to modify the PC master application to substitute FC 03 (Read Holding Registers) for FC 04 (Read Input Registers). Both function codes then access the same MB_HOLD_REG data area in the legacy MB_SERVER instruction.
Operationally:
- FC 06 → 40001 → writes to
MB_HOLD_REG[0]in the user DB (already working). - FC 03 → 40001 → reads from
MB_HOLD_REG[0]in the user DB (now works).
From a strict Modbus conformance standpoint, this is a deviation: the master is reading "input" data through the "holding" function code. Most industrial systems tolerate this, but the change must be documented in the project record and reviewed with the end customer. If the master application is a closed-binary vendor product with no support contract, this solution is not viable.
MB_SERVER instruction on firmware V2.1, FC 03 reads are served from the MB_HOLD_REG data area regardless of the leading digit in the address, so this workaround is safe for the S7-1500 platform specifically.Solution C: Custom Modbus TCP Server via Open User Communication
If neither firmware upgrade nor master modification is possible, a custom Modbus TCP server can be implemented on the S7-1500 using the Open User Communication (OUC) instruction set:
-
TCONfor connection establishment on port 502 -
TRCVfor receiving the Modbus ADU (MBAP header + PDU) - Custom logic to parse the function code, route FC 06 writes to a DB, and route FC 04 reads from a different DB
-
TSENDfor transmitting the response PDU -
TDISCONfor graceful disconnect on shutdown
The implementation must handle the MBAP header (transaction ID, protocol ID 0, length, unit ID), the PDU (function code, starting address, quantity), and the exception responses (codes 1 - 4). Siemens provides reference code for a custom Modbus server in the Siemens Industry Online Support knowledge base; review the code carefully for re-entrancy and connection count limits (S7-1500 supports up to 64 simultaneous OUC connections).
This approach is the most complex and is generally not recommended unless all other options are blocked. Test protocol conformance with a third-party Modbus conformance tester before deployment.
Memory Layout Diagram (MODBUS_SERVER Solution)
FC Routing Flowchart (MB_SERVER Legacy vs MODBUS_SERVER)
Verification Procedure
Verification with modpoll
# Read holding registers (FC 03) - control test
modpoll -m tcp -a 1 -r 1 -c 10 -p 502 192.168.0.10
# Read input registers (FC 04) - target test
modpoll -m tcp -t 4 -a 1 -r 1 -c 10 -p 502 192.168.0.10
# Write single register (FC 06) - control test
modpoll -m tcp -a 1 -r 1 -p 502 192.168.0.10 12345
Flags used:
-
-m tcp→ Modbus TCP transport -
-t 4→ register type = input registers (forces FC 04) -
-a 1→ unit ID 1 (Modbus server address) -
-r 1→ start at register 1 (strips the leading 3 or 4) -
-c 10→ quantity of 10 registers -
-p 502→ TCP port 502
Verification with Wireshark
- Capture on the Ethernet port connecting the S7-1500 to the master PC.
- Apply display filter:
mbtcp || modbus - Trigger an FC 04 read from the master.
- Inspect the response frame. The function code byte should be
0x04(read) or0x84(read exception, high bit set), the exception code should be0x00on success, and the data payload should contain non-zero values matching the DB11 contents.
Verification with TIA Portal Watch Table
- Open a watch table and add
DB11.DBW0throughDB11.DBWn(the input register data area). - Force specific values into the tags.
- Trigger an FC 04 read from the master and confirm the response matches the forced values.
- Check
MODBUS_SERVER.STATUSfor non-zero error codes.
Detailed MODBUS_SERVER Parameter Reference
| Parameter | Direction | Type | Description |
|---|---|---|---|
| MODE | Input | INT | 1 = TCP (default), 2 = UDP |
| MB_ID | Input | INT | Connection identifier, 1 - 247, unique per CPU |
| CONNECT | InOut | TCON_IP_V4 | Connection description (port, IP, partner) |
| IP_PORT | Input | UINT | Local TCP port, default 502 |
| MB_HOLDING_REG_PTR | InOut | VARIANT | Pointer to DB for FC 01/02/03/05/06/15/16/23 |
| MB_INPUT_REG_PTR | InOut | VARIANT | Pointer to DB for FC 04 (optional, requires FW 2.6+) |
| MB_DATA_LEN | Input | UINT | Data area length in bytes |
| NDR | Output | BOOL | New data received (rising edge on completed read/write) |
| DR | Output | BOOL | Data read (rising edge on FC 04 read completion) |
| ERROR | Output | BOOL | TRUE on protocol or parameter error |
| STATUS | Output | WORD | 16-bit error/status code; 0 on success |
STATUS / Error Code Reference
| STATUS (hex) | Meaning | Resolution |
|---|---|---|
| 0x0000 | No error | No action required |
| 0x80B1 | Parameter assignment error | Verify pointer data types; only DB pointers are accepted; check DB length |
| 0x80C8 | TCP/UDP port in use | Change IP_PORT or free the conflicting port |
| 0x8381 | Connection ID conflict | Change MB_ID to a value not used by another Modbus instruction |
| 0x80A1 | Connection establishment error | Check network configuration, partner IP, subnet mask, gateway |
| 0x80A7 | Connection terminated by partner | Inspect partner-side log; check for partner-side timeouts |
| 0x80B5 | Pointer invalid | Re-assign MB_HOLDING_REG_PTR / MB_INPUT_REG_PTR; ensure DB exists in project |
| 0x0001 | Modbus exception 01: illegal function | Master sent unsupported FC; verify against enabled FC set |
| 0x0002 | Modbus exception 02: illegal data address | Master address outside the configured data area; increase DB length |
| 0x0003 | Modbus exception 03: illegal data value | Quantity or value out of range; check FC 15/16 quantity limits |
| 0x0004 | Modbus exception 04: slave device failure | Internal CPU error; check diagnostic buffer |
The STATUS encoding is firmware-version-specific. The complete list is integrated into the TIA Portal F1 help for MODBUS_SERVER; refer to the help for the exact installed version.
Troubleshooting Matrix
| Symptom | Possible Cause | Resolution |
|---|---|---|
| FC 04 always returns 0 | MB_SERVER FW ≤ 2.5 reads FC 04 from internal input area, not user DB | Upgrade to MODBUS_SERVER on FW 2.6+ |
| FC 06 writes succeed; FC 04 returns 0 | As above | As above |
| MODBUS_SERVER STATUS = 16#8381 | Connection ID conflict | Change MB_ID to a value not used by any other Modbus instruction |
| MODBUS_SERVER STATUS = 16#80C8 | TCP port in use | Change IP_PORT or close the conflicting service on the CPU |
| MODBUS_SERVER STATUS = 16#80B1 | Parameter assignment error | Verify pointer data types; only DB pointers are accepted |
| Master times out on FC 04 | Firewall blocking port 502 | Open port 502 in the path between master and CPU |
| FC 04 returns Modbus exception 02 | Master address outside configured range | Increase the length of the DB at MB_INPUT_REG_PTR |
| All FCs return Modbus exception 01 | MODBUS_SERVER is not being called | Verify the cyclic OB is calling the instruction; check OB1 priority |
| FC 04 returns correct value once, then 0 | Another part of the user program overwrites the input DB | Audit program for writes to DB11; add read-only enforcement if needed |
| MODBUS_SERVER not in instruction palette | TIA Portal version < V15.1 | Upgrade TIA Portal to V15.1 or later |
| FC 04 returns correct value but slave ID mismatch | Unit ID in MBAP header does not match MB_ID | Set MB_ID = 1 (or the unit ID expected by the master); verify against master config |
| Write succeeds but read returns wrong register | Endianness mismatch between master and DB | Check word order; S7 is big-endian (Motorola) on the wire, PC often little-endian |
| FC 04 returns data from DB10 instead of DB11 | MB_INPUT_REG_PTR is not assigned | Assign MB_INPUT_REG_PTR to the correct DB; recompile |
Endianness and Word Order
Modbus protocol is big-endian (most significant byte first) on the wire, and so is the S7-1500 DB representation. Some PC-based master libraries reverse the byte order under the assumption that x86 is little-endian. When a value is written via FC 06 from the master and then read back via FC 04, the values should match exactly. If they do not, the master is performing byte swapping. Configure the master to use big-endian (network byte order) and re-test. The same DB representation on both ends eliminates the problem.
Network Configuration Checklist
- CPU PROFINET port assigned a static IP address (DHCP not recommended for Modbus server)
- Subnet mask matches the master PC subnet
- Default gateway set if the master is on a different subnet
- Port 502/TCP open in any firewall between the master and the CPU
- No other device on the network using port 502 (use a port scanner like nmap:
nmap -p 502 192.168.0.0/24) - PROFINET device name assigned and verified (Online → Diagnostics → Module Information)
- CPU in RUN, not STOP;
MODBUS_SERVER.ERROR= 0;STATUS= 0
Legacy IM151-8F to S7-1500 Migration Notes
The IM151-8F (ET 200S high-feature CPU) used the open Modbus/TCP solution published by Siemens for the ET 200S, which gave the user full control over the data area assignment and allowed the read and write traffic to be split into two DBs. The S7-1500 standard library does not include a drop-in replacement for this two-DB configuration in firmware V2.1; the architecture is asymmetric. The MODBUS_SERVER instruction in firmware V2.6+ is the closest functional equivalent and supports the same two-DB layout.
Other migration considerations specific to the IM151-8F → 1512F-1 PN transition:
- The ET 200S used the IM151-8F as a head module with up to 12 I/O modules; the 1512F-1 PN integrates the PROFINET interface and removes the ET 200S station requirement.
- The ET 200S safety-related I/O modules map directly to the S7-1500 F-I/O catalog.
- The IM151-8F used S7-300 instruction syntax in many cases; the S7-1500 uses the optimized TIA Portal instruction set. Open the legacy project in TIA Portal and accept the auto-migration of FBD/LAD blocks.
- The legacy DB10/DB11 layout can be preserved if the data types and offsets are re-created in the new project. The new DBs do not need to match the legacy DB numbers.
Safety Considerations for F-CPU Migration
The CPU 1512F-1 PN is a fail-safe PLC. The Modbus server functionality is part of the standard (non-safety) program. The standard program may read values from the safety program only through the standard-to-safety boundary (F-shared DB) and only with the appropriate access controls. The Modbus master cannot directly read or write safety tags; this is enforced by the F-CPU runtime. Confirm that the data being read by FC 04 is not safety-tag data that requires F-CPU write protection.
Migration Checklist
- Confirm S7-1500 CPU 1512F-1 PN current firmware version
- If FW < 2.6, schedule firmware update with Siemens support and verify backup of the project
- Decide between Solution A (recommended), B, or C based on master modify feasibility
- If Solution A: install TIA Portal V15.1+ on the engineering workstation
- Replace MB_SERVER with MODBUS_SERVER in the program
- Configure MB_INPUT_REG_PTR to the read DB; MB_HOLDING_REG_PTR to the write DB
- Compile, download, verify in the watch table
- Test FC 04 read with modpoll / QModMaster / Wireshark
- Document the deviation if Solution B is used
- Update the master application if Solution B is used
- Back up the original IM151-8F project archive before decommissioning
Terminology Clarification
The original report states: "The PLC is Server and the computer software acts as slave." This is a common but incorrect phrasing. In Modbus terminology, the device that responds to requests is the Server (historically called Slave), and the device that initiates requests is the Client (historically called Master). The S7-1500 is therefore the Modbus Server, and the PC application is the Modbus Client. The two terms are interchangeable per the Modbus specification, but the modern Modbus Organization terminology is "Client" and "Server."
How does the Modbus 3x vs 4x distinction affect S7-1500 MB_SERVER behavior?
In strict Modbus implementations, Input Registers (3x, FC 04) and Holding Registers (4x, FC 03/06/16) are separate memory areas. The MB_SERVER instruction on S7-1500 firmware V2.1 does not differentiate between them in the user-visible configuration: FC 04 reads are served from an internal area, while FC 03/06/16 reads and writes are served from the MB_HOLD_REG data block. The result is that FC 04 cannot return data from a user DB on the legacy instruction, regardless of the address requested.
What firmware version is required for the MODBUS_SERVER instruction on S7-1500?
The MODBUS_SERVER instruction was introduced in TIA Portal V15.1 and requires S7-1500 CPU firmware V2.6 or later. CPUs older than V2.6 can use the legacy MB_SERVER instruction but are limited to the single MB_HOLD_REG data area and cannot directly serve FC 04 from a user DB. The current shipping release for the 1512F-1 PN is firmware V2.9.
Can I keep the existing MB_SERVER instruction and just change the master to use FC 03?
Yes, this is a viable workaround when firmware upgrade is not feasible. Modify the PC master to issue FC 03 (Read Holding Registers) instead of FC 04 (Read Input Registers). Both function codes then access the MB_HOLD_REG data area. This is a documented deviation from the Modbus standard and should be noted in the project record. The change requires access to the master source code and recompilation.
What does the STATUS output of MODBUS_SERVER return on error?
STATUS is a 16-bit word combining Modbus exception codes (1 = illegal function, 2 = illegal data address, 3 = illegal data value, 4 = slave device failure) and Siemens-specific protocol errors (0x80B1 parameter error, 0x80C8 port in use, 0x8381 connection ID conflict, 0x80A1 connection error, 0x80A7 partner disconnect). A value of 0 indicates success. The complete list is available in the TIA Portal F1 help for the instruction.
How do I test FC 04 reads without modifying the master application?
Use a Modbus diagnostic tool such as modpoll, QModMaster, or simply Wireshark with a Modbus dissector. With modpoll, the command modpoll -m tcp -t 4 -a 1 -r 1 -c 10 -p 502 <cpu_ip> issues a Read Input Registers request. The response should match the values stored in the data block assigned to MB_INPUT_REG_PTR. If the response is all zeros, the FC 04 source is not the user DB and the upgrade to MODBUS_SERVER is required.
Is port 502 the only option for the Modbus server?
No. The IP_PORT parameter accepts any TCP port from 1 to 65535. Port 502 is the IANA-registered default for Modbus TCP and should be used whenever possible. If port 502 is blocked by a firewall or occupied by another service, use an alternative port above 1024 and update the master configuration to match. The MODBUS_SERVER instruction does not enforce port 502 specifically.
What happens if the master requests an address outside the configured data area?
MODBUS_SERVER returns a Modbus exception response with code 0x02 (Illegal Data Address). The data area size is determined by the length of the data block assigned to MB_HOLDING_REG_PTR and MB_INPUT_REG_PTR. To support a wider address range, increase the length of the relevant DB or adjust the master request addresses to remain within the configured range.