S7-1500 Alarm Bit Mapping: TP700 HMI Trigger Tag Methods

David Krause15 min read
HMI ProgrammingSiemensTutorial / 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

1. Problem Overview

On S7-300/400 systems, alarm bits in a data block could be exposed to WinCC flexible / TIA Portal HMI tags by pointing the HMI tag to an absolute byte address and using the same address as a trigger for the HMI alarm. Each individual bit in the data block was effectively a single alarm line. The S7-1500 changes this model: data blocks created with the default "Optimized block access" attribute store symbols with a non-disclosed internal layout, and the HMI can no longer access individual BOOL bits through a bit-trimmed word tag. A direct alarm-trigger word pointing into a structured BOOL array becomes impossible in the HMI alarm editor.

This is a recurring commissioning problem when migrating a S7-300/400 alarm DB into a S7-1500 program that drives a TP700 Comfort Panel, or when a third-party SCADA (e.g., Citect, WinCC, AVEVA) must read the same alarm DB symbolically. The HMI alarm system expects a trigger tag of type WORD, INT, or DWORD, and the PLC program is most naturally written in terms of named BOOL tags. Five practical methods close this gap, with different trade-offs in readability, performance, and HMI/SCADA interoperability.

2. Prerequisites

  • CPU S7-1500 (any firmware ≥ V2.0 for full Program_Alarm support; firmware ≥ V1.8 for the AT overlay syntax inside optimized DBs).
  • STEP 7 Professional V15.1 or later (TIA Portal). The AT keyword and Program_Alarm block library are introduced incrementally; V16 or later is recommended for current firmware compatibility.
  • SIMATIC Comfort Panel TP700 (6AV2 124-1GC01-0AX0 or later), or a WinCC Runtime Advanced / Professional target. The trigger tag must be a non-array element of type WORD, INT, or DWORD.
  • For the legacy method, the alarm DB must be created with "Optimized block access" unchecked. The whole DB is then accessible by absolute address and the HMI tag may point at a WORD located inside it.
  • For the Program_Alarm method, the message configuration must be edited in the PLC's "Messages and alarms" editor and the HMI's alarm editor must be associated with the same message number range.
S7-1500 alarm bits are not exposed through a single WORD unless you actively create one. If you want the bit status to appear as a discrete alarm on the TP700, the trigger tag must be a non-array element of one of the supported integer types. Arrays of BOOL are not valid HMI trigger tags.

3. Method Comparison

Method HMI Trigger Type Symbolic Bits Works With Optimized DB SCADA-Friendly Effort
Non-optimized BOOL DB (legacy) Word over absolute byte No (absolute only) No Yes Low
Program_Alarm / Program_Alarm_8P None (message number) Yes (instance DB / FB static) Yes Limited Medium
Slice access ("tag".X0) Word of bits / DWORD No (anonymous bits) Yes Partial Low
AT overlay on structured type Word / DWORD at overlay view Yes (base symbol) Yes Yes Medium
Word packing with SCATTER / GATHER Word composed in logic Yes (individual BOOLs) Yes Yes High

4. Method 1 — Non-Optimized Alarm DB (Legacy S7-300/400 Pattern)

This is the most direct port of the original S7-300/400 approach. Create a global DB named, for example, Alarm_DB, clear the "Optimized block access" checkbox in the DB's properties, and define a flat array of BOOL alarm variables. The absolute address range is now exposed and visible in the project tree.

  1. In the project tree, add a new global DB and open its properties.
  2. On the "Attributes" tab, uncheck Optimized block access. The compiler will then accept absolute addresses and disable certain safety checks; this is intentional for interop with HMI absolute tags.
  3. Add a section with 16, 32, or 64 BOOL tags (Alarm_01 … Alarm_16 for a 16-bit word, etc.).
  4. In the HMI project, create one tag per word (DB_AlarmWord1) with PLC connection to DBx.DBW0, DBx.DBW2, … of the alarm DB. Type WORD or INT.
  5. In the HMI alarm editor, create one alarm line per bit, selecting "Trigger tag" = DB_AlarmWord1 with "Trigger bit" = 0 … 15.

