Using BLKMOV with ANY Pointer in Siemens S7 Function Blocks

David Krause13 min read
SiemensTIA PortalTutorial / 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

The BLKMOV (Block Move) instruction copies the contents of one memory area to another in a single operation. When called from inside a Function Block (FB) with re-usable instances, the source and destination addresses typically change per instance. The clean way to handle this in STEP 7 and TIA Portal is to expose the ResultDataPointer / DSTBLK input as an ANY-typed FB parameter, build that ANY pointer at the call site, and let the block copy arbitrary data without recompiling the FB.

This reference covers the S7-300/400 (SFC20 / classic STEP 7), S7-1200/1500 (native BLKMOV in TIA Portal V13.1+), the exact 10-byte (and 8-byte S7-1500) ANY pointer layout, FB declaration in SCL, multi-instance usage, and the most common BLKMOV/ANY errors observed in commissioning.

1. Overview: What BLKMOV Does

BLKMOV moves a contiguous block of bytes, words, or DWords from a source area (SRCBLK / SourceDataPointer) to a destination area (DSTBLK / ResultDataPointer). It is the binary equivalent of a memcpy and is non-destructive at the source.

Table 1. BLKMOV variants by controller family
Controller Implementation Symbolic name Max length Notes
S7-300 / S7-400 System Function SFC 20 BLKMOV (SFC20) 32 384 bytes ANY pointer = 10 bytes
S7-1200 Native instruction MOVE_BLK / BLKMOV 16 384 bytes Available in LAD/FBD/SCL
S7-1500 Native instruction MOVE_BLK / BLKMOV (legacy) 16 384 bytes (typ.) ANY pointer = 8 bytes (V2.0+)
WinAC / PC-based SFC 20 BLKMOV (SFC20) 32 384 bytes Same ANY layout as S7-400

According to the Siemens manual BLKMOV: Move block (STEP 7 Professional V13.1), the move operation runs in a single OB cycle and is typically used to copy DB contents, I/O areas, or M areas. See the Siemens support entry ID 109011420 for the official description.

2. Prerequisites

  1. Engineering tool: TIA Portal V13.1 SP1 or later (V16+ recommended for S7-1500). Classic STEP 7 V5.5 SP2+ for SFC20 usage.
  2. Controller firmware:
    • S7-1200: firmware V4.0 or higher (for optimized block access and the legacy BLKMOV variant).
    • S7-1500: firmware V1.5 minimum, V2.0+ recommended (extends ANY pointer handling and supports symbolic slice access).
  3. Library access: Standard library > Program blocks > Move operations in TIA Portal, or Standard Library > System Function Blocks > SFC20 in classic STEP 7.
  4. FB knowledge: variable declaration interface (Input, InOut, Static, Temp) and the difference between pass-by-value (Input) and pass-by-reference (InOut) for structured data.
Safety note: When BLKMOV is used to overwrite safety-relevant I/O or process-image areas, the source/destination must be validated for non-overlap and for compliance with the safety program signature. Siemens recommends using dedicated F-blocks for safety-related data movement; see the F-library in TIA Portal.

3. The ANY Pointer Structure

An ANY is a 10-byte (S7-300/400) or 8-byte (S7-1500, optimized) descriptor that contains all the information a block needs to access a variable without knowing its absolute address at compile time.

3.1 S7-300 / S7-400 ANY layout (10 bytes)

Table 2. S7-300/400 ANY pointer byte layout
Byte Content Meaning Example
0, 1 Syntax ID + 0x10 (Type) Data type code (see Table 3) 0x10 0x02 = BYTE
2, 3 Count Number of elements (not bytes) for elementary types, or DB number for DBW/DBD references 0x0064 = 100 elements
4, 5 DB number Source or destination DB (0 if not a DB) 0x000A = DB 10
6 Memory area Area code: 0x81=DB, 0x82=DI, 0x83=M, 0x84=P, 0x85=I, 0x86=Q, 0x87=L, 0x00=0x86 area byte padding 0x81 = DB
7, 8, 9 Byte offset 24-bit pointer to start byte (bit-addressing encoded) 0x00 0x00 0x08 = offset 8

3.2 S7-1500 ANY layout (8 bytes, optimized)

On S7-1500, the ANY pointer is reduced to 8 bytes when the parameter is declared as Variant in TIA Portal V14+. The legacy 10-byte form is still accepted by BLKMOV for compatibility, but new code should use the Variant data type for symbolic-any handling. The TIA Portal BLKMOV: Move block (S7-1500) reference describes the legacy BLKMOV that still accepts a 10-byte ANY.

3.3 Data type codes (byte 1 of the ANY)

