Resolving GET_DIAG OperatingState Returns 0 on S7-1500 i-Device

David Krause17 min read
SiemensTIA PortalTroubleshooting
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 GET_DIAG OperatingState Returns 0 on S7-1500 PROFINET i-Device

The SIMATIC GET_DIAG instruction in TIA Portal is one of the most commonly reached-for tools when an automation engineer needs to surface device health from within an S7-1200 or S7-1500 program. The instruction reads diagnostic data from a hardware component selected by the LADDR parameter. It supports PROFINET and PROFIBUS DP and is documented for both controller families. When deployed against a PROFINET i-device, however, the OperatingState output reliably returns 0, regardless of the actual run state of the partner CPU. This article explains why that happens, when GET_DIAG will produce a useful operating state, and what to use instead when the remote operating state of a peer CPU is required.

Reference documentation: GET_DIAG: Read diagnostic information (S7-1200, S7-1500) — Siemens Industry Online Support, GET_DIAG: Read diagnostic information — STEP 7 Basic/Professional (TIA Portal) manual entry, and the online TIA Portal cloud reference for GET_DIAG.

1. Problem Description

Consider a typical machine-builder architecture: two S7-1500 CPUs connected over PROFINET. One CPU is configured as the IO Controller of the PROFINET subnet; the second CPU is configured as an i-device (intelligent IO device) and exchanges process and diagnostic data with the controller through a configured PROFINET slot. The project was built in TIA Portal V13 SP1 Update 5. An GET_DIAG block is instantiated in the controller to read the diagnostic record of the i-device CPU. After wiring LADDR to the i-device's hardware identifier, the block is called cyclically. The instruction's RET_VAL returns 0, meaning no execution error. The mode and channel diagnostics fill in as expected. The OperatingState output, however, returns 0 even when the i-device is in RUN and is exchanging data normally. Calling the same block on the local CPU using LADDR := Local~exec (or the equivalent constant from the system constants table) also returns 0 for OperatingState. The block appears to work, but the operating-state output is silently inert.

The Siemens manual states that OperatingState is a UINT that returns 7 for RUN and 4 for STOP. Online examples and application posts routinely show 0. The mismatch between the manual and the runtime behaviour is the core of the issue and the reason this question is raised in technical forums.

2. Root Cause Analysis

Siemens technical support has clarified the behaviour directly: GET_DIAG is only intended to return meaningful OperatingState information for the local CPU running the block. To obtain the local CPU's operating state, the LADDR input must point at the local execution system: in TIA Portal this is exposed as Local~exec in the system constants or in the constants tab of the FC/FB that calls the block. Other diagnostic outputs from GET_DIAG (such as IO_State, MaintenanceState, or Channel) do populate correctly when LADDR points at a remote PROFINET device, because those fields reflect the diagnostics of the slot or submodule and not the CPU operating state.

The architectural reason is the PROFINET device model. To the IO Controller, the i-device is a remote IO station with a configured slot structure. PROFINET IO devices do not have a CPU operating state in the same sense as a PLC. From the controller's perspective the i-device is either present, faulty, channel-faulted, or absent. The controller has no PROFINET-defined mechanism that asks the partner PLC "are you in RUN, STOP, or STARTUP?" through the standard GET_DIAG call. Some devices populate an OperatingState value through vendor-specific extensions; many do not. S7-1500 i-devices fall into the latter group in the default diagnostic profile.

This is the reason that all GET_DIAG examples published with V13 SP1 show OperatingState = 0. The output is reserved, defined, and zero by default; the field is not absent, but its value carries no semantic meaning for non-CPU hardware objects, and the S7-1500 i-device does not project an operating state into the slot diagnostics that the controller can read.

Engineer field-note: If OperatingState returns 0 on a remote PROFINET device, this is not a bug in TIA Portal V13 SP1. It is the documented behaviour. The block itself is functioning correctly; the information simply is not available through that path.

3. GET_DIAG Instruction Reference

The GET_DIAG instruction is in the Extended instructions > Diagnostics folder in TIA Portal. It can be called in SCL, LAD, or FBD. The instruction signature is the same across S7-1200 and S7-1500.

