Configuring S7-1200 CTRL_HSC for High-Speed Counter Interrupts

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

Overview

The S7-1200 family of CPUs (including the 1214 used in this application) integrates high-speed counters (HSC) that operate independently of the CPU scan. The HSC hardware captures encoder or pulse-train inputs at hardware speed, holds a current count in a dedicated double-word, and can fire a hardware interrupt the moment the count equals (or in practice, crosses) a programmed reference value. The CTRL_HSC instruction is the user-program interface that lets OB1 or any interrupt OB configure, arm, and rearm those hardware events.

The typical industrial problem is a strobe-light controller: an encoder or proximity sensor generates pulses proportional to line speed, the application must fire a digital output at a precise count (for example, every 1000 pulses), and the pulse must occur with minimal latency regardless of the OB1 cycle time. Because the scan cannot keep up with multi-kHz pulse trains, the solution requires a hardware interrupt OB triggered by the HSC compare event, with the trigger placed as close to the encoder input as physically possible.

This article walks through the full configuration sequence in TIA Portal: enabling the HSC in the device configuration, enabling the hardware interrupt, wiring CTRL_HSC, populating the auto-generated interrupt OB, and using the correct comparison convention. The procedures apply to S7-1200 CPUs 1211/1212/1214/1215/1217 with firmware V4.x and later, programmed in TIA Portal V14 SP1 or later (also validated against V16, V17, and V20 documentation).

Prerequisites

Before beginning the configuration, verify the following items.

  • CPU model and firmware: S7-1200 1214 DC/DC/DC (or DC/DC/RLY). HSC is supported on all S7-1200 CPUs. Firmware V4.0 or later is recommended for the legacy CTRL_HSC instruction used in this article. (S7-1200 V2.x with the original S7-1200 manual collection also supports CTRL_HSC.)
  • Programming environment: TIA Portal V14 SP1 minimum. V16, V17, or V18 are recommended for current SIMATIC S7-1200 system manual alignment.
  • Encoder or pulse source: 24 V push-pull or PNP output capable of exceeding the maximum expected pulse rate. For an S7-1200 HSC the maximum counting frequency depends on the CPU and input filter setting; with the input filter set to the fastest available value the HSC can count at up to 100 kHz single-phase or 80 kHz dual-phase on a CPU 1214.
  • Wiring: Encoder common to the 24 V reference, signal to the assigned HSC input (typically I0.0, I0.1, I0.2, or I0.3 on CPU 1214). For differential encoders, use a 24 V single-ended tap; for RS-422 outputs, the S7-1200 onboard inputs require a 24 V level translator or use of the signal board with differential support.
  • Power budget: The 24 V sensor supply and any load on Q0.0 must remain within the CPU's budget (typically 300 mA total for the 1214 onboard outputs).
Critical pre-check. The default digital input filter on the S7-1200 is 6.40 ms, which limits the maximum count rate to about 150 Hz. For any high-speed application the filter must be reduced to the fastest available setting. For an HSC, use 0.1 µs to 0.4 µs depending on the input. If the input cannot keep up with the encoder, the HSC will not count and the comparison event will never fire.

HSC and CTRL_HSC Technical Background

The high-speed counter is configured in the CPU's device configuration. Once enabled, it occupies specific digital inputs on the CPU or signal board. Each HSC can be assigned to one of several counting modes (single-phase, two-phase, AB quadrature, etc.) and a direction. The HSC maintains the current count in an input image area that is updated by hardware, independent of OB1 execution.

The CTRL_HSC (Control high-speed counter) instruction provides a software interface to that hardware. According to the Siemens SIMATIC S7-1200 Programmable Controller manual entry for CTRL_HSC and the TIA Portal cloud documentation for the legacy CTRL_HSC instruction, the CTRL_HSC block uses a structure stored in a data block to maintain counters and status, and is typically placed in a hardware interrupt OB that is executed when the counter hardware interrupt event is triggered.

CTRL_HSC parameters

Parameter Type Meaning Typical use in this application
HSC HW_IO (Word) Hardware identifier of the HSC (from device configuration) HSC_1
DIR Bool Enable new direction (1 = count down, 0 = count up) FALSE for up counting
CV Bool Enable new counter value (write NEW_CV into the counter on the next call) Pulsed TRUE to load NEW_CV after each strobe
RV Bool Enable new reference value (write NEW_RV into the compare register) TRUE (the value of 1000 is loaded once at startup)
PERIOD Bool Enable new period (for HSC in pulse generator mode only) FALSE
NEW_CV DInt New counter value to load when CV is true 0 (counter resets to zero on each strobe)
NEW_RV DInt New reference value to load when RV is true 1000
NEW_PERIOD Int New period (only for frequency measurement modes) 0
BUSY Bool Function busy status For monitoring only
STATUS Word Execution status / error code For monitoring only

