Resolving S7-1200 MW1 Memory Conflicts Using Data Blocks

David Krause12 min read
S7-1200SiemensTutorial / How-to
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

Resolving S7-1200 MW1 Memory Conflicts Using Data Blocks

Overview: The MW1 Symptom and the Real Issue

When a SIMATIC S7-1200 program reads "weird" values from MW1, the cause is almost never the CPU, the firmware, or the wiring. The cause is byte-level address overlap in the M (bit-memory) area. A programmer assigns MW1 as a 16-bit counter preset, simultaneously uses M1.0 through M2.7 as discrete flags, and reads MD4 as a long value somewhere else. The ladder code looks correct in isolation, but the underlying bytes are shared. The classic instruction list resolves nothing; migrating the non-bit variables into a Global Data Block (DB) does.

This guide explains exactly why MW1 clashes with surrounding bits, when the symptom points to memory overlap versus a wiring fault, and how to construct a Global DB in TIA Portal with proper retentive settings so the application is reliable across power cycles.

SIMATIC S7-1200 Memory Architecture

The S7-1200 CPU exposes several memory areas to the user program. Each area has a defined size, lifetime, and access semantics documented in the S7-1200 Programmable Controller System Manual:

Primary user memory areas in the S7-1200 CPU
Area Identifier Width Granularity Purpose
Process image input I / II Bit, Byte, Word, DWord State of physical inputs at the start of the OB1 cycle
Process image output Q Bit, Byte, Word, DWord State written to physical outputs at the end of OB1
Bit memory M Bit, Byte, Word, DWord Intermediate flags, scratch-pad variables
Data block DB Any elementary / user type Named, structured, optionally retentive variables
Temporary local data L Bit, Byte, Word, DWord Stack storage inside an OB / FB / FC

For the S7-1200 family, the M area is a single, contiguous byte array. There is no automatic separation between bits, bytes, words, and double words. Whatever you write to MW1 also writes to MB1 and MB2; likewise, a write to MD0 overwrites four bytes beginning at MB0. This is by design — the S7-1200 follows the same flat-memory convention as the S7-300/400 — but it becomes a trap the moment a programmer treats bit and word addresses as independent.

Key principle: M-memory is byte-addressed; a "Word" or "DWord" simply consumes 2 or 4 consecutive bytes. There is no protection, no warning, and no compiler error when two symbols alias the same byte.

Address Overlap Mechanics: How MW1 Quietly Erases Other Variables

The Siemens mnemonic rules are summarized below. Note that word addresses end on even byte offsets only when you place them deliberately; the compiler does not enforce this.

Address-width mapping in the S7-1200 M area
Mnemonic Bit Width Byte Footprint Addresses Touched
MX.y 1 bit 1 byte (1 bit) 1 address
MBx 8 bits 1 byte 1 address
MWx 16 bits 2 bytes 2 consecutive
MDx 32 bits 4 bytes 4 consecutive

Working examples using the M area as the surface:

Concrete overlap scenarios in the M area
Symbol A Occupies Bytes Implicitly Affected Hazard
MW0 MB0, MB1 MB0, MB1, any M0.x/M1.x Writing MW0 overwrites all eight bits of MB0 and MB1
MW1 MB1, MB2 MB1, MB2, M1.0-M1.7, M2.0-M2.7 Highest-risk: many beginners use M1.x and M2.x flags while a counter sits in MW1
MD4 MB4–MB7 MW4, MW6, all of MB4–MB7 bits One move to a DWord silently clears a flag word
MB10 + MW10 MB10, MB10–MB11 Each other Same prefix - guaranteed conflict
Engineering insight: Because MW1 occupies MB1 and MB2, every flag symbol assigned to M1.0–M1.7 or M2.0–M2.7 is, by definition, an alias of MW1. Reading a bit, writing a bit, or transferring a word to any of those addresses will all see each other's data. The "weird values" reported in this kind of bug are simply the bit pattern of the last value loaded into the conflicting word, mixed with whatever the bit logic just set.

