Overview: The Three Storage Classes in Step 7
Siemens SIMATIC S7 controllers expose three fundamentally different storage classes for user data, and confusing them is the single most common source of intermittent machine faults in beginner code. Understanding the lifetime, scope, and retentivity of each class is the foundation of writing reliable S7-300, S7-400, S7-1200, and S7-1500 applications in STEP 7 (TIA Portal).
| Class | Declaration Site | Scope | Lifetime | Retentive by Default? |
|---|---|---|---|---|
| TEMP (Local) | OB, FB, FC interface | Block-local | One call invocation | Never |
| STAT (Static) | FB interface only | FB instance | Until instance DB is reinitialized | Configurable |
| Global DB / M | DB or symbol table | Plant-wide | Power-cycle or re-init dependent | DB: always; M: configurable |
The most important rule: never use TEMP to carry a value from one scan to the next. Use STAT inside an FB, or a tag in a global DB, or a retentive M bit. The remainder of this article explains the mechanism behind that rule, documents the OB1 anomaly that misleads newcomers, and provides a verification procedure to confirm your block is storing data where you expect.
How the Local (L) Stack Actually Works
Every organization block (OB), function block (FB), and function (FC) has an interface in STEP 7 where you declare IN, OUT, IN_OUT, STAT (FB only), and TEMP variables. The TEMP variables are mapped onto a per-call region of the L stack (local data stack) when the block executes. When the block returns, that region is released back to the L stack pool.
The L stack is a contiguous memory area whose total size is configured under the CPU properties in TIA Portal (Path: CPU > Properties > System and diagnostics > Local data). For an S7-1500 CPU 1515-2 PN, the default maximum L stack per OB priority class is typically 16 KB; for an S7-319, defaults are smaller. The CPU reserves the L stack for each OB priority class at startup based on the worst-case L-stack usage of the blocks in the call tree of that priority.
Because the L stack is one shared pool, two different blocks — or two instances of the same FB called from the same priority — can occupy overlapping L-stack offsets if the call structure is re-organized. Any value left behind in a TEMP variable from a previous call may be silently overwritten by a later call. This is the root mechanism of every "it works in OB1 but breaks in the FC" bug.
TEMP Variables: Lifetime and the OB1 Anomaly
The lifetime of a TEMP variable is exactly one call. When the block is entered, the L-stack region for that call is allocated; when the block is exited, the values are undefined. Reading the value of a TEMP that was never assigned in the current scan returns the last value left in that L-stack byte — which is, by definition, not deterministic.
Why OB1 looks different: OB1 is a special organizational block because it is the only OB the CPU calls every free-cycle scan. The L-stack region reserved for OB1 is allocated once at startup and is not reclaimed between cycles, because no other block ever runs at OB1's priority that would reuse that exact L-stack region. As a result, a TEMP declared in OB1 will appear to retain its value between scans, and a TEMP used as a one-shot bit in OB1 will work — but the moment the same code is moved into an FC or FB, it will fail.
What the Siemens S7-1500 System Manual Says
The SIMATIC S7-1500 system manual, available through the Siemens SiePortal product catalog, lists the following memory areas and their retentive behavior:
| Memory Area | Description | Retentivity |
|---|---|---|
| I (Process Image Inputs) | Input image | No (refreshed each scan) |
| Q (Process Image Outputs) | Output image | No |
| M (Bit Memory / Merkers) | Scratchpad flags | Configurable per byte |
| TEMP (L Stack) | Block-local temporaries | Never |
| STAT (Instance DB) | FB static data | Configurable per tag |
| Global DB tags | Plant-wide application data | Always (per tag config) |
One-Shot Bits: The Classic TEMP Misuse
Edge detection (rising edge, falling edge) is a one-shot operation: a boolean that is true for exactly one scan. The standard pattern in ladder logic is:
- Capture the input bit before the new scan reads it (use a memory of the previous state).
- Compare the new input to the previous state.
- Assert the edge for one scan only.
STEP 7's built-in |P| (positive edge) and |N| (negative edge) contact instructions rely on a stored edge bit (formerly called the edge memory bit, in M area or instance data). The fundamental implementation is:
// Ladder excerpt, FB "Mode_Select"
// "Start_PB" is an input tag from the symbol table
// "Start_PB_Edge" is a STATIC BOOL in this FB
Start_PB Start_PB_Edge Start_PB
--| |----------|/|-------------( S )--
Start_PB_Edge
--| |---------------------------( )-- // edge result
Start_PB
--| |-------------------------( Start_PB_Edge )-- // save current state
If Start_PB_Edge is declared TEMP instead of STAT, the rising-edge detection will work in OB1 in a small program and will fail the moment:
- The block is moved into an FC and called from two locations, or
- Another FC is added that also uses the same L-stack bytes, or
- The block is called from a cyclic interrupt OB (OB30-OB38) that interleaves with OB1.
Symptoms of a broken one-shot bit: the edge output flickers for one extra scan, the output never sets, or the output stays set permanently. All three failure modes are documented in Siemens FAQ entries for S7-300/400 edge detection.
Static (STAT) Variables: The Persistent Memory of an FB
Static variables are declared in the Static section of an FB's interface. They live in the FB's instance DB (background DB). The instance DB is generated automatically the first time the FB is compiled and downloaded with an instance-DB call site, and it persists across scans, power cycles (if marked retentive), and STOP-to-RUN transitions (subject to retentive tag configuration).
Static variables solve the cross-scan storage problem because they have:
- Unique storage per FB instance — two calls of the same FB each get their own instance DB region.
- Deterministic initialization — values are zeroed at instance-DB creation, then behave per their retentive flag.
-
Symbolic access in TIA Portal:
"MyFB"."Start_PB_Edge"regardless of the absolute memory address.
Multi-Instance FBs on S7-1500 and S7-300/400
On S7-300/400, FBs can be called as multi-instances inside a parent FB: a single instance DB stores the static data of all child FBs. On S7-1200/1500 with optimized block access (the default in TIA Portal V17+), the same is true, and the storage layout is automatically managed by the compiler. The principle is identical: each FB call site has its own static region, so two instances of the same FB do not collide.
Data Blocks: Global Application Memory
A global DB (DB of type "Global DB" in TIA Portal) is a flat collection of tags accessible from any block in the program. By default, every tag in a global DB is always retentive; the retentive range can be restricted per tag in the DB's properties dialog (DB > Properties > Attributes > Retain).
The crucial property for the use case discussed in the source material: a value written to a global DB tag survives a power cycle of the PLC if the tag's retentive flag is set (and the CPU has a working backup battery or supercapacitor, depending on the model). For an S7-1500 CPU 1511-1 PN, retentive data is held in NVRAM (no battery required) up to the configured limit. For an S7-315-2 PN/DP, the retentive area is held by the backup battery and is configured under CPU > Properties > Retentive memory.
| DB Type | Created By | Stores | Retentive? |
|---|---|---|---|
| Instance DB (iDB) | FB call site | STAT + IN_OUT of one FB instance | Per-tag configurable |
| Global DB (gDB) | User / programmer | Any application data | Per-tag configurable (default retentive) |
| Array DB | User (legacy S7-300/400) | Typed array of a single type | Per-element configurable |
| System DB (SDB) | CPU / Siemens | CPU configuration, diagnostics | Not user-editable |
M (Memory / Merker) Area: Configurable Retentivity
The M (Merker) area is a global flag space in the CPU. M0.0, MW10, MD100 — all are bit/word/DWord-addressable global flags. The retentive range of the M area is configured under CPU > Properties > System and diagnostics > Retentive memory > Merker in TIA Portal. The default for an S7-315-2 PN/DP is typically MB0–MB15 (16 bytes of retentive Merker); for an S7-1516, the default is often MB0–MB0 (no M retentivity — the platform prefers DBs).
Configuring Retentive M in TIA Portal V18 / V19 / V20 / V21
- Open the project in STEP 7 Professional (TIA Portal).
- Select the CPU device in the project tree.
- Open Properties > System and diagnostics > Retentive memory.
- Set the Number of retentive Merker bytes from 0 up to the CPU limit (e.g., 2048 bytes for CPU 1518-4 PN/DP).
- Compile the hardware configuration and download to the CPU.
Verification: after the download, perform a power cycle of the CPU. Set a Merker bit (e.g., M0.0 = TRUE), cycle power, and confirm M0.0 reads TRUE on the next online connection. If it does not, the retentive range was not set correctly or the CPU is in a no-battery/no-NVRAM state.
FC vs FB: When to Use Each
The selection of FC versus FB is driven by whether the block needs to remember anything between calls.
| Property | FC (Function) | FB (Function Block) |
|---|---|---|
| Memory across scans | None — TEMP only | Instance DB holds STAT |
| Instance support | No | Yes (multi-instance capable) |
| Static variables | Not allowed | Allowed in STAT section |
| Typical use | Pure math, scaling, type conversion, stateless utilities | Valve control, motor starters, regulators, sequencers, state machines |
| Called by | Any block (OB/FB/FC) | Any block; must specify an instance DB or multi-instance |
The classic rule for code organization: if the block has any kind of "state," it must be an FB, not an FC. A motor starter FB will track run-time hours, last command, fault state, and E-stop history — none of which can live in TEMP. A scaling FC that takes a raw input and an engineering-range pair and returns a scaled real needs no memory and is a clean FC.
Migration Notes: Coming from Unity Pro or Cx-Programmer
Engineers transitioning from Schneider Electric's Unity Pro (Modicon M340/M580) or Omron's CX-Programmer (CP/CJ/NJ series) frequently land on two misunderstandings:
- "Function" semantics differ. In Unity Pro, a "function" (DFB) is roughly equivalent to a Siemens FB — it has instance memory. A "procedure" in Unity Pro is roughly an FC. Mapping Unity Pro DFBs onto S7 FBs and Unity Pro procedures onto S7 FCs is the correct port.
- Local variables are not free-form. In CX-Programmer, you can declare a local inside a subroutine and have it persist; in S7, that local is TEMP and does not persist. The Cx-Programmer equivalent of STAT is the FB's work area or, more commonly, a global variable in a shared data area. Map to S7 FB with STAT.
The phrase "FB is a function with a memory which is DB" is the most concise way to remember the difference: the FB carries its DB with it, the FC does not.
Best Practices Summary
- Use TEMP only for in-block scratch values that are computed and consumed within the same scan.
- Use STAT in an FB for any cross-scan state, including edge-detection memory.
- Use a global DB for plant-wide state (setpoints, modes, recipes, fault logs).
- Use M flags sparingly and never for state that must survive a power cycle unless the M area is explicitly configured retentive.
- Make every non-trivial state machine a separate FB with its own instance DB.
- Never rely on OB1's L-stack retentivity — treat it as a happy accident and write portable code.
- Avoid two FCs with the same name being called from the same priority unless you have confirmed their L-stack regions do not overlap (TIA Portal's "Local data usage" tab in the CPU properties will report this).
Verification and Commissioning Checklist
- Open the project in STEP 7 Professional V18 or later (V21 is the current release as of the catalog snapshot on the Siemens SiePortal).
- Right-click the CPU and choose Compile > Hardware (rebuild all).
- Open CPU > Properties > System and diagnostics > Local data. Verify the per-priority L-stack size is large enough for your deepest call tree (TIA Portal will warn if not).
- Open each FB and inspect the Interface tab. Confirm every cross-scan variable is declared STAT, not TEMP.
- Search the project for direct TEMP accesses in OB1 that act as one-shot bits. Refactor each to a STAT in an FB or a flagged M/DB bit.
- Download to the CPU, go online, and open the Monitor & Force view of each FB instance. Force a STAT to TRUE, cycle power, and confirm the value is retained (if marked retentive).
- Force a TEMP variable — observe that its value is undefined at the start of each call.
Troubleshooting Matrix
| Symptom | Likely Root Cause | Diagnostic Step | Resolution |
|---|---|---|---|
| Edge detection works in OB1, fails in FC | TEMP used as edge memory in FC; L stack reused | Open the FC, check the Interface — TEMP used for "last value" | Convert FC to FB, move edge memory to STAT |
| Edge detection fails after adding a new FC | New FC consumes same L-stack bytes as the original | CPU > Properties > Local data: inspect usage report | Refactor to use STAT or increase L-stack isolation |
| Output stays set after input goes low | One-shot bit in TEMP did not clear between calls | Cross-reference the bit in the program | Move edge bit to STAT or retentive DB tag |
| DB value lost after power cycle | Tag retentivity not enabled, or CPU has no battery | DB > Properties > Attributes: check Retain; CPU diag buffer for battery fault | Enable retentive flag; replace battery; on S7-1500, ensure NVRAM limit not exceeded |
| M bit not retained after STOP→RUN | M retentive range not configured | CPU > Properties > Retentive memory: confirm Merker bytes | Set Merker retentive bytes, recompile HW config, download |
| FB instance data resets on download | Instance DB was reinitialized on download | Compare project online vs offline; check download options | Download blocks only, not the DB; or accept initialization for this download |
| Two FB instances of same type have colliding state | One instance DB used for two call sites | Cross-reference FB call sites | Generate separate instance DB per call site, or use multi-instance |
| Compilation warning "L stack overflow" | Call tree depth × max TEMP per block exceeds configured L stack | Open CPU > Local data; locate the priority class in red | Reduce TEMP usage, split FBs, or increase L-stack size if the CPU allows |
Frequently Asked Questions
Why does my TEMP variable in OB1 retain its value, but the same code fails in an FC?
OB1's L-stack region is reserved for the entire cycle and is not reclaimed between scans, so a TEMP that was written on cycle N still holds its value on cycle N+1. FCs and FBs do not get this guarantee — the L stack is reused, and a TEMP from a prior call may be overwritten. The OB1 behavior is an implementation detail, not a contract. Treat TEMP as non-retentive and use STAT in an FB, or a DB tag, for any value that must persist between scans.
Why does my FB require a DB? Can I not just declare variables inside the FB?
The instance DB is the FB's memory. STAT variables, IN_OUT parameters that are passed by reference, and the FB's local copy of any static state are physically stored in the instance DB. Without an instance DB, the FB has nowhere to keep its state between calls. Multi-instance FBs share a parent instance DB; stand-alone FBs each get their own. Every FB call site in the program must specify either a dedicated instance DB or a multi-instance parent.
How do I make a Merker (M) bit retentive?
Open the CPU device in the TIA Portal project tree, choose Properties > System and diagnostics > Retentive memory, and set the Number of retentive Merker bytes to cover the highest M byte you need retained. Recompile the hardware configuration and download to the CPU. On S7-1500 CPUs, the retentive Merker range is typically small (often 0 bytes by default) and is held in NVRAM; on S7-300 CPUs the range is held by the backup battery.
Are global DB tags always retained across power cycles?
By default, yes — every tag in a global DB is retentive unless you explicitly clear the Retain attribute for that tag in the DB's properties. On S7-1500, the total retentive data is stored in NVRAM up to a CPU-specific limit (for example, the CPU 1515-2 PN holds up to 512 KB of retentive data). On S7-300/400, retentive DB data is held by the backup battery. If the battery is dead, the retentive DB data is lost on power cycle even if the tag is marked retentive.
Can I use a TEMP variable as a one-shot (edge) bit?
It will appear to work in OB1 in a small program, but it is a latent bug. The correct location for a one-shot memory is a STATIC BOOL inside the FB doing the edge detection, or a global DB tag if the edge spans multiple blocks. STEP 7's built-in |P| positive-edge and |N| negative-edge contacts use exactly this pattern internally — they reference an edge-memory bit declared in the operand area you select (M area, DB, or instance).
How is an FB different from a Unity Pro DFB?
They are functionally equivalent: both have instance memory, both support multiple instances, and both carry state across scans. The mapping during a port is straightforward — a Unity Pro DFB with public variables becomes an S7 FB with STAT, an IN/OUT interface, and an instance DB per call. A Unity Pro procedure (no memory) becomes an S7 FC. The same convention applies to Omron Cx-Programmer function blocks (which are S7-FB-like) versus subroutines (which are S7-FC-like).
What is the current TIA Portal version, and where do I download the manuals?
The current release of STEP 7 Professional in the TIA Portal is V21, available on the Siemens STEP 7 product page. S7-1500 system manuals, programming and operating manuals, and the S7-1500 CPU 1511-1518 datasheets are available on the Siemens SiePortal product catalog for the SIMATIC S7-1500 family. Both URLs are the authoritative sources for firmware-version-specific behavior, L-stack sizing rules, and retentive-memory limits.