Detecting Multiple Faulty PROFINET Nodes in TIA Portal S7-1500
A PROFINET network almost never fails at a single node. Field experience shows that the first event in a PROFINET fault cascade is usually one device dropping off the ring, then two more follow as the IO supervisor, port statistics, and watchdog timers react. Detecting one faulty PROFINET node from a Siemens S7-1500 is straightforward through DeviceStates and a single string output. Detecting multiple faulty nodes, holding their assigned device names in a usable structure, and raising a separate alarm per device is a different engineering task. This guide covers the full chain: PROFINET diagnostics, the function-block design for a sliding array of failed-device names, alarm generation with Gen_Usr_Msg, and HMI rendering on both Siemens Comfort Panels and Beijer iX panels.
1. Prerequisites: Hardware, Firmware, and Software Stack
Before writing a single line of code, confirm the engineering environment supports the diagnostics primitives used in this pattern.
| Item | Minimum Requirement | Notes |
|---|---|---|
| CPU family | S7-1500 (all variants), S7-1200 G2 in supported cases | Firmware must be current per the TIA Portal version |
| TIA Portal | V17 Update 4 / V18 / V19 | V17 is the baseline for the Gen_Usr_Msg variants shown |
| PROFINET device list | Configured IO devices in Devices & Networks | Unconfigured nodes return unknown status |
| Device name length | PROFINET spec allows up to 240 characters | This article uses String[20] for typical robot/driver/RFID names |
| HMI panel | Siemens Comfort Panel OR Beijer iX / IXpanel | Alarm forwarding assumes S7 Comm / S7 Ethernet |
| GSD files | Installed for every third-party IO device | Most common cause of "node not in device list" alarms |
Reference the S7-1500 system manual on the Siemens Online Support portal (support.industry.siemens.com) for the firmware-to-TIA compatibility matrix. The diagnostics instructions in this article are documented in the STEP 7 (TIA Portal) online help, accessible from inside TIA Portal via F1 on any selected instruction block.
2. PROFINET Diagnostics Architecture on S7-1500
PROFINET diagnostics on the S7-1500 platform is built from three layers. Understanding which layer a signal comes from determines which instruction reads it.
-
PROFINET stack status (system level): Provided by the IO controller and reflects whether each configured IO device is reachable on the wire. Read with
DeviceStates. -
Channel diagnostics (device level): Records 0x8000 series returned by the IO device, describing port errors, sub-module faults, and channel-level failures. Read with
RDRECon the PROFINET diagnostic slot. - Process alarms (submodule level): Generated by submodules as interrupts (OB 82, OB 83, OB 86, OB 122). Used for pull/plug events, module faults, and rack faults.
For the multi-node detection pattern in this article, only the first layer (DeviceStates) is required. The second layer becomes relevant if you also need to know why a device failed. OB 86 is implicitly engaged: it is the cyclic handler that fires whenever a PROFINET IO device transitions to "station failure" and is what DeviceStates queries under the hood.
3. The DeviceStates Instruction: Reading Node Status
DeviceStates is the central instruction for this pattern. It returns the operational state of every PROFINET IO device the controller has in its project.
| Mode (LADDR / MODE combination) | Returns | Typical Use |
|---|---|---|
| Device status | BOOL array, one element per configured device, TRUE = device OK | Detecting disappeared nodes |
| Module status | Array describing modules of one device | Locating which module is missing |
| Submodule status | Array describing submodules of one module | Channel-level diagnostics |
Place the instruction in OB1 or a cyclic OB (e.g., OB30 through OB38 for time-sliced execution). The call signature in SCL is:
"DeviceStates_DB".DeviceStates(
LADDR := 0, // PROFINET IO system identifier; 0 = PN interface 1
MODE := 1, // 1 = device status
RET_VAL := #iRetVal, // instruction return value
STATE := #aDeviceState // pointer to BOOL array sized to number of devices
);
The output array element at index N corresponds to the N-th PROFINET device listed under the IO controller's IO system. The order is stable for a given TIA Portal project, but it is not necessarily the same as the order in the Devices & Networks editor. Verify the mapping in online mode by disconnecting one device and observing which element goes FALSE.
DeviceStates truncates the result and returns RET_VAL <> 0 with a length mismatch error. Size the array to PtoP_NUM_IO_DEVICES from the project, plus a safety margin of 4 elements.4. Building the Fault Detection Function Block
The FB must be called once per cycle. It reads the current DeviceStates snapshot, compares it against the previous snapshot stored in the FB's instance DB, and reconciles the array of faulty device names. The reconciliation uses the "find first empty slot, then bubble-up the last entry" pattern described in the field report. This keeps the array dense and bounded.
Interface declaration (SCL, TIA Portal V17+):
FUNCTION_BLOCK "FB_PROFINET_Faults"
VAR_INPUT
iExecute : BOOL; // TRUE = perform a scan this cycle
END_VAR
VAR_INOUT
iqFaultyNames : ARRAY[0..MAX_FAULTY_PN_NODE_NAMES] OF STRING[20];
END_VAR
VAR_OUTPUT
oActiveFaultCount : INT; // current number of valid entries in iqFaultyNames
oNewFaultDetected : BOOL; // one-cycle pulse when a new name has been added
oClearedFault : BOOL; // one-cycle pulse when a previously faulty node recovers
oRetVal : INT; // 0 = OK, non-zero = see below
END_VAR
VAR
aDeviceState : ARRAY[0..MAX_PN_DEVICES] OF BOOL;
aPrevState : ARRAY[0..MAX_PN_DEVICES] OF BOOL;
iRetVal : INT;
iSlotIndex : INT;
bInit : BOOL := TRUE;
END_VAR
VAR CONSTANT
MAX_PN_DEVICES : INT := 64;
MAX_FAULTY_PN_NODE_NAMES : INT := 32;
END_VAR
Body (excerpt, two key phases):
// Phase 1 - capture the current state
"DeviceStates_DB"(LADDR := 0, MODE := 1, RET_VAL := iRetVal, STATE := aDeviceState);
// First-call initialization: mark everything as previously OK so a faulted
// node at start-up is detected on the very first scan.
IF bInit THEN
aPrevState := aDeviceState;
bInit := FALSE;
END_IF;
// Phase 2 - reconcile: walk every device, transition FALSE & detect first
FOR #iSlotIndex := 0 TO MAX_PN_DEVICES DO
// Rising edge of fault: aDeviceState FALSE AND aPrevState TRUE
IF NOT #aDeviceState[#iSlotIndex] AND #aPrevState[#iSlotIndex] THEN
#iqFaultyNames[FindFirstEmpty(#iqFaultyNames)] := DeviceNameFromIndex(#iSlotIndex);
#oNewFaultDetected := TRUE;
END_IF;
// Falling edge: recovery, bubble-up the last non-empty entry into this slot
IF #aDeviceState[#iSlotIndex] AND NOT #aPrevState[#iSlotIndex] THEN
CompactArray(VAR_INOUT := #iqFaultyNames);
#oClearedFault := TRUE;
END_IF;
END_FOR;
// Refresh the snapshot for the next cycle
aPrevState := aDeviceState;
The helper DeviceNameFromIndex resolves the device name. There are two reliable ways to build it:
-
Static lookup table (recommended): an
ARRAY[0..MAX_PN_DEVICES] OF STRING[20]constant populated at build time with the assigned PROFINET device names. Index the array with the same loop index that drivesDeviceStates. This is the deterministic, debuggable approach. - Dynamic read from the PROFINET stack: read record 0xF880 (IM data) or use the name resolution available in the controller's online view. This is non-trivial and is generally only worth doing if device names are configured at runtime.
For the static lookup, populate the constant array either by hand or by exporting the device list from TIA Portal. The two arrays (state and names) must have identical length and ordering conventions.
5. Array Management for Multiple Failed Devices
The "find first empty + bubble-up" pattern is correct for bounded arrays. Empty-slot detection is done on a string that has never been written, which on Siemens S7-1500 is the zero-length string. To make empty-slot detection robust against PLC restart:
- On the first cycle after a restart, scan
iqFaultyNamesand zero every element explicitly. This eliminates the issue where a warm restart leaves stale data in the instance DB. - Define a constant sentinel such as
sEMPTY := ''(zero length). Do not use spaces, which survive across the restart boundary and break the empty-slot test. - Bound the search loop with
MAX_FAULTY_PN_NODE_NAMES, not a derived count, so that a corrupted count cannot throw an out-of-bounds error.
The bubble-up on recovery keeps the array dense. Without compaction, a recovered device leaves a hole in the array; a fresh fault then appends to the end, leaving an array that grows in apparent length even though the population is stable. The compaction routine looks like:
// CompactArray - shift entries left, fill tail with ''
FOR #i := 0 TO MAX_FAULTY_PN_NODE_NAMES - 1 DO
IF #iqFaultyNames[#i] = '' THEN
FOR #j := #i TO MAX_FAULTY_PN_NODE_NAMES - 1 DO
#iqFaultyNames[#j] := #iqFaultyNames[#j + 1];
END_FOR;
#iqFaultyNames[MAX_FAULTY_PN_NODE_NAMES] := '';
EXIT; // one shift per outer pass; re-enter on next call
END_IF;
END_FOR;
For diagnostic clarity, also expose oActiveFaultCount as an HMI-visible tag. Operators can confirm at a glance that the array length matches the active alarm count.
6. Generating Per-Device Alarms with Gen_Usr_Msg
A single PROFINET fault should produce a single alarm. The Siemens Gen_Usr_Msg instruction is the canonical way to raise a text alarm from user code without resorting to the bit-message approach of the older Gen_UserMsg in STEP 7 V5.x.
Call pattern in SCL:
IF #oNewFaultDetected THEN
"HMI_Alarm_DB".Gen_Usr_Msg(
ID := 1001,
Event_ID := #iSlotIndex + 100, // unique per device
Severity := 2, // 0=info, 1=warn, 2=fault, 3=diag
Format_String := 'PROFINET node %s is faulty',
Argument_1 := #sNewDeviceName,
Acknowledge := TRUE,
Time_Stamp := DT#0001-01-01-00:00:00 // automatic timestamp
);
#oNewFaultDetected := FALSE;
END_IF;
For the inverse path, generate a "recovered" alarm on oClearedFault:
IF #oClearedFault THEN
"HMI_Alarm_DB".Gen_Usr_Msg(
ID := 1002,
Event_ID := 0,
Severity := 0,
Format_String := 'PROFINET node recovered',
Acknowledge := TRUE
);
#oClearedFault := FALSE;
END_IF;
Event_ID. Using a unique Event_ID per device-slot guarantees that an alarm of a recurring fault supersedes a still-unacknowledged alarm of the same device. Reusing Event_ID across multiple devices is the most common cause of "alarm won't go away" symptoms on the HMI.An alternative to Gen_Usr_Msg is ProDiag, the integrated alarm framework introduced in TIA Portal V15.1 for S7-1500. ProDiag is more powerful because the alarm is bound to the supervising expression itself; if the network path becomes transient, ProDiag's GET_DIAG and Get_IM_Data instructions can attach channel-level detail. For installations that already use ProDiag for general machine alarms, fold the PROFINET fault FB into the ProDiag overview rather than running a parallel alarm path.
7. HMI Integration: Beijer Panels and Siemens Comfort Panels
Both Siemens Comfort Panels and Beijer iX panels receive the same S7 alarm data through the S7 Ethernet driver; the difference is in how the alarm view is configured and which fields the panel exposes by default.
| Aspect | Siemens Comfort Panel | Beijer iX (IXpanel T7A / T12B) |
|---|---|---|
| Alarm source | Tag-based S7 alarms (HMI alarms) connected to the alarm DB | OPC UA / S7 driver alarm subscription |
| Alarm view widget | "Alarm view" / "Alarm control" in WinCC Comfort | "Alarm" object in iX Developer |
| Dynamic text | Multiline text field bound to the alarm's argument | Concatenated string in tag display; alarm field maps to the S7 argument |
| Acknowledgment model | Ack bit on the S7 side, mirrored in alarm view | Same, via S7 driver "Acknowledge" property |
| Filtering | Alarm class & group filters | Filter expression on the alarm object |
For Beijer panels, two practical patterns are common:
-
Single concatenated text: read
iqFaultyNamesas a string array via the S7 driver and build a multiline string for a text box. This is what the field report describes: "concatenate line breaks between the non-null device names". Use the standard CRLF ('$R$N') as the line separator. The S7-1500 STRING type handles 254 characters; for long lists, expose only the first 8 elements or split into multiple tags. -
Per-device alarm entries: forward each
Gen_Usr_Msgevent into the Beijer alarm log. The Beijer alarm object subscribes to S7 events with a configured update rate (typically 250 ms to 1 s).
For the first pattern, populate the visible string with:
// Build a CRLF-separated visible list on the HMI side using iX Developer
// tag-side script or in the PLC by exposing a pre-joined STRING[254]
// Recommendation: expose the pre-joined string from the PLC to keep
// the iX project free of script logic.
On the Siemens side, Gen_Usr_Msg with the format string 'PROFINET node %s is faulty' makes the alarm row's "Event text" field self-describing. Operators do not need a separate lookup table to read the alarm.
8. Verification and Commissioning
Use the following verification sequence on the machine, not just in the simulator. The simulator does not exercise the real PROFINET stack.
-
Online watch the BOOL state array. Disconnect one device on the network (power down or pull the PROFINET cable). Confirm exactly one element of
aDeviceStatetransitions to FALSE. -
Cross-check device name. With the device disconnected, the matching element of
iqFaultyNamesmust contain the assigned PROFINET device name exactly as configured in the project. - Check the alarm appears. On the HMI, verify the alarm line, its event text, and its event time. The timestamp is supplied by the CPU's internal clock; check NTP/SICLOCK synchronization if timestamps drift.
- Recovery behavior. Reconnect the device, confirm the entry compacts out of the array within one cycle, and verify the recovery alarm fires once.
-
Multi-failure stress test. Disconnect three devices simultaneously. Verify the array grows to three entries, the count is three, and three distinct alarms (with three distinct
Event_IDvalues) are visible on the HMI. - Spam test: flap a single device power repeatedly. The array should not grow beyond one entry for that device, and the alarm should not flood the HMI. If it does, add a debounce: require the fault to persist for N cycles (e.g., 3 cycles at 100 ms) before treating it as a real fault.
- CPU restart: trigger a STOP/RUN transition. Confirm the array is empty at start and that the first scan does not raise spurious alarms for devices that were already offline at restart.
9. Troubleshooting Matrix
| Symptom | Likely Cause | Verification | Fix |
|---|---|---|---|
| All devices always shown as faulty | PROFINET interface number wrong (LADDR not 0) | Check Devices & Networks > PROFINET interface properties | Set LADDR to the correct interface number (X1 = 0, X2 = 1 on most S7-1500) |
| Array element count out of sync with HMI | MAX_FAULTY_PN_NODE_NAMES too small | Online watch oActiveFaultCount vs visible alarms | Resize array and recompile both PLC and HMI |
| Device name shows empty string in alarm | Static lookup table not populated for that slot | Watch the static lookup array online | Export the device list from TIA Portal into the lookup constant |
| Alarm appears and does not clear on recovery | Event_ID not unique per device | Cross-check HMI alarm log | Use slot index as part of Event_ID |
| Alarm fires on every cycle | No debounce / no falling-edge detection | Watch oNewFaultDetected in online mode | Add debounce timer and reset oNewFaultDetected after Gen_Usr_Msg call |
| Device missing from DeviceStates array | GSD file not installed; device not in configured IO system | Devices & Networks > Device catalog | Install GSD and add the device; recompile the HW config |
| Beijer panel shows no alarms | Alarm subscription disabled in iX project | iX Developer > Alarm object properties | Enable "Subscribe to controller alarms" and verify driver connection status |
| Gen_Usr_Msg RET_VAL non-zero | Format string length / argument mismatch | Inspect format string in code | Match format-string placeholder count and types to the supplied arguments |
| Fault persists after device returns | OB 86 still in "station failure" state because of port mismatch | Online & Diagnostics > PROFINET topology | Reset topology port assignments; check that cabling matches the configured ports |
10. Edge Cases and Field-Proven Caveats
Configured but unassigned devices. PROFINET devices that exist in the TIA project but have never been assigned a name through the topology editor will never appear as "faulty"; they are not in the IO controller's device list. The symptom is the opposite of the missing-device case: an operator sees a device physically on the network, but the controller is silently ignoring it.
Device-name length boundary. A PROFINET device name can legally be up to 240 characters. The pattern above uses STRING[20], which truncates longer names. Truncation is silent in TIA Portal. To catch truncation, expose a check that compares the lookup-table length with the configured-name length once at startup and raise a startup diagnostic if they differ.
CP 1543-1 vs on-board PROFINET interface. If the S7-1500 is using an external CP (e.g., CP 1543-1) as a second PROFINET IO controller, the LADDR in DeviceStates must point at the CP, not at the on-board interface. Forgetting this is the single most common cause of "all faults show as FALSE at start-up" when an external CP is present.
Hot-swappable devices. Some PROFINET devices (e.g., fieldbus couplers with hot-swap capability) are designed to be pulled and replaced without disturbing the network. If hot-swap is enabled, the controller will, in the typical configuration, NOT raise a station failure on a transient pull. The fault FB will not see the event. For hot-swap topologies, enable OB 83 (pull/plug interrupt) and read module status separately rather than relying on DeviceStates.
Ring redundancy (MRP). In an MRP ring, a single cable break is absorbed by the redundancy manager. The PROFINET diagnostics stack on the S7-1500 typically does not raise a device fault on the break itself; the affected device is still reachable via the ring. To detect ring breaks, monitor the MRP manager's state via RDREC on the redundancy manager, not via DeviceStates.
Subnet crossings. A device on a router-separated subnet (e.g., behind a SCALANCE) requires the controller's routing table to be configured. The DeviceStates instruction will not cross subnets on its own. Configure the PROFINET device's IP in the same subnet as the IO controller, or use PROFINET routing with the SCALANCE W / S series.
How does DeviceStates know which devices to check?
DeviceStates reads the IO controller's configured IO system at runtime, not the live network. Only devices present in Devices & Networks and assigned to the controller are reported; unconfigured devices are not seen at all. To detect an unknown device, monitor the topology or use a separate node-detection scan.
Can I use a STRING[240] instead of STRING[20] for the array?
Yes, but the S7-1500 STRING is 254 bytes max, and an ARRAY of 32 such strings consumes about 8 KB of work memory plus 32 bytes of overhead per element. STRING[20] is a deliberate engineering trade-off; if your device names exceed 20 characters, use STRING[40] and keep the array size to under 16 elements.
Why does my alarm never clear on the HMI even after recovery?
Most often the Event_ID is identical across devices. The HMI treats the cleared event as the same as the active one and does not re-evaluate. Use a unique Event_ID per device slot and a separate Event_ID for the "recovered" message. Also confirm that the alarm class in the HMI project has the correct acknowledgment model (one-shot vs. flat).
How many faulty nodes can the pattern handle at once?
Bounded by MAX_FAULTY_PN_NODE_NAMES. With the value 32 shown in the article, the FB can distinguish 32 simultaneous faults. If your network routinely exceeds 32 faults, raise the constant and rescan the array-size limits in the HMI project and the static lookup table.
Does the pattern work on S7-1200 as well?
Partially. S7-1200 CPUs do not expose Gen_Usr_Msg in the same form as S7-1500; the available user-message instruction is Gen_UserMsg (older) and the diagnostics instruction set is reduced. For S7-1200 deployments, use the older user-message pattern and verify against the TIA Portal help that the target CPU supports DeviceStates; some S7-1200 firmware versions do not.