S7-1200 Retentive Timer: Preserving Cumulative Runtime Across Power Cycles
Standard IEC 61131-3 timers (TP, TON, TOF) on the S7-1200 platform lose their elapsed time (ET) value on every power-off transition, CPU warm restart, and STOP-to-RUN transition. For applications that track cumulative equipment runtime for predictive maintenance, MTBF trending, regulatory audit, or process recipe state, the engineer must implement a retentive alternative. This reference covers three field-proven solutions: the built-in TONR time accumulator, a retained Data Block incremented by clock memory bits, and a scheduled-toggle pattern for components with on/off cycles. Each solution is mapped to the relevant TIA Portal configuration, the S7-1200 retentive memory architecture, and a commissioning procedure that verifies the values survive a real power-down event.
Why S7-1200 Standard Timers Reset on Power Cycle
The S7-1200 implements four IEC 61131-3 timer instructions in its system firmware:
-
TP- Pulse timer. Generates a fixed-duration output pulse on a rising edge of the input. -
TON- On-delay timer. Delays the rising edge of the output by the programmedPT. -
TOF- Off-delay timer. Delays the falling edge of the output by the programmedPT. -
TONR- Time accumulator. Retains the accumulatedETvalue.
The first three instructions store their elapsed time in volatile work memory that is initialized to zero on every power-up, STOP-to-RUN transition, or factory reset. This is correct behavior for a vast majority of automation tasks - a process waiting for a part to dwell for 10 seconds should restart its dwell timing when the controller reboots. The default is, however, wrong for cumulative-runtime tracking, hour-meter style counters, and any logic that depends on the duration of a state that persists across a power event.
Three transition events zero the volatile timer area:
- Power-off to power-on (cold start).
- STOP to RUN on the CPU operator panel or via
PG_STOP_RUNfrom the engineering station. - Memory reset (MRES) - clears both volatile and retentive memory; this is the "factory reset" mode and should be reserved for commissioning or genuine fault recovery.
S7-1200 Retentive Memory Architecture
The S7-1200 backs up its retentive area in NVRAM that is electrically isolated from the working memory. The retain area is updated at each STOP-to-RUN transition and at power-down (capacitor-backed for several milliseconds). The size of the retain area is fixed per CPU and can be partially assigned to M (bit memory), T (timer words), C (counter words), and Data Block bytes.
Default retain area sizes for the S7-1200 family:
| CPU Model | Total Retain (bytes) | M (bytes, default) | T (count, default) | C (count, default) | DB (bytes, default) |
|---|---|---|---|---|---|
| CPU 1211C | 10240 | 0 | 0 | 0 | 10240 |
| CPU 1212C | 10240 | 0 | 0 | 0 | 10240 |
| CPU 1214C | 10240 | 0 | 0 | 0 | 10240 |
| CPU 1215C | 10240 | 0 | 0 | 0 | 10240 |
| CPU 1217C | 10240 | 0 | 0 | 0 | 10240 |
Source: S7-1200 Programmable Controller System Manual. Confirm the exact retain allocation for your CPU in the device configuration under Properties > System and Clock Memory.
The default allocation gives the entire retain budget to Data Blocks. The standard pattern is therefore: store all runtime data in one or more Data Blocks with the retain attribute set, and reduce or eliminate M-area retain. The retain pool is consumed greedily: if you declare 14 KB of retained DBs on a CPU with only 10 KB of backup, the project compiles with an error at the retain budget step.
Solution 1 - IEC TONR Time Accumulator
The TONR instruction is the only built-in IEC timer that retains its ET value through power cycles. While IN is TRUE, ET accumulates. When IN goes FALSE, ET holds. The value is reset only when the R (Reset) input goes TRUE or the CPU performs a memory reset.
SCL declaration in a function block:
// Pump 1 cumulative runtime accumulator
"Pump1_Runtime_TONR"(IN := "Pump1_Running",
PT := T#24d20h31m23s647ms, // Maximum TIME value
Q => "Pump1_TONR_Q",
ET => "Pump1_TONR_ET");
// Reset path - explicit operator action only
IF "Reset_Pump1_Runtime" THEN
"Pump1_Runtime_TONR"(IN := "Pump1_Running",
R := TRUE,
PT := T#24d20h31m23s647ms,
Q => "Pump1_TONR_Q",
ET => "Pump1_TONR_ET");
END_IF;
The ET output of TONR is wired into a tag of data type TIME (DWORD, 32-bit signed, ms resolution). The maximum value T#24d20h31m23s647ms is just over 24.86 days. For a pump that runs 24 hours a day, this is a short window before the TONR saturates. To track longer runtimes, convert ET to hours in a separate tag and use a derived rollover counter:
// Roll over ET to DINT (hours) and accumulate the rest
"Pump1_Runtime_TONR"(IN := "Pump1_Running",
PT := T#24d20h31m23s647ms,
Q => "Pump1_TONR_Q",
ET => "Pump1_TONR_ET");
// Every hour boundary, increment the cumulative hours DB tag
IF "Pump1_TONR_ET" >= T#1h AND "Pump1_Hourly_Tick" THEN
"RuntimeDB".Pump1_Hours := "RuntimeDB".Pump1_Hours + 1;
"Pump1_TONR_ET" := T#0s; // Cannot write - use reset instead
END_IF;
IF "Reset_Pump1_Runtime" THEN
"Pump1_Runtime_TONR"(IN := "Pump1_Running",
R := TRUE,
PT := T#24d20h31m23s647ms,
Q => "Pump1_TONR_Q",
ET => "Pump1_TONR_ET");
"RuntimeDB".Pump1_Hours := 0;
END_IF;
Behavior comparison of S7-1200 timer instructions:
| Instruction | ET Retentive by Default | Reset Trigger | Typical Use |
|---|---|---|---|
| TP | No | IN = FALSE, CPU restart | Fixed-pulse output |
| TON | No | IN = FALSE, CPU restart | On-delay timing |
| TOF | No | IN = TRUE, CPU restart | Off-delay timing |
| TONR | Yes | R = TRUE, MRES, or non-retain config | Cumulative runtime |
TONR is the right choice when the application is a single monotonically increasing hour-meter. For more complex needs (multiple components, on/off scheduling, recipe-driven setpoints), use the patterns in Solution 2 or 3.
Solution 2 - Retained DB with Clock Memory Bit Increment
For a fleet of components, the canonical Siemens pattern is a retained Data Block whose tags are incremented once per second (or per 100 ms, or per minute) while the component is running. The increment source is a clock memory bit, a free-running bit toggled by the CPU firmware at a configured frequency.
Step 1 - Enable clock memory in the device configuration:
- In the project tree, right-click the CPU and select Properties.
- Open the System and Clock Memory tab.
- Check Enable Clock Memory byte.
- Set the Clock Memory byte address. The default is MB0; the recommended address is MB10 or higher to avoid collision with the bit memory used for handshake logic.
The eight bits of the clock memory byte toggle at fixed frequencies:
| Bit | Frequency | Period | Typical Use |
|---|---|---|---|
| M[y].0 | 10 Hz | 100 ms | Fast blink, debounce refresh |
| M[y].1 | 5 Hz | 200 ms | Heartbeat |
| M[y].2 | 2.5 Hz | 400 ms | HMI refresh |
| M[y].3 | 2 Hz | 500 ms | Status update |
| M[y].4 | 1 Hz | 1000 ms | Second tick - runtime accumulator |
| M[y].5 | 0.5 Hz | 2000 ms | Heartbeat, slow LED |
| M[y].6 | 0.2 Hz | 5 s | Slow status |
| M[y].7 | 0.1 Hz | 10 s | Watchdog |
Step 2 - Declare a retained Data Block:
DATA_BLOCK "RuntimeDB"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
STRUCT
Pump1_Runtime_s : DINT; // Cumulative seconds, retained
Pump2_Runtime_s : DINT; // Cumulative seconds, retained
Conveyor_Runtime_s : DINT; // Cumulative seconds, retained
LastPowerLoss : DATE_AND_TIME; // Timestamp of last detected restart
Magic_Code : INT; // First-run detection sentinel
END_STRUCT;
RETAIN
END_DATA_BLOCK
Step 3 - Increment logic in OB1 (cyclic main):
// Edge detection on the 1 Hz clock bit
IF "Clock_1Hz" AND NOT "Clock_1Hz_Prev" THEN
IF "Pump1_Running" THEN
"RuntimeDB".Pump1_Runtime_s := "RuntimeDB".Pump1_Runtime_s + 1;
END_IF;
IF "Pump2_Running" THEN
"RuntimeDB".Pump2_Runtime_s := "RuntimeDB".Pump2_Runtime_s + 1;
END_IF;
IF "Conveyor_Running" THEN
"RuntimeDB".Conveyor_Runtime_s := "RuntimeDB".Conveyor_Runtime_s + 1;
END_IF;
END_IF;
"Clock_1Hz_Prev" := "Clock_1Hz";
The DINT format supports up to 2,147,483,647 seconds (~68 years), well beyond the design lifetime of the equipment it tracks. For sub-second resolution, increment a REAL in a 100 ms task block:
// 100 ms task OB (configured in CPU Properties > Cyclic Interrupts)
IF "Clock_10Hz" AND NOT "Clock_10Hz_Prev" THEN
IF "Motor_Running" THEN
"RuntimeDB".Motor_Runtime_100ms := "RuntimeDB".Motor_Runtime_100ms + 0.1;
END_IF;
END_IF;
"Clock_10Hz_Prev" := "Clock_10Hz";
This pattern is field-proven in thousands of S7-1200 installations. The combination of optimized-block access (S7_Optimized_Access := 'TRUE'), retain attribute, and 1 Hz clock bit increment gives a robust runtime meter that survives every power event short of a memory reset.
Solution 3 - Scheduled Toggle Pattern for Cyclic Components
When a component must run for a defined OnDuration, shut off for a defined OffDuration, and repeat indefinitely, store the next toggle time in a retained DB and compare against the current PLC time-of-day at every scan.
DATA_BLOCK "ScheduleDB"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
STRUCT
Pump1_NextOn : DATE_AND_TIME; // Retained
Pump1_NextOff : DATE_AND_TIME; // Retained
Pump1_OnTime : TIME; // Retained, e.g., T#30m
Pump1_OffTime : TIME; // Retained, e.g., T#10m
Pump1_Initialized : BOOL; // First-run sentinel
END_STRUCT;
RETAIN
END_DATA_BLOCK
Scan-cycle logic in OB1:
// Read current time once per cycle
"CurrentDT" := RD_SYS_T();
// Pump 1 scheduled control
IF "CurrentDT" >= "ScheduleDB".Pump1_NextOn THEN
"Pump1_Output" := TRUE;
"ScheduleDB".Pump1_NextOff := "CurrentDT" + "ScheduleDB".Pump1_OnTime;
END_IF;
IF "CurrentDT" >= "ScheduleDB".Pump1_NextOff THEN
"Pump1_Output" := FALSE;
"ScheduleDB".Pump1_NextOn := "CurrentDT" + "ScheduleDB".Pump1_OffTime;
END_IF;
Initialize on first scan (OB100):
// Warm restart - one-time execution on STOP-to-RUN
IF NOT "ScheduleDB".Pump1_Initialized THEN
"ScheduleDB".Pump1_OnTime := T#30m;
"ScheduleDB".Pump1_OffTime := T#10m;
"ScheduleDB".Pump1_NextOn := "CurrentDT" + T#5s; // start in 5 seconds
"ScheduleDB".Pump1_Initialized := TRUE;
END_IF;
This pattern is what Siemens documentation refers to as "time-tagging" or "scheduled action" logic. Because both the toggle times and the operator-editable setpoints are retained, the schedule resumes on the second after the controller returns from a power outage. The only behavior the engineer must document is whether the pump is on or off when power is restored: the current logic returns the pump to the state implied by the current CurrentDT relative to the saved Pump1_NextOn and Pump1_NextOff times.
Configuring Retain Attributes in TIA Portal
The retain configuration lives in two places: the CPU-wide retain allocation and the per-DB retain attribute.
CPU-wide retain allocation (M, T, C areas):
- Device Configuration > double-click the CPU.
- Properties > System and Clock Memory.
- Adjust Number of memory bytes starting at MB0 - declares the byte count of M-area retain.
- Adjust Number of retentive timers - assigns a number of T-word slots to retain. The S7-1200 supports retain for
IEC_TIMERinstances whose backing T-word falls inside the retain range. - Adjust Number of retentive counters - same logic for C words.
For most modern code, M-area retain is set to 0 and all runtime data is moved to retained Data Blocks. T-area retain is rarely used on S7-1200; the standard pattern uses TONR or a clock-bit-incremented DB instead.
DB-level retain attribute:
- Open the Data Block in the project tree.
- Right-click the DB > Properties.
- Open the Attributes section.
- Set Retain to one of: Non-retain, Set in IDB (the value comes from the initial value column in the DB editor), or Retain.
For a brand-new DB used for runtime accumulators, the typical settings are:
// DB Properties > Attributes > Retain: "Retain" (the value persists from the last write)
// DB Properties > Attributes > Optimized block access: TRUE (recommended for firmware 4.0+)
For per-tag retain within a DB, select the tag in the DB editor and set the Retain dropdown in the right-hand Properties pane. This is useful when a single DB holds both retained (runtime counters) and non-retained (status flags) data.
Output State Retention on Power Restoration
The S7-1200 default after power-up is to drive all standard outputs to 0V. This is intentional - a motor starter that energizes unexpectedly after a brownout is a safety hazard. For applications that legitimately need to resume the last output state (a heating jacket that must stay on, a holding solenoid that releases only on operator command), the engineer has three options.
Option 1: External mechanical latching relay. The most reliable pattern. The PLC output drives a latching relay coil; the relay contacts hold the last state through a complete power loss. The PLC reads the relay state back via a digital input on power-up. This works on every S7-1200 variant and survives brownouts, voltage sags, and MRES events.
Option 2: Signal Board outputs with retain. Some S7-1200 Signal Boards (SB) support output-bit retain. The exact support is per model; consult the S7-1200 System Manual section "Digital outputs". Onboard outputs on the CPU 1214C, 1215C, and 1217C are not retain-capable.
Option 3: Software restore from retained DB. On power-up, the OB100 reads the saved LastOutputState from the retained DB and writes it to the output process image. This is the simplest software-only approach but requires that the field wiring and loads tolerate a brief power-off state followed by restoration of the previous state. For safety-class outputs, never use this pattern without a hardwired safety relay upstream of the PLC output.
// OB100 - power-up restore
"Pump1_Output" := "RuntimeDB".Pump1_LastOutputState;
"Conveyor_Output" := "RuntimeDB".Conveyor_LastOutputState;
OB100 Warm Restart for Power Recovery
The S7-1200 invokes OB100 once on the STOP-to-RUN transition. The OB100 start information includes a 20-byte OB_STARTUP_INFO struct with the start event, the master's diagnostic address, and the rack/slot. The standard use is to set a first-scan flag, evaluate stored time, and adjust the process image to match the retained values.
ORGANIZATION_BLOCK "OB100_WarmRestart"
VERSION : 1.0
VAR_TEMP
StartupInfo : OB_STARTUP_INFO;
END_VAR
BEGIN
// Detect first scan after power-up
"FirstScan" := TRUE;
"PowerRecoveryFlag" := TRUE;
// Read startup diagnostic info
IF StartupInfo.STG_FLT THEN
"StartupFault_Present" := TRUE;
END_IF;
// Re-evaluate the scheduled toggle state
"CurrentDT" := RD_SYS_T();
// Force a one-time initialization for any sentinel-guarded DB
// (handled per DB inside the DB-specific logic)
END_ORGANIZATION_BLOCK
Typical diagnostic tags set inside OB100 for use in the HMI:
-
FirstScan- clears in OB1 after the first scan completes. -
PowerLossDetected- latches a bit the operator can acknowledge from the HMI. -
LastPowerLoss_Time- timestamp read fromRuntimeDB. -
ColdRestartCount- incremented counter to track how many power events the controller has seen.
For more granular fault handling, enable OB82 (diagnostic interrupt), OB83 (insert/remove), OB86 (rack failure), and OB122 (programming access error). On a non-faulted warm restart, only OB100 fires.
Verification and Commissioning Procedure
The following procedure verifies that the runtime values survive a real power cycle. The bench version uses the engineering station's online panel; the field version uses a manual breaker open/close.
Bench verification (engineering station only):
- Build and download the project to the CPU. Resolve any retain-budget compile errors.
- Go online with the CPU.
- Open a Watch Table that includes the retained tags (
RuntimeDB.Pump1_Runtime_s, etc.) and the clock memory byte (e.g., MB10). - Force the input that drives
Pump1_RunningTRUE. Observe the runtime tag incrementing once per second. - Allow the value to reach 30+ seconds. Record the value.
- On the CPU operator panel or in TIA Portal, switch the CPU from RUN > STOP > RUN. This is a warm restart that triggers OB100 and exercises the retain path.
- Re-read the runtime tag. The value must be 30+ seconds, not 0.
- Toggle the CPU RUN > STOP > RUN again. The value must be unchanged.
- Repeat the test for every retained tag in the project.
Field verification (with main breaker):
- Verify clock memory bits are toggling. In the Watch Table, enable cyclic update for MB10 and confirm the bits change at the expected frequency.
- Record the current HMI-displayed runtime values for all tracked components.
- Open the main breaker to the S7-1200 power supply. Wait at least 30 seconds - this exceeds the NVRAM capacitor backup time and forces a cold restart.
- Re-close the main breaker. Watch the CPU boot sequence: any LED fault indication is logged in the diagnostic buffer.
- Confirm OB100 executed:
FirstScanis TRUE for one scan, then FALSE. - Read the HMI value. It must match the pre-outage value.
- If the HMI shows 0, the retain attribute was not applied to that tag. Open the DB, verify the Retain dropdown is set to Retain, recompile, re-download.
Troubleshooting Matrix
| Symptom | Probable Cause | Corrective Action |
|---|---|---|
| TONR ET resets to 0 on power cycle | PT set to T#0s, or R input is unconditional | Inspect the R-input logic; gate the reset on an explicit operator action |
| Clock memory bit not toggling | Clock memory byte not enabled | CPU Properties > System and Clock Memory > Enable Clock Memory byte |
| Retained DB value clears on power cycle | DB Retain attribute not set | DB Properties > Attributes > Retain = "Retain" |
| Increment rate 2x expected | Two OB1 instances, missing edge detection, or scan time > 1 s | Use rising-edge detection on the 1 Hz bit; check cyclic task configuration |
| DINT counter overflow | Runtime > 68 years | Use LREAL, or split into hours and seconds tags, or wrap with modular counter |
| Output resets to 0 after power-up | Output channel not retain-capable | Use external latching relay, or OB100 software restore from retained DB |
| HMI shows wrong value after restart | HMI tag pointer broken, DB renamed, optimized-access mismatch | Re-compile HMI tags, verify DB number, enable symbolic addressing in HMI |
| Compile error: retain area too large | Sum of declared retains > CPU limit | Reduce M-area retain; consolidate DBs; or move to larger CPU |
| Value restores but with wrong state | OB100 logic not re-evaluating against current time | Add RD_SYS_T call in OB100, recompute outputs based on saved NextOn/NextOff |
| Value changes mysteriously on startup | First-scan logic overwriting the retained value | Use a sentinel/initialized flag to prevent first-run code from running after a real power cycle |
Best Practices for Long-Term Reliability
These practices extend from the S7-1200 System Manual, the TIA Portal help, and field experience across hundreds of installations.
- Use TIME format for durations. The TIME data type is milliseconds stored as a 32-bit signed value, with implicit unit awareness in HMI faceplates. Avoid raw DINT millisecond counters when a TIME tag communicates intent more clearly.
- Persist a checksum. Compute a CRC16 or simple XOR over the retained data and store it in the same DB. On OB100, verify the checksum matches; if it does not, log a diagnostic event to the HMI - this is a sentinel for NVRAM corruption in aging hardware.
- Mirror critical runtime to the SD card. The S7-1200 supports data logging and recipes on SD. Mirror the runtime DB to a CSV row on the SD card at end-of-shift. This protects against MRES operator error and NVRAM failure.
-
Timestamp the last write. Store a
LastUpdatetag in the retained DB and stamp it on every increment cycle. The HMI can show "Last updated: 0 seconds ago" so the operator can confirm the runtime is live, not stuck. - Avoid writing retained tags every scan. The 1 Hz clock bit pattern is a healthy balance between accuracy and NVRAM endurance. If sub-second accuracy is required, accumulate in a non-retained tag inside a 10 ms cyclic interrupt and write to the retained tag once per second.
-
Prefer optimized block access.
S7_Optimized_Access := 'TRUE'on the DB is recommended for firmware V4.0 and later. Symbolic addressing reduces HMI tag maintenance and is required for some TIA Portal features. - Document the retain schema in the program header. The retain layout is part of the machine's state. A maintenance engineer who replaces the CPU must know which DBs are the runtime DBs so they are not inadvertently deleted during a refactor.
- Test with a real power outage. Engineering-station STOP-RUN toggles do not exercise the full retain path. A 30-second breaker-open test is the only verification that catches subtle bugs (e.g., initialization code in OB100 that overwrites a retained value because the sentinel flag is also retained as TRUE).
Related Functionality: Trace, Data Logging, Recipes
The S7-1200 offers three complementary features that work with the runtime retention pattern described above:
- Trace - records up to 16 tags at configurable sample rates. Use to capture the runtime DB values during commissioning. Trace data is stored in the CPU and can be exported to CSV.
- Data Logging - writes structured records to the SD card. Mirror the runtime counters to a log file on each shift change. The SD card survives a CPU replacement.
- Recipes - the S7-1200 recipe view in TIA Portal reads and writes sets of tags to/from the SD card. Use to back up the runtime DB on machine build and restore on rebuild.
For detailed parameter references and step-by-step wizards, the official S7-1200 Programmable Controller System Manual and the TIA Portal online help (accessible from within the engineering software via F1) are the authoritative sources for the retain configuration described in this article.
Which S7-1200 timer is retentive by default?
The IEC TONR (Time Accumulator) instruction is the only built-in timer that retains its elapsed time (ET) value through power cycles, STOP-to-RUN transitions, and firmware restarts. The TP, TON, and TOF instructions all reset ET to zero on any of these events.
How do I enable retentive memory on an S7-1200 Data Block?
Open the Data Block in TIA Portal, right-click and select Properties, open the Attributes section, and set Retain to "Retain" for the entire DB. For per-tag retain, select the tag in the DB editor and set the Retain dropdown in the right-hand Properties pane. The CPU's total retain budget (default 10 KB on most S7-1200 CPUs) must not be exceeded.
What is clock memory and how do I use it for runtime accumulation?
Clock memory is a free-running byte configured under CPU Properties > System and Clock Memory. The eight bits toggle at fixed frequencies from 10 Hz down to 0.1 Hz. To accumulate runtime, detect the rising edge of the 1 Hz bit (or 10 Hz for sub-second resolution) inside OB1 or a cyclic interrupt and increment a retained DINT or REAL tag while the tracked component is active.
Do S7-1200 outputs retain their state on power-up?
Standard onboard outputs on the S7-1200 default to 0V on power-up and are not software-retainable in every variant. Some Signal Board outputs support output-bit retain. For guaranteed output state retention, use an external mechanical latching relay or restore the output state from a retained Data Block inside OB100. Never apply this pattern to safety-class outputs that must restart in the safe state.
How much retentive memory does my S7-1200 CPU have?
The standard S7-1200 CPUs (1211C, 1212C, 1214C, 1215C, 1217C) provide 10240 bytes of retentive memory by default, allocated to Data Blocks. The exact allocation is configurable under CPU Properties > System and Clock Memory. Check the compile output for retain-budget errors before declaring any runtime target.