Commissioning note: when the trigger word is read on a S7-1500, the bit order inside the word matches the standard little-endian layout (bit 0 is the LSB). However, when WinCC reads the word and groups alarms by tag, the byte order of the underlying DB can be different from the alphabetical tag order. Byte-swap the word if your test rig shows that the alarm labelled "bit 0" actually lights the high bit of the first word. The cleanest fix is to arrange the BOOLs in the DB so that the HMI's "Alarm number" increments in the same direction as the DB byte index.

Uncheck Optimized block access only for the alarm DB, never for the safety DB or the recipe DB. The legacy pattern is robust for alarm interop but loses the symbolic download-delta guarantees Siemens ships in optimized blocks.

5. Method 2 — Program_Alarm / Program_Alarm_8P (S7-1500 Native)

The S7-1500 message architecture replaces bit triggers with a message-number scheme. The PLC sends a message number plus a state bit, the HMI looks up the number, and the configured text is displayed. The mechanism uses the Program_Alarm extended instruction in the standard library path Instructions > Extended instructions > Alarm.

  1. Open the PLC's "PLC alarms" / "Messages and alarms" editor. TIA Portal auto-generates a MSG_LOCK bit and assigns message numbers starting at 1 for the project.
  2. Add a new message in the alarm editor. Set the message class (e.g., Errors), the trigger signal as Program_Alarm, and assign a message number (e.g., 100).
  3. In the program, declare a static or temp tag of type BOOL for the alarm condition. The standard pattern uses an FB's static section so that each instance of the FB has its own alarm ID.
  4. Call the Program_Alarm block from the FB. The MSG input is the message instance, Sig is the BOOL condition, Sig_0/Sig_1/Sig_2 are the three possible state parameters, and SD_1 … SD_10 are the user-supplied values that substitute into the configured message text.
  5. For batch alarms, use Program_Alarm_8P, which bundles eight boolean signals into one call and uses a starting message number plus an offset of 0–7.
  6. On the TP700 side, the alarm editor will show the messages from the PLC automatically. No trigger tag is required.

Example FB static section and call:

FUNCTION_BLOCK "FB_MotorAlarms"
VAR
  bOverload       : BOOL;   // overcurrent detected
  bOverheat       : BOOL;   // thermal trip
  bPhaseLoss      : BOOL;   // phase monitor
  stAlarmOverload : Program_Alarm;   // auto-generated MSG instance
  stAlarmOverheat : Program_Alarm;
  stAlarmPhase    : Program_Alarm;
END_VAR

BEGIN
  // Overload alarm, MSG-ID 100, format: 'Motor %s overload %d A'
  "stAlarmOverload"(MSG := "instAlm".alarmOverload,    // MSG instance
                    Sig := bOverload,
                    SD_1 := 'M1',
                    SD_2 := INT_TO_STRING(iCurrent));

  "stAlarmOverheat"(MSG := "instAlm".alarmOverheat, Sig := bOverheat);
  "stAlarmPhase"(MSG    := "instAlm".alarmPhase,    Sig := bPhaseLoss);
END_FUNCTION_BLOCK

Program_Alarm is the recommended path for new S7-1500 work. It survives the optimized-block model, supports multi-instance FBs, and gives the HMI configurable text with embedded values. The constraint is that Citect, WinCC, and most SCADA products expect either a bit trigger or an OPC UA alarm; the native WinCC / TP700 integration is the only target that consumes Program_Alarm message numbers out of the box.

6. Method 3 — Slice Access on a Word / DWORD

