Configuring Multiple Cyclic Interrupts on Siemens S7-300/400 CPUs

David Krause14 min read
HMI ProgrammingSiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

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:

  1. 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.
  2. 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 MOD arithmetic to dispatch sub-tasks at 100 ms, 150 ms, 200 ms, 1 s, or any integer multiple of the base interval.
The multiplexer technique is fully compatible with STEP 7 V5.5 STL, S7-SCL, FBD, and LAD. It has been used in S7-300 installations since the early 2000s and remains valid on S7-400, S7-300, and WinAC RTX targets that limit the number of cyclic interrupt OBs.

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 MLFB from 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:

  1. Open HW Config in SIMATIC Manager.
  2. Double-click the CPU module (rack slot 2 or 3).
  3. Select the Cyclic Interrupts tab.
  4. 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.

  1. Open HW Config and double-click the CPU.
  2. Open the Cyclic Interrupts tab.
  3. Click the row for the OB you want to enable (for example OB36) and tick Enabled.
  4. Set Execution to the desired interval, for example 200 ms.
  5. 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.
  6. Set the OB Priority. Priorities 9 to 12 are typical for cyclic interrupts on S7-400. Higher priority OBs can preempt lower ones.
  7. Save, compile, and download HW Config first, then download the program blocks.
On S7-1500 with TIA Portal V17 or later, the maximum number of cyclic interrupt events is hardware-dependent. The S7-1200 G2 manual collection states that the S7-1200/1500 families can run up to 20 cyclic interrupt events in total. Reference: TIA Portal S7-1200 G2 Manual Collection — Cyclic Interrupt OB.

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

  1. Open the project in SIMATIC Manager and confirm the target CPU's MLFB and firmware version match the prerequisite table.
  2. 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).
  3. Save and download HW Config first. The PLC must accept the new OB35 interval before the program is downloaded.
  4. Open OB35 in the program editor (LAD/FBD/STL/SCL).
  5. Add the counter increment (L MW0 / +1 / T MW0) at the top of OB35.
  6. Add one MOD / ==I / JC block per desired effective interval. Use unique jump labels (int1, int2, int3, ...) and finish each sub-task body with JU endOB to skip the remaining bodies.
  7. Append endOB: BEA at the very end of OB35 to mark the block end.
  8. 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).
  9. Download to the target CPU. The download should now succeed because you are reusing the existing OB35 rather than adding a new OB36.
  10. Go online and open a VAT (Variable Table) to monitor MW0. Confirm MW0 increments by 1 every 10 ms, that MW0 MOD 10 = 0 is true exactly once per 100 ms, and that the 150 ms / 1 s branches also fire as expected.

Verification Procedure

  1. Create a VAT with the tag MW0 and the status display format set to DEC. The value should climb 1, 2, 3, ... once per OB execution.
  2. 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.
  3. 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.
  4. 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.
  5. 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.

When migrating from S7-300/400 to S7-1500, the OB30-OB38 numbering is preserved by the TIA Portal migration tool, so existing STL code continues to run. The multiplexer body remains valid on the new platform, but the multiple-OB configuration is preferred for readability.

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.

Back to blog