Overview
Generating accurate, time-stamped event records for hundreds of digital inputs on a SIMATIC S7-315-2DP and forwarding them to a WinCC HMI/SCADA station is one of the most common long-tail problems in S7-300 engineering. The CPU supports time-of-day interrupts and a 40 ALARM_S concurrent instance cap (per Siemens Entry ID 841294), which makes the textbook Alarm-S path unusable for the typical 600–700 discrete signal scale. This article shows the engineered workaround: a polled high-speed input scan, a double-buffered SOE (Sequence of Events) DB in the CPU, and a WinCC tag/project configuration that consumes the buffer like a chronological message stream.
The approach below preserves the standard SIMATIC time model (UTC, no DST flag), works with STEP 7 V5.5 / V5.6 and WinCC V7.x or WinCC Professional (TIA Portal) V16–V18, and degrades gracefully when the buffer is full. The methods described are also valid for the S7-314, S7-315-2 PN/DP, S7-317, and S7-319 CPUs because they all share the same SFC 17/18 ALARM_S architecture and OB1 / OB40 dispatching model.
Prerequisites
| Item | Required value | Notes |
|---|---|---|
| CPU | 6ES7 315-2AFxx / 6ES7 315-2EHxx (S7-315-2DP / -2 PN/DP) | Firmware V2.x–V3.x. OB40 must be present. |
| STEP 7 | V5.5 SP4 or V5.6 with S7-CPU update package | For SFC 17/18 + IEC timers |
| WinCC | V7.4 SP1 / V7.5 / V16 Professional | Tag management + Alarm Logging |
| DI module | SM 321 (6ES7 321-1BL00-0AA0) or ET 200M (6ES7 153-1AA03) | Input filter 0.5–3 ms typical |
| Time source | SIMATIC procedure (master clock on CPU) or NTP via CP | Recommended: synchronize via SFC 0 SET_CLK once per shift |
| OB blocks | OB1, OB40, OB82, OB100, OB121 | OB40 is critical for sub-cycle event capture |
Time-Stamping Methods on S7-300: Comparison
Three implementation paths are available. The first two consume ALARM_S resources and are not viable at 700-signal scale; the third is the only one that scales.
| Method | Resolution | Max events / scan | Hardware cost | Recommended for S7-315-2DP? |
|---|---|---|---|---|
| ALARM_S via SFC 17/18 (OB40 hardware interrupt + time-of-day) | 1 ms (time-of-day stamp embedded by CPU) | 40 concurrent ALARM_S blocks per CPU | None | No — hard cap is 40 |
| S7-400 MCP/FM 350-1/2 hardware time stamping | ≤1 ms (synchronised, distributed) | 32 channels per module, expandable | MCP card, FM 350, isolated backplane slot | No — S7-400 only |
| Software polling + ring-buffer DB (this article) | OB1 cycle time, typically 5–20 ms | Unlimited (configurable ring depth, e.g. 4096 entries) | None | Yes — standard S7-300 + SM 321 |
Why the 40 ALARM_S Limit Exists
Siemens Entry ID 841294 documents that the S7-300 firmware maintains a fixed-size instance table for active ALARM_S / ALARM_8 / ALARM_8P blocks. Each ALARM_S instance costs one slot; the slot is held until the associated message acknowledgment state machine closes. With 700 monitored DIs, you would need at least 700 active instances during a worst-case event storm, which exceeds the 40-slot table and triggers Wöhler-style overflow errors (CPU diagnostic buffer entry "OB40 queue overflow" or "ALARM_S resource exhausted").
Two options remain on the S7-315-2DP:
- Use the standard WinCC chronological message path with a small number of high-priority signals only (process alarms, ESD trips, breaker status).
- Use a polled ring-buffer DB that the application program fills; WinCC reads the DB and generates chronological messages from a 1-second internal polling cycle.
Architecture: Polled SOE Buffer + WinCC Chronological View
The DB is a flat array of UDTs that the application writes on every DI edge. WinCC is configured with one WinCC tag per signal plus a shared "stamp / tail / overflow" triplet that tells the HMI which entries are new since the last read. The same triplets can drive a WinCC Alarm Logging control as user-defined messages via dynamic limits, or they can be displayed in a custom VB / C / C# script on the WinCC client.
Step-by-Step: Build the SOE DB and the Edge-Detect FC
Create the UDT, the ring-buffer DB, the edge-detect FC, and the OB40 dispatcher in STEP 7. All sample code targets STEP 7 V5.5 / V5.6 in STL/SCL.
Step 1 – Define UDT 10 (one SOE entry)
TYPE UDT 10
STRUCT
di_index : INT ; // 0..699 - which DI changed
di_state : BOOL ; // FALSE->TRUE=0 / TRUE->FALSE=1
reserved : BYTE ; // alignment
ms_since : DWORD ; // PLC tick in ms (SFC 64 TIME_TCK diff)
tod : DATE_AND_TIME ; // 8 bytes - SFC 1 READ_CLK
END_STRUCT
END_TYPE
Step 2 – Create DB 1000 (the ring buffer)
DATA_BLOCK DB 1000
TITLE = 'SOE Ring Buffer (4096 entries)'
STRUCT
head : INT ; // write pointer (0..4095)
tail : INT ; // read pointer (WinCC side, updated by WinCC)
overflow : BOOL ; // ring wrapped while WinCC did not read
loss_cnt : DWORD ; // events lost on overflow
last_tick : DWORD ; // last SFC 64 value for ms diff
buf : ARRAY[0..4095] OF UDT 10 ;
END_STRUCT
BEGIN
head := 0; tail := 0; overflow := FALSE;
loss_cnt := 0; last_tick := 0;
END_DATA_BLOCK
Step 3 — FC 100: Edge-detect on the 700 DIs
The function compares the current input image PEW/PEB against the previous image stored in a static DB. On any bit change, it records the DI index, new state, SFC 64 tick diff, and the current DATE_AND_TIME from SFC 1.
FUNCTION FC 100 : VOID
VAR_TEMP
t_di_word_idx : INT ;
t_bit_idx : INT ;
t_prev_word : WORD ;
t_curr_word : WORD ;
t_diff_word : WORD ;
t_di_index : INT ;
t_tick_now : DWORD ;
t_tick_prev : DWORD ;
t_tod : DATE_AND_TIME ;
t_retval : INT ;
END_VAR
BEGIN
// Read high-resolution tick (1 ms if OB period = 1 ms) - SFC 64
t_retval := TIME_TCK(); // returns t_tick_now
t_tick_prev := DB1000.last_tick;
DB1000.last_tick := t_tick_now;
FOR t_di_word_idx := 0 TO 21 DO // 22 words * 32 = 704 bits
t_prev_word := WORD_TO_BLOCK_DB(900).DW[t_di_word_idx];
t_curr_word := PIW[t_di_word_idx * 2]; // 0..43 process image
t_diff_word := t_prev_word XOR t_curr_word;
IF t_diff_word <> 0 THEN
FOR t_bit_idx := 0 TO 15 DO
IF (t_diff_word SHR t_bit_idx) AND 1 = 1 THEN
t_di_index := t_di_word_idx * 32 + t_bit_idx;
t_tod := DT0; // placeholder - see call below
// SFC 1: read time-of-day
t_retval := READ_CLK(LADDER:= t_tod);
// Write to ring buffer
DB1000.buf[DB1000.head].di_index := t_di_index;
DB1000.buf[DB1000.head].di_state := (t_curr_word SHR t_bit_idx) AND 1;
DB1000.buf[DB1000.head].ms_since := t_tick_now - t_tick_prev;
DB1000.buf[DB1000.head].tod := t_tod;
// Advance head with wrap, detect overflow vs tail
IF DB1000.head = 4095 THEN
DB1000.head := 0;
ELSE
DB1000.head := DB1000.head + 1;
END_IF;
IF DB1000.head = DB1000.tail THEN
DB1000.overflow := TRUE;
DB1000.loss_cnt := DB1000.loss_cnt + 1;
END_IF;
END_IF;
END_FOR;
END_IF;
WORD_TO_BLOCK_DB(900).DW[t_di_word_idx] := t_curr_word;
END_FOR;
END_FUNCTION
Step 4 — Wire FC 100 into OB1 (or OB40 for sub-cycle response)
For fastest capture, call FC 100 from OB40. Configure the SM 321 module hardware interrupts to fire on either rising, falling, or both edges. Each OB40 event indicates which channel changed; the FC then batches the additional bits that flipped during the same scan.
ORGANIZATION_BLOCK OB 40
TITLE = 'Hardware interrupt - DI edge dispatcher'
BEGIN
// OB40_POINT_ADDR tells us which channel triggered
IF OB40_POINT_ADDR >= 0 AND OB40_POINT_ADDR <= 21 THEN
CALL FC 100 ;
END_IF;
END_ORGANIZATION_BLOCK
Step 5 — Time synchronisation
Bring the CPU to wall-clock time using SFC 0 SET_CLK from a higher-level clock, or enable SIMATIC time on the CP 343-1 Lean (S7-300 family) so the CPU clock is a stratum slave. Without synchronisation, the SFC 1 timestamp drifts by the RTC tolerance (± a few seconds per day on standard 315-2DP).
// In OB100 (startup) - initialise CPU time from CP
t_retval := SET_CLK(SET := t_external_dt);
Step-by-Step: WinCC Project Configuration
- Open the WinCC Explorer, right-click Tag Management › SIMATIC S7 PROTOCOL SUITE › PROFIBUS (or TCP/IP) and create a new connection. Station address = CPU MPI / IP, slot = 2, rack = 0.
- Create a WinCC tag of type Raw Data Tag (16-bit) for the head pointer at
DB1000, DBB0 (INT). Repeat for tail atDB1000, DBB2and overflow atDB1000, DBX4.0. Update cycle: 1 s. - For every DI in the SOE buffer, create a structure tag of type Text tag with user-defined length pointing to a single UDT 10 element, e.g.
DB1000, DBB12 + i*16. The actual array is best loaded into a single 64 KB "SOE Shadow" data block, and the WinCC alarm control consumes the new entries from head→tail movement. - Open Alarm Logging › Message Classes and add a new class
SOEwith archive enabled. - Add a single User-defined message with 2 process values (DI index, DI state) and select the message number dynamically. Drive the message number from a C / VB action that converts
head - tailinto message numbers 100001–104096. Set the message text to"DI %1 changed to %2 at %3". - Enable the Chronological messaging option in Alarm Logging › Properties › Time and select Time stamp from AS. This is the WinCC V7.x switch that triggers the
PC time = CPU timebehaviour. - Place an AlarmControl on the desired picture, bind it to the SOE message class, and set sort order to Chronological descending with Process time as the secondary key.
Configuring the User-Defined Message Trigger
When a new entry is detected at the WinCC side, fire a single user-defined message with the DiagEvent API or MSG_EVENT C function. The two process values are populated from the shadow DB.
// VBScript bound to a 1 s cyclic trigger
Dim t_idx, t_state, t_text, t_msgno
t_idx = HMIRuntime.Tags("SOE_NewIndex").Read
t_state = HMIRuntime.Tags("SOE_NewState").Read
t_text = "DI " & t_idx & " -> " & t_state
t_msgno = 100000 + t_idx
HMIRuntime.AlarmLogging.Messages.Add t_msgno, vbCrLf & t_text, 0
For TIA Portal / WinCC Professional (V16–V18), the equivalent is the HMIRuntime.Alarm .NET API. See the WinCC Professional scripting manual for the C# overloads.
Time-Stamp Resolution and OB40 Latency
| Source of jitter | Typical | Worst case | Mitigation |
|---|---|---|---|
| DI module input filter | 1.2–3 ms | 3 ms | Configure SM 321 input filter to 0.5 ms (0.5 ms hardware debounce) |
| OB1 cycle time at 700 I/O | 8–12 ms | 20 ms (with 100% I/O update) | Switch update to partial process image (PII 1–9) and call FC 100 from OB40 only |
| OB40 hardware interrupt dispatch | 100 µs | 500 µs | Keep OB40 short; do not call SFC 1 from OB40 — it may take 200 µs |
| CP / MPI transfer latency to WinCC | 5–10 ms | 30 ms (MPI 187.5 kbit/s) | Use TCP/IP via CP 343-1 Lean; limit shadow-DB to 4 KB to fit 100 ms cycle |
Edge Cases and Field-Proven Caveats
- Burst overruns: If 100 DIs flip in a single 10 ms scan, FC 100 records 100 entries before WinCC can drain. The ring buffer absorbs this, but the overflow flag latches. Have the HMI alarm on the flag and force a manual acknowledge.
- DATE_AND_TIME wraparound: DATE_AND_TIME is encoded as BCD and the century byte is the high byte of the year. SFC 1 always returns the year in the range 1990–2089; do not decode it as a raw byte or you will see the year 2089 for a system clocked in 2025.
- OB40 module removal: If the DI module is removed/reinserted, the previous-image DB (DB 900) holds stale bits. Initialize DB 900 with the current PIW in OB100 (startup) to avoid a 700-event storm on the first scan.
- WinCC tag count limits: WinCC V7.4 limits a single channel to ~8 K tags. For 700 DIs plus the shadow tags (head, tail, overflow, plus shadow-DB as a 4 KB blob), use the Tag Multiplexing feature: define one 64 KB raw tag and re-map logical subranges with calculated field names.
- CPU clock drift: Standard 315-2DP has no battery-backed RTC by default on 6ES7 315-2AF03 – add a backup battery or a CP with SIMATIC time to keep the clock alive across power cycles.
Verification Procedure
- In STEP 7 PLCSIM, create a DB instance of DB 1000 and force specific bits in PIW 0–43. Observe that head advances and the corresponding UDT entries populate with the PLCSIM clock.
- In WinCC online tag diagnostics, watch the head and tail tags. The delta should never exceed 4095 and the overflow bit should remain 0 under normal load.
- Use the AlarmControl test mode. Force a new edge and verify that a single SOE message appears with the correct process values and that the timestamp matches the WinCC computer clock within the 20 ms resolution budget.
- Force a sustained burst (set 200 bits in PIW simultaneously) and confirm the overflow flag latches, the loss counter increments, and WinCC raises the
SOE_Overflowoperator message. - Power-cycle the WinCC station while the PLC keeps running. On restart, WinCC should re-acquire the tail from the current head and download the backlog. Verify the chronological view is complete.
Troubleshooting Matrix
| Symptom | Likely cause | Diagnostic step | Fix |
|---|---|---|---|
| Head does not advance when DIs change | PIW mapped to PII wrong / module on wrong slot | STEP 7 › HW Config › Inputs | Re-order address ranges; verify DI start address |
| Head advances but timestamps are all 0 | SFC 1 READ_CLK not executed | CPU diagnostic buffer | Call READ_CLK from FC 100; check return code |
| SOE messages in WinCC show wrong time | OS time zone / DST not set to UTC | Control Panel › Time Zone | Set Windows TZ = UTC, let WinCC show local; per 7604251 |
| Overflow latches immediately | WinCC never reads tail; tail stuck at 0 | WinCC tag diagnostics on tail | Update tail with a WinCC script or use a 2nd PLC for handshake |
| Timestamp off by exactly 1 hour in spring/autumn | DST flag in DATE_AND_TIME not respected by WinCC | Compare CPU time vs WinCC time | Run CPU in UTC, set WinCC TZ = UTC, see Siemens 7604251 |
| Only first 40 events captured per scan | Hit ALARM_S instance limit on a different code path | CPU buffer — search "ALARM_S" | Disable any other ALARM_S blocks; we are using FC 100 only |
| Chronological view shows events out of order | OB40 dispatching order varies | Check OB40 priority and OB1 nesting | Add a 1 ms TIME_TCK discriminator to UDT 10 and sort in WinCC |
Standards Cross-Reference
- IEC 61850-5 — Type 1 timing class requires 1 ms synchronisation. The software approach documented here does not meet Type 1; it meets Type 4 (10 ms) which is the typical SCADA requirement.
- IEC 60870-5-103 — Class 1 (10 ms) sequence-of-events, achievable with the present design if the SM 321 filter is set to 0.5 ms and OB40 latency is below 1 ms.
- IEEE C37.118 — Synchrophasor timing; not applicable to a 315-2DP SOE buffer.
FAQ
Can a S7-315-2DP handle 700 time-stamped digital inputs at all?
Yes, but not via the standard ALARM_S/ALARM_8 blocks: the firmware limit is 40 concurrent instances. Use a polled ring-buffer DB (FC 100 → DB 1000 in this article) that captures all 700 DIs in OB1 or OB40 and writes a UDT 10 entry per edge; the timestamp resolution is then bounded by OB1 cycle time plus DI filter, typically 10–20 ms total.
What timestamp resolution can I realistically achieve on a 315-2DP?
With a 0.5 ms SM 321 input filter, a 10 ms OB1 cycle, and OB40 dispatch for the first edge, you will see ~20 ms worst-case error versus the actual electrical transition. For sub-millisecond SOE recording you need an S7-400 with an MCP/FM 350 module, or an ET 200SP TM (Time stamping) submodule.
How do I avoid the 1-hour DST error in WinCC chronological messages?
Run the CPU in UTC (no DST), set the WinCC computer's time zone to UTC, and let the operator client perform the local conversion. Siemens document 7604251 explains that the AS time stamp carries no zone or DST information, so all localisation must be done in the SCADA layer.
Does WinCC need a special option to read the SOE DB?
No special option. The WinCC tag manager plus Alarm Logging with the Chronological messaging property and Time stamp from AS enabled is sufficient. The S7 connection (PROFIBUS or TCP/IP via the CP 343-1 Lean) is the same channel you use for cyclic I/O.
How is the buffer protected against WinCC downtime?
The ring depth (4096 entries × ~20 ms worst-case event spacing) gives roughly 80 s of buffering at 50 events/s. If WinCC stays offline longer than that, the overflow flag latches and the loss counter increments. The recommended response is a WinCC startup routine that sets tail := head on initial connect to discard the backlog and immediately log a system message.