Problem Definition: Pulse Loss at Increased Shaft Speed
When an incremental rotary encoder is wired to the integrated counter inputs of a Siemens CPU 314C-2 PN/DP (e.g., 6ES7314-6EH04-0AB0) and the quadrature decoding is performed inside a cyclic OB (typically OB1) using Boolean comparisons of I0.0 and I0.1, the application will appear to work at very low shaft speeds and then drop counts as the speed increases. The first indication of the fault is a stable position value when the encoder is rotated manually, but a frozen or jumping value as soon as the shaft is turned faster than a few revolutions per minute.
The user in the field reported a Pepperl+Fuchs RVI58V-032K1A61N-02000 (2000 ppr) wired to channel 0 of the integrated counter, with the following SCL block in OB1:
IF (#b = 1) AND (#bOld = 0) AND (#aOld = 1) AND (#a = 1) THEN
#pulsAmount := #pulsAmount + 1;
END_IF;
IF (#a = 1) AND (#aOld = 0) AND (#b = 1) AND (#bOld = 1) THEN
#pulsAmount := #pulsAmount - 1;
END_IF;
#position := REAL_TO_INT(
#pulsAmount * ("Global DB Parameters".encoderDiameter * #pi
/ "Global DB Parameters".encoderPulseAmount));
#aOld := #a;
#bOld := #b;
Hardware configuration in the device configuration was set to:
- Operating mode: Count continuously
- Signal evaluation: Rotary encoder, double (2× quadrature)
- Count signals / HW gate: 60 kHz
- Latch: 10 kHz
Despite the hardware being set to 60 kHz, the actual count is lost at speed. The SCL block is the cause, not the wiring or the encoder.
Root Cause: Cyclic OB Polling vs. Hardware Counter
The CPU 314C-2 PN/DP integrates four 24 V counter channels on inputs I0.0..I0.7 (channels 0..3). These are not just fast digital inputs; they are hardware counters with their own internal up/down register, gate control, and latch. The 60 kHz rating applies to the counter front-end, not to the OB1 cycle.
When the application polls I0.0 and I0.1 once per OB1 cycle and reconstructs the quadrature transitions in software, the maximum rate it can detect is bounded by half the OB1 cycle time. For a typical CPU 314C-2 program with several FBs, OB1 runs at 5 to 50 ms. At 20 ms, the highest pulse rate the Boolean logic can see is roughly 25 Hz - i.e. less than 0.2 revolutions per second for a 2000 ppr encoder with 2× decoding (4000 increments/rev). This matches exactly the symptom: it works "only on extreme slow rotation speed".
Hardware counters, in contrast, latch the count in a register that the CPU reads with a single load instruction. Pulse rates up to 60 kHz are captured reliably regardless of OB1 timing.
Affected Hardware and Firmware
| Component | Order Number / Variant | Notes |
|---|---|---|
| CPU 314C-2 PN/DP | 6ES7314-6EH04-0AB0 (Firmware V3.3) | 4 integrated counters, 60 kHz each, 24 V |
| CPU 314C-2 PN/DP (older) | 6ES7314-6CH04-0AB0 | Identical counter architecture |
| CPU 314C-2 DP | 6ES7314-6CF02-0AB0 | 3 counters, same SFB47 interface |
| Encoder | RVI58V-032K1A61N-02000 | 2000 ppr, HTL/push-pull 10–30 V, cable output |
| STEP 7 | V5.5 + SP2 or later | For SFB47 in classic project |
| TIA Portal | V13 SP1 / V14 / V15 / V16 / V17 | Use "S7-300C" library for SFB47 |
The counter architecture is described in the S7-300 CPU 31xC technological functions manual.
Why the User's Configuration Looks Correct but Still Fails
Configuring the channel in HW Config as "rotary encoder double" tells the counter front-end to evaluate both edges of both phases (2× decoding). This setting is consumed by the counter hardware, not by OB1. Once the channel is enabled, the count register at input address PID 300 (default) is updated by the silicon every microsecond. The user program must:
- Start the counter via the gate control (set
CTRL_DO = 1in the control interface). - Read the count register (load from
PID 300for channel 0,PID 304for channel 1, etc.). - Convert the raw count to engineering units using the diameter and PPR.
The user's SCL block does none of the above. It is essentially a slow software quadrature decoder running against a fast hardware quadrature decoder and discarding the hardware's actual count.
Solution Path A: SFB47 in STEP 7 V5.5
For STEP 7 V5.x, the integrated counter is operated through the system function block SFB 47 "COUNT" (background DB instance 0..7 per channel). SFB47 is documented in the S7-300/400 Standard and System Functions reference manual.
Hardware Configuration in HW Config
- Open HW Config and insert the CPU 314C-2 PN/DP.
- Double-click Count in the slot overview to open the counter properties.
- For each active channel:
- Operating mode: Count continuously
- Signal evaluation: Rotary encoder, double (2×) or Quadruple (4×) depending on resolution needed
- Count signals / HW gate: 60 kHz
- Latch: 10 kHz (used if you wire a reference pulse)
- Input: 24 V incremental, A = I0.0 (Ch0), B = I0.1 (Ch0), N = I0.2 (Ch0, optional)
- Note the assigned input addresses (default:
300..307for channel 0,304..311for channel 1, etc.).
SFB47 Call in OB1
Declare a multi-instance or background DB, e.g. DB200 ("Cnt0_DB"). Call SFB47 in OB1 with:
CALL "COUNT" , DB200 // SFB47, instance DB200
LADDR := W#16#300 // Channel 0 logical base address
CHANNEL := 0
SW_GATE := // Optional software gate (BOOL)
CTRL_DO := // Optional control output (BOOL)
SET_DO := // Optional direct set (BOOL)
JOB_REQ := // Job request (BOOL, edge)
JOB_ID := // Job identifier (INT) 0=read, 1=write, etc.
JOB_VAL := // Job value (DINT)
STS_GATE:= // Status: hardware gate
STS_CMP := // Status: comparator output
STS_OFL := // Status: overflow
STS_UFL := // Status: underflow
STS_ZP := // Status: zero mark reached
JOB_DONE:= // Job complete (BOOL)
JOB_ERR := // Job error (BOOL)
JOB_STAT:= // Job status word (WORD)
COUNTVAL:= // Current count value (DINT) - the real result
LATCHVAL:= // Latch value (DINT)
END_CALL;
The relevant outputs are COUNTVAL (the live count) and LATCHVAL (the value at the last zero-pulse). For a 2000 ppr encoder in 2× mode, one mechanical revolution is 4000 increments. The user's conversion then becomes:
// "Cnt0_DB".COUNTVAL contains raw count, range -2147483648..2147483647
// Linear distance per increment = (pi * diameter) / (PPR * evaluation)
#position_mm := INT_TO_REAL("Cnt0_DB".COUNTVAL)
* (3.14159265 * 45.0)
/ (2000.0 * 2.0);
300 is the default; if a different slot is configured, change LADDR to match. The status bits STS_OFL and STS_UFL indicate the counter wrapped; reset with JOB_REQ = edge and JOB_ID = 4 (set counter).Reading the Count in OB1 (Simplified)
If the user only needs the current value, the call can be reduced to reading COUNTVAL directly; the gate remains permanently enabled by wiring the hardware gate input high. For higher determinism, the SFB47 can be called in OB35 (cyclic interrupt) instead of OB1.
Solution Path B: TIA Portal and the "S7-300C" Library
The SFB47 block does not appear under "Standard library > System function blocks" in TIA Portal. It is shipped in the S7-300C library that comes with STEP 7 V13 and later. To use it:
- Open the TIA Portal project and switch to the library task card (right side panel).
- Click Libraries > Global libraries → open the supplied S7-300C library (path:
Support > S7-300Con the TIA installation media). - Drag the block COUNT (SFB47) into your project tree.
- Add an instance DB or use multi-instance. The library version of the FB exposes the same interface as SFB47.
- Configure the channel in the device view of the CPU (Properties > Count > Channel 0), exactly as in HW Config.
- Call the block in OB1 or OB35 with the correct
LADDR(the I/O address from the device configuration).
Reference: S7-300C library description in TIA Portal.
Removing the Software Quadrature Decoder
After SFB47 is in place, the original SCL block is no longer needed. The Boolean variables aOld, bOld and the cyclic edge detection on I0.0/I0.1 should be deleted. Reading the count through SFB47 yields a 32-bit signed count that is updated every microsecond by the counter hardware. The OB1 cycle no longer limits pulse capture.
Example final code (SCL):
// One-time initialization, e.g. in OB100 (warm restart)
IF "FirstRun" THEN
"FirstRun" := FALSE;
"Cnt0".SW_GATE := TRUE; // open software gate
END_IF;
// Cyclic in OB1
IF "Cnt0".STS_OFL OR "Cnt0".STS_UFL THEN
"Cnt0_DB".JOB_REQ := TRUE;
"Cnt0_DB".JOB_ID := 4; // set counter
"Cnt0_DB".JOB_VAL := 0;
END_IF;
// Engineering units conversion
#position_mm := INT_TO_REAL("Cnt0".COUNTVAL)
* 3.14159265 * 45.0 / 4000.0;
Wiring Considerations for the RVI58V-032K1A61N-02000
The RVI58V is a 58 mm housing incremental encoder from Pepperl+Fuchs with HTL/push-pull output, 10–30 V supply, and 2000 pulses per revolution. With cable output (-K1) the cable is shielded and should be routed separately from VFD and power cables.
| Wire (cable colour per P+F convention) | Signal | CPU 314C-2 terminal |
|---|---|---|
| Brown | +V (10–30 V) | 24 V supply |
| Blue | 0 V (GND) | 24 V ground |
| Black | Channel A | I0.0 (Ch0 A) |
| White | Channel B | I0.1 (Ch0 B) |
| Pink | Channel N (zero, optional) | I0.2 (Ch0 N) |
| Shield | — | Grounded at cabinet entry only |
The user reported using only A, B, +, GND. This is acceptable for HTL single-ended wiring if the cable is short (typically < 10 m) and electrically quiet. For longer distances, EMI coupling between the phases causes the comparator to switch on noise spikes and produce extra counts. If the encoder also provides /A and /B (the inverse signals), wire them to the CPU's differential input pins if available; the CPU 314C-2 has hardware comparators that benefit from differential drive.
Maximum Speed Calculation
For the user's hardware configuration, the maximum allowable shaft speed is determined by the 60 kHz count frequency and the chosen evaluation mode:
| Signal evaluation | Counts / rev | Max RPM (60 kHz limit) |
|---|---|---|
| Single (1×) | 2 000 | 1 800 |
| Double (2×) | 4 000 | 900 |
| Quadruple (4×) | 8 000 | 450 |
Recommended setting for the 2000 ppr RVI58V: keep double evaluation. This gives 4000 increments/rev, well above the user's mechanical positioning requirement, and a 900 RPM ceiling. The user's original SCL block could never have served this; the SFB47 path makes the 900 RPM limit the actual constraint.
Verification Procedure
- Download the new program to the CPU. Connect online in TIA Portal or STEP 7.
- Open the instance DB of the SFB47 in monitor mode. Confirm
STS_GATE = 1(gate open) andSTS_CMPis following the encoder. - Rotate the encoder shaft slowly by hand.
COUNTVALshould increment/decrement smoothly andSTS_OFL/STS_UFLshould remain FALSE. - Spin the shaft at the intended operating speed using a drill or motor.
COUNTVALshould track the rotation without freezing. - Trigger a known number of revolutions (e.g. 10) and compare
COUNTVALwith10 × 4000 = 40000. Allow ±1 increment for hysteresis. - Force a stop, then resume. Verify that the count does not jump on the start edge (debounce the first sample if necessary by reading twice).
Troubleshooting Matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| Count stable at low speed, frozen at high speed | Software decoding in OB1 (this case) | Replace with SFB47; use hardware counter |
| Count drifts by ±1 increment at stand-still | Noise on HTL single-ended inputs | Use shielded cable, separate from power; switch to RS422 if available |
| Count always 0, no increments | Software gate closed or wrong channel address | Check SW_GATE = TRUE; verify LADDR matches HW config |
| STS_OFL asserted after short run | Count exceeded +2 147 483 647 | Reset on overflow with JOB_ID = 4 |
| Count goes one direction only | A and B wires swapped | Swap black/white at terminal or invert JOB_VAL sign |
| JOB_ERR = 1 after writing | Job ID invalid or wrong channel | Refer to SFB47 status word JOB_STAT; valid IDs: 0 (read), 1..5 (write jobs) |
| Counts random / high value spikes | Reference pulse N connected to wrong input or floating | Leave N unconnected if not used; or wire to I0.2 with shielding |
| SFB47 not found in TIA | Wrong library | Install/open S7-300C global library and copy COUNT block |
Field-Commissioning Notes
When commissioning on a real machine, perform the verification procedure with the motor drive disconnected first - drive a bench motor at 50 %, 75 % and 100 % of rated RPM. Watch COUNTVAL on a trend in TIA. The trend should be a clean ramp; any step discontinuity indicates a missed or extra pulse, which can be tracked to:
- Mechanical slip (loose coupling).
- Encoder bearing failure (signal amplitude drop, edge timing jitter).
- EMI from a VFD - add a ferrite on the encoder cable at the cabinet entry and ensure the shield is bonded to the cabinet ground bar with 360° contact.
For high-precision applications where the 60 kHz limit is too low, migrate the counter to an FM 350-1 or FM 350-2 counter module. The FM 350-1 supports up to 500 kHz per channel; the FM 350-2 supports 8 channels at 20 kHz each. Both are accessed through dedicated FBs that follow the same read-pattern as SFB47.
Frequently Asked Questions
Why does the encoder read correctly at low speed but lose pulses at high speed on a CPU 314C-2?
The integrated counter is a 60 kHz hardware counter, but if the user program polls the raw digital inputs and reconstructs the quadrature in OB1, the OB1 cycle (typically 10–50 ms) limits the resolvable pulse rate to a few tens of hertz. Use SFB47 to read the hardware count register instead, which is updated every microsecond regardless of OB1.
Where is SFB47 in TIA Portal?
SFB47 "COUNT" is shipped in the S7-300C global library that comes with STEP 7 V13 SP1 and later. Open the library task card, copy the COUNT block into your project, and add an instance DB. The interface (LADDR, CHANNEL, COUNTVAL, JOB_ID, JOB_VAL) is identical to STEP 7 V5.x.
What is the maximum RPM my 2000 ppr encoder can reach on the CPU 314C-2?
With "rotary encoder double" evaluation the count is 4000 increments/rev. The 60 kHz counter limit gives a maximum of 60000 / 4000 = 15 rev/s = 900 RPM. Switch to single evaluation for 1800 RPM, or to an FM 350-1 module for up to 7500 RPM with this PPR.
Do I have to wire /A and /B on the RVI58V encoder?
For HTL single-ended wiring at cable lengths under 10 m, A/B/+24 V/GND is sufficient. For longer runs or noisy environments, switching the encoder to RS422 (TTL) and using /A and /B is recommended; the CPU 314C-2 supports differential inputs through the same terminal pairs.
What is the meaning of SFB47 status bits STS_OFL and STS_UFL?
STS_OFL = TRUE indicates the counter has passed the upper limit (+2 147 483 647) and wrapped; STS_UFL signals the lower limit (-2 147 483 648). Both are latched until reset. Send a write job with JOB_ID = 4 and JOB_VAL = 0 to reset the counter, or wrap-around to a smaller range by using JOB_ID = 1 (set upper limit) and JOB_ID = 2 (set lower limit).
Can I call SFB47 in OB35 instead of OB1?
Yes. OB35 is a cyclic interrupt OB that runs at a configurable interval (default 100 ms). Calling SFB47 in OB35 gives a deterministic read cadence independent of OB1 cycle time. For high-speed applications where you need a fresh count every 1 ms, set OB35 to 1 ms - subject to the CPU's minimum OB35 interval (1 ms for CPU 314C-2).