Parameter Declaration Data type Description
MODE Input UINT Selects the diagnostic record to read. 0 = own module/service overview, 1 = module status, 2 = channel diagnostics, 3 = (vendor-specific) extended diagnostics. Only 0, 1, and 2 are guaranteed on all PROFINET devices.
LADDR Input HW_ANY (UINT) Hardware identifier of the diagnostics source. For local operating state use Local~exec. For a remote device, use the HW identifier of the device head, slot, or submodule from the system constants.
RET_VAL Output INT Execution status. 0 = success; non-zero = standard IEC error code (see 109747174).
DIAG InOut VARIANT pointing to Diag_* UDT Structure filled with the requested diagnostic record. The UDT type depends on MODE and is selected when the instruction is inserted.
DETAIL Output VARIANT Optional pointer to a DETAIL structure for channel-level data when MODE = 2.
SET Output VARIANT Optional pointer to a DETAIL structure for module-level data when MODE = 1.
OperatingState Output UINT Operating state of the CPU. 4 = STOP, 7 = RUN, 3 = STARTUP. Only meaningful when LADDR = Local~exec.
IO_State Output WORD Bit field for the IO state of the addressed device.

Notes:

  • Only MODE = 0 returns OperatingState. Other modes return diagnostic data but not the operating state.
  • The OperatingState output is part of the Diag UDT when MODE = 0. The compiler inserts a separate output pin to make it accessible without dereferencing the UDT.
  • Calling GET_DIAG against an i-device with MODE = 1 or MODE = 2 returns valid data because those modes read the slot/submodule diagnostic, not the CPU state.

4. OperatingState Encoding

Value (UINT) Meaning Notes
0 Undefined / not available Returned for any hardware object that is not the local CPU, or when the device does not project an operating state.
1 Reserved Reserved by Siemens; do not interpret.
2 Reserved Reserved by Siemens; do not interpret.
3 STARTUP CPU is in STARTUP (OB100 / OB101 / OB102).
4 STOP CPU is in STOP with no restart pending.
5 Reserved Reserved by Siemens; do not interpret.
6 Reserved Reserved by Siemens; do not interpret.
7 RUN CPU is in cyclic RUN.
8 Reserved Reserved by Siemens; do not interpret.
9 HOLD CPU is in test/breakpoint HOLD (programming device triggered).
10 STOP with restart request STOP with pending restart; typically after a fatal diagnostic.
Reserved values: The list above includes the values documented publicly. Do not branch application logic on values not explicitly listed in the Siemens manual — newer firmware revisions may introduce additional states.

5. PROFINET i-Device Architecture and What the Controller Can See

An i-device is a PROFINET IO device that also functions as an IO controller on a subordinate PROFINET network. From the upper controller's point of view, the i-device is a single IO station with a defined GSDML-based slot structure. The slots are configured on the i-device side under Properties > PROFINET interface > Operating mode > IO device. The controller sees only:

  • Device-level presence and AR (Application Relationship) state.
  • Per-slot submodule state (present, wrong, faulty, substituted).
  • Channel-level diagnostics raised by individual submodules.
  • Port statistics (link state, discarded frames, CRC errors) through RDREC against port statistics record 0x802A / 0x802B.

The CPU operating state of the i-device is a property of its PLC runtime, not of its PROFINET slot. The controller cannot retrieve this through the standard PROFINET diagnostic mechanism because PROFINET does not define such a record. Some non-Siemens devices implement a vendor-specific diagnostic record that includes a CPU state; S7-1500 i-devices do not project one in the default diagnostic profile that ships with TIA Portal V13 SP1 through V18.

5.1 What the controller can read about the i-device

Information Available through GET_DIAG? Available through RDREC? Notes
Device presence / AR state Yes — IO_State Yes — record 0xF00C (PDPortDataReal) or AR state Use as the "is the device alive" check.
Module/submodule presence Yes — MODE = 1 Yes — record 0xAFF0 and similar Per-slot presence bits.
Channel diagnostics Yes — MODE = 2 Yes — record 0x8000–0x80FF range Channel error number, channel properties, channel error type.
Port statistics No Yes — record 0x802A, 0x802B Link state, error counters.
CPU operating state Only on local CPU Not on i-device by default Use the alternatives in section 7.
Firmware version Not directly Yes — record 0xF841 (IM0) Use RDREC against the device head.
Order number / serial Not directly Yes — record 0xF840 (IM0) Standard PROFINET identification.

