Siemens SFC59 RD_REC: Reading Module Data Records in S7-300/400

David Krause14 min read
S7-300SiemensTechnical 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 SFC59 RD_REC

Siemens SFC 59 "RD_REC" (Read Record) is a standard system function supplied in the SIMATIC S7-300 and S7-400 CPU operating system. It is the canonical mechanism for reading parameter records (data records / DS) out of a distributed I/O module on PROFIBUS-DP or PROFINET IO. The function transfers a request to the addressed module, the module interprets the record number and replies with a byte stream whose layout is defined entirely by the device manufacturer (Siemens or third-party).

The function executes asynchronously on S7-300/400: a single call dispatches the request, and the CPU continues. The programmer must poll the BUSY and RET_VAL outputs to determine completion. This behavior is different from the IEC-standard RDREC instruction on S7-1500, which is also asynchronous but reports status through the ENO / STATUS semantics of TIA Portal instructions.

The defining engineering rule is the one that the original forum question was about: SFC 59 does not allocate or interpret the destination area. The programmer must declare RECORD as a sufficiently large ANY-pointer-compatible area before the call, and the byte layout of that area must match the data record layout specified in the device manual. If the target area is undefined, has the wrong length, or is not in a global DB, the function returns one of the negative acknowledgments documented below.

Prerequisites

  • STEP 7 V5.5 or V5.7 with the S7-300/S7-400 system functions library installed. The relevant reference manual is the SIMATIC S7-300/400 Standard Software - System and Standard Functions Reference Manual.
  • Hardware configuration (HW Config) loaded into the CPU with the target module configured at a known logical base address.
  • The module's GSD file imported, or for Siemens ET 200 stations, the ET 200 device manual defining the available data record numbers (0, 1, 2, ... 240 typically).
  • A global DB with a destination area of the correct size and an ANY-compatible declaration. The DB may be of any block type (DB, M, bit memory), but the pointer passed to RECORD must point to a global data area; instance DBs and local stack are not permitted.
  • STEP 7 online connection to the CPU for testing; the RD_REC call cannot be verified offline.

Call Interface and Parameters

The function block is called with the following input and output parameters. All multi-byte values are little-endian per Siemens convention. RECNUM and LADDR are WORD-type; the value of LADDR is the same logical address that appears in HW Config for the slot or channel of the target module.

Parameter I/O Type Description
REQ IN BOOL Edge-triggered start. Set TRUE to dispatch a new read job. Reset before the next edge to retrigger.
IOID IN BYTE Identifier of the address area. B#16#00 = inputs, B#16#01 = outputs, B#16#02 = mixed (e.g. for PROFINET modules where the slot is not separated into pure I or Q).
LADDR IN WORD Logical base address of the module (slot start address from HW Config). Example: W#16#0100 for input address 256.
RECNUM IN BYTE Data record number to read (0-240 decimal, 0-EF hex).
RET_VAL OUT INT Return value / error code. 0000 on success (after the call that finishes the job), 7000h-7002h for status, negative (8xxxh) for error.
BUSY OUT BOOL TRUE while the job is in progress. FALSE means the job is finished and RET_VAL is final.
RECORD IN_OUT ANY Destination area where the read data record bytes are written. The first 2 bytes of the area are reserved by Siemens in some interpretations for the record length; consult the device manual.
Important: The RECORD parameter is a full ANY pointer. Pass it exactly as you would for a BLKMOV (SFC 20) or PUT/GET call. Local stack variables (declared TEMP) are not acceptable as RECORD targets because they may be overwritten by interrupt OBs before the asynchronous job completes.

Designing the Destination Area (RECORD)

The original forum thread touched on the most common source of error: calling SFC 59 with an undefined or under-sized destination. SFC 59 does not create a DB on demand and does not validate that the destination layout matches the record. The CPU firmware simply performs a fixed-length byte copy of the response payload into the memory region pointed to by RECORD, then returns. If the target is too small, the surplus bytes are lost; if it is too large, the unused bytes are untouched.

Recommended procedure:

  1. Open the device manual of the target module (e.g. ET 200S 1SI module manual) and identify the record numbers you intend to read.
  2. For each record number, note the data type, length, and meaning of every byte or word. Most diagnostic records are 4-32 bytes, but parameter records can exceed 200 bytes (e.g. ET 200S parameter record 128 = 128 bytes).
  3. In a global DB, declare a structure whose total length is at least the record's maximum possible size. Allow a few bytes of headroom for vendor revisions that extend a record.
  4. Pass the structure's symbolic name to RECORD using the STEP 7 "Point to symbol" feature, or build the ANY pointer manually with P#DB100.DBX0.0 BYTE 64 syntax.
