Omron PLC CMP Instruction: Multiple Compares in One Program

James Nishida16 min read
HMI ProgrammingOmronTechnical Reference
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

Omron PLC CMP Instruction: Running Multiple Compares in One Program

1. Overview: The Multi-CMP Problem in Omron PLCs

The CMP (Compare) instruction in Omron CS1, CJ1, CJ2, CP1, and CP-series PLCs is one of the most frequently used ladder instructions, yet it is also the source of one of the most common ambiguous-flag errors a maintenance engineer will encounter. Every time the CMP instruction executes, it overwrites the same three condition flags with the outcome of the comparison:

  • P_GT – Greater than
  • P_EQ – Equal to
  • P_LT – Less than

Because those flags are shared, naively placing two CMP instructions back to back in the same scan will let the second CMP silently overwrite the first CMP’s result. By the time downstream logic evaluates the flags, they reflect only the last comparison executed, not the intended one. This is the classic ambiguous result flag failure mode that drives an entire station to behave erratically with no obvious logic error in the editor.

This reference documents the four engineering methods used to safely run multiple CMP blocks inside a single Omron PLC program: latching the result bits to internal relays, using a unique result word per CMP, switching to the CMP2 / symbol-form compare, and the Structured Text (ST) implementation path used in Sysmac Studio for NJ/NX controllers. Each method is paired with ladder samples, IO tables, and verification steps.

Field note: The CMP instruction in Omron PLCs is not uniquely identified by a designator (no instance ID, no instance name, no ENO). It is a stateless block that reuses the same auxiliary flag area every scan. Treat it like a single global function call that returns into shared memory.

2. CMP Instruction Architecture: Result Flags and Execution Model

The CMP instruction lives in the CS/CJ/CP CPU instruction set as a single-output function that consumes two source words (S1 and S2) and an optional result word. The instruction is documented in the CJ2 CPU Unit Hardware User’s Manual (W472) and the CP1 CPU Unit Operation Manual (W394).

2.1 Instruction Format