6. Solution: Read OperatingState from the Local CPU

When the engineer wants the operating state of the same CPU that is running the block, the LADDR must point at the local execution system. There are two ways to wire this in TIA Portal:

  1. Use the Local~exec tag from the system constants. Open the block that calls GET_DIAG, switch to the constants tab, and select System constants > Local > Local~exec. Drag it to the LADDR input. Local~exec resolves to the hardware identifier 0.
  2. Use a symbolic tag whose initial value is Local~exec from the system constants table, or hard-code the constant 0 at the LADDR input. Both compile to the same call.

An example SCL implementation in the OB1 cycle:

// Cyclic OB: read local CPU operating state
#iRetVal   := GET_DIAG(
    MODE           := 0,        // own module / service overview
    LADDR          := "Local~exec",
    OperatingState => #iOperState,
    IO_State       => #wIoState,
    DIAG           => #stDiag);

IF #iRetVal = 0 THEN
    CASE #iOperState OF
        3:  // STARTUP
            #sStateText := 'STARTUP';
        4:  // STOP
            #sStateText := 'STOP';
        7:  // RUN
            #sStateText := 'RUN';
        9:  // HOLD
            #sStateText := 'HOLD';
        10: // STOP with restart
            #sStateText := 'STOP_RESTART';
        ELSE
            #sStateText := 'UNKNOWN';
    END_CASE;
END_IF;

The call executes on the local CPU and reports the local operating state correctly. The same call in the i-device CPU reports the i-device CPU's own state. The block must be instantiated once per CPU on which operating-state visibility is required.

6.1 Why not just use LADDR = 0?

Using the literal 0 is equivalent to Local~exec on S7-1500. On S7-1200 the behaviour is the same. However, the literal 0 is fragile: it depends on the editor being able to validate the constant as a valid local-system reference. Using Local~exec from the system constants table is preferable because TIA Portal will warn if the block is ported to a project where the constant does not exist.

7. Reading the Operating State of a Remote CPU

When the requirement is to read the operating state of a peer CPU (i-device, separate PLC, or any third-party PROFINET device), the following mechanisms are available. Each has trade-offs; pick by network topology, latency budget, and whether the partner device is also a Siemens PLC.

7.1 Cyclic status word on the i-device side

The most robust method for an S7-1500 i-device is to add a status word to the i-device transfer area that the i-device populates from its own GET_DIAG call. The controller reads the status word cyclically through the configured PROFINET slot. This requires no extra wiring, only the assignment of an output word in the i-device transfer area configuration in TIA Portal. Recommended status payload:

Offset Field Data type Description
0.0 OperState UINT Local CPU operating state, from GET_DIAG with LADDR = Local~exec.
2.0 SlotHealth BOOL AND of all submodule "OK" bits from RDREC against the i-device head.
2.1 AnyDiag BOOL OR of all channel diagnostics flags.
4.0 LastUpdateTick DWORD Counter incremented every time the i-device publishes the status; the controller can use it as a watchdog.

7.2 S7 communication with PUT/GET

For Siemens-to-Siemens connections where an S7 connection is already configured (Ethernet, S7 routing), a single-byte status flag can be sent cyclically with PUT or GET blocks. This requires the i-device to allow S7 server connections on its PROFINET interface. Suitable for small numbers of tags but heavier than cyclic PROFINET IO for continuous status.

7.3 RDREC against vendor-specific records

Some Siemens CPUs expose a vendor-specific record that contains the operating state when read against the device head. As of TIA Portal V16/V17/V18 firmware versions, this is not standardised across S7-1200/S7-1500. Treat any specific record number as firmware-version dependent and verify it in the GSDML of the specific i-device CPU. Do not depend on undocumented records in production code.

7.4 Open User Communication with TSEND/TRCV

