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:
| 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.
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.
| 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:
| 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 |
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:
-
No byte aliasing. A DB tag called
CounterPresetlives 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. -
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.
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
- In the project tree on the left side of TIA Portal, expand the S7-1200 CPU branch.
- Open Program Blocks.
- Double-click Add new block (or right-click and choose Add new block).
- In the dialog, pick the type Data Block.
- Choose a name such as
RecipeorCounterData. - Confirm. TIA Portal inserts the new DB into the program's Program Blocks folder.
Step 2 — Declare the variables
- Double-click the new DB to open its editor.
- For each variable, fill in:
-
Name — symbolic identifier (for example
CountPreset,ActualCount,FaultWord). -
Data type —
Bool,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.
-
Name — symbolic identifier (for example
- 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:
| 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
- Right-click the PLC in the project tree and choose Compile → Software (rebuild all).
- Connect online, then download the program blocks including the new DB to the CPU.
- 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:
| 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 |
Configuring the retentive area in TIA Portal
- Open Device Configuration for the CPU.
- Select the CPU and open Properties → System and Clock Memory.
- 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).
- 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:
| 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)
- Create a Global DB named
Recipewith these tags:
| Name | Type | Retain |
|---|---|---|
CountPreset |
INT | Retain |
CountActual |
INT | Retain |
Run |
BOOL | Non-retain |
CycleDone |
BOOL | Non-retain |
- Replace every reference to
MW1with"Recipe".CountPreset. - Replace every reference to
M3.0with"Recipe".Run. - Replace every reference to
M3.5with"Recipe".CycleDone. - 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 :x: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.IW
Verification Steps After Migration
- Compile the program. TIA Portal reports syntax errors and unresolved symbols.
- Open the cross-reference (Ctrl+Shift+F) and confirm that no symbol refers to the deleted MW1 address.
- Download the project to the CPU.
- Go online and open the DB Recipe in Monitor / Modify.
- Force
"Recipe".Runhigh and decrement the counter preset across a power cycle to confirm the Retain column behaves as designed. - Watch the tag list live for 5–10 minutes of normal operation — verify that
CountActualtracks the expected sequence and thatCycleDonetoggles exactly once per cycle.
Troubleshooting Matrix
| 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.