1. Problem Description
An S7-1200 CPU (firmware V4.x through V4.6, configured in TIA Portal V16 through V20) is being used to monitor the connection state of a PROFINET IO device. The application block calls the instruction ModuleStates (FB 1007 / instruction in the "Extended instructions" / "Diagnostics" folder) and supplies the value 1 to the LADDR input. That same value 1 matches the Device Number visible in the PROFINET IO device properties of the device configuration.
On the first call the RET_VAL output reports:
RET_VAL = 16#8091
Siemens assigns the text "Hardware identifier of the LADDR parameter does not exist. Check (for example, in the system constants) whether the value for LADDR exists in the project." to that code. Substituting other values found in the project (system constants, IO device names) either returns the same error or returns 16#0000 (the function executes) but the ModuleStates slot array does not increment when the IO device is disconnected.
2. Root Cause Analysis
The ModuleStates instruction does not accept the PROFINET Device Number for LADDR. The input expects a TIA Portal internal Hardware Identifier (HW ID / HWIE / Hardware-Kennung). The Device Number and the Hardware Identifier are two distinct numbers generated by two different parts of the TIA Portal compiler:
| Parameter | Source | Scope | Editable? |
|---|---|---|---|
| PROFINET Device Number | PROFINET IO configuration (GSDML / device properties) | Used for AR establishment, AR-abort diagnostics, naming | Yes, in device properties |
| Hardware Identifier (HW ID) | TIA Portal project compiler, assigned during build | Internal address used by user program instructions (RDREC, WRREC, ModuleStates, DeviceStates, GET_DIAG, etc.) | No, but the symbolic name is editable |
For a small S7-1200 station with one CPU and one PN device the Device Number is frequently 1 because it is the first IO device in the project. The Hardware Identifier for the same device is assigned by the compiler and is typically in the range of 256 to 300 (CPU head module = small number, IO device = 256 +). The two are not correlated; they just happen to be confused in field code.
Confirming the diagnosis is straightforward: the TIA Portal online help for error 16#8091 explicitly states the parameter is invalid, and the suggestion is to look at the system constants — not the PROFINET device number.
3. ModuleStates Function Specification
The ModuleStates instruction (SCL name: ModuleStates, classic name: ModuleStates_FB, instruction catalog path Extended Instructions > Diagnostics > ModuleStates) is documented in the Siemens TIA Portal help and on the Siemens Industry Online Support portal. It returns the operational state of every sub-module of an IO device (PROFINET IO device, PROFIBUS DP slave, or central module of the CPU rack).
| Parameter | Declaration | Data Type | Meaning |
|---|---|---|---|
| LADDR | INPUT | HW_IO (Word) | Hardware identifier of the IO device (head module) |
| MODE | INPUT / static | USInt |
1 = provide module status list, 2 = count faulty modules |
| RET_VAL | OUTPUT | Int | Function return / error code |
| COUNT (or output length) | OUTPUT / static | USInt / UInt | Number of valid entries in the result array (MODE 1) or fault count (MODE 2) |
| STATE[n] | OUTPUT / static | Array of Byte | Per-module state: 0 = not configured, 1 = wrong module, 2 = module OK, 3 = substitute, 4 = faulty, 5 = not accessible / communication disrupted |
The official Siemens documentation page "Read module status information in an IO system (S7-1200, S7-1500)" within the TIA Portal cloud help confirms that for the function to operate it must receive the Hardware identifier from the project system constants: docs.tia.siemens.cloud — DeviceStates / ModuleStates S7-1200 S7-1500. The companion Siemens Support entry 109747174 confirms the same call pattern for an S7-1500 with two CPUs: support.industry.siemens.com — 109747174 ModuleStates example.
4. Locating the Correct Hardware Identifier
Three reliable methods are available in TIA Portal V16, V17, V18, V19, and V20 to determine the HW ID that the ModuleStates instruction expects.
4.1 System Constants Tab
- Open the Project tree, right-click the PLC and select Properties > System constants.
- Filter the column Name for the PROFINET device name (for example ET200SP_Head or the device catalog name).
- Read the value in the Value column — that integer is the HW ID.
- Mark the constant by ticking Use as symbolic name and reference it symbolically from the user program. TIA Portal will then update the call automatically whenever the project is recompiled.
4.2 Network View Selection
- Switch to the Network view and single-click (do not double-click) the PROFINET IO device head module.
- The properties inspector at the bottom of the screen shows a summary pane. The HW ID is listed under General > Identification > Hardware identifier.
- If the field is hidden, click the » arrow at the right edge of the properties bar to expand the section.
4.3 Cross-reference from the Online & Diagnostics View
- Right-click the IO device in the project tree and select Online & Diagnostics.
- Open the Module information folder. The displayed Module / Sub-module names are followed by the HW ID in parentheses.
5. Step-by-Step Resolution
- Identify the symbolic name of the head module of the PROFINET IO device (for example PROFINET_IO_System_1::ET200SP_Head).
- Look up the HW ID in the system constants table — for the documented case it is
270. - Replace the hard-coded literal
1in theLADDRinput with either the symbolic constant or the constant270. - Recompile the program block (right-click the block > Compile > Software (rebuild all blocks)).
- Download the program to the CPU and observe the
RET_VAL. - Cycle the PROFINET connection by unplugging the Ethernet cable to the device. The relevant entry in the
STATE[]array must transition to5(not accessible) andCOUNTmust increment by one for each faulty slot.
6. Code Examples
6.1 SCL (Structured Control Language)
// FB "IO_Diag_S7_1200" — PROFINET device health monitor
// Compatible: TIA Portal V16 .. V20, S7-1200 FW V4.2 .. V4.6
// Single-instance DB carries MODE / STATE[] across calls
{ S7_Optimized_Access := 'TRUE' }
VAR
ModuleStates_Instance : ModuleStates; // FB 1007 instance DB auto-generated
FaultCount : UINT; // total number of faulty modules
SubIndex : INT; // loop counter
DeviceState : BYTE; // 0 = OK, 5 = disrupted / not accessible
DeviceHealthy : BOOL; // TRUE if no module reports fault
END_VAR
// Edge-triggered call every OB1 cycle is fine; MODE = 1 yields the full state list
ModuleStates_Instance(LADDR := "PROFINET_IO_System_1::ET200SP_Head", // symbolic HW ID
MODE := 1,
RET_VAL := #tmpRetVal,
COUNT => #FaultCount,
STATE => #tmpStateArray);
IF #tmpRetVal <> 0 THEN
// Capture the error code for HMI / logbook. Most common: 16#8091 (bad HW ID),
// 16#8090 (instance DB missing or wrong version), 16#80B1, 16#80C1
"dbDiag".LastError := #tmpRetVal;
RETURN;
END_IF;
// Find the worst state across the device. STATE values: 0/1/2/3/4/5
#DeviceState := 0;
FOR #SubIndex := 1 TO #FaultCount DO
IF #tmpStateArray[#SubIndex] = 5 THEN
#DeviceState := 5; EXIT;
ELSIF #tmpStateArray[#SubIndex] = 4 THEN
#DeviceState := 4;
END_IF;
END_FOR;
#DeviceHealthy := (#DeviceState = 2) OR (#DeviceState = 3);
6.2 Ladder (LAD) / FBD
For engineers that prefer graphic languages, the same logic fits in a single network:
Network 1: ModuleStates call
| [ModuleStates] |
| LADDR = "HW_ID_ET200SP_Head" (270) |
| MODE = 1 |
------| RET_VAL -> "dbDiag".LastError |
| COUNT -> #FaultCount |
| STATE -> "dbDiag".StateArray[0..15] |
------|
Wire the symbolic constant from the system constants tab; the literal value 270 only appears as a tooltip on the constant.
7. Error Code Reference
| RET_VAL (hex) | Meaning (per Siemens TIA Portal help) | Likely cause on S7-1200 | Fix |
|---|---|---|---|
| 16#0000 | No error | Function executed normally | Read STATE[] / COUNT as required |
| 16#7000 | No job active (first call) | Multi-instance background processing | Call from OB1, OB82, OB86, OB100 |
| 16#8090 | Instance DB error / wrong block version | FB version mismatch after firmware upgrade | Recompile, regenerate instance DB |
| 16#8091 | HW identifier of LADDR does not exist | Wrong LADDR — Device Number used instead of HW ID, or HW ID from a removed module | Replace with symbolic constant from system constants |
| 16#8092 | LADDR does not address a head module | Sub-module HW ID supplied instead of head | Use the head module HW ID only |
| 16#80B1 | Length of STATE[] too small | Array dimension < slot count of device | Resize array to at least 16 bytes (default) or to the device slot count |
| 16#80C1 | Resource bottleneck (too many parallel jobs) | ModuleStates called in many OBs simultaneously | Combine calls, use MODE 2 for summary only |
| 16#80D0 / 16#80D1 | Internal CPU diagnostics error | PROFINET stack not yet started | Check OB82 / OB86 diagnostics, restart CPU |
8. DeviceStates vs ModuleStates
The two instructions are often confused. Both exist in the same catalog folder and both return a RET_VAL in the same code family, but their semantics are different.
| Aspect | DeviceStates | ModuleStates |
|---|---|---|
| Operates on | PROFINET IO system (entire PN controller / PN interface) or PROFIBUS DP master system | A single IO device (head module) or central rack |
| LADDR expects | HW ID of the PN interface / PN IO system / DP master | HW ID of the head module of the target device |
| MODE 1 result | Array with one entry per IO device in the system (state codes 0..6) | Array with one entry per sub-module / slot of the addressed device |
| MODE 2 result | Number of faulty IO devices in the system | Number of faulty modules of the addressed device |
| Typical use | "How many of my PROFINET devices are down right now?" | "Which slot in device X is failing?" |
| Documented in | TIA Portal help: Read module status information in an IO system (S7-1200, S7-1500) | Same TIA Portal help page; also Siemens Support entry 109747174 |
For a single ET200SP or other remote head, ModuleStates is the right choice. For a fleet of PROFINET stations the better diagnostic is DeviceStates at the IO system level, with the per-device detail drilled in via ModuleStates only when a fault is reported.
9. PROFINET IO Diagnostics Architecture
The HW ID is the cornerstone of every diagnostics instruction on an S7-1200 / S7-1500. The same identifier that is fed to ModuleStates is the identifier that RDREC / WRREC use to address the head module record index 0x0000/0x8000 (AR establishment, AR abort), and it is the identifier that GET_DIAG uses to read the standard diagnostic record. The PROFINET Device Number, in contrast, is a configuration artifact used by the controller's AR endpoint and never appears in the user program.
The S7-1200 CPU raises OB 86 (rack failure) when an IO device loses its AR, and OB 82 (diagnostic interrupt) on per-slot events. ModuleStates can be polled from OB1, but the same RET_VAL codes (16#0000, 16#8091, etc.) are reported identically when called from OB82 / OB86. Calling the block from OB86 with the LADDR symbol associated with the failing device gives a deterministic snapshot within the diagnostic interrupt itself, avoiding a race condition with the topology auto-discovery in OB1.
10. Verification Procedure
- Place a watch on the symbolic name "PROFINET_IO_System_1::ET200SP_Head". Confirm in the project tree Properties > System constants that the displayed value is what the program passes.
- Establish an online connection to the CPU. Open the Monitor & force window on the instance DB. Verify
RET_VAL = 16#0000andCOUNT > 0. - Force a fault: unplug the PROFINET cable at the head module. Within two PN update cycles (default 1 ms) the slot entries must transition to
5and the OB86 must be entered. - Reconnect the cable. The entries must return to
2(module OK) and OB83 / OB86 must be entered with the "module OK" event. - Capture the diagnostic record via Online & Diagnostics > Module information > PROFINET diagnostics > Channel diagnostics and cross-check the channel number with the slot that ModuleStates flagged.
11. Edge Cases and Advanced Usage
- Rearranged device numbering after hardware change: When a new IO device is added at the top of the PROFINET tree, the HW IDs of all later devices shift. Symbolic constants absorb the change; hard-coded literals break. Always pass the symbol.
- Shared devices on IRT mode: In IRT (isochronous) topologies the AR lifecycle is more strict; call ModuleStates from OB100 once at startup to confirm every device is up before the application OB1 starts demanding data.
- Firmware V4.2 vs V4.6: V4.2 supports ModuleStates but the diagnostic record set is smaller (basic PROFINET alarms only). V4.4+ extends the per-slot STATE granularity. The instruction FB / symbol is identical; the firmware underneath is what differs.
-
Sub-module versus head module HW ID: The head module HW ID is what LADDR expects. A sub-module HW ID returns
16#8092. The system constants table distinguishes the two by the trailing ~Head / ~Slot_n suffix. - Central rack modules on S7-1200: SM4 modules plugged directly into the CPU also have HW IDs. ModuleStates called with the head module HW ID of the CPU itself enumerates the central rack, useful for detecting a hot-swapped SM that the system constants do not flag until recompile.
- Tool-changeover with shared symbols: When the same FB is reused across multiple stations, declare a variable of type HW_IO at the FB input and pass the station-specific constant from the caller. The instance DB stays generic.
Why does ModuleStates return 16#8091 even though the LADDR value is shown in the device properties?
The Device Number in the PROFINET device properties is a configuration value used for AR establishment, not the TIA Portal Hardware Identifier that ModuleStates requires. Open the PLC Properties > System constants, locate the symbolic constant for the head module (for example PROFINET_IO_System_1::ET200SP_Head), and pass that constant instead of the Device Number.
How do I find the HW ID of a PROFINET device in TIA Portal?
Single-click the device head module in the Network view and read the Hardware identifier in the properties inspector, or open the PLC Properties > System constants and read the value column for the matching symbolic name. The HW ID is a non-editable integer in the typical range 256-300 for the first IO device in a small S7-1200 project.
What is the difference between DeviceStates and ModuleStates?
DeviceStates reports the state of every IO device within a PROFINET IO system or PROFIBUS DP master system. ModuleStates reports the state of every sub-module / slot within a single IO device. Use DeviceStates at the system level for "how many stations are down" and ModuleStates at the device level for "which slot is failing". Both expect a Hardware Identifier, not a Device Number, on LADDR.
Can ModuleStates be called on an S7-1200 firmware V4.2 CPU?
Yes. ModuleStates has been available in the TIA Portal instruction set since the S7-1200 first supported PROFINET diagnostics. The RET_VAL codes, the MODE values (1 = list, 2 = count) and the LADDR requirement are identical from V4.2 through V4.6. Only the depth of per-slot information grows with later firmware revisions.
ModuleStates returns 16#80B1 with my custom STATE array — what is wrong?
16#80B1 means the STATE array is shorter than the number of sub-modules the addressed device has. Declare the array with at least 16 bytes for an ET200SP head and increase it for larger devices. If you only need the fault count, call the function with MODE 2 and ignore the STATE array.