Overview
Engineers commissioning a SIMATIC S7-1500 frequently need a single Boolean output that says "module is faulty" for a given I/O logical address, e.g. input byte 123 or output word 256. The TIA Portal ships a fully featured diagnostic stack, but the documentation ladder starts at the IO system (IOSystem) hardware identifier and walks down through stations and slots. That top-down approach returns far more information than the application needs and inflates the code base of every project.
This reference compares the four production-ready paths to the same answer on a S7-1500 CPU (firmware V2.0 and later; instruction set extended on V2.5/V2.9):
- Event-driven OB82 Diagnostic Error Interrupt (zero polling overhead).
- RALRM inside OB82 for vendor-formatted channel diagnostics.
- Polling ModuleStates for a single subsystem (one call returns every slot).
- Address translation with LOG2MOD / GEO2LOG chained to ModuleStates when only the I/O logical address is known.
Each path is presented with the data structures it requires, the exact TIA Portal instruction signature, and a verification checklist. The article closes with a troubleshooting matrix for the most common commissioning defects.
Diagnostic Architecture in the S7-1500
The S7-1500 separates logical addresses (the %I / %Q range a program reads and writes) from hardware identifiers (HW_ID or LADDR, a 16-bit word used by system blocks and instructions). Every PROFINET device, PROFIBUS slave, sub-module and channel receives one HW_ID at compile time; the value is exposed as a system constant in the PLC tags table.
| Term | Symbol | Length | Source |
|---|---|---|---|
| Logical I/O address | %I / %Q | Byte/Word/DWord | Configured I/O address in the device view |
| Hardware identifier | HW_ID (LADDR) | Word (UInt) | System constants -> HW identifiers |
| Diagnostic address | LADDR in OB82 | Word (UInt) | Operating system supplies at interrupt |
| IOSystem identifier | HW_ID (system) | Word (UInt) | PROFINET IO system constant |
Two key diagnostics OBs are wired automatically when the CPU is parameterised in TIA Portal:
-
OB 82 - Diagnostic Error Interrupt. Triggered by channel/module faults coming and going. Input tags:
LADDR,IO_STATE,CHANNEL,MULTI_FAULT. - OB 83 - Remove/Insert Interrupt. Triggered on hot-swap of a module. Useful for line topology diagnostics but outside the scope of this article.
Identifying the Hardware Identifier from a Logical Address
If the application already has the HW_ID of the failing module (for example, the module was added to a user data type as a tag and the system constant is dragged into the program), skip this section. The problem most engineers have is the inverse: they know only the I/O address and want the slot, station and HW_ID.
The TIA Portal instruction set ships the following address-conversion blocks under Extended Instructions -> Addressing:
| Instruction | Direction | Inputs | Output | Typical use |
|---|---|---|---|---|
LOG2MOD |
Logical -> Module | LADDR (log. byte), AREA (I/Q/PI/PQ) | Module slot, station | Find which slot holds input byte 123 |
GEO2LOG |
Geographic -> Logical | HW_ID of station, slot, subslot | LADDR | Start from a known slot |
LOG2GEO |
Logical -> Geographic | LADDR (log. byte), AREA | HW_ID of station, slot, subslot | Reverse of GEO2LOG |
RD_ADDR |
Any IO -> Pointer | Symbolic tag | Variant pointer | Pass any tag to a generic FB |
The combined call sequence that solves the original poster's requirement is shown below. The block returns the slot of the module that owns the logical address, which is then fed into ModuleStates for a station-wide status read.
// SCL - "GetModuleFaultFromLogAddr" FB
#i_LogAddr := 123; // input byte address
#i_Area := 16#81; // 0x81=Inputs (process image), 0x82=Outputs
#LOG2MOD (LADDR := #i_LogAddr,
AREA := #i_Area,
SLOT => #statSlot,
SUBSLOT=> #statSubSlot,
ERR => #statErr);
IF #statErr = 0 THEN
// ModuleStates returns one byte per slot for the IO system
#ModuleStates(LADDR := "PROFINET_Interface_1".IOsystem_HWID,
STATE := #statStates[0..31],
DIAG := #statDiag[0..31],
RETVAL => #statRetVal);
#b_ModuleFault := #statStates[#statSlot] <> 0;
ELSE
#b_ModuleFault := TRUE; // unknown mapping - assume worst case
END_IF;
The constants for PROFINET_Interface_1 are generated automatically when the PROFINET IO system is added; they appear under PLC tags -> System constants -> PROFINET IO system.
Approach 1: Event-Driven Fault Detection with OB82
OB 82 is the canonical Siemens mechanism. It carries four inputs that fully describe the event:
| OB82 input | Type | Meaning |
|---|---|---|
LADDR |
WORD | HW_ID of the module that reported the fault |
IO_STATE |
BYTE | Bit-coded: bit 0 = good, bit 1 = fault, bit 2 = wrong module, bit 3 = channel fault, bit 4 = module removed |
CHANNEL |
UINT | Channel number (0 = whole module) |
MULTI_FAULT |
BOOL | TRUE if more than one fault is queued for this module |
Because the inputs of OB 82 are valid for a single scan, copy them to a global diagnostic data block before processing. The skeleton below illustrates the recommended pattern: one SET rung per monitored module, plus a matching RESET rung that fires when the same module reports the event is cleared.
// OB82 Network 1 - capture inputs
#DiagDB.LADDR := #LADDR;
#DiagDB.IO_STATE := #IO_STATE;
#DiagDB.CHANNEL := #CHANNEL;
#DiagDB.MULTI_FAULT := #MULTI_FAULT;
#DiagDB.EventTime := RD_SYS_T; // SFC 1 returns current time-of-day
// OB82 Network 2 - fault SET per module
IF #LADDR = "Local_1_Slot_2".HWID THEN // system constant
IF (#IO_STATE AND 16#0E) <> 0 THEN // bits 1, 2, 3 set
"DiagDB".L1_Mod_Fault := TRUE;
END_IF;
END_IF;
// OB82 Network 3 - fault CLEARED per module
IF #LADDR = "Local_1_Slot_2".HWID THEN
IF (#IO_STATE AND 16#01) = 1 THEN // bit 0 = good
"DiagDB".L1_Mod_Fault := FALSE;
END_IF;
END_IF;
After this OB executes, the program can consume "DiagDB".L1_Mod_Fault anywhere - in the HMI tag list, in WinCC Unified, in a safety logic input or in a maintenance flag visible on the CPU display.
Approach 2: Reading the Full Channel Record with RALRM
When the field engineer needs the specific channel that failed, not just the module, call RALRM (read alarm) inside OB 82. RALRM returns the complete vendor-formatted alarm record that the PROFINET device pushed into the CPU's diagnostic buffer.
// SCL - inside OB 82
#RALRM(OB := 82,
MODE := 1, // 0=read all, 1=read with filter
LADDR := #LADDR, // filter on the module that just faulted
TINFO := #statTInfo, // task information (input)
AINFO := #statAInfo, // alarm information (output, vendor record)
RETVAL => #statRALRM_RetVal);
Decode the AINFO buffer against the GSDML of the slave (channel number, channel error type, channel error value, vendor extension). Siemens publishes a reference decoder in entry 98210758 ("S7-1500 - Diagnostics in the user program"). The block is on the Siemens support site under Automation Technology -> SIMATIC -> STEP 7 -> Sample projects.
ARRAY[0..255] OF BYTE) to accommodate long records from complex devices. RALRM with a too-small target will return RETVAL 16#80C1.Approach 3: Polling ModuleStates
ModuleStates reads the operational state of every module and sub-module in a given IO system with a single call. The function returns two byte arrays:
-
STATE[x]- 0 = OK, 1 = faulty, 2 = wrong module, 3 = sub-module mismatch, 4 = slot not configured. -
DIAG[x]- bit 0 = channel 0 fault, bit 1 = channel 1 fault, etc.
// SCL - periodic poll from a cyclic OB (e.g. OB 30, OB 35)
#ModuleStates(LADDR := "PN_IO_System_1".IOsystem_HWID,
STATE := #statState[0..31],
DIAG := #statDiag[0..31],
RETVAL => #statRetVal);
FOR #i := 0 TO 31 DO
IF #statState[#i] = 1 THEN
"DiagDB".Slot[#i].Fault := TRUE;
ELSE
"DiagDB".Slot[#i].Fault := FALSE;
END_IF;
END_FOR;
ModuleStates is event-safe: it does not race OB 82, and it can be called from any priority level. Call it from a slow cyclic OB (OB 30, 1 s; OB 35, 100 ms) to refresh an HMI overview screen without flooding the bus.
| RETVAL | Cause | Action |
|---|---|---|
| 16#0000 | OK | Continue |
| 16#80A1 | IO system not configured | Check PROFINET IO system in device view |
| 16#80B1 | HW_ID does not exist | Refresh system constants (compile) |
| 16#80C1 | Output buffer too small | Increase length of STATE/DIAG arrays |
| 16#80C3 | Internal resource busy | Re-call next cycle |
Approach 4: From Logical Address to ModuleState (the Field-Proven Recipe)
The original poster's production requirement is satisfied with a three-step ladder:
- Translate the logical I/O address to a slot number using
LOG2MOD. - Read the entire IO system once with
ModuleStates. - Index into the state array with the slot number from step 1.
This is the minimum code path that gives a single Boolean per arbitrary logical address. The same FB can be instantiated for every module the application wants to supervise, and it scales with no additional code: just change the input address.
The flow above reads a logical I/O address, converts it to a slot number, polls the entire PROFINET station, and indexes the state array to produce a single Boolean. With LOG2MOD + ModuleStates the entire diagnostic primitive lives in a single FB that can be reused across the project.
GEN_DIAG: Producing Vendor-Style Diagnostics for Third-Party Devices
Some third-party PROFINET devices do not push their own diagnostic records. Use GEN_DIAG to synthesise a diagnostic record in the CPU that the HMI and TIA Portal can interpret just like a Siemens-original record. The instruction is part of the S7-1500 extended instruction set and accepts a GEN_DIAG_DB structured data block plus a DIAG_RECORD Variant.
Typical use cases:
- Mapping a PLC-detected soft error (e.g. a calculated value out of range) to a channel fault on a dummy slot.
- Surfacing a HART device warning that the GSDML suppresses.
- Converting a CPU-internal fault (e.g. firmware watchdog) to a PROFINET-readable channel error.
For full signatures and an example application see the TIA Portal help: GEN_DIAG: Generate diagnostics information (S7-1500).
Reading the Same Information on the CPU Display
When the TIA Portal is not available, navigate the S7-1500 front display:
- Select Module on the home screen.
- Open PROFINET I/O (X1).
- Select the Station.
- Select the Slot.
- Open Status -> Module status.
The display shows the same value ModuleStates would return to the user program. Use the display to cross-verify that the BOOL you wired in the program matches what the CPU sees on the wire. Reference: Diagnostics via the display of the S7-1500 CPUs.
Performance and Sizing Notes
| Approach | CPU load | Bus load | Reaction time | Recommended use |
|---|---|---|---|---|
| OB 82 + IO_STATE decode | Negligible | None (event) | < 1 ms from event to program | Safety / fast reaction |
| OB 82 + RALRM | Moderate per call | None | < 1 ms from event to record | Channel-level diagnostics |
| ModuleStates poll | Constant cyclic | None | One OB cycle (e.g. 100 ms) | HMI overviews, dashboards |
| LOG2MOD + ModuleStates | Same as poll | None | One OB cycle | Per-tag Boolean from logical address |
| GEN_DIAG | Per call | None | Immediate | Soft-error mapping |
ModuleStates more than once per scan of the cyclic OB. A 100 ms OB 35 is appropriate for dashboards. Faster rates buy nothing, because the diagnostic buffer in the slave is updated by the device itself, not by polling.Verification Procedure
- Compile the project and check the System constants tab: every expected module and IO system must have a generated HW_ID. Missing constants indicate a misconfigured device view.
- Download to the S7-1500 and go online. Add the diagnostic DB to a Monitor / Modify watch table.
- Force a wire break on a known channel (e.g. remove the field wire on a DI module's first input). OB 82 must fire within one PROFINET update cycle (typically 4 ms).
- Verify the diagnostic DB tag
L1_Mod_Faultgoes TRUE. Note theIO_STATEvalue and confirm it matches the bits documented above for your firmware version. - Reconnect the wire. OB 82 must fire a second time with the cleared-event state. The fault tag must reset.
- On the CPU display, navigate to the same module. The Module status page must read OK.
- Run the Online & Diagnostics -> PROFINET diagnostics view in TIA Portal; the same module must show no error.
If any of the above steps disagree, see the troubleshooting matrix below.
Troubleshooting Matrix
| Symptom | Likely cause | Correction |
|---|---|---|
| OB 82 never fires despite wire break | Channel diagnostics disabled at the device | Device view -> Module parameters -> Diagnostics -> enable Channel diagnostics |
| OB 82 fires but LADDR = 0 | Module added to hardware catalogue but not inserted in the slot | Check the configured assignment table and re-download |
| ModuleStates RETVAL = 16#80A1 | Wrong HW_ID passed (likely the device HW_ID, not the IO system HW_ID) | Use the IO system system constant, not the station constant |
| LOG2MOD returns SLOT = 0, ERR = 1 | Address is in the process image partition that the address is in (constant area) | Confirm the address type in the PLC tag table; pass AREA = 0x81 (input) or 0x82 (output) |
| STATE array too short | Slaves with more slots than the declared array | Increase STATE/DIAG array length, regenerate |
| Fault tag latches on after the event clears | Only the SET branch of OB 82 is implemented | Add the CLEARED branch on bit 0 of IO_STATE |
| GEN_DIAG produces RETVAL 16#80C3 | Target slot already holds a vendor record | Clear the slot with CLR_DIAG before re-generating |
Frequently Asked Questions
Which is faster for module diagnostics on S7-1500, OB82 or ModuleStates?
OB82 is event-driven and reacts within one PROFINET update cycle (typically 1-4 ms). ModuleStates is polled, so its reaction time is bounded by the calling OB (e.g. 100 ms with OB35). Use OB82 for safety and motion; use ModuleStates for HMI overviews and dashboards.
How do I find the hardware identifier (HW_ID) of a module from a logical I/O address?
Use the LOG2MOD instruction under Extended Instructions -> Addressing. Pass LADDR (the I/O byte) and AREA (0x81 for inputs, 0x82 for outputs) to get SLOT and SUBSLOT. Combine with GEO2LOG or LOG2GEO for the full geographic mapping when needed.
Why does my OB82 fault coil stay TRUE after the wire break is fixed?
OB82 is called twice for every event: once on fault and once on cleared. If you only handle the SET case, the coil will latch on. Add a second network that resets the coil when IO_STATE bit 0 is set (module is good).
Can I use ModuleStates with the PROFINET IO system HW_ID, or do I need the device HW_ID?
ModuleStates expects the IO system HW_ID (the parent), not the device HW_ID. The instruction returns the state of every module and sub-module within that IO system in one call. Passing a device HW_ID returns RETVAL 16#80A1.
How do I generate a PROFINET-style diagnostic record from inside the user program for a third-party device?
Use the GEN_DIAG instruction (S7-1500 extended instructions). It accepts a GEN_DIAG_DB structure and a DIAG_RECORD Variant, and pushes a record that WinCC Unified and TIA Portal interpret like a vendor record. See the TIA Portal help for signatures and example code.
Does LOG2MOD work for both inputs and outputs?
Yes. Set the AREA parameter to 0x81 for the process input image, 0x82 for the process output image, 0x01 for direct inputs (PI) and 0x02 for direct outputs (PQ). Mismatching AREA returns ERR = 1 and SLOT = 0.