FM350-1: Solving Encoder Reset and CMP_V1/V2 Read-Back Issues

David Krause17 min read
PLC HardwareSiemensTroubleshooting
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

Siemens FM350-1 Counter Module: Encoder Reset and CMP Read-Back Troubleshooting

The Siemens FM350-1 (order number 6ES7350-1AH03-0AE0) is a single-channel, 32-bit counter module for SIMATIC S7-300 and ET 200M. It accepts 24 V or RS422 incremental encoder signals up to 500 kHz and provides two on-board digital outputs that can be triggered when the count crosses a programmed comparison value. Two recurring field issues complicate otherwise straightforward applications:

  1. ACT_CMP1 / ACT_CMP2 read-back stays at 0 after writing CMP_V1 / CMP_V2 to the output process image.
  2. Direct SW-gate reset of ACT_CNTV drops encoder pulses between the reset command and the next OB1 cycle.

Both problems are not firmware bugs. They are a consequence of the module's hardware-comparator and gate-control timing, and they are documented in the FM 350-1 operating instructions (manual A5E03648639-01, 05/2011). This reference presents the underlying root cause analysis and a software-comparator pattern that eliminates both issues without losing a single encoder pulse.

FM350-1 Module Identification and Ordering Data

The FM350-1 is delivered in three hardware revisions. All are mechanically and electrically compatible at the backplane bus, but the firmware revision affects which function blocks are accepted by the FM350-1 configuration package.

MLFB / Order Number Hardware Revision Firmware Status
6ES7350-1AH01-0AE0 1 ≤ V1.0 Discontinued, replacement: -1AH03
6ES7350-1AH02-0AE0 2 V2.0 Discontinued, replacement: -1AH03
6ES7350-1AH03-0AE0 3 V3.0 Current production

The module is installed into a free slot in an S7-300 rack (centralised) or in an ET 200M station behind an IM153. The configuration package "Configuration software for FM 350-1 and FM 450-1 counter modules" (Siemens KB article 28291262) must be installed on the same STEP 7 V5.x PC that hosts the hardware configuration. Without this package the FM350-1 is not selectable in HW Config and the parameterisation dialog is missing.

Compatibility note: FM350-1 is not a TIA Portal native module. It can be migrated to a SIMATIC S7-1500 via a migration guide and the ET 200SP TM Count 1x24V successor module, but native configuration in STEP 7 V5.x (or STEP 7 Professional V16+ with HSP) is the supported path. The discussion below applies to STEP 7 V5.x STL; the same logic maps to SCL and to LAD/FBD with equivalent comparators.

Technical Specifications and Operating Modes

The electrical and functional envelope of the module is the boundary condition that constrains every workaround. Values below are extracted from the FM 350-1 operating instructions (A5E03648639-01).

Parameter Value Notes
Count inputs A, B, N (24 V or RS422) Single-ended 24 V (default) or 5 V differential (RS422)
Maximum count frequency 500 kHz (24 V) / 1 MHz (RS422) Quadrature x4 evaluation selectable
Count width 32 bit (DINT) Range −2 147 483 648 … +2 147 483 647
Number of channels 1 One encoder / one counter per module
Digital outputs 2 (DQ0, DQ1) 24 V / 0.5 A, short-circuit proof, isolated
Comparator values CMP_V1, CMP_V2 32-bit, written to PQ area
Operating modes Continuous / Single / Periodic count Mode set in HW Config parameter dialog
Gate control SW gate, HW gate, cancel/reset Control word bits 0, 1, 2, 3
Diagnostic Wire break, sensor supply, RAM/ROM Signalled in STS bit fields and SF LED

The two digital outputs are not general-purpose; they are physically bonded to the on-board hardware comparators CMP1 and CMP2. When the on-the-fly count value equals the corresponding comparison value, the assigned output is pulsed for one OB1 cycle (or latched, depending on parameterisation). This output/comparator linkage is the source of both field issues and is the reason the entire comparator subsystem can be replaced by a software implementation.

Process Image Layout: Byte Addresses 272 to 287

The FM350-1 occupies a fixed 16-byte slot in the process image regardless of slot position. The slot is configured in HW Config. The address shown below (272..287) is a real example; in a different project the base address may differ. The offsets within the slot are always the same.

Address (PI / PQ) Mnemonic Length Direction
272..273 STS / CTRL WORD Status (PI) / Control (PQ)
274..275 reserved WORD
276..279 ACT_CNTV DINT PI only (read)
280..283 ACT_CMP1 DINT PI only (read)
284..287 ACT_CMP2 DINT PI only (read)

The output (PQ) side mirrors the same byte layout:

