Overview: Reading a Legacy CP1E PCB Programming Fixture
The OMRON CP1E is a compact PLC frequently used as the controller inside test fixtures, end-of-line programmers, and small bench-top automation cells. A common CP1E application is a PCB programming fixture: an operator loads a printed circuit board assembly (PCBA) onto a pogo-pin nest, closes a safety lid, presses Start, and the PLC orchestrates an RS-232 handshake with a host PC that flashes new firmware onto the board via a serial bootloader.
When inheriting a working CP1E program and trying to add features, the first obstacle is the memory map. CP1E addresses look different from what a controls engineer trained on Allen-Bradley, Siemens, or Mitsubishi expects. This reference decodes every address style encountered in a typical CP1E PCB-programmer ladder: data memory (D), holding relays (H), and decimal constants (&). It then walks through the compare-and-move rung pattern that drives the sequencer, and finishes with the RS-232 ASCII protocol implementation.
The reference material used throughout is the official SYSMAC CP Series CP1E CPU Unit Software User's Manual (W480) and the CP1E/CP2E CPU Unit Instructions Reference Manual (W483). Memory areas, instruction mnemonics, and port specifications are taken from those documents.
CP1E Memory Map Used in a PCB Test Fixture
A CP1E-N20DR-A or CP1E-N40DR-A CPU exposes the following memory areas relevant to the type of program described in the field report. The full area map is documented in W480 section 6 "Memory Areas."
| Prefix | Area | Range on CP1E-N | Retention on power loss | Bit access? |
|---|---|---|---|---|
CIO |
Core I/O (inputs, outputs, link, work) | CIO 0 - CIO 7935 | Partial; CIO 0-127 retained on -D type | Yes |
W |
Internal I/O (work bits) | W0 - W511 | Retained | Yes |
H |
Holding relays | H0 - H511 (32 words) | Retained | Yes |
A |
Special auxiliary relays | A0 - A959 | Mostly retained | Yes (read-mostly) |
T / C
|
Timers / Counters | T0 - T4095 / C0 - C4095 | Retained | Yes (completion flag) |
D |
Data memory (16-bit words) | D0 - D32767 | Retained | Word only on CP1E; bit access on CP2E |
IR / DR
|
Index / Data registers | IR0 - IR15, DR0 - DR15 | Non-retained | Word |
Three address styles appear repeatedly in a CP1E sequencer program: D100, H10, and &10. Each means something completely different, and confusing them is the most common reason a new programmer misreads a legacy rung.
D100 - Data Memory Word
D100 is word 100 in the Data Memory area. Data memory is the general-purpose 16-bit word storage on the CP1E and is retentive across power cycles. The full D area runs from D0 to D32767 on an N-type CP1E; the smaller E-type stops at D8191. According to W480 section 6-4, data memory is the default scratch area for:
- Sequencer step numbers
- Counter set values and current values
- ASCII string data (one character per byte packed in a 16-bit word)
- Math results, scaling constants, and recipe values
- RS-232 TX/RX buffer staging
To force a data memory word back to zero on program start, the convention is to use a one-shot of the first-scan flag or a rising-edge contact driving MOV &0 D100:
| P_First_Cycle ||--[MOV &0 D100]--|
CP1E data memory is word only; you cannot index D100.05 as a bit on a CP1E. If the documentation lists D-area bit access, it is referring to the CP2E series, which added that capability. Treat CP1E D-words as 16-bit containers only.
H10 - Holding Relay Word
H10 is word 10 in the Holding Relay area. The H area is retentive bit memory; H0 through H511 gives 512 individual bits organised as 32 words. Unlike data memory, every H word can be addressed at bit level using a dot suffix:
| Address | Meaning |
|---|---|
H10 |
The entire 16-bit word (often used with MOV, CMP, etc.) |
H10.00 |
Bit 0 of word 10 |
H10.01 |
Bit 1 of word 10 |
H10.11 |
Bit 11 of word 10 (the 12th bit, MSB-first convention) |
H10.15 |
Bit 15 of word 10 |
OMRON uses the IEC bit-numbering convention: bit .00 is the least significant bit (LSB), bit .15 is the most significant bit (MSB). In a PCB-programming fixture, the H area is the standard place to latch handshake flags from the host PC:
-
H10.00- SM message received from host (status message handshake) -
H10.01- RD message received (host ready) -
H10.02- SP message received (start programming request) -
H10.03- OK message received -
H10.04- NG message received (fail)
Because the H area is retentive, these latches survive a power dip, so the fixture can restart where it left off after an E-stop or brown-out. That is the design intent: "This area is also memory retentive and is really useful if power fails and you wish to restart where you were."
&10 - Decimal Constant
The & prefix denotes a decimal integer constant. &10 is the number 10 base 10, not hexadecimal 0x10 (which would be 16 decimal). OMRON's constant prefix system is:
| Prefix | Interpretation | Example |
|---|---|---|
& or no prefix |
Decimal integer |
&10 = 10 decimal |
# |
Hexadecimal integer |
#10 = 16 decimal (0x10) |
+ or -
|
Signed decimal (CX-Programmer) |
+25, -128
|
" " |
ASCII literal (single char in some instructions) |
'A' via MOV #41 |
&& |
32-bit decimal double-word constant | &&123456 |
Therefore &10 written to D100 means "store decimal 10." When that word is later compared with the =(300) instruction against D100, the test is "does D100 currently equal 10?" Constant style is fully covered in W483 section 2-2 "Instruction Formats."
Decoding the Sequencer Rung
A PCB-programming fixture typically uses an incremental sequencer: a single data-memory word holds the current step number, and the program is a long series of compare rungs of the form:
|--(D100 = &10)--| (compare: is the current step 10?)
| |
| +---[ action 1: turn on output, set bit, etc. ]
| +---[ action 2: load timer preset, move data, etc. ]
| +---[MOV &20 D100] (advance to step 20)
The compare instruction in CP1E ladder is = (mnemonic =(300)); the move instruction is MOV (mnemonic MOV(021)). Both are documented in W483.
Why the Original Programmer Used Step Increments of 10
When a sequence is built around &10, &20, &30, &40 ... instead of &1, &2, &3 ..., the author is leaving room for sub-steps and recovery branches:
-
&10- Main step "idle, waiting for start" -
&11, &12, &13- Sub-states within idle (e.g. door closed, lid locked, fixture homed) -
&20- Main step "request programming" -
&21- Sub-state "waiting for RD" -
&22- Sub-state "waiting for SM" -
&30- Main step "verify pass"
This convention is widely used on OMRON CP1E/CP2E/CJ2 because it lets the engineer insert diagnostic sub-states between major steps without renumbering the rest of the sequence. The field report explicitly notes: "The previous programmer used increments of &10 on purpose to make calling them easier. Saying that he has &1, &2 and I can't seem to find what he has stored in them." That is the design signature of a multi-level sequencer.
Why an OR Branch Exists on the Rung
The source question "Why is there an OR command in this step? What if the OR was not there?" has a precise ladder-logic answer. In a CP1E ladder diagram, instructions in series are logically AND-ed; instructions in parallel (OR branches) are logically OR-ed. The rung in question looks conceptually like:
+--[=(300) D100 &10]--[MOV &20 D100]--+
| |
( bus )+----------------------------------------+
| |
+--[H10.00]--------------[MOV &2 D0]---+
Two parallel branches exist because the original programmer wanted to advance the sequencer on either:
- The natural step transition (
D100 == 10) - the "happy path" branch, OR - An unsolicited SM message arriving on the serial port (
H10.00) - the "host override" branch.
Removing the OR would force the rung to evaluate as an AND: the MOV would only execute when both the sequencer step matched 10 and an SM message was present. That is rarely the desired behaviour in a host-driven test cell; the host's SM should be able to jump the sequence forward independently. The OR branch gives the rung two independent triggers for the same writes.
Key CP1E Instructions Used in the Fixture Program
MOV (021) - Move
MOV S D
Copies a 16-bit word from source S to destination D. Used to:
- Initialise
D100to&0on first scan. - Overwrite
D100with the next step number (MOV &20 D100). - Write the ASCII code of a character to the TX buffer word before TXD.
For 32-bit moves use MOVL(498).
=(300) - Equal Compare
= S1 S2
The input condition is ON when S1 equals S2. Companion instructions are <>(305), <(310), <=(311), >(320), >=(325). All are documented in W483 section 3 "Sequence I/O Instructions." The result is a single-bit condition that can drive a contact, a coil, or another instruction's enable input.
OR / OR NOT / OR LD - Boolean Wiring
These are not strictly "instructions" but rung-wire operations in CX-Programmer. In the ladder editor you draw a vertical branch by clicking the OR toolbar button; the compiler emits an OR or OR LD mnemonic. Semantically:
| Wiring style | Boolean operator | Truth table |
|---|---|---|
| Series (--[ ]--[ ]--) | AND | Output ON only when all inputs ON |
| Parallel branch (OR) | OR | Output ON when any input ON |
| NOT contact | Invert | Input inverted before AND/OR |
TXD (236) and RXD (235) - Serial Send/Receive
TXD D C N
RXD D C N
Where D is the first source/destination word, C is the control word (port, protocol), and N is the byte count (0-256). For an RS-232 ASCII handshake against a host PC, set control word for 8 data bits, no parity, 1 stop bit, no protocol, baud matched to the host. TXD triggers from the CP1E to the PC; RXD captures incoming ASCII into the buffer starting at D. Full parameter list is in W483 section 5 "Communication Instructions."
RS-232 ASCII Protocol: SP, RD, SM, OK, NG
The host PC and the CP1E exchange short ASCII command frames terminated by <CR> (carriage return, 0x0D). A typical PCB-programmer sequence is:
| Direction | Frame | Meaning | CP1E action |
|---|---|---|---|
| PC to PLC | SP<CR> |
Start Program | Latch H10.02; advance sequencer to step 20 |
| PLC to PC | RD<CR> |
Ready | Acknowledge: door closed, part present, fixture OK |
| PLC to PC | SM<CR> |
Status Message | Periodic heartbeat or state change notification |
| PC to PLC | OK<CR> |
Programming OK | Latch pass flag; advance to step 30 (verify) |
| PC to PLC | NG<CR> |
Programming NG (fail) | Latch fail flag; light tower red; advance to step 90 (alarm) |
| PC to PLC | AB<CR> |
Abort | Stop; reset; require cycle start |
On the CP1E, the receive buffer is staged in a contiguous block of data memory; on a CP1E-N20DR-A the typical staging area is D200 through D215. The RXD instruction places the bytes there, then a string-compare ladder block (often built from successive =(300) compares of each byte) decodes the message. For "SM", the decode is:
SM Compare Rung
+--[=(300) D200 &'S']--+--[=(300) D201 &'M']--+--[SET H10.00]--+
| | |
| (bus) | +--[TXD D300 C0 &3]----+
+-----------------------+ (transmit SM<CR> back)
Where D200 = 'S' is verified by =(300) D200 #53 (hex 53 is ASCII 'S'). On CP1E, writing the literal ASCII code as #53 is more memory-efficient than passing 'S' as a string.
Recommended PLC Port and DIP-Switch Settings
The CP1E-N and CP1E-S CPUs ship with two onboard serial ports. The wiring diagram below summarises which port is used for what in a typical PCB-programmer fixture.
| Port | Connector | Default use | Fixture assignment |
|---|---|---|---|
| Port 1 (built-in RS-232C) | Mini-DIN 8-pin (CP1W-CIF01 cable) | Host link / NT link / serial gateway | RS-232 ASCII to host PC (front-end comms) |
| USB port | USB Type-B | CX-Programmer programming | Laptop programming only |
| Option board slot (CP1W-CIF01 / CP1W-CIF11 / CP1W-CIF12) | Mini-DIN or terminal block | Additional RS-232C or RS-422A/485 | Optional second serial (barcode scanner, printer) |
DIP switch SW1 on a CP1E-N controls the standard peripheral bus / serial gateway mode for the option board slot. SW2 controls the use of the standard peripheral bus on the CPU. Refer to W480 section 2-2 "Switches" before changing either.
PLC Setup Register Words
Serial port parameters are set in the PLC Setup area (data memory D0 to D255, but used as setup rather than application memory). For the host-link port configured as free ASCII protocol:
| Setup word | Function | Typical value for host ASCII |
|---|---|---|
| Port 1: word 144-149 | Baud, format (start/stop/data/parity), protocol | 9600, 8N1, no protocol |
| Port 1: word 150 | Send delay / CTS control | 0 (no delay, CTS disabled for 3-wire) |
| Port 1: word 151 | End code for reception | 1 (CR only, 0x0D) |
| Port 1: word 152 | Max receive bytes per RXD | 256 |
For 3-wire RS-232 (TX, RX, GND only, no hardware handshaking) use control word bits that disable CTS/RTS. For full DTR/DSR handshaking use the 9-pin version.
Step-by-Step: Documenting an Inherited CP1E Program
- Save the project offline. In CX-Programmer, File > Save As and create a working copy named with today's date. Never edit the production file directly.
-
Open the cross-reference report. View > Cross-Reference Report. Sort by address. This shows every use of
D100,H10.00,W3.05across the entire ladder. -
Map every
Dword used. Create a spreadsheet with columns: address, decimal value, ASCII meaning (if any), written-by which rung, read-by which rungs. -
Map every
Hbit used. Same spreadsheet for theHarea. Flag every coil withKEEP(011)orSET/RESETbecause those are latches that survive power loss. -
Find every
MOVandMOVL. Those are the lines that change sequencer step numbers. They reveal the flow of the state machine. -
Find every
TXDandRXD. Those are the comms lines. Identify whichDblock is the receive buffer and which is the transmit buffer. -
Draw the state diagram. From the MOV targets of
D100, draw boxes for&0, &10, &20, &30.... Annotate each arrow with the trigger condition (which contact is in series) and the side effects (TXD, output set, etc.). -
Mark any undocumented steps. If
&1and&2are stored but no compare rung ever matches them, they are likely sub-step residuals or disabled diagnostic code.
Verification Checklist Before Powering Up a Modified Program
-
Compile with the simulator. CX-Programmer's simulator can run the ladder offline; step through
D100as it advances from 10 to 20 to 30. -
Watch
D100live. In Online > Monitor mode, pinD100in the watch window. Press Start with no PC connected and confirm the sequencer halts at the "waiting for SP" state. -
Loopback the RS-232 port. Fit a TX-to-RX jumper at the PLC end and confirm the PLC receives its own echoed commands. If
H10.00latches, the comms are wired correctly. -
Validate ASCII framing. Use a serial-line monitor (e.g. a laptop running a free COM-port sniffer) to confirm
<CR>(0x0D) and not<CR><LF>is being sent. The PLC's PLC Setup word 151 controls this. -
Confirm retentive bits latch correctly. After a power cycle, confirm
H10.xxretains the last state. If not, check PLC Setup word 99 / 100 (H area retention is normally on by default). - Cycle ten PCBs end to end. Track yield and average cycle time. A new MOV target that goes to the wrong step is the most common regression.
Common Pitfalls When Migrating CP1E Code to a CP2E or CJ2
| Pitfall | CP1E behaviour | CP2E / CJ2 behaviour |
|---|---|---|
Bit-level access on a D word |
Not allowed; D100.05 is a compile error |
Allowed on CP2E and CJ2 |
| DM area size | D0 - D32767 (N-type) | D0 - D32767 on CJ2; D0 - D8191 on CP2E-E |
| Built-in analog I/O | Not present on CP1E | CP2E-S has 2 AI / 1 AO on CPU |
| Structured Text and FB support | Ladder only | Ladder + ST + FB on CJ2; partial on CP2E |
| Special instruction set | Subset of CJ2 (no function blocks for sequences) | Full SEND(090), RECV(098), FINS/UDP on Ethernet |
If a fixture is being upgraded from a CP1E to a CP2E-N30 or CJ2M-CPU33, retain the same step-increment-of-10 convention and the same H-bit flag layout. That keeps the diagnostic documentation forward-compatible.
Quick Reference: Address-to-Meaning Glossary
| Address as written | What it really is | Typical role in a PCB fixture |
|---|---|---|
D100 |
Word 100 of data memory | Current sequencer step number |
D0 |
Word 0 of data memory | Often a counter, retry count, or status code |
H10 |
Word 10 of holding relays | Serial-handshake flag word (16 flags) |
H10.00 |
Bit 0 of word 10 | SM message received |
H10.02 |
Bit 2 of word 10 | SP (start programming) received |
&10 |
Decimal constant 10 | Step 10 of the sequencer |
&0 |
Decimal constant 0 | Step 0 (idle) |
#53 |
Hex constant 53 = ASCII 'S' | Compare against incoming 'S' in SM decode |
#4D |
Hex constant 4D = ASCII 'M' | Compare against incoming 'M' in SM decode |
#0D |
Hex constant 0D = CR | Frame terminator on TXD / RXD |
FAQ
What does D100 mean in an OMRON CP1E program?
D100 is word 100 of the Data Memory (D) area, a 16-bit retentive scratch register. On a CP1E-N the D area runs D0 to D32767. In sequencer programs D100 typically holds the current step number, written by MOV instructions and compared by =(300) instructions.
What does H10 mean and how is it different from H10.00?
H10 is word 10 of the Holding Relay (H) area, a retentive bit-memory block. H10 refers to the whole 16-bit word (used with MOV, CMP, etc.). H10.00 is bit 0 of that same word, addressable individually as a contact or coil. Bit .00 is the least significant bit and .15 is the most significant bit.
What does &10 mean versus #10 in a CP1E rung?
The & prefix denotes a decimal integer; &10 is 10 decimal. The # prefix denotes a hexadecimal integer; #10 is 16 decimal (0x10). Mixing them up is the most common beginner mistake when reading a legacy CP1E program.
Why would a ladder rung use an OR branch to drive the same MOV twice?
Parallel branches in ladder logic are OR-ed. Two branches driving the same MOV mean the destination is written whenever either branch is true. In a PCB fixture this is typical when the sequencer should advance either on the natural step transition or on an unsolicited host message; removing the OR would change the condition from OR to AND.
Which CP1E serial port should connect to a host PC running an ASCII protocol?
Use the built-in RS-232C port (Port 1, Mini-DIN via CP1W-CIF01 cable) on a CP1E-N or CP1E-S CPU. Configure PLC Setup words 144 to 151 for the baud rate, 8N1 format, no protocol, and CR-only end code so the RXD instruction terminates frames on 0x0D. Keep the USB port reserved for CX-Programmer online work.