Overview: Why Access an Instance DB from an FC?
In a SIMATIC S7 program, the boundary between a Function (FC) and a Function Block (FB) is often misunderstood. An FC is a "function" in the literal sense - it has no memory of its own and returns temporary results on the local stack. An FB, on the other hand, is stateful: every call passes a reference to an Instance Data Block (iDB) that persists the FB's variables across scans.
A common field question is: "Can I read and write a value in an Instance DB from a normal FC?" The short answer is yes. The CPU does not enforce FB ownership of the data once the iDB is created. From an FC you can read/write any word in the iDB exactly as you would from a global DB, using the same STL instructions or symbolic names. The only differences are conceptual (who "owns" the data) and behavioral in the area of the DI register and FB call semantics.
This reference consolidates the practical rules, code samples, and pitfalls - including the well-known FB58 TCONT_CP MAN_ON/MAN issue - so that an S7-300/400/1200/1500 programmer can implement FC-to-iDB access with confidence.
Instance DB vs. Global DB: The Architectural Boundary
Siemens documents the distinction between the two DB types in the official support portal entry "What is the difference between an instance data block and a global data block, and how does CALL influence the DB register?". The key points:
| Property | Global DB (Shared DB) | Instance DB |
|---|---|---|
| Purpose | Holds program-wide data shared by any code block | Holds the working memory (STAT, IN, OUT, IN_OUT) of one FB call |
| Ownership | None - any code block may read/write | Assigned to a specific FB; conceptually "owned" by that FB |
| DB register loaded by |
OPN DB x (or AUF DB x) - loaded into the DB register |
CALL FBx, DBy - loaded into the DI register |
| Generated by | Programmer, manually | Automatically created when an FB is instantiated, or manually for multi-instances |
| Symbolic access | Yes, by DB name or data block symbol | Yes, by instance symbol (e.g. "Motor_1".ActualSpeed) |
| Typical variable area | Any user-defined structure | FB static section (STAT), plus IN/OUT/IN_OUT that map to static storage |
From the CPU's point of view, both DBs are simply 16-bit word-addressed memory areas. The distinction exists for the engineering tool, the compiler, and the human reader.
The DB and DI Registers During an FB Call
Inside a running FB, the CPU automatically uses the DI register to address the Instance DB. The CALL instruction sequence is roughly:
- Save the caller's DB register and DI register on the BSTACK.
- Load the called FB's Instance DB number into the DI register.
- Execute the FB body. Any symbolic or absolute reference to a STAT variable resolves through DI.
- On return, the previous DI/DB contents are restored to the caller's context.
Because the DI register is a separate physical register from the DB register, both are available simultaneously inside a code block. This is why an FC that opens DB 100 (global) with OPN DB100 and then references DBW0 does not interfere with the iDB that a nested FB call loaded into DI. The two address spaces remain independent until the programmer intentionally closes one or the other.
Can an FC Read and Write Instance DB Variables?
Yes. The original STL example from the field:
// FC10
L "Motor_Inst".SpeedSetpoint // or: L DB111.DBW0
L 20
+I
T "Motor_Inst".SpeedSetpoint // or: T DB111.DBW0
works identically whether DB111 is a global DB or the Instance DB of FB100 Motor. The CPU does not check ownership; the access succeeds as long as the DB exists and the offset is within its length.
STAT section is the single source of truth for a value, prefer routing writes through an IN_OUT or an FB method instead.Where Do FB Variables Live in the Instance DB?
The Instance DB stores the persistent part of the FB's variable declarations. The mapping rules differ slightly between S7-300/400 (classic) and S7-1200/1500 (TIA) but the principle is the same:
| FB declaration | Stored in Instance DB? | Visible from outside FC? | Notes |
|---|---|---|---|
VAR_INPUT (IN) |
Yes (copied at call time) | Yes, read/write if the FC has the DB open | Inputs are refreshed every call |
VAR_OUTPUT (OUT) |
Yes | Yes | Outputs are written back to the iDB when the FB returns |
VAR_IN_OUT (IN_OUT) |
Yes (passed by reference via pointer; stored copy in iDB) | Yes | IN_OUT is the most efficient way for an FC to mutate FB state, but see the FB58 pitfall below |
VAR / VAR_TEMP (TEMP) |
No - on the local stack (LSTACK) | No | Discarded at FB end; never visible to FC |
STAT |
Yes | Yes | Long-term memory - the canonical place for FB state |
Therefore, if you want an FC to influence or read FB state, you are really reading or writing one of the following Instance DB locations: IN, OUT, IN_OUT, or STAT. You cannot reach the FB's TEMP variables from outside because they live on the LSTACK of the calling instance, not in any DB.
STL Code Examples: Reading and Writing from an FC
2.1 Symbolic access (recommended in TIA Portal)
// FC20 - reads SpeedSetpoint, adds 20, writes back
L "Motor_1".SpeedSetpoint // resolves to DI[DBn].STAT.SpeedSetpoint
L 20
+I
T "Motor_1".SpeedSetpoint // back to the same iDB offset
2.2 Absolute access (S7-300/400 classic STEP 7)
// FC20 - same logic, absolute addressing
OPN DB 111 // open instance DB 111 explicitly
L DBW 0 // offset of SpeedSetpoint (WORD)
L 20
+I
T DBW 0
2.3 Mixed FC + nested FB call (DB vs DI coexistence)
// FC30 - opens a global DB and a nested FB call
OPN DB 200 // global recipe DB -> DB register
L DBW 10 // recipe value
T "Heater_1".Setpoint // writes to instance DB of FB50
CALL FB 50, "Heater_1" // CPU loads DI register with Heater_1 DB
// ... FB50 runs using DI register (DI) and DB register (DB200) stays intact
The CPU keeps DB=200 and DI=DBn(Heater_1) in their separate registers, so the global recipe lookup and the FB's STAT work do not collide.
SCL and Structured Text Examples
In TIA Portal SCL (Structured Control Language), the same operation is type-safe and self-documenting:
// FC20 in SCL
"Motor_1".SpeedSetpoint := "Motor_1".SpeedSetpoint + 20;
SCL resolves the instance symbol against the Instance DB at compile time. If you mistype a member name or the structure changes, the compiler will raise an error - this is one of the strongest reasons to prefer symbolic access over DBWx in any new code.
For complex operations across multiple iDBs:
// FC30 in SCL - cross-instance aggregation
#MaxSpeed := MAX("Motor_1".ActualSpeed,
"Motor_2".ActualSpeed,
"Motor_3".ActualSpeed);
"Line_Control".MaxSpeedObserved := #MaxSpeed;
LAD and FBD Representation
In ladder or function-block diagram, the Instance DB variable is simply dragged from the PLC tags or the FB's static section into the network. The resulting network shows a Move box or an Add box with the symbolic operand visible at the pin:
- Source:
%DB111.DBX0.0(BOOL) or%DB111.DBW0(INT) - the symbol is the human-readable alias - Destination: same block/offset or a different variable
For S7-1200/1500 with optimized blocks, the offset disappears from the LAD display and only the symbolic name is shown. The compiler packs bits and structures for best performance.
Best Practices When an FC Touches an Instance DB
- Prefer symbolic access. Both SCL and the symbolic STL view survive refactors. Absolute offsets break the moment the FB is edited.
-
Use STAT for FB-owned state. The well-known field pattern is to declare
VARfor everything that is not a physical I/O point, then have other blocks read it through the iDB or throughIN_OUT. - Document the coupling. Add a comment in the FC and a CROSS-REFERENCE entry. Siemens TIA Portal will show the cross-reference if you select the iDB tag and press Ctrl+Alt+F (or use the menu Editor → Cross-references).
- Avoid marker (M) flags as a shadow copy. A common anti-pattern is reading an FB output to M0.0, doing math on M0.0 elsewhere, and writing the result back to a different input. This makes the actual FB state invisible to the diagnostic viewer. Read/write the iDB STAT directly instead.
- Centralize the math in the FB when the data is logically the FB's responsibility. External FCs should consume results, not reshape the state machine.
- Mind the scan order. If FC10 and FB50 both write to the same iDB word in the same cycle, the value at the end of the cycle is whichever block ran last. Use the OB1 sequence as the truth source.
The FB58 TCONT_CP Pitfall: Why Constant IN_OUT Writes Are Dangerous
FB58 (TCONT_CP, continuous temperature controller) and similar controller FBs expose inputs such as MAN_ON (manual mode enable) and MAN (manual manipulated variable) as VAR_IN_OUT. The temptation in field code is to "force" a value every cycle:
// FC99 - bad pattern
"Heater_1".MAN_ON := TRUE;
"Heater_1".MAN := 50.0;
The Siemens documentation for the TCONT_CP family flags this as not recommended. The reasons:
-
Internal state machine coupling: FB58 expects
MAN_ONto be a level-sensitive enable, not a constant. Writing TRUE every scan is fine in principle, but if the FB internally raises an internal flag and you have wired something else to the same IN_OUT, you can create a feedback loop where the controller flips between manual and automatic faster than the operator can see. -
Edge behavior in TCONT_CP: Several of the controller's mode transitions are triggered on a change of
MAN_ON. A constant TRUE from FC99 combined with a momentary reset elsewhere (e.g. an HMI writing FALSE on a button release) causes repeated mode flips. - Alarm/suppression side effects: Forcing the manual value can suppress the controller's adaptive logic, leading to drift on the next return to automatic mode.
The correct pattern is to drive MAN_ON/MAN from a single source (HMI tag, mode selector, or a dedicated ModeHandler FB) and never overwrite them in a sweeping FC. If you must, gate the write with a one-shot edge or a change-detect block.
Multi-Instance DBs and the DI Register
When you create a multi-instance, the called FB's STAT area is embedded inside the caller's Instance DB. For example, FB100 Line instantiates FB50 Heater as a static member called Heater_1. There is no separate DB50; Heater_1 lives at some offset inside FB100's iDB. An FC can still access Line.Heater_1.Setpoint symbolically - the compiler resolves the full path. The DI register during the call chain is loaded/unloaded as normal.
Multi-instances keep the Instance DB count low and are the recommended pattern for any FB that contains more than one or two sub-FBs. The trade-off is that the parent iDB grows, and the absolute offset of any child member shifts if the parent STAT section is edited.
S7-300/400 vs S7-1200/1500: What Changes for FC → iDB Access?
| Aspect | S7-300/400 (STEP 7 V5.x, classic TIA) | S7-1200/1500 (TIA Portal V14+) |
|---|---|---|
| Block access model | Standard - absolute offsets always visible | Optimized (default) - offsets hidden, symbolic only by default |
| Symbolic access from FC | Allowed, optional | Strongly preferred; absolute may be disallowed on optimized blocks |
| Pointer to IN_OUT | ANY pointer (legacy) | VARIANT (typed) for newer SCL code |
| DB register visibility in STL | Explicit (DB, DI) - programmer can inspect with SAVE tricks |
Same DB/DI model under the hood, but editor hides the offset |
| Instance DB numbering | Manual or auto-assigned, low numbers typical | Auto, usually high numbers; symbolic only |
| Cross-reference of iDB member | Available in symbol table | Project tree → Instance DB → member → "Go to usage" |
On S7-1200/1500 with optimized blocks, a direct T DB111.DBW0 from an FC will be rejected by the compiler if DB111 is an optimized Instance DB. You must use the symbolic form: T "Motor_1".SpeedSetpoint. The Siemens documentation on optimized block access explains the rationale: better packing, less wear on non-volatile memory, and stronger type safety.
Verification: Prove the FC Really Read or Wrote the iDB
- Online → Monitor/Modify the Instance DB. Right-click the FB instance in the project tree and select "Monitor/Modify." Watch the actual offset while the FC runs.
- Watch table (VAT in classic STEP 7). Add the iDB symbol and the specific member; force the FC's trigger condition and observe the new value.
- Cross-reference the iDB member. In TIA Portal, right-click → "Cross-references" shows every read and write, including the FC. If your FC is not listed, the access did not happen.
- STL trace / trace function (S7-1500 only). Record the iDB member over a few cycles and confirm the FC's value actually landed. This is the most rigorous test.
- Add a one-shot breakpoint in the FC inside STEP 7 / TIA Portal. If the breakpoint is never hit, the scan path is wrong even if the code compiles.
Troubleshooting Matrix
| Symptom | Likely root cause | Fix |
|---|---|---|
| Compiler error: "Access to optimized block via absolute address not permitted" | S7-1200/1500 optimized block; FC used DBW0
|
Switch the FC to symbolic access: "Motor_1".SpeedSetpoint
|
| Value written from FC is overwritten immediately | Another block (often the FB itself) writes the same offset later in OB1 | Re-order OB1 segments, or move the write into the FB |
| SF (system fault) on the CPU after adding the FC | Stack overflow from nested calls; or iDB length too small for the new STAT | Recompile the iDB; check BSTACK depth in the diagnostic buffer |
| iDB value reads as 0 even though FC runs | Wrong DB number (e.g. typo, multi-instance offset miscalculated) | Use the symbolic name; cross-check the iDB number in the FB properties |
| FB58 keeps flipping between manual and auto | Multiple writers to MAN_ON (HMI and FC) |
Centralize the writer; remove the constant IN_OUT write from the FC |
| Compile error: "DB does not exist or is too short" | FB STAT section was enlarged after the iDB was last generated | Right-click the FB → "Instance DB" → "Generate" again |
Field-Notes Summary
- Reading and writing Instance DB variables from an FC is fully supported by the S7 CPU. The original STL example in the field question -
L db1.dbw0 / L 20 / +I / T db1.dbw0- is correct and will run unchanged regardless of whether DB1 is a global DB or an instance DB. - The architectural cost of doing so is coupling. Reserve direct FC-to-iDB access for cross-cutting concerns (line-level aggregation, recipes, mode synchronization). For everything else, keep state inside the FB and expose it via a clean
IN/OUT/IN_OUTinterface. - On S7-1200/1500, the editor will often force symbolic access, which is a feature, not a limitation. Build the project around symbols and the cross-reference tool, and the iDB remains a true single source of truth.
- Never write to FB58's
MAN_ON/MANas a constant from a sweeping FC. Mode-select logic is edge-sensitive and belongs in one place.
FAQ
Can an FC read or write a STAT variable of an FB?
Yes. STAT variables live in the Instance DB, and any code block with the iDB number open can read or write them using either absolute addressing (e.g. DBW0) or symbolic addressing (e.g. "Motor_1".SpeedSetpoint). On S7-1200/1500 with optimized blocks, only the symbolic form is allowed.
What is the difference between the DB register and the DI register?
They are two separate CPU registers used for two separate address spaces. The DB register is loaded by OPN DB x and is used for global DB access. The DI register is loaded automatically by the CALL FBx, DBy instruction and points to the current FB's Instance DB. Both registers coexist, so an FC can hold a global DB open while a nested FB uses DI for its STAT data.
Are TEMP variables visible from outside the FB?
No. TEMP (VAR_TEMP) variables live on the LSTACK and are released when the FB returns. Only IN, OUT, IN_OUT, and STAT are stored in the Instance DB and are reachable from an FC.
Why does my FB58 controller oscillate between manual and automatic mode?
Most likely multiple writers are toggling the MAN_ON IN_OUT, or a sweeping FC is writing a constant TRUE while an HMI button is briefly clearing it. Centralize the mode write in a single block (operator panel, mode-select FB) and remove the constant IN_OUT writes from any FC that runs every cycle.
Is a multi-instance the same as a separate Instance DB?
No. A multi-instance embeds the called FB's STAT area inside the parent FB's Instance DB at a static offset. The compiler still generates a valid iDB - it just lives inside the parent's iDB. Symbolic access from an FC works the same way; the compiler resolves the full path to the correct offset.
Do I need to recompile the Instance DB after editing the FB's STAT section?
Yes. If you add, remove, or reorder STAT members, the Instance DB must be regenerated (right-click the FB → "Instance DB" → "Generate" or "Recompile"). Forgetting this is one of the most common causes of "DB does not exist or is too short" compile errors.