Omron CQM1-CPU11 4-20mA Scaling Formula and Ladder Sample

James Nishida18 min read
HMI ProgrammingOmronTutorial / How-to
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

Overview

When a CQM1-CPU11 reads a 4-20 mA signal through a CQM1 analog input module, the raw count returned to the CPU is an integer in the 0-4000 range (or 0-8000 depending on module). The PLC has no built-in understanding of engineering units, so the program must convert that raw count into a value the operator can read - 0-100 PSI, 0-100 °C, 0-100 % tank level, or any other linear span. The Omron tool for that conversion is the SCL(66) expansion instruction, but on the CPU11's stripped-down instruction table SCL(66) can be flagged as not supported, can compile but never update the result, or can be missing from the CX-Programmer instruction tree. The reliable workaround is a manual scale using the basic arithmetic instructions MUL(32) and DIV(33), both of which are present on every CQM1 firmware revision.

This reference walks through the linear scaling formula, the CPU11 ladder implementation that works without SCL(66), edge-case handling for broken 4-20 mA loops, software damping for noisy loops, and a verification procedure using CX-Programmer's Watch window.

CQM1-CPU11 Hardware Profile and Instruction Set

The CQM1-CPU11 sits at the bottom of the CQM1 CPU family. The specifications that matter for scaling work are:

Parameter CQM1-CPU11 Value
Program capacity 3.2K words (ladder)
Data memory (DM) 1K words (DM 0000 - DM 1023)
Local I/O points 128 max
Expansion I/O points 128 max on one expansion rack
Basic instruction execution 0.5 µs typical
Special instruction execution 5-50 µs per instruction
Floating-point math Not supported (integer only)
Peripheral port RS-232C (Host Link / NT Link 1:1)
Real-time clock Not built-in (optional CQM1-CIF01/CIF02)

For complete specifications, refer to the CQM1 CPU Unit Operation Manual (Cat. No. W237) and the CQM1 Programming Manual (Cat. No. W347) on the Omron Industrial Automation documentation portal. The CPU11 supports the Boolean, timer, counter, and 16-bit integer arithmetic set used in every CQM1 ladder. SCL(66) is officially listed as supported in the CQM1 Programming Manual, but on early CPU11 firmware lots and with older CX-Programmer versions, the instruction can be rejected at compile time, dropped from the download, or accepted with a result word that never updates. The sections below show the manual fallback ladder that produces the identical result on every CPU11 firmware revision.

CQM1 Analog Input Modules

The CPU11 has no analog inputs on board. The most common companion module for 4-20 mA scaling is the CQM1-AD041. The CQM1 family also includes a higher-density and a bipolar option:

Model Channels Ranges Raw count Resolution per count Conversion time
CQM1-AD041 4 4-20 mA, 1-5 V, 0-10 V (per channel) 0-4000 unsigned 4 µA or 1 mV (1-5 V) or 2.5 mV (0-10 V) 2.5 ms / point
CQM1-AD042 4 -10 to +10 V, 0-10 V 0-4000 signed 5 mV 2.5 ms / point
CQM1-AD081 8 4-20 mA, 1-5 V 0-8000 unsigned 2 µA or 0.5 mV 1 ms / point

Set the input range on the AD041 with the front-panel DIP switch. For 4-20 mA, the rotary range switch on the side of the module is set to position "4" (or "2" on some lots) and the per-channel enable DIP sets which of the four channels are active. The module occupies a contiguous block of input words in the CPU's IR area. On a default AD041 mounted in slot 0:

Channel Data word
1 IR 200
2 IR 201
3 IR 202
4 IR 203
Note: The base IR address depends on the slot the module is mounted in and on whether a CQM1-PA power supply is fitted to the left of the CPU. Always upload the I/O table from CX-Programmer (PLC > I/O Table > Upload) before using any IR address in the ladder. If the module is in slot 1, the data words are IR 200-IR 203; in slot 2 they are IR 204-IR 207, and so on.

Some configurations also expose a peak/hold word at IR n+4 to IR n+7. The peak/hold feature is enabled per channel in the module's setup area; the default is disabled, in which case the data words are continuous from IR 200.

4-20 mA Current Loop and the Linear Scaling Formula

The 4-20 mA current loop is a process-control standard where the live zero of 4 mA represents the engineering low (0 %) and 20 mA represents the engineering high (100 %). On a CQM1-AD041, the relationship between the loop current and the raw count is:

Raw = 0    at 4 mA  (engineering low)
Raw = 4000 at 20 mA (engineering high)

The general linear scaling formula is:

EU = (Raw - Raw_low) × (EU_high - EU_low) / (Raw_high - Raw_low) + EU_low

