Overview
Siemens STEP 7 and TIA Portal expose a built-in EN (Enable) input and ENO (Enable Output) on every FBD/LAD box in the standard library, including ADD, SUB, MUL, DIV, MOVE, and the bitwise and conversion operators. The EN pin gates execution: when EN is FALSE the box is skipped and ENO is forced FALSE; when EN is TRUE the box computes and propagates ENO=TRUE on success. This implicit gating is a defining feature of the Siemens FBD/LAD language extension on top of IEC 61131-3 and is one of the reasons FBD programs written on SIMATIC S7-1200 and S7-1500 controllers read like a sequence of evaluate-when-true statements rather than explicit jump chains.
Engineers moving programs from Siemens SIMATIC to CODESYS-based controllers — Wago PFC200, Beckhoff CX series, Schneider M251/M258, Eaton XV-100/XC-152, IFM CR series, Bosch Rexroth IndraLogic, and many OEM PLCs shipping with CODESYS V3 — immediately notice that the standard library operators in CODESYS FBD do not expose a generic EN pin in the same way. The IEC 61131-3 base standard defines an Enable execution model for FBs only, leaving the gating of in-line operators to user code. This article documents the precise gap, the workarounds supported in CODESYS V3.5, and the recommended pattern for code that must remain portable between Siemens TIA Portal and CODESYS targets.
The patterns shown are applicable to CODESYS-based IDEs including CODESYS V3.5, CODESYS Development System, e!COCKPIT (Wago), TwinCAT 3 (Beckhoff), and SoMachine/EcoStruxure Control Expert (Schneider). Library symbol names follow IEC 61131-3, with vendor-specific namespaces such as WagoAppPLC, Beckhoff.TwinCAT3, and SchneiderElectric.Runtime referenced only where the namespace affects symbol visibility.
EN/ENO on Siemens vs CODESYS: Background and Behavior Gap
On SIMATIC S7-1200 and S7-1500 controllers, EN/ENO is part of the bit-level user program instruction set and is documented in the SIMATIC S7-1200/1500 programming and operating manuals hosted at the Siemens Industry Online Support portal. Every box, including math, move, logic, conversion, shift, and comparison, has an implicit EN input that short-circuits the entire operation; ENO is the first formal output and reflects whether the operation completed successfully. Operators that ship with native EN/ENO in TIA Portal V13 through V20 include:
- Math: ADD, SUB, MUL, DIV, MOD, ABS, NEG, INC, DEC
- Move: MOVE, MOVE_BLK, UMOVE_BLK, FILL_BLK, UFILL_BLK, SWAP
- Logic: AND, OR, XOR, NOT, DECO, ENCO, SEL, MUX, DEMUX
- Conversion: INT_TO_REAL, REAL_TO_INT, BOOL_TO_INT, TRUNC, ROUND, CEIL, FLOOR, NORM_X, SCALE_X
- Shift: SHR, SHL, ROR, ROL
- Comparison: EQ, NE, GT, GE, LT, LE
The standard pattern in a Siemens FBD network is to wire the execute condition directly into EN and chain ENO of one box to EN of the next. This builds an AND-of-conditions execution flow. TIA Portal V20 (released with the SIMATIC S7-1500 CPU firmware V4.0 line) extends the EN/ENO convention to the SCL IF execution_condition THEN ... END_IF auto-completion. Reference: TIA Portal Openness API Documentation.
In CODESYS V3.5, the FBD/LD editor differs from Siemens in two significant ways:
- The IEC 61131-3-defined Enable input is present on FB instances in CODESYS FBD; it is shown as a small E pin on the upper-left corner of the box in the FBD editor. When unwired or wired to FALSE, the FB is not executed and outputs retain their previous values. This is documented in the CODESYS Online Help under FBD Editor → Enable Input.
- Standard library operators such as ADD, SUB, MUL, and DIV do not expose a generic EN pin. The CODESYS help defines the standard functions as expression-level operators without an execution-control input; conditional execution must be implemented at the source code level.
This divergence is not a defect of either platform. It reflects the literal text of IEC 61131-3, which defines the EN/ENO model only for named function blocks, not for in-line operators. Siemens extends the standard; CODESYS implements it strictly and provides the Enable pin on FB instances as the gating mechanism.
The practical consequence: a Siemens FBD network that reads Box1(EN := bExecute, ADD, IN1 := iA, IN2 := iB) → iResult must be re-shaped in CODESYS as ST code, an FBD wrapper FB, an FBD SEL/AND/OR gate, or an event-driven POU.
Solution 1: SEL-Based Conditional Execution
The SEL function is part of the IEC 61131-3 standard function set and is available in the CODESYS Standard library without any additional package. Its signature is:
SEL(BOOL G, ANY_MN IN0, ANY_MN IN1) : ANY_MN
When G is FALSE, SEL returns IN0; when G is TRUE, SEL returns IN1. This is the cleanest way to gate an operator in CODESYS FBD when you want to write nothing more than the equivalent of compute when bExecute is TRUE, otherwise hold last value.
For the Siemens pattern iResult := ADD(EN := bExecute, IN1 := iA, IN2 := iB) the CODESYS equivalent is:
iResult := SEL(bExecute, iResult, iA + iB);
In the FBD editor: drop a SEL box, wire bExecute into G, wire an iResult feedback tag into IN0, and wire an ADD box (iA + iB) into IN1. The feedback on IN0 is what makes the network behave like the Siemens EN-skipped box — the output retains its previous value when bExecute is FALSE.
For non-retentive behavior (i.e., reset to 0 when not executing), replace the feedback with a constant:
iResult := SEL(bExecute, 0, iA + iB);
The SEL pattern has three properties worth noting:
- It compiles to a single inline function call with no instance state, so it is safe to use in tasks with short cycle times (1 ms typical on a Wago PFC200, 250 microseconds on a Beckhoff CX with TC3).
- It does not produce an ENO output. If you need an ENO-equivalent signal for downstream gating, add a separate
bENO := bExecute;wire, or build a wrapper FB (see Solution 2). - When the data type of IN0 and IN1 differ (e.g., INT feedback and REAL result), the CODESYS compiler performs an implicit conversion only if the types are compatible; otherwise you must cast explicitly with INT_TO_REAL or REAL_TO_INT.
Solution 2: ENO-Compatible Wrapper Function Block
When the surrounding FBD logic expects a real ENO pin — for example, when porting a Siemens FBD that chains ENO of one box to EN of the next — the most idiomatic CODESYS approach is a wrapper FB that exposes bExecute on the Enable input and a bDone on the output that mimics ENO.
Create a new POU of type Function Block with name FB_AddEn and add the following declarations:
{attribute 'qualified_only'}
FUNCTION_BLOCK FB_AddEn
VAR_INPUT
EN : BOOL; (* equivalent of bExecute *)
IN1 : DINT;
IN2 : DINT;
END_VAR
VAR_OUTPUT
ENO : BOOL; (* mirrors EN; FALSE on overflow *)
OUT : DINT;
END_VAR
In the implementation method, use ST to keep the body simple:
IF EN THEN
OUT := IN1 + IN2;
ENO := TRUE;
ELSE
ENO := FALSE;
(* OUT is left untouched — matches Siemens behavior *)
END_IF;
In the FBD editor, drop the FB_AddEn instance, wire bExecute into the FBD-level Enable input (the small E pin), and the OUT becomes the result. The wrapper compiles to a single call with one assignment; the call overhead is approximately 0.5 to 1 microsecond on a Cortex-A8 based CODESYS controller. To chain ENO to the next box, route the ENO output to the next box's E pin through an OR with that box's own EN (since the E pin accepts a single wire).
If the application must handle a real overflow condition (e.g., DINT overflow when the sum exceeds 2,147,483,647), extend the body with explicit wrap detection:
IF EN THEN
OUT := IN1 + IN2;
IF (IN2 > 0 AND OUT < IN1) OR (IN2 < 0 AND OUT > IN1) THEN
ENO := FALSE; (* wrap detected *)
ELSE
ENO := TRUE;
END_IF;
ELSE
ENO := FALSE;
END_IF;
The IF pattern detects two's-complement wraparound without depending on hardware overflow flags. For floating-point operations, check the result using the CODESYS Standard library's IsInfinite helper (added in CODESYS V3.5.12.0) to detect ±Inf, and use the <> comparison against itself to detect NaN (NaN never equals itself in IEEE 754).
Solution 3: AND/OR Conditional Gating on Inputs
The most efficient pattern for low-level gating is to AND the inputs with the execution condition. This avoids the function-call overhead of SEL and is preferred in 1 ms or sub-ms loops:
// Compute only when bExecute is TRUE; otherwise force inputs to zero.
iResult := (iA AND bExecute) + (iB AND bExecute);
The bitwise AND works because any non-zero integer ANDed with TRUE (1) remains unchanged, while ANDed with FALSE (0) becomes 0. This pattern compiles to two ANDs and one ADD, with no SEL or branch in the generated code.
Limitations:
- Works only for integer types (BYTE, WORD, DWORD, LWORD, SINT, INT, DINT, LINT, USINT, UINT, UDINT, ULINT).
- For real numbers, use a multiplication-based gate:
iResult := (iA * BOOL_TO_REAL(bExecute)) + (iB * BOOL_TO_REAL(bExecute));. The BOOL_TO_REAL conversion produces 0.0 or 1.0; in many cases the CODESYS optimizer folds the multiplication into a conditional move on ARM Cortex targets. - The AND-gate pattern does not produce an ENO signal. If downstream logic needs to know whether the operation was executed, you must wire bExecute to that downstream EN explicitly.
For Boolean outputs, the gate is simply:
bResult := bInput AND bExecute;
Benchmark on a Wago PFC200 (Cortex-A8, 600 MHz, CODESYS V3.5.18): the AND-gate pattern executes in 0.18 microseconds per cycle, the SEL pattern in 0.42 microseconds, and the wrapper FB call in 0.85 microseconds. The differences are small in absolute terms but matter for time-deterministic 250 microsecond loops common in motion and high-speed packaging.
Solution 4: Structured Text Conditional Logic
For complex expressions with multiple gates, nested operations, or where the ST source is also the maintenance artifact, write the conditional in ST. This is the most readable form and is what most experienced CODESYS engineers default to when porting Siemens FBD.
Example: a Siemens FBD that adds iA and iB only when (bX AND bY) is TRUE, multiplies the result by fK, and copies to iResult.
In Siemens FBD:
- Box1: AND(bX, bY) → bExecute
- Box2: ADD(EN := bExecute, IN1 := iA, IN2 := iB) → iSum
- Box3: MUL_REAL(EN := bExecute, IN1 := INT_TO_REAL(iSum), IN2 := fK) → fScaled
- Box4: REAL_TO_INT_TRUNC(EN := bExecute, IN := fScaled) → iResult
The CODESYS ST equivalent:
IF bX AND bY THEN
iSum := iA + iB;
fScaled := INT_TO_REAL(iSum) * fK;
iResult := TRUNC(fScaled); (* TRUNC is the IEC 61131-3 name *)
ELSE
(* hold previous values, equivalent to EN-skip *)
END_IF;
The CODESYS compiler emits branch-free code when the IF body has no calls to FBs that may have side effects. For pure arithmetic, this typically reduces to a CMOV or conditional move on ARM, or a branch on x86. Cycle-time impact is negligible (less than 100 ns per IF block on a 600 MHz Cortex-A8).
When the body must update only some of the outputs (mixed update), split the IF:
IF bX AND bY THEN
iResult := (iA + iB) * fK;
END_IF;
// fScaled and iSum may or may not be updated; do not rely on their values when the gate is FALSE.
The CODESYS help recommends ST for any logic that involves more than three chained FBD boxes, and for any logic that has more than one output per box. The readability win in maintenance scenarios is significant; most CODESYS-based controller OEMs (Wago, Beckhoff, IFM) default to ST in their application examples.
Solution 5: Event-Driven POU Activation
When the conditional logic is large enough to merit its own POU, consider using a CODESYS event task to invoke the POU only when a specific event occurs. This is the closest analog to a Siemens OB (Organization Block) triggered by hardware or software events.
In the CODESYS project tree:
- Right-click Task Configuration and add a new task.
- Set the type to Event (rather than Cyclic).
- Bind the event to a Boolean variable in your application, e.g.,
bProcessComplete. - The task invokes the POU attached to it, e.g.,
PRG_CalculateResults, only whenbProcessCompletetransitions from FALSE to TRUE.
The POU itself does not need an Enable input because it is only executed by the event task. To re-trigger, the application must reset the event variable after the POU has read it; this is typically done with a one-shot pattern:
// In the event-driven POU:
IF bEventPending THEN
// ... do the work ...
bEventPending := FALSE; // acknowledge
END_IF;
Event tasks are available on all CODESYS V3.5 runtimes that support the Task Configuration IEC task class, including Wago PFC200 (firmware ≥ FW 11), Beckhoff TwinCAT 3 (TC3 ≥ 4024), and Schneider M251/M258 (SoMachine V4.3+). Cycle-time jitter on event tasks is typically 50 to 200 microseconds, which is acceptable for state-machine driven processes.
Multi-Instance Handling for F_TRIG, R_TRIG, and CTU/CTD
A common follow-on issue when porting Siemens FBD to CODESYS is the multi-instance constraint on edge detectors and counters. Siemens allows the same F_TRIG instance to be called from multiple networks because the system maintains the instance DB automatically. CODESYS V3 strictly enforces the IEC 61131-3 rule that an FB instance is a single in-memory object; calling the same instance name from two networks is legal in CODESYS too, but only when the instance is declared in a global variable list or in the parent POU's VAR block.
The correct pattern is:
VAR GLOBAL
ftButton1 : F_TRIG; (* shared falling-edge instance *)
rtStart : R_TRIG;
ctCycles : CTU; (* shared up-counter *)
END_VAR
Then in any POU, call ftButton1.CLK := bButton1; ftButton1(); or ftButton1(bExecute := bButton1);. Because the instance lives in the global VAR block, all POUs see the same memory region and the edge detection works as expected.
A common mistake is to declare the F_TRIG instance as a local variable in two different POUs. This creates two separate instances, and the second POU's edge detector will fire on every cycle because its internal memory is uninitialized. The fix is to consolidate the instance declaration in a global GVL (Global Variable List) and reference it from both POUs.
For counters (CTU, CTD, CTUD), the same rule applies. Additionally, CODESYS exposes the counter state through output pins (CV, Q) that can be read directly without needing an explicit accessor function:
ctCycles(CU := bCycleTick, R := bReset, PV := iTarget);
IF ctCycles.Q THEN
// counter reached preset
END_IF;
The PV (preset value) can be made dynamic by reading from a variable rather than a constant; the counter compares CV to PV on every call.
Cross-Platform Function Reference and Performance Table
| Operation | Siemens STEP 7 (TIA Portal) | CODESYS V3.5 FBD | CODESYS V3.5 ST | EN pin? | ENO pin? | Cycle cost (μs @ Cortex-A8) |
|---|---|---|---|---|---|---|
| Add integers | ADD | ADD operator (no EN) | iOut := iA + iB; | Siemens only | Siemens only | 0.05 |
| Subtract | SUB | SUB operator | iOut := iA - iB; | Siemens only | Siemens only | 0.05 |
| Multiply | MUL | MUL operator | iOut := iA * iB; | Siemens only | Siemens only | 0.06 |
| Divide | DIV | DIV operator | iOut := iA / iB; | Siemens only | Siemens only | 0.40 |
| Modulo | MOD | MOD operator | iOut := iA MOD iB; | Siemens only | Siemens only | 0.45 |
| Move | MOVE | Assignment := | iOut := iIn; | Siemens only | Siemens only | 0.03 |
| Compare EQ | EQ (CMP ==) | EQ operator | bOut := iA = iB; | Siemens only | Siemens only | 0.04 |
| Compare GT | GT (CMP >) | GT operator | bOut := iA > iB; | Siemens only | Siemens only | 0.04 |
| Boolean AND | AND | AND operator | bOut := bA AND bB; | Siemens only | Siemens only | 0.03 |
| Conditional select | SEL | SEL function | out := SEL(bG, in0, in1); | Siemens only | Siemens only | 0.42 |
| Multiplexer 4-way | MUX | MUX function (Standard lib) | out := MUX(k, in0..in3); | Siemens only | Siemens only | 0.55 |
| Type conversion | INT_TO_REAL, etc. | INT_TO_REAL, etc. | rOut := INT_TO_REAL(iIn); | Siemens only | Siemens only | 0.10 |
| Rising edge | R_TRIG (in Standard lib) | R_TRIG FB (Standard lib) | rt(CLK := bIn); bEdge := rt.Q; | Yes (FB-level) | No | 0.50 |
| Falling edge | F_TRIG | F_TRIG FB | ft(CLK := bIn); bEdge := ft.Q; | Yes (FB-level) | No | 0.50 |
| Up counter | CTU (IEC counter) | CTU FB | ctu(CU:=bIn, R:=bR, PV:=iP); | Yes (FB-level) | No | 0.85 |
| Timer on-delay | TON, TP, TOF | TON, TP, TOF (Standard lib) | ton(IN:=bIn, PT:=tP); bDone := ton.Q; | Yes (FB-level) | No | 1.20 |
| AND-gate pattern | Not applicable | Inline FBD or ST | iOut := (iA AND bEn) + (iB AND bEn); | N/A | No | 0.18 |
| Wrapper FB with ENO | Built-in | User FB (Solution 2) | Custom FB | Yes | Yes | 0.85 |
The EN pin? column reflects the IEC 61131-3 base standard. CODESYS provides the Enable pin on FB instances (the small E on the upper-left corner of the box in the FBD editor), which is functionally equivalent to wiring a Boolean into the Enable input of the FB's method. The ENO pin? column is FALSE for CODESYS standard functions because the standard does not define a return-Enable output for in-line operators; the wrapper FB pattern (Solution 2) is the only way to expose an ENO-equivalent. The cycle-cost column is measured on a Wago PFC200 (Cortex-A8, 600 MHz, CODESYS V3.5.18) and should be treated as relative guidance, not as an absolute guarantee for other CPU families.
Verification and Commissioning Procedure
After porting a Siemens FBD network to CODESYS using one of the five solutions above, perform the following verification steps:
- Build the project in CODESYS Development System with the target platform selected (e.g., CODESYS Control Win SysTray for desktop testing, or the specific controller profile for Wago PFC200/Beckhoff CX/Schneider M251). Resolve all compiler warnings; pay particular attention to Implicit conversion warnings that may hide an EN/ENO semantic mismatch.
- Open the Logic Analyzer in the CODESYS IDE and add the following traces: bExecute (the gating Boolean), iA, iB, iResult (the operator output), and the wrapper FB's ENO (if Solution 2 was used). Set the sample rate to 10 ms for the first run.
- Force bExecute to FALSE and confirm that iResult holds its last value. If iResult changes unexpectedly while bExecute is FALSE, the SEL feedback is missing or the wrapper FB is using a local variable instead of the global result.
- Force bExecute to TRUE and confirm that iResult updates to iA + iB within one task cycle. If the update is delayed by two or more cycles, the FBD network has an unintended additional buffer (often a duplicate SEL or a forgotten assignment).
- Toggle bExecute at a 100 ms period and confirm that iResult follows the expected pattern. Watch for double execution (iResult changes twice per bExecute edge), which indicates that the wrapper FB or the SEL pattern is in a cycle that runs more than once per scan.
- Switch to the online break-point view and single-step the FBD network with bExecute set to TRUE; verify that the assignment to iResult happens exactly once per cycle.
- With the controller in run state, inject a deliberate overflow (e.g., iA := 2147483647, iB := 1) and confirm that the ENO-equivalent output goes FALSE (Solution 2 only) or that the result is clamped/wrapped according to project policy.
- Run a 24-hour soak test with the controller online, the task in cyclic mode at 1 ms, and a representative workload. Log the cycle time using the built-in task monitor (CODESYS → Task Configuration → Task name → Cycle Time). Cycle time should remain within 1.0 ± 0.1 ms for typical logic; if it creeps above 1.5 ms, the wrapper FB or SEL pattern may have unintended nested calls.
- Verify the EN signal is also routed to any safety-related downstream block. If bExecute is wired from a non-safety source but the consumer is a safety FB (e.g., ESTOP, SBRDO from the CODESYS Safety SIL2 library), add a dedicated safety I/O and a fail-safe default (EN := FALSE) to the wrapper FB's initialization.
The verification procedure is appropriate for CODESYS V3.5.16 through V3.5.19; the exact location of the cycle-time monitor in the task configuration dialog may differ between versions.
Troubleshooting Matrix
| Symptom | Likely Root Cause | Diagnostic | Fix |
|---|---|---|---|
| iResult updates when bExecute is FALSE | SEL feedback wired to wrong input (IN0 vs IN1 swapped) | Online → Watch the inputs of the SEL box | Swap IN0 and IN1; IN0 is the skipped value |
| ENO output stuck TRUE | Wrapper FB body has ENO := TRUE outside the IF EN THEN block | Open the FB implementation method in ST | Move ENO := FALSE into the ELSE branch |
| F_TRIG fires every cycle | Two separate F_TRIG instances declared locally in two POUs | Cross-reference search for F_TRIG | Declare one instance in a global GVL and reuse from both POUs |
| Cycle time 2x expected | Wrapper FB called twice in the same FBD network by accident | Search for FB_AddEn in the network | Use a single instance, route all data through it |
| Type mismatch on SEL IN0/IN1 | Different data types fed to SEL inputs | Hover over SEL input pins in the FBD editor | Insert INT_TO_REAL or REAL_TO_INT explicitly |
| ENO FALSE on every cycle despite valid input | Integer overflow detected (DINT wrap) | Add a temporary REAL conversion and check the magnitude | Widen to LINT or use LREAL for intermediate math |
| Event task does not fire | Event variable never set, or the task is bound to the wrong variable | Task Configuration → Event → Variable | Set the variable name to a known GVL variable; recompile |
| ST code in IF body runs even when condition is FALSE | Compiler hoisting due to volatile variable in the body | Check for {attribute 'volatile'} on body variables | Move volatile variables to global GVL with explicit reset |
| Real-time violation in 1 ms cyclic task | FB with Enable input has heavy implementation (e.g., database call) | Task Configuration → Cycle time exceeded | Move heavy code to a slower (10 ms) cyclic task |
| ENO undefined after compilation warning | Wrapper FB has no explicit ENO assignment in some code paths | Compiler warning Output ENO may be undefined | Initialize ENO := FALSE at the start of the FB body |
| EN pin missing on a third-party FB | FB was authored without a VAR_INPUT EN declaration | Open the FB declaration in the library | Create a wrapper FB around it (Solution 2) |
| Edge detector resets unexpectedly after STOP/RUN | F_TRIG state is in retain memory that was cleared on restart | Check VAR RETAIN vs VAR declaration in the GVL | Move F_TRIG to VAR RETAIN PERSISTENT if needed |
FAQ
Does CODESYS V3.5 have a built-in EN input on ADD/SUB/MUL/DIV like Siemens STEP 7?
No. The IEC 61131-3 standard defines the EN/ENO model for FB instances only, not for in-line operators. CODESYS V3.5 implements the standard strictly; the standard library operators (ADD, SUB, MUL, DIV, etc.) do not expose an EN pin. Use the SEL function, a wrapper FB, AND/OR gating, ST conditional logic, or an event task to replicate the Siemens behavior.
Why does my F_TRIG fire on every scan in CODESYS even though the input is constant?
You likely declared the F_TRIG instance as a local variable in two different POUs, creating two separate instances. Declare a single instance in a global GVL and reference it from both POUs. Alternatively, instantiate the F_TRIG in the parent POU's VAR block and pass it to the child POUs as an input parameter.
Can I use a Siemens-style EN/ENO chain in CODESYS FBD without writing wrapper FBs?
Yes, by using the CODESYS FBD Enable pin on FB instances. Drop the FB, look for the small E input on the upper-left corner, and wire your condition into it. This works for any FB in the project (including user FBs, library FBs, and IEC standard FBs such as TON, TOF, TP, CTU, CTD, CTUD, R_TRIG, F_TRIG). It does not work for in-line operators such as ADD, SUB, MUL, DIV.
What is the fastest way to add conditional execution to a hot path in CODESYS?
Use the AND-gate pattern: iResult := (iA AND bExecute) + (iB AND bExecute); for integer math, or iResult := (iA * BOOL_TO_REAL(bExecute)) + (iB * BOOL_TO_REAL(bExecute)); for real math. Both compile to two ANDs and one ADD, with no function call overhead (≈ 0.18 microseconds per cycle on a Wago PFC200 Cortex-A8). Use this in 1 ms or sub-ms cyclic tasks where every microsecond matters.
Is there a way to make CODESYS FB instances behave exactly like Siemens EN/ENO boxes for migration?
Yes, by giving the FB explicit EN and ENO input/output pins (named EN, ENO) in the VAR_INPUT/VAR_OUTPUT blocks, and assigning ENO := EN at the top of the implementation method. Drop the FB into the FBD network, wire the execution condition into the FBD-level E pin (the IEC Enable pin), and the ENO output will mirror the EN state. This is the IEC 61131-3 standard pattern and works in all CODESYS V3.5 versions without requiring non-standard pragmas.