Troubleshooting External Encoder Error 16#20 on SIMOTION D435

David Krause15 min read
Motion ControlSiemensTroubleshooting
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

Troubleshooting External Encoder Error 16#20 on SIMOTION D435 with SMC30

An intermittently tripped Encoder.error = TRUE flag with Encoder.errorGroup = 16#20 on a SIMOTION D435 controller reading a TTL incremental encoder through a SINAMICS SMC30 sensor module is almost always symptomatic of a command-state conflict on the external-encoder technology object (TO). The 16#20 value is not a free-form status code; it is a direct window into the technology-object alarm buffer, and the H20 alarm class that follows it (Command Aborted) is generated whenever the TO is forced to terminate a running command. In most field cases the aborting trigger is the application program re-issuing _synchronizeexternalencoder on a cycle faster than the TO can complete or acknowledge it, or against a TO that is not in a state that permits synchronization.

1. Problem Statement and Symptom Summary

On the affected axis/encoder, the following TO structure fields are observed:

TO Tag Observed Value Meaning
Encoder.error TRUE / YES Technology object is in an error state
Encoder.errorGroup 16#20 (decimal 32) Alarm class identifier (H20 = Command Aborted)
Encoder.errorNumber 50005..50012 range Specific alarm number, see alarm buffer
Alarm code in Scout H20 Command aborted, command-state conflict

Critically, the alarm does not appear in Scout's alarm window. This is a strong indication that the abort is generated by a TO-internal state change rather than a drive-side fault, and it shifts the investigation away from the SMC30 wiring and toward the application program and the encoder TO configuration.

Field-proven rule: 16#20 is not a wiring or encoder-cable fault code. It is a TO command-state conflict code. Replace the encoder and re-pull the cable first, but expect the same fault to return until the application program is fixed.

2. Hardware Context: SIMOTION D435, SMC30, and TTL Encoders

2.1 SIMOTION D435 controller

The SIMOTION D435 is a SIMOTION D-series motion controller (6AU1435-...) with an integrated SINAMICS S120 drive line. It runs SIMOTION runtime with SCOUT (or TIA Portal with SIMOTION V5.x) and exposes external-encoder TOs that read position via DRIVE-CLiQ, PROFIBUS, or via a SINAMICS Sensor Module Cabinet-Mounted (SMC) on the drive side. External encoders on a D435 are typically connected through an SMC10, SMC20, or SMC30, which converts the encoder signals into drive-side position data that the SIMOTION runtime reads through the assigned drive object (DO).

2.2 SMC30 sensor module

The SMC30 (6SL3055-0AA00-5CA2 or -5CA3) is a SINAMICS Sensor Module Cabinet-Mounted that supports:

Encoder Type Signal Max Frequency Supply
TTL incremental RS422 A, /A, B, /B, N, /N 1 MHz 5 V DC, 300 mA
HTL incremental 24 V A, B, N 300 kHz 24 V DC
SSI RS422 data + clock 1 MHz 24 V DC
1 Vpp sine A, /A, B, /B, R, /R 500 kHz 5 V DC

For a TTL incremental encoder, the SMC30 must be configured (p0400 = 2) to expect RS422 line-driver signals with 5 V supply. DIP switches S1 (encoder type) and S2 (termination) on the SMC30 must be set to TTL with 120 Ω termination on the last driver in the chain. Mis-setting the encoder type causes r949 (drive-side fault) and a 16#20 will not be the result - that combination points to a different fault signature.

2.3 Topology diagram

TTL Incremental Encoder (RS422) 5 V DC, A/B/N SINAMICS SMC30 Sensor Module 6SL3055-0AA00-5CA2 SIMOTION D435 Ext. Encoder TO errorGroup = 16#20 X520 DRIVE-CLiQ Application program issues _synchronizeexternalencoder faster than TO can process => H20 alarm, 16#20 errorGroup, command aborted

3. Decoding Encoder.errorGroup = 16#20

