Advanced Configuration
This guide covers advanced TMC51x0 (TMC5130 & TMC5160) features including CoolStep current reduction, dcStep automatic commutation, freewheeling modes, reference switches, and microstep lookup tables.
Overview
The TMC51x0 (TMC5130 & TMC5160) provides several advanced features for optimizing motor performance:
- CoolStep: Automatically reduces current when load is low
- dcStep: Automatic commutation for DC motor-like operation
- Freewheeling: Low-power modes when motor is stationary
- Reference Switches: Endstop support for homing and limits
- Microstep Lookup Tables: Custom microstep interpolation
CoolStep Current Reduction
CoolStep is an automatic smart energy optimization feature that dynamically adjusts motor current based on mechanical load, measured via StallGuard2. It can reduce power consumption by up to 75% while maintaining adequate torque reserve.
Benefits
- Energy Savings: Up to 75% power reduction when load is low
- Reduced Heat: Lower current means less heat generation
- Extended Motor Life: Cooler operation increases motor lifespan
- Cost Savings: Smaller power supplies and less cooling infrastructure needed
- Automatic Operation: No manual intervention required once configured
When to Use CoolStep
β Recommended for:
- Applications with varying load (e.g., CNC machines, 3D printers)
- Battery-powered systems (extends battery life)
- Motors that run hot under constant load
- Long-running applications (reduces cumulative power consumption)
- Applications where 30-50% torque reserve is acceptable
β Not recommended for:
- Constant high-load applications (minimal benefit)
- Applications requiring precise current control
- Systems where maximum torque must always be available
- Applications where load changes are too rapid for CoolStep to track
Prerequisites
Critical Requirements:
- SpreadCycle Mode: CoolStep requires SpreadCycle mode (
en_pwm_mode=0). StealthChop must be disabled. - StallGuard2 Tuning: CoolStep uses StallGuard2 to measure load. You must first tune StallGuard2 threshold (
sgt) for your motor. - Stable Velocity Range: CoolStep works best at constant velocities. Set velocity thresholds to match your typical operating speed.
How CoolStep Works
CoolStep operates by continuously monitoring the StallGuard2 (SG) value, which represents motor load:
- Load Measurement: StallGuard2 provides a 10-bit value (0-1023) where:
- Low SG value (0-100): High mechanical load (motor working hard)
- High SG value (500-1023): Low mechanical load (motor coasting)
- Current Adjustment:
- When SG < Lower Threshold: CoolStep increases current (load is increasing)
- When SG β₯ Upper Threshold: CoolStep decreases current (load is decreasing)
- Between Thresholds: Current remains stable (hysteresis prevents oscillation)
- Current Range: CoolStep adjusts current between:
- Maximum: IRUN (full current setting)
- Minimum: 50% or 25% of IRUN (configurable via
min_current)
- Velocity Limits: CoolStep only operates between
min_velocityandmax_velocitythresholds.
Understanding SG Thresholds
CoolStep thresholds are configured using register values (semin and semax) that map to actual StallGuard2 values:
Threshold Calculation:
- Lower threshold (SG units) =
semin * 32- Example:
semin = 2β threshold = 64 (when SG < 64, increase current)
- Example:
- Upper threshold (SG units) =
(semin + semax + 1) * 32- Example:
semin = 2,semax = 5β threshold = 256 (when SG >= 256, decrease current)
- Example:
Converting from SG Thresholds to Register Values:
- To set a lower threshold of 64 SG units:
semin = 64 / 32 = 2 - To set an upper threshold of 256 SG units with
semin = 2:semax = (256 / 32) - 2 - 1 = 5
Configuration:
Note: The library automatically converts SG thresholds to register values internally. You only need to specify the actual SG values (0-1023).
Configuration Parameters
Threshold Configuration
SEMIN (Lower Threshold Register):
- Purpose: Triggers current increase when load increases
- Range: 0-15 (0 = CoolStep disabled)
- Typical Values: 1-4 (thresholds 32-128 SG units)
- Too Low: Current increases too late, risk of stalling
- Too High: Current increases unnecessarily, reducing efficiency
SEMAX (Hysteresis Register):
- Purpose: Controls the gap between lower and upper thresholds
- Range: 0-15
- Typical Values: 3-8 (provides hysteresis gap of 96-256 SG units)
- Too Low: Current decreases too aggressively, may cause stalling
- Too High: Current never decreases, no energy savings
Hysteresis: The gap between thresholds prevents oscillation. Typical gap is 3-5 SEMAX units (96-160 SG units).
Response Speed
Increment Step (increment_step):
STEP_1: Slow, smooth response (best for slowly varying loads)STEP_2: Moderate response (recommended default)STEP_4: Fast response (for rapidly increasing loads)STEP_8: Very fast response (may cause oscillations)
Decrement Speed (decrement_speed):
EVERY_32: Slowest reduction, most stable (recommended for smooth operation)EVERY_8: Moderate reduction (recommended default)EVERY_2: Fast reduction (for rapidly decreasing loads)EVERY_1: Fastest reduction (may cause oscillations)
Rule of Thumb: Increment should be faster than decrement to prevent stalling.
Minimum Current (min_current)
HALF_IRUN(50%): Conservative, maintains more torque reserveQUARTER_IRUN(25%): Aggressive, maximum energy savings
Recommendation: Start with HALF_IRUN, switch to QUARTER_IRUN if you need more savings and can tolerate lower torque.
Filter (enable_filter)
- Enabled: StallGuard2 updates every 4 fullsteps (smoother, slower response)
- Disabled: StallGuard2 updates every fullstep (faster response, more sensitive)
Recommendation: Enable filter for smoother operation unless you need fastest response.
Velocity Thresholds
Purpose: Define the speed range where CoolStep is active.
min_velocity: CoolStep disabled below this speed
- Set to match the lowest speed where StallGuard2 gives stable readings
- Typical: 0.004-0.02 rev/s (~0.24-1.2 RPM) depending on motor
max_velocity: CoolStep disabled above this speed
- Set to match the highest speed where StallGuard2 is reliable
- Typical: 0.1-0.4 rev/s (~6-24 RPM) depending on motor
- Set equal to
min_velocityto disable CoolStep during acceleration/deceleration
Best Practice: Set thresholds to match your typical constant-velocity operating range.
Configuration Examples
Basic Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "tmc51x0.hpp"
void configureCoolStep() {
// IMPORTANT: CoolStep requires SpreadCycle mode
driver.motorControl.SetStealthChopEnabled(false);
// Configure CoolStep with user-friendly API
tmc51x0::CoolStepConfig coolstep{};
// Set thresholds using actual SG values (0-1023)
// Automatically converted to register values internally
coolstep.lower_threshold_sg = 64; // Increase current when SG < 64
coolstep.upper_threshold_sg = 256; // Decrease current when SG >= 256
// Moderate response speeds
coolstep.increment_step = tmc51x0::CoolStepIncrementStep::STEP_2;
coolstep.decrement_speed = tmc51x0::CoolStepDecrementSpeed::EVERY_8;
// Conservative minimum current
coolstep.min_current = tmc51x0::CoolStepMinCurrent::HALF_IRUN;
// Enable filter for smoother operation
coolstep.enable_filter = true;
// Set velocity thresholds (CoolStep active between these speeds)
coolstep.min_velocity = 0.01f; // Enable above 0.01 rev/s (~0.6 RPM)
coolstep.max_velocity = 0.1f; // Disable above 0.1 rev/s (~6 RPM)
coolstep.velocity_unit = tmc51x0::Unit::RevPerSec; // Recommended default
// Configure CoolStep (automatically sets velocity thresholds)
driver.motorControl.ConfigureCoolStep(coolstep);
}
Quick Setup with Helper Constructor
1
2
3
4
5
// Quick setup with common defaults
tmc51x0::CoolStepConfig coolstep(64, 256, 0.01f, 0.1f, tmc51x0::Unit::RevPerSec);
coolstep.increment_step = tmc51x0::CoolStepIncrementStep::STEP_2;
coolstep.decrement_speed = tmc51x0::CoolStepDecrementSpeed::EVERY_8;
driver.motorControl.ConfigureCoolStep(coolstep);
Aggressive Energy Savings
1
2
3
4
5
6
7
8
9
10
11
12
// Maximum energy savings configuration
tmc51x0::CoolStepConfig coolstep{};
coolstep.lower_threshold_sg = 96; // Higher threshold = more aggressive reduction
coolstep.upper_threshold_sg = 320; // Wider gap for stability (automatically calculates SEMAX)
coolstep.increment_step = tmc51x0::CoolStepIncrementStep::STEP_4; // Fast increase
coolstep.decrement_speed = tmc51x0::CoolStepDecrementSpeed::EVERY_32; // Slow decrease
coolstep.min_current = tmc51x0::CoolStepMinCurrent::QUARTER_IRUN; // 25% minimum
coolstep.enable_filter = true;
coolstep.min_velocity = 10.0f;
coolstep.max_velocity = 120.0f;
coolstep.velocity_unit = tmc51x0::Unit::RPM;
driver.motorControl.ConfigureCoolStep(coolstep);
Fast Response Configuration
1
2
3
4
5
6
7
8
9
10
11
12
// For rapidly varying loads
tmc51x0::CoolStepConfig coolstep{};
coolstep.lower_threshold_sg = 48; // Lower threshold = faster response
coolstep.upper_threshold_sg = 192; // Smaller gap = faster adjustment (automatically calculates SEMAX)
coolstep.increment_step = tmc51x0::CoolStepIncrementStep::STEP_8; // Very fast increase
coolstep.decrement_speed = tmc51x0::CoolStepDecrementSpeed::EVERY_2; // Fast decrease
coolstep.min_current = tmc51x0::CoolStepMinCurrent::HALF_IRUN;
coolstep.enable_filter = false; // Disable filter for fastest response
coolstep.min_velocity = 5.0f;
coolstep.max_velocity = 100.0f;
coolstep.velocity_unit = tmc51x0::Unit::RPM;
driver.motorControl.ConfigureCoolStep(coolstep);
Tuning Guide
Step 1: Tune StallGuard2 First
Before configuring CoolStep, tune StallGuard2 threshold for your motor:
1
2
3
4
5
6
7
8
9
// Configure StallGuard2
tmc51x0::StallGuardConfig sg_config{};
sg_config.threshold = 0; // Start with 0, adjust based on your motor
sg_config.enable_filter = true; // Enable filter for stable readings
driver.stallGuard.ConfigureStallGuard(sg_config);
// Monitor SG_RESULT during operation
uint16_t sg_value = driver.stallGuard.GetStallGuardResult().Value();
// Adjust threshold until SG_RESULT is in the middle of the range (200-600) at typical load
Step 2: Determine Operating SG Range
Monitor SG_RESULT during normal operation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Run motor at typical load and velocity
uint16_t sg_min = 1023;
uint16_t sg_max = 0;
for (int i = 0; i < 1000; i++) {
uint16_t sg = driver.stallGuard.GetStallGuardResult().Value();
sg_min = std::min(sg_min, sg);
sg_max = std::max(sg_max, sg);
vTaskDelay(pdMS_TO_TICKS(10));
}
// Use these values to calculate register thresholds
// Lower threshold: sg_min + 20% margin
// Upper threshold: sg_max - 20% margin
Step 3: Configure CoolStep Thresholds
Calculate and set register values based on your measured SG range:
1
2
3
4
5
6
7
// Calculate thresholds in SG units
uint16_t lower_sg = sg_min + (sg_max - sg_min) * 0.2; // 20% above minimum
uint16_t upper_sg = sg_max - (sg_max - sg_min) * 0.2; // 20% below maximum
// Set thresholds directly (register values calculated automatically)
coolstep.lower_threshold_sg = lower_sg; // Automatically converts to SEMIN internally
coolstep.upper_threshold_sg = upper_sg; // Automatically converts to SEMAX internally
Step 4: Test and Adjust
- If motor stalls: Lower
lower_threshold_sgor increaseincrement_step - If no energy savings: Raise
upper_threshold_sgor increasedecrement_speed - If oscillations: Increase gap between thresholds or enable filter
- If response too slow: Increase
increment_stepor decreasedecrement_speed
Best Practices
- Start Conservative: Begin with moderate settings and gradually optimize
- Monitor SG Values: Use
GetStallGuardResult()to understand your motorβs load profile - Match Velocity Range: Set velocity thresholds to your typical operating speeds
- Test Under Load: Test CoolStep under actual operating conditions
- Maintain Torque Reserve: Ensure minimum current provides adequate torque (30-50% reserve)
- Disable During Acceleration: Set
min_velocity = max_velocityto disable during accel/decel
Troubleshooting
Problem: Motor stalls when load increases
- Solution: Lower
lower_threshold_sgor increaseincrement_step
Problem: No energy savings observed
- Solution: Raise
upper_threshold_sg, check that velocity thresholds are correct
Problem: Current oscillates rapidly
- Solution: Increase gap between thresholds, enable filter, or slow down
decrement_speed
Problem: CoolStep doesnβt activate
- Solution: Check that SpreadCycle is enabled, verify velocity thresholds, ensure
semin > 0
Problem: Response too slow
- Solution: Increase
increment_step, disable filter, reducedecrement_speed
Technical Details
Register Mapping:
SEMIN(bits 3-0): Lower threshold = SEMIN Γ 32SEMAX(bits 11-8): Upper threshold = (SEMIN + SEMAX + 1) Γ 32SEUP(bits 6-5): Increment step (0=1, 1=2, 2=4, 3=8)SEDN(bits 14-13): Decrement speed (0=32, 1=8, 2=2, 3=1 measurements)SEIMIN(bit 15): Minimum current (0=50%, 1=25% of IRUN)SFILT(bit 24): Filter enable (0=every step, 1=every 4 steps)
Current Scale: CoolStep adjusts CSACTUAL register (0-31), which scales IRUN:
- CSACTUAL = 31: Full IRUN current
- CSACTUAL = 16: 50% IRUN (if SEIMIN=0)
- CSACTUAL = 8: 25% IRUN (if SEIMIN=1)
Note: CoolStep requires StallGuard2, which ONLY works in SpreadCycle mode (en_pwm_mode=0). CoolStep is automatically disabled if StealthChop is enabled.
DcStep Automatic Commutation
DcStep is an automatic commutation mode that allows the motor to run near its load limit without losing steps. When the motor becomes overloaded, it automatically slows down to a velocity where it can still drive the load, preventing stalls.
Benefits
- No Step Loss: Motor never loses steps in overload conditions
- Maximum Performance: Application works as fast as possible
- Automatic Acceleration: Highest possible acceleration automatically
- Energy Efficient: Highest energy efficiency at speed limit
- Full Torque: Uses fullstep drive for maximum motor torque
- Cost Effective: Cheaper motors can be used
When to Use DcStep
β Recommended for:
- Applications with varying mechanical load
- Applications where maximum velocity is limited by load
- Systems that need to handle overload conditions gracefully
- Applications where step loss prevention is critical
- High-torque applications requiring fullstep operation
β Not recommended for:
- High-precision positioning applications (step loss may occur)
- Applications requiring constant velocity regardless of load
- Systems where step loss is completely unacceptable
- Applications with very light, constant load
Prerequisites
Critical Requirements:
- SD_MODE: DcStep can be enabled via VDCMIN threshold (internal ramp generator) or via DCEN pin (external step/dir mode, SD_MODE=1)
- CHOPCONF Settings:
vhighfsandvhighchmmust be set to 1 (handled automatically) - TOFF Setting: Should be >2, preferably 8-15 for DcStep operation
- Microstep LUT: Default microstep lookup table must be used (phase polarity requirements)
How DcStep Works
- Load Monitoring: Continuously monitors motor load via PWM on-time measurement
- Velocity Adjustment: When overloaded, automatically reduces velocity to maintain torque
- Fullstep Operation: Operates in fullstep mode for maximum torque
- Stall Detection: Can detect stalls and stop motor if configured
Configuration Parameters
Minimum Velocity (min_velocity)
Purpose: Lower velocity threshold for DcStep activation.
- Below this velocity: Motor operates in normal microstep mode
- Above this velocity: DcStep is active
- In DcStep: Motor operates at minimum this velocity even when blocked
Setting: Set to the lowest operating velocity where DcStep gives reliable detection.
Typical Range: 0.004-0.04 rev/s (~0.24-2.4 RPM) depending on motor and application.
PWM On-Time (pwm_on_time_us)
Purpose: Controls reference pulse width for DcStep load measurement.
Effect:
- Higher value: Higher torque capability, higher velocity capability
- Lower value: Operation down to lower velocity (as set by min_velocity)
Setting: Should be set slightly above effective blank time (TBL from CHOPCONF).
Auto-calculation: If set to 0, automatically calculated from blank time (TBL + 20 clock cycles).
Typical Range: 1-10Β΅s (for 12MHz clock) or 0.5-5Β΅s (for 24MHz clock).
Blank Time Reference:
- TBL=0: 16 clock cycles (~1.33Β΅s @ 12MHz)
- TBL=1: 24 clock cycles (~2.0Β΅s @ 12MHz)
- TBL=2: 36 clock cycles (~3.0Β΅s @ 12MHz, typical)
- TBL=3: 54 clock cycles (~4.5Β΅s @ 12MHz)
Stall Detection (stall_sensitivity)
Purpose: Controls stall detection threshold in DcStep mode.
Options:
DISABLED: No stall detection (dc_sg = 0)LOW: Low sensitivity - fewer false positives (dc_sg β dc_time / 20)MODERATE: Moderate sensitivity - balanced (dc_sg β dc_time / 16, recommended)HIGH: High sensitivity - detects stalls earlier (dc_sg β dc_time / 12)
Auto-calculation: Automatically calculated from pwm_on_time_us based on sensitivity level.
Stop on Stall (stop_on_stall)
Purpose: Stop motor when stall is detected.
- If
true: Motor stops (VACTUAL = 0) when stall detected - Motor remains stopped until
RAMP_STAT.event_stop_sgflag is read
Note: Requires stall_sensitivity != DISABLED and StallGuard2 configured (TCOOLTHRS set).
Configuration Examples
Basic Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "tmc51x0.hpp"
void configureDcStep() {
// Configure DcStep with user-friendly API
tmc51x0::DcStepConfig dcstep{};
// Set minimum velocity threshold (with unit support)
dcstep.min_velocity = 0.02f; // Enable DcStep above 0.02 rev/s (~1.2 RPM)
dcstep.velocity_unit = tmc51x0::Unit::RevPerSec; // Recommended default
// Auto-calculate PWM on-time from blank time (recommended)
dcstep.pwm_on_time_us = 0.0f; // 0 = auto-calculate
// Moderate stall detection sensitivity (recommended)
dcstep.stall_sensitivity = tmc51x0::DcStepStallSensitivity::MODERATE;
// Don't stop on stall (continue operation)
dcstep.stop_on_stall = false;
// Configure DcStep
driver.motorControl.ConfigureDcStep(dcstep);
// Note: DcStep automatically sets CHOPCONF.vhighfs and CHOPCONF.vhighchm
// Note: Ensure CHOPCONF.TOFF > 2 (preferably 8-15) for DcStep operation
}
Quick Setup with Helper Constructor
1
2
3
4
// Quick setup with common defaults
tmc51x0::DcStepConfig dcstep(0.02f, tmc51x0::Unit::RevPerSec);
// Auto-calculates PWM on-time, uses MODERATE sensitivity
driver.motorControl.ConfigureDcStep(dcstep);
Custom PWM On-Time Configuration
1
2
3
4
5
6
7
8
// For applications requiring specific PWM on-time
tmc51x0::DcStepConfig dcstep{};
dcstep.min_velocity = 60.0f;
dcstep.velocity_unit = tmc51x0::Unit::RPM;
dcstep.pwm_on_time_us = 3.0f; // 3Β΅s PWM on-time (for 12MHz clock = 36 clock cycles)
dcstep.stall_sensitivity = tmc51x0::DcStepStallSensitivity::HIGH; // High sensitivity
dcstep.stop_on_stall = true; // Stop motor on stall
driver.motorControl.ConfigureDcStep(dcstep);
High-Torque Configuration
1
2
3
4
5
6
7
8
// Maximum torque capability
tmc51x0::DcStepConfig dcstep{};
dcstep.min_velocity = 120.0f; // Higher threshold = more torque headroom
dcstep.velocity_unit = tmc51x0::Unit::RPM;
dcstep.pwm_on_time_us = 5.0f; // Higher PWM on-time = higher torque capability
dcstep.stall_sensitivity = tmc51x0::DcStepStallSensitivity::LOW; // Fewer false positives
dcstep.stop_on_stall = false;
driver.motorControl.ConfigureDcStep(dcstep);
Low-Velocity Operation
1
2
3
4
5
6
7
8
// Operation down to low velocities
tmc51x0::DcStepConfig dcstep{};
dcstep.min_velocity = 30.0f; // Lower threshold = operation at lower velocities
dcstep.velocity_unit = tmc51x0::Unit::RPM;
dcstep.pwm_on_time_us = 1.5f; // Lower PWM on-time = operation at lower velocities
dcstep.stall_sensitivity = tmc51x0::DcStepStallSensitivity::MODERATE;
dcstep.stop_on_stall = true; // Stop on stall for safety
driver.motorControl.ConfigureDcStep(dcstep);
Tuning Guide
Step 1: Set Minimum Velocity
Set min_velocity to match your typical operating speed range:
1
2
3
// Monitor actual motor velocity during operation
// Set threshold to lowest speed where DcStep should be active
dcstep.min_velocity = 0.01f; // Example: Enable DcStep above 0.01 rev/s (~0.6 RPM)
Step 2: Configure PWM On-Time
Option A: Auto-calculate (Recommended)
1
dcstep.pwm_on_time_us = 0.0f; // Auto-calculates from blank time
Option B: Manual tuning
1
2
3
4
5
6
7
// Start with value slightly above blank time
// TBL=2 β 36 clocks β ~3.0Β΅s @ 12MHz
dcstep.pwm_on_time_us = 3.5f; // Slightly above blank time
// Test under load:
// - If motor stalls: Increase pwm_on_time_us
// - If no benefit: Decrease pwm_on_time_us
Step 3: Configure Stall Detection
1
2
3
4
5
6
7
// Start with MODERATE sensitivity
dcstep.stall_sensitivity = tmc51x0::DcStepStallSensitivity::MODERATE;
// Adjust based on results:
// - False positives: Use LOW sensitivity
// - Missed stalls: Use HIGH sensitivity
// - No stall detection needed: Use DISABLED
Step 4: Test and Adjust
- If motor stalls: Increase
pwm_on_time_usor increasemin_velocity - If no benefit: Decrease
pwm_on_time_usor check that load varies - If false stall detection: Decrease
stall_sensitivityor disable it - If missed stalls: Increase
stall_sensitivity
Best Practices
- Start Conservative: Begin with auto-calculated PWM on-time and moderate sensitivity
- Test Under Load: Test DcStep under actual operating conditions
- Monitor Lost Steps: Use
GetLostSteps()to monitor step loss - Match Velocity Range: Set
min_velocityto match your typical operating speeds - Optimize PWM On-Time: Tune
pwm_on_time_usfor your specific motor and load - Use Appropriate TOFF: Ensure CHOPCONF.TOFF > 2 (preferably 8-15) for DcStep
Technical Details
Register Mapping:
VDCMIN(bits 22..8): Minimum velocity threshold (lower 8 bits ignored)DC_TIME(bits 9..0): PWM on-time limit in clock cycles (0-1023)DC_SG(bits 23..16): Stall detection threshold (0-255, 0 = disabled)
Conversion Formulas:
- PWM on-time (clock cycles) =
(pwm_on_time_us * f_clk) / 1e6 - DC_SG (auto-calculated) =
DC_TIME / divisor(divisor: 20=LOW, 16=MODERATE, 12=HIGH)
Blank Time Reference (for auto-calculation):
- TBL=0: 16 clocks (~1.33Β΅s @ 12MHz)
- TBL=1: 24 clocks (~2.0Β΅s @ 12MHz)
- TBL=2: 36 clocks (~3.0Β΅s @ 12MHz, typical)
- TBL=3: 54 clocks (~4.5Β΅s @ 12MHz)
Note:
- In internal ramp mode (SD_MODE=0), DcStep can be enabled above the VDCMIN threshold.
- In external STEP/DIR mode (SD_MODE=1), DcStep is enabled via the external DCEN pin; VDCMIN does not enable DcStep in this mode.
DcStep automatically sets CHOPCONF.vhighfs and CHOPCONF.vhighchm to 1.
StallGuard2 Load Measurement
StallGuard2 provides accurate measurement of motor load and can detect stalls. Itβs used for sensorless homing, CoolStep load-adaptive current reduction, and diagnostics.
Benefits
- Load Measurement: Accurate measurement of mechanical load on motor
- Stall Detection: Detect motor stalls automatically
- Sensorless Homing: Enable homing without endstops
- CoolStep Integration: Provides load data for automatic current reduction
- Diagnostics: Monitor motor health and mechanical system condition
When to Use StallGuard2
β Recommended for:
- Sensorless homing applications
- CoolStep load-adaptive current reduction
- Motor diagnostics and monitoring
- Applications requiring stall detection
- Systems where load monitoring is beneficial
β Not recommended for:
- StealthChop mode (StallGuard2 only works in SpreadCycle)
- Very low velocities (< 1 RPS for many motors)
- Very high velocities (where back EMF approaches supply voltage)
Prerequisites
Critical Requirements:
- SpreadCycle Mode: StallGuard2 requires SpreadCycle mode (
en_pwm_mode=0). StealthChop must be disabled. - Velocity Range: StallGuard2 works best at moderate velocities (typically 1-5 RPS for smaller motors).
- Current Setting: Best results at 30-70% of nominal motor current.
How StallGuard2 Works
- Load Measurement: Continuously measures motor load via back EMF and current phase relationship
- SG_RESULT Value: Provides 10-bit value (0-1023) where:
- Low value (0-100): High mechanical load (motor working hard, near stall)
- High value (500-1023): Low mechanical load (motor coasting)
- Stall Detection: When SG_RESULT reaches zero, motor is stalled or about to stall
- Filter Option: Filter reduces measurement rate to one per electrical period (4 fullsteps) for smoother readings
Configuration Parameters
Threshold (threshold)
Purpose: Controls StallGuard2 sensitivity for stall detection and sets optimum measurement range.
Range: -64 to +63 (signed 7-bit)
Sensitivity Levels:
- Lower values (-64 to 0): Higher sensitivity (detects stalls easier, more false positives)
- Higher values (0 to +63): Lower sensitivity (requires more torque to detect stall, fewer false positives)
- Zero (0): Starting value, works with most motors (recommended starting point)
Tuning Goal: Adjust until SG_RESULT is between 0-100 at maximum load before stall.
Typical Values:
- Free-rotating motors: 0 to +20 (less sensitive, fewer false positives)
- Motors with mechanical stops: -20 to 0 (more sensitive for homing)
- High-torque applications: +10 to +30 (less sensitive)
Filter (enable_filter)
Purpose: Reduces measurement rate for smoother, more precise readings.
- Enabled: One measurement per electrical period (4 fullsteps) - smoother, compensates for motor construction variations
- Disabled: One measurement per fullstep - faster response, higher time resolution
Recommendation:
- Enable for CoolStep (smoother readings)
- Disable for sensorless homing (faster response)
Velocity Thresholds
Purpose: Define the speed range where StallGuard2 operates reliably.
min_velocity: StallGuard2 disabled below this speed
- Set to match the lowest speed where StallGuard2 gives stable readings
- Typical: 200-1000 steps/s depending on motor
- For sensorless homing: Set to match search speed
max_velocity: StallGuard2 may not operate reliably above this speed
- Set to match the highest speed where StallGuard2 is reliable
- Typical: 5000-20000 steps/s depending on motor
- Set to 0 for no upper limit
Best Practice: Set thresholds to match your typical operating velocity range.
Stop on Stall (stop_on_stall)
Purpose: Stop motor automatically when stall is detected.
- If
true: Motor stops (VACTUAL = 0) when stall detected - Motor remains stopped until
RAMP_STAT.event_stop_sgflag is read - Motor can be restarted by reading/writing RAMP_STAT or disabling
sg_stop
Note: Requires min_velocity to be set (TCOOLTHRS must be configured).
Configuration Examples
Basic Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "tmc51x0.hpp"
void configureStallGuard() {
// IMPORTANT: Enable SpreadCycle mode first
driver.motorControl.SetStealthChopEnabled(false);
// Configure StallGuard2 with user-friendly API
tmc51x0::StallGuardConfig sg_config{};
// Set threshold (starting value, works with most motors)
sg_config.threshold = 0;
// Enable filter for smoother readings
sg_config.enable_filter = true;
// Set velocity thresholds
sg_config.min_velocity = 0.01f; // Enable above 0.01 rev/s (~0.6 RPM)
sg_config.max_velocity = 0.1f; // Disable above 0.1 rev/s (~6 RPM)
sg_config.velocity_unit = tmc51x0::Unit::RevPerSec; // Recommended default
// Don't stop on stall (for diagnostics/monitoring)
sg_config.stop_on_stall = false;
// Configure StallGuard2
driver.stallGuard.ConfigureStallGuard(sg_config);
}
Quick Setup with Sensitivity Enum
1
2
3
4
5
6
7
8
9
10
// Use sensitivity enum for convenience
tmc51x0::StallGuardConfig sg_config(
tmc51x0::StallGuardSensitivity::MODERATE, // Threshold = 0
true, // Enable filter
10.0f, // Min velocity
120.0f, // Max velocity
tmc51x0::Unit::RPM,
false // Don't stop on stall
);
driver.stallGuard.ConfigureStallGuard(sg_config);
Sensorless Homing Configuration
1
2
3
4
5
6
7
8
9
// Configuration optimized for sensorless homing
tmc51x0::StallGuardConfig sg_config{};
sg_config.threshold = -10; // More sensitive for stall detection
sg_config.enable_filter = false; // Disable filter for faster response
sg_config.min_velocity = 10.0f; // Match search speed
sg_config.max_velocity = 0.0f; // No upper limit
sg_config.velocity_unit = tmc51x0::Unit::RPM;
sg_config.stop_on_stall = true; // Stop motor on stall
driver.stallGuard.ConfigureStallGuard(sg_config);
CoolStep Integration Configuration
1
2
3
4
5
6
7
8
9
// Configuration optimized for CoolStep
tmc51x0::StallGuardConfig sg_config{};
sg_config.threshold = 0; // Moderate sensitivity
sg_config.enable_filter = true; // Enable filter for smoother readings
sg_config.min_velocity = 10.0f; // Match CoolStep min_velocity
sg_config.max_velocity = 120.0f; // Match CoolStep max_velocity
sg_config.velocity_unit = tmc51x0::Unit::RPM;
sg_config.stop_on_stall = false; // CoolStep handles current, not stopping
driver.stallGuard.ConfigureStallGuard(sg_config);
Automatic Tuning with Comprehensive Velocity Range Analysis
The library provides an advanced automatic tuning function that prioritizes target velocity and provides comprehensive velocity range analysis:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Comprehensive tuning with velocity range analysis
tmc51x0::StallGuardTuningResult result;
float target_velocity = 0.6f; // Most important - optimal SGT determined here (0.6 rev/s β 36 RPM)
float min_velocity = 0.18f; // Used to determine SGT range (30% of target)
float max_velocity = 0.9f; // Used to determine SGT range (150% of target)
// Using AutoTuneStallGuard (recommended) with current reduction
// Note: Separate unit parameters for velocity and acceleration
bool success = driver.tuning.AutoTuneStallGuard(
target_velocity, result, // Target velocity: e.g., 0.6 rev/s (~36 RPM)
0, 63, // SGT search range
0.06f, // Acceleration: 0.06 rev/sΒ²
min_velocity, max_velocity, // Velocity range: e.g., 0.18-0.9 rev/s
tmc51x0::Unit::RevPerSec, // Velocity unit (default, can be omitted)
tmc51x0::Unit::RevPerSec, // Acceleration unit (default, can be omitted)
0.3f // Current reduction factor: 30% (recommended)
);
if (success) {
// Use optimal SGT at target velocity
tmc51x0::StallGuardConfig sg_config;
sg_config.threshold = result.optimal_sgt;
sg_config.min_velocity = result.min_velocity_success ? min_velocity : result.actual_min_velocity;
sg_config.max_velocity = result.max_velocity_success ? max_velocity : result.actual_max_velocity;
driver.stallGuard.ConfigureStallGuard(sg_config);
ESP_LOGI(TAG, "Optimal SGT: %d (SG_RESULT=%u at target)",
result.optimal_sgt, result.target_velocity_sg_result);
if (!result.min_velocity_success) {
ESP_LOGW(TAG, "Requested min velocity %.2f not achievable. Use %.2f instead.",
min_velocity, result.actual_min_velocity);
}
if (!result.max_velocity_success) {
ESP_LOGW(TAG, "Requested max velocity %.2f not achievable. Use %.2f instead.",
max_velocity, result.actual_max_velocity);
}
}
Key Features:
- Target Velocity Priority: Optimal SGT is determined at target velocity (most important parameter)
- Velocity Range Analysis: Tests min/max velocities to determine usable SGT range
- Automatic Fallback: If requested velocities donβt work, finds actual achievable velocities
- Comprehensive Results: Returns detailed information about SGT values and velocity compatibility
Result Structure (StallGuardTuningResult):
optimal_sgt: Best SGT value at target velocity (primary result)tuning_success: Whether optimal SGT was foundmin_velocity_success/max_velocity_success: Whether requested velocities workactual_min_velocity/actual_max_velocity: Actual velocities that work (if requested ones donβt)target_velocity_sg_result/min_velocity_sg_result/max_velocity_sg_result: SG_RESULT values at each velocity
Tuning Guide
Step 1: Initial Setup
- Enable SpreadCycle: Ensure StealthChop is disabled
- Set Velocity Thresholds: Set
min_velocityto match your typical operating speed - Start with Default: Set
threshold = 0(starting value)
Step 2: Automatic Tuning (Recommended)
Use the comprehensive automatic tuning function for best results:
1
2
3
4
5
6
7
8
9
10
11
tmc51x0::StallGuardTuningResult result;
// Using AutoTuneStallGuard (recommended) - includes current reduction
// Note: Separate unit parameters for velocity and acceleration
bool success = driver.tuning.AutoTuneStallGuard(
target_velocity, result, // Your target operating velocity: e.g., 0.6 rev/s
0, 63, // SGT search range
0.06f, // Acceleration: 0.06 rev/sΒ²
min_velocity, max_velocity, // Your velocity range: e.g., 0.18-0.9 rev/s
tmc51x0::Unit::RevPerSec, // Unit (default, can be omitted)
0.3f // Current reduction factor: 30% (recommended)
);
Step 3: Interactive Tuning (Manual Alternative)
1
2
3
4
5
6
7
8
9
10
11
12
// Operate motor at normal velocity and monitor SG_RESULT
uint16_t sg_min = 1023;
uint16_t sg_max = 0;
for (int i = 0; i < 1000; i++) {
uint16_t sg = driver.stallGuard.GetStallGuardResult().Value();
sg_min = std::min(sg_min, sg);
sg_max = std::max(sg_max, sg);
vTaskDelay(pdMS_TO_TICKS(10));
}
ESP_LOGI(TAG, "SG_RESULT range: %d to %d", sg_min, sg_max);
Step 3: Load Testing
1
2
3
4
5
6
7
// Apply slowly increasing load
// If motor stalls before SG_RESULT reaches zero: decrease threshold
// If SG_RESULT reaches zero before motor stalls: increase threshold
// Goal: SG_RESULT between 0-100 at maximum load before stall
sg_config.threshold = /* adjusted value */;
driver.stallGuard.ConfigureStallGuard(sg_config);
Step 4: Fine-Tuning
- If false stalls: Increase
threshold(less sensitive) - If missed stalls: Decrease
threshold(more sensitive) - If readings noisy: Enable
enable_filter - If response too slow: Disable
enable_filter
Best Practices
- Use Automatic Tuning: Use
TuneStallGuard()withStallGuardTuningResultfor comprehensive analysis - Prioritize Target Velocity: Set target velocity to your most common operating speed - this gets the best SGT value
- Specify Velocity Range: Provide min/max velocities to determine the usable SGT range
- Check Results: Always check
actual_min_velocityandactual_max_velocityif requested velocities donβt work - Tune First: Always tune StallGuard2 before using CoolStep
- Test Under Load: Test under actual operating conditions
- Monitor SG_RESULT: Use
GetStallGuardResult()to understand your motorβs load profile - Match Velocity Range: Set velocity thresholds to your typical operating speeds
- Use Filter Appropriately: Enable for CoolStep, disable for sensorless homing
- Verify SpreadCycle: Always ensure SpreadCycle is enabled before configuring
Troubleshooting
Problem: SG_RESULT always reads 0
- Solution: Check that SpreadCycle is enabled (StealthChop disabled)
Problem: False stall detection
- Solution: Increase
thresholdvalue (less sensitive)
Problem: Missed stalls
- Solution: Decrease
thresholdvalue (more sensitive)
Problem: Noisy readings
- Solution: Enable
enable_filterfor smoother readings
Problem: Response too slow
- Solution: Disable
enable_filterfor faster response
Problem: StallGuard2 doesnβt activate
- Solution: Check that
min_velocityis set correctly (TCOOLTHRS configured)
Technical Details
Register Mapping:
SGT(bits 22..16): StallGuard2 threshold (-64 to +63, signed 7-bit)SFILT(bit 24): Filter enable (0=every step, 1=every 4 steps)TCOOLTHRS: Lower velocity threshold (bits 22..8 used for comparison)THIGH: Upper velocity thresholdSW_MODE.sg_stop(bit 7): Stop on stall enable
SG_RESULT Range: 0-1023 (10-bit value)
- 0: Highest load (motor stalled or about to stall)
- 100-200: High load (motor working hard)
- 200-600: Moderate load (typical operating range)
- 600-1023: Low load (motor coasting)
Measurement Update Rate:
- Without filter: Every fullstep
- With filter: Every electrical period (4 fullsteps)
Note: StallGuard2 requires SpreadCycle mode (en_pwm_mode=0). StallGuard2 is not available in StealthChop mode.
StealthChop Voltage PWM Mode
StealthChop is an extremely quiet mode of operation for stepper motors, providing absolutely noiseless operation at standstill and low velocities. Itβs based on voltage mode PWM and is ideal for indoor or home use applications.
Benefits
- Silent Operation: Absolutely noiseless at standstill and low velocities
- Vibration-Free: Motor operates free of vibration at low velocities
- Automatic Tuning: StealthChop2 automatically adapts to the motor for best performance
- Energy Efficient: Can power down motor to very low currents
- High Dynamics: Supports high motor dynamics with proper tuning
When to Use StealthChop
β Recommended for:
- Indoor or home use applications
- Applications requiring silent operation
- Low-velocity positioning applications
- Applications where noise is a concern
- Applications with varying supply voltage (with automatic tuning)
β Not recommended for:
- High-velocity applications (use SpreadCycle or combine both)
- Applications requiring StallGuard2 (mutually exclusive)
- Applications with unknown motor characteristics (without proper tuning)
- Applications where current regulation is not satisfying
Prerequisites
Critical Requirements:
- Motor Standstill: Motor must be at standstill when StealthChop is first enabled
- Standstill Period: Keep motor stopped for at least 128 chopper periods after enabling
- Current Setting: IRUN β₯ 8 (current settings below 8 do not work with automatic tuning)
- Lower Current Limit: Motor current must exceed I_LOWER_LIMIT (calculated from TBL, fPWM, VM, R_COIL)
- Open Load Check: Perform open load detection in SpreadCycle before enabling StealthChop
Automatic Tuning (AT#1 and AT#2)
StealthChop2 features automatic tuning that adapts operating parameters to the motor automatically. Two tuning phases are required:
AT#1: Standstill Tuning
Purpose: Regulates to nominal current and stores result to PWM_OFS_AUTO.
Conditions:
- Motor in standstill
- Actual current scale (CS) identical to run current (IRUN)
- Pin VS at operating level
- Duration: β€130ms (with internal clock)
Procedure:
- Enable motor with nominal run current (IRUN)
- Keep motor at standstill for β₯130ms
- Driver automatically regulates current and stores PWM_OFS_AUTO
Note: If standstill reduction is enabled, issue a single step pulse and stop again to power motor to run current.
AT#2: Motion Tuning
Purpose: Optimizes PWM_GRAD_AUTO during motion.
Conditions:
- Move motor at medium velocity (60-300 RPM typical)
- Significant back EMF generated
- Full run current can be reached
- PWM_SCALE_SUM conditions: 1.5PWM_OFS_AUTO(IRUN+1)/32 < PWM_SCALE_SUM < 4PWM_OFS_AUTO(IRUN+1)/32
- PWM_SCALE_SUM < 255
- Requires 8 fullsteps per change of Β±1
- For typical motor with PWM_GRAD_AUTO optimum at 50 or less, up to 400 fullsteps required when starting from default value 0
Procedure:
- Move motor at medium velocity (e.g., during homing procedure)
- Include constant velocity ramp segment
- Monitor PWM_SCALE_AUTO going down to zero (indicates successful tuning)
- Store PWM_GRAD_AUTO to CPU memory for faster tuning procedure (optional)
Success Indicator: PWM_SCALE_AUTO approaches 0 during constant velocity phase.
Configuration Parameters
PWM Frequency (pwm_freq)
Purpose: Chopper frequency selection for StealthChop operation.
Options:
PWM_FREQ_0: ~23.4kHz @ 12MHz (lowest frequency)PWM_FREQ_1: ~35.1kHz @ 12MHz (recommended for most applications)PWM_FREQ_2: ~46.9kHz @ 12MHzPWM_FREQ_3: ~58.5kHz @ 12MHz (highest frequency)
Effect:
- Lower frequencies: Reduce current ripple, may limit high-velocity performance
- Higher frequencies: Improve high-velocity performance, increase dynamic power dissipation
Recommendation: Use lowest setting giving good results. Typical: 1 (~35kHz @ 12MHz).
PWM Offset (pwm_ofs)
Purpose: Initial value for PWM amplitude (offset) for velocity-based scaling.
Range: 0-255
- 0: Disables linear current scaling based on current setting
- Typical: 30 (default) for most motors
Calculation (for manual mode, pwm_autoscale=0):
1
PWM_OFS = 374 * R_COIL * I_COIL / V_M
Note: With automatic tuning (pwm_autoscale=1), this is used as initial value. After AT#1, actual value is stored in PWM_OFS_AUTO.
PWM Gradient (pwm_grad)
Purpose: Velocity-dependent factor to compensate for back EMF.
Range: 0-255
- Typical: 0 (default) - let automatic tuning determine
Calculation (for manual mode, pwm_autoscale=0):
1
PWM_GRAD = C_BEMF * 2Ο * f_CLK * 1.46 / (V_M * MSPR)
Note: With automatic tuning (pwm_autograd=1), this is used as initial value. After AT#2, actual value is stored in PWM_GRAD_AUTO.
Automatic Scaling (pwm_autoscale)
Purpose: Enable automatic current regulation using current measurement feedback.
- true (recommended): Automatic scaling with current regulator
- Adapts to motor heating, supply voltage changes
- Responds to motor stall and load changes
- Requires current measurement (sense resistors)
- false: Feed-forward velocity-controlled mode
- Very stable amplitude
- Does not react to supply voltage changes or motor stall
- Does not require current measurement
- Only for well-known motor and operating conditions
Recommendation: Use automatic mode (true) unless current regulation is not satisfying.
Automatic Gradient (pwm_autograd)
Purpose: Enable automatic tuning of PWM_GRAD_AUTO during AT#2 phase.
- true (recommended): Automatic gradient tuning
- Driver optimizes PWM_GRAD_AUTO during AT#2
- Adapts to motor characteristics automatically
- false: Use PWM_GRAD from register
- Use pre-determined PWM_GRAD value
- Reduces amplitude jitter
- Requires manual tuning
Recommendation: Set to false if you have pre-determined PWM_GRAD and want to reduce jitter.
Regulation Coefficient (pwm_reg)
Purpose: Proportionality coefficient for PWM amplitude regulation loop.
Range: 1-15
- Lower values: Stable, soft regulation (slower response)
- Higher values: Faster adaptation (may be less stable)
- Typical: 4 (default) for balanced response
- Minimum: 1 (for slow acceleration during AT#2)
Recommendation: Should be as small as possible for stability, but large enough for quick reaction. Optimize for fastest required acceleration/deceleration ramp.
PWM Limit (pwm_lim)
Purpose: Limiting value for current jerk when switching from SpreadCycle to StealthChop.
Range: 0-15 (upper 4 bits of 8-bit amplitude limit)
- Lower values: Lower current jerk (smoother switching)
- Higher values: Higher current jerk (faster switching)
- Default: 12 (recommended)
Recommendation: Reduce value to yield lower current jerk at mode switching.
Lower Current Limit
StealthChop current regulator imposes a lower limit for motor current regulation:
1
I_LOWER_LIMIT = t_BLANK * f_PWM * V_M / R_COIL
Where:
t_BLANK: Blank time (from TBL setting: 16, 24, 36, or 54 clock cycles)f_PWM: Chopper frequency (from PWM_FREQ setting)V_M: Motor supply voltageR_COIL: Motor coil resistance
Important:
- IRUN β₯ 8: Current settings for IRUN below 8 do not work with automatic tuning
- Motor current in AT#1 must exceed I_LOWER_LIMIT
- Lower blank time (TBL) allows lower current limit
- During AT#1, driver may reduce frequency if current cannot be reached
Example: Motor with R_COIL = 5Ξ©, V_M = 24V, TBL=1 (24 clocks), PWM_FREQ=0 (2/1024 fCLK):
1
I_LOWER_LIMIT = 24 * (2/1024) * 24V / 5Ξ© = 225mA
Motor target current for automatic tuning must be 225mA or more.
Configuration Examples
Basic Configuration (Automatic Tuning)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "tmc51x0.hpp"
void configureStealthChop() {
// Configure StealthChop with automatic tuning using intuitive enums
tmc51x0::StealthChopConfig stealth{};
// Use recommended PWM frequency (~35kHz @ 12MHz)
stealth.pwm_freq = static_cast<uint8_t>(tmc51x0::StealthChopPwmFreq::PWM_FREQ_1);
// Initial values (will be optimized by automatic tuning)
stealth.pwm_ofs = 30; // Typical starting value (normal mode)
stealth.pwm_grad = 0; // Let automatic tuning determine
// Enable automatic tuning (recommended)
stealth.pwm_autoscale = true;
stealth.pwm_autograd = true;
// Balanced regulation speed (2 increments per half wave)
stealth.pwm_reg = static_cast<uint8_t>(tmc51x0::StealthChopRegulationSpeed::MODERATE);
// Balanced jerk reduction
stealth.pwm_lim = static_cast<uint8_t>(tmc51x0::StealthChopJerkReduction::MODERATE);
// Normal freewheeling
stealth.freewheel = tmc51x0::PWMFreewheel::NORMAL;
// Configure StealthChop
driver.motorControl.ConfigureStealthChop(stealth);
// IMPORTANT: Motor must be at standstill when StealthChop is first enabled
// Keep motor stopped for at least 128 chopper periods
// Set velocity threshold for StealthChop (TPWMTHRS)
// Below this velocity: StealthChop (silent)
// Above this velocity: SpreadCycle (more torque)
driver.thresholds.SetModeChangeSpeeds(0.002f, 0.0f, 0.0f, tmc51x0::Unit::RevPerSec); // Unit::RevPerSec is default
}
Quick Setup with Helper Constructor (Using Enums)
1
2
3
4
5
6
7
8
9
10
11
// Most intuitive: Using enums for all parameters
tmc51x0::StealthChopConfig stealth(
tmc51x0::StealthChopPwmFreq::PWM_FREQ_1, // PWM frequency
tmc51x0::StealthChopRegulationSpeed::MODERATE, // Regulation speed
tmc51x0::StealthChopJerkReduction::MODERATE // Jerk reduction
);
driver.motorControl.ConfigureStealthChop(stealth);
// Or with custom initial values (using raw values)
tmc51x0::StealthChopConfig stealth(1, 30, 0, 4, 12); // freq, ofs, grad, reg, lim
driver.motorControl.ConfigureStealthChop(stealth);
Advanced Configuration (Fine-Tuned)
1
2
3
4
5
6
7
8
9
10
11
12
13
// For applications requiring fast regulation response
tmc51x0::StealthChopConfig stealth{};
stealth.pwm_freq = static_cast<uint8_t>(tmc51x0::StealthChopPwmFreq::PWM_FREQ_1);
stealth.pwm_reg = static_cast<uint8_t>(tmc51x0::StealthChopRegulationSpeed::FAST); // Fast response
stealth.pwm_lim = static_cast<uint8_t>(tmc51x0::StealthChopJerkReduction::LOW); // Allow faster switching
stealth.pwm_autoscale = true;
stealth.pwm_autograd = true;
driver.motorControl.ConfigureStealthChop(stealth);
// For applications requiring very smooth switching
stealth.pwm_reg = static_cast<uint8_t>(tmc51x0::StealthChopRegulationSpeed::SLOW); // Very stable
stealth.pwm_lim = static_cast<uint8_t>(tmc51x0::StealthChopJerkReduction::MAXIMUM); // Smoothest switching
driver.motorControl.ConfigureStealthChop(stealth);
Manual Mode (Advanced)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// For well-known motor and operating conditions only
tmc51x0::StealthChopConfig stealth{};
stealth.pwm_freq = 1;
// Calculate PWM_OFS: 374 * R_COIL * I_COIL / V_M
stealth.pwm_ofs = static_cast<uint8_t>((374.0f * 5.0f * 1.68f) / 24.0f); // Example
// Calculate PWM_GRAD from back EMF constant
// PWM_GRAD = C_BEMF * 2Ο * f_CLK * 1.46 / (V_M * MSPR)
stealth.pwm_grad = /* calculated value */;
// Disable automatic tuning (manual mode)
stealth.pwm_autoscale = false;
stealth.pwm_autograd = false;
driver.motorControl.ConfigureStealthChop(stealth);
Automatic Tuning Procedure
Step 1: Initial Setup
1
2
3
4
5
6
7
8
9
10
11
12
13
// Configure StealthChop with automatic tuning enabled
tmc51x0::StealthChopConfig stealth{};
stealth.pwm_freq = 1;
stealth.pwm_autoscale = true;
stealth.pwm_autograd = true;
driver.motorControl.ConfigureStealthChop(stealth);
// Enable StealthChop mode
driver.motorControl.SetStealthChopEnabled(true);
// IMPORTANT: Motor must be at standstill
// Keep motor stopped for at least 128 chopper periods
driver.GetComm().DelayMs(150); // Ensure AT#1 completes (β€130ms)
Step 2: AT#1 - Standstill Tuning
1
2
3
4
5
6
7
8
// Motor should be at standstill with nominal run current (IRUN)
// AT#1 automatically completes during standstill period
// Read automatic tuning results
auto pwm_auto_result = driver.status.GetPwmAuto();
if (pwm_auto_result) {
uint8_t pwm_ofs_auto = pwm_auto_result.Value();
ESP_LOGI(TAG, "AT#1 complete: PWM_OFS_AUTO = %u", pwm_ofs_auto);
}
Step 3: AT#2 - Motion Tuning
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Move motor at medium velocity (60-300 RPM typical)
// Include constant velocity ramp segment
auto speed_result = driver.rampControl.SetMaxSpeed(0.02f); // Unit::RevPerSec is default
if (!speed_result) {
printf("Error setting max speed: %s\n", speed_result.ErrorMessage());
return;
}
auto accel_result = driver.rampControl.SetAccelerations(0.01f, 0.01f); // Unit::RevPerSec is default
if (!accel_result) {
printf("Error setting accelerations: %s\n", accel_result.ErrorMessage());
return;
}
auto pos_result = driver.rampControl.SetTargetPosition(10000);
if (!pos_result) {
printf("Error setting target position: %s\n", pos_result.ErrorMessage());
return;
}
// Monitor PWM_SCALE_AUTO during motion
while (true) {
auto reached = driver.rampControl.IsTargetReached();
if (reached && reached.Value()) {
break; // Target reached
}
if (!reached) {
ESP_LOGE(TAG, "Error checking target: %s", reached.ErrorMessage());
break;
}
auto pwm_result = driver.status.GetPwmScale();
if (pwm_result) {
uint8_t pwm_scale_sum = pwm_result.Value();
// Note: GetPwmScale returns pwm_scale_sum, pwm_scale_auto is available via diagnostics
// PWM_SCALE_AUTO should approach 0 during constant velocity phase
ESP_LOGI(TAG, "PWM_SCALE_SUM = %d", pwm_scale_sum);
}
driver.GetComm().DelayMs(10);
}
// Read final automatic tuning results
auto pwm_auto_result2 = driver.status.GetPwmAuto();
if (pwm_auto_result2) {
uint8_t pwm_ofs_auto = pwm_auto_result2.Value();
ESP_LOGI(TAG, "AT#2 complete: PWM_OFS_AUTO = %u", pwm_ofs_auto);
// Store values for faster tuning in future (optional)
}
Combining StealthChop and SpreadCycle
For applications requiring high velocity motion, combine StealthChop (low speed) with SpreadCycle (high speed):
1
2
3
4
5
6
7
8
9
10
11
12
// Configure StealthChop for low-speed silent operation
tmc51x0::StealthChopConfig stealth{};
stealth.pwm_freq = 1;
driver.motorControl.ConfigureStealthChop(stealth);
// Set velocity threshold (TPWMTHRS)
// Below threshold: StealthChop (silent)
// Above threshold: SpreadCycle (more torque)
driver.thresholds.SetModeChangeSpeeds(200.0f, 0.0f, 0.0f, tmc51x0::Unit::RPM);
// Use low transfer velocity to avoid jerk at switching point
// Typical: 1 to a few 10 RPM
Important:
- Set TPWMTHRS to low velocity (1-10 RPM) to avoid jerk at switching point
- Jerk occurs because back-EMF causes phase shift between voltage and current
- At low velocities, jerk can be completely neglected for most motors
Best Practices
- Use Automatic Tuning: Enable
pwm_autoscaleandpwm_autogradfor best results - Start at Standstill: Always enable StealthChop with motor at standstill
- Wait for AT#1: Keep motor stopped for β₯130ms after enabling
- Monitor AT#2: Monitor PWM_SCALE_AUTO during motion tuning
- Check Lower Limit: Ensure motor current exceeds I_LOWER_LIMIT
- Open Load Check: Perform open load detection in SpreadCycle first
- Tune Overcurrent: Tune low-side overcurrent detection for motor stall protection
- Store Values: Store PWM_OFS_AUTO and PWM_GRAD_AUTO for faster future tuning
Troubleshooting
Problem: Motor current too high during deceleration
- Solution: Follow automatic tuning process, check optimum tuning conditions
Problem: Current regulation not satisfying
- Solution: Check that IRUN β₯ 8 and current exceeds I_LOWER_LIMIT
Problem: Motor loses steps
- Solution: Ensure proper AT#1 and AT#2 completion, check PWM_SCALE_AUTO
Problem: Jerk at mode switching
- Solution: Use lower TPWMTHRS value (1-10 RPM), reduce PWM_LIM
Problem: Open load flags active
- Solution: Perform open load test in SpreadCycle before enabling StealthChop
Problem: Motor stall causes overcurrent
- Solution: Tune low-side overcurrent detection to safely trigger upon motor stall
Technical Details
Register Mapping:
PWM_OFS(bits 7..0): User defined amplitude offset (0-255)PWM_GRAD(bits 15..8): User defined amplitude gradient (0-255)pwm_freq(bits 17..16): PWM frequency selection (0-3)pwm_autoscale(bit 18): Automatic amplitude scaling enablepwm_autograd(bit 19): Automatic gradient adaptation enablePWM_REG(bits 27..24): Regulation loop coefficient (1-15)PWM_LIM(bits 31..28): Amplitude limit for mode switching (0-15)freewheel(bits 21..20): Freewheeling mode (0-3)
Automatic Tuning Results (read-only):
PWM_OFS_AUTO: Automatically determined offset value (0-255)PWM_GRAD_AUTO: Automatically determined gradient value (0-255)PWM_SCALE_AUTO: Current regulator correction (-255 to +255, should approach 0)
Note: StealthChop requires motor to be at standstill when first enabled. StealthChop and StallGuard2 are mutually exclusive.
SpreadCycle and Classic Chopper
SpreadCycle is a cycle-by-cycle current control providing superior microstepping quality. It can react extremely fast to changes in motor velocity or motor load. Classic mode is an alternative constant off-time chopper algorithm.
Benefits
- Superior Microstepping: SpreadCycle provides superior microstepping quality even with default settings
- Fast Response: Cycle-by-cycle current control reacts extremely fast to velocity/load changes
- Automatic Optimization: SpreadCycle automatically determines optimum fast-decay phase length
- Low Power Dissipation: Slow decay phases reduce electrical losses and current ripple
- StallGuard2 Compatible: Required for StallGuard2 and CoolStep operation
When to Use SpreadCycle
β Recommended for:
- Applications requiring StallGuard2 (mutually exclusive with StealthChop)
- Applications requiring CoolStep (requires SpreadCycle)
- High-velocity applications (better than StealthChop at high speeds)
- Applications requiring maximum torque and dynamic performance
- Applications where noise is not a primary concern
β Not recommended for:
- Applications requiring silent operation (use StealthChop instead)
- Low-velocity positioning where silence is critical
Chopper Frequency
Chopper frequency is an important parameter. Most motors work optimally in 16-30kHz range.
Frequency is influenced by:
- TOFF setting (slow decay time)
- TBL setting (blank time)
- Hysteresis settings (HSTRT, HEND)
- Motor inductance
- Supply voltage
Too low frequency: May generate audible noise Too high frequency: Magnetic losses rise, power dissipation increases
Configuration Parameters
Chopper Mode (mode)
Purpose: Selects between SpreadCycle and Classic chopper algorithms.
- SPREAD_CYCLE (recommended): Patented high-performance algorithm
- Automatically determines optimum fast-decay phase length
- Superior microstepping quality with default settings
- Cycles: on β slow decay β fast decay β slow decay
- CLASSIC: Constant off-time chopper mode
- Alternative algorithm, requires more tuning
- Cycles: on β fast decay β slow decay
- Used automatically in DcStep fullstepping
Off Time (toff)
Purpose: Sets slow decay time and limits maximum chopper frequency.
Range: 0-15
- 0: Chopper off (driver disabled, motor can free-wheel)
- 1: Minimum off time (requires TBL β₯ 2)
- 2-15: Off time setting (typical: 3-5 for 16-30kHz chopper frequency)
Calculation for target chopper frequency:
1
2
t_OFF = (1 / f_chopper) * (slow_decay_percent / 100) * (1 / 2)
TOFF = (t_OFF * f_CLK - 12) / 32
Example (25kHz target, 50% slow decay, 12MHz clock):
- t_OFF = (1/25000) * 0.5 * 0.5 = 10Β΅s
- TOFF = (10Β΅s * 12MHz - 12) / 32 β 3.0 β use 3
Note: For StealthChop operation, any setting is OK (not used for chopping).
Blank Time (tbl)
Purpose: Masks comparator input to block spikes from parasitic capacitances.
Options:
TBL_16CLK: 16 clock cycles (~1.33Β΅s @ 12MHz)TBL_24CLK: 24 clock cycles (~2.0Β΅s @ 12MHz)TBL_36CLK: 36 clock cycles (~3.0Β΅s @ 12MHz, typical)TBL_54CLK: 54 clock cycles (~4.5Β΅s @ 12MHz, for high capacitive loads)
Recommendation: Use TBL_36CLK for most applications. For highly capacitive loads (filter networks), use TBL_36CLK or TBL_54CLK.
Hysteresis (SpreadCycle Mode)
Purpose: Forces minimum current ripple into motor coils for best microstepping results.
Hysteresis Start (hstrt): Adds to hysteresis end value (0-7, adds 1-8 to HEND)
- Lower values: Less current ripple (may reduce microstep accuracy)
- Higher values: More current ripple (may increase chopper noise)
- Typical: 4 (effective hysteresis = 4 when HEND=0)
Hysteresis End (hend): End value after decrements (0-15 encoded)
- Encoded: 0-2 = negative (-3 to -1), 3 = zero, 4-15 = positive (1 to 12)
- Typical: 0 (effective end = -3)
Effective Hysteresis = HSTRT + HEND (with encoding)
Tuning:
- Start from low setting (HSTRT=0, HEND=0)
- Increase HSTRT until motor runs smoothly at low velocity
- Check sine wave shape near zero transition (should have no ledge)
- Too low: Reduced microstep accuracy, humming/vibration at medium velocities
- Too high: Reduced chopper frequency, increased noise, no benefit
Note: Sum HSTRT+HEND must be β€16 (at CS β€ 30).
Fast Decay Time (Classic Mode Only)
Purpose: Sets fixed fast decay time following each on phase.
Range: 0-15
- 0: Slow decay only
- 1-15: Fast decay time duration
- Typical: Similar to slow decay time (TOFF) setting
Tuning: Should be long enough to follow falling slope but not cause excess ripple. Tune using oscilloscope or motor smoothness at different velocities.
Sine Wave Offset (Classic Mode Only)
Purpose: Corrects for zero crossing error in Classic mode.
Range: 0-15 (encoded)
- Encoded: 0-2 = negative (-3 to -1), 3 = zero, 4-15 = positive (1 to 12)
- Typical: 4-6 (positive offset 1-3) for smoothest operation
Tuning:
- Too low: Motor stands still for short moment during zero crossing
- Too high: Makes larger microstep
- Typically requires positive offset for smoothest operation
Passive Fast Decay Time (tpfd)
Purpose: Adds passive fast decay time after bridge polarity change.
Range: 0-15
- 0: Disabled
- 1-15: Fast decay time in multiples of 128 clocks (~10Β΅s per unit @ 12MHz)
Usage: Starting from 0, increase value if motor suffers from mid-range resonances.
Microstep Resolution (mres)
Purpose: Defines number of microsteps per full step.
Options:
MRES_256: 256 microsteps (highest resolution, smoothest)MRES_128: 128 microstepsMRES_64: 64 microstepsMRES_32: 32 microstepsMRES_256: 256 microsteps (typical, balanced)MRES_8: 8 microstepsMRES_4: 4 microstepsMRES_2: 2 microstepsFULLSTEP: Full step (no microstepping)
Note: Interpolation can be enabled to extrapolate to 256 microsteps regardless of MRES setting.
Configuration Examples
Basic SpreadCycle Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "tmc51x0.hpp"
void configureSpreadCycle() {
// Configure SpreadCycle with typical settings
tmc51x0::ChopperConfig chopper{};
// SpreadCycle mode (recommended)
chopper.mode = tmc51x0::ChopperMode::SPREAD_CYCLE;
// Off time for ~25kHz chopper frequency (typical)
chopper.toff = 5;
// Blank time (36 clocks, typical)
chopper.tbl = static_cast<uint8_t>(tmc51x0::ChopperBlankTime::TBL_36CLK);
// Hysteresis (effective = 4)
chopper.hstrt = 4; // Typical
chopper.hend = 0; // Typical (effective end = -3)
// Passive fast decay (disabled)
chopper.tpfd = 0;
// Microstep resolution (256 microsteps)
chopper.mres = tmc51x0::MicrostepResolution::MRES_256;
// Enable interpolation (recommended)
chopper.intpol = true;
// Configure chopper
driver.motorControl.ConfigureChopper(chopper);
}
Quick Setup with Helper Constructor
1
2
3
4
5
6
7
// SpreadCycle mode with typical settings
tmc51x0::ChopperConfig chopper(5); // toff=5, other defaults
driver.motorControl.ConfigureChopper(chopper);
// Or with custom values
tmc51x0::ChopperConfig chopper(5, 2, 4, 0, tmc51x0::MicrostepResolution::MRES_256); // toff, tbl, hstrt, hend, mres
driver.motorControl.ConfigureChopper(chopper);
Classic Mode Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Classic constant off-time chopper
tmc51x0::ChopperConfig chopper{};
chopper.mode = tmc51x0::ChopperMode::CLASSIC;
chopper.toff = 5; // Slow decay time
chopper.tfd = 5; // Fast decay time (similar to toff)
chopper.hend = 4; // Sine wave offset (positive offset for zero crossing)
chopper.disfdcc = false; // Enable comparator termination
chopper.tbl = static_cast<uint8_t>(tmc51x0::ChopperBlankTime::TBL_36CLK);
chopper.mres = static_cast<uint8_t>(tmc51x0::MicrostepResolution::MRES_256);
chopper.intpol = true;
driver.motorControl.ConfigureChopper(chopper);
// Or use helper constructor
tmc51x0::ChopperConfig chopper(5, 5, 4); // toff, tfd, offset
driver.motorControl.ConfigureChopper(chopper);
High-Velocity Configuration
1
2
3
4
5
6
7
8
9
10
// Optimized for high velocities
tmc51x0::ChopperConfig chopper{};
chopper.mode = tmc51x0::ChopperMode::SPREAD_CYCLE;
chopper.toff = 2; // Shorter off time (higher frequency)
chopper.tbl = static_cast<uint8_t>(tmc51x0::ChopperBlankTime::TBL_24CLK); // Shorter blank time
chopper.hstrt = 4;
chopper.hend = 0;
chopper.mres = static_cast<uint8_t>(tmc51x0::MicrostepResolution::MRES_256);
chopper.intpol = true;
driver.motorControl.ConfigureChopper(chopper);
Tuning Guide
Step 1: Calculate TOFF for Target Frequency
1
2
3
4
5
6
7
8
// Target: 25kHz chopper frequency, 50% slow decay, 12MHz clock
float target_freq_hz = 25000.0f;
float slow_decay_percent = 50.0f;
float f_clk_hz = 12000000.0f;
float t_off_us = (1.0f / target_freq_hz) * (slow_decay_percent / 100.0f) * 0.5f * 1000000.0f;
uint8_t toff = static_cast<uint8_t>((t_off_us * f_clk_hz / 1000000.0f - 12.0f) / 32.0f);
toff = constrain<uint8_t>(toff, 1U, 15U);
Step 2: Tune Hysteresis (SpreadCycle)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Start from low setting
chopper.hstrt = 0;
chopper.hend = 0;
// Increase until motor runs smoothly at low velocity
for (uint8_t hstrt = 0; hstrt <= 7; hstrt++) {
chopper.hstrt = hstrt;
driver.motorControl.ConfigureChopper(chopper);
// Test motor smoothness at low velocity
// Move motor and check for smooth operation
auto speed_result = driver.rampControl.SetMaxSpeed(0.002f); // Unit::RevPerSec is default
if (!speed_result) {
printf("Error setting max speed: %s\n", speed_result.ErrorMessage());
continue;
}
auto pos_result = driver.rampControl.SetTargetPosition(1000);
if (!pos_result) {
printf("Error setting target position: %s\n", pos_result.ErrorMessage());
continue;
}
// ... wait for motion and check smoothness ...
// If smooth, this is the optimal setting
// break;
}
Step 3: Tune TPFD (if resonances occur)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// If motor suffers from mid-range resonances
for (uint8_t tpfd = 1; tpfd <= 15; tpfd++) {
chopper.tpfd = tpfd;
driver.motorControl.ConfigureChopper(chopper);
// Test for resonances at mid-range velocities
auto speed_result = driver.rampControl.SetMaxSpeed(0.01f); // Unit::RevPerSec is default
if (!speed_result) {
printf("Error setting max speed: %s\n", speed_result.ErrorMessage());
continue;
}
auto pos_result = driver.rampControl.SetTargetPosition(5000);
if (!pos_result) {
printf("Error setting target position: %s\n", pos_result.ErrorMessage());
continue;
}
// ... wait for motion and check for resonances ...
// If resonances reduced, this is the optimal setting
// break;
}
Best Practices
- Use SpreadCycle: Recommended for most applications (superior microstepping quality)
- Target Frequency: Aim for 16-30kHz chopper frequency
- Start Conservative: Begin with typical settings (TOFF=5, TBL=36CLK, HSTRT=4)
- Tune Hysteresis: Start from low and increase until smooth operation
- Enable Interpolation: Always enable for best microstepping quality
- Match TOFF and TBL: For high velocities, use shorter TOFF (2-3) and TBL (24CLK)
Troubleshooting
Problem: Audible chopper noise
- Solution: Increase TOFF (reduces frequency), check that frequency is in 16-30kHz range
Problem: Reduced microstep accuracy
- Solution: Increase hysteresis (HSTRT), check sine wave shape near zero crossing
Problem: Motor humming/vibration at medium velocities
- Solution: Increase hysteresis (HSTRT), ensure HSTRT+HEND β₯ 4
Problem: Mid-range resonances
- Solution: Increase TPFD (passive fast decay time)
Problem: Chopper frequency too low
- Solution: Reduce TOFF, reduce TBL, reduce hysteresis
Problem: Chopper frequency too high
- Solution: Increase TOFF, increase TBL, increase hysteresis
Technical Details
Register Mapping (CHOPCONF register):
TOFF(bits 3..0): Off time and driver enable (0-15)HSTRT/TFD[2:0](bits 6..4): Hysteresis start (SpreadCycle) or fast decay time (Classic)HEND/OFFSET(bits 10..7): Hysteresis end (SpreadCycle) or sine wave offset (Classic)TFD[3](bit 11): MSB of fast decay time (Classic only)disfdcc(bit 12): Disable fast decay comparator (Classic only)- Reserved (bit 13): Reserved, set to 0
chm(bit 14): Chopper mode (0=SpreadCycle, 1=Classic)TBL(bits 16..15): Comparator blank time (0-3)- Reserved (bit 17): Reserved, set to 0
vhighfs(bit 18): High velocity fullstep selectionvhighchm(bit 19): High velocity chopper modeTPFD(bits 23..20): Passive fast decay time (0-15)MRES(bits 27..24): Microstep resolution (0-8)intpol(bit 28): Interpolation to 256 microstepsdedge(bit 29): Enable double edge step pulsesdiss2g(bit 30): Short to GND protection disablediss2vs(bit 31): Short to supply protection disable
Chopper Cycles:
- SpreadCycle: on β slow decay β fast decay β slow decay (4 phases)
- Classic: on β fast decay β slow decay (3 phases)
Note: SpreadCycle is required for StallGuard2 and CoolStep operation. StealthChop and SpreadCycle can be combined using velocity thresholds (TPWMTHRS).
Freewheeling Mode
Freewheeling controls motor behavior when ihold=0 (no hold current).
Freewheeling Options
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void configureFreewheeling() {
// Configure freewheeling via StealthChopConfig
tmc51x0::StealthChopConfig stealth{};
stealth.freewheel = tmc51x0::PWMFreewheel::NORMAL; // Normal operation (coast when ihold=0)
driver.motorControl.ConfigureStealthChop(stealth);
// Or change freewheeling mode at runtime
stealth.freewheel = tmc51x0::PWMFreewheel::ENABLED; // Freewheeling enabled (low resistance)
driver.motorControl.ConfigureStealthChop(stealth);
stealth.freewheel = tmc51x0::PWMFreewheel::SHORT_LS; // Coil shorted using low-side drivers
driver.motorControl.ConfigureStealthChop(stealth);
stealth.freewheel = tmc51x0::PWMFreewheel::SHORT_HS; // Coil shorted using high-side drivers
driver.motorControl.ConfigureStealthChop(stealth);
}
Use Cases
- NORMAL: Standard operation, motor coasts
- ENABLED: Low power consumption, easy to turn
- SHORT_LS/HS: Braking effect, motor resists rotation
Reference Switches (Endstops)
Reference switches provide hardware endstops for homing and limit detection.
Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void configureEndstops() {
tmc51x0::ReferenceSwitchConfig ref_switch{};
// Configure switches with enum-based API
ref_switch.left_switch_active = tmc51x0::ReferenceSwitchActiveLevel::ACTIVE_HIGH;
ref_switch.right_switch_active = tmc51x0::ReferenceSwitchActiveLevel::ACTIVE_HIGH;
ref_switch.latch_left = tmc51x0::ReferenceLatchMode::ACTIVE_EDGE;
ref_switch.latch_right = tmc51x0::ReferenceLatchMode::ACTIVE_EDGE;
ref_switch.stop_mode = tmc51x0::ReferenceStopMode::SOFT_STOP;
ref_switch.latch_left = tmc51x0::ReferenceLatchMode::ACTIVE_EDGE;
ref_switch.latch_right = tmc51x0::ReferenceLatchMode::ACTIVE_EDGE;
driver.switches.ConfigureReferenceSwitch(ref_switch);
}
Reading Latched Position
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void homeToEndstop() {
// Move toward endstop
auto mode_result = driver.rampControl.SetRampMode(tmc51x0::RampMode::VELOCITY_NEG);
if (!mode_result) {
printf("Error setting ramp mode: %s\n", mode_result.ErrorMessage());
return;
}
auto speed_result = driver.rampControl.SetMaxSpeed(500.0f);
if (!speed_result) {
printf("Error setting max speed: %s\n", speed_result.ErrorMessage());
return;
}
auto enable_result = driver.motorControl.Enable();
if (!enable_result) {
printf("Error enabling motor: %s\n", enable_result.ErrorMessage());
return;
}
// Wait for endstop (check RAMP_STAT register)
// Or use GetLatchedPosition() after switch triggers
auto latched_result = driver.switches.GetLatchedPosition(tmc51x0::Unit::Steps);
if (latched_result) {
float latched_pos_steps = latched_result.Value();
(void)latched_pos_steps;
auto set_pos_result = driver.rampControl.SetCurrentPosition(0.0f, tmc51x0::Unit::Steps); // Set as home
if (!set_pos_result) {
printf("Error setting current position: %s\n", set_pos_result.ErrorMessage());
return;
}
} else {
printf("Error reading latched position: %s\n", latched_result.ErrorMessage());
return;
}
}
Microstep Lookup Tables
Custom microstep lookup tables allow fine-tuning of microstep interpolation for smoother motion.
Default Lookup Table
The TMC51x0 (TMC5130 & TMC5160) uses a default sinusoidal lookup table. For most applications, this is sufficient.
Custom Lookup Table
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void configureCustomMicrosteps() {
// Set lookup table entries (8 entries, 32 bits each)
// Each entry defines current for a microstep segment
// Example: Custom table for smoother motion
uint32_t lut_values[8] = {
0xAAAAB554, // Entry 0
0xAAAAB554, // Entry 1
0xAAAAB554, // Entry 2
0xAAAAB554, // Entry 3
0xAAAAB554, // Entry 4
0xAAAAB554, // Entry 5
0xAAAAB554, // Entry 6
0xAAAAB554 // Entry 7
};
for (uint8_t i = 0; i < 8; i++) {
driver.motorControl.SetMicrostepLookupTable(i, lut_values[i]);
}
// Configure lookup table segmentation
driver.motorControl.SetMicrostepLookupTableSegmentation(
2, 2, 2, 2, // Width selections (0-3)
0, 0, 0 // Segment start positions
);
// Set start current
driver.motorControl.SetMicrostepLookupTableStart(0);
}
Note: Custom lookup tables require deep understanding of motor control. Most users should use the default table.
Position Comparison (X_COMPARE)
The X_COMPARE register generates a pulse when XACTUAL equals the compare value.
Use Case
1
2
3
4
5
6
7
void setupPositionPulse() {
// Generate pulse when position reaches 1000 steps
driver.events.SetXCompare(1000.0f, tmc51x0::Unit::Steps);
// The pulse appears on SWP_DIAG1 output pin
// Useful for triggering external events at specific positions
}
Lost Steps Counter
When dcStep is enabled, the driver can count lost steps.
Reading Lost Steps
1
2
3
4
5
6
7
8
void checkStepLoss() {
uint32_t lost_steps = driver.status.GetLostSteps();
if (lost_steps > 0) {
printf("Warning: %u steps lost\n", lost_steps);
// Handle step loss (re-home, adjust current, etc.)
}
}
Note: Lost steps counter only works when SD_MODE=1 (external step/dir mode).
Complete Advanced Setup Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include "tmc51x0.hpp"
void setupAdvancedMotor() {
// Basic initialization
tmc51x0::DriverConfig cfg{};
auto init_result = driver.Initialize(cfg);
if (!init_result) {
printf("Initialization error: %s\n", init_result.ErrorMessage());
return; // or handle error appropriately
}
// Configure CoolStep
tmc51x0::CoolStepConfig coolstep{};
coolstep.lower_threshold_sg = 64; // Automatically converts to SEMIN=2
coolstep.upper_threshold_sg = 256; // Automatically converts to SEMAX=5
coolstep.increment_step = tmc51x0::CoolStepIncrementStep::STEP_2;
coolstep.decrement_speed = tmc51x0::CoolStepDecrementSpeed::EVERY_2;
auto coolstep_result = driver.motorControl.ConfigureCoolStep(coolstep);
if (!coolstep_result) {
printf("Error configuring CoolStep: %s\n", coolstep_result.ErrorMessage());
return;
}
// Configure reference switches
tmc51x0::ReferenceSwitchConfig ref_switch{};
ref_switch.left_switch_active = tmc51x0::ReferenceSwitchActiveLevel::ACTIVE_LOW;
ref_switch.right_switch_active = tmc51x0::ReferenceSwitchActiveLevel::ACTIVE_LOW;
ref_switch.stop_mode = tmc51x0::ReferenceStopMode::SOFT_STOP;
ref_switch.latch_left = tmc51x0::ReferenceLatchMode::ACTIVE_EDGE;
ref_switch.latch_right = tmc51x0::ReferenceLatchMode::ACTIVE_EDGE;
auto ref_result = driver.switches.ConfigureReferenceSwitch(ref_switch);
if (!ref_result) {
printf("Error configuring reference switch: %s\n", ref_result.ErrorMessage());
return;
}
// Set mode change speeds (StealthChop, CoolStep, High-speed thresholds + unit)
auto speed_result = driver.thresholds.SetModeChangeSpeeds(
200.0f, // stealthChop threshold (TPWMTHRS)
30.0f, // CoolStep threshold (TCOOLTHRS)
300.0f, // High-speed threshold (THIGH)
tmc51x0::Unit::RPM
);
if (!speed_result) {
printf("Error setting mode change speeds: %s\n", speed_result.ErrorMessage());
return;
}
// Enable motor
auto enable_result = driver.motorControl.Enable();
if (!enable_result) {
printf("Error enabling motor: %s\n", enable_result.ErrorMessage());
return;
}
}
Troubleshooting
CoolStep Not Activating
Problem: Current doesnβt reduce despite low load
Solution:
- Verify
TCOOLTHRSis set correctly - Check that motor speed is between
TCOOLTHRSandTHIGH - Ensure StallGuard2 is properly configured
- Verify StallGuard2 threshold is appropriate
dcStep Causes Step Loss
Problem: Steps are lost when dcStep is active
Solution:
- Increase motor current
- Reduce
vdc_minthreshold - Disable dcStep if precision is critical
- Check mechanical system for binding
Reference Switches Not Working
Problem: Endstops donβt trigger stop
Solution:
- Verify switch wiring and polarity
- Check
left_switch_active/right_switch_activeare set (not DISABLED) - Verify switch signal reaches driver (check IO_INPUT register)
- Ensure
stop_modeis SOFT_STOP for smooth stopping
See Also
- Examples β Progressively harder walkthroughs including StealthChop, StallGuard, and fatigue testing
- Sensorless Homing β StallGuard2 homing and bounds finding
- API Reference β Complete method signatures for all subsystems
- ESP32 Example Source Code β Production implementations you can build and flash
Navigation <- Sensorless Homing | Next: Troubleshooting -> | Back to Index