Field note: A frequent mistake is to pass an ANY pointer that points to a 2-byte WORD. SFC 59 will read the full record into memory after the WORD, overwriting whatever is there, because the CPU will not truncate to the declared length - it uses the real bus payload length. Always size the RECORD to the worst case defined in the device manual.

Data Record Structure Per Device Family

The byte stream returned by RD_REC is 100% vendor-defined. The following table gives a quick reference for the most common Siemens modules. Always verify against the device manual before commissioning.

Module / Family Record # Length (bytes) Contents
ET 200S 1SI serial interface 0-3 4-128 Serial port parameters (baud, parity, framing), per-channel.
ET 200S motor starter 0-7 4-16 Trip history, motor current, switching cycle counters.
ET 200M analog input SM 331 0, 1, 128 8-16 Manufacturer diagnostics, channel-specific errors, parameter re-read.
ET 200eco PN 0-127 varies Channel diagnostics, port status.
PROFINET IO device, generic 0x8000-0xBFFF varies Per-channel / per-slot diagnostics, index assignment per GSDML.
PROFIBUS-DP slave, generic 0-240 varies Per-slot diagnostic; record 0 is always the standard DP diagnostic.
S7-1500 (via RDREC) 0-240, plus 0x8000+ varies Same conceptual model; see TIA Portal HELP RDREC.

Code Examples

STL (Statement List) - S7-300/400

// Assumes DB100 has been pre-declared with a 64-byte array "DiagBuffer"
CALL SFC 59
REQ      := M 10.0          // Edge-triggered start request
IOID     := B#16#54         // 0x54 = input identifier (legacy form)
                          // For mixed modules use B#16#55
LADDR    := W#16#0100       // Module base address 256 decimal
RECNUM   := B#16#01         // Read data record 1
RET_VAL  := MW 12           // Return code, integer
BUSY     := M 10.1          // TRUE while job running
RECORD   := P#DB100.DBX0.0 BYTE 64   // Destination: 64 bytes in DB100

SCL (Structured Control Language) - S7-300/400

IF StartRecord AND NOT BusyFlag THEN
   BusyFlag := TRUE;
   SFC59_REQ := TRUE;
ELSE
   SFC59_REQ := FALSE;
END_IF;

IF BusyFlag THEN
   // SFC 59 returns through a multi-instance call;
   // here we use the symbolic form via FB wrapping
   RetVal := RD_REC(
      REQ    := SFC59_REQ,
      IOID   := 0,            // 0 = input
      LADDR  := 256,          // base address
      RECNUM := 1,
      RECORD := DiagBuffer    // symbol from global DB
   );
   IF RetVal = 0 THEN
      BusyFlag := FALSE;
      // DiagBuffer now contains data record 1
   ELSIF (RetVal < 0) OR (RetVal = 7000) THEN
      BusyFlag := FALSE;
      // Handle error - see RET_VAL codes table below
   END_IF;
END_IF;

LAD (Ladder) - S7-300/400

In LAD/FBD, drag SFC 59 from the standard library onto your network. STEP 7 will auto-generate the EN/ENO calls and an instance DB for the parameter retention. Wire REQ from a positive edge contact, LADDR from a constant of type WORD, and connect the RECORD input by right-clicking and selecting the DB symbol.

S7-1500 / TIA Portal (RDREC)

// RDREC on S7-1500: TIA Portal instruction, NOT SFC 59
#Busy := RDREC(
   REQ      := #startTrigger,
   ID       := 256,                  // HW identifier from device table
   INDEX    := 1,                    // Data record number
   MLEN     := 64,                   // Max length to be read
   VALID    := #recordValid,
   BUSY     := #busy,
   ERROR    := #error,
   STATUS   := #status,
   RECORD   := %DB100.DiagBuffer      // Symbolic DB access
);

The ID parameter is the HW identifier from the device configuration (a DWORD, e.g. 257), not a byte address. MLEN is the maximum bytes to read - this explicit length parameter is a safety improvement over SFC 59.