Address (PQ) Mnemonic Length Function
272..273 CTRL WORD Control word (gate, reset, encoder mode)
274..275 reserved WORD
276..279 CMP_V1 DINT Comparison value 1 (DQ0)
280..283 CMP_V2 DINT Comparison value 2 (DQ1)
284..287 reserved WORD

In the source example the user references PID 276. The PID mnemonic denotes a 32-bit double word in the process image starting at byte 276, which is exactly ACT_CNTV (or CMP_V1 when read/written from PQ). Double-word reads/writes on the FM350-1 must be aligned on even byte addresses, and 276 is even, so L PID 276 is valid STL.

Alignment rule: Siemens S7 only allows direct double-word (D) / long-word (DI) access on even byte addresses. If the FM350-1 base address in your project is odd (for example after a slot swap), the PID access will fault (OB121). Re-align the slot or split the read into two PW accesses and reassemble.

Application Problem: Triggering Outputs at Encoder Positions

The original application is a textbook example of position-based event firing:

  1. Encoder increments a 32-bit counter value ACT_CNTV continuously.
  2. When ACT_CNTV reaches 2000, DQ0 must fire (e.g. a marking actuator).
  3. When ACT_CNTV reaches 5000, DQ1 must fire and the counter must reset to 0 so the cycle restarts.

On paper the FM350-1 hardware is the right tool: CMP_V1 = 2000, CMP_V2 = 5000, parameterise the outputs to pulse on equality, and add a software reset of the counter when DQ1 fires. In practice two symptoms emerge:

  • Symptom 1: After writing L 2000; T PQD 276 (CMP_V1) and L 5000; T PQD 280 (CMP_V2), the read-back values L PID 280 (ACT_CMP1) and L PID 284 (ACT_CMP2) consistently return 0.
  • Symptom 2: Resetting the counter by writing the CTRL word (toggling the cancel/reset bit) causes ACT_CNTV to drop to 0, but during the next cycle the comparator never fires again. A manual encoder hand-wheel reveals that several pulses are simply not counted between the reset command and the next comparator match.

Both symptoms trace back to the same root: the hardware comparator is a poor abstraction for time-critical, deterministic I/O. The fix is to take the comparator out of the module and implement it in the CPU where the cycle time and the read-back semantics are well defined.

Root Cause: Why ACT_CMP1 / ACT_CMP2 Return Zero

Section 7 of the FM350-1 operating instructions (A5E03648639-01) describes the ACT_CMP1 / ACT_CMP2 update behaviour precisely. The values are not mirrors of CMP_V1 / CMP_V2 written by the user. They are the comparison values that the on-board FPGA has currently latched into the comparator pipeline. The latching is gated by the following conditions, all of which must be true for ACT_CMPx to update from zero:

  1. The SW gate must be open (CTRL bit 0 = 1).
  2. The HW gate must be open (terminal X1, pin 8, see wiring manual).
  3. The module must be in an operating mode where the comparator is enabled (Continuous / Periodic, not Single mode with comparator disabled).
  4. The user must have set the "load comparison value" bit (CTRL bit 8) and the module must have acknowledged the transfer (STS bit 8 returns 1) before a new value is written. If the load bit is not pulsed for one OB1 cycle, the transfer never completes.
  5. The DI/DO diagnostic interrupt enable must be set in HW Config; otherwise the module stops servicing comparator updates after a diagnostic event.

Miss any one of these and ACT_CMP1 / ACT_CMP2 stay at 0 — the read-back is not a debugging aid, it is a status flag. The easiest cure is to never read it.

Field tip: A common cause of stuck ACT_CMPx in real projects is the parameterisation "Output = no function" in HW Config. The user set CMP_V1 / CMP_V2 anyway "to be safe", but with the output disabled the comparator engine is parked and the read-back is forced to 0. Re-enable DQ0 / DQ1 in the FM350-1 properties dialog and the ACT_CMPx value appears on the next transfer.

Root Cause: Pulse Loss on Direct Counter Reset

The CTRL word layout is:

Bit Symbol Function
0 SW_GATE 1 = open SW gate, 0 = close
1 HW_GATE Status only (read via STS)
2 CANCEL 1 = cancel, 0 = no cancel
3 RESET Set counter and latch registers to 0
4..7 Reserved
8 LD_CMP Transfer CMP_V1 / CMP_V2 to the latch

To reset the counter the user must set CTRL bit 3 (RESET) for at least one OB1 cycle, then clear it. Internally the FM350-1 latches the reset request, then on the next count-clock edge it clears the up/down counter register. The input pulse counter inside the FPGA, however, is also held in reset while CTRL.3 is high. Encoder edges that arrive during that window are lost. At 500 kHz and a 10 ms OB1 cycle the worst-case loss is 5 000 counts — a real and observable quantity on a 1024-ppr encoder in x4 mode.

