1. Problem Definition — Safety Coil Tag Cannot Be Reused as a Logic Condition
Engineers programming SIMATIC S7-1200F and S7-1500F controllers in TIA Portal V15.1 routinely hit a compile-time restriction inside the F-runtime group: a safety tag that has been assigned to an output coil in one network cannot subsequently be evaluated as a normally open (NO) or normally closed (NC) contact in another part of the safety program. The F-Compiler refuses to build the F-block and raises an error similar to one of the following:
Address <F-Tag> is used in more than one assignmentSafety address <F-Tag> cannot be read because it is already assigned to an outputTag <symbolic name> is used in an output and may not be used as input
The compilation of the safety program halts, the offline/online comparison flags the F-block as "Safety program inconsistent," and the project cannot be downloaded to the F-CPU. The download of the standard (non-safety) program is still permitted, but the safety portion remains blocked, which effectively stops commissioning of any SIL 2 / SIL 3 / PL d / PL e path that depends on that logic.
2. Safety Program Architecture in TIA Portal V15.1
Before discussing the workaround, it helps to recall the boundaries of an F-program as defined in the SIMATIC S7-1500F System Manual:
| Element | Location | Read/Write from F-Program | Direct I/O Access |
|---|---|---|---|
| F-runtime group (OB123 / OB35) | F-OB or cyclic F-OB | Hosts all safety logic | Not allowed |
| F-shared DB | Project tree → Program blocks | Read/Write permitted | N/A |
| Instance DB of a safety FB (e.g. FDBACK, ESTOP1, F_SFDOOR) | Auto-generated on FB call | .Q, .ACK, .Q_FDBACK readable | N/A |
| F-IO DB (F-DI, F-DO, F-AI) | Auto-generated per F-I/O module | .IN, .OUT, .QBAD, .VAL readable | Mandatory proxy |
| Standard tags, standard DBs, I/O | Standard program | Hidden — F-program cannot read | Not allowed |
The F-Compiler tracks every assignment (coil) of a writable F-tag. As soon as a tag is written by an output coil, the F-Compiler registers that tag as bound. The binding is global within the F-runtime group, not network-local, which is why reusing the same tag as a contact anywhere else in the F-program — even several networks below — is rejected.
3. Root Cause — Why the F-Compiler Enforces the Single-Assignment Rule
The restriction is not a TIA Portal quirk; it is a direct consequence of the safety integrity requirements documented in IEC 61508 and IEC 62061. A single F-tag that is both written by a coil and read by a contact can introduce a hidden feedback path. If the read precedes the write within the F-cycle, the contact evaluates with the value of the previous cycle; if the read follows the write, it evaluates with the current value. Either timing is permissible for a non-safety program, but inside a safety program the compiler must be able to prove, statically, that the program is single-assignment: every F-tag has exactly one driver, and that driver's output determines the tag value for the rest of the cycle.
The three formal reasons TIA Portal V15.1 enforces the rule:
- Static single-assignment analysis. The F-Compiler performs a graph analysis over the F-runtime group. A tag with two writers (a coil and a network using it as a contact whose result is later assigned) breaks the SSA form and is rejected.
- Passivation determinism. When an F-I/O channel is passivated, the F-IO DB substitutes the last valid value or a configured substitute value. If the same tag were also used in a feedback network, the passivation semantics would be ambiguous. The compiler avoids that ambiguity by forbidding reuse of coil-bound tags.
- Signature integrity. Every F-block has a CRC signature stored in the F-CPU. The signature is generated from the compiled code. Allowing a single tag to be both driven and read would require the compiler to introduce an implicit wire between two networks, which violates the assumption of the signature algorithm that the same input always produces the same output.
4. Solution 1 — Use the Safety FB Instance .Q Output
The cleanest fix, and the one recommended by Siemens in the F-runtime group help, is to read the instance DB static that the safety FB already exposes. Every safety FB in the S7-1500F / S7-1200F Safety Library publishes at least one boolean output that reflects the state of the block:
| Block | Instance Static | Meaning | Usable as Contact? |
|---|---|---|---|
| ESTOP1 / ESTOP1_3 | .Q |
Output of the e-stop logic | Yes (read-only) |
| F_SFDOOR |
.Q, .Q_DOOR
|
Door-closed AND acknowledge | Yes |
| FDBACK (feedback monitoring) |
.Q, .Q_FDBACK
|
Output state, feedback quality | Yes |
| F_2HAND2 | .Q |
Two-hand consensus output | Yes |
| F_MUT_P / F_MUT_M |
.Q, .MUT_ON
|
Muting-active flag | Yes |
| F_LOCK |
.Q, .ACK
|
Lock state and acknowledge | Yes (read-only) |
The instance DB is generated by TIA Portal when the safety FB is called from the F-runtime group. The compiler never tags an instance static as bound unless the same static is also written explicitly by a coil in the safety program. The published outputs are written by the FB body, not by user logic, and are therefore safe to read from any other F-network.
Step-by-step:
- Open the F-block that calls the safety FB (for example, FB_SafetyMain).
- Locate the call of the safety FB (e.g.,
iDB_FDBACK_1instance DB). - In the consuming network, drag the
<instance_DB>.<output>static onto a contact, e.g."iDB_FDBACK_1"."Q". - Compile the F-runtime group. The Address used in more than one assignment error no longer appears because no user-coil assignment touches that static.
5. Solution 2 — Mirror the Coil Value into an F-Shared DB Tag
If the value you need is not a published instance static (for example, you have written a custom safety function inside a customer FB and need to share an intermediate result), mirror the coil value into a dedicated F-shared DB tag and read that mirror in the consuming network.
Create an F-shared DB:
- Project tree → Program blocks → Add new block → Data block.
- Set the Type to F-DB (F-shared DB). The block will be flagged with the yellow safety ribbon.
- Add a
BOOLtag, e.g."safetyOkMirror"with Initial valueFALSE.
Wire the coil and the mirror in two separate networks inside the F-runtime group. The original coil drives the output module; the mirror network simply copies the value with no further logic:
// Network 1 — original output (unchanged)
safetyOk
---| |--------( / )--<output to F-DO channel>
// Network 2 — mirror, read-only tag
iDB_Estop1.Q
---| |----------------( )--"safetyMirror" // F-shared DB tag
Rules to keep the F-Compiler happy:
- The mirror tag must be assigned in exactly one network by a coil. Do not write to it anywhere else.
- Any consumer of the mirror must use it as a read-only contact; never assign to it again.
- The mirror network must not introduce a logical dependency that creates a loop with the original network — for example, do not let the mirror feed back into the condition of the original coil.
6. Solution 3 — Indirect Access via the F-IO DB (Passivation Status)
For the specific case where the coil was driven by an F-I/O channel, read the F-IO DB instead of the process image. TIA Portal generates a unique F-IO DB for every F-I/O module (PROFIsafe or PROFIsafe-over-PROFINET). The DB contains:
| F-IO DB Static | Type | Meaning |
|---|---|---|
IN[n] / OUT[n]
|
BOOL | Channel process value |
QBAD[n] / QBAD_I[n]
|
BOOL | Channel bad / passivated |
VAL[n] |
BOOL | Validity flag (1 = valid, 0 = substitute) |
ACK_NEC |
BOOL | Acknowledgment required after passivation |
DIAG[n] |
WORD | Channel diagnostic |
The F-IO DB itself is not a tag in the symbol table; it is a system-managed data block. You can place contacts on "F-IO-DB_4"."IN0" directly in the F-runtime group, but you cannot assign to those contacts (no coils permitted on F-IO DB inputs). That asymmetry is precisely what allows the read to be safe: the F-IO DB is updated by the F-CPU's safety firmware, not by user logic.
For the consuming condition in your example, the correct contact is:
// F-runtime group — read passivation status of the same F-DI
"F-IO-DB_DI16_1"."VAL0" // 1 = input value is valid
---| |----------------( ACK_NEC )--"ackRequired" // F-shared DB mirror
7. Solution 4 — Use the F-Application Error OB (OB82)
If the reason you were reusing the tag was to react to a passivation event, the proper mechanism is OB82 (or its F-program equivalent, the F-application error handler), not a coil-and-contact chain. OB82 is called by the F-CPU when an F-I/O reports an error, when the PROFIsafe connection drops, or when the F-runtime group cycle time is exceeded. Inside OB82 you can:
- Set a global F-tag to indicate that the safety path is in a "reintegration required" state.
- Log the
OB82_FLT_IDandOB82_IO_FLAGbytes for diagnostics. - Trigger an operator acknowledgment that re-enables the affected F-I/O.
OB82 is read-only with respect to F-IO DB values; it cannot assign to the same tag that you wanted to read, so the SSA restriction does not apply.
8. Worked Example — FDBACK Block on an S7-1500F
The original symptom is most often encountered around a FDBACK block used for contactor monitoring. A typical TIA Portal V15.1 pattern is:
// Network 10 — call FDBACK
"iDB_FDBACK_1"( // FB215 from Safety library V15.1
ACK := "ackButton",
FDBACK := "contactorAux", // contactor mirror contact (F-DI)
Q => "fb_Q", // FAILS — same tag reused below
Q_FDBACK=> "fb_QFbk");
// Network 20 — reuse "fb_Q" as a contact — BLOCKED by F-Compiler
"fb_Q"
---| |----------------( enableDownstream ) // <-- compiler error
Apply Solution 1 by reading the instance static directly:
// Network 10 — call FDBACK (no user coil on .Q)
"iDB_FDBACK_1"(
ACK := "ackButton",
FDBACK := "contactorAux");
// Network 20 — read .Q as a contact
"iDB_FDBACK_1"."Q"
---| |----------------( enableDownstream ) // OK
Apply Solution 2 when the value is computed by a custom safety function block and no instance static is available:
// Network 10 — original output coil
"safetyOk"
---| |--------( / )--"doChannelOK" // F-DO channel
// Network 11 — explicit mirror network
"safetyOk"
---| |----------------( )--"safetyOkMirror" // F-shared DB
// Network 20 — consume the mirror as a contact
"safetyOkMirror"
---| |----------------( enableDownstream ) // OK
The two networks are read in the F-cycle in order, and the mirror is the only writer of "safetyOkMirror". SSA is preserved.
9. Verification & Commissioning
After applying one of the workarounds, validate with the following checks in TIA Portal V15.1:
- F-Compiler clean build. Project tree → right-click the F-CPU → Compile → Software (rebuild all blocks). Confirm no F-block warning or error entries in the inspector window.
- Safety signature. Open the F-block properties; the safety CRC must be regenerated and must match the CRC stored in the F-CPU after download. A mismatch prevents the F-CPU from going to RUN.
- Online watch on the mirror. In the F-runtime group, open Monitor & force with the F-CPU in RUN. Toggle the input that drives the original coil and confirm the mirror tracks within one F-cycle (typically 5–50 ms on S7-1500F).
-
Passivation test. Disconnect the PROFIsafe cable on the F-DI feeding the contactor. Confirm:
- The F-IO DB
QBADfor the channel goes to 1. - The output coil de-energizes within the configured F-cycle time.
- The mirror tag tracks the passivated value (substitute or last valid, depending on configuration).
- Reconnecting the cable requires operator acknowledgment (
ACK_NEC= 1) before the F-DI is reintegrated.
- The F-IO DB
- Trace recording. Use Trace on the F-runtime group to capture the coil, the mirror, and the consuming contact across a forced error. The trace must show the consumer contact following the mirror within one cycle, never leading it.
- F-password. Re-protect the F-block with the same F-password used during development. An unprotected F-block will not run on a configured F-CPU.
10. Platform Comparison — How M580 Safety and GuardLogix Handle the Same Pattern
The same logical pattern — a tag driven by a coil and wanted as a contact downstream — is also restricted on competing safety platforms. The mechanism differs, but the underlying single-assignment invariant is identical.
| Platform | Compiler Behavior | Recommended Workaround | Reference |
|---|---|---|---|
| Siemens S7-1200F / S7-1500F, TIA Portal V15.1 | F-Compiler rejects any F-tag written by a coil and read as a contact in the same F-runtime group | Read instance static .Q / mirror in F-shared DB / read F-IO DB |
S7-1500F System Manual |
| Schneider M580 Safety, Control Expert / EcoStruxure | When the EN input of a safety EF is disabled (EN = 0), its output link keeps its previous value even if it should be set to 0 per the project settings. Reusing the same safety variable as both output and condition can mask this latching behavior | Use the EF .Q output; do not reuse the same safety variable for both assignment and consumption |
Schneider FAQ000192199 |
| Allen-Bradley GuardLogix, Studio 5000 / Logix Designer | Safety tags in a safety task are also subject to single-assignment analysis. The Safety Tag that is the operand of an output cannot be evaluated as a contact elsewhere in the safety task | Use the BOOL output of the safety instruction (e.g. EMSO, DCSTO, CROUT) or alias the tag through a safety Add-On Instruction |
Rockwell KB 1085146 |
The common thread: every IEC 61508-certified runtime enforces single-assignment of safety tags at compile time, and every workaround involves an explicit, named read-only output that the safety firmware publishes.
11. Common Pitfalls and Field-Proven Caveats
- Forgetting to re-protect the F-block. After the recompile, the F-password prompt must be entered again or the F-CPU will refuse the download with Safety program: F-block not protected.
- Mirroring into a standard DB. A standard (non-F) DB cannot be read from an F-runtime group. The mirror must live in an F-shared DB with the safety ribbon in TIA Portal V15.1.
-
Cascading the mirror. Do not let
safetyOkMirrorfeed back into a condition that drives the original coil; that creates a real feedback loop and the F-Compiler will still reject it. -
Using
OB1as a workaround. It is tempting to read the coil in a standard cyclic OB and write the result into a global F-shared DB tag. This crosses the F/standard boundary in the wrong direction; the F-Compiler will flag the F-shared DB tag as having an external writer. - Forgetting F-cycle time. A mirror adds one network of scan time. On S7-1200F, keep the F-cycle below 50 ms; on S7-1500F, below 10 ms for SIL 3 paths. Use the F-Runtime Group Properties → Cycle Time dialog to verify.
- Reusing the tag name in two different F-runtime groups. Each F-runtime group has its own SSA analysis. A tag that is a coil in group 1 and a contact in group 2 is still rejected by the F-Compiler across the whole F-program of the F-CPU.
12. FAQ
Why does TIA Portal V15.1 block a safety tag that was just used as a coil?
Because every safety tag must be single-assigned inside the F-runtime group. Reusing a coil-bound tag as a contact introduces a hidden feedback path that the F-Compiler's static single-assignment analysis cannot prove safe under IEC 61508. The workaround is to read the safety FB's instance static .Q output, or to mirror the value into a dedicated F-shared DB tag written by exactly one coil and read everywhere else.
Can I use the standard process image (I/Q) of a safety output in the F-program?
No. Direct access to %I and %Q addresses is forbidden inside an F-runtime group in TIA Portal V15.1. Safety I/O must be read and written through the auto-generated F-IO DB of the F-DI/F-DO module (statically IN[n], OUT[n], QBAD[n], VAL[n]). The F-IO DB is updated by the F-CPU's safety firmware, which is what makes the read deterministically safe.
Does the same restriction apply to S7-1200F and S7-1500F?
Yes. The F-Compiler rules in TIA Portal V15.1 are the same for both families. The only differences are the available safety library blocks (the S7-1500F library is larger and includes blocks like FDBACK, F_SFDOOR, F_MUT_P, F_LOCK, F_2HAND2) and the F-cycle time limits (50 ms on S7-1200F, 10 ms on S7-1500F for SIL 3).
Will a mirror tag in an F-shared DB affect the SIL rating?
No, as long as the mirror is a pure Boolean copy with no additional logic and the original safety decision is made in the network that contains the safety FB. The mirror is treated by the F-Compiler as a standard F-tag with one writer and multiple readers, which is a valid SSA pattern. The safety signature still covers the mirror network, so any change to it is detected by the F-CPU at download time.
How do I react to a passivation event without using a coil-and-contact chain?
Use OB82 (F-application error OB) in the F-runtime group. OB82 is called when an F-I/O reports an error or when the PROFIsafe connection drops. Inside OB82 you can set an F-shared DB tag, log the OB82_FLT_ID byte, and trigger an operator acknowledgment. OB82 cannot assign to the coil that drove the original output, so the SSA restriction does not apply.
Does the same problem exist on Schneider M580 Safety and Allen-Bradley GuardLogix?
Yes. On M580 Safety in Control Expert, reusing a safety variable as both an EF output and a contact downstream can mask the latching behavior described in Schneider FAQ000192199. On GuardLogix in Studio 5000, safety tags are also single-assigned within the safety task. The same workaround pattern — read the instruction's published output or alias through a safety Add-On Instruction — applies on all three platforms. See also the related Allen-Bradley documentation on coil vs. coil-with-PLC-input for size 4 contactors at Rockwell KB 1085146.