For 4-20 mA to 0-100 with the AD041's 0-4000 range, Raw_low = 0 and the formula simplifies to:

EU = Raw × 100 / 4000

Worked examples for the CPU11 ladder:

Loop current Raw count EU calculation EU result
4.0 mA 0 0 × 100 / 4000 0
8.0 mA 1000 1000 × 100 / 4000 25
12.0 mA 2000 2000 × 100 / 4000 50
16.0 mA 3000 3000 × 100 / 4000 75
20.0 mA 4000 4000 × 100 / 4000 100

If the module is the CQM1-AD081 (0-8000 raw for 4-20 mA), change the divisor only:

EU = Raw × 100 / 8000

If the engineering unit range is not 0-100, plug the EU limits into the full formula. For a 0-1500 mm tank level:

EU = Raw × 1500 / 4000

For a 4-20 mA temperature transmitter calibrated to -50 to +200 °C:

EU = Raw × 250 / 4000 + (-50) = Raw × 250 / 4000 - 50

The CPU11 implements the constant and the offset as separate MUL(32)/ADD(30) operations. Higher-end CQM1 CPUs (CPU41/42/43/44) and the CJ/CP/NJ families can perform the same conversion in floating-point or in a single SCL(66) instruction, but the integer math approach shown here works on every CPU from CPU11 upward.

Why SCL(66) Fails on the CQM1-CPU11

SCL(66) is a four-operand instruction that performs the linear conversion in a single rung. The form is:

SCL(66)  S  P1  P2  R

where S is the source raw value, P1 is the first parameter word (BCD with implied decimal), P2 is the second parameter word (BCD slope), and R is the result. On higher CQM1 CPUs and on the CJ1/CS1/NJ/NX families this is the recommended approach. On the CPU11, three failure modes appear in the field:

  1. CX-Programmer reports the instruction as not supported. Some CX-Programmer builds (especially older V2.x and V3.x) do not list SCL(66) in the instruction tree for the CPU11 device profile. The ladder accepts the instruction when entered manually, but the controller's firmware rejects it at runtime with the ALARM indicator flashing and a non-fatal error in the error log.
  2. CPU11 firmware revision does not include SCL(66). The CQM1 Programming Manual (W347) lists SCL(66) as supported across the CQM1 family, but field experience shows that some early CPU11 firmware lots shipped without the SCL function code in the expansion instruction table. The rung enters the program memory, but the result word stays at 0000 throughout operation.
  3. Result word never updates. The rung is accepted and downloaded, but the result word stays at 0000. This is typically a hand-typed rung with the parameter word order reversed, with P1 and P2 in the wrong data mode (binary vs BCD), or with an unused-but-required P3 word missing on the CPU11's variant of the instruction.

For all three failure modes, the manual MUL(32)/DIV(33) ladder in the next section produces an identical result without depending on SCL(66) expansion instruction support.

Manual Scaling Using Basic Math Instructions

The CPU11's basic instruction set includes MUL(32) for 16-bit signed multiply and DIV(33) for 16-bit signed divide. To produce a 0-100 engineering unit from a 0-4000 raw count, the minimum ladder is:

; Rung 1 - read the analog input into a working word
LD     253.13          ; Always-on flag (or P_On)
MOV(21)  IR200  DM0100

; Rung 2 - multiply by 100 (scaling factor)
MUL(32)  DM0100  #100  DM0200
  ; DM0200 = low 16 bits of (raw * 100)
  ; DM0201 = high 16 bits (always 0 for raw ≤ 4000)

; Rung 3 - divide by 4000 (raw count span)
DIV(33)  DM0200  #4000  DM0300
  ; DM0300 = quotient (engineering units, 0-100)
  ; DM0301 = remainder (discard)

; Rung 4 - move the scaled value to the destination word
MOV(21)  DM0300  DM0400

All four instructions are part of the CPU11's base arithmetic set and execute on every CQM1 CPU model. The total scan-time cost is on the order of 10-20 µs, which is negligible for a process variable that changes once per second or slower.

Watch the 32-bit boundary. MUL(32) on the CQM1 multiplies two signed 16-bit words and produces a 32-bit signed result in a destination word pair. The largest intermediate value with a 0-4000 input is 4000 * 100 = 400,000, which fits in 32 bits but would overflow a 16-bit word. Always allocate the full 32-bit destination pair (DM0200 low, DM0201 high) even though only DM0200 is fed to the DIV(33) rung. For higher engineering unit ranges, scale the constants to keep the intermediate under 32,767: e.g., for 0-1000 EU with 0-4000 raw, use (Raw * 250 / 1000) instead of (Raw * 1000 / 4000).

