1. S7-1200/1500 Memory Architecture Overview
The SIMATIC S7-1200 and S7-1500 controllers partition user memory into three primary regions that every TIA Portal programmer must understand before deciding where to place a variable:
- Load memory – non-volatile storage for the project (code blocks, data blocks, HMI tags, comments) typically implemented as a SIMATIC Memory Card. The S7-1500 keeps the project compressed in load memory and unpacks it into work memory on startup.
- Work memory – volatile, high-speed RAM used for executing code and holding runtime data. It is split into a code-work area and a data-work area. The S7-1511F, for example, ships with 450 KB code work memory and 1.5 MB data work memory; the S7-1214C ships with 100 KB work memory total.
- Retentive memory – a non-volatile subset of work memory that survives power loss, configurable per tag (boolean / byte / word / dword).
Understanding this split matters because variable storage decisions interact with where the value lives at runtime. A bit declared in a global DB but flagged non-retentive still consumes data work memory, whereas a bit placed in a global M-byte (Merker) area is loaded from the load image on every CPU restart by default unless declared in the retentive Merker list. Refer to the S7-1200 system manual chapter on CPU memory and memory management for the canonical description.
2. Memory Area Reference Table
The table below summarizes every legal storage location for user variables in an S7-1200/1500 program, the scope of the variable, and the access-time characteristics that govern scan performance.
| Area | Address prefix | Scope | Retention | Access time on S7-1500 |
|---|---|---|---|---|
| Process image input (I) | %I / %IB / %IW / %ID | Global, hardware-bound | Updated each cycle from PII | Very fast (load image) |
| Process image output (Q) | %Q / %QB / %QW / %QD | Global, hardware-bound | Written to PIQ at end of OB1 | Very fast (store image) |
| Merker / M-bit (M) | %M / %MB / %MW / %MD | Global, software-only | Configurable in retentive list | Fast (single-byte aligned) |
| Global DB (non-instance) | DBx.DBx | Global | Configurable per tag (optimized) or per DB area (classic) | Fast (non-optimized) / ~½ (optimized) |
| Instance DB (FB static) | iDB.Symbol | Per-FB instance | Tag-level (optimized blocks) | Fast (optimized = best) |
| TEMP local | #name | Per-block call (L-stack) | Never retained | Fast; reused after block exit |
| STAT local | #name | Per-FB instance | Retained with the instance | Fast (optimized) |
3. Where to Store Global Variables
The fundamental decision for a value that is read or written by more than one block is whether it lives in a global DB, the Merker area, or inside an FB instance. Each option has a different lifecycle, debugging footprint, and reuse penalty.
3.1 Independent global DB – the default
For S7-1200/1500 the recommended home for cross-block data is a global data block, ideally marked with the Optimized block access attribute. Optimized access gives two real benefits:
- The compiler is free to lay the data out in any order – usually packed – so the data work-memory footprint of 32 booleans is 4 bytes instead of 32 bytes.
- Symbolic, fully-qualified access in optimized blocks resolves to a register offset that the S7-1500 executes in roughly half the time of a non-optimized DB access. Benchmark figures recorded on an S7-1511F show that an M-bit access and a fully-qualified non-optimized DB-bit access take the same time, while a fully-qualified optimized DB-bit access takes approximately half of that time.
A typical project structure puts a single ProjectData or MachineData DB at the top of the program tree and groups the global values there:
// Global DB "MachineData" (optimized, retentive where required)
VAR
bAutoMode : BOOL; // mode selection
bFaultActive : BOOL; // global fault flag
rSetpointSpeed : REAL; // shared across drives FB and HMI FB
iCycleCounter : DINT; // non-retentive runtime counter
wProductionCount: WORD; // retentive production tally
END_VAR
3.2 Merker area – narrow use only
Merker addresses remain available in S7-1200/1500 for backwards compatibility and for a few legitimate purposes:
- System clock bits configured in the CPU properties (e.g. %MB0 as the clock byte).
- Quick debugging tags – during commissioning it is common to wire a suspect condition to an unused M-bit so that the watch table can monitor it without rebuilding the data block. Mark these clearly in the symbol table.
- Hand-off scratch values between program sections when the alternative is a properly-designed interface that you do not have time to refactor.
Long-term, the Merker area should not be used for production data. Reasons documented in the Siemens programming style guide include: the M area is a single shared namespace, has no symbolic structure in the default cross-reference, does not survive software re-downloads cleanly if the retentive list is changed, and discourages the discipline of well-typed data containers.
3.3 Encapsulation in an FB instance – the OOP default
When a value is conceptually owned by a specific subsystem (a motor, a valve, a recipe, a drive axis) it should live in the STAT section of an FB rather than in a global DB. The instance DB that the editor generates automatically becomes the storage container and the value is accessed symbolically through the FB instance, not by raw address. This pattern is the basis of the Siemens object-oriented programming style and is described in the SIMATIC S7-1500 OOP guidelines.
4. Local Variables: TEMP vs STAT
Local variables are declared inside an FB or FC and exist only for the duration of the block call. The distinction between TEMP and STAT is the most common point of confusion in TIA Portal projects.
4.1 TEMP – transient, non-retained
TEMP variables are allocated on the local data stack (L-stack) when the block is entered and released when the block exits. Two implications follow:
- The value is not retained across scans. If you need a value to persist, declare it STAT.
- The L-stack size is finite and is configured per execution level. If a multi-instance FB chain overruns the L-stack, the CPU goes into STOP with diagnostic buffer entry "Local data stack overflow". The S7-1511F, for example, provides 8192 bytes of local data per priority class.
TEMP is the right place for intermediate calculation results, scratch pointers in SCL, and values that are immediately consumed and discarded:
// FB "AxisControl"
VAR_TEMP
rAccel : REAL; // ramp output, single use
nIndex : INT; // FOR-loop index
bOkTmp : BOOL; // pre-conditional flag
END_VAR
4.2 STAT – retained within the instance
STAT variables live in the instance DB. Each call of the FB creates a new instance (or re-uses an existing one) and STATs persist between scans for the lifetime of that instance. The retention attribute of each STAT tag is configurable in optimized blocks – exactly the same mechanism that global DBs use.
// FB "MotorLMS" (Latched Motor Starter)
VAR STAT
bRunning : BOOL; // last commanded state, retentive
bFault : BOOL; // latched fault, retentive
tOnDelay : TIME; // configured via HMI
iStartCount : DINT; // non-retentive, cycles on CPU restart
END_VAR
4.3 Why TEMP can free memory
The frequently-cited claim that "TEMP frees up memory" refers to a specific trade-off: the L-stack memory is allocated and freed dynamically on block entry and exit, so a tag declared TEMP does not consume instance-DB bytes. For a value that is only needed inside a single block, TEMP is therefore more memory-efficient than STAT. For values that must persist, STAT is the only correct choice inside an FB.
5. FB/FC Encapsulation and Code Reuse
The block interface in TIA Portal exposes four sections that govern how data crosses the block boundary:
| Section | Direction | Read by callee | Written by callee | Typical use |
|---|---|---|---|---|
| Input (IN) | Caller → callee | Yes | No (constant within call) | Setpoints, mode selectors |
| Output (OUT) | Callee → caller | No (only after call) | Yes | Status flags, results |
| InOut (IN_OUT) | Caller ↔ callee | Yes | Yes | Buffers, accumulators |
| Static (STAT) | Internal | Yes | Yes | Latched state, history |
| Temp (TEMP) | Internal | Yes | Yes | Scratch values, loop indices |
The IN_OUT interface in optimized blocks is passed by reference, so a 200-byte UDT passed IN_OUT does not copy its data. This is the recommended pattern when a nested function needs to modify a structure owned by the caller. The same UDT passed as IN would either be read-only (caller's value copied in) or – if marked as a non-optimized block – copied back, doubling memory traffic.
For multi-level FB nesting the recommended pattern is to expose the child FB's instance as an IN_OUT of the parent, so the parent's STAT effectively contains the child's STAT and no global DB is involved. A typical three-level decomposition looks like:
// Level 1: Machine FB
VAR STAT
Motors : ARRAY[1..4] OF "MotorLMS"; // 4 motor FBs
Valves : ARRAY[1..8] OF "ValveFB"; // 8 valve FBs
bReady : BOOL; // aggregate hand-shake
END_VAR
Each MotorLMS instance owns its own fault flag, run-time, start count, and configured delay, all in its own instance DB. Machine aggregates the FBs and exposes a single bReady to the calling OB1 via IN_OUT or via a global DB if the HMI also needs direct access.
6. Access Time: Optimized DB vs Non-Optimized DB vs Merker
On modern S7-1500 CPUs the access-time ranking, fastest to slowest, is:
- Optimized block symbolic access (DB or instance)
- M-bit access / non-optimized DB-bit access (tied)
- Fully-qualified classic DB access (e.g. DB100.DBX0.0)
- PI/PO access via the process image (fast in absolute terms but the slowest of the four for raw bit access)
Concretely, on a S7-1511F a bit-access in an optimized DB executes in roughly half the time of the same access in a non-optimized DB. The benchmark numbers vary between firmware versions, but the ratio is consistent across the S7-1500 family because the optimized-block compiler emits a single register-offset instruction and the classic compiler emits a multi-step pointer walk.
7. Scan Time Impact of Storage Choice
For a small or medium-sized program, the scan-time difference between two functionally-identical programs – one using a global DB, the other using FB STATs and TEMPs – is negligible on S7-1200/1500. The reasons are:
- The S7-1500 instruction execution engine is highly pipelined and the bit-test and load/store micro-operations are cached.
- The I/O scan and process-image update dominate the OB1 cycle in most applications, often accounting for more than half the total.
- The optimizer in TIA Portal will often generate identical code for an access that resolves to the same physical byte, regardless of how the source code names the tag.
On S7-300 the picture is different: fully-qualified DB access (e.g. DB100.DBX0.0) is measurably slower than M-bit access because the CPU has to compute the DB pointer at runtime. Projects migrated from S7-300 to S7-1500 often keep the M-bit habit "just in case" and end up with slower code than the equivalent global DB.
8. Memory Monitoring in TIA Portal
The TIA Portal online tools provide real-time visibility into both cycle time and memory consumption. The procedure is documented in the S7-1200 system manual under Online and diagnostic tools – monitoring cycle time and memory usage.
8.1 Online memory display
- Connect the programming device to the target CPU and go online.
- Open the Online tools task card in the project tree (right-hand pane).
- Expand Diagnostics and double-click Online & Diagnostics.
- Select Memory in the diagnostics tree. The view shows load memory usage, work memory usage split into code and data, and retentive memory usage.
- For S7-1500 the same view also shows the maximum cycle time, the current cycle time, and the configured minimum cycle time.
8.2 Offline work memory estimation
Before downloading to a target CPU, the resource consumption can be estimated in the project properties. TIA Portal reports the compiled block sizes for each OB, FB, FC, and DB. A common pre-commissioning check is to compile the project, open the cross-reference, and total the data-work memory required by all optimized DBs against the CPU's data-work memory spec from the hardware catalog.
8.3 Diagnostic buffer entries for memory issues
| Symptom | Diagnostic buffer entry | Likely cause | Remediation |
|---|---|---|---|
| CPU goes to STOP at first scan of a multi-instance chain | "Local data stack overflow" / SF LED on | Excessive nesting depth of FBs, each with large TEMP sections | Raise the local-data size in OB1 properties, or refactor to reduce nesting |
| Download fails with "insufficient load memory" | n/a – download dialog message | Project exceeds SIMATIC Memory Card capacity | Archive and remove unused library versions, or fit a larger memory card |
| HMI loses values on power cycle | n/a – runtime observation | Tags declared in non-retentive DB | Flag the tags as retentive in the DB properties |
| OB1 execution time creeps up after a code change | Cycle-time histogram shift | Classic DB replaced with optimized DB or vice-versa | Use the online cycle monitor to confirm and revert if regression |
9. Siemens and PLCOpen Style Guides
Two documents are worth keeping open while reviewing a project's memory layout:
- Siemens Programming Style Guide – the canonical reference for naming, block structure, and data encapsulation in TIA Portal projects. It codifies the rule that global data should be minimized, that the Merker area is a legacy feature, and that FB instances are the preferred storage container for subsystem data.
- PLCOpen Programming Guidelines – a vendor-neutral set of best-practice documents covering general structure and an OOP-specific edition. The OOP edition is heavily influenced by the IEC 61131-3 Third Edition methods, properties, and actions, which the S7-1500 implements natively in TIA Portal V16 and later.
The Siemens style guide is the right starting point because it is engineered specifically for the S7-1200/1500 toolchain, but the PLCOpen documents are useful when the project is also deployed on third-party controllers (Codesys, Beckhoff, B&R) and a single design language is required.
10. Decision Matrix: Which Storage to Use
The flowchart below summarizes the recommended choice for a new variable.
- Is the value produced or consumed by a physical I/O point? → Use the process image (%I / %Q). No code change required to move it from global DB to PI; the CPU loads it every scan.
- Is the value needed by a single FB only, and does it need to persist between calls? → Declare it STAT in that FB. It will live in the instance DB.
- Is the value needed by more than one FB or by an HMI? → Declare it in a global DB. Mark the DB optimized unless absolute addressing from a third-party tool is required.
- Is the value purely a scratch or intermediate result? → Declare it TEMP in the consuming block.
- Is the value a quick debug observation, a system clock byte, or a hand-off scratch during commissioning? → Merker / M-bit is acceptable as a temporary measure. Replace with a properly-typed STAT or global DB tag before code freeze.
11. Practical Anti-Patterns to Avoid
Field experience with TIA Portal V15 through V19 projects has shown a small set of recurring mistakes around variable storage. Each of these will surface as a maintenance problem long before it surfaces as a memory problem.
- Merker-based "global variables" in the 0–1000 range, with no symbol table entries. The cross-reference shows "M0.0" used in 14 blocks, with no documented meaning.
- Single huge global DB containing motor data, valve data, recipe data, and HMI hand-shake bits in one namespace, with no grouping. The DB cannot be split without breaking every reference.
- TEMP used as if it were STAT – the code reads correctly on the first scan after a download but loses values on warm restart because the L-stack is repopulated with zeros.
- Classic DBs imported from S7-300 projects with no re-evaluation of the optimized-block attribute. On S7-1500 the access-time penalty is real and unnecessary.
- Non-optimized multi-instance FBs. The S7-1500 multi-instance mechanism requires optimized blocks; reverting to classic silently disables the multi-instance storage and forces a separate instance DB per call.
12. Verification Checklist After a Storage Refactor
Once the variable storage is reorganized, run the following checks before declaring the refactor done.
- Compile the project; resolve every compiler warning – TIA Portal flags inconsistent block attributes and unreachable STAT declarations.
- Download to the target CPU and go online.
- Open the Memory view in Online & Diagnostics. Confirm that load, work, and retentive memory are all within the CPU's published limits with at least 20% headroom.
- Open the Cycle time view. Compare the OB1 minimum, current, and maximum before and after the refactor. A large regression usually indicates that an unintended fully-qualified DB access was introduced.
- Open the Cross-reference view and confirm that no production tag is referenced exclusively by its raw address (e.g.
DB100.DBX4.0). All production references should be symbolic. - Cycle power to the CPU and confirm that all values flagged retentive come back with their last value, and that all values flagged non-retentive reset to their initial value.
The combination of these checks is sufficient to verify that the storage refactor is functionally equivalent to the previous program and that the performance and memory characteristics are within the design envelope.
Should I use Merker (M) memory or a global DB for cross-block data on S7-1500?
Use a global DB with the Optimized block access attribute. On S7-1500 a fully-qualified optimized DB-bit access executes in roughly half the time of an equivalent M-bit access, the data work-memory footprint is smaller because booleans are packed, and symbolic cross-referencing is preserved through the symbol table. Reserve M-memory for system clock bytes and temporary debug tags only.
Will scan time change if I move a variable from a global DB into an FB as STAT?
On S7-1200/1500 the difference is negligible for typical program sizes – both compile to similar instructions because the optimized-block access is symbolic. The dominant factor in scan time is I/O and process-image updates, not the choice of storage. On S7-300 the difference is measurable: a fully-qualified DB access is slower than an M-bit access.
When is TEMP the wrong choice for a local variable?
TEMP is wrong whenever the value must persist between scans – for example, a latched fault, a running total, a configured setpoint, or a state in a sequential function chart. The local data stack is repopulated with zeros on each block entry, so the value is lost. Declare these as STAT so they live in the FB's instance DB and can be flagged retentive.
How do I check memory usage of an offline project in TIA Portal?
Compile the project, then open the project properties to view the compiled block sizes, or use the cross-reference to total the data-work memory required by each DB. For a live measurement, connect to the online CPU and use the Memory view under Online & Diagnostics > Diagnostics > Memory as described in the S7-1200 online-tools documentation.
What happens if FB nesting overflows the local data stack?
The CPU stops with a diagnostic-buffer entry "Local data stack overflow" and the SF LED is lit. Remediation is to raise the local-data size in the OB1 properties (each priority class has a configurable budget) or to reduce the nesting depth by flattening the FB hierarchy or moving large TEMP variables into STAT.