Per the TIA Portal cloud CTRL_HSC reference, each call of CTRL_HSC uses a structure stored in a DB to maintain data. A single instance DB is auto-generated when the block is inserted; do not create more than one CTRL_HSC for the same HSC hardware identifier.

Hardware Configuration: Enabling the HSC and the Interrupt

The HSC and its associated hardware interrupt are configured in the device view, not in the program. The steps below are valid for TIA Portal V14 through V20.

Step 1 - Open Device Configuration

  1. In the project tree, double-click Device configuration on the S7-1200 CPU.
  2. Select the CPU and open the Properties tab in the lower inspector window.
  3. Under General, scroll down to High speed counters (HSC).
  4. Expand HSC1 (or the HSC you intend to use).

Step 2 - Configure the HSC basic properties

Property Recommended value for strobe application
Enable Checked
Counting mode Single-phase count (count up only)
Input assignment I0.0 (default for HSC1 on CPU 1214)
Initial counter value 0
Initial reference value 1000
Hardware interrupt on direction reversal Not required

Step 3 - Configure the digital input filter

Under Digital input filter for the assigned input (I0.0 in this example), change the filter time from the default 6.40 ms to the fastest possible value. On a CPU 1214 with HSC, the typical values are 0.1 µs, 0.2 µs, 0.4 µs, 0.8 µs, 1.6 µs, 3.2 µs, 6.4 µs, and 10.0 ms. Choose 0.1 µs for encoders above 50 kHz. Confirm by measurement: if the value in %ID1000 is incrementing in online mode but the compare interrupt never fires, the filter is almost always the cause.

Step 4 - Enable the hardware interrupt event

  1. Under the HSC properties, click Event configuration.
  2. In the main properties window, check Generate interrupt for "counter value equals reference value" event.
  3. Click Add new.
  4. In the dialog box, click OK. A new hardware interrupt OB is created and appears in the project tree (for example, Hardware_interrupt_1 [OB40]).
Multiple events for the same HSC. You may add additional events such as "counter value greater than reference value" or "direction reversal". For a strobe trigger the equal-to-reference event is sufficient, but if pulses are arriving faster than the interrupt latency the equal event may be missed. Adding the greater-than-reference event gives a second opportunity to fire.

Program Implementation

Once the hardware is configured and OB40 is generated, write the program in three pieces: a one-time CTRL_HSC call in OB1 to arm the reference value, the strobe output set/reset logic in the hardware interrupt OB, and a counter-reset mechanism after the strobe.

OB1 - One-time configuration of the HSC

The simplest approach is to place a single CTRL_HSC call in OB1 that is executed once on startup (using a one-shot from a flag bit or first-scan), or continuously. A continuous call is acceptable because CTRL_HSC only writes the new values when the corresponding enable bits are true.

// OB1 - Continuous CTRL_HSC call to keep HSC armed with NEW_RV = 1000
// The CV bit is pulsed TRUE for one cycle after each strobe to reset the counter to NEW_CV
//
// Inputs
//   "hwIntFired"   (Bool)   - set TRUE by OB40, reset by OB1 after handling
//
// Outputs
//   none directly; the block writes to HSC hardware

IF "hwIntFired" THEN
    // OB40 fired - reset the counter to zero so the next 1000 pulses start fresh
    "inst_CTRL_HSC"(HSC       := 1,           // HSC_1 identifier
                    DIR       := FALSE,        // count up
                    CV        := TRUE,         // enable loading of NEW_CV
                    RV        := FALSE,        // RV is already latched, do not reload
                    PERIOD    := FALSE,
                    NEW_CV    := 0,            // reset to 0
                    NEW_RV    := 1000,
                    NEW_PERIOD := 0);
    "hwIntFired" := FALSE;                   // acknowledge
ELSE
    // Normal run - keep the reference value of 1000 armed
    "inst_CTRL_HSC"(HSC       := 1,
                    DIR       := FALSE,
                    CV        := FALSE,
                    RV        := FALSE,        // already 1000, no need to reload
                    PERIOD    := FALSE,
                    NEW_CV    := 0,
                    NEW_RV    := 1000,
                    NEW_PERIOD := 0);
END_IF;

OB40 - Hardware interrupt triggered on count = reference value

Open the auto-generated hardware interrupt OB (commonly OB40). Place the output set and the flag that arms the counter reset.

// OB40 - HSC hardware interrupt
// Triggered when the HSC count equals (or in practice, crosses) the reference value
//
// Strobe pulse pattern
//   - Set Q0.0 immediately on entry
//   - Generate a pulse of defined width using a timer in OB1 (preferred)
//   - Set the "hwIntFired" flag so OB1 reloads NEW_CV = 0 on the next cycle