Complete Ladder Program with Edge-Case Handling

A production-scale ladder should clamp the input, detect an open loop (below 4 mA), detect an over-range condition (above 20 mA), and avoid passing a negative or out-of-range value downstream. The expanded program is:

; Rung 1 - read raw value from AD041 channel 1
LD     253.13
MOV(21)  IR200  DM0100

; Rung 2 - under-range / open-loop detection (raw < 0)
CMP(20)  DM0100  #0
LD       255.06         ; P_LT bit from CMP
OUT      200.00         ; Open-loop alarm flag

; Rung 3 - over-range detection (raw > 4000)
CMP(20)  DM0100  #4000
LD       255.07         ; P_GT bit from CMP
OUT      200.01         ; Over-range alarm flag

; Rung 4 - clamp raw to 0-4000
; (Replace the raw with 0 if under-range, with 4000 if over-range)
LD       200.00
ANDNOT   200.01
MOV(21)  #0  DM0100
LDNOT    200.00
AND      200.01
MOV(21)  #4000  DM0100

; Rung 5 - scale: multiply clamped raw by 100
LD       253.13
MUL(32)  DM0100  #100  DM0200

; Rung 6 - scale: divide by 4000
LD       253.13
DIV(33)  DM0200  #4000  DM0300
  ; DM0300 = engineering units 0-100

; Rung 7 - publish the scaled value with validity flag
LD       253.13
ANDNOT   200.00
ANDNOT   200.01
MOV(21)  DM0300  DM0400
OUT      100.00         ; 'Valid' status bit to HMI

; Rung 8 - safety: force output to 0 if invalid
LD       200.00
OR       200.01
MOV(21)  #0  DM0400

The pattern scales to other ranges without changing the structure. For 0-1000 EU:

MUL(32)  DM0100  #250  DM0200
DIV(33)  DM0200  #1000  DM0300

For 4-20 mA temperature scaled to -50 to +200 °C (a 250 °C span):

MUL(32)  DM0100  #250  DM0200
DIV(33)  DM0200  #4000  DM0300
ADD(30)  DM0300  #(-50 signed)  DM0300   ; offset by -50
Integer limits. The CPU11's integer range is -32,768 to +32,767. When scaling for negative engineering units (such as -50 to +200 °C), the intermediate MUL result must be kept in range. With a 0-4000 raw input and a 250 °C span, the maximum MUL result is 4000 * 250 = 1,000,000, which exceeds the 32,767 limit of a 16-bit word. Rescale to (Raw * 25 / 40) or use a 32-bit division with a smaller intermediate. The 32-bit MUL destination is always safe - the issue is when the MUL result is fed to ADD(30) or another 16-bit operation.

Edge Cases, Alarms, and Open-Wire Detection

The 4-20 mA standard has three states beyond the normal operating range:

Condition Loop current AD041 raw Engineering interpretation
Normal low (engineering zero) 4.0 mA 0 0 % of span
Normal high (engineering full) 20.0 mA 4000 100 % of span
Open loop / broken wire 0 mA negative (typically -200 to 0) Below 0 %
Over-range > 20 mA (up to 25 mA) > 4000 (up to 4095) Above 100 %
Short circuit (sensor side) > 25 mA clamped at 4095 Hard over-range

Industry guidance from NAMUR NE43 recommends treating currents below 3.6 mA and above 21.0 mA as diagnostic conditions, not process values. The CPU11 program should treat anything below raw 0 or above raw 4095 as an alarm. Two flags (one for under-range, one for over-range) plus the scaled value let the HMI display the proper status, and the SCADA system can alarm out the affected tag.

Open-wire detection on a passive transmitter (4-wire device powered separately) is straightforward: the AD041 reads a negative raw count because the input sits below the 4 mA live zero. On an active transmitter (2-wire, loop-powered), an open wire drops the current to 0 mA, again reading as a negative raw count. The CMP(20) DM0100 #0 with the P_LT bit driving an alarm catches both cases. False positives occur if the transmitter drifts slightly below 4 mA at the engineering low - the standard tolerates up to 3.6 mA as "still normal", which on a 0-4000 raw scale is about -100 counts. If the application is sensitive to this, change the threshold to CMP(20) DM0100 #(-100) to match NAMUR NE43.

Filtering, Damping, and Noise Immunity

Raw 4-20 mA signals are often noisy in plant environments, particularly with variable-frequency drives, soft starters, or ungrounded thermocouple instruments. A raw count jittering +/- 50 counts around 2000 produces a EU jitter of +/- 1.25 - significant on a 0-100 scale. Two complementary approaches suppress this noise:

Hardware filter: install a 250 Ω sense resistor at the AD041 input, shielded twisted pair from the transmitter, and ground the shield at the panel end only. This is the first line of defense and resolves 90 % of noise issues without software changes.

Software exponential filter: apply a first-order lag in the ladder using a SFT (shift register) and a scaling factor. A common form is:

; Exponential filter:  Y_new = (1 - alpha) × Y_old + alpha × X_new
; For alpha = 0.25 (1/4), use shift-right by 2 bits:
MOV(21)  DM0400  DM0500      ; Y_old (previous output)
MUL(32)  DM0500  #3  DM0510   ; Y_old * (1 - 1/4) = Y_old * 3
MUL(32)  DM0300  #1  DM0520   ; X_new * (1/4)  (precomputed for 0-100 / 4)
ADD(30)  DM0510  DM0520  DM0530
DIV(33)  DM0530  #4  DM0540   ; final filtered value
MOV(21)  DM0540  DM0400       ; publish as new Y_old

For a stronger filter (alpha = 0.1, 1/10), change the constants to 9/1 and the divisor to 10. A weaker filter (alpha = 0.5) uses 1/1 with divisor 2. A complete deadband filter (hold last good value if the new value is within ± 2 EU) is sometimes added on top of the exponential filter for slow-changing measurements like tank level.

The CPU11's integer math introduces a small quantization error in the filtered output (typically ± 1 EU on a 0-100 scale). For most process-control applications this is acceptable. If a tighter output is required, scale the filter math by 10 (treat DM0400 as 0-1000 internally) and display with one decimal place in the HMI.

Verification Procedure

Validate the scaling ladder with a current calibrator and CX-Programmer's online tools:

  1. Disconnect the field wiring from the AD041 input terminal block. Connect a mA calibrator (Beamex MC5, Fluke 754, or equivalent) in series with the input, with the calibrator driving 4-20 mA into the AD041 channel.
  2. Go online in CX-Programmer (PLC > Work Online) and open a Watch window on DM0100 (raw), DM0200 (raw × 100), DM0300 (quotient), and DM0400 (final output). Also monitor CIO 200.00 and CIO 200.01 (alarm flags) and CIO 100.00 (valid flag).
  3. Force 4.00 mA. Verify DM0100 reads 0 (± 2 counts), DM0400 reads 0, and CIO 200.00 / 200.01 are both off.
  4. Force 8.00 mA. Verify DM0100 reads 1000 (± 2 counts) and DM0400 reads 25.
  5. Force 12.00 mA. Verify DM0100 reads 2000 (± 2 counts) and DM0400 reads 50.
  6. Force 16.00 mA. Verify DM0100 reads 3000 (± 2 counts) and DM0400 reads 75.
  7. Force 20.00 mA. Verify DM0100 reads 4000 (± 2 counts) and DM0400 reads 100.
  8. Force 2.00 mA (below 4 mA). Verify DM0100 reads negative, CIO 200.00 (open-loop alarm) is on, and DM0400 reads 0 (safety clamp).
  9. Force 22.00 mA (above 20 mA). Verify CIO 200.01 (over-range alarm) is on and DM0400 reads 100 (clamped).
  10. Force 4.00 mA again and let the filter settle for 30 s. Verify the final DM0400 reading is within ± 1 EU of the expected value.

Tolerate ± 2 raw counts on every step; that is the AD041's 1/4000 resolution tolerance plus the calibrator's typical ± 0.05 % accuracy. If the readback is off by a full 1 % or more, check that the analog module is configured for 4-20 mA (not 0-10 V) at the side DIP switch on the unit.

Troubleshooting Matrix