The technology-object error response is a two-stage structure. The first stage is the alarm class (or "error group"), and the second stage is the specific alarm number. The high-level decode is:

errorGroup Class Cause Category
16#01 Configuration TO was not created correctly or configuration is inconsistent
16#02 User / Program Application called a system function with invalid parameters
16#10 Drive Drive-side fault reported via PROFIdrive
16#20 Command Aborted (H20) TO terminated a running command; the new command has invalid state or timing
16#40 Encoder Encoder hardware / signal fault
16#80 Following Error Position lag exceeded the configured limit

16#20 specifically maps to the H20 alarm class. The H20 alarm text in the technology-object alarm buffer reads (translated from the SIMOTION documentation): "Command aborted. The previously issued command was terminated because a new command was issued or the command state does not permit execution." When errorGroup = 16#20 appears, the application program is doing one of the following:

  1. Issuing a new TO command while a previous one is still active.
  2. Issuing a command that the TO cannot accept in its current state (for example, calling _synchronizeexternalencoder when the TO is not in Synchronized or Homed state).
  3. Re-issuing a single-shot command from a fast task (IPO, IPO2, Servo) faster than the TO can acknowledge.
  4. Issuing a command while the TO is in ErrorStop state - every command returns H20 until an _resetAxis or _resetExternalEncoder clears the state.

4. Root Cause: The _synchronizeexternalencoder Misuse Pattern

The _synchronizeexternalencoder system function is a one-shot set-position command. It is used to force the encoder's actual position to a configured value (typically 0 or a master-encoder-relative offset) at a defined instant. The correct usage model is:

  • Call it once, from a slow background task (BackgroundTask or a user-defined 100 ms task).
  • Confirm the command-issued acknowledgment before calling it again.
  • Never call it from a Servo-fast or IPO-fast task.
  • Never call it from within a cyclically-fired condition block without a one-shot edge (rising-edge-triggered flag).

The most common misuse pattern that produces 16#20 is:

// INCORRECT: Synchronize is called every servo cycle while condition is true
IF bResetRequest AND (Encoder.state = STATE_SYNCHRONIZED) THEN
   _synchronizeexternalencoder(encoder := myExtEncoder,
                               position := 0.0,
                               mode := ABSOLUTE);
END_IF;

Even with the conditional gate, the call is repeated every cycle as long as the flag is high. The TO's internal command queue sees the second call before acknowledging the first, terminates the first with H20, and reports errorGroup = 16#20.

The correct pattern is edge-triggered and one-shot:

// CORRECT: edge-triggered, one-shot per request
bResetEdge := bResetRequest AND NOT bResetPrev;
bResetPrev := bResetRequest;

IF bResetEdge THEN
   _synchronizeexternalencoder(encoder := myExtEncoder,
                               position := 0.0,
                               mode := ABSOLUTE);
END_IF;
Why Scout does not show an alarm: the H20 abort is generated by the TO command-processing layer, not the alarm-event layer. It is reported through Encoder.error and Encoder.errorGroup but does not write to the project-wide alarm buffer that the alarm window subscribes to. Look in the TO's Diagnostic tab in SCOUT under Alarm History rather than the global alarm window.

5. Required Command Set for an External Encoder

For a passive external encoder (one that is not being controlled as a stand-alone axis), the supported command set is intentionally small. The typical lifecycle commands are:

System Function Purpose When to Use
_enableexternalencoder Activates the encoder TO and starts position acquisition After power-up or a reset
_disableexternalencoder Deactivates the encoder TO Before service, before commanded stop
_resetExternalEncoder Clears errors and returns to a base state After error acknowledgment
_setExternalEncoderHomePosition Defines the home (zero) value of the encoder One-time at commissioning
_synchronizeexternalencoder Forces the encoder position to a specified value Rarely, only at defined events
_homeExternalEncoder Executes the homing sequence defined in the TO At machine start-up, after a controlled reference

