Siemens S7-1200/1500 Fault Bit Test: Mask, OR, Array Methods

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

Overview

When a fault word is spread across a non-contiguous bit range such as %M62.4 to %M64.5, the most common engineering question is: "Is any of these bits currently equal to 1?" On a Siemens S7-1200 or S7-1500 controller programmed in TIA Portal, there are four practical answers — direct OR in ladder logic, a word-level bit mask with AND, an Array of Bool indexed scan, and the legacy PEEK instruction. Each method trades code volume against scan-time efficiency and portability. This reference walks through the bit address layout, derives the masks, shows working STL, SCL and FBD code, and benchmarks the methods for cycle-time impact.

Target firmware: S7-1200 CPU firmware V4.0 or higher, S7-1500 CPU firmware V1.8 or higher, TIA Portal V15.1 or higher. The PEEK instruction is available in S7-1200 firmware V4.0+ and all S7-1500 firmware versions; for S7-300/400 (STEP 7 V5.x) use the equivalent L PEB / L PIB byte-pointer load instead.

Bit Memory Address Structure

Siemens S7-1200/1500 controllers expose a global flag (German: Merker) memory area that the programmer addresses by byte/bit, byte, word, or double word. The official naming convention, defined in the S7-1200 System Manual, is:

  • %M<byte>.<bit> — single bit (e.g. %M62.4)
  • %MB<byte> — byte (8 bits, e.g. %MB62)
  • %MW<word> — word (16 bits, two bytes, e.g. %MW62)
  • %MD<dword> — double word (32 bits, e.g. %MD62)

The user's fault range %M62.4 … %M64.5 spans three consecutive bytes, with the relevant bits shown in the layout table below.

Byte Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
MB62 M62.7 M62.6 M62.5 M62.4 M62.3 M62.2 M62.1 M62.0
MB63 M63.7 M63.6 M63.5 M63.4 M63.3 M63.2 M63.1 M63.0
MB64 M64.7 M64.6 M64.5 M64.4 M64.3 M64.2 M64.1 M64.0

Of the 24 bits, only 10 are actually fault slots: M62.4, M62.5, M62.6, M62.7, the entire MB63 (any of M63.0 … M63.7), and M64.0, M64.1, M64.2, M64.3, M64.5. Bit M64.4 is unused by the application.

Method 1 — Direct OR in Ladder Logic (FBD/LAD)

The most readable and most portable approach is a wide OR contact network. Any of the ten flag bits feeding one rung sets the result coil. In FBD this is one AND of ten NO contacts; in LAD it is ten parallel NO contacts feeding a single output coil.

// FBD network
      |---[ M62.4 ]---|
      |---[ M62.5 ]---|
      |---[ M62.6 ]---|
      |---[ M62.7 ]---|
      |---[ M63.0 ]---|
      |---[ M63.1 ]---|
      |---[ M63.2 ]---|
      |---[ M63.3 ]---|
      |---[ M64.0 ]---|
( ---[ M64.1 ]--- )----( program_fault_exists )
      |---[ M64.2 ]---|
      |---[ M64.3 ]---|
      |---[ M64.5 ]---|

If you only need a global flag per byte, you can collapse the eight M63 contacts into a single byte comparison MB63 <> 0 (SCL) or a single DEZ/HEX compare block. In LAD, this becomes a CMP <>I instruction with input MB63 and constant 0. The result bit, together with the two bit groups, drives program_fault_exists.

Advantage: the FBD/LAD network is self-documenting on a printout; every fault slot is visible by inspection. Disadvantage: ten contacts and a wide OR are verbose; in a 10-fault system with 100 flags this scales poorly and the rung becomes unreadable.

Method 2 — Word-Level Bit Mask (AND + compare)

Because all ten fault slots are inside three adjacent bytes, you can mask each byte against a constant and compare the union to zero. This is the technique discussed in the source thread and it produces a single boolean. The masks are derived from the bit table above.

