Reading and Writing Instance DB Variables from Siemens S7 FCs

David Krause14 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: 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:

  1. Save the caller's DB register and DI register on the BSTACK.
  2. Load the called FB's Instance DB number into the DI register.
  3. Execute the FB body. Any symbolic or absolute reference to a STAT variable resolves through DI.
  4. 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.

Engineering rule of thumb: Just because the compiler allows the access does not mean it is good design. Treat any direct FC-to-iDB write as a coupling that future maintainers must understand. When the FB's 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

  1. Prefer symbolic access. Both SCL and the symbolic STL view survive refactors. Absolute offsets break the moment the FB is edited.
  2. Use STAT for FB-owned state. The well-known field pattern is to declare VAR for everything that is not a physical I/O point, then have other blocks read it through the iDB or through IN_OUT.
  3. 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).
  4. 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.
  5. 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.
  6. 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_ON to 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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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_OUT interface.
  • 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/MAN as 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.

Back to blog