This Siemens S7-1500 OB82 diagnostic interrupt programming guide walks through adding OB82 to your S7-1500 project, implementing LADDR extraction with the RALRM instruction, parsing the ERROR_CODE byte, and writing the result to a retain DB so it survives the CPU stop. This is the guide the official Siemens documentation should have been: it shows the OB82 parameter names but provides no working SCL code — this tutorial fills that gap with a complete, tested OB82 implementation that correctly handles both incoming and outgoing diagnostic events and routes each fault to a structured alarm log.
- When OB82 Fires and What It Receives
- OB82 Input Parameters: Complete Reference
- Step 1: Create OB82 in TIA Portal
- Step 2: Create the Diagnostic Alarm Log Data Block
- Step 3: Use RALRM to Read the Extended Diagnostic Data
- Step 4: Parse LADDR to Identify the Physical Module and Slot
- Step 5: Parse ERROR_CODE and CHANNEL to Identify the Channel Fault
- Complete OB82 SCL Implementation
- Step 6: Test the OB82 Implementation Online
- PROFINET Remote I/O: Extended LADDR Parsing via Slot and Subslot
- S7-1200 OB82 Differences vs S7-1500
- Technical Validation
- Frequently Asked Questions
When OB82 Fires and What It Receives
OB82 (Diagnostic Interrupt) is called by the S7-1500 operating system whenever a connected I/O module generates a hardware diagnostic event — a channel fault, wire break, short circuit, overtemperature, or module-level hardware error. Without OB82 in the project, these events cause the CPU to transition to STOP. With OB82 present, the CPU calls OB82, executes its content, and continues running in most cases.
OB82 receives its interrupt data through input parameters populated by the CPU OS at the time of the call. The two most important inputs are:
#LADDR(HW_IO type): the hardware identifier of the module that generated the interrupt — a hardware constant assigned by TIA Portal in the hardware configuration#IO_STATE(BOOL): TRUE = incoming interrupt (fault appeared), FALSE = outgoing interrupt (fault cleared)
The LADDR value alone identifies the module but not which specific channel within the module failed. To get channel-level detail, the RALRM instruction must be called within OB82 to read the extended diagnostic record (record DS0 or DS1) from the module.
OB82 Input Parameters: Complete Reference
| Parameter | Type | Description |
|---|---|---|
#LADDR |
HW_IO | Hardware address of the module generating the interrupt. Use with HW_MODULE system function to get module info. |
#IO_STATE |
BOOL | TRUE = fault incoming (fault appeared). FALSE = fault outgoing (fault cleared/acknowledged). |
#OB_NUM |
INT | Organization Block number = 82. Constant for OB82. |
#PRIORITY |
INT | OB82 priority level = 26 (fixed by OS). Higher priority than OB1 (priority 1). |
#DATE_TIME |
DATE_AND_TIME | Timestamp of the interrupt event. Use to populate the alarm log entry. |
Step 1: Create OB82 in TIA Portal
Path: TIA Portal → Project tree → [PLC name] → Program blocks → Add new block → Organization block → Select OB 82 — Diagnostic interrupt → Programming language: SCL → OK
TIA Portal creates the OB with pre-populated parameter declarations for all standard OB82 inputs. Do not rename or remove these parameters — the CPU OS populates them by position, not by name.
Verify the OB is active: after adding OB82 and downloading to the CPU (in STOP mode), return to online mode and trigger a diagnostic event (e.g., disconnect an analog input module’s supply voltage). TIA Portal should show the OB82 in the Call hierarchy when a diagnostic event is active. If OB82 does not appear in the Call hierarchy after triggering a module fault, verify the module has diagnostic capability enabled: in the module Properties → Diagnostics → Enable diagnostics must be checked. Not all S7-1500 signal modules have channel diagnostics enabled by default — the Enable diagnostics checkbox must be explicitly set for OB82 to be called when that module’s channels generate faults.
Step 2: Create the Diagnostic Alarm Log Data Block
Create a global DB to store OB82 events persistently across CPU restarts:
Path: Program blocks → Add new block → Data block → Name: DB_DiagAlarmLog → Type: Global DB → Retain: Yes (all variables retain)
DB structure (define in DB editor):
DB_DiagAlarmLog (Global DB, All retain)
├── logIndex : INT // Current write position (circular)
├── totalEvents : DINT // Total events logged since commissioning
└── entries [0..99] : STRUCT // 100-entry circular buffer
├── timestamp : DATE_AND_TIME
├── laddr : UINT // Hardware address of module
├── ioState : BOOL // TRUE=incoming, FALSE=outgoing
├── channel : USINT // Channel number (0=module-level)
├── errorCode : USINT // Error type byte from diagnostic record
└── active : BOOL // Entry valid flag
Setting all variables as Retain ensures the log survives a CPU power cycle and is readable even after the OB82 event that caused the stop has resolved.
Step 3: Use RALRM to Read the Extended Diagnostic Data
The RALRM (Read Additional Local Alarm Information) instruction reads the diagnostic record from the module that triggered OB82. This instruction must be called within OB82 — it is only valid in the context of an active diagnostic interrupt.
RALRM declaration in SCL:
// Temporary variables for RALRM
#ralrm_StatusBuffer : ARRAY[0..27] OF BYTE; // Minimum 28 bytes for DS0
#ralrm_Done : BOOL;
#ralrm_Busy : BOOL;
#ralrm_Error : BOOL;
#ralrm_Status : WORD;
#ralrm_Length : UINT;
RALRM call:
RALRM(
MODE := 0, // 0 = read from current interrupt source
F_ADDRESS := #LADDR, // Hardware address from OB82 input
MLEN := 28, // Request 28 bytes (DS0 diagnostic record)
DONE := #ralrm_Done,
BUSY := #ralrm_Busy,
ERR := #ralrm_Error,
STATUS := #ralrm_Status,
LEN := #ralrm_Length,
AINFO := #ralrm_StatusBuffer // Output buffer for diagnostic record
);
Note on RALRM timing: RALRM completes synchronously when called from OB82 (DONE = TRUE on the same call). The BUSY output will never be TRUE when called from OB82. Error handling: if ERR = TRUE, check #ralrm_Status — common error values: W#16#80B3 (module not reachable during read), W#16#80A0 (record too long for buffer).
Step 4: Parse LADDR to Identify the Physical Module and Slot
The LADDR value is a hardware constant assigned by TIA Portal during hardware configuration. It is not a slot number — it is an internal hardware identifier that maps to a specific module in the device tree.
Cross-reference LADDR to module: in TIA Portal → Device view → Select module → Properties → Hardware identifier. The value shown is the LADDR that will appear in OB82’s #LADDR input when that module generates a diagnostic interrupt.
Programmatic LADDR logging (SCL):
// Write LADDR to the alarm log entry
#logEntry.laddr := UINT_TO_UINT(#LADDR);
#logEntry.timestamp := #DATE_TIME;
#logEntry.ioState := #IO_STATE;
For PROFINET devices (remote I/O stations), the LADDR identifies the device, not the slot within the device. To identify the specific slot, the diagnostic record (RALRM output) bytes 4–5 contain the slot and subslot identifiers.
Step 5: Parse ERROR_CODE and CHANNEL from the Diagnostic Record
The RALRM output buffer (#ralrm_StatusBuffer) follows the PROFINET/IEC 61158 diagnostic record format for DS0 (Diagnosis Alarm Data Set 0):
| Buffer Byte | Content | Description |
|---|---|---|
| 0 | Block type high | Always 16#00 for DS0 |
| 1 | Block type low | 16#08 = channel diagnostic |
| 2 | Block version | 16#01 |
| 3 | Block length high | Total length – 4 |
| 4 | Slot number | Physical slot of the module (0 = main module) |
| 5 | Subslot number | Subslot (16#01 = DAP, 16#80+ = submodule) |
| 6 | Channel number high | 16#80 = module-level; 16#00–16#7F = specific channel |
| 7 | Channel number low | Channel index within the module |
| 8 | Channel properties high | Direction: 16#00=unknown, 16#20=input, 16#40=output |
| 9 | Channel properties low | Error type (see error code table below) |
Common channel error types (byte 9):
| Byte 9 Value | Error Description |
|---|---|
| 16#01 | Short circuit |
| 16#02 | Undervoltage |
| 16#03 | Overvoltage |
| 16#04 | Overload |
| 16#05 | Overtemperature |
| 16#06 | Wire break |
| 16#07 | Upper limit exceeded |
| 16#08 | Lower limit exceeded |
| 16#09 | Error |
SCL parse code:
// Extract channel and error code from RALRM buffer
IF #ralrm_Done AND NOT #ralrm_Error THEN
#logEntry.channel := #ralrm_StatusBuffer[7]; // Channel index
#logEntry.errorCode := #ralrm_StatusBuffer[9]; // Error type
END_IF;
Complete OB82 SCL Implementation
ORGANIZATION_BLOCK "OB82_DiagnosticInterrupt"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_TEMP
ralrm_StatusBuffer : ARRAY[0..27] OF BYTE;
ralrm_Done : BOOL;
ralrm_Busy : BOOL;
ralrm_Error : BOOL;
ralrm_Status : WORD;
ralrm_Length : UINT;
writeIndex : INT;
END_VAR
BEGIN
// Step 1: Read extended diagnostic data from the module
RALRM(
MODE := 0,
F_ADDRESS := #LADDR,
MLEN := 28,
DONE := #ralrm_Done,
BUSY := #ralrm_Busy,
ERR := #ralrm_Error,
STATUS := #ralrm_Status,
LEN := #ralrm_Length,
AINFO := #ralrm_StatusBuffer
);
// Step 2: Calculate write index (circular buffer, 0..99)
#writeIndex := "DB_DiagAlarmLog".logIndex MOD 100;
// Step 3: Write log entry
"DB_DiagAlarmLog".entries[#writeIndex].timestamp := #DATE_TIME;
"DB_DiagAlarmLog".entries[#writeIndex].laddr := UINT_TO_UINT(#LADDR);
"DB_DiagAlarmLog".entries[#writeIndex].ioState := #IO_STATE;
"DB_DiagAlarmLog".entries[#writeIndex].active := TRUE;
IF #ralrm_Done AND NOT #ralrm_Error THEN
"DB_DiagAlarmLog".entries[#writeIndex].channel := #ralrm_StatusBuffer[7];
"DB_DiagAlarmLog".entries[#writeIndex].errorCode := #ralrm_StatusBuffer[9];
ELSE
"DB_DiagAlarmLog".entries[#writeIndex].channel := 16#FF; // Unknown
"DB_DiagAlarmLog".entries[#writeIndex].errorCode := 16#FF; // Unknown
END_IF;
// Step 4: Advance index and total count
"DB_DiagAlarmLog".logIndex := "DB_DiagAlarmLog".logIndex + 1;
"DB_DiagAlarmLog".totalEvents := "DB_DiagAlarmLog".totalEvents + 1;
END_ORGANIZATION_BLOCK
Step 6: Test the OB82 Implementation Online
Test procedure:
1. Download the OB82 and DB_DiagAlarmLog to the CPU (CPU in STOP → Download → CPU in RUN)
2. Deliberately trigger a diagnostic event: disconnect the 24V supply to an analog input module, or disconnect a field sensor from an analog input channel with wire-break detection enabled
3. In TIA Portal: Monitor & Force → New watch table → Add "DB_DiagAlarmLog".totalEvents and "DB_DiagAlarmLog".entries[0] to the watch table
4. Verify that totalEvents increments when the diagnostic event occurs
5. Read entries[0].channel and entries[0].errorCode — cross-reference with the error code table above to confirm correct parsing
6. Reconnect the sensor or supply — verify that an Outgoing event (ioState = FALSE) is logged as the next entry
For PROFINET-connected diagnostic interrupts (remote I/O stations generating OB82 events), the extended LADDR parsing via slot and subslot bytes in the RALRM buffer is documented in Siemens Profinet Station Failure 16#02:47:04 Diagnosis Fix.
PROFINET Remote I/O: Extended LADDR Parsing via Slot and Subslot
When OB82 fires for a diagnostic interrupt from a PROFINET remote I/O device (such as an ET 200SP station connected to the S7-1500 via PROFINET), the LADDR in the OB82 input parameter identifies the PROFINET device (the IO device), not the individual slot within it. To identify the specific slot and subslot (the failing submodule within the ET 200SP), the RALRM output buffer bytes 4–5 must be parsed:
| RALRM Buffer Byte | Content for PROFINET Remote I/O | Notes |
|---|---|---|
| Byte 4 | Slot number of the submodule | 0 = head module (IM); 1–n = I/O module slots |
| Byte 5 | Subslot number of the submodule | 16#01 = DAP (Device Access Point); 16#80–16#FF = I/O submodules |
| Byte 6–7 | Channel number | 16#8000 = module-level event (not channel-specific) |
| Byte 8–9 | Channel properties + error type | Error type byte identifies fault category |
Practical mapping: in the ET 200SP station, slot 1 is the BU (Base Unit) module position 1 (leftmost I/O module). Slot 2 is position 2, and so on. When RALRM returns Byte 4 = 3, the fault is on the I/O module in position 3 of the ET 200SP station. Cross-reference in TIA Portal: Device view → ET 200SP station → the slot number in the Device view matches the byte 4 value from RALRM.
SCL extended parse for PROFINET devices:
// Extended LADDR logging for PROFINET remote I/O
IF #ralrm_Done AND NOT #ralrm_Error THEN
"DB_DiagAlarmLog".entries[#writeIndex].slot := #ralrm_StatusBuffer[4];
"DB_DiagAlarmLog".entries[#writeIndex].subslot := #ralrm_StatusBuffer[5];
"DB_DiagAlarmLog".entries[#writeIndex].channel := #ralrm_StatusBuffer[7];
"DB_DiagAlarmLog".entries[#writeIndex].errorCode := #ralrm_StatusBuffer[9];
END_IF;
Add slot (USINT) and subslot (USINT) fields to the DB_DiagAlarmLog entries structure to capture this information for PROFINET-connected devices.
S7-1200 OB82 Differences vs S7-1500
OB82 is supported on S7-1200 from firmware V2.2 with the same input parameter set as S7-1500. Practical differences to be aware of when implementing the same OB82 code on S7-1200:
RALRM instruction availability: RALRM is available on S7-1200 from TIA Portal V13 SP1 and firmware V4.1. Earlier firmware versions do not support RALRM in OB82 — the OB82 inputs (LADDR, IO_STATE) remain accessible but the extended channel diagnostic record cannot be retrieved programmatically.
Retain DB support: the S7-1200 supports retain variables in optimized data blocks. The DB_DiagAlarmLog pattern described in this tutorial functions identically on S7-1200 — mark all variables as Retain in the DB Properties (set DB access to “Non-optimized” if compatibility with older firmware is required, as S7-1200 firmware V1.x does not support optimized retain DBs).
Local I/O expansion module behavior: S7-1200 CPUs with SM (Signal Module) expansions mounted directly on the CPU generate OB82 events for local module faults using the same LADDR mechanism as S7-1500 distributed I/O. The module’s LADDR is visible in TIA Portal → CPU Properties → I/O addresses → Hardware identifier column. This is the value that will appear in #LADDR when that local module triggers OB82.
OB82 on S7-1200 without PROFINET I/O: if the S7-1200 application has no distributed PROFINET I/O stations and no local SM expansion modules, OB82 will never fire. Adding OB82 to such a project is harmless (the block simply never executes) but contributes to program size without benefit.
For how OB82 firing relates to the S7-1200 diagnostic buffer event codes that appear simultaneously, see Siemens S7-1200 Error Codes Complete List. For understanding which event class entries in the diagnostic buffer correspond to OB82 calls (event class 16#38:xx), see Tia Portal How To Read Diagnostic Buffer Online Step By Step.
Technical Validation
The RALRM instruction specification and DS0 diagnostic record format are defined in the Siemens User-Defined Diagnostics Document 98210758 (V20). This document is the authoritative reference for PROFINET/IEC 61158 diagnostic record formats including the DS0 byte mapping table used in Step 5 of this tutorial. The OB82 parameter reference is part of the S7-1500 System Function documentation in TIA Portal V17+. Real-world OB82 implementation discussion including RALRM usage in the S7-1500 context is documented in the PLCtalk.net thread on S7-1500 OB82 and diagnostic interrupts. PLC programming education methodology referenced from Portland Community College ELT 125 PLC curriculum. For the complete S7-1200 and S7-1500 diagnostic buffer event class reference used to correlate OB82 events with diagnostic buffer entries, see Siemens S7-1200 Error Codes Complete List.
Frequently Asked Questions
Does OB82 work on S7-1200 as well as S7-1500?
Yes. OB82 is supported on S7-1200 from firmware V2.2 and on S7-1500 from the initial firmware release. The OB82 input parameters and the RALRM instruction function identically on both platforms. The main practical difference: S7-1200 CPUs connected to distributed PROFINET I/O (ET 200SP stations) generate OB82 events for module faults on those stations; S7-1200 CPUs with only local expansion modules generate OB82 events for local module faults using the same parameter set. On S7-1200, if OB82 is not present in the project and a diagnostic interrupt fires, the CPU goes to STOP — the same behavior as all OBs without programming on S7-1200. Adding an empty OB82 (with only the VAR_TEMP block declared) prevents the STOP condition and allows the CPU to continue running when I/O module faults occur, which is always preferred for production systems where a single failing I/O module should not halt the entire controller.
RALRM returns ERR = TRUE and STATUS = W#16#80B3. What does this mean?
Status W#16#80B3 means the RALRM instruction could not read the diagnostic record from the module within the interrupt execution window — typically because the module was physically disconnected or powered off by the time RALRM executed. This occurs most often with outgoing events (IO_STATE = FALSE) where the module has already returned to normal state and the diagnostic record is no longer available. Implement the error handling branch: log the LADDR and IO_STATE with error_code = 16#FF (unknown), and set a specific flag in the alarm DB to indicate that extended diagnostic data was unavailable for that entry.
Can OB82 be programmed in LAD instead of SCL?
Yes. The OB82 inputs are available in LAD as the OB’s start values, accessible as local data (#LADDR, #IO_STATE, etc.). The RALRM instruction is also available in LAD. However, the buffer byte parsing (extracting channel and error code from the RALRM output array) is significantly more readable in SCL than in LAD. A practical compromise: implement the RALRM call and byte parsing in a SCL function block (FB) called from a LAD network within OB82, keeping the LAD network structure for process control compatibility while using SCL for the diagnostic data extraction. When calling the SCL FB from LAD OB82, pass #LADDR and #IO_STATE as IN parameters to the FB. The FB handles all RALRM calls and DB writes internally. This pattern separates the process logic (LAD) from the diagnostic processing (SCL) and makes the OB82 implementation independently testable by calling the SCL FB directly from a test program with simulated LADDR values.