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.
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 = 0returnsOperatingState. Other modes return diagnostic data but not the operating state. - The
OperatingStateoutput is part of theDiagUDT whenMODE = 0. The compiler inserts a separate output pin to make it accessible without dereferencing the UDT. - Calling
GET_DIAGagainst an i-device withMODE = 1orMODE = 2returns 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. |
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
RDRECagainst port statistics record0x802A/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:
- 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 theLADDRinput.Local~execresolves to the hardware identifier0. - Use a symbolic tag whose initial value is
Local~execfrom the system constants table, or hard-code the constant0at theLADDRinput. 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:
- Compile and download the project to both CPUs.
- Open the
GET_DIAGblock instance in the controller and confirm in the monitor view thatLADDRresolves toLocal~exec(HW identifier0). - Force the controller to RUN.
OperatingStateshould read7within one OB1 cycle. - Switch the controller to STOP via the programming device.
OperatingStateshould read4within the next cycle. - Re-enter RUN and confirm the value returns to
7. - If the i-device operating-state transfer area is configured, force the i-device to STOP and verify the controller's
iRemoteOperStatereflects4within the PROFINET update cycle (typically 1 ms with RT, 250 µs with IRT). - Disconnect the PROFINET cable to the i-device and verify
IO_Stateshows0x0000(or the documented bad-state code) whileOperatingStatefor 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. Local |
| 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_DIAGcall 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~execfrom the system constants table rather than the literal0. This makes the intent clear and survives a copy/paste into another project. - Treat
OperatingStateas a CPU-level indicator only. For PROFINET device health, useIO_State,RDRECagainst port statistics, orRALRMfor 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_DIAGin a dedicated FB so the call is encapsulated once per project. This keepsMODE,LADDR, and the output UDTs consistent across the codebase. - Do not branch application safety logic on
OperatingStatealone. Combine it with the partner's cyclic data exchange heartbeat (e.g., the watchdog tick pattern in section 8) and the partner'sIO_Statefor 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.