Reading Signal Module Serial Numbers on S7-300/S7-400 with SFC51 (SZL-ID W#16#xy1C)
In a SIMATIC S7-300 or S7-400 system, the CPU stores diagnostic and identification data for every inserted module in the System Status List (SSL / SZL). Component identification — including the unique 24-character serial number of each signal module (SM), function module (FM), communications processor (CP), and interface module (IM) — is exposed through SSL partial list W#16#xy1C. The standard system function SFC51 "RDSYSST" (Read SSL) retrieves that partial list so the user program can extract the serial numbers of all 32 modules in a 4-rack / 8-slot configuration, exactly as the CPU and MMC serial numbers are read with the same call.
1. Prerequisites
- SIMATIC S7-300 (CPU 31x, CPU 319) or S7-400 (CPU 41x, CPU 41xF, CPU 41xH, CPU 41xFH, CPU 416, CPU 417) with firmware that supports SSL partial list
W#16#xy1C. The partial list is available on every standard CPU as of STEP 7 V5.x;xy1Cis part of the basic SSL and is supported on all CPUs with diagnostic capability. - STEP 7 V5.5 SPx or TIA Portal V13+ with the CPU's firmware description installed so that the F1 help on SFC51 "RDSYSST" resolves locally.
- Hardware configuration (HW Config) is compiled and downloaded; the actual physical slots must match the configured slots, otherwise the SSL still returns data for the configured slot but the returned module identification may be empty or zero.
- An instance DB or a global DB with sufficient free space: one read returns up to 34 bytes (header + 12 words of ASCII), so reserve at least 64 bytes per call as a safety margin when reusing the buffer across slots.
2. System Status List (SSL / SZL) Architecture
The System Status List is a CPU-internal data structure that contains the actual system state. It is divided into partial lists, each identified by an SSL-ID with the format W#16#xyyy:
-
xx– partial list number (e.g.,11= module identification,1C= component identification with serial number). -
y– index that further qualifies the entry (rack / slot / subsystem in the high byte, slot in the low byte for some partial lists).
The user program never reads the SSL directly. SFC51 "RDSYSST" copies a slice of the SSL into a user data area (a DB, an instance DB, or a Merker/Flag area). The signature of SFC51 is fixed:
| Parameter | Declaration | Data type | Description |
|---|---|---|---|
REQ |
INPUT | BOOL | Level-triggered request. Set REQ := TRUE to start a read; reset after BUSY falls. |
SZL_ID |
INPUT | WORD | SSL-ID of the partial list to read. W#16#xy1C for component identification with serial number. |
INDEX |
INPUT | WORD | Index that qualifies the partial list. For xy1C the index encodes rack and slot (see Section 4). |
RET_VAL |
OUTPUT | INT | Return value. 0 on success, error code in W#16#80xx family if the call fails. |
BUSY |
OUTPUT | BOOL |
TRUE while SFC51 is working; FALSE when the destination buffer contains valid data. |
SZL_HEADER |
OUTPUT | STRUCT | Optional 2-word header (length of one record, number of records). Define as STRUCT LENGTH_DR, N_DR: WORD END_STRUCT. |
DR |
OUTPUT | ANY | Destination area. Must be at least the record length returned in SZL_HEADER.LENGTH_DR. The first two bytes overlap with the header when the header pointer is supplied; the record data starts at DR[0] when no header is used. |
3. SZL-ID W#16#xy1C — Component Identification with Serial Number
SSL partial list W#16#xy1C provides the component identification of a module, including the serial number as a left-justified ASCII string of up to 24 characters. Padded characters after the actual serial number are filled with blanks (B#16#20) or, on some firmware versions, with B#16#00.
3.1 Index encoding for xy1C
The INDEX input of SFC51 encodes the rack number in the high byte and the slot number in the low byte:
| Byte | Bit(s) | Meaning | Allowed values |
|---|---|---|---|
| High byte (bits 8–15) | 0–7 | Rack number | 0 = central rack of the CPU; 1..3 = expansion racks in the S7-300; 0..3 in the S7-400; B#16#FF = request all racks |
| Low byte (bits 0–7) | 0–7 | Slot number | 1..18 for S7-300, 1..18 for S7-400 (or 0..31 for ET 200S); B#16#FF = all slots of the addressed rack |
W#16#0104 = rack 1, slot 4) to read a single module. Use W#16#FFFF to retrieve the serial numbers of every module in the local station. The destination DR must then be large enough for N_DR * LENGTH_DR bytes; otherwise SFC51 returns W#16#80B1 (DR too small).3.2 Record layout of xy1C
One record of partial list xy1C occupies 34 bytes (17 words) when the SZL header is returned together with the record. With the header supplied, the structure in the destination buffer is:
| Offset (bytes) | Length | Content | Notes |
|---|---|---|---|
| 0..1 | WORD | Component ID |
B#16#05 = serial number record |
| 2..3 | WORD | Index echo (rack, slot) | High byte = rack, low byte = slot |
| 4..27 | 12 WORDs (24 bytes) | Serial number | ASCII, left-justified, padded with blanks (B#16#20). Padded with B#16#00 on some firmware versions. |
When SFC51 is called without the SZL_HEADER output (pass NULL / an unconnected variable), the destination DR receives the record only — i.e., the same 34 bytes starting at offset 0. This is the most common usage in STEP 7 V5.5.
LENGTH_DR = 34 (W#16#0022) and N_DR up to 19 (S7-300, slots 0..18). For a 4-rack station with 8 populated slots each, allocate 4 × 8 × 34 = 1088 bytes minimum, or process the racks/slots one at a time to keep the working buffer small.4. Calling SFC51 from a Function (FC) — STL Reference
The following STL snippet shows a single call that reads the component identification of one specific module. The destination is DB100, byte area starting at byte 0; the function returns the serial number as a STRING[24] at DB100.DBx.
// FC100 — Read module serial number
// Inputs: iRack (BYTE) — rack number 0..3
// iSlot (BYTE) — slot number 1..18
// iStart (BOOL) — edge-triggered start
// Outputs: oDone (BOOL) — read complete, data valid
// oBusy (BOOL) — SFC51 working
// oError (BOOL) — SFC51 returned error
// oErrCode(WORD) — RET_VAL of SFC51
// oSerial (STRING[24]) at DB100 — serial number
NETWORK 1 // Edge-triggered start
A #iStart
FP #statStartFlank
= #statReq
NETWORK 2 // SFC51 call
CALL "RDSYSST" // SFC51
REQ := #statReq
SZL_ID := W#16#011C // partial list xy1C, index 01 (rack 0)
INDEX := #statIndex // built from iRack / iSlot
RET_VAL := #statRetVal
BUSY := #statBusy
SZL_HEADER := #statHdr // STRUCT of 2 WORDs
DR := P#DB100.DBX 0.0 BYTE 34
NETWORK 3 // Evaluate return
L #statRetVal
L 0
==I
= #oDone
<>I
= #oError
T #oErrCode
For a per-slot sweep, the call is identical except that INDEX is rebuilt in each loop pass:
// Build INDEX = (rack SHL 8) OR slot
L #iRack
SHL 8
L #iSlot
OW
T #statIndex
5. Iterating Across 4 Racks × 8 Slots
The 4-rack / 8-slot topology from the original question is a typical S7-400 station with one central rack (rack 0) and three expansion racks (racks 1..3) interconnected by IM460/IM461 send/receive modules. The same algorithm works for an S7-300 with up to three expansion racks. The recommended scan loop is:
- Initialise a pointer to the next free record in the result DB (start at byte 0).
- For
Rack := 0 TO 3: - For
Slot := 1 TO 18(or 1..8 if the station is constrained to 8 slots): - Build the SSL index, call SFC51, wait for
BUSY = FALSEandRET_VAL = 0. - If
DR[0] = B#16#05(component ID = serial number record) and the serial-number field is not all spaces/zeros, copy the 24 bytes into the result DB and advance the pointer by 34 bytes. - If the slot is unconfigured or empty, SFC51 typically returns
W#16#80A2(partial list read error) — treat this as "no module present" and continue.
// Loop body in STL (FC110 "ScanAllModules")
NETWORK 1 // Outer rack loop
L 0
T #statRack // start at rack 0
RACK: NOP 0
NETWORK 2 // Inner slot loop
L 1
T #statSlot // start at slot 1
SLOT: NOP 0
NETWORK 3 // Build INDEX
L #statRack
SHL 8
L #statSlot
OW
T #statIndex
NETWORK 4 // Read SSL xy1C for this slot
SET
= #statReq
CALL "RDSYSST"
REQ := #statReq
SZL_ID := W#16#011C
INDEX := #statIndex
RET_VAL := #statRetVal
BUSY := #statBusy
SZL_HEADER := #statHdr
DR := P#DB100.DBX 0.0 BYTE 34
NETWORK 5 // Wait for completion (simple polling)
WAIT: U #statBusy
SPBN WAIT
L #statRetVal
L 0
<>I
JC NEXT // error → skip slot
NETWORK 6 // Check component ID
L DB100.DBW 0 // first WORD = component ID
L W#16#0005 // B#16#05 = serial number
<>I
JC NEXT
NETWORK 7 // Copy serial number into result DB
L P#DB110.DBX 0.0 // destination pointer in DB110
LAR1
L P#DB100.DBX 4.0 // source: bytes 4..27 of record
LAR2
L 24 // length of serial number
NEXT: L #statSlot
+ 1
T #statSlot
L 18 // max slots for S7-300/400
<=I
JC SLOT
L #statRack
+ 1
T #statRack
L 3 // racks 0..3
<=I
JC RACK
6. Decoding the Serial Number into a STRING
The raw 24 bytes returned at DR offset 4 are two ASCII characters per WORD, low byte first. To store the result as a usable STRING[24] in the result DB, the simplest approach is to declare the destination area as:
// DB110 — Result buffer
DATA_BLOCK DB110
STRUCT
count : WORD; // number of modules found
reserved: WORD;
entries : ARRAY[1..32] OF
STRUCT
rack : BYTE;
slot : BYTE;
res01 : BYTE;
res02 : BYTE;
serial : STRING[24]; // max length 24, actual length byte at byte 24
pad : BYTE; // align to 32-byte boundary
END_STRUCT;
END_STRUCT
END_DATA_BLOCK
Copy the 24 ASCII bytes from DB100 starting at offset 4 directly into entries[i].serial; STEP 7 fills the length byte of the STRING automatically from the first NULL/B#16#00 (or the end of the 24-byte field) when using BLKMOV with a STRING[24] destination. If the firmware pads with blanks (B#16#20), trim trailing blanks manually by scanning from the last byte backwards.
7. Return / Error Codes of SFC51
| RET_VAL (hex) | Meaning | Field action |
|---|---|---|
| 0000 | No error, data valid in DR. | Proceed to copy serial number. |
| 80A1 | Negative acknowledgement when reading from the operating system. | Retry; CPU may be in STOP/RUN transition. |
| 80A2 | DP error or partial list read error (slot empty / module not plugged). | Treat as "no module"; advance to next slot. |
| 80B1 | Destination area DR is too small. | Increase length of the ANY pointer in the call. |
| 80B2 | SSL_ID not supported on this CPU / firmware. | Check HW Config firmware version; xy1C is mandatory but some older 3xC CPUs restrict the index. |
| 80B4 | SSL_ID is not supported when the CPU is in this operating mode. | Retry in RUN; some partial lists are only readable in STOP. |
| 8xyy | General error from a lower layer (xyy = vendor-specific). | Check diagnostic buffer with SFC59 "RD_REC". |
8. Verifying the Serial Number Read
- Open the online SZL viewer in STEP 7: PLC → Module Information → Diagnostic Buffer is not the SSL, but PLC → Accessible Nodes → Online & Diagnostics exposes the SSL in raw form. Navigate to the partial list
xy1Cand confirm the serial number for slot 4 of rack 0 matches the value stored in DB110 by the user program. - Cross-check with the CPU's own SZL view: SIMATIC Manager → PLC → Module Information → "Module Identification" tab (if available in your STEP 7 version). This is the same data the user program reads.
- Set a watchpoint in DB110 in online mode; the
serialfield should populate with a 24-character ASCII string beginning with "S" for Siemens modules (e.g., "S C-P 7 6 6 6 6 6 6 ...") followed by module-specific characters. Pad characters should be B#16#20 or B#16#00. - Compare the serial number printed on the module's front plate with the ASCII string stored in DB110. For 4 racks × 8 slots = 32 expected entries, all 32 must match the physical labels. If any slot shows an empty STRING, the slot is unconfigured or the module is missing; if it shows the CPU's serial number, the INDEX is wrong (you read the CPU rather than the SM).
- Confirm CPU scan time is unchanged (or only marginally higher) when the scan OB is active. A spike of 100-200 ms on a 4-rack station is normal; a spike of >500 ms indicates the destination buffer is too small and SFC51 is retrying.
9. Field-Proven Caveats
-
CPU vs module serial number: The CPU and the MMC expose their serial numbers via separate SSL partial lists (
W#16#001Cfor module identification without serial, and direct MMC commands via SFC58/59). Thexy1Ccall with a valid slot index always returns the slot's module serial number, never the CPU's. -
IM/CP/FM modules also report a serial number under
xy1C; the same call works unchanged for them, including the IM460/IM461 send/receive pair and FM350/FM351 counter modules. - ET 200S / ET 200M distributed I/O: for PROFIBUS DP slaves, the rack/slot encoding becomes head number + slot in the slave. Use the standard PROFIBUS slot numbering: head = DP master system ID, slot = 0..255. The returned record format is the same 34 bytes.
- Firmware restrictions: Some early S7-300 CPU 31x-1 firmware versions (V1.x) do not return the serial number on digital input/output modules (DI/DO) when the module was manufactured before 2004. In that case the field is filled with B#16#20 (blanks) and the call still returns RET_VAL = 0. The only workaround is to use the physical label.
-
Byte order in the WORD field: The serial number is stored as ASCII in two characters per WORD. The low byte is the first character, the high byte is the second — i.e., little-endian. This matches how STEP 7 stores BYTE arrays but trips up engineers who assume big-endian.
DB100.DBB 4is character 1,DB100.DBB 5is character 2, etc.
10. Comparison: SSL xy1C vs Other Identification Methods
| Method | Source | Scope | Returns serial number? | Programmatic? |
|---|---|---|---|---|
SSL xy1C via SFC51 |
CPU's system status list | Local station, all modules | Yes (24 chars ASCII) | Yes |
SSL xy11 via SFC51 |
CPU's system status list | Module identification | No (order number, type ID, version) | Yes |
| STEP 7 Module Information | Online view | One module at a time | Yes | No (operator only) |
| Module front label | Physical | One module | Yes | No |
| GSD file (PROFIBUS DP) | Slave manufacturer | Vendor + type only | No (no per-unit serial) | N/A |
| SFC59 "RD_REC" DSO record | Module diagnostic interface | Module-specific | Only on modules that implement DSO record 1 | Yes |
11. Frequently Asked Questions
Can SFC51 with SZL-ID W#16#xy1C return the serial number of every signal module in a 4-rack, 8-slot-per-rack S7-400 station?
Yes. Set INDEX = W#16#FFFF to retrieve the records for all slots of all racks in a single call (the destination DB must be sized for N_DR × 34 bytes, typically 32 modules × 34 = 1088 bytes), or call SFC51 in a rack/slot loop with INDEX = (rack SHL 8) OR slot for bounded memory usage.
Why is the component-ID field zero or the serial-number field all blanks even though the module is plugged in?
Either the slot is unconfigured in HW Config (the SSL returns no record), the module is from a pre-2004 manufacturing batch that does not embed a serial number (older S7-300 firmware V1.x), or the destination buffer is too small and SFC51 truncated the record. Increase the buffer to at least 34 bytes and re-download the hardware configuration.
What is the difference between SSL partial list W#16#011C and W#16#001C?
W#16#001C returns the module's basic identification (component ID B#16#01, order number, version) without the serial number. W#16#011C (the xy1C family, index byte 01) returns component identification with the 24-character ASCII serial number, identified by component ID B#16#05. Use W#16#011C when you need the serial number, and W#16#001C when you only need the order number / firmware version.
Does reading the serial number affect the CPU's cycle time?
Yes, each SFC51 call takes 2-4 ms on an S7-400 CPU 41x and 5-10 ms on an S7-300 CPU 31x. A full scan of 32 modules therefore adds 70-300 ms. Trigger the scan from a cyclic OB (OB35 every 100-1000 ms) or from an operator-initiated function rather than OB1 to avoid main-scan jitter. Do not call SFC51 with W#16#xy1C inside a time-critical interrupt OB (OB40).
Can the same approach read the serial number of ET 200S or ET 200M distributed I/O modules?
Yes. For PROFIBUS DP slaves, build the SSL index from the head (DP master system ID, 0..127) in the high byte and the slot (0..31 or 0..63 depending on the slave) in the low byte. The 34-byte record format is identical. For PROFINET IO devices, the same SZL entry is available; check the CPU's firmware release notes for the head/slot encoding on your specific CPU, as the PROFINET slot numbering differs from PROFIBUS.