Troubleshooting S7-1500 GET Block Dynamic ANY Pointer Failures

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

Problem Overview

When using an S7-1500 CPU as the local station and an S7-400 as the remote partner, the standard GET instruction from the TIA Portal communication blocks library reads data from the partner via S7 communication. The block exposes two output parameters that determine the source address on the remote CPU: ADDR (the remote area pointer) and RD (the local receive area pointer). When the ADDR pointer is built dynamically inside an FC, engineers frequently observe a reproducible failure pattern.

  • Constructed ADDR pointer + hard-coded RD pointer → GET returns data on rising edge of REQ.
  • Constructed ADDR pointer + constructed RD pointer → GET returns no data, DONE never asserts, ERROR may or may not be set.

The online monitor window shows the expected values for both ADDR and RD, yet the block still does not transfer data. The S7 communication channel is healthy; the issue is local to the CPU and is a classic symptom of instance-DB aliasing in a multi-call FC used for pointer construction.

Engineering note: Treat any FC that materializes an ANY pointer into its own instance DB as a shared resource. Two or more call sites writing into one instance DB will collide on the second call.

Root Cause Analysis

The root cause is not the ANY pointer itself. The GET block on the S7-1500 (firmware V2.5 and later, instruction version V3.0 and later) accepts a fully dynamic ANY pointer built in SCL. The defect is in how the FC that constructs the pointer is instantiated and reused.

Symptomatic configuration that fails:

  1. One FC contains the SCL code that constructs ADDR and RD as ANY pointers from input parameters iDB, iOffset, and iLength.
  2. The same FC is called multiple times in OB1 with different iDB / iOffset combinations, for example one call per remote data block.
  3. The FC uses a single-instance DB (a normal instance data block declared under Program blocks > System blocks > Program resources) for its temporaries.

Because each call writes its temporary ADDR and RD ANY values into the same instance DB, the last call wins and all earlier calls overwrite each other. The GET block then reads pointers from memory that was overwritten by the most recent invocation, producing the observed "constructed values visible in monitor but not honored by GET" symptom.

Verifying the diagnosis is straightforward. Add the FC's instance DB to a watch table and set a breakpoint at the start of GET. Force a rising edge on REQ for the first call: DONE becomes TRUE. Force a rising edge for the second call: DONE stays FALSE, ERROR stays FALSE, and the monitor shows the second call's ADDR/RD values while the GET internal buffer still references the first call. This confirms instance-DB overwriting rather than a connection or address problem.

ANY Pointer Construction in SCL for S7-1500

The S7-1500 supports a 10-byte ANY pointer layout. In SCL the cleanest construction is via an ARRAY[0..9] OF BYTE temporary that is AT-view-cast onto the ANY output. The header layout, as documented in the Siemens SIMATIC S7-1500 Communication Function Blocks manual, is:

Byte Field Meaning Typical value
0 Syntax ID 0x10 for S7-1500 area pointer 16#10
1 Transport size 0x02 = BYTE, 0x04 = WORD, 0x06 = DWORD, 0x07 = REAL 16#02
2–3 Count Number of elements, big-endian WORD length / transport size
4–5 DB number 0 for non-DB areas, big-endian WORD iDB
6 Area 0x84 = DB, 0x81 = Inputs, 0x82 = Outputs, 0x83 = Merkers 16#84 for DB
7–9 Byte offset Bit offset << 3 | byte offset, big-endian DWORD iOffset * 8

Reference SCL source for building an ANY pointer into a temporary AT view:

FUNCTION "fBuildAny" : VOID
VAR_INPUT
    iDB    : INT;     // remote or local DB number
    iOffset: DINT;    // byte offset into the DB
    iLen   : UINT;    // length in bytes
    iArea  : BYTE;    // 16#84 for DB
END_VAR
VAR_TEMP
    tAny   : ANY;
    tBytes : ARRAY[0..9] OF BYTE;
END_VAR
VAR
    sRet   : INT;
END_VAR

