Overview: The Three-Network Toggle Puzzle
A small ladder-logic program on a Siemens SIMATIC S7-1200 or S7-1500 controller contains two CTU (Count Up) counter blocks placed in separate networks, plus a third network that toggles a Merker bit. The arrangement looks simple, but online monitoring in TIA Portal seems to show contradictory behavior: on the first scan the lower-numbered CTU stays idle, the higher-numbered CTU registers a count, and the Merker bit then appears to "magically" revert to 0 at the start of the second scan even though no code in networks 1 or 2 wrote to it. The confusion arises because the toggle network executes at the end of every scan, and the CTU blocks have an internal "previous value of CU" that initializes to FALSE on their first invocation.
This article walks the logic through each scan, documents the CTU instruction's CU default, and provides a watch-table-based verification procedure so engineers can reproduce the trace on their own hardware. The behavior is documented in the TIA Portal information system under Instructions > Counters > CTU and is consistent from TIA Portal V13 through V18 / V19.
Prerequisites
- Siemens TIA Portal V15.1 or later (the behavior described is valid from V13.1 SP1 onward; refer to the Siemens Industry Online Support portal for the latest information system release notes).
- SIMATIC S7-1200 (CPU 1211C through 1215C, including the fail-safe variants) or S7-1500 (CPU 1510 through 1518) controller.
- Familiarity with the
CTUIEC 61131-3 standard function block: inputsCU(count up) andR(reset); outputsCV(current value, INT) andQ(status, BOOL); parameterPV(preset value, INT). - Access to a project online with a watch table in which to monitor M334.0 and both CTU current values.
- Optional: ability to place the controller in single-step mode via the Online > Monitor / Force menu, or to use the S7-PLCSIM simulator for an offline trace.
Network Topology and Tag Map
The program consists of three networks, evaluated top-to-bottom in each PLC scan. The order of evaluation is critical: NW1 and NW2 read the image-table value of M334.0 that was committed at the end of the previous scan, while NW3 writes a new value of M334.0 that will be visible to NW1 and NW2 on the next scan.
| Address / Symbol | Data type | Role in logic | Aliasing note |
|---|---|---|---|
| M334.0 | BOOL | Toggle bit; both NO and NC contacts feed the two CTU instances; NW3 writes it | Bit 0 of MB334; bit 0 of MW334 |
| MW334 | WORD | Not used directly, but any 16-bit write to MW334 overwrites M334.0 | Bytes MB334, MB335 |
| MD332 | DWORD | Not used in the program, but a stray 32-bit write silently overwrites M334.0 | Bytes MB332-MB335; overlaps M334.0 |
| NW1 CTU instance | CTU FB | Counts on a rising edge of CU; CU is driven by a NO contact of M334.0 | Edge detection: 0 → 1 on CU increments CV |
| NW2 CTU instance | CTU FB | Counts on a rising edge of CU; CU is driven by an NC contact of M334.0 | Edge detection: 0 → 1 on CU increments CV |
| NW3 network | Toggle | Standard scan-based flip-flop using NO and NC contacts of M334.0 feeding the same coil | Committed at the end of each scan |
Memory aliasing in the Merker area is the most common root cause of "the toggle bit resets itself unexpectedly." Any write to MD332, MW334, MB334, or to a structured tag that uses these bytes, will silently overwrite M334.0. Keep all symbol declarations outside this address range or use a non-overlapping range such as M400.0 when commissioning.
Scan-by-Scan Trace (Scan 0 through Scan 4)
The following table traces every relevant tag through five scans. The image-table value of M334.0 is the value committed at the end of the previous scan; the value written is the value committed to the image table at the end of the current scan.
| Scan | M334.0 (read) | NW1 CU | NW1 prev-CU | NW1 edge? | NW1 CV | NW2 CU | NW2 prev-CU | NW2 edge? | NW2 CV | M334.0 (written) |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 (pre-startup) | 0 | 0 | 0 (init) | No | 0 | 1 | 0 (init) | Yes | 1 | 1 |
| 1 (first scan, value read = 0) | 0 | 0 | 0 | No | 0 | 1 | 1 | No | 1 | 0 |
| 2 | 1 | 1 | 0 | Yes | 1 | 0 | 1 | No | 1 | 1 |
| 3 | 0 | 0 | 1 | No | 1 | 1 | 0 | Yes | 2 | 0 |
| 4 | 1 | 1 | 0 | Yes | 2 | 0 | 1 | No | 2 | 1 |
The online monitor will display "NW1 idle" and "NW2 active" on Scan 0 / Scan 1 because NW2's CTU just incremented during the very first invocation. NW3 is not a counter; it is a coil, so the online view shows M334.0 lighting up at the end of the cycle. The values for NW1 and NW2 stabilize into a pattern where the two counters differ by 1 and the "leader" alternates between the two.
CTU Internal CU Default: Why NW2 Counts on the First Scan
Most engineers expect edge detection to ignore the very first pass through a network, because no "previous" state is observable. TIA Portal's CTU does not implement that behavior. The block stores the previous value of CU in a static local tag of the instance DB, and the instance DB is created with that static local equal to FALSE. As a consequence, the very first time the CTU sees CU = TRUE, it treats that as a 0 → 1 edge and counts.
This differs from platforms such as Allen-Bradley CTU, which exposes a separate "first scan" bit and a CU bit that can be wired to a one-shot. On a Siemens S7-1500, the system clock byte (system tag "FirstScan" in the system constants of the CPU properties) can be used to gate a CTU's CU input and suppress the first-scan count, but the S7-1200 has no built-in FirstScan system tag. The workarounds for S7-1200 are:
- Maintain a user-defined first-scan flag in a global DB; set it to FALSE at the end of the first cycle, gate the CTU's CU with an AND against the inverse of the flag.
- Set a user bit in OB100 (Startup) and reset it at the end of the first OB1 pass.
- Reset the instance DB during commissioning, then power-cycle the controller.
Why the Toggle Network Works
Network 3 is a textbook scan-based flip-flop. The pattern is:
M334.0 M334.0
--| |------| / |------( = )--- M334.0 // NO and NC of the same bit, single coil
| | |
When M334.0 = 0, the NO contact is open and the NC contact is closed; the coil writes 1. When M334.0 = 1, the NO contact is closed and the NC contact is open; the coil writes 0. The net effect, evaluated once per scan, is that M334.0 alternates between 0 and 1 on every scan, starting from the value committed at the end of the previous scan.
The pattern is not a true edge-triggered flip-flop. It depends on the order of network evaluation. If you move NW3 to the top of the program, NW1 and NW2 will see the toggled value within the same scan, and the alternating behavior of the two CTUs will collapse. If you move NW3 between NW1 and NW2, NW1 will read the pre-toggle value and NW2 will read the post-toggle value within the same scan; the two CTUs will both count on scan 1 and then desynchronize.
| NW3 position | Scan 1 NW1 CV | Scan 1 NW2 CV | Scan 2 NW1 CV | Scan 2 NW2 CV | Steady-state |
|---|---|---|---|---|---|
| Original (NW1, NW2, NW3) | 0 | 1 | 1 | 1 | NW1 and NW2 alternate counts; differ by 1 |
| NW3 moved to top | 0 | 0 | 1 | 0 | Only NW1 counts; NW2 idle after scan 1 |
| NW3 between NW1 and NW2 | 0 | 0 (post-toggle, M334.0=1 → NC=0) | 1 | 1 | Both count; NW1 lags NW2 by 1 scan |
Steady-State: Alternating Counts
After the first few scans the system settles into a stable pattern. The two CTUs count on alternating scans, so the difference between their CV values is always 1:
| Scan N | M334.0 (read) | M334.0 (written) | NW1 CU edge? | NW2 CU edge? | NW1 CV | NW2 CV |
|---|---|---|---|---|---|---|
| 1 | 0 | 1 | No | Yes | 0 | 1 |
| 2 | 1 | 0 | Yes | No | 1 | 1 |
| 3 | 0 | 1 | No | Yes | 1 | 2 |
| 4 | 1 | 0 | Yes | No | 2 | 2 |
| 5 | 0 | 1 | No | Yes | 2 | 3 |
| N (N odd, N > 1) | 0 | 1 | No | Yes | floor(N/2) | ceil(N/2) |
| N (N even) | 1 | 0 | Yes | No | N/2 | N/2 |
The 0/1 alternation is the reason the two counters never fall out of sync. Any external write to M334.0 (a force operation, a different OB writing to the same bit, or an HMI tag) will desynchronize the two counters until the next cold restart, because the toggle pattern is not self-correcting.
Edge Detection: CTU vs P_TRIG / R_TRIG
The IEC 61131-3 standard defines dedicated edge-detection function blocks R_TRIG (rising-edge) and F_TRIG (falling-edge) that are functionally equivalent to the implicit edge detection inside the CTU's CU input. The key implementation difference in TIA Portal is that R_TRIG keeps its previous-input state in a static local of its instance DB and starts at FALSE on instance creation, exactly like the CTU's internal previous-CU. The first time R_TRIG.CLK = TRUE, the output Q pulses for one cycle.
For applications where first-scan suppression is mandatory, prefer R_TRIG + a user-defined FirstScan flag over a direct CTU call. The pattern in SCL is:
IF "FirstScanFlag" = FALSE THEN
"FirstScanFlag" := TRUE;
ELSIF "M334.0" THEN
"NW1_CTU_DB".CTU(CU := TRUE, R := FALSE, PV := 50);
END_IF;
This avoids the ambiguity of whether the CTU has counted on scan 1, at the cost of one extra network and a one-shot pattern that must be maintained in OB100 or OB1.
Equivalent SCL Implementation
The same three-network behavior can be implemented in SCL (Structured Control Language) for engineers who prefer text-based code. The IEC 61131-3 CTU function block is the same in SCL; the difference is the explicit handling of the toggle:
// NW1 SCL
"NW1_CTU_DB".CTU(CU := "M334.0", R := FALSE, PV := 50);
// NW2 SCL
"NW2_CTU_DB".CTU(CU := NOT "M334.0", R := FALSE, PV := 50);
// NW3 SCL (toggle)
"M334.0" := NOT "M334.0";
The SCL version has the same trace as the ladder version. Note that in SCL the assignment to M334.0 in NW3 takes effect immediately for the rest of the OB1 cycle, just as in ladder. If you place NW3 between NW1 and NW2 in SCL, the NC/NO evaluation in NW2 will see the toggled value within the same cycle.
Verifying With a TIA Portal Watch Table
The fastest way to confirm the trace is to delete the toggle network and toggle M334.0 by hand in a watch table. This isolates the CTU's edge-detection behavior from the toggle timing.
- Open the project in TIA Portal, connect to the controller, and create a new watch table (Project tree → "Watch and force tables" → "Add new watch table").
- Add the following tags:
M334.0(BOOL, monitor/force),"DB_name".NW1_CTU.CV(INT, monitor),"DB_name".NW2_CTU.CV(INT, monitor),"DB_name".NW1_CTU.CU(BOOL, monitor),"DB_name".NW2_CTU.CU(BOOL, monitor). ReplaceDB_namewith the actual instance DB name andNW1_CTUwith the instance name of the CTU block in network 1. - Click "Monitor all" (the glasses icon) to start the cyclic update of the watch table. The default refresh rate is 1000 ms; reduce it to 250 ms in the table properties if you want a faster trace.
- Force
M334.0 = FALSEfrom the watch table. ObserveNW1_CTU.CU = FALSE,NW2_CTU.CU = TRUE. The CVs do not change because the controller is in RUN; the toggle is the only writer of M334.0. - Force
M334.0 = TRUE.NW1_CTU.CU = TRUEandNW2_CTU.CU = FALSE. Again, CVs do not change in real time because a write to a BOOL from the watch table is committed only at the end of the next OB1 cycle. - Toggle M334.0 once per second from the watch table (right-click → "Modify to 1", then "Modify to 0", repeat). Count the number of toggles; you should see both CV values advance by exactly the number of 0→1 transitions seen by each CTU's CU input.
- Reinsert the toggle network, recompile, and download. Watch the live values:
NW2_CTU.CVshould be 1 immediately after the first scan, and the two CVs should differ by at most 1.
For a deeper trace, switch to S7-PLCSIM and use the "Single step" button in the Online menu. The single-step mode executes one network at a time, which lets you watch NW1, NW2, and NW3 evaluate in sequence and confirm that NW3 is the only network that writes to M334.0 within a single scan.
Common Pitfalls and Diagnostic Tips
-
Memory aliasing: Any write to
MD332,MW334,MB334, or a structured variable that includes byte 334 will silently clobber M334.0. Search the project for these addresses ("Go to → Usage") before commissioning. - Retentive instance DB: If the CTU's instance DB is retentive, the static local that holds the previous-CU value will survive a cold restart, and the first-scan edge will not occur after a power-cycle. Make the DB non-retentive if you want the first-scan behavior to be reproducible.
- Online monitoring latency: TIA Portal's online monitor updates at a rate that depends on the watch-table refresh interval and the HMI connection load. The CTU's edge detection is computed within the OB1 cycle, so the monitor cannot show every edge. Use the watch-table approach described above for an unambiguous trace.
- FirstScan system tag: The S7-1500 exposes "FirstScan" in the system constants; the S7-1200 does not. Use OB100 to set a user flag if you need first-cycle suppression on an S7-1200.
- Order of evaluation in multi-instance blocks: If NW1 and NW2 are inside the same FB, the order of execution follows the network order in the FB editor. The trace above assumes the network order is NW1, NW2, NW3 in OB1 or in the parent FB.
- Forcing M334.0 from the HMI: An HMI tag wired to M334.0 will write the value at the end of the OB1 cycle. The toggle will then read the new value on the next scan, so the alternation is broken. Remove the HMI tag or wire it to a separate mirror bit.
- Watch-table write timing: A "Modify to 1" from the watch table is committed at the next OB1 cycle boundary. If the toggle runs first in the cycle, your forced value is overwritten before NW1/NW2 see it. Disable the toggle temporarily or use a force operation that takes effect immediately.
Diagnostic Checklist
| Symptom | Likely cause | Verification | Fix |
|---|---|---|---|
| NW2 counts on scan 1 | CTU previous-CU initialized to FALSE | Watch NW2_CTU.CU on scan 1 | Expected behavior; gate with FirstScan flag if undesired |
| M334.0 stays at 0 | Another OB writes 0 to MD332 / MW334 | "Go to → Usage" search for the byte | Move toggle bit to a non-aliased address (e.g. M400.0) |
| M334.0 stays at 1 | NC contact and NO contact wired incorrectly, or coil address differs from contact address | Inspect contacts and coil in the network | Verify the coil address matches the contact address |
| Both CTUs count on the same scan | NW3 moved to top or between NW1 and NW2 | Reorder the networks in the editor | Restore NW3 to the bottom |
| Counters do not alternate | HMI or another FB writing to M334.0 | Disconnect HMI, monitor byte 334 | Remove external writers, use a mirror bit |
| First-scan count not reproducible | Instance DB retentive | DB properties → Retentivity | Clear the retentivity bit for the static area |
| Counter value differs from expected by exactly 1 | NW1 ran first and NW2 ran second, or vice versa | Check network order; force MB334 to 0 and watch the first 2 scans | Reorder networks to match design intent |
Field-Commissioning Notes
When commissioning a similar pattern in a real machine, document the network order in the function specification and the HMI screen design. Engineers who maintain the program in five years will not have the original author available to explain why the toggle is in network 3 and not network 1. A short comment in the network ("Scan-based flip-flop; M334.0 alternates 0,1,0,1,...") is enough. Avoid using M334.0 as a generic machine-state bit; reserve it for the toggle so that the aliasing footprint stays small.
For a more robust implementation, replace the toggle with a system clock bit. On an S7-1500, the system tag Clock_1Hz, Clock_2Hz, or Clock_10Hz can be wired directly to a CTU's CU input, eliminating the network-order dependency. On an S7-1200, the system clock bits are not available, but the IEC timer TP (pulse timer) or a TON with a 100-ms preset can be used to drive a one-cycle pulse that is safe to count.
Cycle-time budget: the three-network program adds well under 5 µs to a typical OB1 cycle on an S7-1214C. The CTU instances each add a few microseconds for the edge comparison; the toggle network is two contacts and a coil. The total program-time impact is negligible for any realistic application. If the program is replicated 200 times in a generator-driven FB, consider consolidating the toggles into a single clock generator and routing the pulse to all counters.
Safety note: do not use this pattern for safety-relevant counting. The TIA Portal F-library provides F_CTU (fail-safe counter) which is TÜV-certified and handles the first-scan case according to IEC 61508 SIL 2/3. The standard CTU is for non-safety counting only.
FAQ
Why does the NW2 CTU count on the very first scan if no input can have changed?
The CTU block stores the previous value of its CU input in a static local of the instance DB. On instance-DB creation that static local is initialized to FALSE, so the first time CU evaluates to TRUE the block sees a 0 → 1 transition and increments CV. TIA Portal does not provide a first-scan suppression for the standard CTU block; you must add a user-defined flag in OB100 or gate the CU input with the inverse of a first-scan bit.
What causes M334.0 to revert to 0 at the start of the second scan?
Network 3 is a scan-based flip-flop using NO and NC contacts of the same bit feeding the coil. The flip-flop writes 0 to M334.0 at the end of scan 2 because M334.0 was 1 at the start of scan 2. The new value is committed to the image table and is what NW1 and NW2 read at the start of scan 3. There is no external reset of M334.0 between scans.
How do I prevent memory aliasing from clobbering M334.0?
Search the project for any reference to MB334, MW334, MD332, or to a structured tag that includes byte 334 (TIA Portal → right-click the address → "Go to → Usage"). Move the toggle bit to a non-aliased address such as M400.0, or remove the offending write. Memory aliasing is the most common cause of "the toggle bit resets itself unexpectedly" reports and can mask the actual scan-based toggle logic.
Can I use the S7-1500 FirstScan system tag to suppress the first CTU count?
Yes. The S7-1500 exposes "FirstScan" in the system constants of the CPU properties. AND the CTU's CU input with the inverse of FirstScan to suppress the first-scan edge. The S7-1200 does not provide a built-in FirstScan system tag; on S7-1200, set a user flag in OB100 and reset it in OB1 at the end of the first cycle.
What happens if I move NW3 to the top of the program?
NW1 and NW2 will then see the toggled value of M334.0 within the same scan, and the alternating-count behavior collapses. In the original configuration (NW1, NW2, NW3) the two CTUs alternate counts; if NW3 is moved to the top, NW1 will count on every scan and NW2 will be idle after scan 1. Verify the network order matches the design intent before downloading.
Is the standard CTU block safe to use in safety-relevant applications?
No. The standard CTU is intended for non-safety counting only. For SIL 2/3 applications per IEC 61508, use the F-library F_CTU block from TIA Portal Safety. The fail-safe variant handles first-scan initialization deterministically and is TÜV-certified for use in safety instrumented functions.