RET_VAL Error Codes

The RET_VAL (or STATUS on RDREC) return is the single most important field for diagnostics. The following values apply to SFC 59 on S7-300/400; RDREC on S7-1500 uses a superset of these plus the IEC 61131-3 error classes.

RET_VAL (hex) Meaning Typical Cause
0000 Success - record read, BUSY now FALSE Normal completion on the call that returns BUSY=FALSE
7000 No job active, BUSY=FALSE Initial call before REQ=TRUE, or just completed
7001 First call, job dispatched, BUSY=TRUE REQ just went TRUE; check back next OB1 cycle
7002 Intermediate call, job in progress, BUSY=TRUE Job still pending - do NOT re-trigger
8090 Logical base address invalid LADDR not in HW Config, or wrong module type
8092 RECORD points to a length of 0 Destination ANY with zero-byte length
8093 LADDR is configured but no slot is present Slot pulled or module swapped and not re-parameterized
80A0 Negative acknowledgment reading from module Module does not support this record number
80A1 Negative acknowledgment writing to module Usually a RD_REC quirk - check RECNUM range
80B0 Module not configured / not PROFIBUS/PROFINET Wrong LADDR - check the slot table
80B1 Target length (RECORD) < source length RECORD too small - extend destination DB
80B2 RECNUM greater than 240 Check record number encoding (BYTE, 0-EF)
80B3 Not allowed (record not permitted) Vendor has restricted access to this record
80C0 Vendor-specific read error Module returned error code; consult vendor manual
80C1 Record length exceeds max Vendor says this record is longer than the bus allows
80C2 Record length less than minimum Record is reserved for vendor and is too small to use
80C3 Resource busy, retry recommended Module is processing another job; back off and retry
80C4 Communication error on DP/PN Bus fault, station failure, re-diagnose
80D0 System error in module Module returned without data; usually a hardware fault

Asynchronous Execution and Polling Logic

Because SFC 59 executes across multiple OB1 cycles, the call must be edge-triggered and the BUSY flag must be used to gate the next call. The recommended pattern is:

  1. On a positive edge of the user's start trigger, set REQ := TRUE and call SFC 59.
  2. Read back BUSY and RET_VAL.
  3. If BUSY := TRUE, do nothing - let the next OB1 cycle observe the result. Critically, do NOT re-set REQ while BUSY is TRUE, or you will cancel the in-flight job.
  4. When BUSY := FALSE, evaluate RET_VAL. 0000 = success, negative = error (see table above).
  5. Reset REQ and arm for the next edge.
Field note: In S7-300, the asynchronous call can take 1-3 OB1 cycles on a lightly loaded bus, but on a heavily loaded PROFIBUS-DP with many slaves, it can stretch to 100-500 ms. On PROFINET IO it is usually 1-2 cycles. Do not assume synchronous semantics when building polling loops in OB1.

Migration to S7-1500 (RDREC)

