UC vs CALL: FB and FC Memory Structure in Siemens S7-300/400
1. Problem Context and Scope
Engineers working with STEP 7 V5.x and STL (Statement List) on S7-300 or S7-400 controllers routinely need to decide between the CALL, UC (Unconditional Call), and CC (Conditional Call) instructions. The recurring question is what each instruction does to the CPU work memory — specifically to the local data (L-stack), the block stack (B-stack), and the instance data block (IDB) — when invoking a Function Block (FB) without parameters versus a Function (FC).
The short, definitive answer from the official Siemens FAQ 19700969 is that UC can call FBs only when the FB has no block parameters and no static local data; under those conditions the FB is invoked without creating an instance DB and behaves, from a memory perspective, like a parameterless FC. CALL, by contrast, always allocates or updates the instance DB (for FBs) and pushes a fully populated B-stack frame with parameter passing.
This reference consolidates the official Siemens FAQ, the S7-300/400 system and programming manuals, and the TIA Portal S7-1200 FB documentation to give a complete memory-level picture. It applies to:
- S7-300 CPUs: 312, 312C, 312 IFM, 313, 313C, 314, 314C, 315, 315-2 DP, 316, 317, 318, 319, 319F
- S7-400 CPUs: 412-1, 412-2, 414-2, 414-3, 416-2, 416-3, 417-4
- WinAC RTX and WinAC Slot (PC-based controllers)
- ET 200S and ET 200pro IM-CPU variants
The newer S7-1200 and S7-1500 families do not expose UC/CC opcodes; they use only the unified CALL mechanism. Section 10 covers the migration implications.
2. Block Taxonomy and Memory Footprint
Before dissecting the call instructions, classify the code blocks because each one carries a different memory signature in the CPU:
| Block Type | Abbrev. | TEMP Local Data? | STAT Local Data? | Instance DB Required? | Formal Parameters at Call? |
|---|---|---|---|---|---|
| Organization Block | OB | Yes (20 bytes startup info) | No | No | Fixed interface only |
| Function | FC | Yes | No | No | IN, OUT, IN_OUT, RETURN |
| Function Block | FB | Yes | Yes (resides in IDB) | Yes (or multi-instance in parent IDB) | IN, OUT, IN_OUT + STAT persist |
| System Function | SFC | Yes (pre-allocated by firmware) | No | No | Inputs at call time |
| System Function Block | SFB | Yes | Yes | Yes (system-supplied IDB, e.g., DB1, DB2...) | Formal parameters + STAT persist |
| Data Block | DB | N/A (data only) | N/A | N/A | Read/write via OPN DB or fully qualified access |
The discriminator between FB and FC in work memory is the Instance Data Block (IDB). The IDB is a real DB downloaded to the CPU and consumes work memory. An FB without static data and without formal parameters collapses, in effect, to an FC. That collapse is exactly what the UC instruction exploits and is the source of the original question.
3. UC, CC, and CALL Instruction Comparison
The three call opcodes differ in four respects: parameter passing, instance DB handling, B-stack frame content, and dependency on RLO.
| Property | CALL | UC | CC |
|---|---|---|---|
| Full name | Call block | Unconditional Call | Conditional Call |
| Available in | STL, LAD, FBD (S7-300/400/1200/1500) | STL only (S7-300/400) | STL only (S7-300/400) |
| Parameter passing | Yes — fills IN/OUT/IN_OUT/STAT | No — actual parameters illegal | No — actual parameters illegal |
| Instance DB update (FB) | Yes — IDB pointer set, STAT retained | No — IDB is not opened/allocated | No — IDB is not opened/allocated |
| Execution condition | Always | Always | When RLO = 1 |
| B-stack push | Yes, with full register save (AR1, AR2, DB, DI, accumulators as needed) | Yes, minimal save (return address only) | Yes, minimal save (return address only) |
| Local data consumption | Full TEMP area of called block | Full TEMP area of called block | Full TEMP area of called block |
| Can be used in FB/FC code? | Yes (any block) | Yes (any block) | Yes (any block) |
| Acceptable target types | OB, FC, SFC, FB, SFB | FC, SFC, FB (param/STAT-less), SFB (param/STAT-less) | FC, SFC, FB (param/STAT-less), SFB (param/STAT-less) |
The salient line in the Siemens STEP 7 help text is verbatim: "UC: Calls FCs and SFCs. FB calls are possible if the FBs do not require any block parameters and have no static local data." In other words, UC can call an FB only when the FB interface reduces to TEMP-only — and at that point the FB has no semantic difference from an FC except for the block type byte and the call opcode generated by the compiler.
4. CPU Work Memory Organization
Every S7-300/400 CPU partitions its memory into the regions that matter for this discussion. The official terminology appears in the S7-300 CPU 31xC and CPU 31x system manuals.
| Memory Region | Contents | Volatile? | Size Example (CPU 315-2 PN/DP) |
|---|---|---|---|
| Load memory | All blocks (OB, FC, FB, DB, SDB, SFB, SFC) including comments/symbols | No (Flash / MMC) | Up to 8 MB on MMC |
| Work memory (code) | Executable code portion of OBs/FCs/FBs/SFBs/SFCs | Yes (RAM, retained with battery) | 384 KB |
| Work memory (data) | DBs, instance DBs, SDBs at runtime | Yes (RAM, retained with battery) | 256 KB |
| System memory (bit memories M) | Flags, timers T, counters C, process image I/O | Yes (RAM) | 2048 B / 256 T / 256 C |
| Local data stack (L-stack) | TEMP variables of the currently executed OB and any nested blocks | Yes (per OB priority class) | Configurable per priority |
| Block stack (B-stack) | Return addresses and saved registers of nested calls | Yes | Same physical RAM as L-stack |
The local data stack is allocated at OB start; each OB priority class receives a fixed-size slice configured in HW Config → CPU Properties → Local Data. When a block calls another block, the called block's TEMP area is carved out of the calling block's remaining local data budget. If the budget is exhausted, the CPU enters STOP with OB121 / OB122 — a common error during UC-driven nesting.
The block stack is the mechanism that stores return addresses and the contents of registers that must be restored on return: AR1, AR2, the DB and DI register pair, and a partial accumulator save area. CALL saves the full register set; UC saves only what is strictly required for the new block to start fresh, which is why UC is slightly faster and uses marginally less B-stack space.
5. UC Calling an FC: Stack-Only Execution
When UC invokes an FC, the CPU performs the following sequence on each OB cycle (priority class):
- Push the return address of the instruction after the UC into the B-stack.
- Save the minimum register context required to resume the caller (no DB/DI/AR save because no parameter passing is implied).
- Set the L-stack pointer to the FC's TEMP area, pre-zeroed by the firmware on cold start and not re-initialized between calls within the same priority.
- Execute the FC's STL code from the first network.
- On reaching BE (Block End), pop the B-stack, restore the saved registers, and resume the caller at the instruction following the UC.
Because no actual parameters are passed, the FC must use absolute addresses (M, I, Q, DB loaded via OPN), shared flags, or the small slice of TEMP it owns. The FC's IN/OUT/IN_OUT formal parameters are visible in the variable table but the call site (UC) does not write into them — they read as undefined (zero) inside the FC on each entry. This is a frequent pitfall: an FC lifted from a library and called with UC often has IN parameters that are silently zeroed, producing unexpected behavior that a CALL-driven test never reproduces.
6. UC Calling an FB Without Parameters: The Hidden FC
When UC invokes an FB, the CPU cannot create an instance DB on the fly. The FB must therefore satisfy three preconditions, checked by the STEP 7 compiler at download and re-validated by the firmware at runtime:
- The FB's VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, VAR_TEMP, and VAR_CONSTANT sections must not contain any block parameter declarations that the call site needs to pass. In practice this means the interface must be empty or contain only VAR_TEMP and VAR_CONSTANT.
- The FB must not declare a STAT section. STAT is the only way FB memory persists between calls; without STAT, the FB has nothing to store in an IDB.
- No multi-instance references (no use of the parent FB's STAT slot for this child FB).
If all three conditions are met, the compiler accepts the UC call. At runtime, the CPU executes the FB exactly as it executes an FC: a new TEMP frame is allocated on the L-stack, code runs from the first network, and BE returns control. The FB's status bit in the B-stack still says "FB" rather than "FC" — useful for diagnostics that key on block type — but the work-memory cost is identical to an FC of the same code size.
Compare the two scenarios side by side:
| Aspect | FC + UC | FB (TEMP-only) + UC |
|---|---|---|
| Work memory code | FC code loaded | FB code loaded |
| Work memory data | No DB | No IDB created |
| L-stack per call | FC's TEMP bytes | FB's TEMP bytes (same algorithm) |
| B-stack per call | Minimal save | Minimal save |
| Can declare STAT? | No (syntax error) | No (would require IDB) |
| Parameter passing? | No | No |
| Multiple instances? | N/A | Not possible without IDB |
The conclusion of the original question is therefore: from the perspective of CPU work memory consumption, a UC-called FC and a UC-called parameterless FB are equivalent. The only practical difference is symbolic — the FB retains its type identifier in the B-stack and in the cross-reference, which is occasionally useful when stepping through the program with breakpoints in STEP 7.
7. Local Data (TEMP) Allocation per Block Type
The STEP 7 compiler reports the local data requirement of every block in the Block Properties dialog (File → Properties → General → Size). Use these values when sizing the priority class slices in HW Config.
| Block | TEMP Default | TEMP Typical Library Block | Local Data Slice Needed (HW Config) |
|---|---|---|---|
| OB1 (cyclic main) | 20 B startup | 20 B + user TEMP | Sum of OB1 TEMP + every nested FC/FB TEMP (per call depth) |
| OB35 (cyclic interrupt) | 20 B | 20 B + user TEMP | Independent slice — configure ≥ cumulative TEMP of nested calls |
| OB100 (warm restart) | 20 B | 20 B | Small slice usually sufficient |
| OB121 / OB122 (error) | 20 B | 20 B | Reserve a small slice to avoid masking the original error |
| FC (parameterless) | 0 B (none declared) | 0–256 B | Added to caller's local data |
| FB (TEMP-only, UC-called) | 0 B | 0–256 B | Added to caller's local data |
| FB (with STAT, CALL-called) | Same TEMP, STAT moves to IDB | Same TEMP | TEMP only; STAT lives in work-memory data region |
Field-proven sizing rule: total local data per priority class = (TEMPs of all blocks that can be on the call stack at once) + 20 B for OB startup. For an OB1 calling FC1 → FC2 → UC-FB3 in a chain, the slice must be ≥ 20 B + FC1.TEMP + FC2.TEMP + FB3.TEMP. CPU 315-2 PN/DP defaults to 256 B per priority, which is more than enough for most small projects but must be raised to 1024 B or 2048 B when a PID self-tuning FB (e.g., FB41 CONT_C) is nested two levels deep.
8. STL Code Examples and Field Patterns
Below are the canonical STL snippets as they appear in STEP 7 V5.x source files. The code is self-contained and can be pasted into an empty STL FC for syntax verification.
8.1 UC calling an FC
// OB1 - cyclic main, S7-315-2 PN/DP
NETWORK 1
L MW 10 // load flag word
UC FC 10 // call parameterless FC10
NOP 0
NETWORK 2
L DB11.DBW 0 // indirect data input
T MW 20 // hand to FC10 via flag
UC FC 10 // second call, same FC, no parameters
NOP 0
Note that FC10 is parameterless in this example. If FC10 has IN/OUT declarations, those values are undefined on entry because UC provides no actual parameters.
8.2 UC calling a parameterless FB
// FB20 - parameterless, no STAT, only TEMP
FUNCTION_BLOCK FB20
VAR
TEMP bFlag : BOOL; // local TEMP, 1 byte
TEMP iCount : INT; // local TEMP, 2 bytes
END_VAR
BEGIN
NETWORK 1
L 1
T #iCount; // use TEMP
SET
= #bFlag; // set TEMP bit
END_FUNCTION_BLOCK
// OB1 caller
NETWORK 1
UC FB 20 // allowed: no params, no STAT
NOP 0
The compiler accepts this because FB20 has no IN/OUT/IN_OUT and no STAT. The call does not allocate or reference an instance DB.
8.3 CALL calling the same FB with full parameters
// FB20 - now with parameters and STAT
FUNCTION_BLOCK FB20
VAR_INPUT
iPreset : INT;
END_VAR
VAR_OUTPUT
bDone : BOOL;
END_VAR
VAR
STAT iCount : INT; // static, persists in IDB
END_VAR
BEGIN
NETWORK 1
L #iCount;
L 1;
+I ;
T #iCount;
L #iCount;
L #iPreset;
>=I ;
= #bDone;
END_FUNCTION_BLOCK
// OB1 caller - must use CALL, IDB20 is auto-generated
NETWORK 1
CALL FB 20, DB20 // required: parameter passing + IDB
iPreset := MW10
bDone := A0.0
NOP 0
Replacing the CALL FB 20, DB20 line with UC FB 20 produces a compiler error: FB20 has parameters and STAT. The S7-300/400 firmware refuses the call because the IDB cannot be opened through the UC mechanism.
8.4 CC (Conditional Call) example
// OB1
NETWORK 1
A M 1.0 // RLO = 1 if M1.0 is true
CC FC 12 // call FC12 only if RLO = 1
NOP 0
CC is functionally identical to UC except the call is suppressed when the RLO entering the CC is 0. Use CC to implement a single-line conditional call without an explicit jump label, saving program memory.
9. Common Configuration Errors and Diagnostics
| Symptom in STEP 7 / HMI / Web Server | Diagnostic Buffer Entry | Cause | Fix |
|---|---|---|---|
| Compiler error: "FB requires block parameters / static local data" | None (offline) | UC references an FB that has IN/OUT/IN_OUT/STAT | Switch to CALL FB x, DBx; or strip the FB to TEMP-only |
| CPU STOP after download, SF LED on, BSTACK shows OB121 with B-Stack depth 0 | "OB not loaded" or "Priority class x: insufficient local data" | Cumulative local data of nested UC calls exceeds the priority slice | Increase local data size in HW Config → CPU Properties → Local Data |
| FC returns zero values unexpectedly | None (logic error) | UC passes no parameters; FC's IN/OUT are zeroed | Use CALL or pass data via M/DB shared region |
| FB output STAT = 0 on every call | None | UC called an FB that uses STAT (compiler should have caught this — re-validate interface) | Convert UC to CALL with explicit IDB; or remove STAT |
| Symbolic name in VAT resolves to wrong value | None | Symbol points to a TEMP inside a UC-called block; TEMP is not retained | Use watch table only on the active priority; avoid monitoring TEMP across cycles |
| OB35 interrupt OB runs but its child FCs seem to lose values | None | Local data slice of OB35 too small; data overwrites the slice of OB1 silently when priorities interleave | Raise OB35 local data; verify with SZL 0x0132 index 0x000A |
Field diagnostic: open the diagnostic buffer in STEP 7 (PLC → Module Information → Diagnostic Buffer), filter on Event ID W:16x 494C and S:16x 3xxx. The Event ID for "priority class local data exceeded" is 494C (hex) — also spelled out as "Local data stack overflow." Cross-reference the BSTACK to find which UC-called block is over-budget. The companion Event ID for "Instance DB not found / not loaded" is 3F3x, which appears when a CALL FB x statement has no IDB downloaded or the IDB has been deleted in offline programming.
10. Migration to S7-1200 and S7-1500
The TIA Portal S7-1200 and S7-1500 instruction sets do not include UC or CC. The migration path is mechanical and safe:
- Open the STEP 7 V5.x project in TIA Portal via the migration tool (TIA Portal V16+ supports direct import of STEP 7 V5.x blocks).
- For every UC/CC call, the migrator converts it to a plain CALL — but only after verifying that the called FB has no parameters and no STAT. If it does, the migrator flags a compile error.
- For an FB that genuinely has no parameters and no STAT, the migrated S7-1200/1500 project continues to behave as before. The new controller stores TEMP in the optimized data area of the call stack; STAT (if any) moves to the instance DB as before.
- Retire UC/CC patterns where the call site intended to pass data via a global flag. On S7-1200/1500, prefer the unified block interface or multi-instance DBs — both of which are enforced by the TIA Portal compiler.
Reference: the TIA Portal S7-1200 manual collection describes the FB as a code block that "uses an instance data block for its parameters and static data." That statement is the conceptual anchor for the FB family across all Siemens controllers: S7-1200 Programming Concepts — Function Block (FB).
11. Frequently Asked Questions
Can UC call an FB that has STAT variables?
No. The STEP 7 compiler rejects UC FB x when the FB declares a STAT section, because STAT persists in an instance DB and the UC mechanism does not open or allocate an IDB. Use CALL FB x, DBx instead, or remove the STAT declarations to make the FB TEMP-only.
Does UC save the caller's accumulator, AR1, and AR2 like CALL does?
No. CALL pushes a full B-stack frame that restores AR1, AR2, DB, and DI on return. UC pushes only the return address and a minimal register snapshot, which is why it is slightly faster but also why any data the caller expected to find in AR1/AR2 on resume must be reloaded explicitly by the called block.
What is the practical difference in work memory between a UC-called FC and a UC-called parameterless FB?
None. Both occupy work-memory code equal to the compiled block size, neither creates an instance DB, and both consume identical L-stack TEMP bytes during the call. The only observable differences are the block-type byte in the B-stack and the symbol name in the cross-reference.
Can UC and CC be used in S7-1200 or S7-1500 projects?
No. The UC and CC opcodes are not part of the S7-1200/1500 instruction set. Use the unified CALL instruction exclusively. Existing UC/CC call sites in STEP 7 V5.x projects are automatically converted to CALL during TIA Portal migration, with a compile-time check that the target FB has no parameters or STAT.
How do I diagnose a "local data stack overflow" when a UC call chain runs out of space?
Read the diagnostic buffer in STEP 7 (PLC → Module Information → Diagnostic Buffer) and look for Event ID 494C hex ("priority class local data exceeded"). The BSTACK panel shows the exact call chain. Raise the local data slice for the affected priority class in HW Config → CPU Properties → Local Data; on S7-300 the maximum is 8 KB per priority, on S7-400 it is 16 KB per priority. Verify with the system status list SZL 0x0132 index 0x000A, which reports the configured and maximum local data per priority.