Siemens S7 Multiple Memory Bit Assignment: Behavior and Risks

David Krause13 min read
HMI ProgrammingSiemensTechnical Reference
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 of Multiple Memory Bit Assignment in S7

In Siemens S7 Statement List (STL) programming, a single memory bit (for example, M 200.7) can be assigned a value more than once within the same logic block. Each assignment is a separate statement that the CPU executes from the first network to the last, in strict top-to-bottom order. The classic question this raises is: when two networks write the same memory bit, which network wins? The deterministic answer, confirmed by every S7 CPU that executes STL, is that the last assignment in scan sequence wins. The first assignment is effectively overwritten unless another part of the program reads the bit between the two networks.

This behavior is not a bug. It is a direct consequence of the S7 execution model: the CPU processes a block network by network, and within each network statement by statement. The memory area is not protected by a process-image write-back step inside a single scan, so any in-scan store operation is immediately visible to subsequent instructions. This is in contrast to an output (Q) that sits in the process image output table (PIIQ/PAA) and is only written to the physical terminal at the end of OB1.

Key concept: Memory bits (M) live in the system memory of the CPU and are updated instantly on every = assignment. Outputs (Q) live in the process image and only reach the physical module at PAA-flush time. The distinction is the reason multiple Q assignments behave differently from multiple M assignments, as detailed below.

Statement-by-Statement Execution Model

Every S7 CPU runs the user program cyclically. The main scan is driven by OB1, which is an interrupt-driven organization block in its own right, scheduled by the operating system. Inside OB1, or any other OB, FC, or FB, the CPU walks through the STL code:

  1. Fetch the next statement.
  2. Decode the operation and operand.
  3. Update the RLO (Result of Logic Operation, the German original term is VKE - Verknüpfungsergebnis).
  4. Execute the operation - read, write, jump, accumulate, or transfer.
  5. Advance the instruction pointer to the next statement.

The RLO is a 1-bit accumulator that holds the result of the most recent boolean operation. An assignment operator such as = copies the current RLO into the target operand without changing the RLO. This is why two consecutive networks can each formulate their own RLO and write it to the same memory bit without interfering with each other - the RLO is local to the current network's logic chain.

Operation Effect on RLO Effect on Target
A M 25.0 AND-combines bit into RLO None
= M 200.7 RLO unchanged RLO written to M 200.7
S M 200.7 RLO unchanged Sets M 200.7 if RLO=1
R M 200.7 RLO unchanged Resets M 200.7 if RLO=1

Why the Last Network Wins

Consider the textbook example from the field report:

NW1
A M 25.0
= M 200.7

NW2
A M 25.1
= M 200.7

When the CPU reaches NW1, it evaluates A M 25.0 which ANDs the state of M 25.0 into the RLO, then writes the RLO into M 200.7. The CPU moves to NW2, evaluates A M 25.1, and writes that new RLO into M 200.7 - overwriting whatever NW1 wrote. The first network is not useless, however: if M 200.7 is read by another instruction between NW1 and NW2, the value from NW1 is visible. In a typical two-network program with no intermediate reads, the result of NW1 is dead.

Trace the two cases:

M 25.0 M 25.1 M 200.7 after NW1 M 200.7 after NW2
0 0 0 0
0 1 0 1
1 0 1 0
1 1 1 1

The final state of M 200.7 is simply the state of M 25.1, because NW2 is processed last and its = is the last write.

Memory Bits Versus the Process Image

The reason multiple M writes work is that memory bits have no process-image barrier inside a single OB cycle. The same is not true for outputs assigned via the process image.

Operand area Live storage Update timing Multiple assignment outcome
M - Merker / memory System memory, instant Each = writes immediately Last write wins within same scan
Q - output (PAA) Process image output table Only PAA flush at end of OB1 sends to module All = see the PAA, the physical pin reflects the last write
PIB/PQB - direct I/O Physical module, instant Each = writes immediately to terminal Last write wins, visible on physical pin
I - input (PII) Process image input table Only PII refresh at OB1 start reads modules Cannot assign; reads always see PII snapshot
L - local / temp Stack frame, instant Each statement writes the L stack Last write wins, scope limited to block
DBW/DBX - data block System memory, instant Each = writes immediately Last write wins within same scan
Critical distinction: The source contributors noted that an output (Q) shows the last-network-wins behavior because the process image output is itself a memory cell in the CPU. The physical terminal only reflects the image at the end of OB1, but the in-scan image follows the same last-write rule as M. The difference is that M is a free working area, while Q is reserved for the physical output module.

The S5 Scratch Pad Heritage: MW200 to MW254

Before the S7 family, S5 CPUs followed a similar cyclic model. S5 programmers commonly reserved the high Merker word area - typically MW 200 through MW 254 - as a scratch pad or "dummy memory" for intermediate boolean and integer values. The S5 memory bit count was limited, so reuse was a necessity, not a choice. The practice carried over into early S7 projects and remains in legacy code translated from S5.

A typical scratch-pad pattern from the discussion:

