Dynamic ANY Pointers for GET in S7-1200 TIA Portal Implementation

David Krause14 min read
S7-1200SiemensTechnical Reference
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

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.

Engineering caveat: S7-1500 supports fully symbolic Variant pointers, so the technique documented here is primarily required for S7-1200 firmware (≤ V4.x tested). Verify against the S7-1200 system manual for your firmware version before commissioning; behavior of Remote-typed tags depends on TIA Portal version and CPU firmware.

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:

  1. Declare an ANY-typed tag in the input, output, in/out, or static section of an FB/FC.
  2. Overlay the tag with a STRUCT that mirrors the 10-byte internal layout (e.g., idCode, dataType, amount, dbNumber, area, byteOffset).
  3. At runtime, write the area, dbNumber, and byteOffset members; the resulting ANY points to the new location.
  4. 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 ANY results 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 ADDR input 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:

  1. 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.
  2. 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), and byteOffset (DWORD).
  3. Drive the members at runtime. Set id := 16#10, choose the data type code, set amount to 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.

id (WORD)0x0010 dataType (WORD)0x0005 amount (INT)n dbNumber (INT)DB# area (BYTE)0x8x byteOffset (DWORD)offset Byte: 024689 Addr: 0+2+4+6+8+9..+12
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.
Endianness: On S7, multi-byte fields inside the ANY are stored in little-endian (Intel) byte order. The id 16#0010 is stored as byte 0 = 16#10, byte 1 = 16#00.

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
Diagnostic tip: If the GET status returns 16#0080 / 16#000A-style "invalid address" codes, the most common causes are (1) wrong area byte, (2) DB number set when area ≠ 0x84, or (3) zero-length amount. Verify the 10 bytes in a watch table before triggering the request.

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.

  1. Create the FB. Add a new Function Block, language SCL. Name it, e.g., FB_DynamicGet.
  2. 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;
  3. Declare inputs. Add inputs for the dynamic address: iConnId : WORD, iReq : BOOL, iDbNumber : INT, iOffset : DWORD, iLen : INT, iTypeCode : WORD.
  4. Declare receive buffer. Add an InOut ioBuffer : ARRAY[0..4095] OF BYTE sized to the maximum expected payload.
  5. 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.
  6. 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, STATUS to FB outputs.
  7. 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.
  8. 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
Block attribute: 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 DONE rising edge for success, check STATUS on 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.

  1. Pointer validity. Open a watch table on the FB instance. Confirm:
    • sAddrAny.id = 16#0010
    • sAddrAny.area matches the intended memory area
    • sAddrAny.dbNumber matches the target DB (or 0 for non-DB areas)
    • sAddrAny.byteOffset is within the area's byte range
    • sAddrAny.amount × element_size does not overflow the receive buffer
  2. 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
  3. Data fidelity. Place a known pattern (e.g., REAL values 1.0, 2.0, 3.0) at the partner. Decode sRxBuf at 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.

Back to blog