Table 3. Common ANY data type IDs (byte 1)
Type ID (hex) Data type Element size Count unit
0x01 BOOL 1 bit (packed) bits
0x02 BYTE 1 byte bytes
0x03 CHAR 1 byte bytes
0x04 WORD 2 bytes words
0x05 INT 2 bytes words
0x06 DWORD 4 bytes double words
0x07 DINT 4 bytes double words
0x08 REAL 4 bytes double words
0x09 DATE 2 bytes words
0x0A TOD 4 bytes double words
0x0B TIME 4 bytes double words
0x0C S5TIME 2 bytes words
0x0E DATE_AND_TIME 8 bytes bytes
0x13 STRING 256 bytes max bytes

4. Declaring the BLKMOV Inputs in a Function Block

The key decision is which input category to use for the ANY pointer.

Table 4. Input category vs. ANY handling
Interface Pass-by Any type Supported? Use case
Input (VAR_INPUT) Value (copy) ANY Yes - copy at call time Read-only source; FB can read but the caller still owns the data
InOut (VAR_IN_OUT) Reference (pointer) ANY Yes - direct reference Destination written by the FB; caller sees updated data
Static (VAR_STAT) Instance area ANY Discouraged Only for one-off FBs that always move the same area

Rule of thumb:

  • SRCBLK (source) → declare as VAR_INPUT of type ANY.
  • DSTBLK (destination) → declare as VAR_IN_OUT of type ANY. Anything written by the FB must be reflected back to the caller's memory.

4.1 Example FB declaration block (SCL)

FUNCTION_BLOCK FB_MoveBlock
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1

   VAR_INPUT
      SRCBLK : ANY;        // Source area (input - pass by value/descriptor)
   END_VAR

   VAR_IN_OUT
      DSTBLK : ANY;        // Destination area (in-out - pass by reference)
   END_VAR

   VAR_INPUT
      Execute : BOOL;      // Edge-triggered execution
   END_VAR

   VAR_OUTPUT
      Done    : BOOL;
      Error   : BOOL;
      Status  : WORD;      // SFC20/UMOVE_BLK_RET error code
   END_VAR

   VAR_TEMP
      retVal  : INT;
   END_VAR

BEGIN
   IF Execute THEN
      retVal := BLKMOV(srcblk := SRCBLK, dstblk := DSTBLK);
      IF retVal = 0 THEN
         Done  := TRUE;
         Error := FALSE;
         Status := 0;
      ELSE
         Done  := FALSE;
         Error := TRUE;
         Status := WORD#16#8001 OR INT_TO_WORD(retVal);
      END_IF;
   END_IF;
END_FUNCTION_BLOCK

This declaration matches the Siemens SCL pattern for BLKMOV described in the TIA Portal V20 BLKMOV (S7-1500) reference.

5. Step-by-Step: Calling the FB from OB1 (SCL)

Step 1. Create two data blocks (or use a DB and a separate M area) to act as the source and destination.

DATA_BLOCK DB_Source
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   STRUCT
      Header   : ARRAY[0..9]  OF BYTE;     // 10 bytes
      Payload  : ARRAY[0..99] OF BYTE;     // 100 bytes
      Trailer  : ARRAY[0..9]  OF BYTE;     // 10 bytes
   END_STRUCT;
END_DATA_BLOCK

Step 2. Declare an instance DB of the FB, e.g. IDB_Move_1.

Step 3. In OB1, call the FB. The ANY pointers are constructed implicitly by TIA Portal when you drag a structured tag to the input pin.

OB1
BEGIN
   // Move DB_Source.Payload to a global M area (120 bytes total)
   "IDB_Move_1"(
      SRCBLK := "DB_Source".Payload,
      DSTBLK := "DB_Dest".Target,           // VAR_IN_OUT, same structure
      Execute := TRUE,
      Done    => "tag_Move_Done",
      Error   => "tag_Move_Err",
      Status  => "tag_Move_Status"
   );
END_OB

The compiler automatically builds the ANY descriptor with the right area code (0x81 for DB), DB number, type code (0x02 for BYTE), count = 100, and offset matching the start of Payload. No manual ANY construction is required if the source/dest are symbolic tags.

6. Manual ANY Construction (Classic STEP 7 / SFC20)

In classic STEP 7 V5.5 or when the source/dest is computed at runtime, the ANY must be built in a temporary variable before calling SFC20.

6.1 STL example (S7-300/400)

      CALL  SFC  20
       SRCBLK := P#DB10.DBX8.0 BYTE 100   // 100 bytes from DB10, offset 8
       RET_VAL := MW100
       DSTBLK := P#M 0.0 BYTE 100         // 100 bytes to MB0
       // Status 0 = OK
       // Status W#16#80A1 = alignment error, blocks must be byte aligned
       // Status W#16#80B2 = area length error
       // Status W#16#80B4 = pointer to slot 0 not allowed

6.2 Building an ANY in SCL when the DB number is dynamic

