Siemens S7 POINTER Data Type: Multi-DB Access Without OPN

David Krause11 min read
SiemensTechnical ReferenceTIA Portal
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

Overview

Accessing data spread across multiple data blocks (DBs) without flooding the program with repetitive OPN instructions is a recurring challenge when programming Siemens S7-300, S7-400, and S7-1500 controllers. This reference explains the POINTER data type family defined for these platforms, the bit-level structure of each variant, and the practical STL/SCL patterns that allow an FC/FB to operate on a DB number supplied by the caller.

The information consolidates details from the official Siemens documentation entry covering POINTER for S7-300/S7-400/S7-1500 in TIA Portal V20 and the legacy STEP 7 Professional V14 SP1 manual. Engineers porting existing STEP 7 code to TIA Portal will find the bit structures, formal-parameter rules, and call-side assignment syntax reconciled here.

The POINTER syntax has not changed between STEP 7 V5.x, STEP 7 Professional V14 SP1, and TIA Portal V20 for the S7-300/400/1500 targets. Differences exist only in the editor surface (STL still present in V14 SP1, hidden by default in V20) and in how ANY pointers reference complex parameters such as STRUCT and ARRAY OF STRUCT.

POINTER Data Type Variants in S7

Three pointer formats exist in the S7 language definition. Each variant is selected implicitly when a block parameter is declared.

Variant Length Carries DB Number? Typical Declaration Typical Usage
Area (intra-area) pointer 32 bits No POINTER Implicit load/store of any address inside the currently opened DB or in bit memory/inputs/outputs
DB pointer 48 bits Yes (DB number in word) POINTER Formal parameter of FB/FC passing a DB address such as DB100.DBW100
ANY pointer 80 bits Yes (DB number, data type, count) ANY Formal parameter passing entire arrays or structures with type information

All three are visible in the TIA Portal block interface under Data typesPointer and ANY. The 32-bit form is what remains after the DB number is stripped; it is never used as a block-parameter type because the receiver has no way to recover the DB context.

POINTER Bit Structure

The 48-bit DB pointer layout is the canonical form when an operand like P#DB100.DBX 10.0 is used in STL or is typed at a formal parameter. Two words and a half-word encode the address.

DB Number (WORD) bits 47..32 = unused 0..65535 Byte Offset (DWORD) bits 31..3 byte address bits 2..0 = 000 in DB Bit / Area Code bits 1..0 bit offset 0..7 bits 7..3 area (10000=b) High word Word 1 Low word

The relevant encoding for the byte/bit fields follows the area-code table used by LAR1/TAR1 on S7-300/400. For an ANY pointer ten bytes are written contiguously in the following order:

Byte Offset Width Field Notes
Bytes 0..1 WORD 10h = ANY identifier Constant
Bytes 2..3 WORD Data type code 02h=BYTE, 04h=WORD, 06h=INT, 07h=DINT, 08h=REAL
Bytes 4..5 WORD Count of elements 1 for non-array actuals
Bytes 6..7 WORD DB number 0 if not in a DB
Bytes 8..11 DWORD Byte.bit + area code Same encoding as DB pointer

Constructing a POINTER in STL

A POINTER is just a 32-bit (area) or 48-bit (DB) integer; it can be loaded like any other double word. The address constant P#DBxxx.DBByte.Bit is the symbolic entry the editor accepts. The example below mirrors the original problem statement: selecting element index 10 in four parallel DBs.