set_master is not a valid external-encoder command in the standard SIMOTION command vocabulary. If the application logic is calling a function named set_master on an external encoder, it is either a user-defined FB (Function Block) wrapping _synchronizeexternalencoder or a wrong namespace call. In either case, the call chain should be re-examined for the burst-fire pattern.

6. Diagnostic Procedure in SCOUT and SINAMICS

Follow the steps in this order. Each step produces a specific data point that determines whether the fault is in the application program (most likely), the TO configuration, or the drive/encoder hardware.

6.1 Capture the live error context

  1. Open SIMOTION SCOUT and connect to the target D435.
  2. Go online with the affected axis or external encoder TO.
  3. Open the Diagnostics tab of the TO and watch the error response in real time.
  4. Note the exact values of Encoder.error, Encoder.errorGroup, and Encoder.errorNumber at the moment of the trip.
  5. Open Alarm History on the TO (not the project-wide alarm window) and scroll back to the trip instant.

6.2 Evaluate the StatusWord bits

The external-encoder TO exposes a StatusWord tag whose bit layout is documented in the TIA Portal help for S7-1500/S7-1500T external encoders and applies analogously to the SIMOTION external-encoder TO structure. Use the StatusWord tag documentation for external encoders (S7-1500/S7-1500T) to interpret the bit-level state. Key bits to verify:

Bit Name Interpretation
0 Enable TO is enabled
1 RestartActive Restart is in progress - commands will be aborted
2 HomingDone Encoder has been homed; _synchronizeexternalencoder permitted
3 Synchronized Encoder is in the synchronized state
5 HomingCommand A homing command is currently active
7 Error TO is in error state; no commands will execute until reset

Inspect the StatusWord in the trace at the moment the H20 fires. If bit 7 is set before the abort, the TO was already in an error state - the abort is a secondary symptom, not the cause.

6.3 Inspect the SINAMICS side

The SMC30 reports its own status into the SINAMICS drive object. The relevant parameters are:

Parameter Meaning
r0451 Encoder 1 fine resolution
r0461 Encoder 1 actual value
r0480 Encoder 1 status word (Gn_STW)
r2122 Fault code, drive-side
r2124 Alarm code, drive-side
r945 / r947 / r949 Encoder fault bits (r949 bit 0 = initialization, bit 1 = level, bit 2 = zero pulse, etc.)

Read these via the SINAMICS drive navigator in SCOUT (drive unit -> Commissioning -> Diagnostic). If r949 has bits set, the SMC30 has a real signal-level fault. In that case the errorGroup is more likely 16#40 (Encoder) and the H20 is a side effect. In the reported symptom, r949 should be clean.

6.4 Review the application task scheduling

  1. Locate the program that calls _synchronizeexternalencoder (or any wrapping FB).
  2. Identify the task in which it runs: Servo, IPO, IPO2, Background, or a user task.
  3. Confirm that the call is edge-triggered and protected by a one-shot flag.
  4. Search the project for any additional callers of the same function on the same encoder TO - in multi-developer projects, the burst-fire often comes from a second developer who added "fallback" logic.

7. SMC30 Wiring and Configuration Verification

Even though the symptom points to a command-state issue, the wiring must be confirmed so that 16#20 is correctly diagnosed and not confounded with a marginal signal that intermittently falls below threshold. A marginal signal that intermittently fails to read produces 16#40, but a noise burst can also corrupt a TO command handshake and produce 16#20 - especially right after the encoder is re-enabled.

7.1 Hardware checklist

  • Encoder supply is 5 V DC, sourced from SMC30 X520 pins 1 and 2; verify with a scope at the encoder, not at the SMC30 terminal.
  • A, /A, B, /B, N, /N pairs are on X520 pins 3..14; verify each pair with a differential probe.
  • Shield is grounded at one end only (cabinet entry).
  • Encoder cable is twisted-pair shielded, 24 AWG minimum, length below the SMC30 TTL maximum (typically 100 m at 1 MHz; scale by frequency).
  • DIP switch S1 is set to TTL (RS422). On SMC30 -5CA2, S1 position 2 = TTL.
  • DIP switch S2 enables 120 Ω termination on the receiver pair; required when the encoder is the last/only device on the line.

