Retain S7-1200 HSC Encoder Position After CPU Restart

David Krause15 min read
S7-1200SiemensTutorial / 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

Retain S7-1200 HSC Encoder Position After CPU Restart

High Speed Counter (HSC) input words such as %ID1000 on a Siemens SIMATIC S7-1200 are process-image locations that map to a hardware counter channel. They are updated every cycle of the I/O image and are not retentive by default. When the CPU transitions from RUN to STOP, when power is removed, or when the program block is reloaded without a master reset, the HSC counter register continues to count only as long as power is applied to the digital inputs. Once the CPU loses the run-time context, the counter is reset to the configured initial value (typically 0) on the next start-up.

This article documents the correct way to capture the live HSC count on every scan, copy it into a retentive data block, and restore that value on the next STARTUP so that the axis position survives power-off, STOP-RUN transitions, program reloads, and warm restarts. The guidance applies to the S7-1200 firmware family V4.x and later, programmed with TIA Portal V13 and newer (validated against V16, V17, V18, and the V20 release line).

Note. A "retain" attribute on a tag is not the same thing as a "remnant" hardware counter. The HSC silicon always restarts at its configured initial value; what you retain is a software copy of the last observed count, and you must write it back into the HSC after start-up if you want the process image word to reflect the pre-outage position.

1. Problem Definition

Symptoms reported in the field:

  • Connecting an incremental encoder to the HSC inputs (for example I0.0, I0.1, I0.2 on a CPU 1214C) gives a stable, monotonically changing count at %ID1000 while the CPU is in RUN.
  • On a power-off / power-on cycle, or after STOP → RUN, the value at %ID1000 returns to 0 (or to whatever "Initial counter value" was configured in the HSC device configuration) instead of the last observed encoder position.
  • Copying %ID1000 into a DB whose tags have the Retain box ticked does not, by itself, solve the problem. The retained value is preserved across the restart, but the live HSC count still starts from zero, so on the first scan after STARTUP the process image shows zero again.
  • A master reset (MRES) from the programmer or a factory reset via the SIMATIC memory card correctly zeroes the retained value as well, which is the desired safety behavior for commissioning.

2. Root Cause: Where the HSC Count Actually Lives

On an S7-1200 the HSC peripheral address (e.g. %ID1000 for HSC1, %ID1002 for HSC2, and so on up to %ID1018 for HSC6 on a CPU 1217C) is a 32-bit signed integer in the I/O input process image. The HSC is implemented in the CPU's onboard I/O silicon. The hardware counter is loaded from the Initial counter value on every STARTUP, including warm restart, cold restart, and the first cycle after power-on. It is then incremented or decremented by the encoder edges until the next STOP.

Because the counter is hardware state and not a normal CPU memory location, it is not covered by the S7-1200 retentive memory model. The retentive bit-memory area (%MB0%MBn) and retentive DB tags are implemented in the CPU's internal SRAM backed up by the optional battery (BB 1297) or by the maintenance-free retentive store on newer CPUs. Neither mechanism can snapshot the live silicon counter. The only correct way to "retain" the HSC value is:

  1. Mirror %ID1000 into a retentive DB tag in OB1 (cyclic), or directly in the HSC's update OB if configured.
  2. On STARTUP (OB100), write that retained tag back into %ID1000 via the HSC control byte, or use it as the process-side position and leave the HSC alone.

