S7-200 to S7-300 Indirect Addressing Conversion Using SFC20

David Krause12 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

S7-200 to S7-300 Indirect Addressing Conversion Using SFC20 BLKMOV

Siemens S7-200 indirect addressing syntax such as *LD4 (where the destination address is read from local double-word LD4) does not have a 1:1 equivalent in the S7-300 / S7-400 instruction set. The replacement pattern is to construct an ANY pointer in a temporary variable and pass it to SFC20 BLKMOV. This article covers the ANY data structure, the SFC20 interface, the conversion procedure, complete STL and SCL code, verification steps, and the RET_VAL error matrix.

1. Overview of the Conversion Problem

In a STEP 7 Micro/Win S7-200 program the block-move operation typically looks like the following ladder snippet:

  • Source area: VW10000 (fixed start address)
  • Destination area: *LD4 (indirect, the actual address is supplied by local double-word LD4)
  • Length: 4 bytes

The S7-200 CPU evaluates *LD4 at runtime, so the destination is dynamic. The S7-300 / S7-400 instruction set removes pointer dereferencing operators from ladder (FBD/LAD). To preserve the same runtime behavior the S7-300 engineer must:

  1. Build a 10-byte ANY pointer in a temporary DB or in the local stack (LW / P#).
  2. Call SFC20 BLKMOV and pass that ANY pointer as SRCBLK or DSTBLK.
  3. Handle the RET_VAL word to detect parameter errors at runtime.
Memory-class rule. STEP 7 rejects any ANY pointer whose memory class field does not match the area you are reading or writing. Building the ANY in STL is the standard technique because it gives bit-level access to all 10 bytes. In SCL you build the same structure using the POINTER / ANY data type and an AT view.

2. Prerequisites

  • STEP 7 V5.5 or STEP 7 Professional (TIA Portal V13+ for S7-300/S7-400 with the S7-300/S7-400 option package). See the STEP 7 V5.5 SP2 download page.
  • S7-300 CPU 31x or 32x, or S7-400 CPU 41x, with firmware that supports SFC20 (all standard S7-CPU firmware).
  • S7-200 source program (STEP 7 Micro/Win project) for reference. The Micro/Win IDE is not required for the target S7-300 build.
  • Working knowledge of STL bit-slicing (L, T, LAR1, +AR1) or SCL AT-view on STRUCT.

3. Anatomy of the STEP 7 ANY Pointer (10 Bytes)

The ANY pointer is the universal "address + length + repetition" descriptor used by SFCs, SFBs, and FC parameter declarations of type ANY. Layout for the S7-300:

Byte Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
0 Syntax ID (10h = area-internal, 11h = area-cross-section via DB no., 16h = area-cross-section via DB no. + memory area, etc.)
1 Transport size in bits per element: 01=BYTE, 02=WORD, 04=DWORD
2,3 Number of elements (WORD, little-endian, 1..n)
4,5 DB number (only when Syntax-ID >= 16h) or 0
6 Memory area ID: 81h=Input (I), 82h=Output (Q), 83h=Bit memory (M), 84h=DB data, 85h=DI data, 86h=L stack, 87h=V (S7-200 legacy)
7,8,9 Byte address within the area, 24-bit, byte-granular. Bits 7/8/9 = bits 24/25/26/27 of the address when the transport size is BIT; otherwise the address is bit-shifted by the transport-size field.

For SFC20 BLKMOV the transport size must be BYTE (01) and the length must be expressed as a number of bytes; therefore the byte address is used as-is.

3.1 Common ANY combinations

Area Byte 0 (SynID) Byte 1 (Trans) Byte 2/3 (Qty) Byte 4/5 (DB) Byte 6 (Area) Bytes 7..9 (ByteAddr)
Inputs (I) 10h 01h n (WORD) 0000h 81h P# byte address
Outputs (Q) 10h 01h n (WORD) 0000h 82h P# byte address
Bit memory (M) 10h 01h n (WORD) 0000h 83h P# byte address
Global DB (DBX) 10h 01h n (WORD) DB no. 84h P# byte address
Instance DB (DIX) 10h 01h n (WORD) DI no. 85h P# byte address
L stack (local) 10h 01h n (WORD) 0000h 86h P# byte address
Endianness. The byte address occupies bytes 7, 8, 9 of the ANY. In a 32-bit word that address is stored low-byte-first (little-endian). When using STL with byte-by-byte loads, place the low byte at offset 7, the high byte at offset 9. SCL's AT-view on a DWORD gives you the right layout automatically when you use DWORD_TO_POINTER semantics on area-cross-section pointers.

4. SFC20 BLKMOV Interface

Parameter Declaration Data Type Description
SRCBLK INPUT ANY Source area. Pointer to first byte of source + length.
RET_VAL OUTPUT (INT) INT Return value. 0 = OK, non-zero = error (see section 8).
DSTBLK OUTPUT ANY Destination area. Pointer to first byte of destination + length.

SFC20 copies exactly count bytes starting at the address inside SRCBLK to the address inside DSTBLK. Overlapping source and destination areas are handled correctly: SFC20 uses an internal intermediate buffer to avoid corruption. Maximum length per call is 512 bytes.

5. Step-by-Step Migration Procedure

  1. Identify the dynamic operand. In the S7-200 source, locate every usage of *LD / *VW inside a BLKMOV block. Note the format (DB number, area code, byte offset) of each dynamic pointer.
  2. Choose a work area. Reserve a 10-byte ANY in a global DB or in the local stack of the FC/FB. The local stack is volatile and is the recommended location when the ANY only lives during one call.
  3. Populate the ANY. Either pre-assemble it in the OB1 startup or assemble it on every call. For runtime-built pointers, place the 10 bytes into a temporary ANY tag using STL byte moves.
  4. Call SFC20. Pass the constructed ANY to SRCBLK (when the source is static and the destination is dynamic) or to DSTBLK (when the destination is static and the source is dynamic). For both dynamic, pass two ANY tags.
  5. Evaluate RET_VAL. Connect the output to a status word and, if desired, raise an OB82 / OB121 fault on a non-zero return.
  6. Verify. Use a VAT table or PLCSIM to inspect memory before and after the SFC20 call, confirm length, address, and data integrity.

6. STL Example: Dynamic Destination in a Global DB

Task: copy 10 bytes from P#I 0.0 BYTE 10 (inputs IB0..IB9) to a destination inside DB100 whose start offset is supplied by MW200. Length is fixed at 10 bytes.

// FC "Build_Any_And_Move"
// Input parameter:  i_destByteOffset (INT) - destination byte offset in DB100
// In/Out parameter: io_status (WORD) - RET_VAL mirror

      L     P##src_any_static        // Pointer to constant source ANY
      LAR1
      L     P##dst_any               // Pointer to work ANY in local stack
      LAR2

      // Build DSTBLK ANY for DB100, offset = i_destByteOffset, length 10
      L     B#16#10                  // Syntax ID = area-internal
      T     LB    6                   // dst_any[0]
      L     B#16#01                  // Transport size BYTE
      T     LB    7                   // dst_any[1]
      L     10                       // Count
      T     LW     8                  // dst_any[2..3]
      L     0                        // DB-no field unused for SynID=10h
      T     LW    10                  // dst_any[4..5]
      L     B#16#84                  // Area = DB
      T     LB    12                  // dst_any[6]
      L     i_destByteOffset          // runtime offset
      SLD   3                        // convert byte offset to bit address
      T     LD    13                  // dst_any[7..10]

      CALL  SFC   20
      SRCBLK := P#I 0.0 BYTE 10
      RET_VAL:= MW   1000
      DSTBLK := dst_any

Notes on the STL code:

  • P##src_any_static is a pointer literal to a 10-byte constant declared in the FC's TEMP area, or directly to P#I 0.0 BYTE 10.
  • The SLD 3 instruction shifts the byte offset left by 3 bits, producing a 24-bit bit-address (bytes 7..9 of the ANY), exactly what SFC20 expects when the transport size is BYTE.
  • If the destination lies in an instance DB instead of a global DB, set the Syntax ID to 10h, the Area byte to 85h, and place the instance DB number in bytes 4..5.

7. SCL Example: AT-View on a STRUCT

SCL hides the byte layout behind the POINTER and ANY data types, but you can still access the inner fields with an AT view. The following FC builds the same destination ANY and calls SFC20.

FUNCTION FC 100 : VOID
VAR_TEMP
  t_retVal     : INT;
  t_srcAny     : ANY;
  t_dstAny     : ANY;
  t_dstView    : AT  VIEW OF t_dstAny : STRUCT
                  synID   : BYTE;
                  trans   : BYTE;
                  count   : WORD;
                  dbno    : WORD;
                  area    : BYTE;
                  addr    : DWORD;
                END_STRUCT;
END_VAR
VAR_INPUT
  i_destByteOffset : INT;    // Destination byte offset inside DB100
END_VAR
BEGIN
  // Static source ANY (built once via literal in OB1 or initializer)
  t_srcAny := P#I 0.0 BYTE 10;

  // Build the destination ANY byte by byte using the AT view
  t_dstView.synID := B#16#10;          // area-internal
  t_dstView.trans := B#16#01;          // BYTE
  t_dstView.count := 10;               // 10 bytes
  t_dstView.dbno  := 0;                // unused for SynID=10h
  t_dstView.area  := B#16#84;          // DB
  t_dstView.addr  := SHL(IN:=WORD_TO_DWORD(INT_TO_WORD(i_destByteOffset)),
                         N:=3);        // byte -> bit shift

  SFC20(SRCBLK := t_srcAny,
        RET_VAL:= t_retVal,
        DSTBLK := t_dstAny);

  IF t_retVal <> 0 THEN
    // Save RET_VAL in MW1000 to surface in VAT/PLCSIM
    "DB_Status".SFC20_RetVal := t_retVal;
  END_IF;
END_FUNCTION

8. RET_VAL Error Matrix for SFC20

RET_VAL (hex) Meaning Recommended action
0000h No error. None.
8091h Source ANY pointer out of process image / DB range. Validate the constructed bytes 6/7/8/9. Check that the Syntax ID and memory area ID match.
8092h Destination ANY pointer out of process image / DB range. Same as 8091 but for DSTBLK.
80A1h Source ANY has transport size != BYTE. Force byte 1 of the ANY to 01h.
80A2h Destination ANY has transport size != BYTE. Force byte 1 of the ANY to 01h.
80B1h Source area length = 0 or > 512. Clamp count to 1..512.
80B2h Destination area length = 0 or > 512. Clamp count to 1..512.
80C1h Source byte range overlaps target byte range in unsupported way. Split into two SFC20 calls.
8xyyh (general) CPU fault during block copy. Refer to STEP 7 System Software manual for the xy encoding.

9. Verification

  1. Static VAT check. Create a VAT with the source bytes (e.g., IB0..IB9) and the destination DB area (DB100.DBB0..DB100.DBB9 or any offset). Trigger the FC and confirm a data-id match.
  2. Monitor control bits. Use PLCSIM or a real CPU. Place a breakpoint inside FC100 (in SCL) or a single-step in STL and inspect the temp ANY bytes after the AT-view population.
  3. Edge cases.
    • Set i_destByteOffset to 0, -1 (illegal), and the maximum legal value (DB size - 10). The first must succeed, the second must return a non-zero RET_VAL, the third must succeed.
    • Change the DB number at runtime. Replace t_dstView.dbno with another open DB to confirm that the Syntax ID / area combination works for both 84h (global DB) and 85h (instance DB).
  4. Performance. SFC20 execution time depends on length and CPU. For a 10-byte copy on an S7-315-2 PN/DP expect < 50 us; on an S7-412 expect < 20 us. Larger copies scale linearly. If a sub-millisecond cycle is required, place the SFC20 call inside OB35 with the appropriate phase offset.

10. Troubleshooting

Symptom Likely root cause Fix
SFC20 returns 8091h on a DB source. Syntax ID set to 10h but DB number field non-zero, or DB not loaded. For area-cross-section pointer, use Syntax ID 16h; for area-internal use 10h with DB number = 0.
SFC20 returns 80A1h. Transport size set to 02h (WORD) by mistake. Hard-code byte 1 of the ANY to 01h.
CPU goes to STOP after the call. Destination offset beyond DB length, or DB not present. Validate i_destByteOffset + count against the DB length; ensure the destination DB is loaded in OB100 / OB1 startup with SFC22 / SFC23 or SFC24 / SFC25 as needed.
Data copied but offset is 8x too large. Byte offset was loaded without the SLD 3 / SHL(...,3) shift. Always shift the byte offset left by 3 to obtain the bit address required by the ANY pointer.
Data scrambled / wrong area. Memory area byte (offset 6) wrong. 83h = M, 84h = DB, 85h = DI, 86h = L stack.
Single-byte instead of multi-byte copy. Count word (bytes 2/3) set to 0. Set count to the actual length BEFORE calling SFC20.

11. Portability Notes (S7-400 / TIA Portal / S7-1500)

  • The same ANY layout applies to S7-400 and to the S7-300 as a derivative. On S7-400 the maximum SFC20 length is still 512 bytes.
  • In TIA Portal, SFC20 is exposed as BLKMOV inside the "Basic Instructions" palette and supports the same ANY input format. The legacy AT-view trick still works.
  • On S7-1500, the MOVE_BLK_VARIABLE instruction replaces SFC20; it uses the VARIANT data type instead of an ANY. The dynamic pointer concept still applies, but at a different syntactic level. If the code must run on both S7-300 and S7-1500, keep the SFC20 call in a dedicated FC and gate it by CPU type, or use a wrapper FB on S7-1500 that accepts a VARIANT.

12. Field-Commissioning Checklist

  • [ ] All dynamic offsets used at runtime have been range-checked against the destination DB size before calling SFC20.
  • [ ] RET_VAL is wired to a status word that HMI can read.
  • [ ] A non-zero RET_VAL triggers a one-shot alarm so that the error is captured even if it clears before HMI polls.
  • [ ] A watchdog timer (e.g., OB80) is enabled if the SFC20 is critical-path.
  • [ ] All DBs referenced by ANY pointers are loaded and unlinked (avoid download in RUN when DB length changes; use "Download in RUN" with care).
  • [ ] A reference S7-200 program (or printout) is archived in the project vault for audit trail.

13. Frequently Asked Questions

Can I keep the S7-200 pointer syntax *LD4 on an S7-300?

No. The asterisk dereference operator is a STEP 7 Micro/Win construct and is not recognized in STEP 7 (LAD/FBD/STL). Replace it with a runtime-built ANY pointer that is passed to SFC20 BLKMOV (or another ANY-aware block).

What is the maximum length that SFC20 BLKMOV copies in one call?

512 bytes. For longer transfers call SFC20 in a loop, incrementing the byte offset of the source and destination ANYs by 512 on each iteration. Verify that the loop counter never exceeds the total length.

Why does SFC20 return 8091h even though the destination DB exists?

The most common reason is that the Syntax ID in the ANY is wrong. Use 10h for area-internal (DB number field must be 0) or 16h for area-cross-section (DB number field set to the target DB). A second cause is the bit-address not shifted left by 3, which yields a misaligned address.

Does SFC20 work on instance DBs (DI)?

Yes. Set the memory area byte (offset 6) of the ANY to 85h and place the instance DB number in bytes 4..5 of the ANY. The Syntax ID remains 10h for area-internal pointers; use 16h only when crossing area boundaries.

How do I migrate the same code to TIA Portal / S7-1500?

For TIA Portal V13+ on S7-300/400 use SFC20 BLKMOV with the same ANY layout. For S7-1500 replace SFC20 with the MOVE_BLK_VARIABLE instruction, which accepts a VARIANT instead of an ANY. Wrap the call in a dedicated FC so that the migration is localized.

Back to blog