1. Problem Overview
A common failure mode in TIA Portal V16–V18 ladder programs on the S7-1200 family (CPU 1211C, 1212C, 1214C, 1215C, 1217C, and 1500-series equivalents running the same memory model) is an HMI button that is bound to a flag bit (for example %M0.4) that appears dead while its neighbor bit (for example %M0.3) works perfectly. Physical inputs (%I0.2, %I0.3) and the HMI's decrease command (%M0.3) all increment/decrement a counter clamped between 0 and 20, but the increase command mapped to %M0.4 never produces a visible state change. No diagnostic LED, no SF (System Fault), no BF (Bus Fault) — the controller is healthy, the HMI tag polls correctly, and the connection in the HMI device configuration is online. The fault is logical, not electrical.
This article documents the root cause, the exact bytes and bits involved, the diagnostic steps to prove the cause in the engineering environment, and the corrective procedure that prevents recurrence. The fix takes less than two minutes once the cause is understood, and the underlying mistake is one of the most common pitfalls in beginner and intermediate TIA Portal projects.
2. Affected Products, Firmware, and Engineering Versions
| Component | Affected Range / Versions |
|---|---|
| PLC | SIMATIC S7-1200 (all CPU variants, firmware V4.0 through V4.6); S7-1500 (same memory model) |
| Engineering | STEP 7 Basic / Professional in TIA Portal V13 SP1 through V18 (V19 and V20 also affected — behavior is unchanged) |
| HMI | SIMATIC Basic Panels (KTP400, KTP700, KTP900, KTP1200), Comfort Panels, WinCC Runtime Advanced / Professional, third-party panels reading S7-1200 tags via OPC UA or S7 communication |
| Symptom class | One bit of a byte/word overlaps with an MW, MD, MB, or symbolic tag that is being written elsewhere in the program |
%M0.0–%M0.7), byte-level access (%MB0), word-level access (%MW0, 16 bits, big-endian), and double-word access (%MD0, 32 bits). All four views share the same physical byte(s). The PLC does not warn you when two symbols alias the same storage.3. The S7-1200 Memory Addressing Model
Before diagnosing, it is essential to understand how SIMATIC addresses overlap. The S7-1200 stores bit memory in a flat byte array starting at %M0.0. Every higher-level data type starts on a byte boundary that is a multiple of its size:
| Address | Width | Byte Coverage | Bits Covered (M notation) |
|---|---|---|---|
%MB0 |
1 byte (8 bits) | Byte 0 |
%M0.0 … %M0.7
|
%MW0 |
2 bytes (16 bits) | Bytes 0 and 1 |
%M0.0 … %M0.7, %M1.0 … %M1.7
|
%MD0 |
4 bytes (32 bits) | Bytes 0, 1, 2, 3 |
%M0.0 … %M3.7
|
%MW2 |
2 bytes (16 bits) | Bytes 2 and 3 |
%M2.0 … %M3.7
|
The width is irrelevant: a BOOL tag and a WORD tag that map to overlapping memory are the same memory. There is no protection, no error, and no warning from the compiler. The byte ordering used inside %MW0 follows the SIMATIC convention: the lowest-numbered byte (MB0) is the high byte of the word, and the next byte (MB1) is the low byte. For %MD0, the highest-numbered byte (MB3) is the most significant. This is critical when interpreting bit-to-word aliasing, because moving a value of W#16#0008 into %MW0 sets %M1.3 (the low byte's bit 3), not %M0.3.
4. Root Cause Analysis
In the failure case, the program uses both of the following symbols:
-
%M0.3and%M0.4as discrete HMI button flags, each driving one rung of the counter logic. -
%MW0as a symbolic 16-bit register, used either as a counter preset, a clamp mask, or a calculated intermediate value.
Because %MW0 occupies bytes 0 and 1, it covers all eight bits of byte 0, including %M0.3 and %M0.4. Every scan cycle in which the program writes to %MW0, the value placed in that word overwrites whatever the HMI wrote into those two bits earlier in the cycle.
The reason %M0.3 appears to work and %M0.4 appears dead is scan-order dependent and almost always traceable to one of these three patterns:
-
Counter clamp logic writing
%MW0last. The decrease branch (%M0.3) executes, decrements the counter, and writes a word value back to%MW0. The value being written happens to have bit 3 set (e.g., the clamp-mask constantW#16#0008literally leaves%M1.3high — but a previous cycle's counter or status word frequently contains a value with bit 3 still asserted). Meanwhile, the increase branch sets%M0.4high at the HMI poll, but the same%MW0write in the next network overwrites it to zero. -
HMI poll executes before the application logic. On many S7-1200 firmware versions, the HMI image update happens at OB1 priority. If the HMI button sets
%M0.4via the HMI tag write at the start of the cycle and the application logic subsequently writes%MW0 := 0for a reset/clear operation, the bit is cleared before the output image is sent. -
Symbolic aliasing through the project tag table. The tag table shows
"IncreaseButton"as%M0.4 : BOOLand"ClampMask"as%MW0 : WORD. The compiler does not detect that they overlap. TIA Portal will happily display both tags in the watch table with overlapping addresses, and the human eye typically does not notice because the watch table displays each tag on its own row.
The bug is not in the HMI, the panel, the cable, or the input wiring. It is in the program's use of the M area.
5. Diagnostic Procedure
Before changing anything, prove the hypothesis. The following sequence takes under five minutes and uses only stock TIA Portal functionality.
-
Open the PLC tag table (PLC tags > Show all tags). Sort by Address. Look for any entry whose address falls in the range
%M0.0–%M1.7that has a width other thanBOOL(i.e.,BYTE,WORD,DWORD,INT,REAL,WORD,DINT). The presence of%MW0in the same byte as the failing%M0.4confirms overlap. -
Open a watch table and force-refresh the following rows simultaneously:
Toggle the HMI increase button. Observe%M0.3 BOOL (decrease button) %M0.4 BOOL (increase button - the suspected dead bit) %MW0 WORD (the overlapping word) %MB0 BYTE (lowest byte of the word, shown for cross-check) %MB1 BYTE (high byte of the word)%M0.4momentarily goes to1, then is cleared within the same cycle. Observe%MW0change at the same instant. -
Cross-check via the cross-reference (right-click the symbol in the program editor → Go to > Cross-reference, or press Ctrl+Shift+F3). Every network that writes
%MW0must be examined. The network that writes the offending value is the one that needs to be fixed. - Use the assignment list (PLC > Accessible nodes on a connected CPU, then Online & diagnostics > Assignment list). This is a runtime view: it shows what is actually using what address. Two tags assigned to byte 0 is the smoking gun.
6. Step-by-Step Resolution
There are two acceptable fixes. Pick one and apply consistently across the project.
Option A — Delete the conflicting word tag (preferred)
- In the project tree, open PLC tags > Default tag table (or whichever user-defined tag table contains
%MW0). - Right-click the row for
%MW0and select Delete. Confirm. The symbolic references in your program now show a red squiggle on"%MW0"/"ClampMask". - Navigate to the first network that uses the symbol. Click on the operand placeholder where
%MW0appeared. Right-click and choose Define tag. - In the Define tag dialog, set:
-
Name: keep the original symbolic name (e.g.,
CounterClamp) or rename for clarity. -
Data type:
WordorInt(whichever the surrounding logic expects). -
Address: leave blank. TIA Portal's Define tag wizard will auto-assign the first unused M-word above the region you are using for flags. By default this means
%MW200or higher, far away from your HMI flag bits.
-
Name: keep the original symbolic name (e.g.,
- Compile (Build) the project. The cross-reference list now shows
CounterClampat%MWxxxand the HMI flag bits are isolated. - Download to the CPU. Watch the HMI increase button now toggle the counter as expected.
Option B — Remap the flag bits out of byte 0
If the program requires the symbolic names %M0.3 and %M0.4 to remain at the original addresses (rare, usually because the HMI was commissioned against them), remap them to an empty region of the M area.
- Choose a free word, for example
%MW200. The corresponding bits are%M200.0–%M200.7and%M201.0–%M201.7. - Update the HMI tag mapping to bind the increase/decrease buttons to
%M200.3and%M200.4(or to two fresh bits, e.g.,%M200.0and%M200.1). - Update the ladder program: replace every reference to
%M0.3and%M0.4with the new addresses. - Update the HMI screen and download to the panel.
%M0.0–%M31.7) exclusively for HMI command and status flags, all BOOL and never aggregated into a word. Reserve a separate block (e.g., %MW200+) for numeric data, masks, and counters. Document the convention at the top of the tag table as a multi-line comment.7. Verification
After the fix, perform the following four checks before signing the change off:
-
Online watch check. Toggle each HMI button from the panel. The corresponding flag bit must transition to
1and remain1for the full debounce / pulse period defined in the HMI tag properties. -
Counter sanity check. Drive the counter to 0 (decrease repeatedly), then to 20 (increase repeatedly), and confirm both the
<and>clamp conditions fire. The%M0.4/ new%Mx.ybit must be observable in the watch table on every press. - Compile clean. Project > Compile > Software (rebuild all). There must be zero warnings about address overlap — TIA Portal will not produce this warning anyway, so this is a sanity step, not a diagnostic.
-
Cross-reference clean. Open the cross-reference for the new word address and for the new flag bits. Each symbol should appear in only its own address family (words in
%MWxxx, bits in%Mx.y), and no two symbols should share a byte.
8. Related Failure Modes on the Same Root Cause
The M-bit/MW overlap is one symptom of a broader class. The same pattern recurs in the following forms; if you fix one, audit the project for the others.
| Symptom | Cause | Fix |
|---|---|---|
| HMI button "works for a moment then resets" | Bit set by HMI is overwritten by a word/dword write later in the same scan | Remap the bit out of the word's byte range |
| Counter only counts up, never down (or vice versa) | One of the two clamp-mask values being OR'd into a word has a bit that toggles the wrong rung | Replace the mask-based clamp with explicit IF CT > 0 and IF CT < 20 blocks |
| HMI displays stale or scrambled numeric value | Word is being aliased to a bit array used as a status word | Separate the boolean status from the numeric data |
| Retain data is partially lost on power cycle | A RETAIN word is overwritten by a non-retain boolean in the same byte |
Mark only the word as retain, and place retain data in its own block |
| Force table appears to "not stick" | Forced word is shared with code that constantly writes a calculated value | Forcing a word is rarely meaningful; force individual bits instead |
For reference, the official SIMATIC S7-1200 Programmable Controller System Manual documents the M area as a unified bit memory region with no per-bit protection against word-level aliasing. The S7-1200 system manual is available from the Siemens Industry Online Support portal:
- SIMATIC S7-1200 Programmable Controller — System Manual (entry ID 109741593)
- S7-1200 Easy Book (entry ID 109798176) — beginner reference covering the M area
- STEP 7 Basic in TIA Portal — Programming and Operating Manual (entry ID 109773506)
- S7-1200 CPU 1211C / 1212C / 1214C / 1215C / 1217C Manual (entry ID 109751049) — for hardware-specific retain and memory layout details
9. Sample Ladder — Before and After
The original (faulty) program looks conceptually like this, where two HMI flag bits drive a counter clamped to 0…20 through a word register:
// Network 1 — HMI decrease
A %M0.3 // decrease HMI button
JCN _skipDec
L %MW0 // load current counter (overlaps with %M0.x!)
+ -1
T %MW0 // store back — this write clears %M0.3 and %M0.4
_skipDec: NOP 0
// Network 2 — HMI increase
A %M0.4 // increase HMI button
JCN _skipInc
L %MW0 // same word, same overlap
+ 1
T %MW0
_skipInc: NOP 0
// Network 3 — clamp at 20
L %MW0
L 20
>I
JCN _noClampHigh
L 20
T %MW0
_noClampHigh: NOP 0
// Network 4 — clamp at 0
L %MW0
L 0
<I
JCN _noClampLow
L 0
T %MW0
_noClampLow: NOP 0
Notice that every write to %MW0 in networks 1, 2, 3, and 4 overwrites the flag bits in %M0.0–%M0.7 with the low byte of the counter value. The %M0.3 / %M0.4 bits do not survive a single scan cycle except by lucky timing.
The corrected version uses an isolated numeric register and an isolated flag area:
// Network 1 — HMI decrease (flag now at %M200.0)
A %M200.0
JCN _skipDec
L %MW200 // counter register, no overlap with flag bits
+ -1
T %MW200
_skipDec: NOP 0
// Network 2 — HMI increase (flag at %M200.1)
A %M200.1
JCN _skipInc
L %MW200
+ 1
T %MW200
_skipInc: NOP 0
// Network 3 — clamp high
L %MW200
L 20
>I
JCN _ok1
L 20
T %MW200
_ok1: NOP 0
// Network 4 — clamp low
L %MW200
L 0
<I
JCN _ok2
L 0
T %MW200
_ok2: NOP 0
Now the bit flags live in byte 200 (addresses %M200.0–%M200.7) and the numeric register lives in word %MW200 (bytes 200–201). Because the word write in networks 1–4 affects %M200.0 and %M200.1, the flag bits are still in the same byte — so the discipline is to keep flag bits and numeric words in different byte regions. The clean layout is to use, for example, %M0.0–%M0.7 for flags and %MW200 for the counter. If the flag bits had to remain in the same byte as the word, the bit-write would still race with the word-write. The lesson is to keep boolean and numeric data in disjoint byte regions.
10. State Machine of the HMI Button Failure
The following diagram summarises the runtime behaviour of the original (faulty) program and shows where the bit is lost:
11. Tooling — Quick Watch-Table Trick
To detect any overlapping tag in a project, paste the following snippet into a watch table; it groups every byte of the M area and forces the engineer to see byte-level occupancy at a glance:
%MB0 BYTE
%MB1 BYTE
%MB2 BYTE
%MB3 BYTE
%MB4 BYTE
... (extend as needed)
%MW0 WORD
%MW2 WORD
%MW4 WORD
%MD0 DWORD
%MD4 DWORD
If the same byte is written to by both a BOOL row and a WORD/DWORD row in the same scan, the problem is visible immediately. Cross-reference each row with the project tag table to see which symbolic name owns each address.
12. HMI-Side Tag Configuration That Prevents Recurrence
Beyond the PLC fix, harden the HMI side. In the HMI tag properties (e.g., on a KTP1200 in WinCC within TIA Portal):
- Acquisition mode: Cyclic in operation, 1 s cycle, for status flags. For momentary command buttons, use Cyclic continuous only when the program is designed to read the bit every cycle.
- Update policy: set the HMI tag's PLC tag to Read for status and Read/Write for command. Mixing them causes the panel to overwrite a status flag that the program owns.
-
Bit-packing awareness: if the HMI polls
%MW0as a 16-bit status word, do not also poll individual bits of that word (%M0.0,%M0.4, etc.) as discrete tags. The panel will read the word first, decode the bits, and then write back the word if the bit was a control. Two pollers of the same byte is a recipe for the same overlap bug at the HMI layer. - Acknowledge / debounce: configure the button's "Press" event to set the bit and the "Release" event to reset it. Do not leave the bit latched by the HMI, because the program cannot guarantee clearing it cleanly while the word-write loop runs.
13. Engineering Checklist
Use this checklist as a pre-commissioning gate for any new S7-1200 / S7-1500 program that mixes HMI command flags with numeric M storage:
- Document a memory partition in the project header (e.g.,
%M0.0–%M31.7for HMI flags,%MW100–%MW499for numeric,%MB500–%MB999for handshake bytes). - Open the cross-reference for every word and dword symbol; verify no
BOOLsymbol shares its bytes. - Use only symbolic addressing for new code — never mix
%M0.4and a symbolicWORDin the same byte range. - In the watch table, group all symbols by byte during the first online test.
- Tag the project with the memory convention in the project properties description field.
14. Frequently Asked Questions
Why does one M-bit work and the other doesn't in the same byte?
Both bits are overwritten by the same %MW0 write, but the bit that "works" is one that the surrounding program happens to reassert (via a clamp-mask constant, status word, or counter value whose low byte has that bit set) before the output image is sent. The bit that appears dead is overwritten by a value whose low byte has that bit cleared. The fix is identical for both: separate the flag bits and the numeric word into disjoint byte regions.
Is %MW0 little-endian or big-endian on the S7-1200?
SIMATIC uses big-endian word order: %MW0 = MB0 (high byte) concatenated with MB1 (low byte). So %MW0 := W#16#1234 puts 12 in %MB0 and 34 in %MB1. This is the opposite of Modbus/Intel convention, and it matters when a third-party device reads the same memory as bytes in the opposite order.
Can I force %M0.4 to TRUE in the watch table to prove it isn't a hardware fault?
Yes. Right-click the row, choose Modify > Modify to 1, and check the result. If forcing %M0.4 := 1 does not change the rung's behaviour, the bit is being cleared by your program within the same scan. If forcing does change the behaviour, the HMI tag binding or panel-side acquisition is the fault, not the PLC logic.
Why does TIA Portal not warn me about the overlap?
Symbolic addressing with overlapping absolute addresses is a permitted combination in the S7-1200 memory model; it is the same flat byte array, and the compiler has no way to know that the developer's intent is exclusive. The protection is your memory-allocation convention, not the tool. Document the convention in the project.
Does the same bug exist on S7-1500 and on the S7-300 / S7-400?
Yes. The M-bit/MW overlap behaviour is identical across the S7-300, S7-400, S7-1200, and S7-1500 families because they all share the SIMATIC bit-memory addressing model. The fix and the discipline are also identical. On the S7-1500, symbolic addressing and optimised block access can hide the issue for a while because the compiler may place symbols in a different order than the absolute address, but as soon as any tag is pinned to an absolute %M address the bug returns.