Resolving DB? Unknown Datablock References in S7-300/400 Step 7

David Krause15 min read
S7-300SiemensTroubleshooting
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. Symptom: DB? in the Step 7 Cross-Reference

When a Step 7 (SIMATIC Manager) project for an S7-300 or S7-400 CPU is opened and the cross-reference list is generated (Options → Reference Data → Display), every access to a data block normally resolves to a concrete number. A bit access is shown as DB50.DBX7.7, a word as DB50.DBW20, a double word as DB50.DBD24, and an instance data block access as DI201.DBX0.0. When the Step 7 compiler cannot statically resolve which data block the access belongs to, the numeric identifier is replaced by a literal question mark:

  • DB?.DBX7.0 — bit access on an unresolved global DB
  • DB?.DBW20 — word access on an unresolved global DB
  • DI?.DBX0.0 — bit access on an unresolved instance DB
  • L DIB[AR1,P#0.0] with a dynamic area identifier — pointer-based access where the DB number is a parameter

The placeholder is emitted by the compiler at the time the block is built, not by the user at the keyboard. It is not a sign of project corruption, a missing license, or a bad block. It is a deterministic signal that at least one of three Step 7 language constructs was used in the program. The remaining sections identify those constructs, show the exact diagnostic procedure, and give the field-tested fix for each.

Engineering note. Step 7 V5.x is in extended maintenance under Siemens' product lifecycle ("Siemens Industry Online Support — SIMATIC S7-300/400 phase-out notice 109759590). This article applies to STEP 7 V5.5 SP4 and the SIMATIC Manager cross-reference as used with S7-300 CPUs 31x-2, S7-400 CPUs 41x/416, and the integrated PLC inside a Sinumerik 840D sl NCU (S7-317-2DP / S7-315-2DP).

2. The Three Root Causes of DB? / DI?

The Step 7 V5.x compiler emits a DB? or DI? placeholder for exactly three situations. Each one has a different origin and a different fix, so the first step is always to identify which one applies.

Cause Code shape Cross-reference output Resolution path
(1) Indirect DB addressing OPN DB[MW10], OPN DBI[MW10], L DBB[AR1,P#0.0] with dynamic area byte DB?.DBW... for every following access Eliminate the index, parameterize as IN, or document as dynamic
(2) Static OPN DBxx in the same priority class OPN DB50 followed by L DBW20 DB?.DBW20 in the cross-reference Navigate to the OPN to identify DB50
(3) Direct DB / DI access in an FC with no instance bound L DIB0 or U DIX0.0 inside an FC DI?.DBX0.0 Convert FC to FB with multi-instance, or pass DB number as IN of type BLOCK_DB

All three are covered below with code examples, the exact navigation in the cross-reference, and the change that makes the placeholder go away.

3. Cause 1 — Indirect DB Addressing

The classic pattern is an FC or FB that opens a DB based on a runtime index:

L #IndexInArray   // integer input
ITD
T #temp_dbno
OPN DB[#temp_dbno]
L DBB 0
T MB 100

Because the DB number is computed at runtime, the compiler cannot know which physical DB the subsequent L DBB 0 will land on. The cross-reference row reads DB?.DBB0 with the same ? for every indirect access in the project.

Diagnostic: in the cross-reference, filter by Operand pattern DB?.*. Double-click any row; if the network shows OPN DB[...], OPN DBI[...], or a pointer with a variable area byte, you have cause 1.

Fixes, in order of preference:

  1. Eliminate the index. If the application actually only ever opens one DB, replace OPN DB[#temp] with OPN DB50. The compiler will then resolve the cross-reference and the placeholder disappears.
  2. Parameterize the DB. Declare VAR_INPUT TargetDB : BLOCK_DB and call the FC with the target DB as a parameter. The FC then uses TargetDB symbolically, but inside the FC the access still emits DB?.DBB0 because the index is data-dependent — this only solves the call site, not the access inside the FC.
  3. Use UDTs. Make every record the same shape by deriving it from a UDT (user-defined data type). The runtime DB number is allowed to be unknown, but the offsets inside the DB are then guaranteed safe.
  4. Document the dynamic access. If the application genuinely picks the DB at runtime (recipe handling, tool tables on a CNC), leave the code as-is, document the placeholder in the project README, and filter the cross-reference by the call site to confirm only the expected FCs are involved.
Type-2 pointer with dynamic area byte. A register-style L DIB[AR1,P#0.0] in STL uses the byte after the area identifier (B#16#87 for DB, B#16#84 for DI) as the DB number. If the pointer is built in a different block from the one that consumes it, the compiler has no way to resolve the area byte at compile time. This is the most common form of DI?.DBX0.0 on a Sinumerik NCU and is by design.

4. Cause 2 — OPN DBxx in the Same Priority Class

The pattern is straightforward and very common in OB1, OB35, OB82, and OB100:

OPN DB50                    // open DB50 as the current data block
L DBW 20                    // implicitly uses DB50
T MW 40
CALL FC 100                 // inside FC 100, "the current DB" is still DB50
   i_input := MW40

The OPN DB50 makes DB50 the implicit data block for the whole priority class. Every subsequent L DBW... in the same OB will be emitted in the cross-reference as DB?.DBW... with the question mark, because the cross-reference is generated at the access site, not at the OPN site.

Diagnostic — how to confirm the actual DB number:

  1. In the cross-reference, double-click the row DB?.DBW20. SIMATIC Manager opens the network that contains the L DBW20 instruction. The status bar shows the source block (e.g. OB1, NW 7).
  2. Switch the editor to STL with View → STL (or press F8 if the network is in LAD/FBD). The first line in the same network (or earlier in the same OB) is the OPN DBxx.
  3. The DB number in the OPN is the actual DB that DB?.DBW20 resolves to at runtime.
  4. If two OPNs appear in the same OB, the one that executed most recently before the L DBW20 wins — OB scan order matters.

To bulk-confirm, use the Filter dialog in the cross-reference: filter Block to the OB and Operand to DB?.*. All DB? rows in that OB belong to the same OPN family.

5. Cause 3 — Direct DB/DI Access Inside an FC

An FC has no static instance data block. When the FC contains U DIX0.0, L DIB0, or L DB50.DBW20, the compiler emits the access in the cross-reference with a placeholder for two different reasons:

  • DI?.DBX0.0 — the FC has no instance bound to it, so the DI is unknown at compile time.
  • DB?.DBW20 — the explicit DB number is preserved in the operand column, but inside an FC the compiler still emits a ? because the FC can be called with different context (the call site can be different DBs in different OBs).

Fix 1 — convert to FB with multi-instance. This is the canonical solution.

FUNCTION_BLOCK FB100
VAR
   Static_State : BOOL;
   Static_Count : INT;
END_VAR
BEGIN
   U    #Static_State;        // bound to the instance DB of FB100
   L    #Static_Count;        // bound to the instance DB of FB100
   ...
END_FUNCTION_BLOCK

When FB100 is called inside FB200 as a multi-instance, Step 7 allocates a single DI for FB200 and a slice of that DI for FB100. The cross-reference will show DI201.DBX0.0 after Program → Compile all — but during a partial compile of only FB100, the cross-reference will show DI?.DBX0.0 because the slice address is not yet final. This is the most common reason a freshly modified project still has DI? in the cross-reference.

Fix 2 — pass the DB as a parameter. If the FC truly must remain an FC (e.g. it is called from many places and converting is too invasive), pass the DB number as an IN of type BLOCK_DB and open it inside the FC:

FUNCTION FC100 : VOID
VAR_INPUT
   TargetDB : BLOCK_DB;
   Slot : INT;
END_VAR
VAR_TEMP
   ret : INT;
END_VAR
BEGIN
   ret := TEST_DB(TargetDB);            // validate before OPN
   IF ret <> 0 THEN RETURN; END_IF;
   OPN   DB[TargetDB];
   L     DBB[AR1,P#0.0];                // still emits DB? in cross-reference
   T     MB 100;
END_FUNCTION

The OPN DB[TargetDB] still produces DB?.DBB0 in the cross-reference. Fix 1 is preferred when the access is more than a one-shot read.

Fix 3 — leave it as an FC and add an OPN at the call site. If the FC is non-re-entrant and the design treats it as a macro, add OPN DBxx immediately before the call. The OPN establishes the implicit DB for the duration of the call, and the cross-reference will resolve as in section 4. This is the lightest-touch fix and is common in legacy S7-300 code.

6. The "Check Block Consistency" Procedure

Cross-reference data is generated from the compiled block objects, not from the source. If only some blocks have been recompiled, the reference data lags behind the source. The standard fix is:

  1. In SIMATIC Manager, right-click the Blocks folder of the S7 program.
  2. Choose Check block consistency... from the context menu.
  3. In the new window, choose Program → Compile all (or Compile and check).
  4. Wait for the status bar to read 0 errors, 0 warnings.
  5. Re-open Options → Reference Data → Display → Generate / Update.

On an S7-300 inside a Sinumerik NCU, this step is mandatory before every cross-reference export. The HMI and PLC share blocks, and the BTSS toolbox FCs/FBs reference each other; a partial compile leaves the multi-instance numbers (DI nnn) unallocated and the cross-reference shows DI? even though the project is functionally correct.

7. Sinumerik 840D sl — S7-300 in the NCU

The original report describes the symptom on a Siemens S7-300 PLC integrated in NCU where the 840D toolbox is not installed in SIMATIC Manager. This is a specific environment that the standard S7-300 KB articles do not cover, so the field-tested procedure is documented here in full.

Item Detail
CPU in the NCU S7-317-2DP (NCU 710/720) or S7-315-2DP (older NCU box)
Engineering tool STEP 7 V5.5 SPx + SINUMERIK 840D sl toolbox
Toolbox content BTSS FCs (FC21..FC30 family: BSEND/BRECV, RDPIW/RDPID, WRPIW/WRPID, ...), NC VAR selector, symbol table for NCK / HMI / drive variables
License tool Automation License Manager (ALM), license key on a USB stick (mmc) or a floating license served from a license server
Default PLC project path card/user/sinumerik/ncu/.../S7 on the CFast card

Without the toolbox and its license, the project opens, the blocks load, the CPU runs — but the cross-reference will not symbol-resolve any BTSS call. The unresolved entries appear as DB? or DI? in the reference data because the symbol table that would map DBW20 to myAxisSpindleSetpoint is the toolbox's symbol table, not the user's.

Toolbox license verification:

  1. Start → SIMATIC → Automation License Manager (ALM).
  2. Confirm the SINUMERIK 840D sl toolbox license is present and valid (yellow = OK, red = missing).
  3. If red, recover the license from a backup file (.zip) or import the license key from the Siemens License Key web portal (Siemens License Key download portal).
  4. Restart SIMATIC Manager. Regenerate the cross-reference (Options → Reference Data → Display → Generate).

If the symbol table itself shows ??? for the BTSS block names (FC21 BSEND, FC22 BRECV, etc.) and the data block names are DB? rather than the BTSS names, the toolbox installation is incomplete. Re-run the toolbox setup from the SINUMERIK commissioning DVD (or the Siemens HMI Vxx toolbox download) and pick Install for use with Step 7 V5.x. After re-install, reapply the license in ALM and repeat the cross-reference regeneration.

NCU-specific check. The PLC inside the NCU loads its blocks from the CFast card on every cold restart. If the engineering PC does not have the toolbox license, the PC's cross-reference will be partly unresolved even when the live NCU is fully consistent. Treat this as a license/engineering-station issue, not a NCU issue. Verify the NCU by reading the CPU diagnostic buffer via HMI → Diagnostics → PLC → Module Information.

8. Cross-Reference Window — Field-Use Tips

For routine DB? hunting, the following keystrokes cut the work by half:

  • Filter → Operand → DB?.* — shows only unresolved global DB accesses.
  • Filter → Operand → DI?.* — shows only unresolved instance DB accesses.
  • Filter → Block → OB1 / OB35 / FB200 — restricts the result to a single block, useful when the OPN is in OB1 and the reads are scattered across FCs.
  • View → Cross-references — the right view for DB? resolution. The Program Structure view only shows block hierarchy and is not helpful here.
  • Table → Save As — export the cross-reference as .txt and grep for DB? / DI?. This is the fastest way to scope a project-wide DB? cleanup.

Exporting is also the right way to document the dynamic accesses that legitimately remain in the project (Cause 1 with a runtime index). Save the .txt alongside the project README as cross_reference.txt.

9. Edge Cases and Pitfalls

  1. Reading the wrong column. The cross-reference shows the operand as written. DB?.DBX7.7 in the Operand column is a bit access in the currently open DI. The actual DB number is not in that row — it is in the network you jump to.
  2. Multi-instance renumbering. If you rename FB200, change the FB100 static interface, or rearrange the call order inside FB200, the DI number for FB100 changes. Old cross-references will show DI? until Program → Compile all re-allocates the DI numbers.
  3. Parameter-driven DB numbers from the HMI. A recipe or setup screen on the HMI can pass a DB number to the PLC at runtime. The PLC stores it in an MW and the FC uses OPN DB[MWxx]. This is a legitimate Cause 1 access and the placeholder is correct.
  4. DB vs DI semantics. Step 7 distinguishes global data blocks (DB) from instance data blocks (DI). The placeholder follows the operand: DB?.DBX0.0 for a global DB access, DI?.DBX0.0 for an instance DB access. Filtering both at once produces a confusing list — filter separately.
  5. STL vs LAD/FBD display. In LAD/FBD the editor hides the implicit OPN. If the network is in LAD, switch to STL with View → STL to see the OPN command.
  6. Partial download. If you download only the user blocks (not the system data), the PLC will reject the download with Online: blocks inconsistent. Always download the system data when the cross-reference was regenerated.

10. Verification Procedure

After the project is consistent, run through the following checklist to confirm the placeholder is gone (or that what remains is intentional):

  1. Open Options → Reference Data → Display. Filter by DB?.* and DI?.*. The expected number of remaining rows is zero for projects that do not use dynamic DB numbers, and a small documented set for projects that do.
  2. For any remaining dynamic accesses, document them in the project README with the HMI / NC source of the DB number.
  3. Run Check block consistency on the entire PLC. Expected result: 0 errors, 0 warnings.
  4. Download the project to the PLC (PLC → Download to Target). Expected result: the SFC 17 / SFC 18 download completes; partial download is rejected if blocks are inconsistent.
  5. Watch the CPU for one full OB1 cycle plus OB35 (if configured) in online mode. The CPU diagnostic buffer should contain no BLOCK_DB or DB_NOT_LOADED errors.
  6. On the Sinumerik 840D sl side, watch for PLC alarms 700000…700199 (PLC-side faults) and NCK alarms 800000…999999 (drive-related). An unresolved DI typically surfaces as a PLC stop with PLC alarm 700015 DB not loaded on first start-up after a reconfiguration.

11. Diagnostic Flowchart

DB? in cross-reference Jump to network (double-click row) OPN DB[MWxx] / OPN DBI[MWxx] Static OPN DB50 (or similar) Direct DB/DI access in FC Cause 1 — dynamic index Document or UDT-ize Cause 2 — OPN DBxx DB50 in same OB Cause 3 — FC without instance Convert to FB multi-instance Check block consistency → Compile all Regenerate cross-reference DB? resolved — verify with checklist

12. Field-Proven Tips

  • Keep the SINUMERIK 840D sl toolbox separate from the project. Do not put toolbox DBs in the project archive — they will then be confused with user DBs and the cross-reference will show user-named entries alongside BTSS-named entries.
  • Use UDTs and FBs with multi-instances for any structure that is repeated more than twice. This removes most of the indirect OPN DB patterns in older S7-300 code and the cross-reference stays clean.
  • Document every OPN DBxx in the project with a one-line comment that includes the name of the data block. This is the cheapest way to make the next engineer's life easier when they see DB? and navigate to the network.
  • If the project must be opened on a station without the toolbox (e.g. a customer site without license), the cross-reference will be partly unresolved. This is a license issue, not a project issue — explain this to the customer before they start editing.
  • Use the Reference Data → Display export (Table → Save As) in your project archive. The .txt file is the most useful diagnostic artefact when a second engineer picks up the project six months later.

FAQ

What does DB? mean in the Step 7 cross-reference?

DB? is a literal placeholder the Step 7 compiler emits whenever it cannot statically resolve the DB number at compile time. It is caused by one of three constructs: indirect DB addressing, an OPN DBxx in the same priority class, or a direct DB access from inside an FC that has no instance DB bound to it.

How do I tell which OPN DBxx a DB?.DBXy.z access belongs to?

Double-click the DB? row to jump to the network. The DB number is the most recent OPN DBxx in the same OB or FC (or the caller's OB/FC if the access is in a called FC with an OPN at the call site). For multi-instance FBs the DI is allocated at compile time — run "Program → Compile all" to resolve DI? to a real DI number.

Does the Sinumerik 840D toolbox affect DB? cross-references?

Yes. The toolbox contains the BTSS blocks (FC21 family), the NCK/HMI variable selectors, and the symbol table entries that the PLC program inside an NCU depends on. If the toolbox is missing or the Automation License Manager (ALM) cannot find its license, the cross-reference will show DB? for any access that goes through a BTSS block. Install or license the toolbox and regenerate the reference data.

What is the difference between DB? and DI? in the cross-reference?

DB? refers to an unresolved global data block (DB), DI? refers to an unresolved instance data block (DI). Step 7 reserves DB numbers for global data blocks and DI numbers for FB instances. In the program, L DBW20 uses the currently open DB and L DIW20 uses the currently open DI; the placeholders follow the same naming.

How do I avoid DB? altogether in new S7-300 code?

Use FBs with multi-instance DBs, prefer UDTs for repeated data structures, parameterize the DB number as an IN of type BLOCK_DB or pass an ANY pointer, and avoid writing inside FCs that read from "the current DI". This combination removes all three causes of DB? in user code and keeps the cross-reference clean.

Back to blog