3. Prerequisites

  • SIMATIC S7-1200 CPU, any model (1211C / 1212C / 1214C / 1215C / 1217C) with firmware V4.0 or later. The HSC functionality is supported on all standard CPUs in the family; the number of available HSC channels varies (see the table below).
  • Incremental encoder wired to the on-board inputs. For quadrature (four-fold evaluation) use two channels, e.g. A on I0.0, B on I0.1, optional Z (reference mark) on I0.2.
  • Encoder output type compatible with the S7-1200 digital inputs: 24 V HTL push-pull, or 24 V PNP sourcing, or 5 V TTL via a signal conditioner. Differential RS-422 outputs require the signal conditioner 6ES7 132-6BD20 (SB 1221) or an external differential receiver.
  • Encoder supply: 24 V DC sourced from the CPU sensor power terminals or from a separate PSU if current draw exceeds 200 mA per channel group.
  • TIA Portal V13 or later installed (V16, V17, V18, or V20 recommended for current support).
  • Programmer access to the CPU (online via PROFINET, Ethernet, or the SIMATIC memory card).

4. S7-1200 HSC Channel Allocation

The number of HSC channels and their default pin assignments depend on the CPU model. Pin assignments can be reassigned in the device properties if a channel is not used by another function such as PTO (Pulse Train Output) or PWM.

CPU HSC channels Default input assignment (HSC1–HSC6) Max encoder frequency (quadrature)
CPU 1211C 3 I0.0 / I0.1, I0.2 / I0.3, I0.4 / I0.5 (digital inputs only) 100 kHz
CPU 1212C 4 I0.0–I0.5 (digital), I0.6–I0.7 optional 100 kHz
CPU 1214C / 1215C 6 I0.0–I1.5 (on-board) 100 kHz (digital), 1 MHz with SB
CPU 1217C 6 I0.0–I1.5 plus DIO 2 (SB) up to 1 MHz 1 MHz

The process image input words for HSC1–HSC6 are %ID1000, %ID1002, %ID1004, %ID1006, %ID1008, and %ID1010 respectively. Each HSC also has a 16-bit control byte that drives functions such as gate enable, synchronization, and initial-value loading. The exact layout is in the S7-1200 System Manual, chapter "High-speed counters".

5. Procedure: Build a Retentive Position DB

5.1 Configure the HSC in Device Properties

  1. In the TIA Portal project tree, open Devices & networks and double-click the S7-1200 CPU.
  2. Select Properties > High-speed counters (HSC).
  3. Enable HSC1 and select Mode: Counting or Measuring as required. Choose Counting mode: Two-phase for quadrature (X1, X2, or X4 evaluation).
  4. Set the Initial counter value (the value the HSC loads on every STARTUP) to 0 for now; it will be overwritten by the retention logic on each start-up.
  5. Set the upper and lower limits appropriate for your mechanics. If the axis can run negative, allow the lower limit to be negative; the HSC count is a signed DINT.
  6. Under Hardware inputs, assign the encoder A, B, Z signals to the on-board inputs that match your wiring.
  7. Confirm and compile the hardware configuration.

5.2 Create the Retentive Data Block

  1. In the project tree, add a new Data Block (for example DB_EncoderRetention, DB number 200).
  2. Open the DB, then click the small "gear" icon next to the block name to open DB properties.
  3. Deselect Optimized block access only if your program uses absolute addresses (e.g. DB200.DBD0). For new projects, optimized access is preferred; if you enable optimization, you access the tag by symbolic name ("DB_EncoderRetention".Position).
  4. In the DB properties page, locate the Retain column. There are two settings that must be correct:
    • Memory area of the DB tags: switch from Non-retentive to Retain for every tag that should survive a restart. For a single position value, the simplest approach is to click the DB header row and set the entire DB's tag area to Retain.
    • Retain memory area in the CPU: this is configured in the CPU properties, see step 5.3.
  5. Add the following tags (adjust names to your convention):
    DATA_BLOCK "DB_EncoderRetention"
    { S7_Optimized_Access := 'TRUE' }
    VERSION : 0.1
    NON_RETAIN
      REPEAT_HSC1 : DINT;          // raw HSC count, non-retentive (snapshot buffer)
    END_NON_RETAIN
    RETAIN
      LastPosition : DINT;          // last observed HSC count, retained
      SavedAt      : DATE_AND_TIME; // optional timestamp
      RestoreFlag  : BOOL;          // set to TRUE while restoring
    END_RETAIN
    END_DATA_BLOCK
  6. Compile the DB and download it to the CPU.
