Problem Definition
A common commissioning challenge on an Omron CJ1M-CPU22 (or CJ2M-CPU31) is sending data from the controller's serial port to an external device such as an Arduino Mega using the RS-232 protocol. Symptoms reported in the field include:
- The TXD(236) instruction executes but no bytes appear on the DB-9 line when probed with LEDs.
- Status flag A392.05 (Port 2 Send Ready) never goes ON.
- Flag A392.04 (Port 2 Transmission Error) latches ON instead, indicating the port cannot initialize.
- The CPU's COMM LED never blinks, confirming no edge transitions are present on TXD/RXD.
The root cause is almost always a combination of three issues: (1) the wrong option board installed in the CPU socket, (2) a logic-level mismatch between the Arduino (TTL 0–5 V) and the PLC port (RS-232 ±3 to ±15 V), and (3) port parameters in CX-Programmer set incorrectly or never set at all. This reference walks through every layer of the problem, from hardware selection to field verification with a serial monitor.
.cxp before applying changes.Hardware Identification & Required Components
The first step in any CJ-series serial commissioning is to confirm exactly which CPU you have and which port you are addressing. Many CJ1M and CP1H SKUs ship without a built-in DB-9 connector on the CPU module itself; the serial port is delivered as a snap-in option board. Misidentifying the SKU is the most frequent cause of the symptom "the port is configured but nothing transmits."
| Catalog Number | Built-in USB | Built-in RS-232 (Port 1) | Optional RS-232 Board (Port 2) | Notes |
|---|---|---|---|---|
| CJ1M-CPU11/12/13 | Peripheral USB only | None | CP1W-CIF01 required | No native DB-9; must add option board. |
| CJ1M-CPU21/22/23 | Peripheral USB only | None on CPU22 | CP1W-CIF01 required | The CPU22 discussed in the field case ships with the option slot empty. |
| CJ2M-CPU11/12/13 | Yes | RS-232 | Optional CP1W-CIF01 | Port 1 is pre-wired DB-9. |
| CJ2M-CPU31/32/33 | Yes | RS-232 | Optional CP1W-CIF01 | Default RS-232 port uses pins 2/3/5. |
For the CJ1M-CPU22 referenced in the field, the bottom socket of the CPU accepts an option board. The required board for true RS-232 on the CPU module is:
- CP1W-CIF01 – RS-232C option board, DB-9 male, signals on pins 2 (RXD), 3 (TXD), 5 (GND). This is NOT the same as the CP1W-CIF11 (RS-422/485) or CP1W-CIF12 (RS-485 isolated) variants.
Alternatives for older installations: the older CPM1A-CIF01 (RS-232C) and CPM1A-CIF11 (RS-422) boards are functionally compatible when CJ1M is configured to recognize them, but the CP1W form factor is the modern recommendation.
| Component | Catalog / Part Number | Purpose |
|---|---|---|
| RS-232 option board | CP1W-CIF01 | Provides Port 2 DB-9 with RS-232C levels. |
| TTL/CMOS ↔ RS-232 converter | MAX232 / MAX232CPE / MAX3232 | Bidirectional level translation between Arduino and DB-9 line. |
| Charge-pump caps (5 ea.) | 1.0 µF / 10 µF tantalum (per MAX232 datasheet) | Required for the on-chip ±10 V charge pump. |
| RS-232 cable | DB-9 male → DB-9 female straight-through | Carry 5 V logic probe or serial monitor tap. |
| USB-serial sniffer | FTDI FT232 or compatible | Tap the line into a laptop running RealTerm. |
Electrical Interface: RS-232 vs TTL
The Arduino Mega uses an ATmega2560 UART with TTL signal levels (0 V / 5 V), with logic HIGH ≥ 2.0 V and LOW ≤ 0.8 V, where the controller and listener share a common ground. RS-232C, in contrast, defines a single-ended asymmetric interface with a logic "1" (mark/Space) between –3 V and –25 V and a logic "0" (mark) between +3 V and +25 V, with the standard voltage range of ±5 V to ±15 V used by most transceivers, including the MAX232.
Connecting a 5 V Arduino TX pin directly to a PLC DB-9 RX pin will fail for two reasons:
- The Arduino's 0 V "space" will sit inside the PLC's ±3 V dead band, producing a logic-low error.
- The PLC's negative voltage swing can forward-bias the ATmega's input clamping diodes, risking permanent damage to the MCU if the PLC's –10 V appears on the Arduino's RX.
The correct bridge is a charge-pump transceiver such as the MAX232CPE (or 3.3 V-tolerant MAX3232). The chip accepts 5 V TTL on T1IN/T2IN and produces ≈ ±9 V on T1OUT/T2OUT. The MAX232 requires five external capacitors (typically 1.0 µF). Refer to the Maxim datasheet for the exact capacitor values and DC-DC polarity.
CX-Programmer PLC Setup – Serial Port Configuration
On a fresh project, the port parameters for the CJ1M serial option must be set both in CX-Programmer (offline) and downloaded to the CPU. The PLC Setup table holds the entries that the TXD instruction uses at runtime. The two relevant settings are:
Step-by-Step Procedure (CX-Programmer / Sysmac Studio)
- Open the project and go online. Right-click the CPU in the project tree and select PLC Setup → Serial Port 2 (or "SERIAL PC" depending on the version).
- Set the following fields for the Arduino link configured at 9600, 7, E, 2:
| Parameter | Required Value | Default (CPU factory) | Remarks |
|---|---|---|---|
| Communication Setting (Mode) | Host Link / Serial Gateway OFF | Host Link | Host Link forces a fixed protocol; disable if using raw TXD/RXD. |
| Baud Rate | 9600 bps | 9600 | Must match Arduino Serial.begin(). |
| Data Bits | 7 | 7 | Required for 7E2. |
| Parity | Even | Even | Use None/8N1 only if both sides agree. |
| Stop Bits | 2 | 2 | 2 stop bits equals the "2" in 7E2. |
| Flow Control | None | None | Disable Xon/Xoff for MCU links. |
| Send Delay | 0 ms | 0 | Increase only if the MCU is slow to react. |
| CTS Control | No | No | Set to "No" so TXD proceeds without hardware handshake. |
- Transfer the change: PLC → Transfer → To PLC. Confirm with the dialog box, switch to Program mode if prompted, then back to Run/Monitor.
- Verify that the new settings are now visible at CPU → Edit PLC Setup → Serial Port while online.
TXD Instruction Implementation
The TXD(236) instruction reads bytes from a consecutive block of words and pushes them out Port 1 or Port 2. The operands are:
| Operands | Address / Value | Meaning |
|---|---|---|
| S (Source) | D0 | First word holding the data to send. |
| C (Count) | #0010 (decimal 16) | Number of bytes to send (1–255). |
| P (Port) | 0010 (binary) = Port 2 | Selects the RS-232 option board port. |
Minimal Ladder Example
|
| P_On A39205 TXD(236)
|-----||----------------------||--------------------------------(S C P)|
| (D0,#0010,#0010)
|
Here, P_On is the always-closed flag (CF100 or CIO W0.00) and A392.05 is the "Port 2 Send Ready" flag – TXD interlocked against A392.05 ensures the previous transmission has finished before a new one starts, which is mandatory because TXD will not queue; it will silently drop bytes if the port is busy.
Loading the Source Buffer
Words D0..D7 must be pre-loaded with the bytes to send, in little-endian order per word:
MOV(021) #5441 D0 ; "AT" ASCII 0x41 ('A'), 0x54 ('T')
MOV(021) #2B0D D1 ; "\r+" ASCII 0x0D (CR), 0x2B ('+')
For testing, a simple two-byte stream such as "\r\n" at 9600 7E2 helps isolate whether the issue is the data or the framing.
Status Flag Diagnostics
The CJ1M exposes serial port status in the AR (Auxiliary Relay) area. The most useful flags during commissioning are:
| Flag | Function | Normal Condition | Symptom If It Latches |
|---|---|---|---|
| A392.05 | Port 2 Transmission Ready | ON when port is idle and ready | OFF with A392.04 set = port error |
| A392.04 | Port 2 Transmission Error | OFF during normal operation | ON = framing/overrun error or wrong port config |
| A392.07 | Port 2 Reception Complete | Pulses ON after each char | Stuck OFF = RX pin never toggled |
| A392.13 | Port 1 Transmission Ready | ON when port 1 is idle | Use this if you actually wired to the USB/built-in port |
| A392.15 | Port 1 Reception Complete | Pulses ON per byte | Verify the Arduino is talking back if needed. |
Field interpretation:
- A392.04 ON and A392.05 OFF at the same time means the port never came up. The most common cause is mismatched settings (baud rate wrong, parity wrong, port in Host Link mode without a host talking to it).
- A392.04 OFF and A392.05 OFF means the previous TXD is still in progress or the buffer is full.
- A392.05 ON while A392.04 OFF is the healthy state; if you still see no activity, the fault is downstream in the wiring or the converter.
MAX232 Wiring & DB-9 Pinout
The MAX232 in a 16-pin DIP requires four capacitors plus an optional fifth for the voltage doubler. The TTL side connects to the Arduino; the RS-232 side to the PLC DB-9.
Pinout Table
| MAX232 Pin | Signal | Arduino Pin (Mega) | DB-9 Pin (CP1W-CIF01) |
|---|---|---|---|
| 11 (T1IN) | TTL TX input | 19 (TX1) | — |
| 14 (T1OUT) | RS-232 TX output | — | 2 (RXD, to PLC) |
| 13 (R1IN) | RS-232 RX input | — | 3 (TXD, from PLC) |
| 12 (R1OUT) | TTL RX output | 18 (RX1) | — |
| 15 (GND) | Signal ground | GND (Mega) | 5 (GND, shield) |
| 16 (VCC) | +5 V | +5 V (Mega) | — |
| 6 / 4 / 2 / 5 / 1 / 3 | Charge pump caps | 1 µF to GND (typical) | — |
Inline Wiring Diagram (SVG)
Three rules are repeated in every CJ-series serial guide:
- Use only pins 2, 3, and 5 of the DB-9. Pins 4 (RTS) and 6 (DSR) are bridged inside the PLC; pins 7/8 are internal handshake and may be left open.
- Tie all grounds together: PLC ground, MAX232 ground, and Arduino ground must be on the same 0 V reference.
- Keep the cable short. RS-232 is rated for 15 m at the slowest common baud rates, but field installations beyond 5 m should be probed with an oscilloscope rather than LEDs.
Arduino Mega Serial1 Configuration
On the ATmega2560, Serial goes to the USB-UART bridge (pins 0/1), while Serial1 is the hardware USART1 on pins 18 (RX1) and 19 (TX1). Use Serial1 for the PLC link so you keep the USB monitor free for diagnostics.
// Arduino Mega sketch for 9600 7E2 receive from PLC
#include <Arduino.h>
void setup() {
Serial.begin(115200); // USB monitor
Serial1.begin(9600, SERIAL_7E2); // 7 data, Even parity, 2 stop bits to CJ1M
while (!Serial) {}
Serial.println(F("PLC link ready @ 9600 7E2"));
}
void loop() {
static uint8_t buf[64];
static uint8_t idx = 0;
while (Serial1.available() > 0) {
uint8_t c = Serial1.read();
if (idx < sizeof(buf)) buf[idx++] = c;
}
// Echo each message back to the USB monitor
if (idx > 0) {
Serial.print(F("RXD: "));
for (uint8_t i = 0; i < idx; i++) {
Serial.print(buf[i] < 0x10 ? "0" : "");
Serial.print(buf[i], HEX);
Serial.print(' ');
}
Serial.println();
idx = 0;
}
}
The key call is Serial1.begin(9600, SERIAL_7E2);. The Arduino's parameter set on the PLC must match this exactly: any deviation produces framing errors that surface on the PLC as A392.04 ON.
Communication Verification with RealTerm
Before chasing firmware bugs, verify the byte stream from the PLC with a passive monitor on the line. The recommended tooling:
- Hardware: FTDI USB-to-Serial adapter tapped to pins 2, 3, 5 of the DB-9. Tie the grounds; do not rely on the chassis.
- Software: RealTerm configured at 9600 7E2, Display as HEX, Half Duplex off, capture to file enabled.
-
Exercise: Cycle the PLC, run TXD with a known buffer such as
0x54 0x41 0x0D 0x0A("AT\r\n") and watch for the same bytes in RealTerm.
Step-by-Step Commissioning Procedure
- Confirm hardware: Power off the CPU, insert CP1W-CIF01 into the option slot until the latch clicks. Power up. The CPU COMM LED should remain OFF.
- Configure port: In CX-Programmer, open PLC Setup → Serial Port 2, set 9600 7E2, Host Link OFF, transfer to PLC, cycle power.
- Stage the buffer: Write D0 = 0x5441 ("AT") and D1 = 0x0D0A ("\r\n") via MOV instructions on first scan, then latch them.
- Wire the TXD rung: Use the ladder in the previous section. Put the CPU in Monitor mode.
-
Verify with RealTerm: Tap the line with a USB-serial sniffer, confirm the bytes
41 54 0D 0Aappear once per TXD scan when a rising-edge trigger fires the rung. - Verify the round trip: Have the Arduino echo the message back through Serial1. The PLC RXD(235) instruction should pulse A392.07 with each byte received.
- Log and document: Save the RealTerm capture as evidence for the project folder.
Troubleshooting Matrix
| Observed Symptom | Likely Cause | Diagnostic Step | Corrective Action |
|---|---|---|---|
| A392.05 OFF, A392.04 ON | Port in Host Link / wrong option board | Verify PLC Setup → Serial Port 2 mode | Set Host Link OFF, transfer, power-cycle. |
| A392.05 ON, COMM LED never blinks | Telegram sent on wrong port number | Check P operand of TXD | Set P = 0010 (hex) for port 2. |
| Bytes on line but corrupted in HEX view | Mismatched 7E2 vs 8N1 | Cross-check CX-Programmer and Arduino parity | Use identical parity and stop bits on both ends. |
| Garbled characters, e.g. 41→C2 | No ground between PLC and Arduino | Measure DB-9 pin 5 to Arduino GND | Strap the two grounds with a short link. |
| First byte correct, rest are junk | Arduino slower than 9600 7E2 | Trigger scope on byte boundary | Reduce baud to 4800 or add a 5 ms Send Delay in PLC Setup. |
| No voltage swing on DB-9 pin 3 | MAX232 capacitors missing / wrong polarity | Check V+ and V- pins of MAX232 | Use 1 µF (T) capacitors on C1+/C1-/C2+/C2-/V+. |
| LED test on TXD "blinks" but PLC COMM LED never does | LED probe loading the line | Remove LED; tap with USB-serial | Rely on protocol analyzer, not LEDs, for RS-232. |
| PLC COMM LED blinks, but Arduino shows nothing | T1OUT/R1OUT crossed | Trace MAX232 pins 14 and 12 | T1OUT → DB-9 pin 2; R1OUT → Arduino pin 18. |
Frequently Asked Questions
Does the CJ1M-CPU22 have an integrated DB-9 port?
No. The CPU module ships with a peripheral USB port and a free option-board slot. For RS-232 on Port 2 you must add the CP1W-CIF01 option board, which snaps into the socket on the bottom of the CPU and presents a male DB-9. The CP1W-CIF11 and CIF12 variants offer RS-422/485 instead and will not support the Arduino voltage levels described above.
Why does A392.04 latch ON right after power-up?
The transmission-error flag clears when the port has successfully initialized. If it latches ON immediately, the most common causes are mismatched baud rate / parity in PLC Setup, the option board missing, or the port still set to Host Link mode from a previous project. Reset PLC Setup to defaults, set 9600 7E2 with Host Link OFF, transfer, and cycle power. The flag should clear on next scan.
Can I bypass the MAX232 and connect Arduino TX directly to pin 3 (TXD) of the DB-9?
No. RS-232 expects ±3 to ±25 V swings; the Arduino delivers 0 / 5 V. Without the MAX232 you will see framing errors on the PLC and risk damaging the ATmega's input clamp diodes because the PLC can drive as low as –10 V on the TX line. The MAX232CPE generates the required voltage from a single 5 V supply.
What is the correct operand P for sending out Port 2?
For TXD(236) on a CJ1M/CJ2M with the CP1W-CIF01 in the option slot, use P = #0010 (hex) to address Port 2, or P = #0000 (default) to address Port 1 (the USB/peripheral port). The flag A392.05 corresponds to Port 2 Send Ready; A392.13 corresponds to Port 1. Choosing the wrong operand prevents the flag-based interlock from ever resolving.
Is RealTerm still the recommended Windows monitor for this link?
RealTerm remains a stable free option for ASCII or HEX captures on Windows XP/7/10/11. For modern environments, alternatives are PuTTY + a USB-serial adapter, Saleae Logic 2 for protocol decode, or simply the Arduino IDE's built-in Serial Monitor. The critical configuration is always the same: 9600 baud, 7 data bits, even parity, 2 stop bits, no flow control.