// Returns the size of the moved block, 0 on error
FUNCTION FC_BuildAny : INT
VAR_INPUT
   iDB      : INT;
   iOffset  : INT;
   iLength  : INT;
END_VAR
VAR_IN_OUT
   ioAny    : ANY;       // 10-byte ANY to be filled
END_VAR
VAR_TEMP
   pArea    : POINTER;   // 6-byte pointer helper
END_VAR
BEGIN
   // Build pointer portion (6 bytes at offset 4 of ANY)
   pArea := ADR(ioAny);                  // wrong, see below
   // Easier: use the temporary as P#DB.DBX
   // SCL does not allow direct ANY assembly; use the technique:
   ioAny := (DOUBLE_INT_TO_DWORD(iDB) AND 16#0000FFFF)
            + DWORD#16#81000000                  // area DB
            + SHL(DWORD#16#0,iOffset*8);  // pseudo - placeholder
   // In practice, use multi-assignment with TYPE helpers or move from
   // a static ANY template. See Siemens entry ID 22783999 for the
   // canonical pattern.
   FC_BuildAny := 0;
END_FUNCTION

For the canonical approach, refer to the Siemens FAQ ID 22783999: Accessing I/O address area indirectly with SFC20, which shows the exact byte layout and SCL/FB-style ANY templates.

7. S7-300/400 (SFC20) vs. S7-1200/1500 (Native BLKMOV)

Table 5. Behavioral differences
Aspect SFC20 (S7-300/400) Native BLKMOV (S7-1200/1500)
ANY length 10 bytes 10 bytes (legacy) / 8 bytes (Variant)
RET_VAL semantics 0 = OK, hex codes for errors ENO = FALSE on error, status via output parameter
Overlapping areas Not allowed (error 80B1) Allowed for S7-1500, error on S7-1200
Max length 32 384 bytes 16 384 bytes (per call)
Optimization Symbolic not enforced Optimized blocks preferred (Slice access)
Type check None (raw bytes) Type-safe when using Variant

On S7-1500 with optimized blocks, prefer the Variant data type for the source/dest pins and use MOVE_BLK_VARIANT instead of the legacy BLKMOV. The legacy BLKMOV is retained for migration scenarios, as documented in the TIA Portal V20 BLKMOV (S7-1500) reference.

8. Multi-Instance Reuse of the FB

One of the main reasons for parameterizing the ANY pointers is to reuse the same FB in many locations. Declare one FB with ANY inputs and instantiate it multiple times as multi-instance or instance-DB.

// OB1 - three independent moves using the same FB
"IDB_Move_1"(SRCBLK := "DB_Source".Payload,    DSTBLK := "DB_Dest".Target,     Execute := TRUE);
"IDB_Move_2"(SRCBLK := "DB_Source".Header,     DSTBLK := "DB_Log".Header,       Execute := TRUE);
"IDB_Move_3"(SRCBLK := "DB_Recipe".Setpoint,  DSTBLK := "DB_Drive".Cmd,        Execute := TRUE);

Each instance DB contains its own Done, Error, and Status tags, while the FB body is shared. This is exactly the re-usability pattern requested in the original question and is the standard approach in TIA Portal project templates.

9. Error Codes and Status Word

Table 6. BLKMOV / SFC20 error codes (RET_VAL / Status)
RET_VAL (hex) Meaning Remediation
0000 No error —
80A1 Source/dest alignment error (must be byte boundary) Round offsets to byte, use BYTE arrays only
80B2 Area length error (count 0 or too large) Verify count ≤ remaining DB size and ≤ 16 384 / 32 384
80B1 Source/dest overlap on S7-300/400 Use distinct areas or a temporary buffer; OK on S7-1500
80B4 Pointer references slot 0 (DI/DB misuse) Re-check DB number and area code (0x81 vs 0x82)
80B5 Read-only destination on S7-300 Switch to writable area; e.g. DB or M, not I
8xxx General OB priority or memory error Reduce call frequency, split into multiple BLKMOVs
Common pitfall: An error of W#16#80A1 on SFC20 almost always means the ANY is not byte-aligned (i.e. it specifies a bit offset inside a byte). BLKMOV only moves whole bytes; rebuild the ANY with DBX addresses, not DBX with bit suffix.

10. Verification and Commissioning Steps

  1. Static analysis: in TIA Portal, open the FB, place the cursor on the SRCBLK / DSTBLK input and read the Effective address in the Inspector. Confirm the area code, DB number, and offset match the intended source/destination.
  2. Watch table: create a watch table with the source array, the destination array, and the FB instance tags Done, Error, Status. Force the source pattern (e.g. 1..120) and run the FB.
  3. Compare: read both source and destination arrays in online mode and verify they are bit-identical.
  4. Edge cases: test with Execute = FALSE (no move) and with the maximum legal length (e.g. 16 384 bytes on S7-1500).
  5. Trace: use the PLC trace in TIA Portal to capture the Execute, Done, and Status bits over several OB cycles to confirm the move completes in one scan.
  6. Boundary test: temporarily reduce the FB's DSTBLK length to 1 byte less than the source to verify the error path (expect 80B2).

11. Troubleshooting Matrix

Table 7. Symptom → root cause mapping
Observed symptom Likely root cause Fix
EN/ENO goes FALSE immediately on call Source ANY has type code 0x10 (void) - no data type Reconstruct ANY with non-zero type code (Table 3)
Destination unchanged, no error flag Execute input pulsed too briefly (< 1 OB cycle) Use a static or set/reset pattern; verify scan
Compiler error "Invalid ANY parameter" VAR_IN_OUT used with elementary BOOL/INT instead of structured tag Drag the structured array directly onto the pin
Online: status = 80B1, move aborts Source and destination overlap on S7-300/400 Use distinct areas or switch to S7-1500 with overlap support
SF LED on, diagnostics buffer "Area length error during read/write" ANY count exceeds actual DB size Reduce count or enlarge destination area
Move works in simulation but fails on real CPU Optimized block access; tag is symbolic, ANY still uses absolute address Recompile hardware, regenerate ANYs from symbolic tags
Move corrupts adjacent tags Wrong offset, e.g. P#DB10.DBX1200.0 inside a 100-byte DB Validate against DB length in watch table

12. Best Practices

  • Prefer symbolic ANYs: drag a structured tag onto the FB input rather than typing P#.... TIA Portal will build a correct 10-byte ANY for you.
  • Use VAR_IN_OUT for destinations: avoids an extra copy and ensures the caller sees the result without re-reading the instance DB.
  • Validate before move: in safety-related FBs, call WRD_LIM or range-check the offset/length before issuing BLKMOV.
  • Avoid overlapping moves on S7-300/400; for S7-1500 the overlap is supported but the result is implementation-defined - keep copies logically distinct.
  • Mark FB optimized: in the FB properties, set Optimized block access to TRUE for S7-1200/1500. The legacy 10-byte ANY is still accepted.
  • Document the FB interface: in the FB header comment, state the maximum supported source/dest length, alignment requirement, and endianness (always little-endian on S7).
  • Migrate to MOVE_BLK_VARIANT when starting a new S7-1500 project; it provides type checking and eliminates the manual ANY construction step.

13. Frequently Asked Questions

How do I pass an ANY pointer to BLKMOV inside a Siemens function block?

Declare the source as VAR_INPUT SRCBLK : ANY; and the destination as VAR_IN_OUT DSTBLK : ANY;, then call BLKMOV(SRCBLK := SRCBLK, DSTBLK := DSTBLK) in SCL. Wire the actual structured tag to each pin at the call site - TIA Portal will build the 10-byte (S7-300/400) or 8-byte (S7-1500 optimized) ANY descriptor automatically. See Siemens ID 109011420.

What is the difference between SFC20 and the native BLKMOV instruction?

SFC20 is the classic block-move system function for S7-300/400 with a fixed 10-byte ANY and a max length of 32 384 bytes. The native BLKMOV/MOVE_BLK on S7-1200/1500 is integrated into the CPU firmware, supports optimized block access, and integrates with the Variant data type. Status reporting differs: SFC20 uses a RET_VAL word, native BLKMOV uses ENO and an explicit status output.

Why does my BLKMOV return error code 80A1?

Error 80A1 is an alignment error - the source or destination ANY is not byte-aligned, or the type code is invalid. BLKMOV only operates on whole bytes; rebuild the pointer with a byte offset (e.g. P#DB10.DBX8.0 BYTE 100) and use a valid type ID from Table 3. Reference: Siemens ID 22783999.

Can the source and destination memory areas overlap?

On S7-300/400 with SFC20, overlapping areas produce error 80B1. On S7-1500 the firmware handles overlapping blocks, but the result is still implementation-defined, so the recommended practice is to keep source and destination logically separate (e.g. move into a temporary DB and then swap pointers).

How can I reuse the same BLKMOV FB for many different source/destination pairs?

Create one FB with VAR_INPUT SRCBLK : ANY and VAR_IN_OUT DSTBLK : ANY, then create one instance DB per call site (or use multi-instance declaration in a parent FB). Each instance keeps its own Done/Error/Status tags and the same body code moves whatever the caller has wired to the ANY pins.

What is the maximum length BLKMOV can copy in one call?

SFC20 (S7-300/400) supports up to 32 384 bytes. The native BLKMOV on S7-1200/1500 typically supports 16 384 bytes per call, but always check the firmware reference. For larger copies, loop the call in an OB or split into multiple BLKMOVs in a sequence.

Back to blog