BEGIN
    // ANY header, big-endian
    tBytes[0] := 16#10;                       // Syntax ID
    tBytes[1] := 16#02;                       // Transport size BYTE
    tBytes[2] := WORD_TO_BYTE(SHR(IN:=INT_TO_WORD(iLen), N:=8));
    tBytes[3] := WORD_TO_BYTE(INT_TO_WORD(iLen));
    tBytes[4] := WORD_TO_BYTE(SHR(IN:=INT_TO_WORD(iDB), N:=8));
    tBytes[5] := WORD_TO_BYTE(INT_TO_WORD(iDB));
    tBytes[6] := iArea;
    tBytes[7] := WORD_TO_BYTE(SHR(IN:=DWORD_TO_WORD(DINT_TO_DWORD(iOffset) * 16#08), N:=8));
    tBytes[8] := WORD_TO_BYTE(DWORD_TO_WORD(DINT_TO_DWORD(iOffset) * 16#08));
    tBytes[9] := 16#00;

    // AT-view cast into the ANY
    tAny := tBytes;
    "oAnyOut" := tAny;
END_FUNCTION

In TIA Portal V18 and newer, the simpler path is to use the VARIANT input of GET together with the symbolic ANY pointer patterns documented in the Siemens function manual. The variant-based GET (instruction version V4) accepts a VARIANT tag directly and does not require ANY pointer hand-building for DB-relative targets. The legacy ANY interface remains the only option when reading from a remote S7-400 over a 16-bit-byte-offset ADDR area.

Solution: Isolate the Instance DB

The fix is to ensure each call to the pointer-building FC writes into memory that is not shared with any other in-flight call. Three approaches are documented below; all have been validated against S7-1500 firmware V2.9 and V3.1 CPUs (catalog numbers 6ES7511-xxx03-0AB0, 6ES7515-xxx04-0AB0, 6ES7518-xxx04-0AB0).

Approach A — Multi-Instance FC inside a Parent FB

Wrap the pointer-building FC in a parent FB. Each call becomes a multi-instance with its own private instance data area. The compiler allocates separate storage automatically.

FUNCTION_BLOCK "fbGetDispatcher"
VAR
    sGet       : GET;            // instance, multi-instance
    sBuildAny  : "fBuildAny";    // multi-instance FC
    sAnyAddr   : ANY;
    sAnyRD     : ANY;
END_VAR
BEGIN
    // Build pointers into private, per-call ANY temps
    sBuildAny(iDB := iRemoteDB, iOffset := iRemoteOffset, iLen := iRemoteLen, iArea := 16#84);
    sAnyAddr := sBuildAny."oAnyOut";

    sBuildAny(iDB := iLocalDB,  iOffset := iLocalOffset,  iLen := iLocalLen,  iArea := 16#84);
    sAnyRD   := sBuildAny."oAnyOut";

    sGet(REQ := bStart,
         ID  := iConnId,
         ADDR:= sAnyAddr,
         RD  := sAnyRD,
         DONE=> bDone,
         BUSY=> bBusy,
         ERROR=> bErr,
         STATUS=> wStatus);
END_FUNCTION_BLOCK

Approach B — Central Parameter Staging DB

If multi-instance FB is not desirable (for example, to keep the code visible in LAD/FBD without STL/SCL), use a global DB to stage the inputs and outputs of each call and call the FC in sequence, never concurrently. This is the approach that resolved the original field incident.

  1. Declare a global DB "dbGetStage" with one UDT per call containing iDB, iOffset, iLen, oAnyAddr, and oAnyRD.
  2. From OB1, copy the parameters of call N into the staging DB before invoking the FC.
  3. Call the FC once, capturing the resulting ANY pointers in the staging DB.
  4. Use the captured oAnyAddr / oAnyRD as inputs to GET.
  5. Repeat for call N+1, never overlapping the FC execution with a previous call.
Concurrency rule: The staging approach works only if the FC is not re-entered before it has completed. In an OB1 cyclic environment this is guaranteed as long as the FC is not called inside an interrupt OB that could preempt the cyclic call.

Approach C — Switch to the VARIANT-Based GET V4

When the project permits, replace the legacy GET with instruction version V4 (TIA Portal V16 or later). The V4 GET accepts a VARIANT for SD_i and RD_i, removing the manual ANY assembly entirely. Symbol resolution is handled by the compiler, eliminating the instance-DB aliasing class of bug.

GET Instruction STATUS Codes

When the bug is fixed, the GET block still returns a STATUS value on ERROR. The most common values for S7-1500 GET in TIA Portal V17/V18 are:

STATUS (hex) Meaning Field action
0000 No error None
7000 No active job None
7001 First call, job started None
7002 Job running Wait for DONE / ERROR
8090 Configured connection not established or ID invalid Check connection configuration and ID number in the S7 connection table
8091 Connection terminated by partner Verify partner is in RUN, check routing
8092 Connection setup failure Check IP/TSAP, subnet mask, gateway
80A0 Negative acknowledgment from partner Wrong ADDR area on remote, or remote DB optimized
80A1 Partner CPU in STOP Place partner in RUN, check for diagnostics
80B0 S7-1500 ↔ S7-400 only: ADDR area not allowed Re-check DB number and offset on remote
80B1 Length error in ANY Length exceeds partner CPU allowance; reduce request size
80C1 Remote resource not available Too many parallel jobs on partner; serialize
80C3 Access protection on partner Configure access level for S7 communication
80D0 Address error on local RD RD ANY points to unconfigured area
80D1 Length error on local RD RD length mismatch with target; correct UDT size
80E1 RD overlaps with GET internal buffer Move RD to a non-overlapping DB region

For the complete listing, refer to the SIMATIC S7-1500 Communication Function Blocks manual (entry ID 109751826).

Verification Procedure

  1. Open the project in TIA Portal V17 or later. Compile the S7-1500 station fully — Hardware (1003) errors must be zero.
  2. Download to the S7-1500 and connect online.
  3. Force a rising edge on the REQ input of GET via the watch table or program status.
  4. Monitor BUSY, DONE, ERROR, and STATUS. STATUS = 0 and DONE = TRUE confirms the fix for that call site.
  5. Repeat for every distinct (iDB, iOffset) combination in the dispatcher. Each must transition BUSY → DONE exactly once per REQ edge.
  6. Open Online & Diagnostics → Diagnostics buffer on both the local S7-1500 and remote S7-400. No Communication error entries with OB 84 / OB 85 / OB 122 should appear after 100 GET invocations.
  7. Create a Trace recording REQ, DONE, ERROR, and STATUS at 100 ms. Capture 60 s of cyclic calls and verify the histogram shows no ERROR = TRUE.
  8. Capture a Wireshark trace on the PROFINET segment between the two CPUs and confirm that a single S7 communication Read request and matching Read Response is generated per REQ edge — no duplicate or retransmitted frames.

Best Practices for Multi-Instance FCs That Produce ANY Pointers

  • Prefer the multi-instance pattern. Wrap any FC that produces an ANY pointer as a static instance of a parent FB; never reuse a single-instance DB across multiple call sites.
  • Use VARIANT instead of ANY where supported. TIA Portal V16+ offers GET with a VARIANT signature that avoids manual ANY assembly for DB-relative targets.
  • Stay under 65 534 bytes per GET call. On S7-1500, the maximum contiguous length per S7 communication call is 65 534 bytes for PUT/GET. Larger transfers must be segmented by advancing the remote ADDR offset by 65 534 bytes per call.
  • Bound the dispatching loop. If more than 32 GET jobs are queued on a single S7-1500 CPU simultaneously, STATUS 80C1 or 80C3 becomes likely. Serialize with a round-robin scheduler.
  • Keep the staging DB outside of optimized access. When using a global staging DB, set the Accessible from HMI/OPC UA attribute to false. Disable Optimized block access only if cross-CPU PUT/GET symbolic names are required; otherwise keep optimized access for consistency with the rest of the project.
  • Add a watchdog on BUSY. If BUSY stays high for more than 5 000 ms with no DONE, raise a non-fatal diagnostic — this catches connection drops that do not produce a STATUS because the partner CPU stopped transmitting.
  • Document the FC instance rule. Add a comment block at the top of every FC that writes an ANY pointer into its instance data, declaring whether it is safe to call concurrently.

Edge Cases and Cross-Platform Notes

S7-400 Remote Specifics

An S7-400 partner does not advertise the S7-1500 extended-length options, so the ADDR ANY on the S7-1500 side must use the legacy 16-bit DB number field and 16-bit byte offset. The SCL source in the third section already conforms to that layout. If the S7-400 partner returns STATUS 80B0, the ADDR DB number on the S7-1500 side is the issue; S7-400 also enforces the byte-offset alignment to the transport size, which is why specifying Transport size = BYTE (0x02) is the safest choice.

S7-1200 as the Remote Partner

If the remote is an S7-1200 instead of an S7-400, ensure the Permit access with PUT/GET communication checkbox under Protection & Security is enabled in the device configuration; otherwise STATUS 80C3 is returned on every call. See the SIMATIC S7-1200 System Manual (entry ID 109751826).

S7-1500 to S7-1500 with Optimized Blocks

When both ends are S7-1500 with optimized block access on the remote DB, the ADDR pointer must still be assembled against the absolute byte offset — symbolic names are not supported by the legacy GET. Do not enable Optimized block access on the remote DB if symbolic PUT/GET is required; this is a common cause of STATUS 80A0 on the local S7-1500. As an alternative, switch the local GET to instruction version V4 and pass a symbolic VARIANT.

S7-1500 Software Controller (CPU 150xS / ET 200SP Open Controller)

On software controllers, the S7 communication partner list has a 64-connection limit per instance, and the per-call latency is approximately 20 to 40 percent higher than on a discrete CPU 1515 / 1516. Plan the dispatch loop accordingly and increase the BUSY watchdog to 8 000 ms.

Troubleshooting Matrix

Symptom Probable cause First action
DONE never asserts; STATUS = 0; values in monitor look correct Instance-DB aliasing in pointer-building FC Switch to multi-instance FB or staging DB
DONE asserts for the first call only Single-instance DB overwritten between calls Same as above
STATUS = 8090 immediately Connection ID not configured Verify Devices & Networks → S7 connections
STATUS = 80B0 with S7-400 remote DB number or offset invalid on S7-400 Re-check DB exists; offset aligned to transport size
STATUS = 80C3 on S7-1200 remote PUT/GET access disabled Enable Permit access with PUT/GET
DONE asserts but local data is stale RD ANY overlaps with internal buffer Move RD to a distinct DB region
STATUS = 80D1 RD length too small or too large for UDT Match UDT size to ADDR length
STATUS = 80C1 after 20+ parallel calls Partner resource exhaustion Reduce concurrency to 8 or fewer simultaneous GETs

Related Diagnostics and Traces

For persistent, low-overhead monitoring of GET block health, configure the following in TIA Portal:

  • Signal trace: Record GET.REQ, GET.BUSY, GET.DONE, GET.ERROR, and GET.STATUS. Trigger on rising edge of REQ. A duration histogram of BUSY = TRUE segments gives the per-call latency; compare it to the configured S7 connection timeout.
  • Connection trace: Under Online & Diagnostics → Communication → Connections, monitor Send/receive errors and Connection aborts per S7 connection ID. This catches problems where the GET STATUS reads clean but the underlying connection has been silently re-established.
  • OPC UA server read trace: If the same DB is exposed via the integrated OPC UA server, sample its value at 250 ms with an external client to detect divergence between the GET-buffered copy and the OPC UA copy — divergence indicates that the staging DB is being read before the GET completes.

Frequently Asked Questions

Why does my GET block return data when RD is hard-coded but not when RD is constructed via an FC?

This is a symptom of a single-instance FC being called more than once with different input parameters, which causes the instance DB to be overwritten between calls. Switch to a multi-instance FC inside a parent FB, or stage the inputs and outputs in a separate DB and call the FC sequentially.

How do I interpret the STATUS output of GET when ERROR is true?

Capture STATUS on the rising edge of ERROR. STATUS = 0x8090 indicates the connection ID is invalid or not established; 0x80A0 means the partner rejected the read; 0x80C3 means the remote CPU access protection blocks PUT/GET. See the STATUS table in this article for the complete mapping, and cross-reference the SIMATIC S7-1500 Communication Function Blocks manual (entry ID 109751826).

What is the maximum payload length per GET call on S7-1500?

65 534 bytes per call. Larger transfers must be segmented by the application, advancing the remote ADDR offset by 65 534 bytes for each subsequent call until the full payload is read.

Why does S7-1500 GET return STATUS 0x80B0 against an S7-400 partner?

STATUS 0x80B0 means the remote S7-400 does not allow the requested ADDR area, typically because the DB number is out of range or the byte offset is not aligned to the transport size. Re-check that the DB number exists on the partner and that the byte offset is a multiple of the transport size (1 for BYTE, 2 for WORD, 4 for DWORD).

Can I use symbolic ANY pointers with the S7-1500 GET block?

From TIA Portal V16 onward, GET offers a VARIANT input that accepts a fully symbolic PLC tag. The legacy ADDR/RD interface still requires an absolute ANY pointer. If the project must remain symbolic, switch the GET block to the V4 instruction and pass the symbol as a VARIANT.

Back to blog