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 |
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:
- 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.
- 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.
- 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.
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
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:
- 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.
- 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).
- Force 4.00 mA. Verify DM0100 reads 0 (± 2 counts), DM0400 reads 0, and CIO 200.00 / 200.01 are both off.
- Force 8.00 mA. Verify DM0100 reads 1000 (± 2 counts) and DM0400 reads 25.
- Force 12.00 mA. Verify DM0100 reads 2000 (± 2 counts) and DM0400 reads 50.
- Force 16.00 mA. Verify DM0100 reads 3000 (± 2 counts) and DM0400 reads 75.
- Force 20.00 mA. Verify DM0100 reads 4000 (± 2 counts) and DM0400 reads 100.
- 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).
- Force 22.00 mA (above 20 mA). Verify CIO 200.01 (over-range alarm) is on and DM0400 reads 100 (clamped).
- 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.