TMC2209 with Encoder Feedback: What the Driver Does and What Firmware Must Do
Search for "TMC2209 closed loop" and you will find tutorials, forum threads, and product listings that make it sound like the TMC2209 is a closed-loop stepper driver. It is not.
The TMC2209 is a microstepping motor driver. It handles current regulation, chopper control, and smooth step interpolation. It has zero encoder input pins, zero position comparison logic, and zero ability to close a position loop on its own.
Closed-loop control — the ability to measure actual shaft angle and correct for position error — lives entirely in firmware running on an external microcontroller paired with a rotary encoder. The TMC2209 just executes the step pulses it is told to.
This article clarifies exactly what the TMC2209 does, what it does not do, how closed-loop control actually works with this driver, and what a complete firmware stack looks like in practice (using Grafito CANStepper's ESP32-C3 stack as a concrete example).
1. What the TMC2209 Does
The TMC2209 is an excellent stepper driver. It is worth understanding its feature set precisely, because the features that make it a good choice for closed-loop systems are not closed-loop features — they are drive-quality features.
Microstepping up to 1/256
The TMC2209 supports microstepping from full-step down to 1/256 through its internal MicroPlyer™ interpolation. At 1/256 microstepping on a standard 200-step/rev motor, each microstep is ~0.007° — far finer than any encoder you will reasonably pair with it. This smooth step resolution is what enables the firmware PID loop to make fine corrections without audible step quantization.
StealthChop2™
StealthChop2 is Trinamic's voltage-chopper mode for silent operation at low to medium speeds. Instead of hard PWM switching, it modulates coil current with a spread-cycle approach that eliminates the audible whine typical of chopper drivers. In a closed-loop system, this means the motor runs quietly during position-hold corrections — important for lab automation, camera gimbals, and noise-sensitive environments.
StallGuard4™
StallGuard4 measures back-EMF to estimate motor load without an external sensor. It can detect a stall (blocked rotor) and signal it via the DIAG pin. This is sensorless load detection, not position feedback. It cannot tell you where the shaft is — only that the load has exceeded a configurable threshold.
Key distinction: StallGuard4 does not measure position. It detects load change. Many people confuse this with closed-loop position control. It is not.
UART Configuration
The TMC2209 exposes a single-wire UART interface for runtime configuration. You can change:
- Run / hold current
- Microstep resolution
- StealthChop vs. SpreadCycle mode
- StallGuard threshold
- TOFF, hysteresis, and other chopper parameters
This is critical for closed-loop firmware: the MCU can reconfigure driver parameters on the fly without resetting the motor or power-cycling. For example, dropping IHOLD when the PID error is near zero reduces motor heating during position hold.
Current Regulation
The TMC2209 is, at its core, a constant-current chopper driver. Its job is to regulate the current through the two motor coils so that each microstep produces the correct magnetic field vector. It does this with fast decay control and adaptive blanking time. This regulation loop runs entirely inside the driver IC — at the coil level, not the position level.
2. What the TMC2209 Does NOT Do
This section is the entire reason this article exists. The TMC2209 has none of the following:
| Capability | Present in TMC2209? | What would be needed |
|---|---|---|
| Encoder input (ABI, SSI, SPI, I²C) | ❌ No | Dedicated encoder interface pins |
| Position comparison (commanded vs actual) | ❌ No | A register comparing setpoint to encoder angle |
| Closed-loop position correction | ❌ No | PID or other control law in silicon |
| PID controller | ❌ No | On-chip control loop logic |
| Trajectory planning (accel/decel ramps) | ❌ No | Velocity profile generator |
| Step pulse generation | ❌ No (consumes, not generates) | Timer-based pulse train output |
| Multi-axis coordination | ❌ No | Cross-axis synchronization |
The TMC2209 is a step/direction consumer. It receives STEP pulses and a DIR signal, and it energizes the motor coils to advance the rotor by one microstep per pulse. That is its entire function.
Everything else — reading the encoder, comparing actual angle to target, running a PID loop, computing velocity profiles, and generating the STEP/DIR pulse train — is the firmware's job.
3. How Closed-Loop Actually Works with TMC2209
Here is the real control flow in a closed-loop stepper system built around a TMC2209:
Encoder (MT6701) ──SSI──▶ ESP32-C3 ──PID loop──▶ STEP/DIR pulses ──▶ TMC2209 ──▶ NEMA 17 Motor
▲ │
│ │
└─────────────── feedback path ──────────────────────┘
(encoder angle is the feedback signal)
Step-by-step, at 200 Hz
-
Encoder read: Firmware reads the MT6701 magnetic encoder over SSI (Serial Synchronous Interface) at ~200 Hz. The MT6701 provides 14-bit raw angle (~0.022° resolution).
-
Position comparison: Firmware subtracts the current encoder angle from the commanded setpoint to compute the position error.
-
PID computation: A PID controller (proportional + integral + derivative) converts the position error into a step-rate command. The proportional term handles immediate error, the integral term eliminates steady-state offset, and the derivative term damps overshoot.
-
Trajectory limiting: Before sending steps, the firmware clamps the commanded velocity to acceleration/deceleration limits defined by the trapezoidal planner. This prevents step-rate jumps that would cause the motor to stall.
-
Step pulse generation: Firmware configures a hardware timer to generate STEP pulses at the computed rate, with the DIR pin set accordingly. The TMC2209 receives these pulses and energizes the coils.
-
Loop repeats: At the next 200 Hz tick, the encoder is read again, and the loop corrects any remaining error.
The TMC2209 never sees the encoder data. It never knows the actual shaft position. It never knows there is an error. It blindly executes whatever STEP/DIR pulses arrive on its input pins.
4. Real Firmware Stack: CANStepper (ESP32-C3)
To make this concrete, here is the actual firmware architecture running on Grafito's CANStepper — a production closed-loop NEMA 17 adapter that pairs a TMC2209 with an MT6701 encoder:
| Layer | Technology | Role |
|---|---|---|
| MCU | ESP32-C3 (RISC-V, 160 MHz) | Hosts all control logic |
| RTOS | FreeRTOS | Task scheduling: PID loop, CAN comms, UART config |
| Encoder interface | SSI (bit-banged GPIO) | Reads MT6701 at 200 Hz |
| PID controller | C implementation, 200 Hz tick | Position → step-rate conversion |
| Trajectory planner | Trapezoidal velocity profile | Acceleration / cruise / deceleration phases |
| Step generator | ESP32 RMT (Remote Control Transceiver) | Hardware-precise STEP/DIR pulse train |
| Driver interface | TMC2209 UART (single-wire) | Runtime current, microstep, mode changes |
| Host protocol | GCSP v1 over CAN Bus | Position commands, status, telemetry at up to 1 Mbps |
| Multi-axis | CAN daisy-chain (up to 31 nodes) | One CAN pair for the whole machine |
Why FreeRTOS matters
The PID loop runs as a high-priority FreeRTOS task at a fixed 200 Hz tick. CAN message handling runs in a separate task. UART configuration runs on demand. This separation ensures the control loop is never starved by communication overhead.
Why 200 Hz?
200 Hz (5 ms loop period) is a sweet spot for stepper closed-loop control:
- Fast enough to catch missed steps before they accumulate into mechanical error
- Slow enough to run comfortably on a 160 MHz RISC-V core alongside FreeRTOS and CAN
- The MT6701 encoder updates at up to 55 kHz — the bottleneck is the control computation, not the sensor
5. Why This Distinction Matters
People search for "TMC2209 closed loop" expecting to find a driver that does closed-loop control. They buy a TMC2209 breakout board, wire it to a stepper, and discover... nothing. No encoder port. No position feedback. No closed-loop.
The confusion has real consequences:
- Wasted hardware purchases: Buying TMC2209 boards expecting plug-and-play closed-loop
- Incomplete designs: Assuming the driver handles position error, skipping the encoder and firmware entirely
- Misleading product marketing: Some vendors list "TMC2209 closed-loop stepper driver kit" when the kit is really TMC2209 + separate MCU + encoder — the driver itself is unchanged
The correct framing is: "TMC2209-based closed-loop system" or "closed-loop stepper with TMC2209 driver" — never "TMC2209 closed-loop driver."
6. Other Approaches: What Truly Does On-Chip Closed-Loop?
If you want a single IC that actually closes the position loop in hardware, Trinamic makes one: the TMC4361A.
TMC4361A — Trinamic's Closed-Loop Motion Controller
| Feature | TMC2209 | TMC4361A |
|---|---|---|
| Purpose | Stepper driver (coil current) | Motion controller + closed-loop |
| Encoder input | ❌ None | ✅ ABN, SSI, SPI, BiSS, EnDat |
| PID position loop | ❌ No | ✅ On-chip, configurable gains |
| Trajectory planner | ❌ No | ✅ S-curve and trapezoidal |
| STEP/DIR output | ❌ (consumes) | ✅ (generates for external driver) |
| Interface | UART (config only) | SPI + STEP/DIR output |
| Pair with | External MCU for closed-loop | External driver (TMC2130, TMC5160, etc.) |
The TMC4361A reads an encoder, runs a PID loop, generates STEP/DIR pulses, and outputs them to a separate driver IC. It is the closest thing to a "closed-loop stepper driver on a chip" — but it still needs an external motor driver.
External MCU Approach (CANStepper, MKS SERVO42C, etc.)
The alternative — and the architecture most hobbyist and prosumer closed-loop boards use — is a general-purpose MCU running firmware that:
- Reads the encoder
- Runs the control loop
- Drives the TMC2209 over STEP/DIR
This is cheaper, more flexible, and allows features like CAN networking, WiFi configuration, and custom protocols — things a fixed-function motion IC cannot do.
| Approach | Cost | Flexibility | Multi-axis | Development effort |
|---|---|---|---|---|
| TMC4361A + driver | Higher | Low (fixed function) | SPI per axis | Low (configure registers) |
| ESP32 + TMC2209 + encoder | Lower | High (custom firmware) | CAN daisy-chain | Medium–high (write firmware) |
| Ready board (CANStepper) | Medium | Medium (configured) | CAN daisy-chain | Low (Python host library) |
7. Real-World Performance
What can you expect from a TMC2209 + MT6701 + well-tuned firmware stack? Here are measured numbers from the CANStepper platform running firmware v1.2+ on a standard 1.2 A NEMA 17 at 24 V:
| Metric | Value |
|---|---|
| Encoder resolution | 14-bit (~0.022°) |
| PID loop rate | 200 Hz |
| Settling error (static) | ≤ 0.1° |
| Closed-loop position cruise | 800 RPM |
| Open-loop continuous spin | 1,200 RPM |
| Acceleration (trapezoidal) | Configurable, tested at 5,000–50,000 steps/s² |
| Step loss recovery | Automatic — PID integral term compensates within 2–3 loop cycles |
Why 800 RPM closed-loop vs 1,200 RPM open-loop?
The 400 RPM gap is the PID loop overhead. At high speeds, the 200 Hz loop rate means fewer correction opportunities per revolution. The firmware is still tracking position, but above ~800 RPM the control bandwidth starts to limit correction authority. This is a firmware constraint, not a TMC2209 constraint — the driver itself can handle much higher step rates.
8. Practical Recommendations
If you are building a closed-loop system around a TMC2209:
-
Choose an encoder with enough resolution. 12-bit (0.088°) is workable; 14-bit (0.022°) is ideal. The MT6701 (14-bit, SSI) and AS5600 (12-bit, I²C) are common choices.
-
Match the control loop rate to your MCU. 100–200 Hz is practical on ESP32-class hardware. Faster MCUs (STM32F4, Teensy 4) can push 500–1000 Hz for higher-speed closed-loop.
-
Use the TMC2209's UART interface. Dynamically adjusting run current during position hold (drop to ~40% when error is near zero) cuts motor heating dramatically.
-
Disable StealthChop at high speeds. Above ~300 RPM, switch to SpreadCycle for better torque. The UART interface lets you flip modes mid-motion.
-
Plan your trajectory. Don't command instantaneous velocity jumps — the TMC2209 will try to execute them, and the motor will stall. Use a trapezoidal or S-curve velocity profile.
-
Consider a ready-made board. The CANStepper adapter board packages TMC2209 + MT6701 + ESP32-C3 + CAN transceiver in a NEMA 17 mountable format with pre-tuned firmware and a Python host library — skip the driver/encoder/MCU integration work.
Bottom Line
The TMC2209 is a microstepping driver with excellent current control, silent operation, and UART configurability. It has no encoder input, no position comparison, and no closed-loop control logic. It is a step executor, not a motion controller.
Closed-loop stepper control with a TMC2209 requires:
- A rotary encoder (magnetic or optical) mounted on the motor shaft
- An MCU (ESP32, STM32, etc.) running firmware that reads the encoder, computes position error, runs a PID loop, and generates STEP/DIR pulses
- Proper trajectory planning and loop-rate tuning
The TMC2209 makes an excellent driver for closed-loop systems — but it is never the thing closing the loop. That distinction matters for system design, debugging, and for anyone searching "TMC2209 closed loop" expecting the driver to do the heavy lifting.
Related reading:
- CANStepper vs MKS SERVO42C: Closed-Loop NEMA 17 Comparison
- How to Make a NEMA 17 Stepper Motor Closed Loop
- CANStepper Product Page
- CANStepper Documentation
- TMC2209 Datasheet (Trinamic)
- TMC4361A Datasheet (Trinamic)
Published by Grafito Innovations. We build closed-loop stepper hardware and firmware — including the CANStepper adapter board — so we live at the intersection of driver ICs, encoder feedback, and real-time control firmware. This distinction between "what the silicon does" and "what the firmware does" is something we debug daily.

