Overview: Why You Cannot Always Add Another Cyclic Interrupt
Siemens SIMATIC S7-300 and S7-400 CPUs execute cyclic interrupt OBs in the OB30 to OB38 range. The default is OB35 set to 100 ms, and most S7-300 CPUs ship with OB35 already inserted in the offline program. When a programmer right-clicks the S7 program container in SIMATIC Manager and inserts an additional block such as OB36, the editor accepts the new block and the symbol table parses cleanly, but the download to the target CPU terminates with a system error: "The OB is not supported by the target CPU" or "Download of OB36 to CPU 314C-2 PN/DP not possible". The error is not a project bug, it is a hardware/firmware constraint: many CPU 31x variants only support one cyclic interrupt OB in their run-time system, while S7-400 CPUs and the newer S7-31x PN/DP and CPU 319 family support multiple OBs simultaneously.
Two paths solve the problem:
- Native multi-OB configuration when the CPU hardware/firmware allows it. Configure OB30, OB31, OB32, OB33, OB34, OB36, OB37, OB38 from HW Config > CPU Properties > Cyclic Interrupts.
-
Multiplexer workaround for CPUs that allow only one cyclic OB. Run OB35 (or whichever OB the CPU permits) at the fastest supported interval, count the calls in a marker word, and use STL
MODarithmetic to dispatch sub-tasks at 100 ms, 150 ms, 200 ms, 1 s, or any integer multiple of the base interval.
Prerequisites
- SIMATIC STEP 7 V5.5 SP2 or later (works on V5.4 SP3 and V5.3 SP3 with identical STL syntax).
- SIMATIC Manager with the appropriate CPU HSP (Hardware Support Package) installed for the target CPU.
- Target CPU type and firmware version known. Identify via HW Config > PLC > Module Information, or read
MLFBfrom the module label. - Online connection via MPI, PROFIBUS, or Ethernet (CP 343-1 / CP 443-1) for download and verification.
- Working knowledge of STL accumulator operations or willingness to use the SCL equivalent.
Cyclic Interrupt OB Numbering and Default Behaviour
All S7-300/400 CPUs share the same OB numbering for cyclic interrupts:
| OB | Default Phase Offset | Default Interval (ms) | Typical Use |
|---|---|---|---|
| OB30 | 0 | — | Free cyclic interrupt slot |
| OB31 | 0 | — | Free cyclic interrupt slot |
| OB32 | 0 | — | Free cyclic interrupt slot |
| OB33 | 0 | — | Free cyclic interrupt slot |
| OB34 | 0 | — | Free cyclic interrupt slot |
| OB35 | 0 | 100 | Default 100 ms cyclic interrupt |
| OB36 | 0 | — | Free cyclic interrupt slot |
| OB37 | 0 | — | Free cyclic interrupt slot |
| OB38 | 0 | — | Free cyclic interrupt slot |
OB35 with a 100 ms interval is the factory default for S7-300 CPUs. The interval can be modified from 1 ms to 60 000 ms in HW Config, but most CPU 31x variants enforce a minimum of 10 ms and reject values below that range during HW Config download.
Identifying Which Cyclic OBs Your CPU Supports
The fastest way to determine hardware support is the hardware configuration:
- Open HW Config in SIMATIC Manager.
- Double-click the CPU module (rack slot 2 or 3).
- Select the Cyclic Interrupts tab.
- Inspect the OB column. CPUs that support only one OB show a single entry (OB35). CPUs that support multiple OBs list OB30 through OB38 with editable Execution, Phase Offset, and Priority fields.
Use the table below as a quick reference for common S7-300/400 CPU families. Always cross-check against the printed manual for your specific MLFB and firmware version.
| CPU Family | Typical MLFB (example) | Max Cyclic OBs | Min Interval |
|---|---|---|---|
| CPU 312 / 312C | 6ES7 312-1AE14-0AB0 | 1 (OB35 only) | 100 ms |
| CPU 313 / 313C | 6ES7 313-1AD03-0AB0 | 1 (OB35 only) | 100 ms |
| CPU 314 / 314C-2 PN/DP | 6ES7 314-6EH04-0AB0 | 1 (OB35 only) | 10 ms |
| CPU 315-2 PN/DP | 6ES7 315-2EH14-0AB0 | 1 (OB35 only) | 1 ms |
| CPU 317-2 PN/DP | 6ES7 317-2EK14-0AB0 | 1 (OB35 only) | 1 ms |
| CPU 319-3 PN/DP | 6ES7 318-3EL01-0AB0 | Multiple (OB30-OB38) | 1 ms |
| CPU 412 / 414 / 416 | 6ES7 412-1XJ05-0AB0 | Multiple (OB30-OB38) | 1 ms |
| CPU 1516-3 PN/DP (S7-1500) | 6ES7 516-3AN02-0AB0 | Multiple, see TIA Portal | 500 µs |
If your CPU shows only OB35 with an uneditable count, you are in the multiplexer territory. The download error you saw in the offline > online transfer dialog is the firmware enforcing this exact limitation.
Native Multi-OB Configuration (When Supported)
For S7-400 CPUs, CPU 319-3, and S7-1500 controllers configured in TIA Portal, multiple cyclic OBs are first-class citizens.
- Open HW Config and double-click the CPU.
- Open the Cyclic Interrupts tab.
- Click the row for the OB you want to enable (for example OB36) and tick Enabled.
- Set Execution to the desired interval, for example 200 ms.
- Set Phase Offset to stagger the start time relative to OB35. A 50 ms offset on OB36 with a 200 ms interval guarantees OB36 fires 50 ms after OB35 each cycle and avoids overlapping scan spikes.
- Set the OB Priority. Priorities 9 to 12 are typical for cyclic interrupts on S7-400. Higher priority OBs can preempt lower ones.
- Save, compile, and download HW Config first, then download the program blocks.
The Multiplexer Workaround: One Fast OB, Many Effective Intervals
When the CPU only allows one cyclic OB, configure that OB at the fastest interval the CPU permits (typically 10 ms on CPU 314, 1 ms on CPU 315-2 PN/DP and higher). Inside the OB, maintain a free-running counter in a marker word (MW, DBW, or static variable in an FB). For each desired effective interval, test whether the counter modulo the integer ratio equals zero, and if so, jump to the sub-task body. This is the canonical STEP 7 V5.5 STL pattern.
Why It Works
OB35 fires every T ms (for example 10 ms). The counter MW0 increments by 1 on every entry, so it counts elapsed OB invocations. The condition (MW0 MOD N) == 0 is true on every Nth entry, which corresponds to an effective interval of N × T ms. With T = 10 ms and N = 10, the effective interval is 100 ms; with N = 15 it is 150 ms; with N = 100 it is 1 000 ms. Because the dispatcher lives in the only cyclic OB, all sub-tasks are mutually time-serialised and never overlap, which simplifies priority management on the PLC side.
STL Code Walkthrough
The reference STL is written in pure STEP 7 V5.5 syntax. All instructions are documented in the SIMATIC STEP 7 V5.5 Statement List (STL) for S7-300 and S7-400 Programming manual, Section 7 "Integer Math Instructions".
//----------------------------------------------------------
// OB35 — Multiplexed cyclic dispatcher
// Base interval: 10 ms (configured in HW Config)
// MW0 = free-running call counter
//----------------------------------------------------------
L MW0 // Load counter
+ 1 // ACCU1 = ACCU1 + 1
T MW0 // Store counter
//------ Effective 100 ms task (ratio = 10) ------
L MW0
L 10 // 100 ms / 10 ms = 10
MOD // ACCU1 = MW0 MOD 10
L 0
==I // ACCU2 == 0 ?
JC int1 // Jump to 100 ms block
//------ Effective 150 ms task (ratio = 15) ------
L MW0
L 15 // 150 ms / 10 ms = 15
MOD
L 0
==I
JC int2 // Jump to 150 ms block
//------ Effective 1 s task (ratio = 100) ------
L MW0
L 100 // 1000 ms / 10 ms = 100
MOD
L 0
==I
JC int3 // Jump to 1 s block
JU endOB // Skip sub-task bodies
int1: // Begin 100 ms body
// ... call FB / set outputs / read inputs ...
JU endOB
int2: // Begin 150 ms body
// ... 150 ms logic ...
JU endOB
int3: // Begin 1 s body
// ... 1 s logic ...
JU endOB
endOB: BEA // Block end
Why the +1, T, MOD, ==I, JC Pattern
| Instruction | Effect on ACCU | Engineering Intent |
|---|---|---|
L MW0 |
Loads the counter into ACCU1; old ACCU1 shifts to ACCU2. | Read current count. |
+1 |
ACCU1 := ACCU1 + 1 (integer add without status flags unless explicit). | Advance counter by one call. |
T MW0 |
Transfers ACCU1 to MW0. | Persist counter for next call. |
L MW0 then L 10
|
Loads MW0 into ACCU2, then 10 into ACCU1. | Prepare dividend and divisor. |
MOD |
ACCU1 := ACCU2 MOD ACCU1. With ACCU2 = MW0 and ACCU1 = 10, result is the remainder. | Compute modulo. |
L 0 / ==I
|
Loads 0 and compares ACCU2 (remainder) for integer equality to 0. | Detect Nth call. |
JC int1 |
Conditional jump if RLO = 1 (i.e. equality true). | Enter sub-task body. |
The same logic expressed in SCL is more compact:
// SCL version — place inside OB35
#iCnt := #iCnt + 1;
IF (#iCnt MOD 10) = 0 THEN
// 100 ms body
END_IF;
IF (#iCnt MOD 15) = 0 THEN
// 150 ms body
END_IF;
IF (#iCnt MOD 100) = 0 THEN
// 1 s body
END_IF;
IF #iCnt > 32000 THEN
#iCnt := 0; // wrap to avoid overflow on INT range
END_IF;
Step-by-Step Implementation in SIMATIC Manager
- Open the project in SIMATIC Manager and confirm the target CPU's MLFB and firmware version match the prerequisite table.
- Open HW Config, double-click the CPU, select the Cyclic Interrupts tab, and confirm OB35 is the only enabled entry. Set OB35 to the fastest interval the CPU permits (commonly 10 ms).
- Save and download HW Config first. The PLC must accept the new OB35 interval before the program is downloaded.
- Open OB35 in the program editor (LAD/FBD/STL/SCL).
-
Add the counter increment (
L MW0 / +1 / T MW0) at the top of OB35. -
Add one
MOD / ==I / JCblock per desired effective interval. Use unique jump labels (int1, int2, int3, ...) and finish each sub-task body withJU endOBto skip the remaining bodies. -
Append
endOB: BEAat the very end of OB35 to mark the block end. - Compile the S7 program (F7 or via menu). The compiler reports the OB size in the local data; ensure the OB does not exceed the CPU's local data stack (default 256 bytes per priority class, configurable in HW Config > Memory).
- Download to the target CPU. The download should now succeed because you are reusing the existing OB35 rather than adding a new OB36.
-
Go online and open a VAT (Variable Table) to monitor MW0. Confirm MW0 increments by 1 every 10 ms, that
MW0 MOD 10 = 0is true exactly once per 100 ms, and that the 150 ms / 1 s branches also fire as expected.
Verification Procedure
- Create a VAT with the tag
MW0and the status display format set to DEC. The value should climb 1, 2, 3, ... once per OB execution. - Add a second tag for the 100 ms body execution counter (e.g.
MW10) and increment it inside the int1 block. The online trend should show a 10:1 ratio between MW0 and MW10. - Use Monitor/Modify on a digital output wired to a panel lamp or scope. Toggle the output inside each sub-task body. With a 100 ms effective interval and a 50% duty cycle, the lamp should appear solidly lit at 5 Hz on a scope.
- Check PLC > Diagnostic Buffer for OB35 priority class overruns. A "OB35 cycle time exceeded" or "OB35 priority class error" entry indicates that the total execution time of all sub-tasks is longer than the 10 ms base interval. Either raise the base interval or split the bodies into multiple OBs once the CPU firmware allows it.
- Force a STOP/RUN transition and confirm MW0 starts from 0 (or from the retained value, depending on whether MW0 is set to Retain in the symbol table). For deterministic behaviour, force a reset of MW0 in OB100 (warm restart) or in the startup OB of the CPU.
Edge Cases, Jitter, and Caveats
| Scenario | Risk | Mitigation |
|---|---|---|
| Total sub-task time > base interval | OB35 cycle time exceeded, OB85 triggered, possible STOP. | Measure worst-case execution with OB35_TIME and the system clock SFC64. Raise base interval or split work. |
| MW0 overflow | Integer overflow at 32 767, then negative values, then 0 at 65 536 (16-bit wrap). | Reset MW0 when it crosses 30 000, or store the counter in a DINT (32-bit) in a DB. |
| CPU STOP during dispatcher | Lost calls. Time-of-day OB (OB10-OB17) is not affected. | For hard real-time, use a separate time-of-day OB or a hardware-interrupt OB (OB40-OB47) instead. |
| Phase offset on S7-300 | Many CPU 31x variants ignore the phase offset and fire OB35 only. | Use the multiplexer ratio to approximate offsets (e.g. start int1 at MOD 0, int2 at MOD 5 for a 50 ms phase lead). |
| Watchdog | Default OB35 watchdog is 2× the configured interval. | Verify the watchdog under CPU Properties > Cyclic Interrupts > OB35 > Watchdog. Increase to 3× or 5× if the dispatcher body is long. |
| Time-of-day drift | The OB interval is a CPU tick, not a wall-clock time. Drift accumulates over hours. | For drift-sensitive tasks, cross-check with SFC1 (READ_CLK) once per second and re-zero the counter. |
Alternative: Time-of-Day and Hardware Interrupts
Where cyclic OB multiplexing still does not give the deterministic phase required, combine the multiplexer with one of the following:
- Time-of-day interrupts OB10-OB17: configured in HW Config > CPU Properties > Time-of-Day Interrupts. Up to 8 start times, each can fire daily, weekly, monthly, or on the last day of the month. Use for hard real-time calendar tasks (shift reports, end-of-day routines).
- Hardware interrupts OB40-OB47: triggered by digital input edges, CP interrupts, or FM module events. Use for low-latency, event-driven response where cyclic scan is too slow.
- SFB35/SFB36/SFB37 (ALARM_8P, NOTIFY_8P, ALARM_8): diagnostic interrupts generated from the user program. Useful for status polling at intervals that are independent of the cyclic OB.
Comparison: Native Multi-OB vs Multiplexer
| Criterion | Native Multi-OB (OB30-OB38) | Multiplexer (Single OB35) |
|---|---|---|
| Hardware support | S7-400, CPU 319, S7-1500 only. | Any S7-300/400 CPU that supports OB35. |
| Code complexity | Low — one body per OB. | Medium — dispatcher plus bodies. |
| Priority management | Per-OB priority, independent phase offsets. | Single priority, sub-tasks are time-serialised. |
| Jitter between sub-tasks | Lowest (true parallel execution by the OS). | Sequential, sum of dispatcher time + earlier sub-task time. |
| Overflow / wrap risk | None from user code. | Counter wrap, must be reset in OB100. |
| Diagnostic buffer entries | One per OB. | Only OB35 — harder to spot which sub-task faulted. |
| Reusability across CPU types | Code must be rewritten when moving to a CPU without the OB. | Portable to any CPU that allows OB35. |
Migrating to TIA Portal / S7-1500
If your application can move to S7-1200/1500 with TIA Portal V16 or later, the multiplexer is no longer required. Add multiple cyclic interrupt OBs from Program Blocks > Add New Block > Organization Block > Cyclic Interrupt, and TIA Portal presents a wizard that lets you pick the interval and phase offset for each OB. The S7-1500 CPU 1516-3 PN/DP supports sub-millisecond intervals (500 µs minimum on most variants), and the S7-1200 G2 manual collection confirms that the family supports up to 20 cyclic interrupt events in total. The TIA Portal V18 release notes also introduce Synchronous Actions in cyclic OBs for motion control integration.
FAQ
How do I know whether my S7-300 CPU supports more than OB35?
Open HW Config, double-click the CPU, and inspect the Cyclic Interrupts tab. CPUs that allow only OB35 show a single row with no add/remove buttons. The downloadable CPU datasheet on the Siemens Industry Online Support portal also lists the maximum number of OBs and the minimum interval for each MLFB and firmware version.
What is the fastest OB35 interval I can configure on a CPU 314C-2 PN/DP?
On a CPU 314-6EH04-0AB0 with firmware V3.3, the minimum OB35 interval is 10 ms. Values below 10 ms are rejected during HW Config download with the error "Value out of range". On the CPU 315-2 PN/DP (6ES7 315-2EH14-0AB0) and higher, the minimum drops to 1 ms.
Will the multiplexer pattern work in SCL on TIA Portal?
Yes. Replace the STL L / MOD / ==I / JC chain with a single IF (iCnt MOD N) = 0 THEN ... END_IF; block per sub-task. The behaviour is identical. On S7-1500, the MOD operator is overloaded for LREAL, but for INT/DINT modulo arithmetic no special handling is required.
How do I avoid MW0 integer overflow?
Add a wrap-around test at the end of OB35: IF MW0 > 30000 THEN MW0 := 0; END_IF; (STL: L MW0 / L 30000 / >I / JC rst0 / ... rst0: L 0 / T MW0). For 1 ms base intervals on CPU 315-2 PN/DP, the wrap must occur within 32 767 ms to remain inside the 16-bit range; the larger wrap window is preferred for stability.
What happens if OB35's watchdog is exceeded?
The CPU enters STOP with diagnostic buffer entry "OB35 cycle time exceeded" and calls OB80 (time error OB) if programmed. Increase the watchdog under CPU Properties > Cyclic Interrupts > OB35 > Watchdog (default factor is 2× the configured interval), or split the dispatcher across multiple OBs once the CPU firmware allows it.