1. Overview
The classic Siemens S7-300/400 approach to runtime-mutable pointers — declare an ANY, overlay it with a STRUCT via the AT construct, then rewrite the bytes of the STRUCT — does not translate cleanly to the S7-1200/S7-1500 generation. The ANY data type is not selectable in the S7-1200 declaration editor, and the Variant pointer that replaces it is not overlayable. Communication instructions such as GET and PUT, however, accept pointer-like address parameters that can be driven at runtime if you build the pointer from primitive bytes and pass it through a Remote-typed tag.
This reference consolidates the engineering practice for assembling a dynamic ANY-compatible pointer in TIA Portal, applying it as the ADDR input to the GET instruction, and verifying correct behavior on the wire. It covers the canonical 10-byte ANY layout, the S7 memory-area codes, the elementary data-type codes, a complete SCL function block, and the diagnostics that confirm pointer validity before the GET request is fired.
2. The S7-300/400 ANY-Pointer Pattern
On S7-300 and S7-400, an ANY pointer is a first-class data type. The classic recipe is:
- Declare an
ANY-typed tag in the input, output, in/out, or static section of an FB/FC. - Overlay the tag with a STRUCT that mirrors the 10-byte internal layout (e.g.,
idCode,dataType,amount,dbNumber,area,byteOffset). - At runtime, write the
area,dbNumber, andbyteOffsetmembers; the resulting ANY points to the new location. - Pass the ANY to any instruction that accepts ANY as an input (BLKMOV, fill, indirect addressing via POINTER, etc.).
This pattern relies on two facts: (1) the ANY type is exposed in the editor, and (2) the AT construct on ANY is permitted. Both are false on the S7-1200.
3. Why the Pattern Does Not Transfer Directly to S7-1200
Three restrictions defeat the S7-300/400 pattern:
-
ANY is not a selectable data type. The S7-1200 declaration editor in TIA Portal does not list ANY among the data types. Any attempt to type
ANYresults in an invalid-type error. - VARIANT is not overlayable. Variant is a system data type that does not occupy a fixed instance footprint; the compiler rejects the AT overlay on a Variant tag.
-
Communication instructions accept a "Remote" pointer, not ANY. The
ADDRinput of GET, PUT, and related SIMATIC S7 Communication instructions uses a pointer-like system type referred to in the editor as Remote. The internal byte layout of this type is compatible with ANY but it is exposed as a black box.
The fix is to declare a variable of that same internal layout (or to write to the bytes of a Remote-typed tag directly), then pass it as the ADDR parameter of GET.
4. Variant Pointer — Properties and Limitations
According to the official SIMATIC S7-1200 manual collection, the Variant pointer can point to complete structures and to individual structural components, and it does not occupy any space in instance memory. Variant is the recommended pointer type for any symbolic, fully-resolvable address reference. Variant Pointer Data Type — SIMATIC S7-1200 Manual Collection.
Limitations that matter for this technique:
- Cannot be overlaid. AT-construct overlays against Variant are not permitted by the S7-1200 compiler.
- Cannot store arbitrary runtime-formed bit/byte addresses in the classic ANY sense. Variant always carries symbolic information plus a runtime-resolved address, not a raw 10-byte ANY record.
- Not interchangeable with the Remote parameter of GET/PUT. While TIA Portal will accept a Variant at some ADDR parameters, the byte-level control required for fully dynamic addressing across multiple DBs/areas is only available through the Remote/ANY approach.
Therefore, when the address must be computed at runtime and the same FB must read from changing DBs, offsets, or areas, build the pointer manually and pass it through a Remote-typed tag.
5. The Remote + AT Overlay Solution
The workaround has three components:
-
Declare the pointer as a Remote tag. In the FB static section, declare
ADDR_PTR : Remote. The Remote type is the system type for the ADDR parameter of PUT/GET; TIA Portal accepts it as an in/out parameter when the instruction expects an address pointer. -
Overlay it with a STRUCT that mirrors ANY. Add an AT view that reinterprets the Remote bytes as a STRUCT of primitive types:
id(WORD),dataType(WORD),amount(INT),dbNumber(INT),area(BYTE), andbyteOffset(DWORD). -
Drive the members at runtime. Set
id := 16#10, choose the data type code, setamountto the number of items, set the memory area and DB number, and set the byte offset. The compiler sees a Remote; the runtime sees a valid ANY.
This is the only legal way in S7-1200 to mutate the address of a GET (or PUT) call from the program without touching the editor-declared instance each cycle.
6. ANY-Pointer Structure (10-Byte Layout)
The ANY record is a 10-byte structure documented by Siemens. The first two bytes are an identifier, followed by the data type, the count of items, the DB number, the area code, and a 32-bit byte offset. The layout below is the canonical Siemens definition and must be reconstructed exactly when building a dynamic ANY on the S7-1200.
| Byte | Field | SCL Type | Description |
|---|---|---|---|
| 0–1 | id | WORD | Identifier. Must be 16#0010 for a valid ANY. |
| 2–3 | dataType | WORD | Elementary data-type code. See §8. |
| 4–5 | amount | INT | Number of items of the data type. Range 1..n. Use 0 to indicate length-in-bytes in some legacy contexts; for GET/PUT, set amount ≥ 1. |
| 6–7 | dbNumber | INT | DB number (0..65535). Only meaningful when area = 0x84 (DB). For other areas set to 0. |
| 8 | area | BYTE | Memory-area code. See §7. |
| 9–12 | byteOffset | DWORD | Byte offset within the area. Bit-granularity not used by ANY in GET/PUT. |
7. Memory-Area Codes
The byte at offset 8 selects which memory area the ANY addresses. The high nibble encodes the area family; the low nibble encodes the access width or sub-type. The table below lists the codes used by GET/PUT in S7-1200.
| Area Code (Hex) | Area | dbNumber Meaning | Notes |
|---|---|---|---|
| 16#81 | Inputs (I) | ignored (set 0) | Process image of inputs |
| 16#82 | Outputs (Q) | ignored (set 0) | Process image of outputs |
| 16#83 | Bit memory (M) | ignored (set 0) | Flags / Merkers |
| 16#84 | Data block (DB) | DB number 1..65535 | Most common target for dynamic read |
| 16#85 | Local data (L / Temp) | ignored (set 0) | Temp area of calling OB/FB; rarely used in GET/PUT |
| 16#86 | Previous local data (V) | ignored (set 0) | Legacy S7-300 area |
8. Elementary Data-Type Codes
The data-type field at bytes 2–3 uses the canonical Siemens type codes. Only a subset is meaningful for GET/PUT because the instruction copies raw bytes; pick the code that matches the element size the receiver should interpret.
| Code (Hex) | Type | Size (bytes) | Notes |
|---|---|---|---|
| 16#0001 | BOOL | 1 | Bit-granularity must be encoded in the offset (byte 9 = bit position 0..7, low 3 bits of byte 10). Avoid BOOL for GET/PUT bulk transfer. |
| 16#0002 | BYTE | 1 | Byte string |
| 16#0003 | CHAR | 1 | Single ASCII character |
| 16#0004 | WORD | 2 | Bit string, unsigned |
| 16#0005 | INT | 2 | Signed 16-bit |
| 16#0006 | DWORD | 4 | Bit string, unsigned 32-bit |
| 16#0007 | DINT | 4 | Signed 32-bit |
| 16#0008 | REAL | 4 | IEEE 754 32-bit float |
| 16#0009 | DATE | 2 | Days since 1990-01-01 |
| 16#000A | TOD (Time_of_Day) | 4 | Milliseconds since midnight |
| 16#000B | TIME | 4 | IEC 61131-3 duration |
| 16#000C | S5TIME | 2 | Legacy S5 duration |
| 16#000E | DATE_AND_TIME | 8 | BCD-encoded DT |
The total byte count transferred is amount × element_size. For REAL with amount = 100, the GET copies 400 bytes.
9. Step-by-Step Implementation in TIA Portal
The procedure below assumes TIA Portal V16+ and an S7-1200 CPU (firmware V4.x). Adjust to match your installation.
-
Create the FB. Add a new Function Block, language SCL. Name it, e.g.,
FB_DynamicGet. -
Declare the pointer static. In the Static section add two tags:
// Static sAddrRemote : Remote; // Real pointer consumed by GET sAddrAny AT sAddrRemote : STRUCT // Overlay view, mutable at runtime id : WORD; // 16#0010 dataType : WORD; // 16#0008 = REAL amount : INT; // number of elements dbNumber : INT; // 0..65535 area : BYTE; // 0x84 = DB byteOffset : DWORD; // byte offset within area END_STRUCT; -
Declare inputs. Add inputs for the dynamic address:
iConnId : WORD,iReq : BOOL,iDbNumber : INT,iOffset : DWORD,iLen : INT,iTypeCode : WORD. -
Declare receive buffer. Add an InOut
ioBuffer : ARRAY[0..4095] OF BYTEsized to the maximum expected payload. - Initialize the ANY fields each cycle (or on change). Set the id, area, type, amount, DB number, and offset before raising REQ. The implementation is shown in §10.
-
Wire the GET instruction. Use the TIA "GET" instruction from the Communications → S7 Communication palette. Connect
REQ := iReq,ID := iConnId,ADDR_1 := sAddrRemote,RD_1 := ioBuffer,DONE,ERROR,STATUSto FB outputs. - Compile and download. Compile the program; the compiler must accept the AT overlay on a Remote tag. If it rejects, your TIA Portal version does not permit the overlay — see §13.
-
Establish the connection. Configure the partner connection in "Devices & Networks" with the connection ID used in
iConnId. Use ISO-on-TCP (RFC 1006) or S7 Communication as required by the peer.
10. SCL Implementation: BuildANY Function
The SCL below builds the ANY-compatible pointer from inputs and triggers the GET. The function writes the canonical fields directly into the overlay STRUCT and lets the compiler treat the result as a Remote tag.
FUNCTION_BLOCK FB_DynamicGet
{ S7_Optimized_Access := 'FALSE' } // required: AT overlay on non-optimized block
VAR
// Mutable ANY-style pointer overlaid on a Remote tag
sAddrRemote : Remote;
sAddrAny AT sAddrRemote : STRUCT
id : WORD;
dataType : WORD;
amount : INT;
dbNumber : INT;
area : BYTE;
byteOffset : DWORD;
END_STRUCT;
// Receive buffer — size to maximum expected payload
sRxBuf : ARRAY[0..4095] OF BYTE;
// Edge detection for one-shot REQ
sReqOld : BOOL;
sBusy : BOOL;
sDone : BOOL;
sError : BOOL;
sStatus : WORD;
END_VAR
VAR_INPUT
iReq : BOOL; // rising edge fires the GET
iConnId : WORD; // connection ID from Devices & Networks
iArea : BYTE; // 0x81..0x86
iDbNumber : INT; // 0..65535, valid only for area = 0x84
iOffset : DWORD; // byte offset within area
iTypeCode : WORD; // see §8
iLength : INT; // number of items to fetch
END_VAR
VAR_OUTPUT
oDone : BOOL;
oError : BOOL;
oStatus : WORD;
oRxBuf : ARRAY[0..4095] OF BYTE;
END_VAR
VAR_IN_OUT
// Optional external buffer reference for caller; here mapped to sRxBuf
END_VAR
BEGIN
// 1) Update pointer fields each cycle. Triggers without copy if unchanged.
sAddrAny.id := 16#0010;
sAddrAny.dataType := iTypeCode;
sAddrAny.amount := iLength;
sAddrAny.dbNumber := iDbNumber;
sAddrAny.area := iArea;
sAddrAny.byteOffset := iOffset;
// 2) Edge-triggered REQ
IF iReq AND NOT sReqOld THEN
sBusy := TRUE;
sDone := FALSE;
sError := FALSE;
END_IF;
sReqOld := iReq;
// 3) Issue the GET
GET(REQ := iReq,
ID := iConnId,
ADDR_1 := sAddrRemote,
RD_1 := sRxBuf,
DONE => sDone,
ERROR => sError,
STATUS => sStatus);
// 4) Export
oDone := sDone;
oError := sError;
oStatus := sStatus;
oRxBuf := sRxBuf;
END_FUNCTION_BLOCK
S7_Optimized_Access := 'FALSE' is mandatory for AT overlays against non-optimized tags. If the FB must be optimized, store the pointer in a non-optimized DB and overlay it from there.11. Integrating with the GET Instruction
Wire the call exactly as for any other GET, with one critical difference: the ADDR_1 parameter receives the Remote-typed tag, not the STRUCT overlay. The compiler uses the underlying memory image; the overlay is purely a programmer convenience.
- REQ: pulse high for one cycle to start the transfer. Subsequent transfers require a falling edge before the next rising edge.
- ID: connection identifier from the configured S7 connection (1..65535).
-
ADDR_1: the dynamic pointer
sAddrRemote. - RD_1: a byte array sized ≥ amount × element_size. For REAL length 100, allocate at least 400 bytes.
-
DONE / ERROR / STATUS: monitor
DONErising edge for success, checkSTATUSon error (see §12).
For multi-variable GETs, repeat the same pattern with ADDR_2 / RD_2, ADDR_3 / RD_3, ADDR_4 / RD_4 — each with its own Remote tag and its own overlay STRUCT.
12. Verification with Watch Tables and Traces
Verification falls into three checks: pointer validity, instruction status, and data fidelity.
-
Pointer validity. Open a watch table on the FB instance. Confirm:
sAddrAny.id = 16#0010-
sAddrAny.areamatches the intended memory area -
sAddrAny.dbNumbermatches the target DB (or 0 for non-DB areas) -
sAddrAny.byteOffsetis within the area's byte range -
sAddrAny.amount × element_sizedoes not overflow the receive buffer
-
Instruction status. Pulse REQ and observe STATUS. Common values:
STATUS (Hex) Meaning Action 0000 No error / idle None 0001 Communication in progress Wait for DONE 0080 / 000A Invalid pointer or area mismatch Inspect ANY bytes per §6 8085 / 8086 Connection not established or aborted Verify Devices & Networks configuration 80A1 / 80A2 Partner rejected (resource / area length) Confirm peer DB exists and is large enough -
Data fidelity. Place a known pattern (e.g.,
REALvalues 1.0, 2.0, 3.0) at the partner. DecodesRxBufat the same offsets and compare with a structured tag overlaid on the buffer.
13. Edge Cases, Restrictions, and Firmware Behavior
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Compiler rejects AT overlay on Remote | TIA Portal version prior to V14 SP1 or block marked optimized | Upgrade TIA Portal or move the Remote tag to a non-optimized DB |
| GET returns 16#0080 on first call | id field not 0x10, or amount set to 0 | Force id := 16#0010 and amount := n before raising REQ |
| GET returns 16#80A1 even with correct pointer | Partner DB does not exist or is shorter than offset + amount × size | Verify partner DB size; S7-1200 limits DBs to 64 KB |
| Read returns stale values | REQ held high longer than one cycle | Pulse REQ for exactly one cycle using edge detection |
| Works in DB area, fails in M area | area byte set to 0x83 with non-zero dbNumber | Set dbNumber to 0 for non-DB areas |
| BOOL access not working | Bit position must be encoded in low bits of byteOffset | Compute byteOffset = (byte << 3) OR bit; avoid BOOL in bulk GET |
For S7-1500 the same logical pattern works, but the AT overlay against Remote is permitted on optimized blocks in TIA Portal V17+. Consider migrating the same pattern forward when you move to S7-1500; the Variant pointer becomes the preferred alternative because the compiler can resolve symbols statically.
14. Comparison of Indirect-Addressing Alternatives
| Technique | Where Permitted | Mutable at Runtime? | Compiler Checks | Use Case |
|---|---|---|---|---|
| VARIANT | S7-1200 / S7-1500 | Limited (symbolic only) | Strong (symbolic) | Symbolic, compile-time-known addresses |
| ANY + AT (classic) | S7-300 / S7-400 | Fully mutable | None | Legacy FBs with dynamic DB access |
| Remote + AT (this technique) | S7-1200 / S7-1500 (TIA ≥ V14 SP1) | Fully mutable | None | GET/PUT/communication with changing DB numbers |
| PEEK / POKE | S7-1500 / S7-1200 (limited) | Fully mutable | None | Any-pointer-style access without instruction parameter |
| Slice access | S7-1500 / S7-1200 (V4.x) | Static | Strong (symbolic) | Compile-time bit/byte slicing |
| Indirect field access with index | S7-1200 / S7-1500 | Index mutable | Strong (within array) | Iterating over arrays in a single DB |
For dynamic cross-DB or cross-area reads via GET, the Remote + AT overlay is the most reliable pattern on the S7-1200. For S7-1500, prefer Variant unless the partner requires raw byte ranges.
FAQ
Why can't I declare an ANY pointer directly in an S7-1200?
The ANY data type is not exposed in the S7-1200 declaration editor in TIA Portal. The replacement pointer is VARIANT, but VARIANT is not overlayable. To regain the runtime mutability of ANY on S7-1200, declare a Remote-typed tag and overlay it with a STRUCT that mirrors the canonical 10-byte ANY layout.
Is the AT overlay on a Remote tag legal in TIA Portal?
Yes, from TIA Portal V14 SP1 onward the compiler accepts AT overlays against Remote-typed tags provided the host block is non-optimized (S7_Optimized_Access := 'FALSE') or the pointer lives in a non-optimized DB. Older TIA Portal versions will reject the overlay.
What value must the id field of the ANY pointer contain?
The id field at bytes 0–1 must be 16#0010. Any other value is treated as an invalid pointer and the GET instruction returns an address-error status (typically 16#0080) without sending a request.
Can I use the same dynamic pointer for multiple GETs in the same cycle?
Yes. The Remote tag is a value passed by reference; copy the same pointer into multiple ADDR_x parameters of a single GET block, or trigger separate GETs sequentially. Make sure to update each pointer's amount and offset before each REQ pulse to avoid races.
Does this technique work on S7-1500?
Yes, with two caveats. First, S7-1500 supports Variant as a fully symbolic pointer, so dynamic addressing can be done with less manual byte packing. Second, when you do need ANY-style control, the Remote + AT overlay is permitted on optimized blocks starting in TIA Portal V17, simplifying the block attributes. Always verify against the S7-1500 system manual for your firmware.