Why Data Blocks Replace M Memory for Structured Variables

Data blocks give every variable a named, typed symbol. The compiler assigns a unique byte offset and enforces non-overlap because each tag is laid out at compile time. The two principal advantages for the MW1 symptom are:

  1. No byte aliasing. A DB tag called CounterPreset lives at a single address; no other tag shares its bytes unless declared as a multi-element array, in which case that array is documented in one place.
  2. Symbolic access. The user program refers to the variable by name (for example, "Recipe".CountPreset) rather than by raw address. Reordering or renaming the structure does not change the call site; only the block declaration does.

The trade-off is migration effort, but it is one-time. Once you have a Global DB in TIA Portal, the rest of the program reads more cleanly and any future technician can scan the block once to understand all program-level variables.

Prerequisites

Before creating a DB, confirm the following are in place:

  • A SIMATIC S7-1200 CPU (1211C, 1212C, 1214C, 1215C, or 1217C) online or available offline in TIA Portal V16 / V17 / V18 / V19.
  • A project with at least one program block already in the CPU's Program Blocks folder.
  • Write access to the project — DB creation must be done in the offline project and then compiled/downloaded to the CPU.
  • Knowledge of which variables are currently occupying the MW1/MW2/MW3 region. A quick way to enumerate them is to open the cross-reference (Ctrl+Shift+F) and filter on the address substring "MW1" or "M1.".
  • The S7-1200 CPU Memory Management section of the system manual open for reference on retentive ranges.
Firmware note: Steps below are valid for TIA Portal V16 and later. Earlier versions use STEP 7 Basic V13/V14 with slightly different menu paths; the underlying DB semantics are identical.

Step-by-Step: Creating a Global Data Block in TIA Portal

The following procedure produces a Global DB named, for example, Recipe, with a retentive counter preset tag.

Step 1 — Add the DB to the project

  1. In the project tree on the left side of TIA Portal, expand the S7-1200 CPU branch.
  2. Open Program Blocks.
  3. Double-click Add new block (or right-click and choose Add new block).
  4. In the dialog, pick the type Data Block.
  5. Choose a name such as Recipe or CounterData.
  6. Confirm. TIA Portal inserts the new DB into the program's Program Blocks folder.

Step 2 — Declare the variables

  1. Double-click the new DB to open its editor.
  2. For each variable, fill in:
    • Name — symbolic identifier (for example CountPreset, ActualCount, FaultWord).
    • Data typeBool, Int, DInt, Real, Word, DWord, array, struct, etc.
    • Retain — set to Retain if the value must survive a power cycle; leave as Non-retain for transient flags.
  3. Save and compile the project.

Step 3 — Confirm the DB number

TIA Portal assigns a DB number automatically (DB1, DB2, …). You can use that number with the legacy absolute syntax, or use the symbolic name. Both forms appear below:

DB access forms in the S7-1200
Form Ladder Example ST Example
Absolute (DB number + byte offset) MOVE "Recipe".CountPreset → MW200; DB1.DBD0 := 100;
Fully symbolic "Recipe".CountPreset := 100; "Recipe".CountPreset := 100;
Mixed (DB num + symbol) DB1.CountPreset DB1.CountPreset := 100;

Step 4 — Compile and download

  1. Right-click the PLC in the project tree and choose Compile → Software (rebuild all).
  2. Connect online, then download the program blocks including the new DB to the CPU.
  3. Open the DB online in watch mode to verify the declared layout.

Configuring Retentive Behavior

S7-1200 CPUs retain selected M, DB, timer, and counter values across a power loss using a dedicated retentive area. From the SiePortal support thread on S7-1200 storage, the CPU 1215C ships with 10 KB of retentive memory (see SiePortal — Storage data in PLC S7-1200). Sizing for other CPUs in the family is similar:

