1. Problem Overview
A common pattern in Siemens TIA Portal programming is the "alarm block": a Function Block (FB) that monitors a process condition and produces two boolean outputs, typically a warning and an alarm. In a plant that has many alarm conditions, the same two boolean outputs are aggregated from many FB instances. The naive implementation - declaring warning and alarm as Output (OUT) parameters and wiring a Set coil (S) or a Reset coil (R) to them inside the FB body - produces a runtime behavior that surprises new TIA Portal programmers:
- When two or more FB instances are called in parallel networks and each attempts to set the same global bit (for example
%M600.2), the assignment from the second instance is silently ignored. - Test bit 14 (set) and Test bit 15 (reset) placed on an OUT parameter do not behave like a Set/Reset coil at the call site; they behave like a single standard coil, which the LAD editor refuses to duplicate.
- The original symptom appears as if the FB were a function (FC) instead of a block, leading programmers to chase a bug that is actually a feature of the LAD/FBD compiler rules.
The behavior is not a defect in the firmware or a corrupt project. It is the direct consequence of two facts: (1) the LAD/FBD editor enforces one coil assignment per operand per network across the entire compiled code, and (2) an FB's OUT parameter is generated as a single coil at every call site. The fix is to change the parameter category of the shared bit from Output to InOut (IN_OUT). This article documents the root cause, the correct workaround, the verification procedure, and the edge cases you will encounter when you adopt it.
2. Root Cause: Ladder Coil Uniqueness Rule
In TIA Portal, the LAD (Ladder Diagram) and FBD (Function Block Diagram) editors translate every coil-like instruction into a single = assignment to the operand during compilation. The PLC's cycle model does not tolerate a single memory bit being written from two different network locations in the same scan, because the order of execution is determined by network number, and the last write wins. To prevent nondeterministic behavior, the compiler enforces the rule:
Within a network, a given boolean operand may appear as the target of at most one coil instruction. Across networks, the same operand may not be the target of more than one regular coil
( ). Multiple Set(S)and Reset(R)instructions on the same operand are allowed provided no plain coil( )on that operand exists anywhere in the OB/FC/FB.
This rule applies to operands, not to FB parameters. The compiler resolves FB parameter references to the underlying memory address (the bit you wired in the instance DB or as a global address) before applying the uniqueness check. The implication is critical: if you have ten FB instances and each one wires warning to %M600.2, the compiler sees ten coils on %M600.2 after inlining the parameter mapping, and it allows at most one of them to compile as a non-Set/Reset assignment.
The Siemens support thread on FB Set bit behavior documents the same restriction in the context of FCs; the rule is identical for FBs, and the symptom is identical for any reusable block (FB, FC, or multi-instance block). The supporting reference for the general rule is the SIMATIC S7-1200/1500 Programming and Operating Manual, chapter on LAD/FBD bit logic.
3. Why Set/Reset Coils Behave the Same as Standard Coils
Inside an FB body, the engineer selects the parameter warning and assigns it to a Set coil (S). The instruction looks correct in the editor and compiles without warnings. The surprise is at the call site: when the FB is instantiated and the OUT parameter warning is wired to a global bit %M600.2, the generated code for that call site is:
// Pseudo-code generated by TIA Portal for one FB call
A #warning_condition // internal logic
S %M600.2 // Set coil assigned to the wired bit
Two such FB calls in the same OB each generate a S %M600.2 line. The CPU executes both lines, and the second one is redundant but harmless. The failure case is when the engineer also has a plain coil ( ) on the same bit elsewhere in the program (for example, a hand-operated override), or when the engineer uses a Reset coil (R) in the FB and a Set coil (S) in another FB, with no plain coil in sight. The compiler accepts both, but the editor flags the OUT parameter usage as "output parameter cannot be used bidirectionally" if you try to place both (S) and (R) on the same parameter inside the FB.
Test bit 14 (--|TEST|---) and Test bit 15 (--|TEST_N|---) are LAD debug instructions that do not generate any compiled output but can be used on inputs and outputs of an FB. They are a useful diagnostic but they do not modify the rule above; they merely let you force the visual state of a contact for testing.
4. The IN_OUT Parameter Solution
The IN_OUT (InOut) parameter category in the FB interface was designed exactly for this use case. An IN_OUT parameter is a reference (pointer) to a memory location in the caller's data scope. Inside the FB, the parameter behaves as both a read and a write target. The caller passes the address of the variable (not its value), and the FB can perform Set, Reset, assignment, or any bit-logic combination on that address without violating the coil-uniqueness rule, because the FB does not contain a coil at all - it contains references that resolve at call time to the same single address.
When two FB instances both pass %M600.2 as an IN_OUT parameter, the compiler sees one coil in the generated code per call site, but the target of that coil is the same memory bit. The Set instructions are functionally redundant, but the Reset instruction from the last-deactivated alarm block correctly clears the bit, and any new activation re-sets it. This is exactly the OR-aggregator behavior the alarm logic requires.
5. Step-by-Step Implementation
The following procedure converts an alarm FB that uses OUT parameters to the IN_OUT pattern. The example uses an S7-1500 CPU with TIA Portal V18, but the same steps apply to S7-1200 V4.4 and later.
- Open the FB in the project tree under Program Blocks > System Blocks > [FB number].
- In the FB interface (top section of the editor), locate the OUT parameters named
warningandalarm. - Change the Name if you want to distinguish the in-out reference (for example, rename to
warning_ioandalarm_io) to make the call sites self-documenting. - Change the Data type to
Bool(it should already be Bool for this pattern). - Change the Section from
OutputtoInOutusing the dropdown in the interface column. - Save the FB. The instance DBs of all existing calls will lose their wiring on these parameters; this is expected.
- Re-open each call site (OB1 or the alarm-cyclic OB) and re-wire the IN_OUT pins to the global bit symbols
"Warning_Aggregate"(tag%M600.2) and"Alarm_Aggregate"(tag%M600.4). - Inside the FB, replace the Set/Reset coils on the OUT parameters with the latch pattern in section 6.
- Compile the project (Project tree > right-click CPU > Compile > Software (rebuild all blocks)).
- Download to the CPU and observe the online value of
%M600.2with Monitor & Force > Monitor all.
For the Reset side (clearing the aggregate bit when no alarm is active), the call site must still be able to perform a Reset. A common design is to expose a reset_pulse INPUT parameter on the FB and have the alarm-clear logic in the FB itself drive the Reset coil on the IN_OUT reference. The patterns in section 6 cover both cases.
6. Ladder Logic Patterns Inside the FB
Three reusable patterns cover virtually every alarm-aggregation need. The first pattern is the simplest and is the direct equivalent of the Set/Reset coil approach you started with.
6.1 Latch-on-Set, Latch-off-Reset (Direct Replacement)
// Network 1 inside Alarm_FB
A #condition_warning // internal OR of all warning triggers
S #warning_io // set the caller's bit
A #reset_pulse // one-shot pulse from caller's clear logic
R #warning_io // reset the caller's bit
This is the cleanest replacement for the original Set/Reset coil pair. The only change from the OUT-based version is that the target is now IN_OUT. The compiler allows multiple Set coils on the same IN_OUT reference because each Set is generated at a different call site, and the LAD uniqueness rule counts resolved operands, not references in the FB body.
6.2 OR-Aggregate Without Latch (Recommended for Self-Clearing Conditions)
// Network 1 inside Alarm_FB
A #condition_warning // current-cycle condition
= #warning_io // write 1 if active, 0 if not
For alarms that should track the current condition in real time (no latch), the IN_OUT parameter is simply assigned the OR of all triggers inside the FB. The call site does not need to manage a Reset; the bit is automatically cleared the cycle after the last trigger drops. This is the cleanest pattern for plant-floor annunciation where a momentary acknowledge is not required.
6.3 Latch with Operator Acknowledge (Most Common Industrial Pattern)
// Network 1: latch the warning on the rising edge of any trigger
A #condition_warning
FP #warning_edge // static edge flag in STAT section
S #warning_io
// Network 2: clear on operator acknowledge AND condition gone
A #acknowledge // INPUT parameter from HMI or pushbutton
A #condition_warning
FP #ack_edge // static edge flag in STAT section
R #warning_io
// Network 3: optional auto-clear when condition drops without ack
A #condition_warning // NOT condition
AN #warning_io // bit still latched
R #warning_io // not used; alarm requires explicit ack
Edge flags warning_edge and ack_edge must be declared in the Static (STAT) section of the FB as Bool. The FP (Flank Positive) instruction is --|P|-- in LAD. This pattern survives the transition from OUT to IN_OUT with no behavior change and is the recommended default for SIL-rated alarm blocks.
7. Inline SVG: Network Topology and Signal Flow
The diagram below shows how two FB instances aggregate into a single global memory bit through IN_OUT references, and how the call site reads the aggregated bit for HMI and output modules.
8. Alternative Patterns and When to Use Them
8.1 Global DB Word with Multi-Read Inside FB
Replace individual bit memory addresses with a global data block (DB) of type Bool array, for example "AlarmDB".warning[1..32]. The FB writes a single bit of the array via an IN_OUT parameter typed as a non-optimized DB reference. This pattern is preferred for S7-1500 with optimized block access disabled, and it gives symbolic names in the HMI without consuming bit memory.
8.2 Multi-Instance FB (S7-1500 Only)
The S7-1500 supports multi-instance FBs where one FB is called inside another FB and the static data of the inner FB is stored in the outer FB's instance DB. For alarm aggregation, the outer FB holds the OR-aggregator logic, and each inner alarm FB uses a STAT parameter of FB type. This eliminates the need for global bits entirely, at the cost of needing a call from a cyclic OB for each alarm type.
8.3 Word Status with Bit Extraction
For very large alarm counts (more than 32 per group), aggregate into a Word or DWord via IN_OUT parameters typed as WORD or DWORD, set the relevant bit inside the FB with bitwise OR, and let the HMI read the word for annunciation. The LAD OW (OR Word) instruction handles the aggregation; Set/Reset coils are not needed. This pattern is used in the Siemens S7-1500 standard library examples for alarm handling.
9. Verifying the Solution
After re-wiring the call sites and downloading, run the following verification sequence to confirm the fix and to detect any missed OUT-to-IN_OUT conversions.
- Open the project, right-click the CPU in the project tree, and select Compile > Software (rebuild all blocks). The compile must complete without errors. A warning about unused outputs is acceptable; an error about a duplicate coil on a bit address is not.
- Open the OB that calls the alarm FB. In the network view, confirm the IN_OUT pins of all instances are wired to the same global symbol
"Warning_Aggregate". - Go online with the CPU. In the FB instance DB, force the internal
condition_warningof one instance to TRUE. Observe%M600.2in the Monitor & Force table: it must be TRUE within one OB1 cycle. - Force the same condition TRUE in a second instance. Observe that
%M600.2remains TRUE; this confirms the Set coil from the second instance is honored. - Clear the first instance's condition. Observe that
%M600.2remains TRUE (the second instance still drives it). This is the correct OR-aggregator behavior. - Clear the second instance's condition. Observe that
%M600.2goes FALSE in the same cycle, provided the FB does not use a latch pattern. If the FB uses the latch pattern from section 6.3, drive theacknowledgeinput to TRUE and verify the bit clears. - Open the Cross References (right-click the bit
%M600.2> Go to > Cross References). Confirm that the bit appears as a target in exactly as many networks as there are alarm FB instances plus any external readers. The cross-reference count is the ground truth for the coil-uniqueness rule.
10. Troubleshooting Matrix
| Symptom | Likely Cause | Diagnostic | Fix |
|---|---|---|---|
| Second FB instance sets the same bit but the output does not activate | Parameter is still declared as OUT | Open the FB interface, check the Section column | Change Section from Output to InOut |
| Compiler error: "Duplicate coil on operand %M600.2" | Plain coil ( ) exists on the same bit in addition to the Set/Reset coils |
Cross-reference %M600.2, locate all ( ) instructions | Remove the plain coil or convert it to Set/Reset |
| Bit clears instantly after the alarm condition drops, even though the FB is supposed to latch | IN_OUT parameter is assigned with = instead of Set/Reset coils |
Open the FB body, check the instruction on the IN_OUT pin | Use the pattern in section 6.3 (FP + Set, FP ack + Reset) |
| After downloading, instance DB shows a "value invalid" indicator on the parameter | The IN_OUT wiring was not reconnected after changing the parameter section | Open the instance DB, check the parameter row for the wiring icon | Re-wire the IN_OUT pin at each call site |
| Compiler warning: "Temporary variable cannot be used as IN_OUT" | The call site is wiring a local TEMP variable as the IN_OUT argument | Open the call site, check the argument source | Wire a global symbol, instance DB tag, or I/O tag instead |
| Bit toggles every cycle (chatter) | FB writes the IN_OUT with = but the call site also writes the same bit with a coil |
Cross-reference the bit, look for any plain coil | Remove the conflicting coil at the call site; the IN_OUT is sufficient |
| Set bit from FB works, Reset bit from another FB does not | Compiler accepts the Set/Reset pattern but the Reset is in a network that is not scanned in the same OB | Open the call sites, confirm both FB calls are in the same OB or in OBs of the same priority class scanned every cycle | Move both calls to the same cyclic OB |
11. Migration Checklist: From OUT to IN_OUT
When you convert an existing project, work systematically to avoid leaving a parameter in a hybrid state. The following checklist has been used to convert plants with up to 600 alarm FBs in a single project.
- Inventory: list every FB that has a boolean output meant to be aggregated across instances. Tag each one with a project-tree note.
- Compile the project before any change; record the existing cross-reference counts for the affected bits. This is the baseline.
- For each FB, change the OUT parameter to IN_OUT in the interface editor. Save the FB.
- Re-wire the call sites. Use Go to > Cross References on the FB symbol to find every instance.
- Adjust the FB body to use one of the three patterns in section 6.
- Compile the project. No duplicate-coil errors should remain.
- Run the verification sequence in section 9 on at least one instance of each FB type.
- Download and run a watchdog test: force the alarm condition, observe the HMI, clear the condition, confirm the bit transitions match the new logic.
- Update the HMI tag list if the bit symbol changed.
- Document the change in the project change log with the firmware version, TIA Portal version, and the FB version stamp from the block properties.
12. Safety and Best-Practice Notes
- For SIL2 or SIL3 alarm paths, the latch-with-acknowledge pattern (6.3) is the only acceptable aggregation. Latch-on-OR (6.1) is acceptable for operational warnings that do not drive safety outputs.
- When the aggregated bit drives a hard-wired output (relay, contactor, indicator), use a non-optimized data block for the aggregate so that the address is visible in the wiring diagram and can be cross-checked with the hardware documentation. The SIMATIC S7-1200 System Manual describes optimized vs. non-optimized block access in detail.
- Do not use the same IN_OUT reference to drive both a Set coil in the FB and a plain coil in the call site. The compiler will accept it on S7-1500, but the runtime behavior is order-dependent and will change after a firmware update.
- Reserve the
%Mrange for aggregated alarms; keep per-instance latches in STAT so that the global bit memory map remains a clean summary of the plant state. The cross-reference display in TIA Portal will then show one row per alarm group rather than one row per alarm instance. - If the project is on TIA Portal V15.1 or earlier, the IN_OUT section was added for multi-instance calls only. Upgrade to V16 or later, or use the workaround of declaring a global DB and passing its element as an IN/OUT variable via the call site interface. The behavior is equivalent.
Why does my second FB instance Set bit not activate the output when both FBs wire to the same memory bit?
Because the parameter is declared as Output, the compiler generates a single coil at each call site, and the LAD editor enforces the rule that only one coil may target the same operand in a scan. Change the parameter section from Output to InOut in the FB interface; the compiler then sees references, not coils, and multiple instances can drive the same bit correctly.
What is the difference between an OUT parameter and an IN_OUT parameter in a TIA Portal FB?
An OUT parameter is a value the FB writes; the caller sees the value after the FB returns. An IN_OUT parameter is a reference (pointer) the caller hands to the FB; the FB can read and write the caller's variable in the same scan. Use OUT when the caller only needs the result; use IN_OUT when the caller and the FB must share state, as in an alarm aggregator.
Can I use a Set coil (S) on an IN_OUT parameter inside the FB and a Reset coil (R) on the same IN_OUT parameter in a different FB?
Yes. Each call site generates a Set or Reset instruction on the resolved operand, and the compiler accepts multiple Set and multiple Reset instructions on the same operand provided no plain coil ( ) is present. The last Reset in the scan wins, and any new Set in the same scan re-asserts the bit. This is the canonical OR-aggregator with latched acknowledge pattern.
How do I clear the aggregate alarm bit when the last alarm condition goes away?
Two approaches are common. (1) Inside the FB, write the IN_OUT with a plain assignment = driven by the current-cycle condition; the bit is automatically cleared the cycle after the last condition drops. (2) Use a dedicated Reset INPUT parameter and have the FB drive a Reset coil (R) on the IN_OUT when the operator acknowledges; the FB then latches until the operator acts. The choice depends on whether the alarm must be acknowledged (SIL convention) or is self-clearing.
Does this pattern work on S7-1200 as well as S7-1500?
Yes. IN_OUT parameters have been supported in both families since the introduction of TIA Portal. The S7-1200 requires firmware V4.4 or later for full multi-instance and IN_OUT semantics on optimized blocks; earlier firmware accepts IN_OUT only on non-optimized blocks. Confirm your firmware version under Online & Diagnostics > Diagnostics > Module Information if the compiler reports an unsupported feature.
Why does my HMI show the aggregated warning but the physical output on the DO module does not energize?
The aggregated bit is wired to a %M (memory) address; the DO module reads from the process image of the outputs, not from memory bits. You must add a network that assigns the %M bit to a %Q (output) address or to a tag exposed to the DO module. A typical pattern is A "Warning_Aggregate"; = %Q0.2 in a network that runs every cycle. The cross-reference view in TIA Portal will confirm whether the %Q is being driven.