Siemens S7-300/400 TEMP Variable Not Updating Between LAD Networks in FBs
Symptom: a TEMP variable written in Network 1 of a Function Block (FB) is read as 0 in Network 2 of the same FB even though no other network overwrites it. The same logic works when the variable is declared as STAT, when the FB is split into two FBs, or when the network is split into two networks. The CPU correctly executes Block 1, then Block 2; the issue is intra-block scope, not the OB scan order.
1. Problem Description
A typical failing FB looks like the following. Both networks live inside the same FB, the TEMP variable is declared only once in the FB's TEMP area, and no other code writes to it:
FUNCTION_BLOCK FB100
VAR_TEMP
bSignal : BOOL; // written in Net 1, read in Net 2
bAux : BOOL;
END_VAR
BEGIN
NETWORK 1 // Title: derive bSignal
U E 0.0;
= bSignal; // expected: TRUE when input is TRUE
NETWORK 2 // Title: forward bSignal
U bSignal;
= A 4.0; // output stays FALSE even when bSignal is TRUE
END_FUNCTION_BLOCK
The same engineer observes:
- Output
A 4.0does not change even thoughE 0.0is TRUE. - Adding a normally-open contact of
bSignalafter the output coil shows the contact state matches the output, not the input. - Changing
bVARfrom TEMP to STAT (in the static area) makes the network work correctly. - Splitting Network 2 into two networks restores correct behavior, even with TEMP.
- The instance DB has been regenerated and a "Check block consistency" pass reports no errors.
2. Root Cause: LAD/FBD Compiler Scratchpad Reuse
Siemens documents this behavior in entry FAQ 13988019 - "In STEP 7 why are TEMP variables sometimes overwritten?". The compiler that emits MC7 code from LAD and FBD sources does not reserve a dedicated bit per declared TEMP. Instead, the compiler assigns each formal parameter or named local symbol to a slot in the local stack (the L stack / TEMP area) on a per-network basis, reusing the same slot when the symbol is no longer needed in the current network.
Two facts follow from this allocation strategy:
- The compiler is free to back the variable in Network 1 with a different bit cell than the same variable in Network 2, as long as both networks can be proven self-consistent. The L-stack slot for Network 1 may be reused for an unrelated TEMP in Network 2.
- The optimized MC7 for the second network reads the slot that was just allocated to it - which contains the default value (
0for BOOL) because Network 2 has not yet executed the assignment from Network 1.
3. Affected Products and Versions
| Item | Catalog / Version | Affected? |
|---|---|---|
| STEP 7 V5.x (V5.4, V5.5, V5.6) | 6ES7 810-5CC0x | Yes - LAD/FBD compiler uses scratchpad optimization |
| STEP 7 Professional (TIA Portal) for S7-300/S7-400 | V13 to V18 | Same behavior; only LAD/FBD sources are affected |
| S7-PLCSIM V5.x | 6ES7 841-0CC0x | Reproduces the issue (it executes the same MC7) |
| S7-300 CPU 312, 314, 315, 315F, 317, 319-3 PN/DP | 6ES7 31x-xxxxx | Affected (firmware-independent) |
| S7-400 CPU 412, 414, 416, 417 | 6ES7 41x-xxxxx | Affected |
| S7-1200 / S7-1500 with TIA Portal | All firmware | Different compiler model - symptom not reproduced |
| WinAC RTX / Slot PLC | All | Affected when program is LAD/FBD |
4. Why "Check Block Consistency" Does Not Catch It
Block consistency verifies that:
- The interface declaration of every FB matches the instance DB.
- Multi-instance DBs are regenerated.
- Calls of updated FBs force re-instantiation.
- UDT references are in sync.
It does not validate that a TEMP variable declared in the FB interface is actually propagated between networks, because from a type-checking standpoint the variable exists and is read/written consistently. The compiler-level optimization is invisible to the consistency checker. Running "Check block consistency" on a project that exhibits this symptom will return a green status; this is expected.
5. Workarounds and Solutions
Four engineering options, ranked from recommended to situational.
5.1 Use STAT instead of TEMP (recommended)
Move bSignal from the TEMP area to the STAT area:
FUNCTION_BLOCK FB100
VAR
bSignal : BOOL; // STAT: retained across networks and OB cycles
bAux : BOOL;
END_VAR
BEGIN
NETWORK 1
U E 0.0;
= bSignal;
NETWORK 2
U bSignal;
= A 4.0;
END_FUNCTION_BLOCK
STAT symbols get a fixed backing bit in the instance DB, so the compiler cannot reuse the cell. This is the canonical Siemens recommendation for any value that must survive between networks or between FB calls. Reserve TEMP for true scratch values that are assigned and consumed inside one network.
5.2 Split the network
If the variable must remain TEMP (for example, the FB interface is frozen because it is used by third-party tooling that rejects interface changes), split Network 2 so the read of bSignal happens in a fresh network context:
NETWORK 2
U E 0.0;
= A 4.0;
NETWORK 3
U bSignal; // still TEMP, but in its own network
S M 10.0;
END_FUNCTION_BLOCK
Splitting works because the new network creates a new scratchpad window in the compiler's view; the bit cell that bSignal lived in is still live at the top of the new network. Use this only as a stop-gap; the underlying interface is fragile and any future re-compile can break the timing again.
5.3 Switch the affected network to STL
LAD/FBD networks and STL networks can be mixed inside a single FB. Edit Network 2 as STL and explicitly load and transfer the variable to itself at the top of the network:
NETWORK 2 // STL
L #bSignal; // force a load from the L stack slot
T #bSignal; // and write it back, pinning the slot
U #bSignal;
= A 4.0;
END_FUNCTION_BLOCK
The redundant load/transfer has no functional effect but it forces the compiler to keep the slot reserved for the rest of the network. This is a single-network patch and is the smallest-blast-radius option when only one of many networks is affected.
5.4 Use a bit memory or marker instead
If neither TEMP nor STAT are acceptable, write the value to a global bit memory (M area) or to a designated shared DB:
NETWORK 1
U E 0.0;
= M 100.0; // global bit, always reliable
NETWORK 2
U M 100.0;
= A 4.0;
END_FUNCTION_BLOCK
This is the worst option because M bits are not encapsulated, are not retained on FB re-instantiation, and conflict with the Siemens naming conventions for global memory. Use it only for diagnosis, never as the long-term fix.
6. TEMP vs STAT - When to Use Which
| Attribute | TEMP | STAT |
|---|---|---|
| Backed by | L stack (per call frame) | Instance DB |
| Persists across OB cycles | No - undefined on next call | Yes |
| Persists across networks within one FB call | Compiler-dependent | Yes - guaranteed |
| Multi-instance safe | N/A - each call has its own L stack | Yes |
| Default value behavior | May be reused / zeroed by compiler | Initialized from instance DB defaults |
| Suitable for handshake flags between networks | No | Yes |
| Suitable for one-network scratch | Yes (preferred) | Works, but wastes instance DB memory |
7. Verification Procedure
After applying any of the four workarounds, verify the fix in this order:
- Open the FB in STEP 7 and select Options > Check Block Consistency. The status must be green before testing logic.
- Regenerate the instance DB (right-click > Instance DB > Generate) if you changed any STAT declarations. For multi-instance calls, regenerate the parent FB's instance DB as well.
- Download the FB, the instance DB, and all calling blocks to the CPU. Use PLC > Download, not partial download of the FB only, because the instance DB layout may have changed.
- In VAT or a watch table, monitor the affected variable. Toggle the input
E 0.0on, then observe the outputA 4.0and the variable itself on the next OB1 scan. The output should follow the input on the same cycle. - Force a re-run of the PLC restart (warm restart) to make sure the instance DB initializes STAT variables to the declared defaults, not to random values.
- If a CPU 319-3 PN/DP or CPU 41x is in RUN with breakpoints, use Debug > Monitor with STEP 7 to single-step the FB and confirm the value seen by Network 2 matches the value written by Network 1.
8. Diagnostic Checklist
Use this matrix to map symptoms to root causes. The "Temp not updated between networks" row is the failure mode described in this article; the others are commonly confused with it.
| Symptom | Most likely cause | Confirm with | Fix |
|---|---|---|---|
| TEMP value reads 0 in next network of same FB | LAD/FBD compiler scratchpad reuse (FAQ 13988019) | Switch to STAT or STL - works | Use STAT, split, or STL |
| TEMP value reads 0 in different FB called from same OB | TEMP is per-call frame by definition - never share via TEMP | Inspect VAR_TEMP of both FBs | Use a shared DB or pass as IN_OUT |
| STAT value reads stale after online edit | Instance DB was not regenerated | Check instance DB timestamp vs FB timestamp | Re-download both, then warm restart |
| Output follows input only every other cycle | Two networks competing for the same bit memory or output in different OBs | Cross-reference the output across OBs | Use a single assignment point |
| Variable correct in VAT, wrong in PLC | Compile/run mismatch: blocks compiled but not downloaded | Compare online/offline block timestamps | Download blocks again |
| Variable correct in S7-PLCSIM, wrong on real CPU | Different firmware or different memory layout; or partial download missed an FC call | Cross-reference FC/FB calls | Full download including all referenced blocks |
9. Step 7 V5.x Reference
- Siemens FAQ 13988019 - Why are TEMP variables sometimes overwritten in STEP 7? - the canonical answer for the LAD/FBD compiler behavior.
- STEP 7 V5.x - Block consistency and time stamp conflicts - explains why "Check Block Consistency" passes despite the issue.
- CPU 319-3 PN/DP manual (6ES7318-3EL00-0AB0) - hardware reference for the most commonly reproduced case.
- Programming and Operating Manual STEP 7 V5.6 - VAR_TEMP and VAR scoping rules.
- S7-PLCSIM V5.x - Functional description - confirms PLCSIM executes the same MC7 as the real CPU.
10. Best-Practice Rules for Siemens S7-300/400 FB Design
- Default to STAT. Anything that is set in one network and read in another, or that must survive across calls, belongs in the instance DB.
- Use TEMP only for single-network scratch. Examples: a temporary accumulator name, a temporary loop counter, or a derived BOOL consumed by the very next coil.
- Never share TEMP across FBs. The L stack is per call, so a TEMP in FB1 is invisible to FB2 by design.
- Always pass shared data via IN_OUT or a shared DB. Avoid implicit cross-FB coupling through global M bits.
- Regenerate the instance DB after every interface change. A stale instance DB can hide this symptom behind a different symptom (wrong initial values, wrong field offsets).
- Run "Check Block Consistency" before download. It will not catch scratchpad issues, but it prevents the much more common "interface drift" bug that looks similar.
- For mixed-language FBs, document which networks are STL. Future maintainers who re-compile in LAD lose the manual load/transfer you inserted.
11. Common Mistakes After the Fix
- Changing TEMP to STAT but forgetting to regenerate the instance DB - the symptom persists with a "STATIC NOT FOUND" SF LED on the CPU.
- Splitting the network but re-merging it later for "cleanliness" - the symptom returns.
- Using a marker (M 100.0) as the fix and then forgetting the marker is global - a different FB overwrites it under load conditions.
- Fixing the symptom on the development CPU but not downloading the regenerated instance DB to the production CPU - the production CPU keeps running with the old layout until the next restart.
12. Frequently Asked Questions
Why does my TEMP variable read 0 in the next LAD network of the same FB on S7-300?
The LAD/FBD compiler in STEP 7 V5.x and TIA Portal (for S7-300/400) reuses L-stack slots per network for symbols in the TEMP area. The slot assigned to the variable in Network 1 may not be the same slot read in Network 2, so the second network sees the default value (0 for BOOL). Siemens documents this in FAQ 13988019.
Does the same bug affect S7-1500 or S7-1200 in TIA Portal?
No. The S7-1200/S7-1500 compiler model does not perform the same scratchpad optimization for TEMP, so a TEMP written in one network is reliably read in the next. The behavior is specific to S7-300/S7-400 with the STEP 7 V5.x or TIA Portal LAD/FBD compiler.
My "Check Block Consistency" passes but the symptom is still there - why?
Block consistency only verifies interface-to-instance-DB matching and call graph integrity. It does not perform data-flow analysis across networks, so it cannot detect that a TEMP variable is being read from a different L-stack slot than the one it was written to. A green consistency status is necessary but not sufficient.
Should I convert the FB to STL to make the symptom go away?
Yes, but only for the specific affected networks. STL exposes the L-stack directly, so the same TEMP variable behaves predictably. Keep the rest of the FB in LAD/FBD if your team prefers; mixing is allowed. Document the STL networks so future maintainers do not re-compile them as LAD.
Is this a CPU 319-3 PN/DP firmware bug?
No. The CPU firmware executes the MC7 code that the compiler produced. The compiler's scratchpad optimization is documented Siemens behavior and is independent of firmware version. CPU 319-3 PN/DP (6ES7 318-3EL00-0AB0), CPU 317, CPU 315, and the S7-400 CPUs all exhibit the same behavior on identical source code.