Resolving BLKMOV Compilation Warning with UDT Parameters in TIA Portal
This technical reference documents the root cause and resolution of the compiler warning emitted by the TIA Portal compiler when the BLKMOV (SFC20 / "Move block") instruction uses a parameter declared as a User Defined Type (UDT) as the destination area. The behavior is most often reported after migrating from STEP 7 V5.x to TIA Portal V13+ on S7-300 CPUs, but the underlying mechanism applies across the S7-300/S7-400 and S7-1200/S7-1500 families. The article consolidates Siemens documentation references, a concrete reproducer, four field-proven workarounds, runtime diagnostics for W#16#837F, and a migration checklist that resolves the warning without sacrificing the original block architecture.
SFC20 (BLKMOV) on a classic STEP 7 or TIA Portal firmware load. The S7-1500 path uses the native "Move block" instruction. Where the symptom is identical across families, the resolution has nuances detailed in Resolution Strategies.1. Overview of the BLKMOV Compilation Warning
The BLKMOV instruction copies the contents of a source memory area to a destination memory area in a single call. Both source (SRCBLK) and destination (DSTBLK) are declared as ANY pointer parameters so the block can operate on different memory types, sizes, and addresses at runtime. Siemens describes the instruction formally in the entry BLKMOV: Move block - STEP 7 Professional V13.1 (ID: 109011420).
In TIA Portal V13 and later, the compiler emits an informational warning (level 1 in the TIA compiler pipeline) when a parameter that receives the result of BLKMOV is typed as a UDT rather than as a fully qualified ANY pointer or as an in-instance symbolic address with known storage location. The warning does not prevent download or runtime, but it flags a potential mismatch between the length encoded in the ANY pointer and the absolute memory footprint of the UDT. The reproducer follows.
FUNCTION_BLOCK FB100
VAR
uParam : ANY; // source pointer, length auto
Param : UDT_PARAM_STRUCT; // destination typed as UDT
bOK : BOOL;
END_VAR
BEGIN
// Source: P#DB20.DBX0.0 BYTE 80
// Destination: a UDT instantiated in DB50
bOK := BLKMOV(uParam, Param); // compiler emits 'Inconsistent ANY/UDT length' warning
END_FUNCTION_BLOCK
Switching the same call into a Function (FC) does not clear the warning. Inverting the situation so the compilation happens inside a separate Function Block that owns the temporary area, however, often silences the warning because the compiler can resolve the temporary to an absolute offset inside the FB's instance DB or local stack frame.
2. Technical Background: BLKMOV and ANY Pointer Mechanics
The ANY pointer format used by Siemens is ten bytes long and encodes the data type, length, and byte address of the referenced area:
| Byte | Meaning | Typical value |
|---|---|---|
| 0..3 | ID + data type |
10 00 00 00, B#16#02 = BYTE, B#16#04 = WORD, B#16#06 = DWORD, B#16#15 = BOOL, etc. |
| 4..5 | Length (repetition factor) | Number of elements, max 65535 |
| 6..9 | DB number + byte offset | DB #, byte offset (negative offsets for inputs/outputs) |
The destination ANY is re-encoded with the byte length of the destination parameter each call. When the destination parameter is a UDT, the length is the size of the UDT (header included). The TIA Portal compiler can only verify the ANY at compile time when both pointer operands can be statically resolved. UDTs that are not bound to a DB, FB-static, or FC-temp area lack a backing storage location during compile, so the warning is raised.
The runtime counterpart of this compile-time check is the return value RET_VAL. Per the Siemens KB entry 109011420, error code W#16#837F is the canonical "source/destination cannot be processed" error for BLKMOV. RET_VAL is W#16#0000 on success and an error word on failure. The CPU family influences which specific error codes can be issued; the table in Section 8 consolidates them.
3. Root Cause: UDT Templates vs. Absolute Memory Addresses
UDT (User Defined Type) is a type template, not an actual memory location. It is downloaded to the CPU only inside a Data Block, in the static area of an FB, or as the type of an IN_OUT parameter of an FB/FC. The UDT itself never holds runtime data. TIA Portal's compiler needs to know the actual address at which the destination bytes live so it can populate the ANY destination pointer at compile time. When the destination is a UDT but the compiler cannot resolve an absolute offset, it falls back to a "best-effort" ANY and emits the warning.
The mismatch has three common variations:
-
FC with UDT
IN_OUT: FCs do not own background memory. The UDT type is acceptable, but the compiler cannot fully verify the destinationANYbecause the FC's stack frame is volatile. The warning is raised. -
FB with UDT
IN_OUTor static: The FB owns an instance DB. The compiler can resolve offsets to a specific address in the instance DB or to a temp local offset, and the warning is suppressed. -
FC/FB with UDT inside a passed DB: The destination is a
UDTfield in a referenced DB. The compiler resolves the offset, but only if the DB is symbolically known. Passing anANYtyped input shifts the validation back to runtime.
ANY validation to runtime. Migration to TIA exposes the structural ambiguity that V5.x hid.4. Affected Platforms and CPU Behavior
| Platform | CPU sample | FW range | Warning visible in TIA? | Runtime RET_VAL codes used |
|---|---|---|---|---|
| S7-300 | CPU 315-2 PN/DP (6ES7315-2EH14) | V3.3 | Yes (when UDT destination is ambiguous) |
0000, 8091, 8092, 837F
|
| S7-400 | CPU 416-3 PN/DP (6ES7416-3ES06) | V6.x | Yes |
0000, 8091, 8092, 837F
|
| S7-1200 | CPU 1214C DC/DC/DC (6ES7214-1AG40) | V4.2-V4.7 | Yes | Native "Move block" differs; see SCL doc. |
| S7-1500 | CPU 1515-2 PN (6ES7515-2AM02) | V2.5-V3.1 | Yes (for legacy SFC20 calls) |
Native BLKMOV equivalent; SFC20 wrapper behaves as S7-300/400. |
For S7-1500, Siemens recommends the native Move block instruction described in BLKMOV: Move block (S7-1500) - TIA Portal Help. The S7-1500 instruction honors the same SRCBLK/DSTBLK/RET_VAL interface, but its compiler checks are tighter; passing a UDT reference that lacks an absolute address raises the warning too.
5. Compiler Warning Reference
The TIA Portal compiler classifies this message as a "Length information cannot be derived" warning. It is similar in spirit to C4651 (Microsoft Learn) in that the compiler proceeds but signals a structural inconsistency that may surface as a runtime fault. The TIA warning text reads approximately:
[Warning] Block <name>: The length of an ANY pointer for parameter <Param> could not be statically determined.
Verify that the destination area can fully contain the source bytes at runtime.
Three options are presented in the TIA "Information" pane after a build:
-
Keep as warning. Acceptable if you have manually verified that the UDT size matches the source
ANYlength. - Convert to error. Available via Project > Settings > Compiler > Warnings as errors. Forces a clean compile for CI/Gate processes.
- Refactor the call (recommended when migrating a large program).
6. Resolution Strategies
Four field-proven patterns resolve the warning. Pick the smallest one that fits your code topology.
6.1 Move the UDT into an FB's Static or Temp Area
This is the canonical fix. Promoting the UDT from a free variable to a static variable of an FB (or to the temporary area of an FB/FC) gives the compiler a deterministic address.
FUNCTION_BLOCK FB200
VAR
stData : UDT_PARAM_STRUCT; // static instance > absolute address known
END_VAR
VAR_TEMP
tBuf : ARRAY[0..79] OF BYTE; // temp > DBB offset known per FB call
END_VAR
BEGIN
// No warning; static and temp are part of instance/stack frame
BLKMOV(uParam, stData);
END_FUNCTION_BLOCK
6.2 Declare the Destination as an Explicit ANY Pointer
If you cannot change the FB static layout, force the destination to be ANY:
VAR_IN_OUT
Param : ANY; // explicit pointer > compiler assumes caller matches length
END_VAR
Length validation is then performed by the caller (typically a DB instance whose first bytes are the UDT). The compiler no longer emits the warning because it has a fully resolvable ANY at compile time.
6.3 Use a Wrapper DB that Holds the UDT as a Field
DATA_BLOCK dbParam
VAR
stParam : UDT_PARAM_STRUCT;
END_VAR
BEGIN
// source > dbParam.stParam size matches source length
BLKMOV(uParam, dbParam.stParam); // no warning; absolute offset resolvable
END_DATA_BLOCK
This is the pattern that most cleanly preserves the FC interface while keeping data persistence.
6.4 Replace BLKMOV with Serialized Field Copies (Last Resort)
For UDTs whose size is dynamic (e.g., ARRAY[*] or STRING with ANY-like boundaries), consider per-field assigns or a loop with MOVE_BLK_VARIANT on S7-1500:
MOVE_BLK_VARIANT(SRC := uSrcAny, DST := stDst, COUNT := uCount, RET_VAL := iRet);
7. Implementation Examples in SCL, LAD, and FBD
7.1 SCL (Structured Control Language) Pattern
// SCL in TIA Portal V18
FUNCTION "fcCopyToUdt" : Void
{ S7_Optimized_Access := 'TRUE' }
VAR_INPUT
iSrcAny : ANY;
END_VAR
VAR_IN_OUT
ioDst : ANY; // length matches UDT, address must reference UDT
END_VAR
VAR_TEMP
tDiag : WORD;
END_VAR
BEGIN
BLKMOV(srcblk := iSrcAny, dstblk := ioDst, ret_val := tDiag);
IF tDiag <> W#16#0 THEN
// raise diagnostic, do not trip CPU
END_IF;
END_FUNCTION
7.2 LAD/FBD Wiring with SFC20
Place SFC20 on a network and assign:
| Pin | Source example | Destination (FB static) |
|---|---|---|
SRCBLK |
P#DB20.DBX0.0 BYTE 80 |
n/a |
DSTBLK |
n/a |
P#DB100.DBX0.0 BYTE 80 (must equal UDT size) |
RET_VAL |
n/a |
MW200 (WORD) |
7.3 S7-1500 Native Move Block
Drag the Move block instruction onto the network, configure SRCBLK and DSTBLK as Variant tags, and the instruction will accept symbolic UDT references without warning as long as the destination is a typed variable in a known DB, FB static, or tag.
8. Error Code W#16#837F and Runtime Diagnostics
When the destination ANY is later truncated at runtime (for example because the UDT was renamed and the offsets changed in TIA Portal), BLKMOV writes W#16#837F into RET_VAL. Other relevant codes:
| Code | Meaning | Diagnostic action |
|---|---|---|
W#16#0000 |
No error | None. |
W#16#8091 |
Source area exceeds the assigned area | Check SRCBLK length vs DB size. |
W#16#8092 |
Destination area exceeds the assigned area | Check DSTBLK length vs UDT/DB size. |
W#16#837F |
Source/destination pointer invalid or inconsistent | Re-pass both ANY pointers; verify DB exists. |
W#16#80A1 |
DB not loaded (cross-DB access) | Verify DBNUM in ANY against current runtime DB list. |
For S7-400 V4 CPUs, W#16#837F may be raised if a forced or unlinked DB is referenced. The exact message catalog lives in the Siemens support entry 109011420.
9. Migration Considerations from STEP 7 V5.x to TIA Portal
-
Convert all FCs containing
BLKMOVwith UDT destinations to FB wrappers. The simplest migration path is to wrap the FC call inside a new FB that owns the UDT as static data. -
Re-verify
ANYlengths. TIA Portal enforces byte alignment and may flagP#DB20.DBX0.0 BYTE Ncases whereNdiffers from the UDT size. - Update HMI references. If the UDT was renamed or its fields reordered, refresh HMI tag DBs after the migration.
- Audit cross-references. Use Project tree > Cross-references to find every call site of the migrated block and confirm no legacy FCs still pass raw UDTs.
- Run an online/offline compare on a test CPU before production rollout.
10. Best Practices and Field-Proven Patterns
-
Prefer FB static or DB-typed destinations. They give the compiler an address to encode in
ANYat call time. -
Document the
ANYlength rule. Add a comment block on every wrapper FC stating the expected source bytes per UDT. -
Use symbolic names. Pass
P#"DB_Param"."stParam"instead ofP#DB100.DBX0.0 BYTE 80so renames do not break the link. - Validate RET_VAL on every call until the program is signed off; remove the check only after a project-wide review.
-
Centralize
BLKMOVcalls in one FB per logical subsystem to make future refactors easier. -
For S7-1500, use the native Move block /
MOVE_BLK_VARIANTinstructions rather than legacySFC20unless you have a documented S7-300 compatibility reason.
11. Verification and Commissioning Checklist
- Compile the project and confirm there are no entries with text "length of an ANY pointer".
- Open the block online; observe
RET_VALafter one scan cycle. It must beW#16#0000. - Inspect the destination DB with Monitor/Modify; the first byte of the UDT field should reflect the first source byte copied.
- Introduce a deliberately oversized source
ANYin a test instance; verify that the CPU returnsW#16#8091orW#16#837Frather than crashing OB121. - Document the
ANY/UDT length contract in the program comments and the Functional Specification.
BLKMOV to copy data between fail-safe and standard DBs without an explicit fault-tolerant wrapper. Verify against the latest F-CPU Safety Manual before deploying.FAQ
Why does TIA Portal raise a warning when BLKMOV uses a UDT destination?
The compiler cannot determine the absolute byte offset of a UDT that is not bound to a Data Block, FB static, or temporary area, so it cannot statically validate the destination ANY pointer length. Wrap the UDT in an FB static or a DB field, or declare the parameter as ANY.
Does the warning mean the program will malfunction at runtime?
No. The block executes, but RET_VAL may surface a runtime error such as W#16#837F if the source and destination lengths are not equal. Always evaluate RET_VAL during commissioning and consider promoting warnings to errors for production compiles.
What is the difference between BLKMOV on S7-300/400 and S7-1500?
S7-300/400 use SFC20 with explicit ANY pointers. S7-1500 uses a native Move block that accepts Variant tags. Both share the error codes W#16#837F, 8091, and 8092; see Siemens TIA Portal V20 Help for the S7-1500 behavior.
Can I suppress the warning without refactoring the block?
Yes. In Project > Settings > Compiler, you can demote specific warnings to informational or turn off the relevant class. The warning stays out of the build log but is documented in the compiler log; this is acceptable for legacy blocks you do not intend to maintain.
Why does the warning disappear when I compile in an FB instead of an FC?
FBs own an instance DB and a static layout, so the compiler can resolve the destination ANY to a concrete byte offset. FCs lack persistent memory, which leaves the UDT address unresolvable at compile time. Promoting the destination to an FB static is the recommended fix.