Resolving OPN DB Indirect Addressing Failures in S7-1500 STL

David Krause13 min read
HMI ProgrammingSiemensTroubleshooting
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 Description

When programming Siemens S7-1500 controllers in Statement List (STL) using TIA Portal V20, a common failure pattern appears when engineers attempt indirect data block access through the OPN instruction. The classic symptom is that DBW (data block word) reads return zero or stale values even though the target DB is being opened with a dynamic number stored in a memory word.

A representative failing sequence looks like this:

OPN   DB[Heat]                // Heat = MW110, currently 131
L     131
T     Heat
A     "BIT1"
A(
L     DBW 360
L     DBW 362
>=I
...

Engineers observe that DBW 360 and DBW 362 evaluate to 0 instead of the actual values stored at offsets 360 and 362 in DB131. The same code works if the DB number is hard-coded with OPN DB 131, but breaks when the number is parameterized through a marker word and an indexed OPN call.

The root cause is not a bug in the instruction. It is a fundamental behaviour of the S7-1500 CPU's DB register that is not always obvious to engineers transitioning from S7-300/400 or from ladder logic.

Root Cause Analysis

The S7-1500 CPU maintains two register pairs that track the currently open data block:

Register Pair Purpose Indexed access syntax
DB / DI Two independent DB register pairs, each holding a DB number DBW, DBB, DBD use the DB pair; DIW, DIB, DID use the DI pair

When the program issues a fully qualified DB access such as "DB_L2_Cmd_OP_Transfert".G1_TEMP — that is, an absolute or symbolic access that names the data block explicitly — the CPU loads the number of that named DB into the DB register before reading the operand. This is the same mechanism that makes a symbol like "Motor_DB".Speed work without an explicit OPN in front of it.

The user's failing code mixes two addressing styles inside the same AND block:

  1. An indexed access — DBW 360, DBW 362, DBW 364 — which depends on the DB register containing DB131.
  2. A fully qualified access — "DB_L2_Cmd_OP_Transfert".G1_TEMP — which silently writes a new value into the DB register as the compiler resolves the symbol.

Once any fully qualified DB access is evaluated inside the statement, the DB register no longer points to DB131. Every subsequent DBW read in that same network — or even in the next network, depending on cycle position — is interpreted against the wrong DB, and may even resolve against DB0 (the null block) where every DBW reads as zero.

Engineering note: In S7-300/400, the symptom is usually a "DB not loaded" or "Address error" diagnostic entry in the diagnostic buffer. In S7-1500, the CPU often substitutes DB0 silently and returns zero, which makes the failure appear as a logic error rather than an addressing error.

Background: The OPN Instruction in S7-1500 STL

The OPN (Open data block in DB register) instruction for S7-1500 STL transfers the number of a global data block into the DB register. After OPN executes, any subsequent DBW, DBB, or DBD operand access reads from that DB until either the register is overwritten by another OPN or by a fully qualified access.

Key facts that govern the behaviour:

  • OPN DB <n> opens DB number n in the DB register.
  • OPN DB[MW110] opens the DB whose number is the current value of MW110.
  • OPN DI <n> opens instance DB n in the DI register.
  • A fully qualified symbolic access (e.g., "MyDB".Tag or DB20.DBW0) writes that DB number into the DB register as a side effect.
  • OPN DB 0 opens the null DB; DBW reads from DB0 always return 0.

This last point is the trap. The CPU does not raise an error when the DB register is silently repointed — it simply routes the next indexed access to whatever DB is now loaded.

Why the Failing Network Returns Zero

Walk through the original network step by step:

OPN   DB[Heat]                 // (1) DB register := DB131
L     131
T     Heat                      // (2) Heat := 131 (redundant, fine)
A     "BIT1"
A(
L     DBW 360                   // (3) reads DBW360 of DB131 — OK the first time
L     DBW 362
>=I
L     DBW 360                   // (4) reads DBW360 of DB131 — OK
L     DBW 364
>=I
L     DBW 360                   // (5) reads DBW360 of DB131 — OK
L     "DB_L2_Cmd_OP_Transfert".G1_TEMP  // (6) DB register := DB_L2_Cmd_OP_Transfert
>=I
L     DBW 360                   // (7) reads DBW360 of DB_L2_Cmd_OP_Transfert, NOT DB131
T     #G1_MaxTemp
)

Statement (6) is the point of failure. The compiler resolves "DB_L2_Cmd_OP_Transfert".G1_TEMP by loading that DB's number into the DB register before reading the tag. From that moment on, every DBW in the same network is interpreted against DB_L2_Cmd_OP_Transfert, not DB131. The values seen in DBW360, DBW362, DBW364 will be whatever those offsets happen to contain in that DB — which in the user's case is zero, giving the impression that "the indexed access is broken."

The same problem recurs in each of the four O(...) branches. The fully qualified read of G1_TEMP in every branch silently invalidates the indexed reads that follow it within the same AND/OR block.

Verified Solution: Reopen the DB Before Every Indexed Read

The reliable fix is to re-issue OPN DB[Heat] (or OPN DB Heat) immediately before any indexed DBW access that follows a fully qualified access. The corrected network looks like this:

OPN   DB[Heat]
L     131
T     Heat
A     "BIT1"
A(
// --- Branch 1: DBW360 is the maximum ---
OPN   DB[Heat]                  // reopen DB131 before every indexed read
L     DBW 360
L     DBW 362
>=I
L     DBW 360
L     DBW 364
>=I
L     DBW 360
L     "DB_L2_Cmd_OP_Transfert".G1_TEMP
>=I
L     DBW 360
T     #G1_MaxTemp
)

Repeat the OPN DB[Heat] line in front of every O(...) branch as well. The instruction is a single STL word (2 bytes) and executes in microseconds; there is no measurable performance penalty on S7-1500 CPUs.

Best practice: Treat the DB register as volatile across any fully qualified DB access. Place OPN DB[Heat] immediately before every indexed DBW/DBB/DBD read in the network. Do not rely on the register value surviving a single STL line that contains a fully qualified reference.

Alternative Pattern: Use a Local Copy to Avoid the Register Clash

If the OPN-per-read pattern is too verbose — for example, in a function that runs against four different DB numbers — copy the fully qualified tag into a temporary local variable first, then perform the comparisons against that local. This keeps the indexed DBW reads untouched:

// Copy G1_TEMP into a temp, using the DI register pair so the DB
// register is not disturbed:
L     "DB_L2_Cmd_OP_Transfert".G1_TEMP
T     #G1_OpTemp               // INT local in the FC/FB interface

OPN   DB[Heat]                 // DB register := DB131
L     131
T     Heat
A     "BIT1"
A(
L     DBW 360
L     DBW 362
>=I
L     DBW 360
L     DBW 364
>=I
L     DBW 360
L     #G1_OpTemp               // use the local copy, no DB-register side effect
>=I
L     DBW 360
T     #G1_MaxTemp
)

This pattern is more readable and removes a class of register-overwrite bugs. It is the recommended approach for any FC or FB that mixes indirect and fully qualified DB access.

Alternative Pattern: Use the DI Register for Indexed Access

The S7-1500 keeps a second register pair (DI) for instance DBs. DIW, DIB, and DID read against the DI register, which is not affected by "DB...".Tag fully qualified access. If the target data blocks are instances of a known FB, open them with OPN DI[Heat] and read with DIW:

OPN   DI[Heat]                // opens the instance DB at number Heat in the DI register
L     DIW 360
L     DIW 362
>=I
L     DIW 360
T     #G1_MaxTemp

This is the cleanest pattern when the indexed DB is always an instance of a particular FB type. It also removes the need to keep reopening after every fully qualified DB access, because the DI register is not touched by "MyDB".Tag references.

Alternative Pattern: Symbolic Multiplexing with the PEEK/POKE Helpers

For S7-1500/1200 projects that prefer symbolic-only code, a user-defined FB can wrap PEEK (read) and POKE (write) to a parameterized DB number. The wrapper hides the indexed STL altogether. The disadvantage is that PEEK/POKE operate on byte offsets and do not honour the DB's declared data type, so the calling code must keep offsets consistent with the DB structure.

Pattern Pros Cons When to use
OPN DB[Heat] + indexed DBW Direct, type-aware, fastest DB register is volatile; reopen before every read Performance-critical loops, large DBs
Local copy of fully qualified tag + indexed DBW Readable, register-safe Extra local variable FC/FB that mixes both access styles
OPN DI[Heat] + indexed DIW DB register never disturbed Only works for instance DBs Indexing across instances of the same FB
PEEK/POKE wrapper FB Pure symbolic code Byte-offset, no type checking Configuration tools, HMI-driven DBs

Verification Procedure

After applying the fix, verify the network behaves as intended. Use the S7-1500 online watch table and program-status tools available in TIA Portal V20.

  1. Watch table setup. Create a watch table that contains:
    • MW110 (the Heat marker)
    • DB131.DBW360, DB131.DBW362, DB131.DBW364
    • DB_L2_Cmd_OP_Transfert.G1_TEMP
    • The output tag #G1_MaxTemp
  2. Pre-condition. Force three distinct values into DBW360, DBW362, DBW364 (e.g., 100, 200, 300) and a threshold into G1_TEMP (e.g., 50).
  3. Single-step the network. Right-click the network in the FC/FB and choose "Monitor with single step" (or use the STL debugger). Confirm that immediately before the first L DBW 360, the DB register shows DB131 (visible in the CPU's register view under "STW / DB / DI").
  4. Run cyclic. Set MW110 := 131 and confirm #G1_MaxTemp tracks the maximum of the three DBW values that exceeds G1_TEMP. Repeat for MW110 := 132 with DB132 populated, and for MW110 := 133 with DB133 populated.
  5. Negative test. Set MW110 := 0 and confirm the network does not crash but #G1_MaxTemp is undefined or zero (DB0 returns zero for every DBW). Add a range check on Heat before the OPN if the value can ever be zero.

Diagnostic Buffer and Error Codes

The S7-1500 rarely surfaces a hard error for a stale DB register, but it does log certain conditions in the diagnostic buffer:

Event ID Meaning Likely cause
0x2520 / 0x2530 Data block not found / wrong number MW110 contains a DB number that does not exist (e.g., 0, or a number above the configured max DB)
0x35xx I/O access error Not relevant to pure DB reads
0x5500 / 0x5501 Programming error, area length violation Indexed DBW offset larger than the open DB's length
Field tip: If the diagnostic buffer shows a "Data block not found" event every cycle, the value in MW110 is outside the range of configured DB numbers. The CPU does not stop, but DBW reads return zero because DB0 is treated as the fallback. Add a L Heat; L 1; >=I; L Heat; L MaxDB; <=I; A "BIT1"; guard to suppress the network on invalid indices.

Common Pitfalls and Field-Proven Caveats

  • Indexed OPN with a constant operand. OPN DB 131 and OPN DB[MW110] behave identically with respect to the register; the difference is only in where the DB number comes from. The pitfall is mixing the indexed and fully qualified forms in the same network without reopening.
  • Order of evaluation in STL. STL executes strictly top to bottom. The first fully qualified DB reference in the network wins, and every DBW below it sees the new DB number. Reorder the network so all fully qualified reads come before the indexed reads, and copy the result into locals, or reopen the indexed DB after each fully qualified read.
  • Symbol resolution in TIA Portal V20. If the target DB has the "Optimized block access" attribute, indexed DBW access with absolute offsets is still permitted in STL but the offsets refer to the compiled layout, not the source order. Check the DB's properties and the "Offset" column in the data view.
  • Multi-instance DBs. For FBs that use multi-instances, the DI register is the natural place for indexed reads; the DB register is reserved for global DBs. Mixing them is a common source of subtle bugs.
  • AR1 / AR2 pointer side effects. LAR1 and LAR2 with DB-relative addressing are independent of the DB register and are not disturbed by fully qualified access. They can be a robust alternative for very large, deeply indexed scans.
  • Memory word type. MW110 must be wide enough to hold the maximum DB number. For projects that may exceed 32767 DBs, use a DWORD marker and OD/OD instructions; OPN DB[MW110] with a 16-bit MW caps at 32767.

S7-300/400 vs. S7-1500 Behaviour

Engineers who learned indirect DB access on S7-300/400 sometimes expect the DB register to be sticky until a new OPN is issued. On S7-300/400, fully qualified DB access writes the DB register, but a warning is logged in the diagnostic buffer more often. On S7-1500, the register is overwritten silently and the diagnostic buffer stays clean, which is why the symptom is "values are zero" rather than "addressing error." Treat the DB register as transient in both families, but verify with online monitoring on S7-1500 because no event is generated.

Commissioning Checklist

  1. Confirm Heat (MW110) is a 16-bit (or 32-bit) marker that holds the active DB number; check the project default and the data type.
  2. For every network that combines indexed and fully qualified DB access, place OPN DB[Heat] (or OPN DI[Heat]) immediately before the first indexed read of each branch.
  3. If using the local-copy pattern, ensure the temporary is declared in the FC/FB interface with the correct data type (INT for DBW, DINT for DBD).
  4. In the watch table, monitor the DB register (visible in the CPU register view) while single-stepping the network. It should show the expected DB number at every DBW / DIW read.
  5. Add a range check on Heat to prevent OPN DB 0 and out-of-range DB numbers.
  6. For projects that must work on both S7-300/400 and S7-1500, prefer the OPN DI[Heat] + DIW pattern; it is portable and avoids the DB register clash.

Summary

The OPN instruction in S7-1500 STL is correct and reliable. The "values are zero" symptom arises because fully qualified DB references inside the same network silently repoint the DB register away from the index-loaded DB. The robust patterns are: reopen DB[Heat] before every indexed read, copy fully qualified tags into locals and compare against those, or use the DI register pair with DIW/DIB/DID for instance DBs. Each pattern keeps the indexed and fully qualified access styles from interfering with each other, and each is verifiable in the TIA Portal V20 online watch table.

FAQ

Why does my S7-1500 STL network read DBW values as zero after OPN DB[Heat]?

Because a fully qualified DB access (for example, "DB_L2_Cmd_OP_Transfert".G1_TEMP) inside the same network silently overwrites the DB register. After the overwrite, every DBW is read from the wrong DB, and if the network reopens DB0, every value is zero. Reopen the indexed DB with OPN DB[Heat] immediately before each indexed read, or copy the fully qualified tag into a local variable first.

Is the OPN instruction different in S7-1500 STL compared to S7-300/400 STL?

The instruction itself is the same, but the S7-1500 overwrites the DB register on fully qualified symbolic access without raising a diagnostic event, whereas S7-300/400 often logs a warning. Treat the DB register as transient on both families and reissue OPN before any indexed read that follows a fully qualified reference.

Can I use OPN DI[Heat] with DIW to avoid the DB register problem?

Yes. OPN DI[Heat] opens the instance DB in the DI register pair, which is not disturbed by fully qualified "DB...".Tag access. Use DIW, DIB, and DID for indexed reads. This is the cleanest pattern for indexing across instances of the same FB.

What is the maximum DB number I can load with OPN DB[MW110]?

With a 16-bit MW, the maximum value is 32767. If your project may exceed that, use a 32-bit MD marker and confirm the S7-1500 firmware you are running supports the resulting index. S7-1500 CPUs as of firmware V2.0 support 16-bit OPN DB indices; the 32-bit form is permitted on newer firmware and is documented in the STL manual.

How do I confirm the DB register value during online monitoring in TIA Portal?

Open the online watch table or the program status view, then in the "Register" area of the S7-1500 online interface, monitor the DB and DI register contents. The register is updated on every OPN and on every fully qualified DB access. Single-stepping the network lets you see exactly which instruction changes the register and which indexed read is affected.

Back to blog