tmc: implement ready state current reduction

Signed-off-by: Timofey Titovets <nefelim4ag@gmail.com>
This commit is contained in:
Timofey Titovets 2025-07-24 00:24:49 +02:00
parent 32b70e7536
commit 7260cca7c8
4 changed files with 74 additions and 30 deletions

View file

@ -98,7 +98,7 @@ cs_pin: PD14 # X_SPI_EN Required for communication
spi_bus: usart1 # All TMC2660 drivers are connected to USART1
run_current: 1.000
sense_resistor: 0.051
idle_current_percent: 20
ready_current: 0.5
[stepper_y]
step_pin: PD7
@ -115,7 +115,7 @@ cs_pin: PC9
spi_bus: usart1
run_current: 1.000
sense_resistor: 0.051
idle_current_percent: 20
ready_current: 0.5
[stepper_z]
step_pin: PD8

View file

@ -3752,6 +3752,9 @@ run_current:
# when the stepper is not moving. Setting a hold_current is not
# recommended (see TMC_Drivers.md for details). The default is to
# not reduce the current.
#ready_current:
# The amount of current (in amps RMS) to configure the driver to use
# when the printer is in ready state - between last move and [idle_timeout].
#sense_resistor: 0.110
# The resistance (in ohms) of the motor sense resistor. The default
# is 0.110 ohms.
@ -3867,6 +3870,9 @@ run_current:
# when the stepper is not moving. Setting a hold_current is not
# recommended (see TMC_Drivers.md for details). The default is to
# not reduce the current.
#ready_current:
# The amount of current (in amps RMS) to configure the driver to use
# when the printer is in ready state - between last move and [idle_timeout].
#sense_resistor: 0.110
# The resistance (in ohms) of the motor sense resistor. The default
# is 0.110 ohms.
@ -3912,6 +3918,7 @@ uart_pin:
#interpolate: True
run_current:
#hold_current:
#ready_current:
#sense_resistor: 0.110
#stealthchop_threshold: 0
# See the "tmc2208" section for the definition of these parameters.
@ -3996,10 +4003,10 @@ run_current:
#sense_resistor:
# The resistance (in ohms) of the motor sense resistor. This
# parameter must be provided.
#idle_current_percent: 100
# The percentage of the run_current the stepper driver will be
# lowered to when the idle timeout expires (you need to set up the
# timeout using a [idle_timeout] config section). The current will
#ready_current:
# The amount of current (in amps RMS) to configure the driver to use
# when the printer is in ready state - between last move and [idle_timeout].
# Upon move, the current will
# be raised again once the stepper has to move again. Make sure to
# set this to a high enough value such that the steppers do not lose
# their position. There is also small delay until the current is
@ -4073,6 +4080,9 @@ run_current:
# when the stepper is not moving. Setting a hold_current is not
# recommended (see TMC_Drivers.md for details). The default is to
# not reduce the current.
#ready_current:
# The amount of current (in amps RMS) to configure the driver to use
# when the printer is in ready state - between last move and [idle_timeout].
#rref: 12000
# The resistance (in ohms) of the resistor between IREF and GND. The
# default is 12000.
@ -4208,6 +4218,9 @@ run_current:
# when the stepper is not moving. Setting a hold_current is not
# recommended (see TMC_Drivers.md for details). The default is to
# not reduce the current.
#ready_current:
# The amount of current (in amps RMS) to configure the driver to use
# when the printer is in ready state - between last move and [idle_timeout].
#sense_resistor: 0.075
# The resistance (in ohms) of the motor sense resistor. The default
# is 0.075 ohms.

View file