SET;
    S   "Strobe_Output"  // Q0.0 - set the strobe output
    =   L0.0;
S "hwIntFired";        // tell OB1 to reload NEW_CV = 0

The actual strobe pulse width is normally generated by a timer in OB1 that resets Q0.0 after a few microseconds or milliseconds, depending on the strobe light's required flash duration. The interrupt OB is the right place to trigger the strobe, but it should not be the place to time a long flash, since blocking OB40 with a long timer delays subsequent compare events.

Optional - Generating a fixed-width strobe pulse in OB1

// Edge-detect entry to "Strobe_Output" and start a TON timer that clears the output
//
"strobePulseStart" := "Strobe_Output" AND NOT "strobePulseStart_d";
"strobePulseStart_d" := "Strobe_Output";

IF "strobePulseStart" THEN
    "iecTimer_Strobe".IN  := TRUE;
    "iecTimer_Strobe".PT  := T#200us;       // adjust to the strobe manufacturer's spec
END_IF;
IF "iecTimer_Strobe".Q THEN
    RESET; S ; R "Strobe_Output";
    "iecTimer_Strobe".IN := FALSE;
END_IF;

The Equal vs Greater-Than Comparison

The original question used the strict equality comparison: when %ID1000 = 1000 trigger the output. In practice this is unsafe for high-speed counting. Consider the sequence:

  1. The HSC has just reached 1000 and triggered the hardware interrupt.
  2. The CPU services the interrupt and enters OB40.
  3. While OB40 is executing, additional encoder pulses arrive (perhaps 5, perhaps 50).
  4. By the time any software comparison inside the program runs, the count is now 1055 or some value above 1000.
  5. A software = 1000 test would never be true.

This is why the HSC compare event should be configured in hardware (equal-to-reference), but any software check inside the application should use >= rather than =. The hardware compare is the actual strobe trigger; the software compare is a diagnostic or a rearm check.

Practical consequence. If the strobe appears to fire late or skip on a high-speed line, the cause is rarely the HSC or CTRL_HSC. It is almost always the filter setting on the digital input, or a compare condition that is too strict.

Resetting the Counter Inside the Interrupt

The user wanted the counter to reset after each 1000-pulse trigger. There are two ways to do this:

  1. Software reset via CTRL_HSC in OB1: Set the flag in OB40; in OB1, pulse CV := TRUE and load NEW_CV := 0. This is the approach shown above and is the simplest, since it does not call CTRL_HSC from inside OB40.
  2. Hardware reset via the assigned digital input: The HSC supports a separate external reset input. If a free I0.3 or similar is wired to a marker pulse, the HSC will reset on that edge. This avoids the OB1 round-trip but adds a wire.

Choose option 1 unless the application is so fast that the OB1 round-trip is unacceptable. For an S7-1200 OB1 at 1 ms, the worst-case reset delay is one scan, which for a 100 kHz pulse train is 100 pulses of additional count before the next comparison. If that is significant, switch to the hardware reset input.

Verification and Commissioning

  1. Compile and download the project to the CPU. Make sure no other CTRL_HSC exists for the same HSC identifier, and confirm that Q0.0 is not being set or reset anywhere else in the program.
  2. Go online and open the HSC instance DB or watch %ID1000. The current count must increment when the encoder or pulse source is rotating.
  3. Watch the HSC status in the device configuration: the online view of the HSC should show a current count and a reference value of 1000.
  4. Force a software compare by temporarily setting NEW_RV to a small value (for example, 10) so the interrupt fires within seconds. Confirm Q0.0 toggles.
  5. Restore the production value of 1000 and verify with the real encoder speed.
  6. Record the OB40 execution time by inspecting the cycle time of OB1. The interrupt latency from the HSC event to OB40 entry is on the order of microseconds on an S7-1200.

Troubleshooting Matrix