7.2 Drive-side parameter verification

Confirm the encoder configuration parameters on the SINAMICS drive object that owns the SMC30:

Parameter Recommended Value (TTL incremental) Meaning
p0400 2 (Encoder type = TTL) Defines the connected encoder family
p0404 0 (no inversion), 1 (invert signals), or as needed Signal inversion
p0405 0 (square-wave, no error on signal loss) Signal monitoring (set to 1 if you want F3x11 on signal loss)
p0408 Enc_pulses (e.g., 2500, 5000) Encoder pulses per revolution
p0425 0 (single-turn, no commutation) Encoder mode for TTL incremental

After any change, run Copy RAM to ROM and power-cycle the drive line so the new parameters take effect on cold start.

8. Fix: Command Sequencing and Edge Discipline

8.1 One-shot pattern for synchronize

Replace any direct call to _synchronizeexternalencoder in a cyclic task with an edge-triggered one-shot. A canonical, production-safe pattern in Structured Text (ST) is:

// One-shot on rising edge of bSyncRequest
bSyncReqEdge := bSyncRequest AND NOT bSyncReqPrev;
bSyncReqPrev := bSyncRequest;

IF bSyncReqEdge
   AND (myExtEncoder.state = STATE_SYNCHRONIZED OR
        myExtEncoder.state = STATE_HOMED)
   AND NOT myExtEncoder.error THEN
   _synchronizeexternalencoder(encoder := myExtEncoder,
                               position := lrSyncPosition,
                               mode := ABSOLUTE);
END_IF;

8.2 Allow the TO to acknowledge

The SIMOTION TO command processing is asynchronous to the application task. The command-issued acknowledgment bit (returned in the command-issued output of the function block instance, when used as a system-function-instance form) must be confirmed before issuing another command. Add a minimum dwell of one BackgroundTask cycle (typically 10-100 ms) after a synchronize before any other TO command is permitted.

8.3 Use the right command for the job

If the application intent is to re-zero the encoder at a defined machine event (for example, after a part fixture is detected), use _homeExternalEncoder with mode Passive homing triggered by a probe. This is the standard homing path and is designed for cyclic re-trigger; _synchronizeexternalencoder is reserved for rare re-anchoring events.

8.4 State-gate every command

Before calling any command on the external encoder TO, gate the call on the current state. Reject the call if the TO is in ErrorStop, RestartActive, or CommandAborted. Log the rejected call in a counter for diagnostics.

9. Verification Steps

  1. After the code change, download to the D435 and run the machine through a full production cycle that previously triggered the fault.
  2. In SCOUT, add a watch window on the encoder TO with the following tags: Encoder.error, Encoder.errorGroup, Encoder.errorNumber, Encoder.state, Encoder.StatusWord (mapped from the equivalent status word on the SIMOTION TO).
  3. Record a trace on the calling task that includes the request flag, the one-shot edge flag, and the encoder state - confirm the one-shot pattern is firing exactly once per request.
  4. Force a manual error and verify that _resetExternalEncoder clears the TO and that subsequent commands execute without H20.
  5. Run a 24-hour soak test under production load, and verify Encoder.errorGroup remains at 0 throughout.

10. Troubleshooting Matrix

Symptom Likely errorGroup First Check
One-shot synchronize trips once at machine start, then never again 16#20 Confirm the one-shot flag is consumed correctly
errorGroup = 16#20 every few seconds during normal run 16#20 Application is calling _synchronizeexternalencoder cyclically
errorGroup = 16#20 immediately after a restart 16#20 Reset is being called while a synchronize is still in flight; sequence the reset first
errorGroup = 16#20 with H20 message in global alarm window 16#20 Another axis/TO is issuing commands on the shared encoder; check for multi-instance sharing
errorGroup = 16#40 with r949 bit 0/1/2 set 16#40 Encoder signal fault, not a command-state issue; check SMC30 wiring and p0405
errorGroup = 16#10 with drive fault F3x11 16#10 Encoder cable broken or shield ground loop; check SMC30 wiring
errorGroup = 16#80 during motion 16#80 Position following error; mechanical or tuning problem, unrelated to this code

