Configuring CJ1M-CPU22 RS-232 Port for Arduino Serial

James Nishida13 min read
CJ/CP SeriesOmronTroubleshooting
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

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.

Safety: Always remove power before inserting or removing the CP1W-CIF01 option board or any wiring on the DB-9 connector. CJ1M/CJ2M CPUs retain the program but lose buffered port settings only if the battery is dead; back up project files to .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:

  1. The Arduino's 0 V "space" will sit inside the PLC's ±3 V dead band, producing a logic-low error.
  2. 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.

Field rule: Never trust a working LED on TXD/RXD as proof of data integrity. LEDs + series resistors impose nonlinear loading on the line and can masquerade as a working link while the PLC's UART never recognizes the start bit. Always verify with a protocol analyzer or a USB-serial tap.

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)

  1. 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).
  2. 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.
  1. Transfer the change: PLC → Transfer → To PLC. Confirm with the dialog box, switch to Program mode if prompted, then back to Run/Monitor.
  2. Verify that the new settings are now visible at CPU → Edit PLC Setup → Serial Port while online.
Watch out: On older CJ1M firmware (pre-V3.0), the Serial Port 2 settings only take effect after a power cycle. Cycle the PLC after the transfer if A392.04 still latches ON immediately.

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)

Arduino Mega ATmega2560 UART1 Pin 19 (TX1) Pin 18 (RX1) GND +5 V MAX232CPE T1IN / T1OUT / R1IN / R1OUT Pin 11 (T1IN) Pin 12 (R1OUT) Pin 15 (GND) Pin 16 (VCC) ±9 V swing ±9 V swing PLC DB-9 CP1W-CIF01 Pin 2 (RXD) Pin 3 (TXD) Pin 5 (GND) DTR/RTS (NC)

Three rules are repeated in every CJ-series serial guide:

  1. 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.
  2. Tie all grounds together: PLC ground, MAX232 ground, and Arduino ground must be on the same 0 V reference.
  3. 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.
RealTerm notes: The terminal scrollback buffer defaults to 10000 lines. Increase it if you are capturing long-running log streams. The Capture tab can write directly to a CSV with timestamps, which is invaluable when correlating TXD bursts with PLC cycle time in Watch Window.

Step-by-Step Commissioning Procedure

  1. 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.
  2. Configure port: In CX-Programmer, open PLC Setup → Serial Port 2, set 9600 7E2, Host Link OFF, transfer to PLC, cycle power.
  3. Stage the buffer: Write D0 = 0x5441 ("AT") and D1 = 0x0D0A ("\r\n") via MOV instructions on first scan, then latch them.
  4. Wire the TXD rung: Use the ladder in the previous section. Put the CPU in Monitor mode.
  5. Verify with RealTerm: Tap the line with a USB-serial sniffer, confirm the bytes 41 54 0D 0A appear once per TXD scan when a rising-edge trigger fires the rung.
  6. 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.
  7. 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.

Back to blog