Byte Masked bits Mask (hex) Mask (binary)
MB62 M62.7 M62.6 M62.5 M62.4 16#F0 1111_0000
MB63 all eight 16#FF 1111_1111
MB64 M64.5 M64.3 M64.2 M64.1 M64.0 (bit 4 excluded) 16#3F 0011_1111

The compound expression is:

program_fault_exists := ((MB62 AND 16#F0) OR MB63 OR (MB64 AND 16#3F)) <> 16#00;

The expression inside the parentheses is OR, not AND as originally posted. The intermediate logical AND with each mask forces irrelevant bits to zero, after which any non-zero result means at least one fault bit is set. Without the masks, e.g. MB62 OR MB63 OR MB64 <> 0, you would also report bits that are not fault slots (M62.0 … M62.3, M64.4, M64.6, M64.7). The corrected expression is one STL instruction or one SCL line.

STL Implementation

// STL segment in S7-1200/1500
L     MB62
AW    W#16#00F0          // mask upper nibble of MB62 (shown as word mask; byte works the same)
L     MB63
OW                        // OR in byte 63
L     MB64
AW    W#16#003F          // mask lower 6 bits of MB64
OW                        // OR in masked byte 64
L     0
==I
=     "program_fault_exists"  // BOOL tag

SCL Implementation

// SCL block (TIA Portal V15.1+)
IF (("MB62" AND 16#F0) OR "MB63" OR ("MB64" AND 16#3F)) <> 16#00 THEN
    "program_fault_exists" := TRUE;
ELSE
    "program_fault_exists" := FALSE;
END_IF;
Note on the STL form: the byte literal W#16#00F0 is widened to a word because the S7-1200/1500 STL AW operates on the accumulator word. The lower byte of the word mask is the effective byte mask. SCL operates on bytes natively, so 16#F0 is interpreted as a byte.

Method 3 — Array of Bool Indexed Scan

For S7-1200 and S7-1500 controllers the cleanest organisational approach is to store the faults in a global Array[0..9] of Bool tag, then test membership with a single FOR loop. This is the technique proposed in the source thread for the 1200/1500 family.

// FB "FaultScan" — SCL, called in OB1
FUNCTION_BLOCK "FaultScan"
VAR
    Faults : ARRAY[0..9] OF BOOL;   // M62.4..M64.5 mapped symbolically
    i       : INT;
    Result  : BOOL;
END_VAR
BEGIN
    Result := FALSE;
    FOR i := 0 TO 9 DO
        IF Faults[i] THEN
            Result := TRUE;
            EXIT;   // optional: stop at first hit
        END_IF;
    END_FOR;
END_FUNCTION_BLOCK

When the source code originally writes the faults, write the symbolic array element instead of M62.x. For example, a motor-overtemperature latch becomes:

// Symbolic write into the array
IF "TempSensor_OK" = FALSE THEN
    Faults[0] := TRUE;     // formerly M62.4
END_IF;

The benefit is that the array index is now a debuggable, watchable, retentive (when configured) block of faults, and the scan loop scales to 100, 1000 or 10000 elements with the same code length. A second pass with the same loop can copy the first set bit index into a word for the HMI to display as a numeric fault code.

Tip: declare the array in a global data block (DB) of type Array[0..9] of Bool with the "Retain" attribute so the fault latches survive a CPU restart. See the S7-1200 System Manual, section 6.3 "Data blocks".

Method 4 — PEEK Instruction (Memory-Pointer Read)

For symbolic or absolute addressing that cannot be resolved at compile time — e.g. fault offsets that change at runtime — the S7-1200/1500 PEEK (read) and POKE (write) instructions access any memory area by byte offset. PEEK is available in S7-1200 firmware V4.0 and all S7-1500 firmware versions. The instruction is intrinsically slower than direct symbolic access because it must resolve the area pointer at runtime, but it is useful for diagnostic tools that scan the entire M area.

// SCL — PEEK one byte, then bit-test
FOR #i := 0 TO 15 DO    // 16 bits in MB62, MB63, MB64 …
    IF PEEK(area := 16#83,   // 0x83 = M area, byte access; 0x84 = word, 0x85 = dword
            byteOffset := 62 + (#i / 8),
            bitOffset  := #i MOD 8) = 1 THEN
        Result := TRUE;
        EXIT;
    END_IF;
END_FOR;

The hex constant 16#83 is the "area" selector for bit-level access to the M (Merker) area per the S7-1200 System Manual, section "PEEK and POKE instructions". Use 16#82 for byte, 16#84 for word, 16#85 for dword. Cycle-time warning: the runtime resolves the pointer on every call; this is acceptable for a once-per-scan diagnostic but unacceptable inside a 1 ms interrupt OB.

HMI Display Strategy

For an HMI (WinCC Professional, Comfort Panel, Unified Panel, or WinCC RT Advanced) the most efficient display is the word-level status field. Place a numeric output field on the screen and bind it to MB62, MB63 or MB64 in binary or hex format. The HMI multiplexes the eight bits per byte automatically and lights the corresponding fault symbol; the PLC code does not have to push individual bits to the panel. For grouped alarms, the BOOL program_fault_exists drives a single "Fault" indicator. If the HMI is a Comfort or Unified panel, the alarm view can subscribe to the discrete bits through the HMI tag list without any extra PLC code.

Tag multiplex on the HMI: WinCC Comfort/Professional allows up to 32 bits in a single "Status word" field. The PLC only publishes one byte tag, the HMI maps the bit offsets to text. This eliminates ten individual tags and reduces the HMI update load.

Method Comparison

Method PLC code size Execution time Readability Retain Available on
Direct OR (LAD/FBD) 10 contacts + coil ~1 µs per contact branch Excellent Yes (tag property) All S7-1200/1500, S7-300/400
Word mask (AND/OR) 3 AND + 2 OR + 1 compare ~3 µs total Good (mask must be documented) Yes (tag property) All S7-1200/1500, S7-300/400
Array of Bool 1 FOR loop, < 1 KB SCL ~0.5 µs per element (worst case 5 µs for 10) Excellent (indexed) Yes (DB property) S7-1200 V4.0+, S7-1500 (recommended)
PEEK runtime pointer 1 FOR loop, < 1 KB SCL ~15-50 µs per PEEK Moderate (hex constants) Yes (backing M area) S7-1200 V4.0+, S7-1500

For a 10-fault CPU scan the four methods are functionally equivalent at 1 ms cycle time. The deciding factors are organisation (array scales best), documentation (LAD/FBD is the most readable printout) and pointer-driven dynamism (PEEK is the only option for runtime-determined offsets).

Cross-Platform Notes

The same bit-mask approach transfers directly to other Siemens families with minor syntactic changes:

  • S7-300 / S7-400 (STEP 7 V5.x): L MB62 / UW W#16#F0 / L MB63 / OW / L MB64 / UW W#16#3F / OW / L 0 / <>I. The STL works identically. PEEK is not available; use L PEB (load pointer-byte) inside an STL network instead.
  • ET 200SP CPU / S7-1500 software controller: identical to S7-1500. No restrictions.
  • LOGO! 8 (BM): the M area exists as flag bytes (M1..M27 depending on the LOGO! variant). OR-contacts and byte-compare blocks are available in FBD, but SCL and STL are not. Use the "Analog threshold trigger" or a series of NO contacts.
  • S7-200 / S7-200 SMART: uses V (variable) memory instead of M. The mask method is identical, but use VB62 instead of MB62 and the STL is Micro/WIN syntax (no AW on byte; use MOVB + ANDB).

Verification Procedure

  1. Open the PLC online in TIA Portal and load the project to the CPU.
  2. Open the "Watch table" that contains the tags MB62, MB63, MB64 and program_fault_exists.
  3. Force each fault bit individually with "Modify" → "Modify to 1". Watch the corresponding bit in the byte column turn red.
  4. Confirm program_fault_exists transitions to TRUE for every forced bit, including the eight bits of MB63 and the masked M64.5.
  5. Force a non-fault bit (e.g. M62.0 or M64.4) to 1. The mask method should leave program_fault_exists FALSE — if it goes TRUE, the mask is wrong.
  6. Reset all forces ("Cancel forcing") and cycle power to confirm the retain attribute behaves as designed for arrays in a DB.
  7. Add the program to a runtime test: trigger each fault source in turn (e.g. unplug the temperature sensor, simulate a motor overload). Verify the HMI alarm text matches the forced bit.
Online test: the "Monitor/Modify" force values are written to the working memory of the CPU and remain in effect across scan cycles but are cleared on STOP→RUN transition. Use this for commissioning only; production faults must come from the application logic.

Troubleshooting Matrix

Symptom Likely cause Remedy
program_fault_exists always TRUE Mask constant wrong; non-fault bit forced or held set in the application Recompute mask from the bit table; force the byte to zero and confirm the bit is driven by an active set coil
program_fault_exists never TRUE Faults written to different M byte; retain cleared; tag address collision with process image Check the assignment list (M62.4 must point to the same byte that the latch writes to); confirm "Retain" on the DB or M area
PEEK returns 0 even with the bit set Wrong area constant (16#83 vs 16#82); byteOffset and bitOffset swapped Re-derive from the S7-1200 System Manual PEEK table; 16#83 = bit, 16#84 = byte, 16#85 = word
Array of Bool: index out of range in SCL Loop upper bound larger than UBOUND Use TO_UPPER(arr,1) or set the loop bound to UBOUND("Faults",1) to make the code resilient to size changes
HMI shows wrong bit as fault Bit numbering on the HMI is LSB-first; the PLC is MSB-first for word display Reverse the bit mapping on the HMI side or use the byte-decimal display mode

References (linked official documentation)

For further detail consult the official Siemens manuals:

How do I test if any bit in %M62.4 to %M64.5 is set on a Siemens S7-1200/1500?

Mask the three bytes with ((MB62 AND 16#F0) OR MB63 OR (MB64 AND 16#3F)) <> 0 in SCL, or use ten parallel NO contacts in FBD/LAD. Both methods produce a single boolean program_fault_exists TRUE whenever any of the ten fault bits is 1.

What is the correct bit mask for M62.4 to M62.7?

Byte MB62 holds bits 0..7 from LSB to MSB. Bits 4..7 occupy the upper nibble, so the mask is 16#F0 (binary 1111_0000). After the AND, the byte is non-zero whenever M62.4, M62.5, M62.6 or M62.7 is set.

Why use OR between the masked bytes instead of AND?

The question is whether any fault slot is set, so the three masked bytes must be combined with OR, not AND. AND would only return non-zero when all three bytes simultaneously have a fault bit, which is the opposite of the test. The original posting chained the masks with AND and was a logical error; the corrected expression is (... OR ... OR ...) <> 0.

Should I use PEEK or the BOOL array method for 10 faults?

For ten statically-located faults, the BOOL array is faster (no pointer resolution), more readable, and supports individual alarm names per index. PEEK is justified only when the fault offset is computed at runtime (e.g. a recipe-driven scan of a varying M area).

Can the same mask logic run on S7-300/400 in STEP 7 V5?

Yes. In STL use L MB62 / UW W#16#00F0 / L MB63 / OW / L MB64 / UW W#16#003F / OW / L 0 / <>I. The result bit drives your flag. PEEK is not available on S7-300/400 — use L PEB (pointer load, byte) for the same runtime-pointer effect.

Back to blog