Indicative retentive memory by S7-1200 CPU family
CPU Approx. Work Memory Approx. Retentive Area Notes
CPU 1211C 50 KB 10 KB (typ.) Compact starter; 14 digital / 6 analog I/O onboard
CPU 1212C 75 KB 10 KB (typ.) 8 DI/DO + 4 AI onboard, expandable
CPU 1214C 100 KB 10 KB (typ.) Midrange; widely deployed
CPU 1215C 125 KB 10 KB Confirmed via SiePortal reference
CPU 1217C 150 KB 14 KB (typical high end) Highest-density S7-1200
Verify on the datasheet: Always confirm the retentive value against the specific CPU's Technical Data sheet — firmware revisions occasionally raise the available retentive area. The figures above are general indications and should not be quoted as guarantees.

Configuring the retentive area in TIA Portal

  1. Open Device Configuration for the CPU.
  2. Select the CPU and open Properties → System and Clock Memory.
  3. Under Retentive Memory, declare:
    • Number of retentive MB bytes (default = 0; raise as needed for flags).
    • Number of retentive timer bytes (default = 0).
    • Number of retentive counter bytes (default = 0).
    • Optional: specify starting address ranges for individual areas (for example MB0 .. MB15).
  4. Click OK and recompile.

To make a specific DB tag retentive, open the DB and toggle the Retain column for the relevant rows. Only tags explicitly marked retain will survive a power-off cycle even if their bytes fall inside the declared retentive memory range.

Symbolic vs Absolute Addressing in S7-1200

The original technicians in this kind of case often use absolute addressing such as DB1.DBD0 because HMI tag imports map cleanly to that form. Symbolic addressing — "Recipe".CountPreset — is more readable and survives block renaming, but it requires a Symbol Table or a fully qualified symbolic path. Use both as appropriate:

Choosing between symbolic and absolute DB access
Use Case Recommended Form Reason
Reading values into WinCC / HMI on basic panels Absolute (DB number + offset) Direct import of PLC tag list to the HMI configuration
Logic inside FC / FB Fully symbolic Refactoring safety; cross-reference updates on rename
Multi-instance data Multi-instance DB symbol Avoids DB sprawl; idiomatic to OOP-style FB use
Diagnostic routines Either Match the project's prevailing convention for consistency

Migrating the MW1 Counter from M Memory to a DB Tag

A worked example of replacing the symptom:

Before (problematic)

  • MW1 — counter preset, INT
  • M3.0 — "Run" bit, BOOL
  • M3.5 — "Cycle Done" bit, BOOL
  • Many other flags scattered across MB0..MB15, all written by various FCs

Whenever the cycle-end logic touched M3.0, the Word move that updated MW1 simultaneously clobbered bits inside MB1 and MB2, producing phantom transitions.

After (idiomatic)

  1. Create a Global DB named Recipe with these tags:
Name Type Retain
CountPreset INT Retain
CountActual INT Retain
Run BOOL Non-retain
CycleDone BOOL Non-retain
  1. Replace every reference to MW1 with "Recipe".CountPreset.
  2. Replace every reference to M3.0 with "Recipe".Run.
  3. Replace every reference to M3.5 with "Recipe".CycleDone.
  4. Recompile and download to the CPU.

ST snippet showing the migrated logic

// Migrated logic - DB variables are guaranteed non-overlapping
IF "Recipe".Run THEN
    "Recipe".CountActual := "Recipe".CountActual + 1;
    IF "Recipe".CountActual >= "Recipe".CountPreset THEN
        "Recipe".CycleDone := TRUE;
        "Recipe".CountActual := 0;
    END_IF;
END_IF;

Process Image vs Bit Memory — Don't Use Both for the Same Purpose