Warning. A common mistake is to mark only LastPosition as retain but leave the DB's default memory area as Non-retentive. The DB will compile fine and the box will look ticked, but the value will still be lost because the entire block is in the non-retain region of the CPU's memory map. Always verify that the CPU's retain range covers the DB number you are using.

5.3 Configure the Retain Range in the CPU

  1. In the CPU device properties, open System and clock memory and confirm that Retentive memory is enabled.
  2. Open PLC > Properties > Retentive memory.
  3. Allocate bytes to the following three areas:
    • Retentive bit memory (M): number of MB starting from %MB0. Default is 0.
    • Retentive counters (C): default 0.
    • Retentive timers (T): default 0.
  4. DBs are handled separately. A DB is retentive if either:
    • The block was loaded with the Retain attribute (in the DB properties), and the DB number falls inside the configured retentive DB range; or
    • All tags in the DB are individually marked retain (this works for optimized access DBs without an explicit DB-range allocation).
  5. Click Compile, then download the hardware configuration to the CPU.

CPU-specific retain memory sizes (approximate, for V4.x firmware):

CPU Work memory (program/data) Max retain area (DB + M + C + T) Battery
1211C DC/DC/DC 30 KB / 50 KB 14 KB None (non-volatile)
1212C DC/DC/DC 50 KB / 75 KB 14 KB None
1214C DC/DC/DC 75 KB / 100 KB 14 KB None
1215C DC/DC/DC 100 KB / 150 KB 14 KB None
1217C DC/DC/DC 125 KB / 175 KB 14 KB None

All S7-1200 CPUs store the retain area in non-volatile SRAM without needing the BB 1297 battery (the BB 1297 is only required if you want to retain the real-time clock past a power cycle longer than the supercap hold-up time).

5.4 Program Logic: Snapshot in OB1, Restore in OB100

The recommended pattern is to use OB100 (warm restart) to set a "first scan" flag and write the retained value into the HSC, then use OB1 (cyclic) to keep the DB mirrored against the live HSC count.

OB100 – Startup logic (SCL)

// OB100 "Complete restart" - runs ONCE after power-on / STOP-RUN
IF "DB_EncoderRetention".LastPosition <> 0 THEN
    // Force the HSC to reload its initial value from the DB
    // by toggling the HSC1 "Load initial value" bit in the HSC CTRL byte
    // (byte offset depends on slot; HSC1 CTRL byte is %QB1000 by default)
    "HSC1_Ctrl".LoadInitialValue := TRUE;          // set bit 3 of CTRL byte
    "DB_EncoderRetention".RestoreFlag := TRUE;
END_IF;
// Alternative: write the retained value into the ID image directly
// (useful only for display; the HSC silicon ignores ID writes
//  unless the CTRL byte "Load initial value" bit is pulsed)
"HSC1_PV" := "DB_EncoderRetention".LastPosition;

OB1 – Cyclic snapshot (LAD or SCL)

// OB1 - cyclic
// Mirror live HSC1 count into the non-retentive tag, then
// write that into the retentive tag every scan.
"DB_EncoderRetention".REPEAT_HSC1 := "HSC1_Count";
"DB_EncoderRetention".LastPosition := "DB_EncoderRetention".REPEAT_HSC1;

// Optional: timestamp the save (uses the CPU clock)
IF "DB_EncoderRetention".REPEAT_HSC1 <> "DB_EncoderRetention".LastPosition THEN
    "DB_EncoderRetention".SavedAt := RTM_TOD();
END_IF;

// Clear the restore flag after one complete cycle
"DB_EncoderRetention".RestoreFlag := FALSE;

5.5 Why %ID1000 "Overwrites Zero"