NW1
A I 1.1
= M 200.0
A I 4.5
= M 200.1

NW2
A I 2.1
= M 200.0      <-- Reused as scratch
A I 8.5
= M 200.1      <-- Reused as scratch
C DB 10
L MW 200
T DBW 10

NW3
A ...
= M 200.0
A ...
= M 200.1
C DB 10
L MW 200      <-- Read scratch into a different DBW
T DBW 11

This pattern packs two bits per byte, accumulates them into MW 200, and transfers the word into a data block. It is dense, fast, and very hard to read. Modern S7 programmers rarely see it because the data-block count and instance-DB size have grown large enough that named symbolic tags are preferred.

Risks with Interrupt-Driven OBs

The S7 operating system schedules OB1 as one priority level among many. Time-of-day, cyclic, hardware, and error OBs all run at higher or lower priorities. If a higher-priority OB is triggered while OB1 is in the middle of its scratch-pad reuse, that OB will see the partially-written M area. When control returns to OB1, OB1's subsequent statements will also see whatever the interrupting OB wrote.

Concrete failure modes:

  1. Bit flip during interrupt. OB1 has just written M 200.0 in NW2. A cyclic OB35 fires and overwrites M 200.0 with its own value. OB1 resumes, its NW3 reads M 200.0 expecting its own logic, but the value is now from OB35.
  2. Edge detection corruption. If a positive-edge (FP) flag such as M 200.1 is reused as scratch, the edge bit may already be 1 from OB1's earlier use. The OB35 may falsely trigger an "edge" that did not occur.
  3. Indirect addressing chaos. An M word used as a loop counter or pointer can be stepped by OB1, stepped again by OB35, and the loop will terminate at the wrong iteration count.
Rule: If the program is entirely contained in OB1, the scratch-pad reuse is safe because no other code runs mid-scan. If the program uses cyclic OBs (OB30-OB38), time-of-day OBs (OB10-OB17), hardware interrupt OBs (OB40-OB47), or any other priority class, the scratch-pad reuse becomes unsafe. The source contributors explicitly flagged this caveat.

Best Practices in S7 and PCS7

The PCS7 process-control system formalizes an object-oriented programming style. Data is owned by data blocks or instance DBs and accessed by symbolic name. Bit memory is reserved for narrowly-defined control flags: machine ready, auto mode, edge flags, handshake bits. It is not used as a general scratch pad.

Practice S5 legacy S7 / PCS7 modern
Free working storage MW 200 - MW 254 scratch Local L stack or temp TEMP in FB
Handshake / ready flags Free Merker bits Static STAT in FB instance DB
Edge flags Free Merker bits Static STAT in FB instance DB
Counter scratch Free Merker words Local L words in FC or temp TEMP in FB
Cross-block data exchange Merker + global DBs Named instance DBs and DBs of type
Interrupt OB isolation Rare, OBs were thin Mandatory: OBs exchange data via DBs, not Merker scratch

Recommended refactor for the scratch-pad example above:

FUNCTION_BLOCK FB_Scratch
VAR
  BitA : BOOL; END_VAR
  BitB : BOOL; END_VAR
END_VAR
BEGIN
  BitA := I1.1;       // NW1 logic
  BitB := I4.5;
  // ...
  BitA := I2.1;       // NW2 logic - same symbols, FB stack isolates them
  BitB := I8.5;
  DB10.Word := pack_bits(BitA, BitB);
END_FUNCTION_BLOCK

Because the FB has its own instance DB, two calls of FB_Scratch do not share BitA or BitB. The temp variables are isolated to the call frame. This is structurally what scratch-pad reuse was trying to achieve, but with type safety and OB-isolation guaranteed by the compiler.

Practical Code Examples and Anti-Patterns

Anti-pattern from the source - multiple assignment without an intervening read:

NW1
A M 25.0
= M 200.7
NW2
A M 25.1
= M 200.7

This compiles and runs, but NW1 is wasted code. A static analyzer or code review should flag it. The intended behavior is almost always "M 200.7 is set if either M 25.0 OR M 25.1", which is more correctly written as:

O M 25.0
O M 25.1
= M 200.7

Legitimate pattern - multiple assignment with an intervening read:

NW1
A I 0.0
= M 100.0
NW2
A M 100.0
A I 0.1
S M 50.0
NW3
A I 0.2
= M 100.0          // Reuses M 100.0 as scratch
NW4
A M 100.0
A I 0.3
S M 50.1

Here M 100.0 is a temporary holder for the input combination in NW1-NW2 and again in NW3-NW4. The two reads of M 100.0 in NW2 and NW4 see the values written by their preceding networks. The pattern is valid only if no higher-priority OB interferes.

Legitimate pattern - bit packing with set/reset interlocks:

NW1
A I 2.2
S M 200.0           // Latch on I2.2
NW2
A I 7.3
R M 200.0           // Reset on I7.3
NW3
A M 200.0
A ...
S M 88.0

Here S and R are dominant, so multiple assignments are intentional: the latch-reset pair is the natural pattern. This is the recommended use of M for state storage.