For new projects on S7-1500, ET 200SP, or any TIA Portal target, the IEC-standard instruction RDREC replaces SFC 59. Key behavioral differences:

  • Identifier is ID (DWORD, HW identifier from the device table), not LADDR + IOID.
  • MLEN explicitly bounds the read, eliminating the over-write risk of SFC 59.
  • Output VALID pulses for one cycle when new data is available - a cleaner edge signal than the BUSY/FALSE pattern of SFC 59.
  • Error reporting uses ERROR/STATUS instead of a single RET_VAL with hex codes. STATUS follows IEC 61131-3 error classes (e.g. 16#80B1 for RECORD overflow).
  • RDREC is placed in the program directly, not as a system function from a library. It is found under "Extended instructions > Distributed I/O > RDREC".

For migration of legacy SFC 59 code, the wrapper is straightforward: replace the IOID + LADDR pair with a single ID DWORD, add an MLEN literal matching the RECORD size, and adjust the post-call evaluation logic to use ERROR/STATUS. The full conversion table is in the TIA Portal online help under "RDREC - Read data record".

Verification Procedure

  1. Build a global DB with a 64-byte byte array named DiagBuffer. This is the RECORD target.
  2. In OB1, insert a CALL to SFC 59 with REQ tied to a tag-controlled edge, IOID = 0 (input), LADDR = 256 (your module base address), RECNUM = 1, RECORD = P#DB100.DBX0.0 BYTE 64.
  3. Trigger a positive edge on the REQ tag (use a SET / RESET from the STEP 7 debug watch table, or a force in online mode).
  4. Open the SFC 59 instance in the online block view and observe BUSY toggle from TRUE to FALSE within a few OB1 cycles.
  5. Check RET_VAL; if 0, open the destination DB and verify the byte pattern matches the record layout from the device manual. A diagnostic record from an ET 200S 1SI module, for example, will start with bytes that correspond to baud rate, then parity, framing, etc.
  6. Test the error path: change RECNUM to an unsupported value (e.g. 200) and re-trigger. Expect RET_VAL = 16#80A0 (negative ack) and a new error entry in the diagnostic buffer.

Troubleshooting Matrix

Symptom First Check Fix
RET_VAL = 8090 at first call Verify LADDR in HW Config Use the slot's input base address, not the diagnostic address
RET_VAL = 80B1 after first cycle RECORD ANY too small Resize destination DB to vendor-spec length
RET_VAL stays at 7001 / BUSY never clears Bus fault? Module pulled? Check SF LED on the slave, look at OB82 (diagnostic interrupt) and OB86 (rack failure)
Record data looks like garbage Byte order wrong in the DB Confirm the device manual's byte order; some vendors use big-endian
Different PLC gets different values for the same record CPU firmware version Newer CPU firmware may enforce stricter RECORD size checks
Call works once then RET_VAL = 8093 LADDR conflicting with another call Make sure multiple SFC 59 calls do not share LADDR on S7-300 with limited parallel jobs
RDREC on S7-1500 returns STATUS 16#80B2 INDEX too large Limit INDEX to 0-255 (BYTE) unless the device manual explicitly says otherwise

Performance and Concurrency Limits

S7-300 CPUs have a limited number of asynchronous job slots. S7-313/314 allow 1-2 concurrent RD_REC calls, S7-315/316 allow 4-8, and S7-400 scales with the CPU type. If you issue more parallel calls than the CPU supports, the call returns RET_VAL = 16#80C3 (resource busy) and the request should be retried after a short back-off. S7-1500 RDREC does not have this hardware-imposed limit but is still subject to the underlying PROFINET/PROFIBUS job scheduler.

For high-frequency polling (e.g. reading diagnostic records every OB1 cycle), prefer the GET_DIAG function (SFC 13) for module-level diagnostics, and use RD_REC only for the less-frequent parameter-record reads. SFC 13 is fully synchronous and cheaper on the job pool.

FAQ

Does SFC 59 automatically create a destination DB for the read data record?

No. SFC 59 requires the destination area to be pre-declared by the programmer - typically a global DB with a byte array sized to match the maximum record length from the device manual. Pass it as an ANY pointer (e.g. P#DB100.DBX0.0 BYTE 64). If the destination is undefined or too small, the call returns RET_VAL = 16#80B1.

Where do I find the structure of the data record I want to read?

In the device manual of the addressed module (Siemens ET 200 manuals list records 0-240 with byte-by-byte layouts) or in the GSD/GSDML file for third-party devices. Record 0 on PROFIBUS is always the standard DP-V0 diagnostic; PROFINET uses indices in the 0x8000-0xBFFF range for channel diagnostics.

Why is BUSY still TRUE several OB1 cycles after I called SFC 59?

RD_REC executes asynchronously. The CPU dispatches the request, the bus scheduler queues it, the module processes it, and only on the next poll cycle does BUSY drop to FALSE. Wait for BUSY = FALSE before evaluating RET_VAL, and do not re-trigger REQ while BUSY is TRUE - that cancels the in-flight job.

What is the difference between SFC 59 and SFB 52 / SFB 53?

SFB 52 (RDREC) and SFB 53 (WRREC) are the S7-400 multi-instance / PROFIBUS-DP equivalents that support multiple parallel jobs and can be embedded as instances. On S7-300, SFC 59 / SFC 58 are the only options. On S7-1500, the RDREC / WRREC instructions replace both, with cleaner VALID/ERROR/STATUS outputs.

Can I use SFC 59 to read data records from an S7-1500 module on an ET 200SP?

No - SFC 59 is not available in the S7-1500 firmware. Use the RDREC instruction in TIA Portal. The call interface is similar (REQ, ID, INDEX, RECORD) but with an additional MLEN parameter and an HW identifier for ID instead of a byte address.

Back to blog