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.
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
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:
- Issuing a new TO command while a previous one is still active.
- Issuing a command that the TO cannot accept in its current state (for example, calling
_synchronizeexternalencoderwhen the TO is not in Synchronized or Homed state). - Re-issuing a single-shot command from a fast task (IPO, IPO2, Servo) faster than the TO can acknowledge.
- Issuing a command while the TO is in ErrorStop state - every command returns H20 until an
_resetAxisor_resetExternalEncoderclears 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;
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
- Open SIMOTION SCOUT and connect to the target D435.
- Go online with the affected axis or external encoder TO.
- Open the Diagnostics tab of the TO and watch the error response in real time.
- Note the exact values of
Encoder.error,Encoder.errorGroup, andEncoder.errorNumberat the moment of the trip. - 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
- Locate the program that calls
_synchronizeexternalencoder(or any wrapping FB). - Identify the task in which it runs: Servo, IPO, IPO2, Background, or a user task.
- Confirm that the call is edge-triggered and protected by a one-shot flag.
- 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
- After the code change, download to the D435 and run the machine through a full production cycle that previously triggered the fault.
- 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). - 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.
- Force a manual error and verify that
_resetExternalEncoderclears the TO and that subsequent commands execute without H20. - Run a 24-hour soak test under production load, and verify
Encoder.errorGroupremains 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-reasondetail 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.