Slice access is the shortest path when you want to keep an optimized DB. The S7-1500 accepts the syntax "MyTag".X0 through "MyTag".X7 on a BYTE, WORD, or DWORD. The catch: the bits accessed this way are not symbolic alarm names; they are anonymous bit positions in a single word.

  1. Create a global DB with a single static WORD or DWORD tag (e.g., wAlarmStatus).
  2. In the program, set the bits using the slice syntax. The lower-case x is required and the index is decimal.
  3. On the HMI side, expose wAlarmStatus as a HMI tag, point the alarm editor at it, and select bit 0..15.
// Set alarm bit 3 in an optimized DB
"Alarm_DB".wAlarmStatus.X3 := TRUE;

// Clear alarm bit 7
"Alarm_DB".wAlarmStatus.X7 := FALSE;

// Test the union as a whole
"Alarm_DB".wAlarmStatus := 16#0041;   // bits 0 and 6 set

This is acceptable for small, well-documented alarm maps but it does not scale. With 32 or 64 alarms, the code that sets .X0 … .X31 becomes hard to read, and the HMI alarm list shows only "Bit 17" rather than "Tank_101_High_Level". For 16 alarms or fewer it is the fastest implementation.

7. Method 4 — AT Overlay on a Structured PLC Data Type

The AT keyword allows a single memory area to be viewed under two different types. A structured PLC data type (UDT) carries the named BOOL alarms; an AT overlay on a WORD or DWORD exposes the same storage to the HMI as a trigger word. This is the most maintainable path on a S7-1500 because the alarms stay symbolic in the program and the HMI sees a single integer tag.

  1. Create a PLC data type (UDT), e.g., UDT_AlarmWord, with sixteen BOOL members b00 … b15 (or with semantic names such as bHighLevel, bLowPressure).
  2. Create a global DB and add a static tag stAlarms of type UDT_AlarmWord. Keep "Optimized block access" enabled.
  3. In the same DB, add a second static tag wAlarms AT "stAlarms" : WORD;. The AT clause tells the compiler that the new tag is a view over the same memory.
  4. Use the BOOL names in the program: "Alarm_DB".stAlarms.bHighLevel := TRUE;.
  5. On the HMI, point a single tag at "Alarm_DB".wAlarms (type WORD), then create 16 alarm lines, each with the same trigger tag and a different trigger bit (0..15).
TYPE "UDT_AlarmWord"
VERSION : 0.1
  STRUCT
    bHighLevel     : BOOL;   // bit 0
    bHighPressure  : BOOL;   // bit 1
    bLowLevel      : BOOL;   // bit 2
    bLowPressure   : BOOL;   // bit 3
    bMotorOverload : BOOL;   // bit 4
    bPhaseLoss     : BOOL;   // bit 5
    bEstopActive   : BOOL;   // bit 6
    bDoorOpen      : BOOL;   // bit 7
    bReserved_8    : BOOL;
    bReserved_9    : BOOL;
    bReserved_10   : BOOL;
    bReserved_11   : BOOL;
    bReserved_12   : BOOL;
    bReserved_13   : BOOL;
    bReserved_14   : BOOL;
    bReserved_15   : BOOL;
  END_STRUCT;
END_TYPE

DATA_BLOCK "Alarm_DB"
VERSION : 0.1
  STRUCT
    stAlarms : "UDT_AlarmWord";
    wAlarms  AT "stAlarms" : WORD;   // overlay for HMI trigger
  END_STRUCT;
END_DATA_BLOCK

The AT overlay is the cleanest answer when you have a SCADA that needs a single trigger word. The BOOL layout in the UDT is stable, the bits stay named in the program, and the HMI alarm list still has 16 trigger bits but reads from one tag.

If the UDT grows past 16 BOOLs, stack two WORDs: wAlarmsLo AT "stAlarms" : WORD; and wAlarmsHi AT "stAlarms" : DWORD; with a manual offset, or use a DWORD overlay. The compiler will reject the AT clause if the target type does not fit the source size.