@ -333,6 +333,10 @@ class TMCCommandHelper:
hold = config.getfloat('hold_current', run_cur,
above=0., maxval=run_cur)
self.hold_current = hold
self.ready_current = config.getfloat('ready_current', run_cur,
above=0., maxval=run_cur)
self._restore_current = [self.run_current, self.hold_current]
self._in_ready = False
self.fields = mcu_tmc.get_fields()
self.stepper = None
# Stepper phase tracking
@ -356,6 +360,8 @@ class TMCCommandHelper:
self._handle_mcu_identify)
self.printer.register_event_handler("klippy:connect",
self._handle_connect)
self.printer.register_event_handler("idle_timeout:ready",
self._handle_ready)
# Register commands
gcode = self.printer.lookup_object("gcode")
gcode.register_mux_command("SET_TMC_FIELD", "STEPPER", self.name,
@ -402,8 +408,12 @@ class TMCCommandHelper:
prev_cur, prev_hold_cur, max_cur = ch.get_current()
run_current = gcmd.get_float('CURRENT', None,
minval=0., maxval=max_cur)
hold_current = gcmd.get_float('HOLDCURRENT', None,
above=0., maxval=max_cur)
hold_current = None
if prev_hold_cur is not None:
hold_current = gcmd.get_float('HOLDCURRENT', None,
above=0., maxval=max_cur)
ready_current = gcmd.get_float('READYCURRENT', None,
above=0., maxval=max_cur)
if run_current is not None or hold_current is not None:
if run_current is None:
run_current = prev_cur
@ -413,12 +423,50 @@ class TMCCommandHelper:
print_time = toolhead.get_last_move_time()
ch.set_current(run_current, hold_current, print_time)
prev_cur, prev_hold_cur, max_cur = ch.get_current()
if ready_current is not None:
self.ready_current = ready_current
# Don't silently miss user input to change ihold upon restore
if self._in_ready and hold_current is not None:
self._restore_current[1] = hold_current
# Report values
if prev_hold_cur is None:
gcmd.respond_info("Run Current: %0.2fA" % (prev_cur))
gcmd.respond_info("Run Current: %0.2fA "
"Ready Current: %0.2fA"
% (prev_cur, self.ready_current))
else:
gcmd.respond_info("Run Current: %0.2fA Hold Current: %0.2fA"
% (prev_cur, prev_hold_cur))
gcmd.respond_info("Run Current: %0.2fA "
"Hold Current: %0.2fA "
"Ready Current: %0.2fA"
% (prev_cur, prev_hold_cur, self.ready_current))
# Handle printer ready state current reduction
def _handle_ready(self, print_time):
if self.ready_current >= self.run_current:
return
if self._in_ready:
return
ch = self.current_helper
run, hold, max_cur = ch.get_current()
self._restore_current = [run, hold]
def callback(eventtime):
if hold is not None:
ch.set_current(run, self.ready_current, print_time)
else:
#TMC2660
ch.set_current(self.ready_current, None, print_time)
self.printer.get_reactor().register_callback(callback)
self._in_ready = True
force_move = self.printer.lookup_object("force_move")
stepper = force_move.lookup_stepper(self.stepper_name)
stepper.add_active_callback(self._restore)
def _restore(self, flush_time):
if not self._in_ready:
return
ch = self.current_helper
run, hold = self._restore_current
def callback(eventtime):
ch.set_current(run, hold, flush_time)
self.printer.get_reactor().register_callback(callback)
self._in_ready = False
# Stepper phase tracking
def _get_phases(self):
return (256 >> self.fields.get_field("mres")) * 4
@ -525,7 +573,8 @@ class TMCCommandHelper:
res = {'mcu_phase_offset': self.mcu_phase_offset,
'phase_offset_position': cpos,
'run_current': current[0],
'hold_current': current[1]}
'hold_current': current[1],
'ready_current': self.ready_current}
res.update(self.echeck_helper.get_status(eventtime))
return res
# DUMP_TMC support

View file

@ -120,14 +120,6 @@ class TMC2660CurrentHelper:
self.fields = mcu_tmc.get_fields()
self.sense_resistor = config.getfloat('sense_resistor')
self.current = .0
# Register ready/printing handlers
self.idle_current_percentage = config.getint(
'idle_current_percent', default=100, minval=0, maxval=100)
if self.idle_current_percentage < 100:
self.printer.register_event_handler("idle_timeout:printing",
self._handle_printing)
self.printer.register_event_handler("idle_timeout:ready",
self._handle_ready)
def _calc_current_bits(self, current, vsense):
vref = 0.165 if vsense else 0.310
@ -152,16 +144,6 @@ class TMC2660CurrentHelper:
irun = irun2
return vsense, irun
def _handle_printing(self, print_time):
print_time -= 0.100 # Schedule slightly before deadline
self.printer.get_reactor().register_callback(
(lambda ev: self._update_current(self.current, print_time)))
def _handle_ready(self, print_time):
current = self.current * float(self.idle_current_percentage) / 100.
self.printer.get_reactor().register_callback(
(lambda ev: self._update_current(current, print_time)))
def _update_current(self, current, print_time):
vsense, cs = self._calc_current(current)
val = self.fields.set_field("cs", cs)