Resolving S7-1200 ModuleStates Error 16#8091 HW ID Not Device

David Krause12 min read
S7-1200SiemensTroubleshooting
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

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.

Symptom signature: The error occurs at the first call cycle, never recovers, and persists across re-download / re-init. The same value that is shown as "Device Number" in the device properties is being passed unchanged to LADDR.

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

  1. Open the Project tree, right-click the PLC and select Properties > System constants.
  2. Filter the column Name for the PROFINET device name (for example ET200SP_Head or the device catalog name).
  3. Read the value in the Value column — that integer is the HW ID.
  4. 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

  1. Switch to the Network view and single-click (do not double-click) the PROFINET IO device head module.
  2. The properties inspector at the bottom of the screen shows a summary pane. The HW ID is listed under General > Identification > Hardware identifier.
  3. If the field is hidden, click the » arrow at the right edge of the properties bar to expand the section.
Important: Double-clicking the device opens the device view, and from there the head module properties do not display the HW ID of the head module itself — they show the sub-module or slot HW IDs. The single-click on the head module in the network view is the correct location.

4.3 Cross-reference from the Online & Diagnostics View

  1. Right-click the IO device in the project tree and select Online & Diagnostics.
  2. Open the Module information folder. The displayed Module / Sub-module names are followed by the HW ID in parentheses.

5. Step-by-Step Resolution

  1. Identify the symbolic name of the head module of the PROFINET IO device (for example PROFINET_IO_System_1::ET200SP_Head).
  2. Look up the HW ID in the system constants table — for the documented case it is 270.
  3. Replace the hard-coded literal 1 in the LADDR input with either the symbolic constant or the constant 270.
  4. Recompile the program block (right-click the block > Compile > Software (rebuild all blocks)).
  5. Download the program to the CPU and observe the RET_VAL.
  6. Cycle the PROFINET connection by unplugging the Ethernet cable to the device. The relevant entry in the STATE[] array must transition to 5 (not accessible) and COUNT must 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

  1. 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.
  2. Establish an online connection to the CPU. Open the Monitor & force window on the instance DB. Verify RET_VAL = 16#0000 and COUNT > 0.
  3. 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 5 and the OB86 must be entered.
  4. Reconnect the cable. The entries must return to 2 (module OK) and OB83 / OB86 must be entered with the "module OK" event.
  5. 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.

Back to blog