A separate but related pitfall is treating the Process Image Input area (IBx, IWx) the same way as M memory. The process image is a snapshot taken once per OB1 cycle; outside of the image window, I/O reads must use :IWx:P (immediate read). M memory, in contrast, can be read or written at any time with consistent values. Mixing the two will produce the same kinds of "weird" symptoms if a Word move targets an I-address while a bit elsewhere expects an I-bit. Always keep digital I/O and scratch flags in distinct areas — I/Q for the field wiring and M / DB for internal variables.

Verification Steps After Migration

  1. Compile the program. TIA Portal reports syntax errors and unresolved symbols.
  2. Open the cross-reference (Ctrl+Shift+F) and confirm that no symbol refers to the deleted MW1 address.
  3. Download the project to the CPU.
  4. Go online and open the DB Recipe in Monitor / Modify.
  5. Force "Recipe".Run high and decrement the counter preset across a power cycle to confirm the Retain column behaves as designed.
  6. Watch the tag list live for 5–10 minutes of normal operation — verify that CountActual tracks the expected sequence and that CycleDone toggles exactly once per cycle.

Troubleshooting Matrix

Symptom → Likely cause → corrective action
Symptom Likely Cause Corrective Action
Counter reads "weird" intermediate values Byte-word overlap (e.g. MW1 vs M1.x or M2.x) Migrate word/dword variables into a Global DB
Bit randomly clears on its own Bit sits inside an MW or MD that is being moved elsewhere Move that bit into a dedicated DB BOOL or a free M bit outside the word/dword range
Variables reset to zero after power-off Retain flag not set on the tag, or retentive memory range not declared Toggle the tag's Retain column; expand the Retentive Memory limits in the CPU properties
DB tag cannot be forced online Variable is in a write-protected optimized block or an instance DB Switch to non-optimized block access or use the program logic instead of online force
HMI can't see new DB tags HMI tag import not refreshed Re-export the PLC tag list from the DB and re-import on the HMI side
Download fails with "DB not consistent" DB contains a value (typed in Monitor/Modify) that conflicts with the declared structure Clear or reset the DB via online menu; then download
Two FBs appear to share the same data Both FBs were assigned to the same instance DB number manually Let TIA Portal auto-assign distinct DB numbers per multi-instance

Frequently Asked Questions

Why does MW1 conflict with M3.0 if they have different addresses?

MW1 occupies the byte range MB1–MB2, not MB3, so MW1 and M3.x do not directly share bytes. However, the broader lesson is that any M-bit used alongside the same word will create a hidden alias. If MW1, MW2, MW3, and a dozen M1.x, M2.x, M3.x flags are mixed, the natural way to keep them clean is to move the word/dword variable into a Global Data Block tag, where the compiler enforces unique placement.

Do I lose any performance by using a DB instead of MW1?

No. On the S7-1200, symbolic DB access compiles to the same machine instructions as direct M-memory access. Both are byte-aligned loads and stores. The only overhead is at compile time, where the symbolic name is resolved to an offset; this happens once when the project is built, not during cyclic execution.

How much retentive memory does my S7-1200 CPU have?

The CPU 1215C is documented at 10 KB of retentive memory. Other S7-1200 CPUs in the same family (1211C, 1212C, 1214C, 1217C) have similar capacities — see the CPU-specific datasheet inside TIA Portal under Properties → General → Technical Data. Configure the value in Properties → System and Clock Memory → Retentive Memory.

Can I make only part of a DB retentive?

Yes. Each tag declaration has a Retain column. Toggle it to Retain for the tags that must survive a power-off cycle, and leave it as Non-retain for transient flags. The retentive memory area is a physical buffer inside the CPU and the S7-1200 firmware only persists the bytes belonging to retain-marked tags.

Should I keep using bit memory for temporary flags at all?

Temporary flags inside a single FC can use the local stack (L area) by declaring variables with the TEMP attribute — they consume zero M memory. For inter-function flags, a Global DB is preferable because it gives every variable a name, a type, and a documented footprint. Reserve the M area for low-level modular scratch space if your company standard still requires it.

Back to blog