8. Method 5 — Word Packing with SCATTER / GATHER

For larger alarm maps (hundreds of BOOLs) the standard library provides SCATTER and GATHER blocks. The pattern keeps the individual BOOLs symbolic in a structured DB, then on every cycle packs the relevant subset into a WORD or ARRAY[..] OF WORD for the HMI.

  1. Define a UDT or DB with 16 / 32 / 64 named BOOL alarms per group.
  2. Use SCATTER to read the BOOLs and produce a single WORD (or use WORD_TO_BOOL arrays in a manual packing loop).
  3. Use GATHER on the operator side to convert a written WORD back to individual BOOLs if the operator must acknowledge or reset alarms per bit.
  4. Expose the resulting WORD array as a multi-element HMI tag and assign one HMI tag per element to the alarm editor.
// Pack 16 BOOL alarms into one word, bit 0 = first alarm
FOR i := 0 TO 15 DO
  IF "Alarm_DB".stAlarms[i] THEN
    "Alarm_DB".wAlarmGroup[i DIV 16] := "Alarm_DB".wAlarmGroup[i DIV 16] OR (SHL(WORD#1, i MOD 16));
  ELSE
    "Alarm_DB".wAlarmGroup[i DIV 16] := "Alarm_DB".wAlarmGroup[i DIV 16] AND (NOT SHL(WORD#1, i MOD 16));
  END_IF;
END_FOR;

SCATTER / GATHER is the right answer when the alarm DB must be accessible from third-party SCADA through a single named word array, and you do not want to give up the symbolic BOOLs inside the PLC. It is more work to wire up than AT overlay, but it scales linearly to thousands of bits.

9. Bit-to-Word Mapping Discipline

Whatever method is selected, the HMI sees only one trigger word per group. Three rules keep the system maintainable:

  1. Use UDTs, not free-standing BOOLs. A UDT in the PLC data types defines the alarm group once, and every instance of the FB / DB that uses it inherits the same layout. Renaming a BOOL inside the UDT propagates everywhere.
  2. Reserve bits explicitly. A UDT with bReserved_8 … bReserved_15 documented in comments is better than letting the SCADA guess. Operators searching the HMI for "Bit 9" will not find a name; operators searching for "Bit 9 / reserved for future level switch" will at least know the answer is "not wired".
  3. Document the trigger word layout in a single place. A spreadsheet in the project documentation that lists "HMI Alarm Number 17 → TP700 trigger bit 1 of word wAlarms_03 → UDT_AlarmGroup member bLowPressure" is the only thing that survives a 5-year maintenance window.

10. Verification

After commissioning, run a four-step validation before signing off the panel:

  1. Cross-trigger from the watch table. Force each BOOL in the alarm DB to TRUE in STEP 7. Confirm the corresponding alarm appears on the TP700 within one cycle. If the HMI shows the wrong text for the bit, the trigger bit index is mis-mapped or the byte-swap has flipped the order.
  2. Acknowledge round-trip. Acknowledge the alarm from the TP700. With bit triggers the acknowledgement clears the HMI side but does not clear the PLC BOOL. With Program_Alarm, the acknowledgement is reported back to the FB and the Ack output on the Program_Alarm block goes high for one cycle.
  3. SCADA cross-check. If the system also has a WinCC Professional / Citect client reading the same DB, watch the BOOL from the SCADA's tag browser. The value seen there must match the TP700 alarm state. A mismatch is the standard symptom of the byte-swap issue described in §4.
  4. Download-delta test. Change one alarm text in the HMI alarm editor and download-delta the project. With an optimized DB the change must be downloaded cleanly; with a non-optimized DB the entire alarm DB may recompile, and the SCADA OPC namespace may need a refresh.

11. Troubleshooting Matrix

Symptom Likely Cause Fix
HMI shows "No valid trigger tag" on every alarm line Trigger tag is an array element or a STRUCT member Create a non-array WORD/INT/DWORD tag and use it as the trigger
Alarm bit lights a different HMI alarm than expected Byte swap between DB byte order and HMI bit order Reorder the BOOLs in the DB, or rebuild the trigger word with explicit shifts
TP700 alarm is shown but text is generic Message number not configured in HMI alarm editor Open the HMI alarm editor, link it to the PLC's message configuration, download
SCADA cannot see the alarm DB at all DB is optimized and SCADA only supports absolute OPC Use Method 1 (non-optimized) or expose a WORD overlay (Method 4)
Compiler rejects AT "stAlarms" : WORD; Size mismatch or UDT does not start with the same byte layout Verify the UDT is exactly 16 / 32 / 64 bits, no padding
Program_Alarm does not appear on the TP700 HMI alarm editor is using bit triggers instead of message numbers Open the HMI editor, switch the alarm class to "Message number" and select the PLC as the source
Slice syntax accepted in LAD/FBD but not in SCL SCL requires the period and capital X (.X0) Rewrite in SCL: "MyDB".wTag.X0 := TRUE;
Word value flickers between two states on a fast alarm HMI poll cycle is longer than the alarm pulse Latch the alarm bit in the PLC and clear it only after HMI acknowledgement

12. Field-Commissioning Notes

For most retrofit work (S7-300 → S7-1500 with the same TP700 firmware version), Method 1 is the cheapest to implement and survives the existing HMI project unchanged: just uncheck optimized access on the alarm DB. The price is the loss of symbolic download-delta guarantees for that single DB.

For new builds that will only ever be visualized on a TP700 / WinCC Runtime, Method 2 is the right answer. Program_Alarm integrates with the HMI alarm editor's message-number framework, supports multi-instance FBs, and the message text is configurable per FB instance. The cost is the loss of third-party SCADA interop unless that SCADA is also configured to consume the same message numbers.

For mixed PLC / SCADA sites where Citect, AVEVA, or another OPC client must read the same alarms, the AT overlay (Method 4) is the best balance: the BOOLs stay named in the PLC, the HMI sees one trigger word, and the SCADA can read the same word through the OPC namespace. The overlay is stable across firmware versions and survives every download-delta cycle. Method 5 (SCATTER / GATHER) is preferred only when the alarm count exceeds 64 bits per group and the additional packing code is justified.

Can I use an ARRAY of BOOL as the HMI alarm trigger tag?

No. The WinCC alarm editor only accepts a non-array element of type WORD, INT, or DWORD as a trigger. Expose a single WORD (or DWORD) and set the individual bits through slice, AT overlay, or a packing loop.

Why does the HMI show the alarm text for the wrong bit after a S7-300/400 migration?

The byte order of the trigger word inside a S7-1500 alarm DB is not guaranteed to match the HMI's bit-numbering scheme. Reorder the BOOLs in the DB so that the HMI's "Bit 0" alarm corresponds to bit 0 of the first word, or use an explicit packing loop with shifts.

Do I have to disable Optimized Block Access for the alarm DB?

Only for Method 1 (the legacy absolute-address pattern). Methods 2 through 5 keep the alarm DB optimized. If a third-party SCADA reads the DB through OPC and does not support the optimized layout, disable optimization on the alarm DB only, never on safety or recipe DBs.

How many alarms can a single Program_Alarm block handle?

Program_Alarm carries one boolean signal per call. Program_Alarm_8P carries eight boolean signals. For more than eight grouped alarms, add multiple Program_Alarm_8P instances or use a UDT-driven loop with one Program_Alarm per FB instance.

Does the AT overlay survive a TIA Portal version upgrade?

Yes, the AT keyword syntax is part of the STEP 7 V14+ language definition and is preserved across upgrades as long as the UDT layout does not change size. If you insert or remove a BOOL in the UDT, the AT overlay will not auto-resize; rebuild the overlay tag manually.

Back to blog