11. Edge Cases and Caveats

  • Remote diagnostics ambiguity: the original report is from a service technician on site feeding information back to engineering. If the technician reports that "there are no alarms in Scout," the global alarm window is being checked, not the TO-specific alarm history. This is a common misinterpretation that leads to long investigations.
  • Multi-axis sharing: a single external encoder can be referenced by multiple axis TOs (for example, as a master encoder for an electronic gear). If any of those axes issues a command that conflicts, the encoder TO can return H20 even when no command is issued directly against it. Check whether the encoder is shared and audit all referring axis programs.
  • Servo vs. IPO vs. IPO2: issuing even an edge-triggered command from the Servo task is risky. A 1 ms cycle that misses an acknowledgment can still produce 16#20 because of timing jitter. Always issue external-encoder commands from a background or user task with a 10-100 ms cycle.
  • Warm restart during synchronize: if a warm restart (NcAction 8) is issued while a synchronize is in flight, the TO will terminate the synchronize with H20. Sequence the restart to occur only when the encoder state is Standstill or Synchronized, not in transition.
  • Firmware versions: the exact H20 alarm text and the errorGroup mapping are stable from SIMOTION V4.4 onward. On V5.4 and later the same behavior is preserved with the addition of the command-aborted-reason detail in the alarm history - use it where available to confirm the abort reason.

12. Related Diagnostics on the S7-1500/S7-1500T Platform

For projects that are migrating from SIMOTION to the S7-1500/S7-150T platform, the equivalent external-encoder technology object exposes a StatusWord tag whose bits carry the same semantics as the SIMOTION TO status word. Use the official documentation for the StatusWord tag of the external-encoder technology object (S7-1500/S7-1500T) to interpret the bits in the same way: bit 5 (HomingDone), bit 7 (Error), and the rest of the state map. The same edge-triggered, one-shot, state-gated command pattern applies to the S7-1500T version of _synchronizeExternalEncoder.

13. FAQ

What does Encoder.errorGroup = 16#20 mean on a SIMOTION D435?

16#20 (decimal 32) is the H20 alarm class, "Command Aborted". It means the technology object terminated a running command because a new command was issued too quickly, the TO was in a state that did not permit the command, or the TO was already in an error state. It is a command-state conflict, not a wiring or signal fault.

Why does 16#20 not appear in Scout's global alarm window?

The H20 abort is generated by the TO's command-processing layer, which reports through the TO's error and errorGroup tags and writes to the TO-specific Alarm History, not the project-wide alarm window. Open the TO's Diagnostics tab and check the per-TO alarm history.

Is the error caused by the TTL encoder or the SMC30 wiring?

Usually no. 16#20 is not a signal-level fault code; signal-level faults map to 16#40 (Encoder) and produce SINAMICS r949 bits. If r949 is clean, the encoder wiring and SMC30 configuration are not the cause. Replace the encoder and re-pull the cable only after the application program has been audited.

How do I prevent the H20 abort from _synchronizeexternalencoder?

Issue the call from a background or user task (10-100 ms), edge-trigger it with a one-shot flag, gate it on the TO state being Synchronized or Homed, wait for the command-issued acknowledgment before calling again, and consider using _homeExternalEncoder with passive homing if the synchronize is being used as a recurring reference.

Can the external encoder be shared by multiple axis TOs without triggering 16#20?

Yes, but every axis that references the encoder must follow the same edge-triggered, state-gated discipline. If any axis issues a command against the shared encoder out of turn, the encoder TO can return H20 to all referring axes. Audit the calling code in every axis that references the encoder, not just the one reporting the fault.

Back to blog