// STL (STEP 7 Professional V14 SP1)
      L     10                       // desired array index
      SLD   3                        // multiply by 8 to get byte.bit spacing
      T     #temp_ptr                // MD 100 for example

      OPN   DB   100
      L     DBD [AR1,P#0.0]          // pointer as base
      T     DB100.DBD 40

      OPN   DB   101
      L     DBD [AR1,P#0.0]
      T     DB101.DBD 40

      OPN   DB   102
      L     DBW [AR1,P#0.0]
      ITD
      TAK
      /D
      T     DB103.DBD 40

The repetition is still required because the CPU opens only one DB at a time. The next sections show how to eliminate the repetition by changing the calling structure.

Constructing a POINTER in SCL

SCL (Structured Control Language, IEC 61131-3) hides the address arithmetic. Assigning DB100.DBW100 to a variable of type POINTER is sufficient; the compiler emits the 48-bit constant automatically.


// SCL inside an FB declared as POINTER
      IF #IndexValid THEN
          #pSrc1 := P#DB100.DBX 40.0;          // initialize at first scan
      END_IF;

      #value1 := DWORD_TO_REAL(
                   IN:= WORD_TO_BLOCK_DB(100).DD[(#iIndex-1)*4 + 40/8]);

SCL is the recommended tool on TIA Portal V20 because STL is hidden by default and is not installed for new CPU projects targeting S7-1500. On S7-300/400, both editors remain available in STEP 7 Professional V14 SP1.

Block Parameter Passing for DB Pointers

The formal parameter declaration decides which pointer type is transferred. Use the rules below when designing FC/FB interfaces.

  1. Declare a formal parameter as POINTER if the caller hands over a single DB operand (for example P#DB100.DBX 10.0). The full 48-bit pointer (including DB number) is copied into the temporary variables of the called block.
  2. Declare the parameter as ANY when arrays or structured operands are passed. The block receives an 80-bit descriptor containing the type code, length, DB number, and start address; no OPN is needed inside the called block.
  3. Declare the parameter as VARIANT (TIA Portal V14+) for polymorphic sources. Conversion to POINTER or ANY is possible inside the block.
Per the official Siemens documentation for POINTER (S7-300/S7-400/S7-1500): "Enter the actual value without prefix P# in the block call to supply a formal parameter of the POINTER data type. The entry is then automatically converted to P#...". This applies to TIA Portal V20 and STEP 7 Professional V14 SP1.

Workaround: FB with Instance DB (Multi-Instance Pattern)

If the design requires the same index applied to four parallel arrays, the most compact implementation uses a single FB whose instance data block contains the four arrays. The data move is performed once during the parent FB call - the array elements are copied to the instance, and the FC/FB body accesses only the instance. No OPN, no POINTER arithmetic, no per-call block parameter passing for the arrays.


// FB declaration (TIA Portal V20 / STEP 7 V14 SP1)
FUNCTION_BLOCK MultiArrayFB
VAR_INPUT
    iIndex    : INT;       // user-provided array index
END_VAR
VAR
    aSource1  : ARRAY[1..200] OF REAL;   // mirror of DB100.DBD40 region
    aSource2  : ARRAY[1..200] OF REAL;   // mirror of DB101.DBD40 region
    aSource3  : ARRAY[1..200] OF INT;    // mirror of DB102.DBW20 region
    aTarget   : ARRAY[1..200] OF REAL;   // mirror of DB103.DBD40 region
END_VAR
VAR_TEMP
    rVal1     : REAL;
    rVal2     : REAL;
    iVal3     : INT;
    rProduct  : REAL;
END_VAR
BEGIN
    // Pull the values from the four DBs at the requested index
    rVal1 := WORD_TO_BLOCK_DB(100).DD[((#iIndex-1)*4) + 40];
    rVal2 := WORD_TO_BLOCK_DB(101).DD[((#iIndex-1)*4) + 40];
    iVal3 := WORD_TO_BLOCK_DB(102).DW[((#iIndex-1)*2) + 20];

    // Required math: rVal1 / rVal2, then convert iVal3 to REAL, divide again, write back
    rProduct := rVal1 / rVal2;
    rProduct := rProduct / DINT_TO_REAL(INT_TO_DINT(iVal3));
    WORD_TO_BLOCK_DB(103).DD[((#iIndex-1)*4) + 40] := REAL_TO_DWORD(rProduct);
END_FUNCTION_BLOCK

The four WORD_TO_BLOCK_DB(...).DD[] expressions carry the DB context implicitly; no OPN is needed because TIA Portal generates view-of-DB references via the integrated instance DB or via multi-instance background. The call site shrinks to:


    "InstanceDB".MultiArrayFB(iIndex := 10);

Why the Source Pattern Fails Without Restructuring

The original code loads from DB100 and DB101 in immediate sequence. The S7 CPU has only two address registers (AR1/AR2) and one DI/DB pair held in registers. You can read from DI (instance DB) and DB simultaneously on S7-400/1500, but a third concurrent DB read still requires an OPN or a manual AR manipulation. This is why each additional DB forces a sequential access. Lifting the data into an instance DB sidesteps the limitation entirely.

TIA Portal V20 vs STEP 7 Professional V14 SP1 Differences

Aspect TIA Portal V20 STEP 7 Professional V14 SP1
STL editor Optional, installed as a separate package; not for S7-1200/1500 new projects Always present in the LAD/FBD/STL editor
SCL VARIANT parameter Supported Supported from V14 SP1 onwards
POINTER P# constant Same syntax; e.g. P#DB100.DBX 10.0 Identical
ANY with STRUCT/ARRAY OF STRUCT Fully supported; length and type code emitted automatically Fully supported
Block parameter assignment at call Type info dialog; no P# prefix required per official docs Type info dialog; identical behaviour per V14 SP1 manual

S7-300/400/1500 Implementation Notes

  • S7-300: POINTER/ANY types use the standard 32/48/80-bit encoding. STL is fully available. AR1/AR2 cannot point into a DB whose DB number has not been opened - the assignment P#DB200.DBX0.0 accepted by AR1 stores the DB number but the CPU does not switch the DB register; you still need OPN DB[AR1] to dereference.
  • S7-400: Two DB registers are accessible simultaneously (DB and DI). Useful when reading from an instance DB (DI) and a global DB (DB) at the same time. Combined with a parameterised POINTER, an FB can dereference the source on DB and the instance on DI without explicit OPN at every call.
  • S7-1500: Optimised block access hides the POINTER representation - tags are referenced symbolically and the compiler embeds the address literal. The DB number is preserved implicitly. Area pointers and DB pointers still exist for legacy blocks but should be avoided in new projects; use VARIANT, ANY, or symbolic tags instead.

Limits, Hazards, and Edge Cases

  • DB number zero. A POINTER with DB number 0 references bit memory (M area). The area code byte 10001b (21h) means M. Without an explicit check, accidental assignments can land in the wrong area.
  • Bit boundary at byte 65535. Byte offset is stored in bits 31..3 as a 29-bit value. Valid range 0..0x1FFFF (524287 bytes). Do not exceed the per-DB limit (8192 bytes standard, up to 65535 bytes for large DBs configured in CPU properties).
  • Optimised access on S7-1500. POINTER-typed parameters are not allowed when the block has optimised access; switch the block to standard (non-optimised) access, or use VARIANT.
  • Multi-instance depth. Recursive use of instance DBs compiles on S7-1500 only when each level has a unique qualifier (the editor assigns Static_1, Static_1.Static_2 ...). Keep nesting < 8 levels to avoid online watch latency.
  • AR1/AR2 volatile on FC calls. Save the pointer across a nested FC call with LAR1 / TAR1 or - preferred - use the multi-instance pattern that depends on the compiler-managed ARs only inside the FB scope.

Best Practices

  1. Reorganise related arrays into a single DB whenever cross-index math is repeated more than ten times. Locate the start address of each array at a known offset (commonly 0) so the index formula becomes a constant array multiplication.
  2. If the four DBs must remain separate, declare a multi-instance FB that holds copies of the four arrays. The "copy on first scan" pattern ensures the data block layout stays external to the function block.
  3. Use SCL P#DBxxx.DByyy z constants only at static locations; never build them dynamically inside loops unless the project is restricted to S7-400/1500 with non-optimised access.
  4. Declare block parameters that receive DB addresses as VARIANT for new code, and cast to POINTER or ANY inside the block when the target S7-300/400 cannot be upgraded.
  5. Always validate the received DB number inside the called block before dereferencing - it might point to a DB that is not loaded; protect with a sentinel like ANY with type code 0xFFFF to abort.

Verification Procedure

To verify the resulting program, follow these checks in online mode with the programming device connected:

  1. Insert the FB into OB1 with a fixed index (e.g. iIndex = 5) and the four source DBs loaded into the active project.
  2. Trigger a single scan and inspect the instance DB tag values for aSource1[5], aSource2[5], aSource3[5] and aTarget[5]. They must equal the expected math result.
  3. Repeat with iIndex = 200 (last element) to confirm the byte-offset arithmetic does not overflow into adjacent tags.
  4. Open the block consistency check (TIA Portal: Project > Compile > Software (rebuild all)) and confirm zero warnings related to POINTER or ANY parameter types.
  5. For S7-1500 targets, switch the block to optimised access and ensure the cross-DB parameter passing still resolves without compiler errors; if errors appear, revert to standard access for that block only.

Can I read from two DBs at the same time without an OPN?

Yes - on S7-400/1500 you can use the two DB registers (DB and DI). Pass the second DB via a POINTER formal parameter (DB number auto-loaded by the CPU), then dereference AR1 with L DIB [AR1,P#0.0] while the instance DB stays open. S7-300 has only one DB register, so an OPN is still required for a third DB.

Why does the editor strip "P#" at the call site?

Per the official POINTER documentation, the actual parameter is entered as e.g. DB100.DBW100; the compiler automatically inserts the internal P# encoding into the pointer. Typing P# manually in the call is illegal and produces an error.

How do I copy a structured array instead of a single variable?

Declare the formal parameter as ANY. The block receives the full descriptor (data type, length, DB number, byte offset). Inside the block, use SCL's ARRAY[*] slice or STL's BLOKMOV (SFC 20) to copy without any per-element pointer arithmetic.

What is the maximum DB number I can store in a DB pointer?

DB numbers 1..65535 fit in the 16-bit field of bytes 6..7 of an ANY pointer (or the high word of a 48-bit DB pointer). DB number 0 refers to the bit-memory area and is reserved for non-DB operands.

Should I use POINTER or VARIANT in new code?

Use VARIANT in new code. VARIANT is available from STEP 7 V14 SP1 and TIA Portal V14 onwards; it allows polymorphism across all data types and can be inspected with TypeOf() / IS_NULL(). POINTER remains valid for legacy blocks and for parameter passing into S7-300/400 STL where the editor does not surface VARIANT cleanly.

Back to blog