Configuring S7-400H CPU Validity: SFC51 SZL W#16#0071 Reference

David Krause26 min read
S7-400SiemensTechnical Reference
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

Overview of S7-400H CPU Validity Diagnostics

The SIMATIC S7-400H is Siemens' high-availability (Hochverfügbar) fault-tolerant PLC platform that pairs two identical CPUs in a hot-standby configuration. Each CPU independently executes the user program and synchronizes its state with the partner through fiber-optic redundancy links. The CPU validity bits reported through SZL W#16#xy71 are the lowest-level heartbeat that tells the application program which redundancy partner's diagnostic snapshot can be trusted at any given moment.

System function block SFC51 "SYSST" (Read SZL) is the canonical method for retrieving this data from any S7-400/H CPU, and SZL W#16#xy71 is the dedicated system status list for H-system module and CPU status. This reference documents the structure of that SZL, the meaning of the B#16#01 / B#16#02 / B#16#03 validity bytes, the operating-state (Betriebszustand, BZ) encoding from W#16#0001 through W#16#000F, and the engineering consequences of consuming invalid data downstream.

Scope: This document applies to STEP 7 V5.5 and the legacy S7-400H CPU families (CPU 412-3H, 414-4H, 416-4H, 417-4H). Equivalent functionality in TIA Portal is exposed through the H-CPU device diagnostics and the RD_SINFO/RD_SST instructions; the SFC51/SZL interface remains valid in mixed environments and is the only supported path on classic S7-400H firmware below V6.0.

S7-400H Redundancy Architecture and Diagnostic Sources

An S7-400H station contains two identical CPUs (CPU 0 in rack 0 and CPU 1 in rack 0 or 1 depending on the configuration), each connected to the partner via two redundant fiber-optic synchronization modules. Two synchronization links must be active for full redundancy; a single link results in a Single-Mode warning but operation continues. Each CPU independently reads its own inputs and writes its own outputs; the active (master) CPU owns the I/O bus and the partner remains in hot standby, executing the program but with outputs inhibited.