A TCP or UDP socket on the i-device can be used to publish the operating state as an integer or text. Latency is in the millisecond range. Use when the controller already runs TCP/UDP services to the i-device and the engineering team wants to avoid touching the configured PROFINET transfer area.

7.5 OPC UA server on the i-device

S7-1500 CPUs from firmware V2.0 upward support OPC UA server. The i-device can publish its operating state as an OPC UA tag; the controller (or any OPC UA client) can subscribe to it. Useful when the consuming system is an HMI or SCADA package that already supports OPC UA.

8. Implementation Example: i-Device Reporting Its Own Operating State

The recommended pattern in a two-CPU setup is to place one GET_DIAG call on each side. The controller's call uses LADDR = Local~exec for its own operating state. The i-device's call uses LADDR = Local~exec as well, writes the result into the i-device transfer area, and the controller reads it cyclically through the PROFINET slot.

i-device program (OB1):

// iDevice_OB1: publish local operating state into transfer area
#iRetVal   := GET_DIAG(
    MODE           := 0,
    LADDR          := "Local~exec",
    OperatingState => #iOperState);

// Write to transfer area output area, byte offset 0
QW0 := INT_TO_WORD(#iOperState);

// Watchdog counter for the controller side
IF "Clock_1Hz" THEN
    #dwTick := #dwTick + 1;
END_IF;
QD4 := #dwTick;

Controller program (OB1):

// Controller_OB1: read i-device operating state from input transfer area
#iRemoteOperState := WORD_TO_INT(IW0);
#dwRemoteTick     := ID4;

IF (#dwRemoteTick = #dwLastTick) THEN
    // i-device has not updated for at least one cycle
    #bRemoteStale := TRUE;
ELSE
    #bRemoteStale := FALSE;
    #dwLastTick := #dwRemoteTick;
END_IF;

// Local operating state for diagnostics only
#iLocalRetVal   := GET_DIAG(
    MODE           := 0,
    LADDR          := "Local~exec",
    OperatingState => #iLocalOperState);

This pattern is firmware-version independent, does not depend on undocumented records, and works on S7-1200 and S7-1500 alike.

9. Verification

After implementing the change, verify by running through these steps in TIA Portal with the project online:

  1. Compile and download the project to both CPUs.
  2. Open the GET_DIAG block instance in the controller and confirm in the monitor view that LADDR resolves to Local~exec (HW identifier 0).
  3. Force the controller to RUN. OperatingState should read 7 within one OB1 cycle.
  4. Switch the controller to STOP via the programming device. OperatingState should read 4 within the next cycle.
  5. Re-enter RUN and confirm the value returns to 7.
  6. If the i-device operating-state transfer area is configured, force the i-device to STOP and verify the controller's iRemoteOperState reflects 4 within the PROFINET update cycle (typically 1 ms with RT, 250 µs with IRT).
  7. Disconnect the PROFINET cable to the i-device and verify IO_State shows 0x0000 (or the documented bad-state code) while OperatingState for the local CPU remains valid. This confirms the two values are decoupled.

10. Firmware and Software Compatibility

Component Versions tested / documented Notes
STEP 7 (TIA Portal) V13 SP1 Update 5, V14, V15, V15.1, V16, V17, V18 GET_DIAG signature unchanged across versions. Localexec constant available from V13 onward.
S7-1500 CPU firmware V1.5 through V2.9 All supported versions project the same diagnostic record set.
S7-1200 CPU firmware V4.0 through V4.6 GET_DIAG supported; behaviour identical to S7-1500 for local CPU.
PROFINET conformance PN Spec V2.3 MU5+ i-device diagnostic profile matches.

The TIA Portal V13 SP1 Update 5 project in the original case report is supported by Siemens; the issue raised is not a TIA Portal version bug. Newer TIA Portal releases introduce additional diagnostic blocks (GET_DIAG_EX, GetStationInfo) but the localexec operatingstate path remains the canonical method.

11. Troubleshooting Matrix

Symptom Likely cause Fix
OperatingState = 0 always LADDR not pointing at the local CPU Use Local~exec or HW identifier 0.
RET_VAL = 8090 Module with the given LADDR not configured / not present Verify the device is online; check the system constants table.
RET_VAL = 80B0 Hardware fault at the addressed slot Inspect IO_State and port statistics; check the physical PROFINET segment.
RET_VAL = 80C0 Cannot read the diagnostic record (busy or in startup) Retry after the AR is established; do not call during AR startup.
OperatingState = 0 on local CPU CPU is in a state that does not project an operating state (firmware update, factory reset) Check LEDs; check CV status via LED instruction.
OperatingState returns valid value but partner device still appears faulty Block is correctly reporting local state; partner diagnostics are independent Use IO_State or RDREC for partner diagnostics.

12. Best Practices

  • Always document whether each GET_DIAG call is intended to read the local CPU state or a remote device state. Mix-ups are the most common source of confusion when this block is used.
  • Use Local~exec from the system constants table rather than the literal 0. This makes the intent clear and survives a copy/paste into another project.
  • Treat OperatingState as a CPU-level indicator only. For PROFINET device health, use IO_State, RDREC against port statistics, or RALRM for alarm-driven diagnostics.
  • When reading peer CPU state across PROFINET, push the state from the peer into the configured transfer area and read it cyclically. This avoids dependence on undocumented record numbers and survives firmware upgrades.
  • Wrap GET_DIAG in a dedicated FB so the call is encapsulated once per project. This keeps MODE, LADDR, and the output UDTs consistent across the codebase.
  • Do not branch application safety logic on OperatingState alone. Combine it with the partner's cyclic data exchange heartbeat (e.g., the watchdog tick pattern in section 8) and the partner's IO_State for a complete picture.

13. Related Instructions

Instruction Purpose When to use instead of GET_DIAG
RDREC Read a PROFINET/PROFIBUS record from any device/slot When you need a record that GET_DIAG does not expose (port stats, IM0, vendor records).
WRREC Write a record (e.g., parameter assignment, port mode) When you need to change device settings.
RALRM Receive a PROFINET process alarm For interrupt-driven diagnostics rather than polled.
GetStationInfo Read station-level information including topology and port data When you need full PROFINET topology from the controller.
GetSZL Read system state lists For diagnostic information about the local CPU (SSLs).
RD_SINFO Read OB start info For OB-level diagnostics inside the local CPU.

14. Frequently Asked Questions

Why does GET_DIAG always return OperatingState = 0 against my PROFINET i-device?

Because PROFINET IO devices do not have a CPU operating state in the slot diagnostics. GET_DIAG can only return a meaningful OperatingState when the LADDR input points at the local execution system (Local~exec, HW identifier 0). To see the i-device CPU state, push it from the i-device into the configured transfer area and read it back on the controller side.

Is the GET_DIAG OperatingState behaviour a bug in TIA Portal V13 SP1 Update 5?

No. The behaviour is the same in V14 through V18. The Siemens manual describes the local CPU output path, but the block is intentionally scoped to the local CPU for operating state. Diagnostic data for remote devices (IO_State, channel diagnostics, module state) is read correctly when LADDR points at the remote device.

What LADDR value do I use to read the local CPU operating state?

Use Local~exec from the system constants table. The hardware identifier it resolves to is 0 on S7-1200 and S7-1500. The call must be made with MODE = 0; only that mode returns the OperatingState output.

How do I detect a STOPped i-device CPU from the controller?

Add a status word to the i-device transfer area. The i-device calls GET_DIAG on itself with LADDR = Local~exec and writes the resulting OperatingState into the transfer area output. The controller reads the value cyclically through the configured slot. This works on all supported firmware versions without depending on undocumented records.

Which values can OperatingState take and which are reserved?

Documented values: 3 = STARTUP, 4 = STOP, 7 = RUN, 9 = HOLD, 10 = STOP with restart pending. Values 0, 1, 2, 5, 6, and 8 are reserved or "undefined / not available". Do not branch safety logic on undocumented values; check the Siemens manual for firmware-specific additions before relying on new values.

Where can I find the official Siemens documentation for GET_DIAG?

The canonical references are: Siemens ID 109747174 for S7-1200 and S7-1500, Siemens ID 109773506 for STEP 7 Basic/Professional, and the TIA Portal cloud manual.

Back to blog