1. Overview
On Siemens S7-400 / S7-400H controllers the SFC 51 "RDSYSST" (Read System Status List) is the canonical mechanism to read diagnostics data such as module identification, diagnostic buffer excerpts, and the live CPU front-panel LED status. The relevant partial list is SZL ID W#16#0174 (decimal 372), which reports the current state of every LED exposed by the CPU or an interface (IF) module.
On a CPU 412-5HK06 (6ES7 412-5HK06-0AB0) – an S7-400H high-availability CPU – users frequently hit RET_VAL = W#16#8081 the first time they call SFC 51 with this SSL ID. The error is almost always a buffer-length / DR-struct mismatch, not a hardware defect or a missing SZL. This article documents the SZL layout, the error-code root cause, and the exact struct expansion that resolves the issue.
2. SFC 51 / RDSYSST Fundamentals
SFC 51 reads one partial list extract of the System Status List (SSL). The block is declared as follows in the S7-300/400 system library:
// CALL SFC 51 (RDSYSST)
// REQ := TRUE
// SZL_ID := W#16#0174 // LED status partial list
// INDEX := W#16#000D // LED identifier (e.g. REDF)
// SZL_LEN := 0 // 0 = use implicit max length
// DR := P#DBX0.0 BYTE 30 // destination buffer
// BUSY := M10.0
// RET_VAL := MW12
When SZL_LEN = 0 the CPU writes the maximum number of records for the requested ID/index combination. The DR pointer must reference an ANY pointer that is large enough to hold the entire SZL header plus the full set of records; otherwise SFC 51 returns 8081h. The official Siemens reference for the block is the RDSYSST — Read system status list (S7-300, S7-400) documentation page in the TIA Portal help system.
3. SZL W#16#0174 Data-Record Layout
Each call to SFC 51 with SZL_ID = W#16#0174 returns the following binary structure inside the destination area pointed to by DR:
| Offset | Bytes | Meaning |
|---|---|---|
| +0 | 2 | SZL_ID (echo) – W#16#0174 |
| +2 | 2 | SZL_INDEX (echo) of first record |
| +4 | 2 | Length of one SZL record (bytes) |
| +6 | 2 | Number of records (n) |
| +8 | 2 × n | Record[n].INDEX – LED identifier |
| +10 + 2n | 1 | Record[n].STATUS_1 |
| +11 + 2n | 1 | Record[n].STATUS_2 |
| +12 + 2n | 2 | Record[n].LED_STATUS – bit-coded state |
Each record is therefore 8 bytes wide. The H-CPU returns more records than a standard S7-400 CPU because it must also publish the redundancy LEDs (REDF, MSTR, LINK) that the simplex CPUs do not have.
4. LED Index Mapping on CPU 412-5HK06
The SZL W#16#0174 exposes the following LED indices on a 6ES7 412-5HK06-0AB0 S7-400H CPU. The "Index (hex)" column is the value to pass to the SFC 51 INDEX input when a single LED is queried:
| Index (hex) | Index (dec) | LED | Meaning | H-CPU only? |
|---|---|---|---|---|
| W#16#0001 | 1 | INT | Internal fault | No |
| W#16#0002 | 2 | EXT | External fault | No |
| W#16#0003 | 3 | BUS1F | Bus 1 fault (PROFIBUS DP1) | No |
| W#16#0004 | 4 | BUS2F | Bus 2 fault (PROFIBUS DP2 / MPI) | No |
| W#16#0005 | 5 | IFM1F | Interface module 1 fault | No |
| W#16#0006 | 6 | IFM2F | Interface module 2 fault | No |
| W#16#0007 | 7 | LINK | PROFINET / sync link status | H-CPU |
| W#16#0008 | 8 | RX/TX | Optical sync cable activity | H-CPU |
| W#16#0009 | 9 | MSTR | Master role indicator | H-CPU |
| W#16#000A | 10 | (reserved) | – | – |
| W#16#000B | 11 | (reserved) | – | – |
| W#16#000C | 12 | RUN | RUN state LED | No |
| W#16#000D | 13 | REDF | Redundancy fault LED | H-CPU |
| W#16#000E | 14 | STOP | STOP state LED | No |
5. RET_VAL 8081h – Root Cause
The SFC 51 RET_VAL codes reported in the STEP 7 System and Standard Functions manual are reproduced below. Only the codes relevant to SZL W#16#0174 are shown:
| RET_VAL | Meaning (SZL read) | Likely cause with W#16#0174 |
|---|---|---|
| W#16#0000 | No error | – |
| W#16#8081 | Result length is larger than the destination area (DR) that was passed | DR struct is too small – the SZL contains more records than the buffer can hold |
| W#16#8082 | SZL header is wrong | DB / area no longer matches the ANY pointer; check LEN byte |
| W#16#8083 | SZL_ID/INDEX is wrong | Did you pass the ID/INDEX combination that the CPU supports? |
| W#16#8090 | Module does not support this SZL | SSL W#16#0174 not implemented in the firmware of the queried module |
| W#16#8091 | SZL_ID is not supported | Typo – e.g. 17A instead of 174 |
| W#16#8092 | INDEX is not supported | Index 4 is BUS2F, not RUN; use 0C for RUN, 0D for REDF |
| W#16#80C1 | SZL is currently being processed by another job | Two OB1 calls to SFC 51 racing on the same SZL |
| W#16#80C3 | Internal error | CPU firmware bug; update to ≥ V6.0.7 on 412-5HK06 |
For the symptom "RET_VAL = 8081 on a 412-5HK06, always, with every INDEX" the dominant root cause is the DR buffer is undersized. The H-CPU publishes 14 LED records (8 bytes each) plus an 8-byte SZL header – a total of 120 bytes – but the example struct in the question only contained 1 WORD + 2 BYTE = 4 bytes. SFC 51 detects the overflow and returns 8081h.
6. Prerequisites
- STEP 7 V5.5 SP2 or later (TIA Portal V13+ for the documentation link above), with the optional S7-400H package installed.
- S7-400 / S7-400H CPU with firmware ≥ V6.0 (6ES7 412-5HK06-0AB0 ships with V6.0.6 from the factory; 6.0.7 fixes the 80C3 path).
- Knowledge of the SZL index you actually need (RUN = 0C, REDF = 0D on a 412-5HK06).
- A free DB (preferably instance DB) of at least 120 bytes in the work-memory area accessible to the call (the S7-400H allows DB 0 – DB 65535).
7. Step-by-Step: Resolving RET_VAL 8081 on the 412-5HK06
- Create the destination DB. Open the S7 program in STEP 7 and add a new DB (e.g. "DB_LED") with a length of 120 bytes. The block must be set as a non-optimised access block (classic DB) for the ANY pointer to work correctly.
- Declare a STRUCT that mirrors the SZL header plus the 14 records. The declaration must start at byte 0 of the DB:
DATA_BLOCK "DB_LED"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
STRUCT
SZL_ID : WORD; // +0 echoed SSL ID
SZL_INDEX : WORD; // +2 echoed first INDEX
SZL_LEN : WORD; // +4 length per record (bytes)
SZL_NREC : WORD; // +6 number of records returned
LED_INDEX : ARRAY[1..14] OF WORD; // +8 record INDEX
LED_STATUS1 : ARRAY[1..14] OF BYTE; // +36 record STATUS_1
LED_STATUS2 : ARRAY[1..14] OF BYTE; // +50 record STATUS_2
LED_STATE : ARRAY[1..14] OF WORD; // +64 bit-coded LED state
END_STRUCT;
END_DATA_BLOCK
- Call SFC 51 with the corrected ANY pointer. The ANY must span all 120 bytes:
CALL "RDSYSST" (
REQ := TRUE,
SZL_ID := W#16#0174,
INDEX := W#16#0000, // 0 = all LEDs in the SZL
SZL_LEN := 0, // let CPU choose max length
DR := P#DB_LED.DBX0.0 BYTE 120,
BUSY := M 10.0,
RET_VAL := MW 12);
- Poll BUSY / RET_VAL. With REQ = TRUE, evaluate RET_VAL: any non-zero value means the call failed – see the table in §5.
-
Decode the LED you need. After a successful call, the field
DB_LED.LED_STATE[i]holds the bit-coded state of the i-th LED. The bit pattern for S7-400 / S7-400H is:
| LED_STATE value | Visual state |
|---|---|
| W#16#0000 | LED off |
| W#16#0001 | Green, steady |
| W#16#0002 | Green, flashing |
| W#16#0003 | Red, steady |
| W#16#0004 | Red, flashing |
| W#16#0005 | Yellow, steady |
| W#16#0006 | Yellow, flashing |
- Read a single LED by index. If you only need the REDF LED, narrow the call down with INDEX = W#16#000D. SFC 51 then returns exactly one record (8 bytes) so the buffer can be much smaller:
DATA_BLOCK "DB_REDF"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
STRUCT
SZL_ID : WORD;
SZL_INDEX : WORD;
SZL_LEN : WORD;
SZL_NREC : WORD;
REDF_IDX : WORD;
REDF_ST1 : BYTE;
REDF_ST2 : BYTE;
REDF_LED : WORD; // 0=off, 1=green, 3=red, 4=red-flashing
END_STRUCT;
END_DATA_BLOCK
8. Sample Structured-Text (SCL) Implementation
FUNCTION_BLOCK FB_LED_Read
VAR
dbLed : INT := 100; // DB_LED number
retVal : INT;
busy : BOOL;
i : INT;
END_VAR
BEGIN
IF NOT busy THEN
RDSYSST(REQ := TRUE,
SZL_ID := 16#0174,
INDEX := 16#0000,
SZL_LEN:= 0,
DR := P#"DB_LED".DBX0.0 BYTE 120,
BUSY := busy,
RET_VAL:= retVal);
END_IF;
IF retVal <> 0 THEN
// Error path – see error table in §5
RETURN;
END_IF;
// Iterate through the records returned
FOR i := 1 TO WORD_TO_INT("DB_LED".SZL_NREC) DO
CASE "DB_LED".LED_INDEX[i] OF
16#000C: // RUN LED
; // publish RUN state to HMI / tag
16#000D: // REDF LED
; // publish REDF state to HMI / tag
16#0009: // MSTR LED
; // master role status
END_CASE;
END_FOR;
END_FUNCTION_BLOCK
9. Verification Procedure
- Compile and download the program to the standby CPU of the 412-5HK06 H-system first; then perform a switchover and download to the master.
- Go online and open DB_LED in the watch table. The first four words must echo SZL_ID = W#16#0174, the first INDEX of the partial list, the record length (W#16#0008) and the record count.
- Toggle the CPU into STOP via the mode selector;
LED_STATE[14](STOP) must change to W#16#0001 (green steady) andLED_STATE[12](RUN) must change to W#16#0000 (off). On a 412-5HK06 the STOP LED on the front panel will not change because the redundancy partner is still in RUN; the SZL nevertheless reports the local CPU state. - Pull one of the sync cables to provoke a REDF event;
LED_STATE[13](REDF) must change to W#16#0003 or W#16#0004 within one OB1 cycle. - Force
SZL_LEN = 8andRET_VALmust remain W#16#0000 – this proves that a 4-byte buffer would have overflowed the SZL and confirms the 8081 root cause.
10. Troubleshooting Matrix
| Symptom | RET_VAL | Root cause | Remedy |
|---|---|---|---|
| Always 8081, every call | 8081h | DR too small for the number of LED records returned by the H-CPU | Expand the DB to ≥ 120 bytes and pass the full 120 bytes in the ANY |
| 8081 only on REDF | 8081h | Reused an SZL buffer originally sized for a standard S7-400 CPU (60 bytes) | Re-size to 120 bytes; S7-400H returns 14 records |
| 8081 after firmware update | 8081h | New firmware added LED records beyond the previous total | Re-read the SZL_LEN field and resize the DB |
| 8081 then 8091 | 8091h | Typo in SZL_ID (e.g. 17A) | Use exactly W#16#0174 |
| 8081 then 8092 | 8092h | Index not supported – e.g. 0004 used to query RUN | Use W#16#000C for RUN, W#16#000D for REDF on a 412-5HK06 |
| Works once, then 80C1 | 80C1h | Concurrent SFC 51 calls on the same SZL | Sequence calls with a single BUSY handshake or use a global semaphore |
| Returns no records | 0000h | INDEX filter excludes all records | Pass INDEX = W#16#0000 to read the whole SZL |
| RET_VAL=0, LED_STATE always 0 | 0000h | DR written to a non-existent / wrong DB | Check the DB number in the ANY pointer |
11. Variant Notes: S7-300, S7-400, S7-400H
The SZL W#16#0174 is implemented on S7-300 CPUs starting with firmware V2.0, on all S7-400 CPUs, and on every S7-400H CPU. The record count differs:
- S7-300 (e.g. 319-3 PN/DP, 6ES7 318-3FL01-0AB0): typically 7 LED records – INT, EXT, BUS1F, BUS2F, IFM1F, IFM2F, RUN, STOP. Buffer 64 bytes is sufficient.
- S7-400 standard (e.g. 416-3, 6ES7 416-3XR05-0AB0): 10 LED records. Buffer 88 bytes is sufficient.
- S7-400H (e.g. 412-5HK06, 6ES7 412-5HK06-0AB0): 14 LED records (RUN, STOP, REDF, MSTR, LINK, RX/TX plus the standard fault LEDs). Buffer 120 bytes is required.
For S7-1500 the equivalent block is RDSYS_T (instruction "Read system status") – the LED partial list still uses SZL W#16#0174 but is published as a typed PLC tag instead of a raw byte buffer.
Why does SFC 51 return 8081h when I read SZL W#16#0174 on a CPU 412-5HK06?
RET_VAL 8081h means the destination area (DR) you passed to SFC 51 is smaller than the partial-list extract the CPU wants to write. The 412-5HK06 publishes 14 LED records (8 bytes each) plus an 8-byte SZL header, i.e. 120 bytes. A 4-byte buffer therefore overflows immediately and SFC 51 reports 8081h. Resize the destination DB and the ANY pointer to 120 bytes.
What is the correct SFC 51 INDEX to read the REDF LED on a 412-5HK06 H-CPU?
Use INDEX = W#16#000D (decimal 13). The H-CPU exposes REDF, MSTR, LINK, RX/TX, RUN, STOP and the standard fault LEDs through SZL W#16#0174 at indices 1 – 14. Reading only the REDF LED needs a destination buffer of exactly 16 bytes (SZL header 8 bytes + one record 8 bytes).
Can I read the RUN LED with INDEX 4?
No. INDEX 4 (W#16#0004) is the BUS2F LED (PROFIBUS DP2 / MPI fault). The RUN LED is INDEX W#16#000C and the STOP LED is INDEX W#16#000E on every S7-400 and S7-400H CPU. Using the wrong index returns RET_VAL 8092h (index not supported) on the H-CPU firmware 6.0.6 and later.
Which SZL ID gives me the current CPU operating mode (RUN / STOP / HOLD)?
The LED status of the RUN/STOP LEDs is in SZL W#16#0174 (INDEX 0C / 0E). For the actual mode word (STARTUP, RUN, STOP, HOLD, LINK-UP, UPDATE, …) use SZL W#16#0019 "Status of the priority classes" or read OB 1 / OB 100 / OB 101 start information. The CPU operating-state byte in the diagnostic buffer is also available via SZL W#16#0131 / W#16#0132.
Do I have to expand the DR struct for every firmware update?
Yes. Each firmware release can add new LED records (e.g. a new FO synchronization LED on 412-5H firmware V6.0.7 added the RX/TX record). The safest practice is to always read SZL W#16#0174 with INDEX = W#16#0000 and a buffer ≥ 120 bytes, then iterate over SZL_NREC records. The official reference is the RDSYSST documentation.