Problem Overview
When programming an S7-315-2 PN/DP (CPU 315 firmware family, e.g., 6ES7315-2EH14-0AB0) under TIA Portal V15, an FC that performs a copy of a data block region with the BLKMOV instruction cannot directly accept the source/destination ANY pointers declared on the block interface. The compiler either rejects the wiring, raises a type-inconsistency error, or silently accepts code that the SFC rejects at runtime with OB121 errors. Copying the incoming ANY pointers into TEMP variables before the BLKMOV call resolves the fault, but leaves the programmer uncertain about why the parameter model fails in the first place.
This reference explains the underlying semantics of ANY pointers, the difference between S7-300/400 and S7-1500 handling, the role of optimized block access, the differences between IN, INOUT, and TEMP variables, and the working patterns that have to be used on legacy S7-300 CPUs.
Affected Products and Versions
| Component | Affected Identification | Notes |
|---|---|---|
| CPU | S7-315-2 PN/DP, order number 6ES7315-2EH14-0AB0 (and equivalent 6ES7315-2AH14, 6ES7315-2EH13) | Classic S7-300 firmware; SFC20 (BLKMOV) is the supported primitive. |
| Engineering | TIA Portal V15, V15.1, V16, V17 with S7-300 CPU package installed | Compiler accepts the legacy SFC20; S7-1500-only instructions are filtered. |
| Block types | FC, FB with optimized block access ENABLED | Optimized access prevents SFC20 from reading interface parameters. |
| Blocks NOT affected | S7-1500 CPUs (CPU 1511-1 PN through CPU 1518-4 PN/DP) and ET 200SP CPUs | Use the symbolic BLKMOV instruction with optimized blocks and direct VARIANT/ANY parameters. |
Root Cause: Why ANY Pointers Fail on the FC Interface
There are three independent but interacting reasons why an FC interface parameter of type ANY cannot be wired directly to the BLKMOV/SFC20 on an S7-300:
1. SFC20 Is a System Function, Not a Symbolic Instruction
On S7-300/400, BLKMOV is only available as SFC 20 "BLKMOV". SFC20 receives source and destination by IN/OUT of type ANY but evaluates them through the CPU's pointer register AR1/AR2 and the DB register at runtime. When the compiler passes an interface parameter, it generates a copy in TEMP that the FC code manipulates. Any pointer the optimizer then writes back may not match the AR-register convention SFC20 expects.
2. IN vs INOUT Parameter Passing (Call-by-Value vs Call-by-Reference)
On classic S7-300/400 blocks, an IN parameter is passed by value: the caller's data is copied into the FC's TEMP image, and any modification of the pointer is local. An INOUT parameter is passed by reference: the interface holds an ANY descriptor (10 bytes: ID/DBW/byte offset/area) that points back to the caller's actual storage. SFC20 requires a stable pointer descriptor for the entire call; that descriptor is only valid for INOUT parameters, not for IN parameters whose descriptor was rewritten during the FC prologue.
3. Optimized Block Access
If the FC has Optimized block access enabled (the default in TIA Portal for new FCs since V13), the compiler does not publish the interface parameters at fixed offsets in the instance/TEMP image. SFC20 cannot resolve them through absolute pointer arithmetic and the call is rejected at compile time with one of the following messages:
- "The parameter type ANY is not allowed at INPUT for SFC 20."
- "Inconsistent parameter: the ANY pointer must point to a non-optimized area."
- "SFC 20 cannot be used in blocks with optimized access."
Why S7-1500 Behaves Differently
On S7-1500, the legacy BLKMOV instruction (now BLKMOV: Move block (S7-1500)) is a fully symbolic, compiler-managed instruction that supports VARIANT and ANY parameters at the block interface, optimized access, and direct symbolic DB operands. The compiler resolves the source/destination at compile time using the symbolic information of the tag, not the AR-register convention. That is why the same FC code compiles and runs unchanged on an S7-1516-3 PN/DP, but fails on an S7-315-2 PN/DP.
For the legacy S7-1500 environment see also BLKMOV: Move block - STEP 7 Professional V13.1 (ID 109011420).
Differences Between SFC 20 and the S7-1500 BLKMOV Instruction
| Attribute | SFC 20 (S7-300/400, also 1200/1500 with restriction) | BLKMOV instruction (S7-1200/1500) |
|---|---|---|
| Parameter model | IN: SRCBLK (ANY); IN/OUT: DSTBLK (ANY) | IN: SRCBLK (Variant); IN/OUT: DSTBLK (Variant) |
| Block access | Requires non-optimized (standard) blocks | Supports optimized blocks |
| Symbolic operand | Not permitted on S7-300; permitted as ABS only on S7-1200/1500 in standard blocks | Fully symbolic (e.g., "DB_Machine".recipe.header) |
| Length handling | Length field of ANY must be even; max 8192 bytes for SFC20 (CPU-dependent) | Length field up to 64 KB on 151x; up to 4 MB on 1518 (depends on firmware) |
| Overlap behaviour | Defined; copies byte-by-byte from low to high address | Same behaviour documented for the legacy instruction |
| DB number 0 / process image | Allowed (PI/PQ) | Restricted; some targets reject PI/PQ |
Workarounds That Work on S7-300
Workaround A — Copy ANY to TEMP before SFC 20
This is the canonical fix reported by field engineers. The source and destination ANY parameters are moved into TEMP ANY variables; SFC 20 is then called with the TEMP copies. Because TEMP is the only storage the compiler guarantees to keep stable for the duration of the FC call, the pointer descriptor that SFC20 receives is valid for its entire execution.
Code Pattern (SCL / Structured Text)
// Block interface
// IN : srcPtr : ANY
// IN : dstPtr : ANY
// IN : len : INT // optional, overrides ANY length
// TEMP : srcTemp : ANY
// TEMP : dstTemp : ANY
#srcTemp := #srcPtr;
#dstTemp := #dstPtr;
IF #len > 0 THEN
POKE_BLK(area := #srcTemp, byteOffset := 0,
value := INT_TO_WORD(#len));
END_IF;
IF #srcTemp <> #dstTemp THEN
BLKMOV(srcblk := #srcTemp,
dstblk := #dstTemp);
END_IF;
Code Pattern (LAD / FBD wiring)
- Declare
srcTempanddstTempof typeANYin the FC TEMP section. - Insert a
MOVE_BLK(or twoMOVEblocks) to copy the ANY descriptor (10 bytes) from the input interface into the TEMP. - Wire the TEMP
ANYs toSFC 20SRCBLK and DSTBLK.
Workaround B — Disable Optimized Block Access on the FC
If the FC is brand-new and not yet integrated into a program that relies on optimized access, set Optimized block access = No on the FC properties. This forces the compiler to publish the interface at fixed offsets. After this change, IN and INOUT parameters can be passed directly to SFC20 in many cases. The drawback is that the FC is no longer eligible for symbolic debugging and you cannot use multi-instance DBs of optimized FBs.
Workaround C — Move the Copy Logic into the Caller
Instead of encapsulating BLKMOV inside an FC, call SFC 20 directly from the OB or from a non-optimized FB that owns the source/destination pointers as INOUTs of its own interface. This is the most robust pattern because the caller's pointer descriptor is guaranteed to remain stable.
Workaround D — Use the Symbol-Resolved Variant (Not Recommended)
For projects migrating to a 1500V/ET 200SP CPU, replace the FC with a VARIANT-parameterized routine and call the S7-1500 BLKMOV instruction. Do not attempt this on an S7-300 CPU; the CPU cannot execute the S7-1500 instruction.
Step-by-Step Resolution Procedure
- Open the failing FC in TIA Portal V15/V16.
- Select the FC in the project tree and open Properties → Attributes.
- If "Optimized block access" is enabled, decide between two paths:
-
Path A (preferred): Keep optimization ON and apply Workaround A (TEMP
ANYcopies). - Path B: Uncheck "Optimized block access" and recompile; verify the FC.
-
Path A (preferred): Keep optimization ON and apply Workaround A (TEMP
- For Path A, declare two TEMP variables
srcTemp : ANYanddstTemp : ANYin the FC TEMP section. - Insert MOVE blocks (SCL: direct assignment) to copy the IN/INOUT
ANYparameters into the TEMPs. - Wire the TEMP
ANYs to theSFC 20SRCBLK and DSTBLK inputs. - Compile the block (Ctrl+B). Confirm no warnings referencing the ANY pointer.
- Download to the S7-315-2 PN/DP. Monitor the online view of the FC: confirm
srcTempanddstTempshow the same descriptor as the inputANYs.
Verification Checklist
| Check | Expected Result | How to Verify |
|---|---|---|
| Compile clean | No warnings related to ANY or SFC 20 | TIA Portal "Compile" output, "Information" pane |
| No OB 121 at runtime | CPU stays in RUN; no diagnostic buffer entry for "Area length error" | Online → Diagnostics → Diagnostic buffer; CPU display → SF LED off |
| TEMP descriptor matches input | 10-byte ANY for srcTemp/dstTemp identical to srcPtr/dstPtr | Monitor & force tables on srcPtr, srcTemp, dstPtr, dstTemp |
| Memory protection | Length field <= destination area size | Manual review of length passed by caller; clamp in FC if necessary |
| Same-DB overlap | If src and dst are both inside the same DB, the FC must split or copy in correct order | Compare absolute offsets; SFC20 copies from low to high |
| AR-register clean-up | No leftover AR1/AR2 after SFC20 returns | SFC20 saves and restores AR1/AR2 internally; verify with STL view |
Edge Cases and Field-Proven Caveats
- Same DB for source and destination. If both ANY pointers reference the same DB and the ranges overlap, SFC20 will copy byte-by-byte from the low offset to the high offset, producing a corrupted result. Either compute a copy order or use a scratch DB.
- Length > 8192 bytes. SFC20 on S7-300 CPUs supports a maximum of 8192 bytes per call. For larger payloads, segment the copy inside a loop.
- Odd length. SFC20 rounds odd lengths up to the next even byte. If the caller passes an odd value, the trailing byte is copied from the source and may overflow the destination.
- Access to optimized DB. Even when the FC is non-optimized, if the source or destination DB has Optimized block access enabled, the absolute address resolved from the ANY pointer may not match the symbolic offset. Always pair a non-optimized FC with a non-optimized DB.
- Length = 0. SFC20 does nothing when length is 0, but the input pointer must still be valid (non-NULL ANY descriptor).
- PI / PQ areas. Passing process-image input/output area as source or destination is supported but the data is read once; subsequent changes are not reflected in the move.
- Calling from an FB instance. If the FC is called from inside an FB with multi-instance DBs, the caller's ANY descriptor may itself be a TEMP. In that case, Workaround A is mandatory.
Troubleshooting Matrix
| Symptom | Likely Cause | Remediation |
|---|---|---|
| Compiler error: "ANY not allowed at INPUT" | IN parameter passed directly to SFC20 | Change IN to INOUT, or apply Workaround A |
| Compiler warning: "Inconsistent parameter" | Optimized block access conflicts with SFC20 | Disable optimization OR use TEMP copy |
| Runtime: OB121 "Area length error" | Length field of ANY larger than destination area | Clamp length in the FC, or allocate destination area accordingly |
| Runtime: garbage in destination | Same-DB overlap with low-to-high copy | Reorder source and destination to remove overlap, or use a scratch DB |
| Online: srcTemp and srcPtr differ | Caller is re-writing the input ANY each call | Snapshot the ANY into TEMP at the very start of the FC |
| CPU goes STOP after one scan | Pointer descriptor invalid (e.g., DB number 0 with offset 0) | Validate ANY descriptor before calling SFC20 |
| Code compiles on S7-1500 but not on S7-300 | Compiler difference (VARIANT vs ANY) | Use classic ANY on the FC interface; do not mix VARIANT and SFC20 |
Alternative Memory-Copy Approaches on S7-300
If the SFC20 path remains problematic in a particular application, three additional approaches are commonly used:
- Inline SFC 20 calls in OB1. Direct calls with absolute pointers avoid the FC interface issue entirely.
- UDT-based copy. Copy struct-by-struct using symbolic UDT assignment; slower but fully debuggable.
-
DPRD/DATW pairs. Use
DPRD_DATandDPWR_DATfor PROFINET/PROFIBUS transfers; not a general-purpose copy.
Migration Path to S7-1500
When the project is later migrated to an S7-1500 CPU (e.g., 6ES7511-1AK02-0AB0 or later), the entire FC code can be reused without Workaround A:
- Replace the call to SFC20 with the symbolic
BLKMOVinstruction from BLKMOV: Move block (S7-1500). - Switch the interface parameters from
ANYtoVARIANTfor symbolic resolution. - Keep the FC optimized.
- Update unit tests to cover the larger 64 KB / 4 MB length envelope.
Safety and Operational Notes
- SFC20 does not perform any bounds checking on the destination. A defective ANY from the caller can corrupt memory or trigger OB121. Always validate the length field before the call.
- If the FC is part of a safety program (F-CPU), the ANY pointer mechanism is not usable inside the F-runtime; use the F-library-equivalent copy blocks instead.
- When the FC is downloaded to the running CPU, the active call is interrupted; ensure no real-time-critical cycle is open during the download.
FAQ
Why does an ANY pointer passed as IN fail to compile when wired to SFC 20 on S7-300?
On classic S7-300/400, SFC 20 expects a stable pointer descriptor for the duration of the call. IN parameters are passed by value, so the compiler generates a TEMP copy whose descriptor may not match the SFC20 AR-register convention. Declare the parameter as INOUT or copy the ANY into a TEMP variable before the SFC20 call.
Does disabling "Optimized block access" on the FC fix the BLKMOV error?
Yes, in many cases. With optimization off, the compiler publishes the interface parameters at fixed offsets that SFC 20 can resolve. The trade-off is that the FC loses symbolic multi-instance capability and full symbolic debugging. If optimization is mandatory, apply the TEMP copy workaround instead.
Can I use the S7-1500 BLKMOV instruction on an S7-315-2 PN/DP?
No. The S7-1500 BLKMOV is a symbolic, optimized-aware instruction that is only loaded on S7-1200/1500 CPUs. An S7-300 CPU cannot execute it. Use SFC 20 instead.
What is the maximum length that SFC 20 can copy on S7-300?
SFC 20 supports up to 8192 bytes per call on S7-300 CPUs. For larger payloads, segment the copy in a loop and call SFC 20 repeatedly with smaller length fields.
How do I avoid data corruption when source and destination are in the same DB?
SFC 20 copies from low to high address. If source and destination ranges overlap inside the same DB, copy either in reverse order, split the copy into two non-overlapping halves, or use a scratch DB. Compare the absolute offsets of both ANY descriptors before the call.