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.
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:
-
Eliminate the index. If the application actually only ever opens one DB, replace
OPN DB[#temp]withOPN DB50. The compiler will then resolve the cross-reference and the placeholder disappears. -
Parameterize the DB. Declare
VAR_INPUTTargetDB : BLOCK_DBand call the FC with the target DB as a parameter. The FC then usesTargetDBsymbolically, but inside the FC the access still emitsDB?.DBB0because the index is data-dependent — this only solves the call site, not the access inside the FC. - 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.
- 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.
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:
- In the cross-reference, double-click the row
DB?.DBW20. SIMATIC Manager opens the network that contains theL DBW20instruction. The status bar shows the source block (e.g.OB1, NW 7). - 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. - The DB number in the OPN is the actual DB that
DB?.DBW20resolves to at runtime. - If two OPNs appear in the same OB, the one that executed most recently before the
L DBW20wins — 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:
- In SIMATIC Manager, right-click the Blocks folder of the S7 program.
- Choose Check block consistency... from the context menu.
- In the new window, choose Program → Compile all (or Compile and check).
- Wait for the status bar to read 0 errors, 0 warnings.
- 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:
- Start → SIMATIC → Automation License Manager (ALM).
- Confirm the SINUMERIK 840D sl toolbox license is present and valid (yellow = OK, red = missing).
- 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). - 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.
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
.txtand grep forDB?/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
-
Reading the wrong column. The cross-reference shows the operand as written.
DB?.DBX7.7in 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. -
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. -
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. -
DB vs DI semantics. Step 7 distinguishes global data blocks (DB) from instance data blocks (DI). The placeholder follows the operand:
DB?.DBX0.0for a global DB access,DI?.DBX0.0for an instance DB access. Filtering both at once produces a confusing list — filter separately. - 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.
- 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):
- 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.
- For any remaining dynamic accesses, document them in the project README with the HMI / NC source of the DB number.
- Run Check block consistency on the entire PLC. Expected result: 0 errors, 0 warnings.
- 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.
- 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.
- 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
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 DBxxin 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 seeDB?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
.txtfile 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.