Problem Overview
The Omron CPM1A-20CDR-A (and equivalent CPM1A-10/30/40CDR- CPUs) executing a ROL (Rotate Left, mnemonic 27) instruction in a CX-Programmer 5.0 ladder program produces irregular hexadecimal readouts on the source and destination words. Operators see expected pattern progressions such as 0000 → 0001 → 0010 → 0100 → 0000 for a 3-sensor cookie conveyor interleaved with anomalous values in the 0xFFF0 to 0xFFFF range. The root cause is carry-flag contamination: ROL rotates all 16 bits left by one position while feeding bit 15 into the CY (carry) auxiliary bit at SR 255.04 and feeding the existing CY state into bit 0.
Because the application rotates the IR200 word (live sensor data) and the IR202 word (sequence reference) without first clearing CY, the carry state from prior arithmetic or comparison operations leaks into bit 0 of the rotated word. When a single 1-bit rotates out of bit 15 into CY, every subsequent ROL cycle on the next word pushes a 1 (or whatever CY currently holds) back into bit 0, corrupting the bit pattern and producing two's complement-style HEX displays.
Root Cause: CY Feedback into Bit 0
The ROL instruction executes the following bit operation every program scan while its input condition is ON:
IR[n] bit 0 ← CY (SR 255.04) IR[n] bits 1..15 ← IR[n] bits 0..14 CY ← IR[n] bit 15
If CY holds a 1 from a prior ANDW, SUB, ADD, or CMP operation, bit 0 of the rotated word becomes 1 after every ROL cycle. For the cookie line where the first 3 bits hold the state of three inductive sensors (IR200.00, IR200.01, IR200.02), any extraneous 1 in bit 0 or in bits 3 to 15 produces a comparison mismatch with IR202. When the comparison fails the operator sees the sequence word displayed as a high hexadecimal value rather than the expected low-order bit progression.
CY is a sticky bit that retains its value until the next instruction that explicitly modifies it executes. In CX-Programmer 5.0 the ROL instruction does not automatically clear CY before each rotation, and there is no differentiated "ROL with carry clear" variant. The only differentiated form is @ROL (edge-triggered) which executes once per OFF→ON transition but still propagates the existing CY value into bit 0 on that single execution.
Solution 1: Differentiated @ROL for Edge-Triggered Execution
Prefix the ROL mnemonic with the @ symbol to instruct the PLC to execute the rotation only on a rising edge of the input condition. This controls the timing of the rotation but does NOT clear the carry flag itself.
| LD 253.13 ; Always ON flag | @ROL IR202 ; Rotate IR202 left by 1 on rising edge | LD 253.13 ; Always ON flag | @ROL IR200 ; Rotate IR200 left by 1 on rising edge
Because 253.13 (Always ON) cycles OFF→ON only on the first scan after entering RUN, the rotation will not repeat unless a real input transition drives the input condition. Wrap the rotation in a one-shot circuit driven by the actual sensor input if a single cycle per event is required.
Solution 2: Replace ROL with ASL (Arithmetic Shift Left)
The ASL instruction (function code 25) shifts all 16 bits left by one position, places a hard-wired 0 into bit 0, and feeds bit 15 into CY. This eliminates the CY→bit 0 contamination path because bit 0 always becomes 0 regardless of the carry flag's prior state.
| LD 253.13 ; Always ON flag | ASL IR202 ; Shift IR202 left; bit 0 ← 0, bit 15 → CY | LD 253.13 ; Always ON flag | ASL IR200 ; Shift IR200 left; bit 0 ← 0, bit 15 → CY
ASL is the correct instruction for the cookie line where the objective is to advance a 1-bit marker through positions 0, 1, 2, 3, ... rather than perform circular rotation. Use the differentiated @ASL form when a single shift per event is required.
Solution 3: Clear CY Before ROL with STC Instruction
The CPM1A instruction set includes the STC (Set Carry, function code 40) instruction which forces CY to 1, but no direct CLC exists in the legacy set. To force CY to 0, execute an instruction whose CY behavior you control. For example, compute CLC-equivalent by performing an ANDW of a word against itself (ANDW IR202 IR202) which always yields the same word and clears CY as a side effect, or use the CLC instruction available in the CP1E/CP1L/CP2E extended set with firmware version 1.0 or later.
For the legacy CPM1A, the simplest approach is to recompute the bit pattern from the inputs directly without rotation, which leads to the shift-register approach described in the next solution.
Solution 4: Shift Register (SFT) Instruction
The SFT instruction (function code 10) shifts a contiguous range of bits left through a 16-bit word, optionally wrapping with the optional reset input. SFT is purpose-built for sequence-tracking applications:
| LD IR200.00 ; Sensor 1 input | SFT(10) IR202.00 IR202.15 R ; Shift left, optional reset on R
SFT shifts bit IR202.00 → IR202.01, IR202.01 → IR202.02, etc., and accepts new data into IR202.00 from the preceding rung's execution. The result is a clean shift register that records the history of sensor activations in bit positions 0 through 15 with no CY contamination.
Solution 5: Bit-Mask Comparison with ANDW
Even with a corrected shift/rotate instruction, the full 16-bit comparison against IR200 may mask mismatches caused by stray bits in positions 3 to 15. Apply a 3-bit mask before comparing:
| LD 253.13 ; Always ON | ANDW #0007 IR202 D0 ; Mask IR202 to 3 bits → D0 | ANDW #0007 IR200 D1 ; Mask IR200 to 3 bits → D1 | CMP(20) D1 D0 ; Compare masked words
The ANDW instruction (function code 34) ANDs the constant 0x0007 (binary 0000 0000 0000 0111) with each source word, zeroing all bits except bits 0, 1, and 2. CMP (function code 20) sets the EQ flag (SR 255.06) when the two masked words are equal.
Cookie Line Implementation Sequence
For the specific 3-sensor cookie line, the cleanest implementation uses SFT or ASL rather than ROL. The expected sequence of one cookie passing three sensors in order is:
| Step | Sensor 1 (IR200.00) | Sensor 2 (IR200.01) | Sensor 3 (IR200.02) | IR200 Hex | Expected IR202 Hex (shifted) |
|---|---|---|---|---|---|
| Initial | 0 | 0 | 0 | 0000 | 0000 |
| Cookie enters sensor 1 | 1 | 0 | 0 | 0001 | 0001 |
| Cookie enters sensor 2 | 0 | 1 | 0 | 0002 | 0003 |
| Cookie enters sensor 3 | 0 | 0 | 1 | 0004 | 0007 |
| Cookie exits | 0 | 0 | 0 | 0000 | 000E (rolling out) |
Two cookies in the line simultaneously would produce 0x0007 (sensors 1+2 active) or 0x0006 (sensors 2+3 active). If a cookie is "eaten" between sensor 2 and sensor 3, IR200 jumps from 0x0002 (sensor 2 only) to 0x0000 (no sensors active) without ever hitting 0x0004. The sequence reference IR202 still expects 0x0004, the CMP detects inequality, and the conveyor stops until the operator clears the jam.
Instruction Comparison Reference
| Instruction | Code | Bit 15 Destination | Bit 0 Source | CY Effect | Best Use |
|---|---|---|---|---|---|
| ROL | 27 | CY | CY | Bidirectional feedback | True circular rotation, requires CY management |
| ROR | 28 | CY | CY | Bidirectional feedback | True right rotation |
| ASL | 25 | CY | 0 (hard-wired) | CY ← bit 15 | Linear shift left, multiply by 2 |
| ASR | 26 | CY | 0 (hard-wired) | CY ← bit 0 | Linear shift right, divide by 2 |
| SLD | 74 | bit 3 of next word | bit 12 of previous word | None | 4-bit digit shift across words |
| SRD | 75 | bit 3 of next word | bit 12 of previous word | None | 4-bit digit shift right |
| SFT | 10 | dropped (or reset) | input data | None | Bit-shift register with optional reset |
| SFTR | 84 | dropped or CY | input data | CY ← last shifted bit | Reversible shift register |
Carry Flag Reference (SR Area 252-255)
| Address | Name | Function |
|---|---|---|
| SR 253.13 | Always ON | Always ON - used for unconditional execution |
| SR 253.15 | First Cycle | ON for first scan only after RUN transition |
| SR 255.00 | 0.1s clock | 0.1 second pulse (50 ms ON / 50 ms OFF) |
| SR 255.01 | 0.2s clock | 0.2 second pulse (100 ms ON / 100 ms OFF) |
| SR 255.02 | 1.0s clock | 1.0 second pulse (500 ms ON / 500 ms OFF) |
| SR 255.03 | ER | Error flag - set when instruction error occurs |
| SR 255.04 | CY | Carry flag - set by arithmetic overflow or rotate out |
| SR 255.05 | GR | Greater-than flag (CMP result) |
| SR 255.06 | EQ | Equal flag (CMP result) |
| SR 255.07 | LE | Less-than flag (CMP result) |
Verification Procedure
- Connect CX-Programmer 5.0 (or later version up to CX-Programmer 9.74 in CX-One 4.x) to the CPM1A via the CPM1A-CIF01 or CPM1A-CIF11 RS-232C peripheral port. Set DIP switch SW1 on the CPU to OFF (default) for Host Link mode at 9600 bps.
- Place the PLC in PROGRAM mode and download the corrected ladder program. Verify the ANDW mask constants are entered as decimal #0007 or hex &0007 depending on the CX-Programmer radix setting under Tools → Options.
- Switch to MONITOR mode. Open the Watch Window for IR200, IR202, SR 255.04 (CY), and SR 255.06 (EQ).
- Force IR200.00, IR200.01, IR200.02 individually and observe that IR202 tracks the expected mask sequence: 0x0001 → 0x0003 → 0x0007 → 0x000E. Verify that the EQ flag (SR 255.06) sets when the masked IR200 matches the masked IR202.
- Force IR200.04 (a bit outside the mask range) and confirm that the comparison still indicates equality as long as bits 0-2 of both words match. If the EQ flag drops, the masking is not active.
- Force SR 255.04 (CY) to 1 manually and execute a ROL on IR202. Confirm that bit 0 of IR202 becomes 1 after the rotation. This reproduces the original contamination symptom and validates that the ASL solution is required for predictable behavior.
- Run a 30-minute production test with the cookie simulator (real sensors or simulated I/O) and record the EQ flag transitions. No false EQ drops should occur during normal sequencing.
Edge Cases and Field-Proven Caveats
CY propagation across instruction blocks: The CY flag survives across multiple scan cycles until any arithmetic, comparison, or rotate instruction modifies it. If the ROL is in a subroutine that runs only on certain conditions, CY may carry state from the main program's last ADD or SUB instruction. Insert a known-state-producing instruction (such as ANDW of a word against itself) immediately before the ROL if subroutine execution is non-deterministic.
Watchdog effects of @ROL with high-frequency inputs: Differentiated @ROL is safe up to the CPM1A's instruction execution budget of approximately 0.72 µs per ROL instruction (per the W353 instruction timing table). With 3 sensors at 50 Hz each, the maximum ROL rate is 150 Hz, well within budget. For higher rates on a CPM1A-10CDR (smaller instruction memory), consider moving the rotation to scheduled interrupt task INT(89) at a fixed interval.
IR vs CIO addressing: In CX-Programmer 5.0, the legacy IR (Internal Relay) prefix maps to the CIO area in newer platforms. If migrating to CP1E, CP1L, or CP1H, replace IR200 with CIO 200, IR202 with CIO 202, and SR 255.04 with the equivalent auxiliary bit in the new platform's AR area. The instruction codes (ROL, ASL, SFT) remain identical across the migration.
CX-Programmer version compatibility: CX-Programmer 5.0 projects load correctly in CX-Programmer 9.x and later, but the Save As format may strip legacy comments. Always export the project to a CX-One 4.x format (CX-Programmer 9.74 or later) before migrating to a new PLC model, and verify all instruction operand formats against the target CPU's instruction set.
SFT reset input: The SFT instruction's third operand is an optional reset bit. If you supply a non-zero bit address, the entire shift register clears when that bit is ON. For the cookie line, wire the operator "Clear Jam" pushbutton to the SFT reset input so the conveyor can be re-armed after an eaten-cookie event without entering PROGRAM mode.
Scan time impact on CY-sensitive logic: A 1 ms increase in scan time does not affect ROL/ASL behavior, but a subroutine call that performs heavy floating-point math can leave CY in an unpredictable state. Always force CY to a known value (via ANDW x x or STC + CLC) before any rotate instruction that depends on bit 0 starting at 0.
Recommended Implementation
For the cookie production line on a CPM1A, the recommended approach combines three of the solutions above:
- Replace ROL with SFT (preferred) or ASL to eliminate CY contamination by construction.
- Add an ANDW mask (constant 0x0007) before each compare so stray bits in positions 3-15 do not affect equality.
- Wire the jam-clear pushbutton to the SFT reset input (if using SFT) or to a CLR instruction on IR202 (if using ASL) so the operator can re-arm the line without a full program-mode transfer.
Result: bit-0 contamination is impossible by construction, the comparison is unaffected by stray bits in the upper positions, and the operator can resume production after a fault without restarting CX-Programmer.
FAQs
Why does the Omron CPM1A ROL instruction produce 65535 minus N hexadecimal values?
The high readouts occur because ROL rotates bit 15 into the CY flag (SR 255.04) and rotates the previous CY value back into bit 0. When CY holds 1 from a prior arithmetic operation, bit 0 becomes 1 after every rotation, and a string of leading 1s in the upper bits causes CX-Programmer to display the value as its two's complement representation. Use ASL or clear CY before each ROL to eliminate the symptom.
Does the @ROL differentiated instruction clear the carry flag?
No. The @ROL instruction only changes when the rotation executes (once per OFF→ON transition of the input condition). The CY flag is still rotated into bit 0 exactly as in the non-differentiated ROL. The @ prefix is a timing control, not a carry-control modifier.
What is the difference between ROL and ASL on the CPM1A?
ROL performs circular rotation: bit 15 wraps into CY and CY wraps into bit 0. ASL performs linear shift left: bit 15 wraps into CY and a hard-wired 0 enters bit 0. Use ASL when you want the rotated-out bit to be discarded; use ROL only when true circular behavior is required and you manage CY explicitly via STC and the ANDW trick.
Can I use the SFT instruction instead of ROL for a shift register application?
Yes. SFT (function code 10) is purpose-built for shift register applications on the CPM1A and avoids the CY contamination issue entirely. Specify the start bit, end bit, and optional reset bit in the operand list. SFT does not interact with the CY flag and executes in approximately 4.3 µs per scan.
How do I mask only the lower 3 bits of IR200 for comparison on the CPM1A?
Use ANDW #0007 IR200 D1 to AND the source word with hex 0x0007 (binary 0000 0000 0000 0111). The result in D1 contains only bits 0, 1, and 2 of IR200; all other bits are forced to 0. Then execute CMP(20) D1 D0 to compare against the masked reference word. The EQ flag (SR 255.06) sets when the masked words match.