Symptom Likely cause Corrective action
SCL(66) flagged "not valid" in CX-Programmer CX-Programmer version or CPU11 device profile does not list SCL(66) Switch to the manual MUL(32)/DIV(33) ladder in this article; works on every firmware
SCL(66) rung accepted but result word stays at 0 Parameter word order or BCD/binary mode flag is wrong Verify P1 and P2 are in 4-digit BCD with 3 implied decimal places, and the result word R is in BCD
Result is always 0 or always 100 Source word IR 200 is reading the wrong channel or the wrong module Upload the I/O table from PLC and update the IR address in the ladder
Result is exactly 50 % low across the entire span Module is configured for 0-10 V but the loop is 4-20 mA Reset the AD041 DIP switches / rotary switch for 4-20 mA input
Result jitters ± 5 EU or more Electrical noise on the 4-20 mA loop or no shielding Use shielded twisted pair, ground shield at the panel end only, add the exponential filter in this article
Result reads 0 but the loop is healthy Open input terminal on the module or loose ferrule Re-torque the screw terminal, check the wire ferrule, verify the loop is complete end-to-end
Result is consistently negative Open loop, reversed polarity, or a transmitter wired backwards Verify transmitter polarity (loop+ to AD041 I+, loop- to AD041 I-), check the loop is complete with a mA clamp meter
Result maxes at 4095 raw and never settles Short circuit in the field loop or transmitter failure Disconnect the loop at the transmitter terminals and re-test; replace the transmitter if short persists
DM0300 is correct but DM0400 stays at 0 MOV from DM0300 missing or executed inside a non-firing conditional branch Add the MOV(21) rung unconditionally, not inside a conditional branch
DM0400 changes but HMI does not update HMI tag pointer is set to the wrong DM word or the HMI poll cycle is too slow Verify the HMI tag address matches DM0400; reduce the HMI scan/poll interval
Reading drifts upward or downward continuously with a fixed input Integration of noise on a slowly-changing measurement; filter is too weak Reduce the filter alpha to 0.1 (1/10) for stronger damping; add a deadband of ± 2 EU

Cross-Platform Scaling Reference and Migration

The manual math approach used here is the same operation implemented in expansion instructions on higher-end controllers. On Siemens SIMATIC S7-1200/S7-1500 systems, the SCALE and NORM_X function blocks in TIA Portal perform the identical linear conversion with explicit upper and lower limits for both the input and output ranges. The conceptual map between the two platforms is:

Omron CQM1 (manual math) Siemens TIA Portal SCALE
Source raw word (IR 200) VALUE input (raw integer)
Multiplier constant (#100) LO_LIM / HI_LIM of output range (engineering high)
Divisor constant (#4000) LO_LIM / HI_LIM of input range (raw high)
Result word (DM 0400) OUT (scaled real)
CMP + flag bit ladder Status outputs of NORM_X

The implementation language differs (ladder on CQM1, SCL/CFC/FBD on S7) but the underlying math is the same linear scale. The CQM1 manual ladder is the minimum-firmware solution; the SCL(66) instruction is the higher-CPU solution; the TIA Portal SCALE block is the modern-platform equivalent.

When migrating a CQM1-CPU11 system to a CP1E, CP1L, or CJ2 CPU, the same integer math approach can be carried over directly, and the CJ2/CP1L additionally offer a hardware SCL2 instruction that handles non-zero offsets and bipolar ranges natively. On the NJ/NX series with full floating-point support, the scaling is performed in real numbers with no integer-boundary concerns. The 4-20 mA loop wiring, the AD041 scaling constants, and the edge-case detection logic remain the same across the migration - only the ladder implementation changes.

Frequently Asked Questions

Why does SCL(66) show as "not valid" on my CQM1-CPU11?

CX-Programmer version mismatches, early CPU11 firmware lots, or a manually entered rung that the controller does not recognize at runtime. The manual MUL(32)/DIV(33) ladder in this article works on every CQM1 firmware revision and produces the same 0-100 EU output.

Can the same ladder handle a 0-10 V input on a CQM1-AD042?

Yes, with two changes. The AD042 returns a signed raw count from -2000 to +2000 for ±10 V, or 0-4000 for 0-10 V. Use SBN(89) to sign-extend the word, then apply EU = Raw × 100 / 4000 (for 0-10 V) or EU = (Raw + 2000) × 100 / 4000 (for ±10 V centered at 0).

What if my raw count is 0-8000 instead of 0-4000?

Change the divisor in the DIV(33) rung from #4000 to #8000. The CQM1-AD081 and some third-party analog modules return a 0-8000 raw range for 4-20 mA, in which case EU = Raw × 100 / 8000. The rest of the ladder is unchanged.

How do I detect a broken 4-20 mA loop?

On a healthy AD041, raw counts never go below 0. If the field wiring opens, the raw count goes negative (typically -200 to -500). Add a CMP(20) DM0100 #0 with the P_LT bit driving an alarm flag. Treat any negative raw as an open-loop diagnostic per NAMUR NE43; a 3.6 mA threshold (raw ≈ -100) is the industry-standard cutoff.

Does the CQM1-CPU11 support floating-point math?

No. The CPU11 is integer-only. Use fixed-point integer math with the MUL(32)/DIV(33) approach and scale the constants to keep the intermediate within the 16-bit signed range of -32,768 to +32,767. For example, to display 0.0-100.0 with one decimal place, scale internally by 10 and divide by 40000, then display with the decimal in the HMI tag formatting.

Back to blog