Overview
The Siemens FM 350-1 counter module is a single-channel 100 kHz function module for the S7-300 (and compatible S7-400) programmable controller. It can be parameterized to issue a hardware (process) interrupt when the measured count value reaches a configured comparison value, a zero crossing, a gate open/close edge, or an over/underflow condition. When the FM 350-1 raises the interrupt, the CPU enters the assigned hardware-interrupt organization block.
On most S7-300 CPUs only one hardware-interrupt OB is available: OB 40. When two or more FM 350-1 modules are configured to use the same OB 40, the OB executes on every interrupt from any module. The problem the engineer must solve is therefore not "which OB is called" but "which module triggered the call once OB 40 is entered." The answer lies in the OB 40 start information, specifically the local tag OB40_MDL_ADDR, which holds the logical base address of the module that raised the interrupt at the moment the OB was called.
Problem Definition
Two FM 350-1 modules are installed in the same S7-300 station. Both are configured to generate a hardware interrupt on comparison match. The engineer wants:
- Module 1 interrupt → run code path A
- Module 2 interrupt → run code path B
The user initially expected to assign OB 40 to module 1 and OB 41 to module 2. The S7-300 system manual (System Software for S7-300/400, § 1.6) describes this kind of per-module OB assignment for hardware interrupts, but the option is not visible for many S7-300 CPUs because only OB 40 is enabled in the firmware. The exact capability is CPU-dependent:
| CPU class | Hardware interrupt OBs enabled | Per-module OB selectable? |
|---|---|---|
| CPU 312 / 313 / 314 / 315-2 DP (6ES7 315-2AG10-0AB0) | OB 40 only | No — OB 40 is the sole sink |
| CPU 317-2 DP / PN | OB 40 only (some firmware ≥ V3.x: OB 40–OB 47) | Check CPU properties > Interrupts |
| CPU 319-3 PN/DP | OB 40–OB 47 | Yes (via HW Config) |
| CPU 41x / 416 / 417 (S7-400) | OB 40–OB 47 | Yes (per-module assignment supported) |
For the target CPU 315-2AG10-0AB0, only OB 40 is callable, so the only correct architectural answer is to multiplex inside OB 40 using the start information.
Root Cause
The architectural reason is twofold:
- CPU firmware gating. The S7-300 CPU 315-2DP family only registers OB 40 in its interrupt vector. OB 41–OB 47 either do not exist in the firmware image or are explicitly disabled. STEP 7 will not offer them as selectable targets in the module's Hardware Interrupt dialog because they cannot be entered on that CPU.
- Per-module OB routing is an HW-Config level binding. Even on S7-400 and CPU 319 where OB 41–OB 47 are available, the assignment is one OB per module slot, not an automatic demultiplexer. Two modules can each have a different OB, but a single module cannot trigger two different OBs based on the cause of the interrupt — the demultiplexing of which comparison event fired is the responsibility of the FM 350-1's own status bits and the OB 40 start information.
The engineer therefore has two options:
- Upgrade to a CPU that supports the full OB 40–OB 47 set, then assign a unique OB to each FM 350-1 slot. This is rarely economical just to split an interrupt handler.
- Keep the existing CPU 315-2DP and demultiplex inside OB 40 by reading
OB40_MDL_ADDR(logical base address of the triggering module) andOB40_POINT_ADDR(the channel/cause bit pattern returned by the module).
Solution — Demultiplexing OB 40 by Source Module
When the FM 350-1 raises a hardware interrupt and the CPU calls OB 40, the operating system fills the OB 40 temporary (local) variables with information describing the event. The two relevant tags are:
| Local tag | Data type | Meaning |
|---|---|---|
OB40_MDL_ADDR |
WORD | Logical base address of the module that triggered the hardware interrupt. This is the same address shown in HW Config under the FM 350-1 slot > Addresses. |
OB40_POINT_ADDR |
DWORD | Bit pattern showing which event on the module fired. For FM 350-1 this is a packed bitfield of comparison, zero, overflow, gate start, and gate stop events. |
OB40_IO_FLAG |
BOOL | TRUE for input modules / FMs, FALSE for output modules. |
OB40_FLT_ID |
BYTE | Fault ID for diagnostic interrupts (not used for the comparison match scenario). |
The pattern is: read OB40_MDL_ADDR, compare it to the configured logical base addresses of FM 1 and FM 2, then jump to the matching branch.
Prerequisites
- STEP 7 V5.5 or TIA Portal with the FM 350-1 GSD/GSDML or HSP installed. The module can be configured in the TIA Portal FM 350-1 configuration page (also documented in FM 350-1 Operating Instructions).
- CPU 315-2DP (6ES7 315-2AG10-0AB0) with firmware ≥ V2.x recommended.
- Two FM 350-1 modules slotted in the rack with unique logical addresses. Typical assignments are 256–271 and 272–287 (each FM 350-1 occupies 16 bytes of I/O).
- For the assignment values: when configuring the FM 350-1, navigate to the "Hardware Interrupt" parameter group and select the comparison, zero, gate-start, gate-stop, overflow, and underflow events you want to be interrupt-capable. "Hardware interrupt at upper/lower limit" must be enabled or the OB will never be triggered.
Step-by-Step Configuration
- Open the S7 project in STEP 7 (or TIA Portal) and launch HW Config.
- Insert the FM 350-1 from the hardware catalog (path: SIMATIC 300 > FM-300 > FM 350-1 Counter Module). Place it in slot 4 and slot 5 of the rack, or whichever free slots are available after the CPU (slot 1), power supply (slot 0), and signal modules.
-
Assign logical base addresses. Double-click each FM 350-1 and, on the Addresses tab, set the input and output start addresses. Recommended: FM1 = 256, FM2 = 272. These values are what will appear in
OB40_MDL_ADDRat runtime. - Configure the hardware interrupt causes. In the FM 350-1 properties dialog, open the "Hardware Interrupt" parameter group. Enable "Hardware interrupt on comparison" for each comparison value you intend to use. Repeat for gate-start, gate-stop, overflow, and underflow as required.
- Confirm the CPU interrupt assignment. Open the CPU properties, go to the "Interrupts" mask. Under "Hardware Interrupts" (HW-Interrupt OBs), verify that only OB 40 is listed as active. Do not attempt to add OB 41 — it is not enabled in the firmware and the assignment will be rejected at compile time.
-
Generate the OB 40 source (right-click > Insert New Object > Organization Block > OB 40). OB 40's local variable table is auto-generated by the editor and contains the
OB40_MDL_ADDR,OB40_POINT_ADDR, and other fields listed above. - Implement the demultiplexer using the LAD, FBD, or STL/ST code shown in the next section.
- Compile and download the hardware configuration and the OB 40 source to the CPU. The FM 350-1 parameter block (UDT 1 / DB 2 by default) is downloaded with the program and is required for the FM 350-1 to begin counting.
Reference Code — OB 40 Demultiplexer (Structured Text)
// OB 40 — Hardware interrupt for FM 350-1 modules
// CPU 315-2AG10-0AB0, two FM 350-1 at logical base 256 and 272
IF OB40_IO_FLAG THEN // Input/FM interrupt
CASE WORD_TO_INT(OB40_MDL_ADDR) OF
256: // FM 350-1 #1 fired — run path A
// OB40_POINT_ADDR bit map (FM 350-1):
// bit 0 = upper limit reached
// bit 1 = lower limit reached
// bit 2 = counter overflow
// bit 3 = counter underflow
// bit 4 = gate started
// bit 5 = gate stopped
IF (OB40_POINT_ADDR AND 16#00000001) <> 0 THEN
// Upper-limit interrupt from FM1
"dbg_evt".FM1_UpLimitCnt := "dbg_evt".FM1_UpLimitCnt + 1;
// application-specific handling here
ELSIF (OB40_POINT_ADDR AND 16#00000002) <> 0 THEN
"dbg_evt".FM1_LoLimitCnt := "dbg_evt".FM1_LoLimitCnt + 1;
END_IF;
272: // FM 350-1 #2 fired — run path B
IF (OB40_POINT_ADDR AND 16#00000001) <> 0 THEN
"dbg_evt".FM2_UpLimitCnt := "dbg_evt".FM2_UpLimitCnt + 1;
// application-specific handling here
END_IF;
ELSE
// Unknown / unexpected address — log it
"dbg_evt".UnknownIntAddr := OB40_MDL_ADDR;
"dbg_evt".UnknownIntPoint := DWORD_TO_DWORD(OB40_POINT_ADDR);
END_CASE;
END_IF;
Reference Code — Ladder Equivalent
Network 1 — Branch on module base address
OPN DB "dbg_evt"
L #OB40_MDL_ADDR
L W#16#0100 // FM1 base = 256 decimal = 0x100
==I
JC FM1
L W#16#0110 // FM2 base = 272 decimal = 0x110
==I
JC FM2
JU UNK
FM1: L #OB40_POINT_ADDR
L W#16#1 // test bit 0 (upper limit)
AW
JPZ FM1_NOT_ULIM
L L#1
T DBW 0 // dbg_evt.FM1_UpLimitCnt + 1
FM1_NOT_ULIM: BEU
FM2: L #OB40_POINT_ADDR
L W#16#1
AW
JPZ FM2_NOT_ULIM
L L#1
T DBW 4 // dbg_evt.FM2_UpLimitCnt + 1
FM2_NOT_ULIM: BEU
UNK: L #OB40_MDL_ADDR
T DBW 8 // dbg_evt.UnknownIntAddr
BE
Note: the addresses inside "dbg_evt" are illustrative; map them to the actual DB layout of your project.
FM 350-1 Interrupt Sources — OB40_POINT_ADDR Decode
Per the FM 350-1 Operating Instructions, the FM 350-1 returns the following packed bit pattern in OB40_POINT_ADDR when a hardware interrupt fires:
| Bit in OB40_POINT_ADDR | Event |
|---|---|
| 0 | Upper count limit reached (comparison 1 / 2 if enabled) |
| 1 | Lower count limit reached |
| 2 | Count value overflow (count value wrap > 2^31) |
| 3 | Count value underflow |
| 4 | Gate start (HW gate or SW gate edge 0→1) |
| 5 | Gate stop (gate edge 1→0) |
If the FM 350-1 raises a diagnostic interrupt instead of a hardware interrupt, the CPU enters OB 82 (Diagnostic Interrupt) rather than OB 40. The OB82_MDL_ADDR tag inside OB 82 carries the FM 350-1 base address. Use the same demultiplex pattern there if you must route module-specific diagnostics.
Verification
-
Watch table test. Open a watch table with the FM1 and FM2 actual count value addresses plus the "dbg_evt" counters from the demultiplexer. Force a count on FM 1 by feeding a slow pulse train or by writing to the load value register and triggering a software gate. Observe that
FM1_UpLimitCntincrements andFM2_UpLimitCntstays at zero. - Repeat for FM 2 to confirm path B executes correctly.
- Buffer / diagnostic buffer check. The CPU's diagnostic buffer records each OB 40 entry with the start event "Hardware interrupt OB 40 from module <OB40_MDL_ADDR>". Open PLC > Diagnostic/Setting > Diagnostic Buffer and confirm two distinct base addresses are recorded when both modules fire.
- Online & Diagnostics on the FM 350-1. STEP 7 / TIA Portal exposes an "Online & Diagnostics" panel for the FM 350-1 showing the active interrupt status. Reference: TIA Portal: FM 350-1 Online & Diagnostics.
- Group error LED on the FM 350-1. The FM 350-1 group error LED lights if configuration is inconsistent or a diagnostic is pending. If the interrupt never fires, the first thing to check is whether the SF (group error) LED is on — this usually means the FM has rejected its parameter assignment.
Common Pitfalls
-
Comparing the wrong address. The value in
OB40_MDL_ADDRis the logical base address as configured in HW Config, not the slot number and not the physical address. If you rearranged modules and the addresses moved, the compare in OB 40 will no longer match. Always read the address from HW Config and update the OB code if the rack is rebuilt. - OB 40 not generated at all. If OB 40 is not in the project, the CPU goes into STOP on the first hardware interrupt (OB not loaded). Make sure OB 40 is present and downloaded.
- FM 350-1 not in RUN. The FM 350-1 must have a valid parameter assignment. If you see SF lit on the FM 350-1, the FM is in error and will not generate interrupts until the parameter assignment is corrected and the FM is restarted (power cycle or online → restart).
-
Multiple causes → one OB call. If a comparison match and an overflow happen on the same scan, the FM 350-1 may combine them into a single OB 40 entry with multiple bits set in
OB40_POINT_ADDR. Test each bit independently rather than treatingOB40_POINT_ADDRas an enumerated value. - Time spent in OB 40. The hardware interrupt latency on S7-300 is in the order of a few hundred microseconds, but the OB 40 itself runs to completion. Heavy logic in OB 40 delays the cyclic OB 1. Keep the demultiplexer and any direct application code lean; defer non-critical work to flags polled by OB 1.
Diagnostic Interrupt Companion (OB 82)
The FM 350-1 can also issue a diagnostic interrupt (for example, channel fault, parameter assignment error, or encoder wire break). The diagnostic interrupt calls OB 82, not OB 40. Inside OB 82, OB82_MDL_ADDR holds the triggering module's base address and OB82_IO_FLAG identifies whether it was an input event. The demultiplexer pattern is identical to OB 40. If your application has a strong requirement to keep OB 40 separate from diagnostic handling, route FM 350-1 hardware interrupts to OB 40 and let OB 82 handle the diagnostics side, then use the same address-comparison technique in OB 82 to direct module-specific diagnostic recovery.
Parameter Reference — FM 350-1 Hardware Interrupt Settings
| Parameter (FM 350-1 Properties) | Typical value | Effect on OB 40 |
|---|---|---|
| Hardware interrupt at upper limit | Enabled | OB 40 fires when count reaches upper comparison |
| Hardware interrupt at lower limit | Enabled | OB 40 fires when count reaches lower comparison |
| Hardware interrupt on overflow | Enabled | OB 40 fires on count overflow |
| Hardware interrupt on underflow | Enabled | OB 40 fires on count underflow |
| Hardware interrupt on gate start | Enabled | OB 40 fires on gate 0→1 transition |
| Hardware interrupt on gate stop | Enabled | OB 40 fires on gate 1→0 transition |
| Diagnostic interrupt | Enabled | Routes faults to OB 82, not OB 40 |
Summary
On an S7-300 CPU 315-2DP (6ES7 315-2AG10-0AB0), only OB 40 is registered for hardware interrupts. Two FM 350-1 modules must share OB 40, and the demultiplexing of "which module fired" is performed inside OB 40 by reading OB40_MDL_ADDR and comparing it to the configured logical base addresses. The OB40_POINT_ADDR word carries the event-cause bit pattern. This pattern is portable to OB 82 for diagnostic interrupts and to any other S7-300 CPU where only OB 40 is enabled. For S7-400 and CPU 319 deployments, the per-module OB assignment in HW Config is also available, but the demultiplexer pattern remains useful for handling the case where a single module raises multiple interrupt causes from a single OB call.
FAQ
Why can't I assign OB 41 to the second FM 350-1 in HW Config?
CPU 315-2AG10-0AB0 only enables OB 40 in its firmware for hardware interrupts. The S7-300 system supports OB 40 through OB 47 in the OS, but the specific CPU's runtime only registers OB 40. Check the CPU properties > Interrupts tab; OB 41 through OB 47 will not be available. Use the OB 40 demultiplexer pattern described above.
What does OB40_MDL_ADDR contain at runtime?
OB40_MDL_ADDR is a WORD local tag inside OB 40 that holds the logical base address (the start address shown in HW Config) of the module that triggered the hardware interrupt. For two FM 350-1 modules configured at base addresses 256 and 272, OB40_MDL_ADDR will be 256 when FM 1 fires and 272 when FM 2 fires.
How do I tell which interrupt cause fired on the FM 350-1?
Read OB40_POINT_ADDR as a 32-bit bit pattern. Bits 0 through 5 indicate upper limit, lower limit, overflow, underflow, gate start, and gate stop respectively. Test each bit with a bitwise AND against 1, 2, 4, 8, 16, 32 (or the hexadecimal equivalents 0x1, 0x2, 0x4, 0x8, 0x10, 0x20).
What if the CPU still goes into STOP on the FM 350-1 interrupt?
If OB 40 is missing from the S7 program, the CPU stops on the first hardware interrupt because the interrupt has no valid OB to call. Add OB 40 to the project (right-click the Blocks folder, Insert New Object > Organization Block, type OB 40), write at least a BE / RET instruction into it, and download. The CPU will then enter OB 40 instead of going to STOP.
Does the same pattern work for FM 350-2 or FM 450-1?
Yes. The OB40_MDL_ADDR / OB40_POINT_ADDR mechanism is part of the S7-300/400 system software and is not specific to the FM 350-1. Any module that raises a hardware interrupt into OB 40 fills these tags the same way. The bit layout of OB40_POINT_ADDR will differ per module; consult the specific operating instructions for the channel mapping. For the FM 350-1 specifically, see the FM 350-1 operating instructions.