Verification and Diagnostics

When debugging a multiple-assignment issue, follow this checklist:

  1. Open the cross-reference (Querverweis) in STEP 7. List every access to the bit. If you see multiple W (write) accesses in the same block, the last write is the one that matters at end-of-block.
  2. Add a breakpoint in the STL editor. Set a breakpoint after the first = and inspect the bit with the variable table (VAT). Step to after the second = and inspect again. The change confirms the last-write-wins rule.
  3. Check OB priority configuration. In the CPU properties under Interrupts, list all enabled OBs and their priority. If any OB has a priority above OB1, audit M-bit reuse in OB1.
  4. Watch the cycle time. If a cyclic OB fires near the end of the OB1 cycle, the probability of a race condition rises. Use the diagnostic buffer to confirm OB-call order.
  5. Refactor to a temp variable. Replace the scratch M-bit with a local L variable in an FC, or a TEMP variable in an FB. Re-test.
  6. Use symbolic addressing. A symbolic name tied to a DB or instance forces the compiler to track uses. Accidental reuse is much harder when names are unique per function.
Safety check: If the bit is part of a safety function (F-runtime, fail-safe, or a hardwired E-stop chain), the multiple-assignment pattern is forbidden. Safety bits must be single-source, single-write, and have cross-checked evaluation per IEC 61508 / IEC 61511. Treat this pattern as non-safety by definition.

Standards and Documentation References

The S7 execution model and the semantics of the RLO are described in the Siemens S7-300 / S7-400 STL programming manuals. The process image (PII/PAA) update is documented in the S7-300 and S7-400 system manuals. Refer to the official Siemens Industry Online Support portal for the current edition of each manual when verifying behavior on a specific CPU family.

The bit-level semantics of boolean storage in digital systems are a general computer-science concept; the Wikipedia article on the bit provides a useful background read on the unit of information. For broader context on multi-operand memory access patterns in computing, the ScienceDirect topic on memory multiple discusses how wider memory accesses can pack multiple operands into a single bus cycle - the same density principle that drove the S5 MW200 scratch pad.

Note on documentation links: The S7-300/S7-400 programming and system manuals are versioned per firmware. Always confirm the manual edition matches the CPU's firmware level. The STEP 7 version (v5.x for classic, TIA Portal V15-V18 for newer projects) determines which manual is authoritative for the STL syntax in use.

Summary of Operational Rules

Condition Effect of multiple assignment Recommended action
OB1-only program Last write in scan order is final Avoid the pattern; use boolean OR if intent is OR-logic
OB1 plus cyclic OBs (OB30-OB38) Race possible; OB may overwrite OB1 mid-scan Refactor scratch to local L or instance STAT
OB1 plus hardware interrupts (OB40-OB47) Race possible and rare, but very hard to reproduce Refactor; if impossible, document and add runtime checks
Output (Q) via process image Last write in PAA, physical pin updates at PAA flush Single assignment per output per scan is the convention
Direct I/O (PQB) Last write hits the physical pin immediately Avoid; prefer PAA for diagnostic-friendly output
Safety function (F-CPU) Forbidden pattern Use single source, single sink, cross-checked logic

What happens when the same M-bit is assigned in two networks of OB1?

The S7 CPU processes OB1 from top to bottom, statement by statement. The second = instruction overwrites the first, so the final value of the bit at end-of-OB1 is the RLO of the second network. The first network's assignment is effectively dead code unless another instruction reads the bit between the two networks.

Why does this work for M-bits but is discouraged for outputs?

M-bits and process-image outputs (Q) both behave "last-write-wins" inside a single scan because both are stored in CPU memory. The difference is that Q is reserved for physical outputs and triggers PAA flush to the module. Convention requires one logical owner of each output. M-bits are general working storage, and reuse is technically allowed but reduces readability.

Is the multiple-assignment pattern safe in programs with cyclic interrupt OBs?

No. If a higher-priority OB fires mid-scan and also writes the same M-bit, OB1 will resume and may see the OB's value. The result is non-deterministic. The source contributors flagged this explicitly. Refactor the scratch storage to a local L variable in an FC, a TEMP in an FB, or an instance-DB static variable to isolate it from OB-level interference.

What is the S5 scratch pad MW200 to MW254 tradition?

S5 CPUs had limited flag memory, and S5 programmers reserved MW 200 through MW 254 as a scratch area for boolean packing and intermediate integer results. The pattern survived in early S7 code, especially in programs translated from S5 sources. Modern S7 and PCS7 practice replaces this with named instance-DB variables, eliminating the manual reuse pattern.

Can the same pattern be used with inputs (I) or with direct peripheral access (PIB/PQB)?

Inputs (I) cannot be assigned with = - they are read-only via the process image. Direct peripheral outputs (PQB) accept assignment, and like M-bits the last write hits the physical pin immediately. However, PQB bypasses the diagnostic layer that Q provides, so use it only when the application explicitly requires it (for example, fast outputs to a digital sub-module that the PAA cycle is too slow for).

Back to blog