Reading Signal Module Serial Numbers on S7-300/S7-400 with SFC51

David Krause14 min read
S7-300SiemensTutorial / How-to
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

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; xy1C is 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:

Table 1 — SFC51 RDSYSST input / output parameters
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:

Table 2 — INDEX structure for SZL-ID W#16#xy1C
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
Engineering note: Set the rack/slot index to a specific slot (e.g., 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:

Table 3 — Record layout of SZL-ID W#16#xy1C (DR area)
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 safety: The header reports 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:

  1. Initialise a pointer to the next free record in the result DB (start at byte 0).
  2. For Rack := 0 TO 3:
  3. For Slot := 1 TO 18 (or 1..8 if the station is constrained to 8 slots):
  4. Build the SSL index, call SFC51, wait for BUSY = FALSE and RET_VAL = 0.
  5. 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.
  6. 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
Cycle-time awareness: Each SFC51 call consumes 2-4 ms of CPU time on an S7-400 (more on S7-300). Trigger the sweep from a slow OB (e.g., OB35 every 100 ms) or from an operator-initiated function rather than OB1 to avoid jitter on the main scan. For a 4 × 8 topology with 32 modules, expect 70-130 ms of SSL traffic per full scan.

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

Table 4 — SFC51 RET_VAL codes relevant to xy1C reads
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

  1. 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 xy1C and confirm the serial number for slot 4 of rack 0 matches the value stored in DB110 by the user program.
  2. 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.
  3. Set a watchpoint in DB110 in online mode; the serial field 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.
  4. 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).
  5. 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#001C for module identification without serial, and direct MMC commands via SFC58/59). The xy1C call 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 4 is character 1, DB100.DBB 5 is character 2, etc.

10. Comparison: SSL xy1C vs Other Identification Methods

Table 5 — Methods to read a module's serial number on S7-300/400
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.

Back to blog