The original symptom reported by the user — that copying %ID1000 into a retain tag is "overwritten by zero" on the next start — is explained by the cycle ordering on the S7-1200:

  1. On STARTUP, the HSC loads its hardware initial value (commonly 0) into the counter register before OB100 runs.
  2. The process image of inputs is updated after OB100 and before OB1's first cycle.
  3. OB1 then reads %ID1000, which is now the fresh hardware counter value (0). The previous retain-tag value is still in the DB, but the HSC silicon has already been reset.

The fix is to either (a) use the HSC's "load initial value" mechanism (CTRL byte bit pattern) to push the retained DINT back into the hardware counter on STARTUP, or (b) treat the retain tag as the canonical position and do not rely on the HSC count surviving across a stop.

5.6 Alternative: Use a Snapshot on Every Edge (Higher Reliability)

For axes that move at very high speed between OB1 cycles, snapshot the HSC into the retain tag inside the HSC interrupt OB (configured in the HSC properties as "Event on CV = RV" or "Event on direction change"). This guarantees the saved value is fresh even if the encoder moves between the last OB1 scan and the power-off event.

// OB40 / HSC interrupt OB
"DB_EncoderRetention".LastPosition := "HSC1_Count";
"DB_EncoderRetention".SavedAt := RTM_TOD();

6. Verification

  1. Download the project to the CPU. Ensure the CPU is in STOP-RUN transition (online → "Start CPU").
  2. Open an online watch table on "DB_EncoderRetention".LastPosition and on %ID1000.
  3. Rotate the encoder so that both values change in step. Confirm they track exactly.
  4. Trigger a STOP via TIA Portal (online → "Stop"), wait 3 seconds, then RUN. The HSC count at %ID1000 will reset to the configured initial value, but the retain tag should still show the last observed position.
  5. Power-cycle the CPU (turn off the 24 V supply, wait at least 10 s, restore). On the next STARTUP:
    • %ID1000 should equal the last position (if you wired the load-initial logic correctly).
    • "DB_EncoderRetention".LastPosition must equal the pre-outage value.
  6. Force an MRES (master reset) from TIA Portal: online > MRES. Confirm that all retain data, including LastPosition, is zeroed. This is correct behavior and confirms the retention is bound to the program memory, not to firmware defaults.
  7. Reload the program block (right-click the block → "Download to device > Software (only changes)"). The retain data should persist because the block was not deleted, only updated.

7. Edge Cases and Field-Proven Caveats

7.1 S7-1500 and S7-1500T Motion Control Axes

On S7-1500 / S7-1500T with the TIA Portal motion control library, the encoder adjustment routine (used to assign a known mechanical position to an incremental encoder) is not retentive by design. According to the official TIA Portal V20 documentation for incremental encoder adjustment, the position of the incremental encoder is not saved retentively in the CPU and the values are lost after POWER-OFF. Always use a homing routine on the next start-up, or set the axis to "Active homing" instead of "Passive homing" if the mechanical reference is fixed.

7.2 Loss of Position if the Encoder Moves During Power-Down

Between the last OB1 scan (or last HSC interrupt OB) and the moment power is removed, the encoder may still move. The retained value reflects the position at the last scan, not at the exact instant of power-down. For high-speed axes (e.g. a rotary knife running at 1000 rpm with a 10 000-pulse encoder, or roughly 167 kHz), consider:

  • Braking the drive before allowing a controlled stop.
  • Adding an uninterruptible power supply (UPS) sized to hold the 24 V bus for at least 50 ms, which is enough to write a final snapshot.
  • Using a buffered encoder with battery backup that can output an absolute value on the next start (not applicable to pure incremental encoders).

7.3 Master Reset vs. Factory Reset vs. Format Memory Card

Action Retain data cleared? Program cleared? IP address cleared? Use when
STOP → RUN No No No Normal operation
Power cycle No No No Normal operation
MRES (online) Yes No No Commissioning, force a clean state
Reset to factory (online) Yes Yes Yes Re-deploy from scratch
Format SIMATIC memory card Yes Yes Yes CPU swap / device replacement