Resolving this requires either:

  • A reset pulse shorter than 1 / max_count_frequency (here 2 µs), which OB1 cannot guarantee; or
  • A logical reset of the count that does not touch the FPGA register at all.

The second approach is the only deterministic one, and is implemented by treating ACT_CNTV as a raw, monotonically increasing read-only register and subtracting a software offset on every scan.

Solution: Software-Based Comparator with Zero Offset

Declare two DINTs in the CPU's working DB:

  • ZeroOffset — the snapshot of ACT_CNTV at the moment the cycle is "logically zero".
  • UserCount — the virtual, reset-able count visible to the application.

Then in OB1 every scan:

UserCount = ACT_CNTV − ZeroOffset

and the application comparator is a simple integer comparison on UserCount:

UserCount ≥ 2000 → set DQ0  (any logic output of the CPU, not the FM350-1 output)
UserCount ≥ 5000 → set DQ1  AND set the reset one-shot for the next scan

The "reset" is now a single assignment:

ZeroOffset = ACT_CNTV

executed on the positive edge of the reset request. No pulse is dropped because the FPGA counter is never touched. ACT_CNTV keeps incrementing indefinitely; the application sees a wrap-around-free 0…5000 counter, and the hardware comparators are simply left disabled in HW Config.

Step-by-Step Implementation in STEP 7 STL

Allocate the following symbols in DB100 (or any working DB / M area):

Symbol Address Type Initial value
ResetTrig DB100.DBX0.0 BOOL FALSE
OneShot DB100.DBX0.1 BOOL FALSE
DQ0_Out DB100.DBX0.2 BOOL FALSE
DQ1_Out DB100.DBX0.3 BOOL FALSE
ZeroOffset DB100.DBD4 DINT 0
UserCount DB100.DBD8 DINT 0
SetPoint1 DB100.DBD12 DINT 2000
SetPoint2 DB100.DBD16 DINT 5000

OB1 — segment 1, edge-detected zero-offset capture:

      A    "ResetTrig"            // ResetTrig (e.g. from HMI or from DQ1_Out)
      FP   "OneShot"              // edge flag, FB-internal or DB bit
      JNB  END1
      L    PID 276                // ACT_CNTV (32-bit, aligned)
      T    "ZeroOffset"           // snapshot — pulse loss impossible
END1: NOP 0

OB1 — segment 2, the running virtual counter (executed every cycle):

      L    PID 276                // ACT_CNTV (32-bit)
      L    "ZeroOffset"           // 32-bit
      -D                           // double-integer subtraction
      T    "UserCount"            // visible count to the rest of the program

OB1 — segment 3, software comparators and outputs:

      L    "UserCount"
      L    "SetPoint1"            // 2000
      >=D
      =    "DQ0_Out"              // mapped to any CPU DO (e.g. Q4.0)

      L    "UserCount"
      L    "SetPoint2"            // 5000
      >=D
      =    "DQ1_Out"

      A    "DQ1_Out"
      =    "ResetTrig"            // self-resetting trigger for segment 1
STL mnemonic note: The field report uses -I (16-bit integer subtraction). Because ACT_CNTV and ZeroOffset are 32-bit, the correct opcode is -D. Using -I will compile and run but will silently truncate ACT_CNTV to 16 bits, producing wrong counts above 32 767. Always use -D for any 32-bit counter arithmetic on S7-300/400.

OB1 — segment 4, optional hysteresis to release the outputs at the end of the cycle. The pattern above keeps DQ0 and DQ1 latched between cycles 2000/5000 and 0. If the application needs edge-pulsed outputs, add a one-cycle pulse on first cross:

      L    "UserCount"
      L    1
      <=D
      A    "DQ0_Out"
      S    "DQ0_Pulse"            // fires for one scan on the way back to 0
      AN   "DQ0_Out"
      R    "DQ0_Pulse"

Hardware Configuration, Wiring, and Encoder Selection

In STEP 7 HW Config, after the FM350-1 has been inserted and addressed (the example uses PI 272..287 / PQ 272..287), double-click the module and set the following parameters:

Tab Parameter Recommended setting for this application
Basic Operating mode Continuous counting
Basic Encoder signal 24 V incremental (A, B, N) or RS422, matching your sensor
Basic Count direction Up (default)
Basic Gate control SW gate only (cancel / reset controlled by user program)
Outputs DQ0 / DQ1 function No function — outputs are driven by the CPU now
Outputs Comparator source — (n/a when "No function")
Diagnostics Wire break, sensor supply Enable, route to OB82