Three families of diagnostic information are available to the user program:

  1. Local CPU diagnostics – diagnostic buffer, OB-startup information, and standard SZLs (for example W#16#0019 for LED status, W#16#001C for component identification).
  2. H-system diagnostics – SZL W#16#xy71, the topic of this reference, which aggregates redundancy status, CPU validity, and link state.
  3. Module and DP-slave diagnostics – SZLs W#16#xy00 through W#16#xy0A, surfaced as DP diagnostics in OB82 / OB86 / OB122.

The S7-400H system manual, entry ID 1117397, is the canonical document for redundancy-state interpretation. The FAQ 19537149 on Siemens Support is the original reference for SZL W#16#0071 that engineers in the field most commonly cite.

SFC51 "SYSST" and the System Status List (SZL) Mechanism

SFC51 is the system function every S7-400/H user program uses to query the system status list. The declaration in STEP 7 is:

FUNCTION_BLOCK SYSST / SFC51
VAR_INPUT
  REQ    : BOOL;     // start read on rising edge
  SZL_ID : WORD;     // SSL_ID (system status list identifier)
  INDEX  : WORD;     // partial-list index
END_VAR
VAR_OUTPUT
  BUSY   : BOOL;
  SZL_HEADER : STRUCT // length / number of records
    LENTHDR  : WORD;
    N_DR     : WORD;
  END_STRUCT;
  SZL_DATA  : ARRAY[1..464] OF BYTE;  // 232 WORD
  RET_VAL  : INT;
END_VAR

Calling SFC51 places an asynchronous request; the call must be repeated until BUSY goes FALSE. RET_VAL = 0 indicates success, and the header word LENTHDR / N_DR (read as two separate words inside SZL_HEADER.LENTHDR and SZL_HEADER.N_DR) reports the record length and number of records returned. SZL_ID is the SZL number; for S7-400H H-system status the SZL number is decimal 113 (hex 0x71). The INDEX parameter selects the partial list:

SZL_ID (W#16#) Decimal INDEX Description
W#16#0071 113 0 Header / overall H-system status
W#16#0171 113 1 CPU 0 redundancy state record
W#16#0271 113 2 CPU 1 redundancy state record
W#16#0F71 113 15 All partial lists returned sequentially

The "xy" in W#16#xy71 is the partial-list selector. Most production code reads W#16#0071 with INDEX=0 once per OB1 cycle and indexes into SZL_DATA by record offset. SFC51 uses the caller's input buffer for SZL_DATA; that buffer must be at least LENTHDR * N_DR bytes long. SFC51 also returns a 16-bit RET_VAL, not a BOOL – RET_VAL = 0 is success, RET_VAL > 0 is warning, RET_VAL < 0 is error.

SZL W#16#0071 Record Layout for S7-400H

When SFC51 returns SZL W#16#0071 (SZL number 113, partial list 0), it delivers one or more fixed-format records. Each record is 16 bytes long. The byte map is documented in the STEP 7 System and Standard Functions reference manual and reproduced here with field-level annotations:

Offset Length Field Meaning
Byte 0 1 Validity flags Bit-encoded validity for fields in this record. Bit 0 = bz_cpu_0_valid, bit 1 = bz_cpu_1_valid, bit 2 = both CPU states valid (B#16#03 condition).
Byte 1 1 Reserved Reserved, must be 0.
Word 1 (bytes 2-3) 2 bz_cpu_0 Operating state of CPU 0. WORD, value range W#16#0001 ... W#16#000F. Values outside this range are flagged invalid by bit 0 of the validity byte.
Word 2 (bytes 4-5) 2 bz_cpu_1 Operating state of CPU 1. Same encoding as bz_cpu_0.
Byte 6 1 Role / master-reserve 0 = no master assignment, 1 = CPU 0 is master, 2 = CPU 1 is master, 3 = undefined (only valid in single-mode or during link-up).
Byte 7 1 Link status Bit 0 = link 1 OK, bit 1 = link 2 OK, bit 2 = both links OK (redundant), bit 3 = fiber-optic modules present.
Word 3 (bytes 8-9) 2 Reserved Reserved for future expansion.
Word 4 (bytes 10-11) 2 Last partner update tick Time in 10 ms increments since last successful role / program update from partner CPU. 0xFFFF = no update yet.
Word 5 (bytes 12-13) 2 Sync attempts since last success Counter of synchronization retries since last successful link event.
Word 6 (bytes 14-15) 2 Diagnostic counter Increments on every H-system diagnostic event. Useful as a "new event" edge detector.

The validity byte (offset 0) is the most important field for the calling code because it tells the program which of the following fields are trustworthy. The byte is interpreted as a set of three named tokens, which is exactly the source documentation's B#16#01, B#16#02, B#16#03 encoding:

Token Bit mask Set when
B#16#01 (bz_cpu_0 valid) 0x01 The bz_cpu_0 word at offset 2 contains a defined value in the range W#16#0001..W#16#000F. Cleared when CPU 0 has lost power, is in an unrecoverable defect state, or has not yet completed the first diagnostic snapshot after startup.
B#16#02 (bz_cpu_1 valid) 0x02 Same condition for the partner CPU 1. Cleared independently of CPU 0; a defective partner sets B#16#02 = 0 while B#16#01 = 1 remains.
B#16#03 (both CPUs valid) 0x03 Both bz_cpu_0 and bz_cpu_1 are valid. The "fully redundant" condition. Most user programs gate fail-over logic on this token rather than on either bit individually.
Important: The validity bits are not status bits. A cleared bit does not mean "CPU is bad"; it means "the bz_cpu_x word in this record is not trustworthy and must be ignored." Always gate the bz_cpu_x read with its validity bit before using the value in a safety or process-critical path.

BZ Operating State Encoding W#16#0001..W#16#000F

The bz_cpu_0 and bz_cpu_1 words report the operating state of each CPU. Siemens reserves the lower four bits for the state code and the upper twelve bits for vendor-specific extension (treated as zero in current firmware). The full encoding is:

W#16# Decimal State Set by CPU outputs
0001 1 STOP, update from partner pending CPU has just been switched to STOP; outputs disabled, role handshake not yet complete. Inactive
0002 2 STARTUP (cold restart, OB100) Power-up or reset request; CPU executes startup OBs. Per OB100 logic
0003 3 STARTUP (warm restart, OB101) Restart on retained tags. Per OB101 logic
0004 4 RUN Normal cyclic operation, OB1 in scan. Active
0005 5 RUN, partner link-up in progress CPU in RUN but the partner has not yet reached link-up; outputs reflect single-mode behavior. Active (single mode)
0006 6 HOLD Test/debug breakpoint; outputs frozen, scan paused. Frozen
0007 7 Defect (CPU self-test failed) Firmware detected internal fault, CPU is in self-test failure state and may not respond to SZL requests on its own bus. Inactive
0008 8 Defect (redundancy handshake lost) CPU is running but has lost all synchronization with the partner and is now operating as a stand-alone (single) CPU. Outputs are still active. Active (single mode)
0009 9 Link down, partner not reachable Both fiber-optic links broken; CPU is master by default, no partner data is available. Active (single mode)
000A 10 Standby (reserve, link OK) CPU is the standby partner; program is executing, outputs inhibited, fully in sync with master. Inhibited
000B 11 Standby, partner updating Standby CPU is processing an update from the master (role swap in progress). Inhibited
000C 12 Synchronization Initial sync after power-up; both CPUs exchanging role and program state. Inactive
000D 13 Reserved Reserved by Siemens, must be treated as invalid. —
000E 14 Reserved Reserved by Siemens, must be treated as invalid. —
000F 15 NO POWER CPU has no supply voltage or is physically absent. bz_cpu_x validity bit is always 0 in this case. Inactive

Any value outside W#16#0001..W#16#000F must be treated as an invalid snapshot, and the corresponding validity bit (B#16#01 or B#16#02) will be cleared by the firmware to signal that condition. This is the primary defensive check the user program must perform before consuming the bz_cpu_x word.

The following state machine summarizes the transitions and the validity flag behavior. The validity bits are the contract the firmware offers to the application: if the bit is set, the value is trustworthy; if cleared, the application must ignore it.

STOP (0001)outputs offSTARTUP (0002/3)OB100/101RUN (0004)OB1 cyclicSTANDBY (000A)partner masterDEFECT (0007/8)validity = 0NO POWER (000F)validity = 0power-upinit donelink-updefectpower offMRESSTOPvia MRES

SFC51 Error Codes and RET_VAL Diagnostics

When SFC51 reports an error, RET_VAL contains a hex-coded diagnostic word. The most common values are:

RET_VAL (W#16#) Meaning Typical cause Recommended action
0000 No error, SZL_DATA valid. Successful read. None; consume SZL_HEADER and SZL_DATA.
0080 Header retrieval not yet complete; call again. First call to a new SZL_ID, firmware is preparing the data. Poll SFC51 until BUSY = 0; do not read SZL_DATA yet.
0081 Data retrieval not yet complete; call again. Subsequent call to same SZL_ID; firmware is still building the data. Same as 0080; continue polling.
7000 First call with REQ = 0; no read initiated. Calling without rising edge on REQ. Trigger REQ with a one-shot pulse.
8090 SZL_ID not supported on this CPU / firmware. SZL W#16#0071 not available on firmware before V3.1 or on non-H CPUs. Verify CPU is an S7-400H type and firmware supports the SZL.
8092 INDEX out of range for the requested SZL. INDEX value not valid for SZL W#16#0071. Confirm INDEX = W#16#0000 or 0x0F for "all".
80A0 Negative acknowledgment while reading from the target CPU. Partner CPU is in NO POWER or DEFECT, target memory area not accessible. Read the validity byte first; if B#16#02 = 0, ignore the call result.
80A1 Negative acknowledgment while writing to the target CPU. Not applicable to SFC51 (read-only) but can appear in SFC51 background diagnostics. Re-run the call after a 1 s delay.
80B0 System error (SZL fetch driver fault). Firmware-level issue, often cleared by STOP/RUN. Cycle the CPU mode switch; if persistent, update firmware.
80B1 Requested SZL_ID not configured. CPU's SZL configuration does not include W#16#0071. Check HW Config → CPU properties → SZL tab; enable if disabled.
Tip: The W#16#80A0 error is the most common in H-system SZL reads. It occurs whenever the partner CPU cannot answer a SZL request. Always check RET_VAL before indexing into SZL_DATA; a stale buffer from a previous successful call is the typical root cause of "ghost" validity data after a partner CPU has been powered down.

Programming Examples: STL, SCL, and Ladder

Three reference implementations of the same logic are presented: STL for compactness, SCL for type-safety, and ladder for visualization in STEP 7. All three consume SFC51 output and expose the bz_cpu_x values and validity tokens as symbolic tags.

STL Implementation (STEP 7 V5.5)

FUNCTION_BLOCK FB_H_SSL_READ
TITLE = 'Read S7-400H SZL W#16#0071 and decode validity'
VERSION : '1.0'

VAR
  sfc51_req  : BOOL := FALSE;       // rising edge trigger
  sfc51_busy : BOOL;
  sfc51_ret  : INT;
  sfc51_hdr  : STRUCT
    LENTHDR  : WORD;                // record length in bytes
    N_DR     : WORD;                // number of records
  END_STRUCT;
  sfc51_data : ARRAY[0..463] OF BYTE;
END_VAR

VAR_TEMP
  rec  : INT;                       // record index
  off  : INT;                       // byte offset
END_VAR

BEGIN
NETWORK 1
      A     "scan_1Hz";              // call once per second
      FP    "M_H_Trigger";
      =     sfc51_req;

NETWORK 2
      CALL SFC51 (
        REQ       := sfc51_req,
        SZL_ID    := W#16#0071,
        INDEX     := W#16#0000,
        BUSY      := sfc51_busy,
        SZL_HEADER:= sfc51_hdr,
        SZL_DATA  := sfc51_data,
        RET_VAL   := sfc51_ret
      );

NETWORK 3
      L     sfc51_ret;
      L     0;
      <>I   ;
      JC    _err;                    // 0x80xx range = SFC51 protocol error

NETWORK 4
      // Walk all records; for H system one record per CPU
      L     sfc51_hdr.N_DR;
      L     0;
      ==I   ;
      JC    _done;

      L     0;
      T     #rec;

LOOP: NOP 0;
      // record offset = rec * LENTHDR
      L     #rec;
      L     sfc51_hdr.LENTHDR;
      *I    ;
      T     #off;

      // byte 0: validity flags
      L     sfc51_data[off + 0];
      T     "DB_H.DBB0_validity";

      // bytes 2-3: bz_cpu_0
      L     sfc51_data[off + 2];
      T     "DB_H.DBB2_bz_cpu0_lo";
      L     sfc51_data[off + 3];
      T     "DB_H.DBB3_bz_cpu0_hi";

      // bytes 4-5: bz_cpu_1
      L     sfc51_data[off + 4];
      T     "DB_H.DBB4_bz_cpu1_lo";
      L     sfc51_data[off + 5];
      T     "DB_H.DBB5_bz_cpu1_hi";

      L     #rec;
      L     1;
      +I    ;
      T     #rec;
      L     sfc51_hdr.N_DR;
      <I    ;
      JC    LOOP;

_done:NOP 0;
      BEU;

_err: SET;
      S     "H_SSL_READ_ERROR";
      BE;
END_FUNCTION_BLOCK

The decoded values can then be consumed in OB1 with a guard pattern:

NETWORK 10
      // Safety gate: only allow role-swap decisions when BOTH bz values are valid
      L     "DB_H.DBB0_validity";
      L     B#16#03;                 // both bits set
      ==I   ;
      =     "H_Both_CPU_Valid";

      A     "H_Both_CPU_Valid";
      JCN   SKIP_FAILOVER;

      // safe to read the master/role field
      L     "DB_H.DBB6_Role";
      L     1;                       // CPU 0 is master
      ==I   ;
      =     "H_CPU0_Is_Master";

SKIP_FAILOVER: NOP 0;

SCL Implementation (TIA Portal / SCL)

FUNCTION_BLOCK FB_H_SSL_READ_SCL
TITLE = 'S7-400H SZL W#16#0071 Reader (SCL)'
{ S7_Optimized_Access := 'FALSE' }
VERSION : '2.0'

VAR
  sSZLHeader : STRUCT
    LENTHDR  : WORD;
    N_DR     : WORD;
  END_STRUCT;
  sSZLData   : ARRAY[0..463] OF BYTE;
  bTrigger   : BOOL;
END_VAR

VAR_OUTPUT
  bz_cpu_0       : WORD;
  bz_cpu_1       : WORD;
  validity_byte  : BYTE;
  bz_cpu_0_valid : BOOL;
  bz_cpu_1_valid : BOOL;
  both_valid     : BOOL;
  bError         : BOOL;
  wErrorCode     : WORD;
END_VAR

VAR_TEMP
  sfc51_busy : BOOL;
  sfc51_ret  : INT;
  iOff       : DINT;
END_VAR

BEGIN
  // Fire SFC51 once per cycle when triggered
  IF bTrigger THEN
    sfc51_ret := SFC51(
      REQ        := TRUE,
      SZL_ID     := W#16#0071,
      INDEX      := W#16#0000,
      BUSY       := sfc51_busy,
      SZL_HEADER := sSZLHeader,
      SZL_DATA   := sSZLData
    );
  END_IF;

  IF sfc51_ret <> 0 THEN
    bError := TRUE;
    RETURN;
  END_IF;

  IF sfc51_busy THEN
    RETURN;  // wait for completion
  END_IF;

  // First record only for a 2-CPU H system
  IF sSZLHeader.N_DR = 0 THEN
    RETURN;
  END_IF;

  iOff := 0;  // rec=0, LENTHDR ignored for first record

  validity_byte  := sSZLData[iOff + 0];
  bz_cpu_0.%B0   := sSZLData[iOff + 2];
  bz_cpu_0.%B1   := sSZLData[iOff + 3];
  bz_cpu_1.%B0   := sSZLData[iOff + 4];
  bz_cpu_1.%B1   := sSZLData[iOff + 5];

  bz_cpu_0_valid := (validity_byte AND B#16#01) <> B#16#00;
  bz_cpu_1_valid := (validity_byte AND B#16#02) <> B#16#00;
  both_valid     := (validity_byte AND B#16#03) =  B#16#03;
  bError         := FALSE;
END_FUNCTION_BLOCK

Ladder Implementation

Network 1:  One-shot SFC51 trigger (rising edge of 1-Hz clock)
  [ scan_1Hz ] --[P|-- ( sSZL_Trigger )

Network 2:  Call SFC51 with H-system SZL ID
  [ sSZL_Trigger ] --[ CALL SFC51
                        REQ    := sSZL_Trigger,
                        SZL_ID := W#16#0071,
                        INDEX  := W#16#0000 ]

Network 3:  Watch BUSY; only consume SZL_DATA on completion
  [ SFC51.BUSY ] --[/]-- ( sSZL_Done )

Network 4:  Read RET_VAL; abort on non-zero
  [ SFC51.RET_VAL ] --[== 0]-- ( sSZL_OK )
  [ sSZL_OK ] --[/]-- ( sSZL_Error )

Network 5:  Move validity byte to a symbolic tag
  [ sSZL_OK ] --[ MOVE sSZLHeader.N_DR -> DB_H.N_DR ]
  [ sSZL_OK ] --[ MOVE sSZLData[0]   -> DB_H.Validity ]

Network 6:  Decode B#16#01 - bz_cpu_0 valid
  [ DB_H.Validity ] --[ AND B#16#01 ]
                   --[ <> 0 ]-- ( DB_H.bz_cpu_0_valid )

Network 7:  Decode B#16#02 - bz_cpu_1 valid
  [ DB_H.Validity ] --[ AND B#16#02 ]
                   --[ <> 0 ]-- ( DB_H.bz_cpu_1_valid )

Network 8:  Decode B#16#03 - both CPUs valid
  [ DB_H.Validity ] --[ AND B#16#03 ]
                   --[ == B#16#03 ]-- ( DB_H.both_valid )

Network 9:  Conditional move of bz_cpu_0 (gated on validity)
  [ DB_H.bz_cpu_0_valid ] --[ MOVE sSZLData[2] -> DB_H.bz_cpu_0.LB ]
  [ DB_H.bz_cpu_0_valid ] --[ MOVE sSZLData[3] -> DB_H.bz_cpu_0.HB ]

Network 10: Conditional move of bz_cpu_1
  [ DB_H.bz_cpu_1_valid ] --[ MOVE sSZLData[4] -> DB_H.bz_cpu_1.LB ]
  [ DB_H.bz_cpu_1_valid ] --[ MOVE sSZLData[5] -> DB_H.bz_cpu_1.HB ]
Code style note: The call to SFC51 is asynchronous on S7-400H. Always use the rising-edge trigger on REQ and poll BUSY; do not assume one call returns immediately. Repeat the call in the same OB1 cycle until BUSY = 0 before consuming SZL_DATA. Using a 100 ms cyclic interrupt (OB35) is the most common commissioning pattern.

Engineering Impact: Why Invalid Data Matters

The user's original question is whether a bz_cpu_x snapshot flagged invalid can affect the system behavior. The answer is yes, in three ways that the application program must defend against.

  1. Process decisions taken on stale or zero-initialized data. If the bz_cpu_x word is treated as RUN (W#16#0004) when the validity bit is 0, the program may continue driving outputs as if the partner is healthy when the partner is actually NO POWER (W#16#000F) or DEFECT (W#16#0007). The SZL firmware will write W#16#0000 (a value outside the defined range, which is itself an invalid marker) into the word when the validity bit is 0, but the application code is responsible for checking the validity bit before trusting the value.
  2. Role-swap logic can fire on partial data. Most H-system programs implement a "primary loses, secondary takes over" routine. If that logic is gated only on bz_cpu_0 == 0007 (DEFECT) and ignores the B#16#01 validity bit, a freshly powered-up secondary CPU that has not yet synchronized will report bz_cpu_0 = 0000 and the program will treat it as a defect, possibly triggering an unnecessary role swap.
  3. Diagnostic buffer entries can flood. Calling SFC51 with SZL_ID = W#16#0071 when the partner CPU is in NO POWER state will return RET_VAL = W#16#80A0 (target CPU does not exist) or, on some firmware versions, a header with N_DR = 0. Code that does not check N_DR or RET_VAL will repeatedly attempt the call and may generate a "SFC51 call without active SZL" diagnostic event on every OB1 cycle.

The defensive pattern in production code is therefore: read the validity byte first, branch on the B#16#01 / B#16#02 / B#16#03 tokens, and never trust bz_cpu_x values when the corresponding validity bit is 0.

Reproducing an Invalid CPU Validity State for Testing

The user also asked how to force an invalid snapshot. There are four practical methods, in order of increasing risk to a live process. Always perform these tests on a bench rig or during a scheduled outage.

Method What it does Expected validity Risk
Power down CPU 1 with the H-system in RUN CPU 0 remains master, CPU 1 reports NO POWER (W#16#000F). bz_cpu_1 validity bit (B#16#02) goes 0; B#16#01 remains 1. B#16#01 = 1, B#16#02 = 0 Medium – live system continues in single mode; any in-process role swap logic will trigger.
Pull both fiber-optic links during RUN Both CPUs detect link-down, bz_cpu_0 / bz_cpu_1 both go to W#16#0009 (Link down). Validity bits stay 1 because the firmware still has a valid local snapshot. B#16#01 = 1, B#16#02 = 1, but bz values are 0x0009 High – master continues running single mode, system may generate OB70 / OB72 errors.
Insert a deliberately defective spare CPU Defective CPU reports W#16#0007 (defect) or refuses to power up, producing W#16#000F (NO POWER). Validity bit is 0. B#16#01 = 1, B#16#02 = 0 (or vice-versa) None to process; excellent for testing diagnostic buffer entries.
Use a CPU in firmware update / MRES state CPU is present on the rack but is in MRES / firmware-update mode. Firmware does not publish a valid SZL snapshot, so validity bit is 0. B#16#0n = 0 for that CPU None to process; safe bench test.
Testing caveat: Some S7-400H firmware versions (CPU 417-4H, firmware V4.5.0 and later) do not return B#16#01 / B#16#02 / B#16#03 in the SZL validity byte directly. Instead, the validity information is reported in a separate "extended H status" SZL, W#16#0F71. Verify the exact byte map against the firmware release you are running by exporting the SZL with SFC51 and writing the raw bytes to a watch table during commissioning.

Troubleshooting Matrix and Verification Procedure

Observed SZL byte 0 bz_cpu_0 bz_cpu_1 Diagnosis Recommended action
B#16#00 0000 0000 Both CPUs not yet producing snapshots (H-system not in RUN, or SZL_ID mismatch). Confirm SZL_ID = W#16#0071, INDEX = W#16#0000. Verify the H-system has completed link-up (H LED on CPU front).
B#16#01 0004 (RUN) 0000 CPU 0 healthy, CPU 1 not yet reporting (typical during first 5 s after link-up). Wait for link-up to complete; if condition persists past 30 s, check fiber-optic cable on the partner side.
B#16#02 0000 0004 (RUN) CPU 0 invalid (typically NO POWER or DEFECT), CPU 1 master. Check CPU 0 power supply, mode switch position, and diagnostic buffer (SZL W#16#00A0).
B#16#03 0004 000A (standby) Healthy redundant pair, CPU 0 master, CPU 1 standby. None – normal operation.
B#16#03 000A 0004 Healthy redundant pair, CPU 1 master, CPU 0 standby. None – confirm intended master assignment.
B#16#03 0009 0009 Both CPUs link-down, each in stand-alone single mode. Inspect both fiber-optic links and synchronization modules (IF 960 or IF 962).
B#16#01 0007 0000 CPU 0 in self-test defect state. Replace CPU 0; check for firmware mismatch with the partner.
B#16#00 FFFF FFFF SZL not initialized – call to SFC51 not yet complete, or RET_VAL non-zero. Check RET_VAL; poll BUSY; verify the SZL_ID partial list number is supported by your CPU firmware.

When commissioning an S7-400H station, verify the SZL W#16#0071 path is functioning correctly using this 6-step procedure.

  1. Force SFC51 call in OB100 – call the SZL read once during cold restart, log the raw bytes to a watch table.
  2. Confirm byte 0 = B#16#03 – both validity bits should be set within 10 s of link-up; if not, both CPUs are not yet synchronized.
  3. Confirm bytes 2-3 = W#16#0004 – bz_cpu_0 should report RUN.
  4. Confirm bytes 4-5 = W#16#000A or W#16#0004 – bz_cpu_1 should be standby (W#16#000A) or RUN (W#16#0004) depending on which CPU is master.
  5. Force a partner power-cycle – disconnect power to CPU 1; byte 0 should drop from B#16#03 to B#16#01, byte 5 should drop to W#16#000F, byte 6 should remain 1 (CPU 0 master).
  6. Restore power to CPU 1 – byte 0 should recover to B#16#03, byte 5 should recover from W#16#000F to W#16#000A within 30 s of link-up.

If step 5 or 6 fails, the most common root cause is a partially seated fiber-optic connector (link 1 OK, link 2 not OK); the link-status byte at offset 7 confirms the diagnosis.

Integration with TIA Portal and Diagnostic Symbols

On S7-400H CPUs configured in TIA Portal V15 or later, the same diagnostic information is available through three additional paths:

  1. Online & Diagnostics → Diagnostics status – the H-system tab shows the bz_cpu_0 and bz_cpu_1 values as a live dashboard. The validity token (B#16#01 / B#16#02 / B#16#03) is not exposed directly; it is implicit in the Status column (green = valid, gray = invalid).
  2. Web server diagnostic pages – the H-CPU's integrated web server exposes the same fields under "Module information → SZL 0x71". This is useful for remote monitoring without a STEP 7 connection.
  3. Diagnostic symbols in the project tree – TIA Portal renders the H-system state using the standard diagnostic symbol set documented at TIA Portal – Explanation of diagnostics symbols. A gray "no diagnosis" symbol next to the partner CPU indicates that the B#16#02 / B#16#01 validity bit for that CPU is 0.

Even with these GUI aids, the canonical source for redundancy decisions in the user program is the SFC51 path, because the H-system Web server and TIA Portal dashboard run outside the OB1 scan and cannot be polled at the rate a process controller requires.

Safety, OB70 / OB72 / OB82 Handling, and Performance

S7-400H is not by itself a SIL-rated platform. The H-CPU family can be deployed in SIL 2 / SIL 3 applications when paired with an F-CPU (e.g., CPU 416F-3 PN/DP) in a separate rack and a certified safety program. The validity bits in SZL W#16#0071 are not safety-relevant inputs; they are diagnostic-only and must never be used as the primary decision input in a safety path. Safety decisions must be made by the F-CPU's own F-runtime diagnostic, not by reading SZL on a standard H-CPU.

Safety note: Do not gate safety logic on the SZL W#16#0071 validity tokens. A safety-rated program must use the F-CPU's own diagnostic mechanism (e.g., F-I/O channel quality bits) and must be reviewed against IEC 61508 / IEC 61511 by a TÜV-certified safety engineer. The validity tokens in SZL W#16#0071 are for operational monitoring and process control only.

The H-system generates three error OBs that should be wired in production code to correlate with the SZL validity token transitions:

OB Fires when Typical action Correlates with SZL field
OB70 Redundancy loss (I/O redundancy error) Log the event, set a maintenance tag, continue in single mode if possible. Validity byte B#16#01/B#16#02 transition; role byte (offset 6) flip.
OB72 CPU redundancy loss (standby partner unavailable) Log, alert, optionally initiate controlled shutdown if safety requires. Validity byte for the affected CPU; sync-attempts counter (offset 12).
OB82 DP / PN slave diagnostic interrupt (often I/O module health change) Evaluate the diagnostic frame, isolate the affected module. Module-level validity, not directly tied to SZL W#16#0071.

A robust production code pattern: in OB70 / OB72, do not blindly trust the SFC51 SZL read for the first call after the OB fires; wait for the diagnostic counter at offset 14 to increment at least once (which it does within one OB35 cycle, ~100 ms), then read the validity byte and decide.

For performance, the SZL W#16#0071 call on CPU 417-4H typically completes in 4-8 ms, well within an OB35 cycle budget. The SZL_DATA buffer is 464 bytes maximum, more than enough for the 16-byte records. Caching the SZL data in a global DB and reading it from OB1 (rather than calling SFC51 in OB1 directly) reduces OB1 scan time by 1-3 ms on a typical configuration. For a more deterministic cycle, use OB35 at 100 ms to drive SFC51 and a global DB tag (e.g., DB_H.bz_cpu_0) that OB1 can poll without re-issuing the SZL call.

Cross-Platform Redundancy Patterns and Field-Proven Caveats

The cross-platform SZL pattern is not unique to Siemens. High-availability PLCs in general implement similar CPU-validity / partner-validity bit pairs. Mitsubishi Q4ARCPU redundant CPUs in a MELSECNET/H network, for example, report partner status through comparable network diagnostic buffers where the Q4ARCPU's "partner CPU existence" bit maps cleanly onto the S7-400H B#16#01 / B#16#02 concept. Allen-Bradley ControlLogix Redundancy Module (1756-RM2 / 1756-RM) systems expose an analogous qualification bit on each chassis, where the partner chassis must qualify before a switchover is allowed. The universal lesson is the same: a CPU validity bit is a contract from the runtime to the user program, and consuming partner data without checking the contract leads to spurious role swaps and "ghost" partner states.

From hundreds of field deployments, the following pitfalls recur in H-system SZL handling code. Engineers integrating SFC51 should review against this list.

  • Forgetting that SFC51 is asynchronous. The call must be repeated every OB1 cycle until BUSY = 0. A single call often returns BUSY = 1 and an empty SZL_DATA buffer.
  • Reading SZL W#16#0071 before the first link-up completes. During the first 10 s of H-system startup the SZL returns N_DR = 0. The application code must wait for N_DR > 0 before indexing into the data array.
  • Treating the validity byte as a status indicator. The byte does not say "the CPU is bad"; it says "the snapshot in this record is not trustworthy."
  • Confusing W#16#0071 with W#16#0019. W#16#0019 is the LED status of a single CPU; W#16#0071 is the H-system status of the pair. S7-400H returns both, but only W#16#0071 contains the BZ operating state for both CPUs.
  • Indexing by N_DR instead of by LENTHDR. A bug-fix to the LENTHDR field (for example, after a firmware update that adds a new field) shifts the offsets. Always index by (record index * LENTHDR), not by hard-coded byte offsets.
  • Not using OB35 (100 ms cyclic interrupt) for SZL polling. OB1 runs at a variable scan rate, which makes the diagnostic update rate non-deterministic. Use a fixed-rate cyclic interrupt for the SZL read so the diagnostic counter at offset 14 increments at a known rate.
  • Migrating from S7-400 single to S7-400H without re-checking the SZL map. Single-CPU S7-400 code that reads W#16#0019 for the LED status will continue to work on an H-system CPU but will not return the bz_cpu_0 / bz_cpu_1 operating state. Add SZL W#16#0071 calls explicitly when porting.

Frequently Asked Questions

What is the difference between B#16#01 and B#16#03 in the SZL W#16#0071 validity byte?

B#16#01 (binary 0000 0001) is set when bz_cpu_0 is trustworthy. B#16#03 (binary 0000 0011) is set when both bz_cpu_0 and bz_cpu_1 are trustworthy. B#16#01 alone means CPU 0 is valid but CPU 1 is not (e.g., partner in NO POWER or DEFECT). B#16#03 is the "fully redundant, both CPUs healthy" condition. B#16#02 alone means only CPU 1 is valid.

Can I rely on bz_cpu_x being zero when the validity bit is cleared?

No. The SZL firmware writes the undefined value W#16#0000 into the bz_cpu_x word when the validity bit is cleared, but this is a firmware implementation detail that may change between firmware versions. Always check the validity bit first, and treat any bz_cpu_x read with the validity bit cleared as undefined data, not as a known state.

Why does SFC51 return N_DR = 0 sometimes?

Either the H-system has not yet completed link-up (typically the first 10 s of startup), or the SZL_ID is not supported by the current CPU firmware. Confirm the SZL_ID is W#16#0071 and the INDEX is W#16#0000, and confirm the H LED on both CPUs is solid green (link-up complete) before debugging further.

How do I reproduce an invalid CPU state for testing without taking the plant down?

The safest method is to insert a known-defective CPU in slot 1 of a bench rig configured as an H-system. The defective CPU will refuse to power up or report W#16#0007 (DEFECT), setting B#16#02 = 0 in the partner's SZL. For a live-plant test, power down CPU 1 only (CPU 0 remains master) and observe the validity byte drop from B#16#03 to B#16#01.

Is the SZL W#16#0071 validity token safe to use for fail-over decisions in OB1?

Yes, for operational fail-over (which CPU takes over as master, which is the standby) the validity token is the canonical input. It is not a safety input and must not be used in F-runtime logic. A safety-rated fail-over must use the F-CPU's own diagnostic mechanism (e.g., F-I/O PASS_OUT, F-runtime diagnostic flags) and must be reviewed against IEC 61508.

What is the difference between SZL W#16#0071 and SZL W#16#0F71?

SZL W#16#0071 (INDEX = 0) returns the partial list 0 of the H-system SZL, which contains the validity token and the bz_cpu_0 / bz_cpu_1 operating states. SZL W#16#0F71 (INDEX = 15) returns the entire SZL 113 in one buffer, which is more efficient for a full snapshot but requires more buffer space. For cyclic operational use, W#16#0071 is preferred because the call is smaller and the response is faster.

What does W#16#000F (NO POWER) actually mean in SZL W#16#0071?

W#16#000F indicates the CPU has no supply voltage or is physically absent from the rack. The bz_cpu_x validity bit for that CPU will be 0 (B#16#01 = 0 if CPU 0 has no power, B#16#02 = 0 if CPU 1 has no power). The remaining CPU, if present, will continue in single-mode operation as long as its own validity bit is 1.

Back to blog