Operand Meaning Allowed Areas
S1 First source word (16-bit signed/unsigned) CIO, W, H, A, D, T/C, DM, @-indirect, *-indirect, constants (#)
S2 Second source word Same as S1
C Result word (optional in newer firmware) W, H, A, D, CIO

2.2 Condition Flag Behaviour

By default CMP writes its result into the shared arithmetic condition flags in the auxiliary area of the CJ2/CP1E/CP1H/CS1D family. The relevant bits and their default addresses are:

Flag Function Shared Address (CJ2 example) Symbolic Name
P_GT Greater than A200.05 CMP_P_GT
P_EQ Equal to A200.06 CMP_P_EQ
P_LT Less than A200.07 CMP_P_LT

On the CJ2M CPU units the result word operand (C) is mandatory on firmware 2.0+ for any CMP block that you want to write into a destination other than the auxiliary area. On CS1 and CJ1 units, the C operand was added in later firmware revisions; older units only write to the global flags.

2.3 Execution Timing

CMP is a single-scan instruction. It executes in one CPU cycle when its input condition is ON, writes the flags immediately, and is finished. There is no rising-edge detection built into the instruction. If the input condition is ON for ten consecutive scans, CMP runs ten times and writes the same flag pattern ten times – which means it will also overwrite a previously latched result from an earlier block during the same scan if the ladder order is wrong.

3. Why Multiple CMP Instructions Produce Ambiguous Results

Consider the following “obvious” ladder, which is the pattern that produces the most service calls:

     |---[ CMP D0  D100 ]---( A200.05 )-->  "high_speed_ok"
     |
     |---[ CMP D1  D100 ]---( A200.05 )-->  "torque_ok"

Both rungs drive coil A200.05 (the P_GT bit). Whichever CMP block executes last in the scan determines the value of A200.05 for the rest of the cycle. Coils driven from A200.05 downstream therefore see only the last result, not the “AND” of both. The behaviour is rarely what the original programmer intended.

3.1 The Three Failure Modes

  1. Last-write-wins — The final CMP block in the scan overwrites every previous result.
  2. Cross-contamination — A GT flag from CMP-A is misread as the result of CMP-B by downstream logic.
  3. Rung-disabled results — If a CMP input condition is OFF, the flags are not cleared; they retain the previous scan’s values. This is documented behaviour, not a bug, but it is a common reason a “stuck” comparison flag appears after a mode change.
Important: Omron does not clear the auxiliary area condition flags when CMP is skipped. If you change the input condition from ON to OFF, the previous result will persist until the next CMP executes. Always latch the result you need, never read the raw flag directly.

4. Method 1 — Latch CMP Result Bits with Internal Coils

The most common fix in legacy CS1/CJ1 code, and still the recommended pattern for technicians, is to snapshot the P_GT / P_EQ / P_LT flags into a private work-word immediately after each CMP, using a differentiated contact or a one-scan pulse to capture the result.

4.1 Ladder Example — Two CMPs, Latched to W0

     ; --- CMP #1: high-speed overspeed check ---
     |---[ W0.10 ]---[ CMP D0   D100 ]---------------------|
     |                  S1   S2   (implicit flags)          |
     |                                                     |
     |    +--[ A200.05 ]--[ DIFU 200.00 ]---( W1.00 )--+   |  ; GT snapshot
     |    |                                            |   |
     |    +--[ A200.06 ]--[ DIFU 200.01 ]---( W1.01 )--+   |  ; EQ snapshot
     |    |                                            |   |
     |    +--[ A200.07 ]--[ DIFU 200.02 ]---( W1.02 )--+   |  ; LT snapshot
     |                                                     |
     ; --- CMP #2: torque envelope check ---
     |---[ W0.11 ]---[ CMP D1   D200 ]---------------------|
     |                                                     |
     |    +--[ A200.05 ]--[ DIFU 200.03 ]---( W1.10 )--+   |  ; GT snapshot
     |    |                                            |   |
     |    +--[ A200.06 ]--[ DIFU 200.04 ]---( W1.11 )--+   |  ; EQ snapshot
     |    |                                            |   |
     |    +--[ A200.07 ]--[ DIFU 200.05 ]---( W1.12 )--+   |  ; LT snapshot

4.2 Why DIFU Is Required

DIFU (Differentiate Up) converts the momentary ON of a flag into a one-scan pulse, which the trailing coil uses to set a sticky bit. Without DIFU, the result coil would track the raw flag bit by bit, so you would still be subject to last-write-wins on the same scan. With DIFU, the snapshot coil latches after CMP has finished, isolating the two comparisons from each other.

4.3 Memory Map for the Latch Words

Word Bit Meaning Use in downstream logic
W1.00 CMP1_GT Speed > limit Trip overspeed alarm
W1.01 CMP1_EQ Speed = limit Target band reached
W1.02 CMP1_LT Speed < limit Spindle accel permissive
W1.10 CMP2_GT Torque > envelope Mechanical jam
W1.11 CMP2_EQ Torque = envelope Steady state
W1.12 CMP2_LT Torque < envelope Light load

4.4 Reset Path

Because the latched bits are now “sticky,” add a master reset rung to clear W1.00–W1.12 on mode change or cycle end:

     |---[ W0.00 ]---( RSET W1 )--|   ; All 16 bits of W1 cleared on one-shot reset

5. Method 2 — Use a Unique Result Word per CMP

On CJ2M firmware 2.0+ and CS1D, CMP accepts an explicit result word operand. The instruction then writes its result into a private word instead of the shared auxiliary area, which means two CMP blocks can run in the same scan without interfering with each other.

5.1 Ladder Example — Unique Result Word

     |---[ W0.10 ]---[ CMP D0   D100   W2 ]---|
     |                  S1    S2     C          |
     |
     |---[ W0.11 ]---[ CMP D1   D200   W3 ]---|
     |                  S1    S2     C          |

5.2 Bit Decoding of the Result Word

Result Word Bit Meaning For W2 (CMP1) For W3 (CMP2)
Bit 15 (MSB) Greater than W2.15 W3.15
Bit 14 Equal to W2.14 W3.14
Bit 13 Less than W2.13 W3.13

The same decoding pattern is documented in the CJ2 CPU Unit Software Manual (W473) for the BCMP2 and TCMP table-compare instructions, and applies to the legacy CMP C-operand form on every CJ2 firmware after v1.3.

5.3 Pros and Cons of Method 2

Aspect Method 2 (Unique Result Word)
Scan determinism Excellent — no flag collision
CPU load Lower (no DIFU, no extra rungs)
Firmware requirement CJ2 v2.0+ / CS1D / CP1H v1.0+
Readability Highest — results are private per block
Migration cost from legacy CMP Medium — must add the C operand

6. Method 3 — Use CMP2 (Symbol Compare) and Table Compare

Omron added a number of compare variants in the late CS1 / CJ1 era that store their result in a private word by design. They are often the cleanest way to embed multiple comparisons in dense logic.

6.1 CMP2 — Symbolic Comparison

CMP2(2) is the unconditional compare. It accepts the same S1, S2 operands as CMP but always writes its result into a private word passed as a third operand. It does not touch the global P_GT/P_EQ/P_LT flags.

     |---[ W0.10 ]---[ CMP2(2) D0  D100  W2 ]---|
     |                    S1   S2    C           |

6.2 Comparison Family and Result Word Layout

Instruction Mnemonic Result Word Bits Notes
Compare CMP / CMP2 15 = GT, 14 = EQ, 13 = LT 16-bit signed or unsigned
Double Compare CMPL / CMPL2 15 = GT, 14 = EQ, 13 = LT 32-bit, S1+1 / S2+1
Table Compare TCMP / TCMP2 16 bits, one per table row 16-row table, C is mask
Block Compare BCMP / BCMP2 16 bits, one per range Upper/lower table
Zone Compare ZCP / ZCP2 15 = GT, 14 = in range, 13 = LT Tests if S1 is between LL and UL

6.3 Why CMP2 Is Preferred for Multi-Compare Programs

  • No global flag pollution — Other parts of the program reading P_GT / P_EQ / P_LT are isolated.
  • One mnemonic, one result word — Ladder is self-documenting; the trailing C operand documents which work word owns this comparison.
  • Compatible with function blocks — In a structured FB, each instance can be passed its own C operand, which scales to dozens of comparisons without symbol conflicts.
Best practice: When the project standard is “no global CMP flags,” use CMP2 exclusively and reserve raw CMP for the rare cases where the global flags are intentionally read (e.g., driving a PID autotuner or a single analog alarm).

7. Method 4 — Sysmac Studio Structured Text (NJ/NX)

On the NJ and NX series controllers programmed with Sysmac Studio, the legacy CMP instruction is replaced by the EQ, GT, LT, GE, LE, NE operators inside Structured Text. There is no shared flag area in the same sense, so multiple comparisons in the same POU are inherently safe. However, the engineering discipline of isolating each comparison into its own boolean variable is still required for clean code review and FDA-style validation.

7.1 ST Example — Multiple Compares in One POU

// Conveyor and spindle comparison block
IF bCompareEnable THEN
    bSpeedHigh  := (iActualSpeed > iSpeedLimit);     // GT  -> bSpeedHigh
    bSpeedOK    := (iActualSpeed = iSpeedLimit);     // EQ  -> bSpeedOK
    bSpeedLow   := (iActualSpeed < iSpeedLimit);     // LT  -> bSpeedLow

    bTorqueJam  := (iActualTorque > iTorqueEnvelope);
    bTorqueOK   := (iActualTorque = iTorqueEnvelope);
    bTorqueLow  := (iActualTorque < iTorqueEnvelope);
END_IF;

7.2 Mixing Ladder and ST in Sysmac

Many engineers keep a ladder routine for the IO scan and use a single ST routine named RPM_TorqueLogic to host all the comparisons. This makes code review trivial — one file, one set of boolean outputs, no shared global flag area to audit.

7.3 Ladder Variant in Sysmac

If you need ladder for shop-floor technicians, the equivalent is the >, =, < contact instructions. Each is a stateless block that does not pollute any global flag area:

     |---[ D0 > D100 ]---( bSpeedHigh )---|
     |---[ D0 = D100 ]---( bSpeedOK   )---|
     |---[ D0 < D100 ]---( bSpeedLow  )---|

8. Step-by-Step Implementation Procedure

  1. Identify the CPU model and firmware. In CX-Programmer, double-click the CPU entry in the project tree. CJ2M units below firmware v1.3 cannot use the C operand on CMP and must use Method 1 (latch with DIFU). CJ2M v2.0+ can use Method 2 (unique result word).
  2. Define a private work word per logical comparison. Allocate W2, W3, W4, … in the symbol table. Document each bit (GT, EQ, LT) in the symbol comments.
  3. Replace CMP with CMP2, or add the C operand to CMP, on every comparison that previously relied on the global flags.
  4. Map every consumer of P_GT / P_EQ / P_LT to the new private word, then search the program for any remaining A200.05, A200.06, A200.07 references to confirm they are intentional.
  5. Add a global reset rung for the latched work words. Tie it to a mode-change flag or cycle-complete flag to avoid stale comparisons across batches.
  6. Verify the symbol export for any HMI or SCADA tag that previously bound to the global P_GT. Update the OPC tag to point to the new private word.
  7. Run a structured offline simulation in CX-Programmer. Force each comparison source to a known value, step the program, and confirm that only the intended result word changes.

9. Verification and Debugging Techniques

After the conversion, validate that the ambiguous-flag failure is gone. The following checks are field-proven and work on every Omron PLC in the CS/CJ/CP/NJ family.

9.1 Watch Window Checklist

Item What to monitor Expected value
W2.15 / W2.14 / W2.13 CMP1 result bits Exactly one bit ON at a time
W3.15 / W3.14 / W3.13 CMP2 result bits Exactly one bit ON at a time
A200.05–07 Global flags Should be stable or intentionally driven
W1.00–W1.12 Latched snapshot bits (Method 1) Stable across scans; only change on edge

9.2 Data Trace Setup

Set up a 1-second data trace on the comparison sources, the result words, and the global flags. The trace should be long enough to cover one full mode change (typically 5–30 s). If you ever see A200.05 toggle when only CMP2 should be running, the global flag is still being touched and the migration is incomplete.

9.3 HMI Cross-Check

If the SCADA was bound to the global P_GT bit, force the bit in CX-Programmer and confirm the HMI shows the right alarm. Repeat for the private result word. If the HMI still reads A200.05, it will keep showing the old (last-write-wins) result until the tag is updated.

9.4 Scan Time Impact

CMP2 adds no measurable scan time compared to CMP on CJ2M and CP1H. Adding DIFU per CMP block adds roughly 3–5 µs per block on a CJ2M-CPU31, which is negligible. The bottleneck in nearly every case is the read of the comparison sources, not the instruction itself.

10. Common Errors and Resolution Matrix

Symptom Likely Root Cause Fix
Comparison result flickers ON/OFF every scan Two CMP blocks share P_GT; flag is overwritten Apply Method 2 (C operand) or Method 3 (CMP2)
Result stays ON even after source changes DIFU is missing; the snapshot coil tracks the raw flag Insert DIFU between flag and latching coil
Result never updates Result word assigned to a read-only area (e.g., EM bank protected by UM) Reassign to a writable work area in CIO/W/D
PLC online shows 0x0000 in result word CMP not actually executing (input condition OFF) Verify input rung; CMP does not clear stale flags
HMI alarm lags by one cycle HMI tag still bound to global flag, not the private word Rebind HMI tag to W2.15 / W3.15 / etc.
“Operand type error” on transfer of CMP CJ2M unit below firmware v1.3 cannot accept C operand Use Method 1 (DIFU latch) or upgrade firmware
CMP result wrong on first scan after power-up Flags retain power-down state; no first-scan reset Add P_First_Cycle (A200.11) reset of all comparison result words
Two CMPs run “in parallel” but logic behaves sequentially Method 1 used without DIFU; coil races between the two blocks Insert DIFU on each flag path; re-test

11. Best Practices and Field-Proven Patterns

  • Never read global P_GT / P_EQ / P_LT directly from more than one comparison block. If you must, use the global flags only for a single dedicated CMP that is reserved as the “system comparison.”
  • Reserve W2–W31 (or W100–W131) for comparison result words. Document the allocation in the symbol table so future engineers do not reuse a comparison result as a scratch word.
  • Use P_First_Cycle (A200.11) to clear all comparison result words on power-up. Stale comparisons at first scan are a common source of nuisance trips.
  • Prefer CMP2 over CMP on new code. The only reason to use the global-flag CMP is for backward compatibility with an existing routine that reads the global flag.
  • Document every comparison with a one-line comment naming the source, the limit, and the consumer. A five-line program may not need it; a 200-rung program definitely does.
  • For high-speed comparisons on the same two words, use the <, =, > contact instructions. They execute in a single bit slice and avoid the auxiliary flag area entirely.
  • On NJ/NX projects, default to Structured Text for the comparison block, but keep one ladder routine for the IO scan so shop-floor technicians can troubleshoot on the console.
  • When validating per FDA 21 CFR Part 11 or GAMP 5, capture the symbol table snapshot in the validation report. A change in the comparison result word allocation must trigger a regression review.
Engineering judgment: The methods above are presented in order of increasing isolation. Method 1 (DIFU latch) is the smallest change to legacy code; Method 2 (unique result word) is the most common modern choice on CJ2/CP1H; Method 3 (CMP2 / table compare) is the cleanest for new programs; Method 4 (ST in Sysmac) is the standard for NJ/NX. Use the lowest method that meets your project’s validation and review requirements – do not introduce a CJ2M firmware upgrade just to enable CMP2 if a DIFU latch will satisfy the same logic test.

12. Frequently Asked Questions

Can I use the CMP instruction more than once in the same Omron PLC program?

Yes, the CMP instruction can appear multiple times in the same program, but each CMP block writes to the same shared auxiliary flags (P_GT at A200.05, P_EQ at A200.06, P_LT at A200.07). To prevent the last CMP block from overwriting earlier results in the same scan, add the optional C operand to write into a private result word, replace CMP with CMP2, or latch each flag to its own internal coil using DIFU before any other CMP runs.

Does the Omron CMP instruction clear the result flags when the input condition is OFF?

No. The auxiliary area condition flags are not cleared when CMP is skipped. If the input condition turns OFF, the previous result remains in the flags until the next CMP execution. The recommended pattern is to snapshot each flag into a sticky work bit via DIFU and clear the work bit on a mode change or first-scan flag, not to rely on the raw flag bit.

What is the difference between CMP and CMP2 in Omron PLCs?

CMP writes its result into the shared auxiliary flags A200.05–A200.07, while CMP2 always writes its result into the private result word supplied as the third operand and does not touch the global flags. CMP2 is the safer choice when multiple comparisons live in the same program because each instance owns its own result word, eliminating last-write-wins errors.

On which Omron CPUs can the CMP instruction use a result word (C operand)?

The C operand is supported on CJ2M firmware v2.0 and later, on CS1D, and on CP1H / CP1L CPUs that include the relevant instruction expansion. Older CJ1M and CS1G units without the firmware update cannot accept the C operand; on those, use the DIFU latch method or replace CMP with CMP2. Always confirm support in the CPU unit’s operation manual before relying on the C operand in production code.

How do I run multiple comparisons in an NJ or NX series controller?

Use the EQ, GT, LT, GE, LE, and NE operators in Structured Text inside Sysmac Studio, or the <, =, > contact instructions in ladder. The NJ/NX architecture does not use the legacy auxiliary flag area, so multiple comparisons in the same POU are inherently isolated. For shop-floor readability, keep all comparisons in one ST routine named after the function (for example RPM_TorqueLogic) and assign each result to its own named boolean variable.

Back to blog