Troubleshooting OB86 FLT_ID 16#CD on ET200S-ET200SP PROFINET
1. Problem Overview: OB86 Stuck on 16#CD Instead of 16#CB
When an ET200S CPU (IM151-8 PN/DP family) is connected to a remote ET200SP station over PROFINET IO, the application expects OB86 to fire with FLT_ID = B#16#CB the moment the IO device disappears from the network. In normal operation this is the case: pulling the PROFINET cable while both controller and device remain powered triggers an incoming event (EV_CLASS = B#16#38) with FLT_ID = B#16#CB (station failure). When the cable is plugged back in, OB86 fires the outgoing event (EV_CLASS = B#16#39) with the same FLT_ID, indicating the failure has cleared.
A specific scenario breaks this pattern and is the source of the field symptom reported on a TIA Portal V11 project:
- ET200S CPU remains powered on (RUN or STOP).
- ET200SP station is switched OFF (24 V removed from the interface module).
- The PROFINET cable is disconnected and reconnected at the ET200SP side.
- OB86 fires with
EV_CLASS = B#16#38andFLT_ID = B#16#CD(configuration difference), not the expectedB#16#CB(station failure). - The CPU never reports the
B#16#CB(failure) orB#16#39(outgoing) events until the cable is unplugged and plugged a second time after the device has been powered up.
The PLC cannot be used to monitor the ET200SP station reliably with OB86 alone in this configuration. This article documents why this happens, what each FLT_ID actually means on PROFINET, and the available mitigations - from event buffering in OB86 to PROFINET diagnostic reads via SFB52 RDREC and SFC51 RDSYSST.
2. OB86 Local Data Layout and Event Codes
OB86 is the rack-failure / distributed-I/O-failure OB. According to the Siemens reference, the start information of OB86 contains the following temporary variables that the firmware pre-fills before the OB is entered:
| Variable | Type | Description |
|---|---|---|
| OB86_EV_CLASS | BYTE | Event class: B#16#38 (incoming, OB entered) or B#16#39 (outgoing, OB completed / fault cleared) |
| OB86_FLT_ID | BYTE | Fault identifier (see Section 3) |
| OB86_PRIORITY | BYTE | Priority class - default 2 in RUN, may be 26 in STARTUP |
| OB86_OB_NUMBR | BYTE | OB number (always 86) |
| OB86_RESERVED_1 | BYTE | Reserved |
| OB86_IO_FLAG | BYTE | I/O flag: B#16#54 = input, B#16#55 = output |
| OB86_MDL_ADDR | WORD | Logical base address of the master / affected PROFINET IO system |
| OB86_ZINFO | WORD | Additional information - on PROFINET: device number 1-255 |
| OB86_ZINFO_1 | DWORD | Slot / module identifier |
| OB86_ZINFO_2 | DWORD | Module status / vendor ID |
| OB86_ZINFO_3 | DWORD | Device identification (vendor ID + device ID) |
For PROFINET IO, OB86_MDL_ADDR returns the HW identifier of the affected PROFINET IO system or station, and OB86_ZINFO returns the device number (1-255). OB86_ZINFO_1 carries the slot number. The combination of these three values uniquely identifies a station/slot pair and is the only reliable way to distinguish a missing device from a configuration mismatch.
3. EV_CLASS and FLT_ID Code Reference
The two bytes most engineers key on are EV_CLASS and FLT_ID. The complete set of FLT_ID values that can appear in OB86 on a PROFINET IO system is shown below. Codes are taken from the SIMATIC S7-300/400 CPU reference manual; verify against the manual that ships with your specific CPU firmware version.
| EV_CLASS | FLT_ID | Meaning | Typical trigger |
|---|---|---|---|
| B#16#38 | B#16#C1 | PROFINET IO system failure | PN controller side network down |
| B#16#38 | B#16#C3 | PROFINET station failure (legacy) | PROFIBUS DP or older PROFINET device drop |
| B#16#38 | B#16#C5 | PROFINET slot / submodule failure | Module pulled from a powered station |
| B#16#38 | B#16#CB | PROFINET interface module failure | ET200SP head station lost from an established AR |
| B#16#38 | B#16#CD | Configuration difference (expected != actual) | Configured device missing at scan time, topology mismatch |
| B#16#39 | B#16#C2 | PROFINET IO system return | Controller-side network restored |
| B#16#39 | B#16#C4 | PROFINET station return (legacy) | Older PROFINET device reappears |
| B#16#39 | B#16#C6 | PROFINET slot / submodule return | Submodule reinserted |
| B#16#39 | B#16#CC | PROFINET interface module return | ET200SP head station powered back up |
| B#16#39 | B#16#CE | Configuration difference cleared | Topology now matches the project |
Observe that B#16#CD is paired with an outgoing event of B#16#CE, not B#16#CB/B#16#CC. This is the source of the symptom reported in the field: a station that was simply not powered cannot report "failure" because the PROFINET stack has never seen it answer. The controller reports a configuration mismatch instead.
FLT_ID = B#16#CD because the configured device is unreachable. Only when the ET200SP head module is powered on does the second cable pull generate the expected B#16#CB / B#16#CC sequence.4. Root Cause: Why OB86 Reports 16#CD Instead of 16#CB
The PROFINET IO controller inside the ET200S CPU maintains an Application Relationship (AR) state machine for every configured device. The relevant states are:
- Expected - device configured in TIA Portal, not yet seen on the wire.
- Discovering - DCP identify frames answered, AR being negotiated.
- Established - cyclic data exchange running.
- Failure - watchdog timeout on the established AR.
- Return - AR re-established.
When the ET200SP is unpowered, the controller sits in the Expected state (or a passive "wait for identify" substate) and never builds an AR. Pulling the cable at this point is invisible to the controller at the AR layer - the link LED on the CPU port may indicate link loss, but the AR was never active, so OB86_FLT_ID does not move to B#16#CB. Re-plugging the cable prompts a re-scan that finds no device with the configured name, which the stack reports as a configuration difference (B#16#CD) rather than a station failure (B#16#CB).
Powering the ET200SP head module up causes the device to respond to DCP, the AR to be built, and from that moment onward the controller is in a state where it can distinguish failure from configuration. At that point, removing the cable triggers B#16#CB, restoring it triggers B#16#CC.
5. Verifying PROFINET Configuration in TIA Portal
Before modifying the OB86 program, validate the engineering view of the project:
- Open the PROFINET topology view in TIA Portal. Confirm the ET200SP station has the correct PROFINET device name assigned (Online > Accessible nodes > Assign PROFINET device name).
- Compare the configured device number to the actual ring/line position. PROFINET device numbers 1-255 must be unique on the subnet.
- Verify that the ET200SP head module is configured with the right catalog version. ET200SP IM 155-6 PN ST, HF and HS variants differ in supported diagnostics. Mismatch with the configured module version triggers
B#16#CDat every restart. - In the device properties, set "Startup behavior > Comparison preset to actual configuration" to "From compatible partner module" or "From configured module" - never to "From slot 0" if the slot is empty.
- Compile and download the hardware configuration. A stale PLC that still uses an old HW identifier will not match the renamed device and will keep producing
B#16#CDevents.
6. Implementing a Robust OB86 with Event Buffering
OB86 may be entered multiple times within a single second (e.g., a flapping station). To avoid losing events, buffer every entry into a ring DB keyed on a timestamp and MDL_ADDR. The pattern below uses a single FB and is written in Structured Text (SCL), which TIA Portal V11 supports natively for new function blocks.
FUNCTION_BLOCK "FB_OB86_Logger"
VAR
sidx : INT := 0; // ring slot index
cnt : DINT := 0; // total events seen
END_VAR
BEGIN
// 1. Always save the event first - never overwrite blindly
"DB_OB86_Log".Event[cnt MOD 16].EV_CLASS := OB86_EV_CLASS;
"DB_OB86_Log".Event[cnt MOD 16].FLT_ID := OB86_FLT_ID;
"DB_OB86_Log".Event[cnt MOD 16].MDL_ADDR := OB86_MDL_ADDR;
"DB_OB86_Log".Event[cnt MOD 16].ZINFO := OB86_ZINFO;
"DB_OB86_Log".Event[cnt MOD 16].TIMESTAMP := RD_SYS_T(LO_TOD#0s);
cnt := cnt + 1;
// 2. Trigger application logic only on the (EV_CLASS, FLT_ID) pair you care about
IF OB86_EV_CLASS = B#16#38 AND OB86_FLT_ID = B#16#CB THEN
"DB_OB86_Log".Station[OB86_MDL_ADDR].Lost := TRUE;
ELSIF OB86_EV_CLASS = B#16#39 AND OB86_FLT_ID = B#16#CC THEN
"DB_OB86_Log".Station[OB86_MDL_ADDR].Lost := FALSE;
END_IF;
// 3. Treat B#16#CD / B#16#CE as a soft "configuration drift" alarm
IF OB86_FLT_ID = B#16#CD THEN
"DB_OB86_Log".LastConfigMismatch := OB86_MDL_ADDR;
END_IF;
END_FUNCTION_BLOCK
Notes on the snippet:
- Use the standard OB86 temporary variables that the firmware pre-fills; do not redeclare them by hand.
- The ring has 16 slots. With 1 s resolution from
RD_SYS_T, this gives 16 s of history, which is enough to catch cable flaps that the human eye misses. - The logger is the only call inside OB86. OB86 is non-preemptive: nothing else will run until OB86 returns, so keep the body short.
WR_PARM with the wrong record), the firmware will skip the OB at startup priority 26. In TIA Portal V11 this can be diagnosed by opening the CPU diagnostic buffer and looking for the entry "OB86 priority error".7. Reading ET200SP Slot Diagnostics with SFB52 RDREC
When OB86 only gives you B#16#CD/B#16#CE, read the diagnostic record of the affected station to know which slot is misbehaving. SFB52 RDREC is the only standard tool to do this from PLC code without going through the CPU display. The block signature in S7-300/400 is:
CALL "RDREC" , DB52
REQ := TRUE // edge-triggered; keep TRUE until BUSY goes low
ID := W#16#10C // HW identifier of the ET200SP head module
INDEX := 0 // standard diagnostic record 0
MLEN := 64 // up to 64 bytes of record
VALID := "DB52".RDREC_VALID
BUSY := "DB52".RDREC_BUSY
ERROR := "DB52".RDREC_ERROR
STATUS := "DB52".RDREC_STATUS
LEN := "DB52".RDREC_LEN
RECORD := P#DB 52 DBX 0.0 BYTE 64
END_CALL;
| Parameter | Value for ET200SP | Notes |
|---|---|---|
| ID | HW identifier of the station | Read from the ET200SP device properties in TIA Portal (Project tree > Device properties > System constants). For an ET200SP PN on PROFINET IO system 1 with device number 3, the ID is typically 268 dec. Verify in the system constants table. |
| INDEX | 0 = standard diagnostic; 0x8000 = identifier-related; 0x800A = diagnostic interrupt; 0x802B = port data | For ET200SP modules, INDEX 0 returns the standard record 0 (vendor-specific length up to 64 bytes). Records 0x8000-0x800C are defined by the PROFINET profile. |
| MLEN | 4-234 bytes | Use 4 first to read the standard header (first 4 bytes include the length), then read the full record in a second call. |
| RECORD | DB / area of MLEN bytes | Must be exactly MLEN bytes or longer. TIA Portal V11 warns but still allows shorter areas; V13+ is stricter. |
| STATUS | Standard SFB52 return codes | W#16#0000 = OK; W#16#80A0 = negative acknowledgement; W#16#80A1 = slot does not exist; W#16#80C0 / 80C3 = record not available |
After the read, bytes 0-3 of the record always contain the standard PROFINET header:
- Byte 0 - block type (0x01 = record 0, 0x02 = record 1, 0x03 = record 2, 0xF0 = vendor-specific)
- Byte 1 - reserved / length high
- Bytes 2-3 - length low 16 bits
- Byte 4+ - vendor-specific payload (channel number, error type, LED status)
LEN output tells you how many bytes were actually written.8. Polling System Status Lists via SFC51 RDSYSST
For station-level status without driving a single slot, use SFC51 RDSYSST to read the partial system status lists (SZL). The SZL is the in-CPU database that the diagnostic buffer, the web server, and the HMI all use. The SZL entries that matter for PROFINET are:
| SSL_ID (hex) | Name | What it tells you |
|---|---|---|
| W#16#0131 | Diagnostic status of a station | Aggregate status, single word per device number |
| W#16#0174 | Status of the modules of a PROFINET IO station | One entry per slot: OK / faulty / not present |
| W#16#0424 | Status of the PN interfaces | Up/down for every PN port - used to triangulate cable issues |
| W#16#0F31 | Module diagnostic information (raw) | First 4 bytes mirror the standard PROFINET record 0 |
| W#16#0A91 | PN IO interface parameters | Port link state, speed, autonegotiation |
Example - reading the link status of port 1 of the PROFINET IO system:
CALL "RDSYSST" , DB51
REQ := TRUE
SSL_ID := W#16#0424 // PN interface status
INDEX := 1 // port number
SZL_HEADER := "DB51".HDR
DR := P#DB 51 DBX 0.0 BYTE 32
RET_VAL := "DB51".RV
BUSY := "DB51".BSY
END_CALL;
If RET_VAL returns W#16#7000 (busy) or W#16#0000 (done), the entry was read. A return of W#16#0085 means the entry is dynamic and may not be available during STOP. Combine the link state with OB86 to distinguish "cable yanked" from "device powered off":
- OB86 fires
B#16#CBand SZL 0x0424 = "down" -> cable removed on a running device. - OB86 fires
B#16#CDand SZL 0x0424 = "down" -> device unpowered from boot. - OB86 fires
B#16#CCand SZL 0x0424 = "up" -> device returned and link is alive.
9. CPU Diagnostic Buffer and Online Diagnostics
When OB86 does not fire at all (e.g., during STOP->RUN transition), the diagnostic buffer is the only place the events are recorded. In TIA Portal:
- Online > Online & diagnostics > Diagnostics buffer.
- Filter on "IO controller" and "IO device".
- Look for entries with text "Station failure", "Station return", "Configuration error".
Each entry carries a timestamp accurate to 10 ms, plus the event ID in the format "0xE0xx" or "0xE1xx" (mapped to OB86 FLT_ID). Sample entries the engineer will see in this scenario:
- "Station failure - PROFINET IO device" - corresponds to B#16#C3 / CB.
- "Configuration error - expected configuration does not match actual configuration" - corresponds to B#16#CD.
- "No fault" - OB86 was not entered, so nothing fired at the application level. The buffer will still show the firmware event.
10. ET200SP Power-Up and Station-Return Sequencing
PROFINET follows a strict startup sequence. For an ET200SP IM 155-6 PN HF (or HS) head module, the controller expects:
- DCP identify (NameOfStation assignment).
- AR establishment (Connect request -> Connect response).
- Cyclic I/O data exchange.
- Alarm handshake (Diagnostic alarms if OB82 is loaded).
If step 1 or 2 fails (e.g., the head module is still in POST), the controller aborts the AR and reports B#16#CD. The AR is then re-attempted at the next device-scan cycle (default 1 s for ET200SP HF, configurable down to 250 ms). The engineer can therefore expect:
- t = 0 ms - power ON 24 V at the ET200SP.
- t approx 1.5-3 s - IM 155-6 PN is ready, DCP responds.
- t approx 3.0-4.0 s - AR established, cyclic data exchange starts.
-
t approx 4.0-4.5 s - OB86 fires with
EV_CLASS = B#16#39,FLT_ID = B#16#CE(configuration difference cleared) orB#16#CC(interface module return), depending on whether the head module matched the configured version exactly.
The window where the engineer can see B#16#CD is therefore at most 1 s to 4 s. Anything longer usually means a name mismatch, wrong GSDML, or a defective port on the switch. If the time exceeds 10 s, swap the patch cable and check the switch port LED state via SZL 0x0424.
11. Verification and Commissioning Checklist
Before the system can be handed over, run and log the following checks:
-
Power ON test: Power on PLC and ET200SP simultaneously. Within 5 s, OB86 must report
B#16#CEorB#16#CC. The diagnostic buffer must show a "station return" event. -
Cable pull test: With both devices powered, pull the PROFINET cable. OB86 must report
B#16#CBwithin 1 s. Re-plug and verify OB86 reportsB#16#CCwithin 1 s. Repeat 10 times to catch flapping. -
Powered-off device test: Power off the ET200SP. Wait 30 s. OB86 must report either
B#16#CD(configuration difference) or, in newer firmware,B#16#CBwith a delay. Pulling the cable at this point must not produce an additionalB#16#CBevent. - Stop->Run test: Stop the CPU, leave ET200SP off, restart CPU. OB86 must NOT fire. Verify that the application sees the station as "missing" through the IO system status bits (e.g., quality flag in the process image or SZL 0x0174).
-
SFB52 RDREC sanity test: With the device present, call RDREC with INDEX = 0.
STATUSmust be 0 andLENmust be greater than 4. With the device powered off, the call must returnSTATUS = W#16#80A0orW#16#80A1within 1 s. - SFC51 RDSYSST link test: With the device powered, SZL 0x0424 INDEX 1 must return LINK = up. With the device powered off, it must return LINK = down. The application uses this to disambiguate a powered-off station from a cable break.
- Diagnostic buffer dump: Save the buffer as a .bin file and attach it to the commissioning report.
- Web server: If the CPU has a web server, enable it and verify the diagnostic page mirrors the buffer.
B#16#CD during normal operation. If B#16#CD is observed, treat it as a configuration or firmware mismatch and resolve it before commissioning the IO. Acceptance is only granted when OB86 logs zero B#16#CD events across a full power-cycle test.12. Frequently Asked Questions
Why does OB86 show FLT_ID 16#CD instead of 16#CB when my ET200SP is off?
The PROFINET IO controller in the CPU distinguishes between a station that was present and has gone away (B#16#CB) and a station that was never reachable because the head module is unpowered (B#16#CD - configuration difference). The AR was never established, so there is nothing to report as a failure. Power up the ET200SP and wait for the AR to come up; only then will B#16#CB / B#16#CC appear on subsequent cable events.
How can I tell the difference between a powered-off station and a cable break on a live station?
Check the port link state via SZL 0x0424 with SFC51 RDSYSST. A powered-off device reports the link as "up" (cable is good) and OB86 shows B#16#CD. A cable break reports the link as "down" and OB86 shows B#16#CB. Combining the OB86 event and the link state uniquely identifies both cases.
Which SFB52 RDREC parameters do I use for an ET200SP station?
Set ID to the HW identifier of the ET200SP head module (visible in the system constants of the TIA Portal project), INDEX to 0 for the standard diagnostic record, and MLEN to 64 bytes to cover the largest standard record. For channel diagnostics, set INDEX to 0x800A and MLEN to 234 bytes. STATUS returns W#16#0000 on success, W#16#80A0 / 80A1 / 80C0 / 80C3 on common errors.
Is SFC51 RDSYSST still usable on an S7-300 CPU running TIA Portal V11?
Yes. SFC51 is a standard CPU function and is available in every S7-300 CPU from firmware V2.x onward. TIA Portal V11 places it in the standard library; drag it from "Program elements > Libraries > Standard Library > System Function Blocks" onto a call block. Inputs are REQ, SSL_ID, INDEX, SZL_HEADER, DR, RET_VAL, BUSY.
Why is OB86 not called at all when the CPU transitions from STOP to RUN?
OB86 reports faults detected during RUN. A device that was already missing when the CPU entered RUN is reflected in the IO system status table (process image quality bits) but does not fire OB86 because the controller has no AR to report against. Use the SZL 0x0174 via SFC51 RDSYSST, or RDREC on the head module, to detect the missing device on application startup.
Can I use DIS_IRT to mask the 16#CD event and rely on a different mechanism?
Yes, but only on OB8x family interrupts. DIS_IRT disables a specific interrupt (OB40-OB47, OB82, OB83, OB86) for a given logical address. For an OB86 station-failure event on a powered-off device, calling DIS_IRT(MODE := 0, OB_NR := 86, ...) suppresses the event entirely. This is acceptable when the application does not need to react to a non-running head module. The drawback is that ENA_IRT must be called to re-enable OB86, and any genuine failure will be masked until the application remembers to re-enable the interrupt. Reserve this for HMI/scada paths that consume SZL 0x0174 instead of OB86.