Symptom Most likely cause Corrective action
%ID1000 never increments Input filter too slow; encoder wiring inverted; HSC not enabled Set input filter to 0.1 µs; check wiring; verify HSC enabled in device configuration
%ID1000 increments but OB40 never fires Compare event not enabled; interrupt OB not assigned Check "Generate interrupt for counter value equals reference value"; confirm OB40 is the assigned OB for the event
OB40 fires too early or too late Count is too high; filter causes pulse loss Reduce filter to fastest setting; verify encoder supply voltage at the CPU terminal
OB40 fires but Q0.0 does not set Q0.0 being reset elsewhere in the program Search the project for additional writes to %Q0.0; remove or condition them
CTRL_HSC returns STATUS <> 0 Multiple CTRL_HSC blocks for the same HSC; bad HSC HW identifier Keep only one CTRL_HSC; verify the HSC identifier in device configuration
Strobe fires, counter does not reset to 0 CV bit never set, or NEW_CV wrong Verify the flag flow from OB40 to OB1; ensure NEW_CV is 0 and CV is TRUE for at least one scan
First few strobes correct, then drifting Counter overflows integer range; OB1 cycle slower than expected Use a 32-bit DInt (default); check for OB1 overload from other tasks
Works in OB1 cyclic interrupt, fails in OB40 Cyclic OB has higher latency than the pulse train Use the hardware interrupt OB as the trigger, not a cyclic OB. CTRL_HSC cannot compensate for missed pulses

Edge Cases and Field-Proven Caveats

Cycle time of OB1. A 1 ms OB1 is fine for reset and rearm, but if the application adds image-table accesses, communications, or motion blocks, the OB1 cycle can stretch past 5 ms. At a 10 kHz pulse rate, 5 ms equals 50 pulses, so the first strobe will appear at 1000 pulses but the next one (after a 1 ms scan delay) will appear at 1050 pulses. For consistent timing, keep OB1 lean and consider using a hardware reset input.

Encoder common and grounding. 24 V encoders with PNP output need their 24 V supply common tied to the CPU's 1M terminal. Floating the encoder common is a frequent source of noise-induced false counts.

Single call discipline. Only one CTRL_HSC block per HSC identifier is allowed in the project. If the program block is copied into a different OB, this becomes a silent failure - the second call returns a STATUS error and the HSC may stop responding.

Firmware changes. The S7-1200 HSC API changed between firmware V2.x and V4.x. The legacy CTRL_HSC block continues to work on V4.x and later, but the new "Counting and measuring" technology objects (introduced in V4.x) offer more flexibility. For new projects above V14, consider the CTRL_HSC_EXT or the technology object TO_Counting. The procedure documented in this article (legacy CTRL_HSC with hardware interrupt) is the correct match for TIA V14 and for users porting V11/V12 programs.

Diagnostic block. Use the RD_SINFO instruction or the HSC instance DB to confirm which event triggered OB40. This is helpful when more than one HSC event is enabled and a single OB serves multiple sources.

Performance Limits

Parameter CPU 1214 value Notes
Maximum single-phase count rate 100 kHz With input filter at 0.1 µs
Maximum AB quadrature rate (4x) 80 kHz 20 kHz mechanical
Number of HSC per CPU 1214 6 HSC1 to HSC6, on-board and signal board
Hardware interrupt latency typ. 10-30 µs Independent of OB1
Count range -2 147 483 648 to 2 147 483 647 32-bit DInt

FAQ

Why is OB40 the right place to set the strobe output instead of OB1?

OB40 is the hardware interrupt OB generated automatically when the HSC compare event is configured. It runs with microsecond latency the moment the count equals the reference value, independent of the OB1 scan. OB1 can be 1 ms or longer, which is too slow for a high-speed strobe and will cause the strobe to drift on a fast line.

Should I use '=' or '>=' when comparing the count value in software?

Use '>='. By the time any software comparison executes, several additional encoder pulses may have arrived and the count will already be above the trigger value. The HSC compare event in hardware is the real trigger; software comparison is only for diagnostic or rearm logic.

How do I reset the HSC counter to zero after each strobe?

Set a flag in OB40, and in OB1 pulse the CV input of CTRL_HSC to TRUE while passing NEW_CV := 0. The HSC then loads 0 on the next CTRL_HSC call. For zero-delay reset, wire a free digital input to the HSC's external reset input and pulse it from OB40.

The count in %ID1000 does not change. What is wrong?

Check the input filter time on the assigned input (I0.0 by default) and reduce it to 0.1 µs. The S7-1200 default of 6.40 ms limits the HSC to roughly 150 Hz. Also confirm the HSC is enabled in the device configuration and that the encoder common is tied to the 24 V reference of the CPU.

Can I have more than one CTRL_HSC for the same HSC?

No. The Siemens documentation states that each HSC supports exactly one CTRL_HSC block, using a single instance DB. Multiple CTRL_HSC calls for the same hardware identifier will return a STATUS error and the HSC may stop responding to configuration changes.

Does CTRL_HSC work on TIA Portal V14 with the original S7-1200 firmware V4.x?

Yes. The legacy CTRL_HSC instruction is supported in TIA Portal V14 through V20 on all S7-1200 CPUs with firmware V4.0 or later. For new development above TIA V14, the newer technology object "TO_Counting" or the CTRL_HSC_EXT instruction provides additional features, but the procedure in this article remains valid.

Back to blog