Wiring on the front connector (X1):

Pin Signal Function
1 24 V Encoder supply (24 V out, fused 500 mA)
2 GND Encoder supply return
3 A Track A (24 V or RS422+)
4 A\ Track A inverted (RS422 only)
5 B Track B
6 B\ Track B inverted (RS422 only)
7 N Zero pulse (optional)
8 HW gate 24 V input — leave open if SW gate only
9 DQ0 Module output 0 (unused in this design)
10 DQ1 Module output 1 (unused in this design)
EMC wiring: Twisted-pair shielded cable for the encoder, shield clamped to the cabinet ground bar at the cable entry side only. Do not connect the shield at the FM350-1 end. RS422 wiring must use a twisted pair per channel (A/A\ and B/B\ twisted together). Maximum cable length for 24 V single-ended: 50 m; for RS422: 1 000 m at 500 kHz, derate above 200 kHz.

Diagnostic Status Word and Error Code Matrix

The status word (PIW 272) carries both operational state and diagnostic information. Read it every cycle and route the relevant bits to HMI:

Bit Symbol Meaning Diagnostic action
0 STS_RUN Counting active (SW + HW gate open)
1 STS_DIR 0 = up, 1 = down
2 STS_CMP1 DQ0 comparator match flag (sticky until read) Diagnostic, not used for control
3 STS_CMP2 DQ1 comparator match flag (sticky until read) Diagnostic, not used for control
4..5 Reserved
6 STS_GATE Internal gate state (1 = open)
7 STS_OV Overflow / underflow of the 32-bit counter Reset ZeroOffset; investigate encoder direction
8 STS_LD_CMP_ACK Comparison values latched into the comparator
9 STS_LD_VAL_ACK Load-value (preset) latched
10..12 Reserved
13 STS_WIREBRK Wire break on A, B, or N Check encoder and cable; clear after repair
14 STS_SENS_SUP Sensor supply fault (short / overload) Remove load on pin 1, check 24 V
15 STS_ERROR Group fault (RAM/ROM/parameter) Cycle power, re-parameterise if persistent

Mapping to SFCs: STS_WIREBRK and STS_SENS_SUP are also reported as diagnostic interrupt (OB82). STS_OV is purely status; it must be handled in user logic because the counter is read-only and the FM350-1 cannot be configured to auto-preset on overflow. The standard handling is exactly the ZeroOffset snapshot pattern shown above — increment ZeroOffset by 2 147 483 647 (or the negative equivalent) when STS_OV is observed, so that UserCount continues monotonically across the wrap.

Edge Cases: 32-bit Overflow, Cycle Time, and Reset Storms

1. 32-bit overflow. At 500 kHz the raw 32-bit counter wraps in roughly 4 294 s of uninterrupted counting. For most positioning applications this is irrelevant, but on a continuously rotating spindle running for hours it is real. The recommended handling is to subscribe to STS_OV and add a 2 147 483 647 DINT correction to ZeroOffset in a one-shot. UserCount stays continuous.

2. OB1 cycle time. The software comparator introduces a ±1 OB1 cycle of jitter on the output firing instant. For a 10 ms cycle and a 500 kHz encoder this is 5 000 counts of uncertainty. If the application requires sub-cycle accuracy, route UserCount through a hardware-supported interrupt (OB40) driven by a 100 µs timer, or replace the FM350-1 with the modern ET 200SP TM Count 1x24V (6AT1131-0CA04-0AA0), which exposes a sub-µs comparator output via PWM.

3. Reset storm. The self-reset pattern in segment 3 (DQ1_Out drives ResetTrig) is safe provided the reset one-shot is on the positive edge of ResetTrig only. If the user wires a level-driven reset, the counter is re-initialised every OB1 cycle while DQ1 is true, and UserCount oscillates between 5000 and ZeroOffset. The FP (rising edge) instruction in segment 1 is the entire protection.

4. Initial ZeroOffset on cold start. On the first OB1 scan after a CPU restart, ACT_CNTV may be non-zero (the module retains its count through PLC stop). The user code must initialise ZeroOffset to ACT_CNTV on first scan. Use a startup flag (e.g. OB100 sets ZeroOffset := ACT_CNTV) or check the "FirstScan" bit in OB100.

5. Negative UserCount after a forward-running reset. If the encoder keeps moving forward for 1 cycle between the DQ1 fire and the OB1 cycle that runs segment 1, UserCount is briefly 1…N before the new ZeroOffset takes effect. Most applications tolerate this. If not, latch DQ1_Out for one extra cycle.

