In CoDeSys 2.3 the force list runs twice per PLC cycle: after the inputs are read and again after the IEC program, just before the outputs are written. IEC code can change a forced variable between those two passes. Trace the writes in call order and gate the conflicting assignment to run a clean test.
Forcing in CoDeSys is a cycle-phase operation, not a lock on memory. In CoDeSys 2.3 the runtime creates a force list when you force variables and executes that list twice per PLC cycle: after the inputs are read, and again after the IEC program has run, immediately before the outputs are written. Your IEC code can write a forced variable between those two passes, so later POUs see the assigned value while the online view still shows the forced value at the end of the scan. This page gives the sequence, shows which write wins for each reader, and walks one cycle with real numbers so you can tell a code overwrite from a force that never applied.
When is a forced value applied in the PLC cycle?
The force list runs twice per cycle in CoDeSys 2.3: once after the inputs are read and once after the IEC program finishes, immediately before the outputs are written. The documented sequence for one cycle is:
- Read the inputs.
- Execute the force list, first pass.
- Execute the IEC program.
- Execute the force list, second pass.
- Write the outputs.
Two instants, five phases. Between pass 1 and pass 2 the program owns the variable; at each pass the force list owns it. The force reaches your logic twice per cycle, and it reaches the outputs through the second pass, which lands directly ahead of the output write.
Why does my forced variable not hold through the whole POU?
Your IEC code is free to write the variable between the two force passes; the force wins only at the moment each pass runs, so an assignment in between temporarily replaces the forced value. A force in CoDeSys 2.3 is not write protection. Assignments take effect the moment they execute: iLevel := iLevel + 30; computes off the current value, and iLevel := 0; later in the same scan replaces that result. The force list restores its values only when a pass runs, so a variable written at three points in the program carries three different values through the scan. When you need a value no instruction can touch, the force dialog is the wrong tool; gate the writes in code.
Which value does the rest of the program see?
Each read sees whatever the last writer left: a POU that runs before the overwriting assignment sees the forced value, and a POU that runs after it sees the assigned value. The rule is last writer wins, and the force list counts as a writer at its two instants. A POU called before any in-program write reads the forced value. A POU called after the write reads the assigned value. Nothing that runs later changes what a reader already consumed, and the second force pass arrives too late for logic that already executed. When the variable crosses task boundaries, establish which task writes it, which task reads it and in which order the tasks run; the last-writer rule is the same.
Why does the online view show the forced value after the code changed it?
The second force pass runs after the program and before the outputs, so by the time the online view refreshes you see the restored forced value, hiding the intermediate one. The display answers the question of what the force list left, while your logic answered the question of what the last write left. That gap is the signature of an in-program overwrite: the screen shows the forced value while the output behaves as if it saw something else. A dashboard or HMI polling the controller reads the same end-of-cycle value; whether a value like that belongs on a live dashboard or on standalone playback at the line is the choice live factory data display: signage or dashboard works through.
How do I find the code that overwrites the forced value?
Force the variable, then search the project for every write to it and put the writers in call order; the writer that executes before your reader is the one changing the test. Work in this order:
- Confirm the target. Check that the variable you watch is the one in the force list, not a local with a similar name or a copy made into another POU.
- Collect the writers. Search the project for the variable name and read every assignment, including code in function blocks and methods called from the POU.
- Order them. Put the writers in execution order. For calls that cross POUs and tasks, tracing logic across task layers gives the method.
- Place your reader. Mark where the logic you care about reads the variable relative to those writes.
- Check the output path separately. A forced internal variable reaches a terminal only through the logic that consumes it.
The record you want is short: variable, each writer, call order, and the point where you observed the value.
Worked example: which level does the pump logic see?
A tank level iLevel is forced to 40 %, the first POU adds a 30 % reading, and the pump logic compares against 50 %, so the pump sees 70 % while the display shows 40 %. The setup: iLevel is an INT in a task running every 10 ms, Update writes the level, Control switches the pump at 50 %.
Walk the five phases of one cycle:
- Inputs are read.
- Force pass 1 sets
iLevel := 40. - The program runs.
UpdateexecutesiLevel := iLevel + 30;, so 40 + 30 = 70.Controlexecutes next: 70 > 50 is TRUE, sobPump := TRUE. - Force pass 2 sets
iLevel := 40again. - Outputs are written. The pump output is ON.
| Phase | iLevel after the phase |
What ran |
|---|---|---|
| Force pass 1 | 40 % | force list |
Update |
70 % | 40 + 30 |
Control |
70 % | compares against 50 %, sets pump ON |
| Force pass 2 | 40 % | force list |
The online view then shows 40 % with the pump running on 70 %. Swap the call order and the result flips: Control compares 40, 40 > 50 is FALSE, the pump stays off, and the 70 from Update sits in the variable until pass 2 erases it. Same force, same code, opposite machine behavior, decided by call order alone.
Does the forced value reach the physical output?
Yes when the forced variable is the output variable itself, because the second pass runs just before the outputs are written; no when you force an internal variable and other logic derives the output. If you force an input variable, pass 1 runs directly after the inputs are read, so every piece of logic in that cycle reads your forced value; this is the dependable case. If you force an internal variable that feeds output logic, the output follows the logic as executed, with whichever value the consumer actually read.
How do I run a clean test with a force?
Gate the overwriting assignment instead of fighting the force: comment the write, add a condition on a test flag, or reorder so the reader runs first, then watch the consumer, not the variable display. Work in this order:
- Put the machine in a safe state, drives disabled, so an unexpected output cannot move anything. A force overrides values your normal logic produced, including values that feed interlocks.
- Reduce the force list to the variables the test needs and check each value.
- Gate the conflicting write: wrap it in
IF bTest THEN ... END_IFwithbTestFALSE, comment it out, or move the reading logic ahead of it. - Judge the test at the consumer: the output, the state machine, the visualization, not the variable field after the scan.
- Record the whole test instead of sampling it; showing the full test duration on a live trend chart covers the setup.
- Release every force and restore the code, then confirm the machine behaves normally.
Recommendation: Use a force for variables no code writes between the two passes, such as a raw input feeding your logic; when the program assigns the variable anywhere in its path, gate that assignment for the test and leave the force off it.
Questions
Is forcing the same as writing a value in CoDeSys?
No. A written value is applied once and the next program pass can overwrite it. A forced value sits in the force list and is reapplied at both cycle points, after the inputs are read and before the outputs are written, until you release the force. Use write for one-time presetting and force when the value must return every cycle.
How do I keep a forced variable from changing during the scan?
You cannot do it from the force dialog in CoDeSys 2.3. The force list runs before and after the program, and every assignment between those points takes effect. Gate or comment the assignment that writes the variable, or reorder the calls so the reading logic runs first, and keep forces on variables no code writes.
Do other PLC platforms apply forces at the same points?
The two-pass sequence described here is the documented CoDeSys 2.3 behavior. Other platforms place their override at their own points in the scan. Run the two-writer test from this page once on your platform: force a variable, write to it in code, then check both the consuming logic and the end-of-cycle display before trusting the force.
Is it safe to force variables while the machine runs?
Treat a force as a live override. It replaces a value your normal logic produced, including values that feed interlocks and permissives, and a forced output drives the terminal directly. Put the machine in a safe state, disable drives or isolate outputs, and release every force before returning to normal operation.
Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.