7.4 Optimized vs. Non-Optimized DB Access

Optimized DB access is the default in TIA Portal V14+ projects. Retain behavior is identical, but symbolic tag access becomes mandatory. If your program uses absolute addresses such as DB200.DBD0, either keep the DB non-optimized and set the entire block as retain in its properties, or switch to symbolic access (e.g. "DB_EncoderRetention".LastPosition) before the final compile.

7.5 PTO and HSC Conflict

If you also use Pulse Train Output (PTO) for stepper / servo control on the same CPU, the encoder inputs for the corresponding HSC channel may be reassigned. Verify the PTO mapping under CPU properties > Pulse generators (PTO/PWM) and select "Use PTO" or "Use HSC" per channel. Trying to use the same on-board input for HSC and PTO will yield a hardware configuration compile error in TIA Portal.

7.6 Watchdog and OB1 Cycle Time

If OB1 has a long cycle time (over 50 ms typical), the snapshot may lag the live counter by one cycle. For high-speed axes, either shorten the cycle time or use the HSC's hardware interrupt OB (configured in the HSC device properties) to update the retain tag on every reference-mark pulse (CV = RV event).

8. Reference to Official Documentation

  • Siemens Industry Online Support FAQ: "How do you implement retentive data on the SIMATIC S7-1200?"support.industry.siemens.com/cs/ww/en/view/41995947
  • TIA Portal V20 help: "Incremental encoder adjustment (S7-1500, S7-1500T) – Motion Control"docs.tia.siemens.cloud
  • S7-1200 Programmable Controller System Manual, chapter "High-speed counters" — available via the S7-1200 product page on Siemens Industry Online Support.

9. FAQ

Why does %ID1000 reset to zero after power-on even though my DB tag is marked retain?

The HSC silicon reloads its hardware initial value (commonly 0) on every STARTUP and writes that into %ID1000 before OB1 runs. The retain tag still holds your last snapshot, but you must use the HSC's "Load initial value" control bit in OB100 to push that snapshot back into the counter, or treat the DB tag as the canonical position and ignore %ID1000 for absolute position readout.

How much retain memory does an S7-1200 have?

All current S7-1200 CPUs (1211C / 1212C / 1214C / 1215C / 1217C) provide approximately 14 KB of non-volatile retain memory for bit memory (M), counters (C), timers (T), and data blocks combined. The allocation is configured in CPU properties > Retentive memory. The retain area is backed by internal SRAM and does not require the BB 1297 battery for retentivity, only for clock retention beyond the supercap hold-up time.

Does ticking the "Retain" box in the DB properties guarantee the value survives a power cycle?

Only if the CPU's retentive memory range includes that DB number (or, for optimized access, the tag is individually marked retain inside a DB that itself is in the retain region). Check CPU properties > Retentive memory and ensure the DB number falls within the allocated range. Mismatches are the most common cause of "the box is ticked but the value still zeroes out" field complaints.

What is the difference between a STOP-RUN transition, an MRES, and a factory reset for retention?

STOP-RUN and power cycles preserve the retain area unchanged. MRES (master reset from the programmer) zeros the retain area but keeps the program. A factory reset or a memory card format also clears the program and IP configuration. Use MRES during commissioning to force a known-good starting position.

Can I retain the HSC value on an S7-1500T motion control axis with passive homing?

No. Per the TIA Portal V20 documentation on incremental encoder adjustment, the position of an incremental encoder on S7-1500T is not saved retentively and the values are lost after POWER-OFF. Use active homing on each start-up, switch to an absolute encoder (SSI / PROFIdrive over PROFINET with P encoder class), or implement the retention pattern described in this article using a retentive DB and a startup-side load-initial-value routine before the axis is enabled.

Back to blog