Commissioning Checklist and Verification Procedure

  1. HW Config check. Open the FM350-1 properties dialog; confirm Outputs = "No function" and SW gate enabled. Save and download to the CPU.
  2. Process image check. Open a VAT table online, force PID 276 (ACT_CNTV) into a watch view. Hand-turn the encoder and verify the value increments in x1, x2, or x4 as configured.
  3. Status word check. Watch PIW 272. Bit 0 (STS_RUN) should be 1 after the SW gate is opened. Bit 13 (wire break) should be 0 with the encoder wired.
  4. ZeroOffset path test. Set a breakpoint in segment 1; trigger ResetTrig; confirm ZeroOffset takes the value of ACT_CNTV, and that ACT_CNTV is unchanged after the trigger.
  5. UserCount test. Turn the encoder slowly. UserCount must track 1, 2, 3 … continuously. Reset at any value; UserCount must jump to the new offset without dropping the next count.
  6. Comparator test. Drive SetPoint1 to 100; turn the encoder 200 counts. Confirm DQ0_Out is 1 between UserCount = 100 and the next reset. Repeat for SetPoint2 / DQ1_Out.
  7. Pulse-loss test. At 100 kHz and an OB1 of 10 ms, run the cycle for 1 hour. Compare the number of DQ1 events with a reference counter fed by the same encoder; both should agree to within 1 count per cycle (≈ 1 count / 10 ms at the comparator, none elsewhere).
  8. OB82 diagnostic test. Unplug the encoder cable. Confirm OB82 fires, STS bit 13 goes high, and the SF LED on the FM350-1 is lit. Reconnect, acknowledge the diagnostic, and verify STS bit 13 clears.
Safety note: If DQ0 or DQ1 in the original design controlled a safety-rated actuator, this software pattern is not a valid replacement for the safety chain. The CPU outputs and the application logic must reach the required Performance Level / SIL independently. For SIL 2 / PL d applications, use a safety output module (e.g. SM 326F) and route the comparator logic through it, not through the FM350-1 outputs.

Why does my FM350-1 keep ACT_CMP1 and ACT_CMP2 at zero after I write CMP_V1 and CMP_V2?

ACT_CMPx are not mirrors of CMP_Vx; they are status flags indicating the values the on-board FPGA has latched. They stay at 0 until the SW gate is open, the HW gate is open, the output is enabled in HW Config, and the LD_CMP bit in the control word has been pulsed and acknowledged (STS bit 8 = 1). If you do not need the module's hardware comparator, disable the outputs in HW Config and implement the comparator in the CPU — read-back issues disappear entirely.

How do I reset the FM350-1 counter without losing encoder pulses?

Do not touch the FPGA counter register. Instead, snapshot ACT_CNTV (PID 276) into a DINT called ZeroOffset on the rising edge of your reset request, and compute UserCount = ACT_CNTV − ZeroOffset on every OB1 cycle. The raw counter never resets, no pulses are dropped, and the application sees a virtual counter that can be "reset" instantly to any value.

Can I still use the FM350-1 on-board DQ0 and DQ1 outputs with this software-comparator pattern?

Yes, but it is rarely useful. The DQ0 / DQ1 outputs are bonded to the on-board comparators and only fire on hardware-equal matches. With the software pattern you normally drive general-purpose digital outputs of the CPU (e.g. a SM 322 DO32). Only keep DQ0 / DQ1 in play if you specifically need the sub-µs hardware latency and your application tolerates the ACT_CMPx read-back configuration discipline.

What is the correct STL opcode for subtracting a 32-bit counter value?

Use -D (double-integer subtraction), not -I. ACT_CNTV and ZeroOffset are 32-bit DINT; -I truncates to 16 bits and produces wrong results above 32 767 counts. The full three-instruction pattern is L PID 276; L "ZeroOffset"; -D; T "UserCount".

Does the FM350-1 configuration software need to be installed separately?

Yes. The FM 350-1 / FM 450-1 configuration package is a separate install on top of STEP 7 V5.x. Without it, the FM350-1 does not appear in HW Config and the parameterisation dialog is missing. The package is documented in Siemens KB article 28291262 and is required for any project that uses the module on S7-300 or ET 200M.

How do I handle the FM350-1 32-bit overflow in a continuous-rotation application?

Watch the STS_OV bit (PIW 272, bit 7). When it sets, add 2 147 483 647 (or the negative equivalent) to ZeroOffset in a one-shot. UserCount stays continuous across the wrap. Do not attempt to "reset" the FM350-1 to recover from overflow — that re-introduces the pulse-loss problem.

Back to blog