This commit is contained in:
Timofey Titovets 2026-02-03 16:52:37 +01:00 committed by GitHub
commit 35933a0a3f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 101 additions and 77 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

@ -3755,6 +3755,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.
@ -3870,6 +3873,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.
@ -3915,6 +3921,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.
@ -3999,10 +4006,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
@ -4076,6 +4083,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.
@ -4211,6 +4221,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

@ -322,7 +322,21 @@ class TMCCommandHelper:
self.stepper_name = ' '.join(config.get_name().split()[1:])
self.name = config.get_name().split()[-1]
self.mcu_tmc = mcu_tmc
# Handle current settings
self.current_helper = current_helper
_, hold_support, max_cur = self.current_helper.get_current()
self.run_current = config.getfloat('run_current',
above=0., maxval=max_cur)
self.hold_current = None
run_cur = self.run_current
if hold_support:
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
@ -346,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,
@ -389,25 +405,68 @@ class TMCCommandHelper:
cmd_SET_TMC_CURRENT_help = "Set the current of a TMC driver"
def cmd_SET_TMC_CURRENT(self, gcmd):
ch = self.current_helper
prev_cur, prev_hold_cur, req_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)
prev_cur, prev_hold_cur, max_cur = ch.get_current()
run_current = gcmd.get_float('CURRENT', None,
minval=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
if hold_current is None:
hold_current = req_hold_cur
hold_current = prev_hold_cur
toolhead = self.printer.lookup_object('toolhead')
print_time = toolhead.get_last_move_time()
ch.set_current(run_current, hold_current, print_time)
prev_cur, prev_hold_cur, req_hold_cur, max_cur = ch.get_current()
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
@ -500,6 +559,8 @@ class TMCCommandHelper:
self.stepper_name)
# Send init
try:
ch = self.current_helper
ch.set_current(self.run_current, self.hold_current, None)
self._init_registers()
except self.printer.command_error as e:
logging.info("TMC %s failed to init: %s", self.name, str(e))
@ -512,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

@ -124,16 +124,7 @@ class TMCCurrentHelper:
self.name = config.get_name().split()[-1]
self.mcu_tmc = mcu_tmc
self.fields = mcu_tmc.get_fields()
run_current = config.getfloat('run_current',
above=0., maxval=MAX_CURRENT)
hold_current = config.getfloat('hold_current', MAX_CURRENT,
above=0., maxval=MAX_CURRENT)
self.req_hold_current = hold_current
self.sense_resistor = config.getfloat('sense_resistor', 0.110, above=0.)
vsense, irun, ihold = self._calc_current(run_current, hold_current)
self.fields.set_field("vsense", vsense)
self.fields.set_field("ihold", ihold)
self.fields.set_field("irun", irun)
def _calc_current_bits(self, current, vsense):
sense_resistor = self.sense_resistor + 0.020
vref = 0.32
@ -166,9 +157,8 @@ class TMCCurrentHelper:
vsense = self.fields.get_field("vsense")
run_current = self._calc_current_from_bits(irun, vsense)
hold_current = self._calc_current_from_bits(ihold, vsense)
return run_current, hold_current, self.req_hold_current, MAX_CURRENT
return (run_current, hold_current, MAX_CURRENT)
def set_current(self, run_current, hold_current, print_time):
self.req_hold_current = hold_current
vsense, irun, ihold = self._calc_current(run_current, hold_current)
if vsense != self.fields.get_field("vsense"):
val = self.fields.set_field("vsense", vsense)

View file

@ -280,17 +280,6 @@ class TMC2240CurrentHelper:
self.fields = mcu_tmc.get_fields()
self.Rref = config.getfloat('rref', 12000.,
minval=12000., maxval=60000.)
max_cur = self._get_ifs_rms(3)
run_current = config.getfloat('run_current', above=0., maxval=max_cur)
hold_current = config.getfloat('hold_current', max_cur,
above=0., maxval=max_cur)
self.req_hold_current = hold_current
current_range = self._calc_current_range(run_current)
self.fields.set_field("current_range", current_range)
gscaler, irun, ihold = self._calc_current(run_current, hold_current)
self.fields.set_field("globalscaler", gscaler)
self.fields.set_field("ihold", ihold)
self.fields.set_field("irun", irun)
def _get_ifs_rms(self, current_range=None):
if current_range is None:
current_range = self.fields.get_field("current_range")
@ -327,12 +316,15 @@ class TMC2240CurrentHelper:
bits = self.fields.get_field(field_name)
return globalscaler * (bits + 1) * ifs_rms / (256. * 32.)
def get_current(self):
ifs_rms = self._get_ifs_rms()
ifs_rms = self._get_ifs_rms(3)
run_current = self._calc_current_from_field("irun")
hold_current = self._calc_current_from_field("ihold")
return (run_current, hold_current, self.req_hold_current, ifs_rms)
return (run_current, hold_current, ifs_rms)
def set_current(self, run_current, hold_current, print_time):
self.req_hold_current = hold_current
current_range = self._calc_current_range(run_current)
if current_range != self.fields.get_field("current_range"):
val = self.fields.set_field("current_range", current_range)
self.mcu_tmc.set_register("DRV_CONF", val, print_time)
gscaler, irun, ihold = self._calc_current(run_current, hold_current)
val = self.fields.set_field("globalscaler", gscaler)
self.mcu_tmc.set_register("GLOBALSCALER", val, print_time)

View file

@ -118,21 +118,8 @@ class TMC2660CurrentHelper:
self.name = config.get_name().split()[-1]
self.mcu_tmc = mcu_tmc
self.fields = mcu_tmc.get_fields()
self.current = config.getfloat('run_current', minval=0.1,
maxval=MAX_CURRENT)
self.sense_resistor = config.getfloat('sense_resistor')
vsense, cs = self._calc_current(self.current)
self.fields.set_field("cs", cs)
self.fields.set_field("vsense", vsense)
# 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)
self.current = .0
def _calc_current_bits(self, current, vsense):
vref = 0.165 if vsense else 0.310
@ -157,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)
@ -177,7 +154,7 @@ class TMC2660CurrentHelper:
self.mcu_tmc.set_register("DRVCONF", val, print_time)
def get_current(self):
return self.current, None, None, MAX_CURRENT
return (self.current, None, MAX_CURRENT)
def set_current(self, run_current, hold_current, print_time):
self.current = run_current

View file

@ -268,16 +268,7 @@ class TMC5160CurrentHelper:
self.name = config.get_name().split()[-1]
self.mcu_tmc = mcu_tmc
self.fields = mcu_tmc.get_fields()
run_current = config.getfloat('run_current',
above=0., maxval=MAX_CURRENT)
hold_current = config.getfloat('hold_current', MAX_CURRENT,
above=0., maxval=MAX_CURRENT)
self.req_hold_current = hold_current
self.sense_resistor = config.getfloat('sense_resistor', 0.075, above=0.)
gscaler, irun, ihold = self._calc_current(run_current, hold_current)
self.fields.set_field("globalscaler", gscaler)
self.fields.set_field("ihold", ihold)
self.fields.set_field("irun", irun)
def _calc_globalscaler(self, current):
globalscaler = int((current * 256. * math.sqrt(2.)
* self.sense_resistor / VREF) + .5)
@ -307,9 +298,8 @@ class TMC5160CurrentHelper:
def get_current(self):
run_current = self._calc_current_from_field("irun")
hold_current = self._calc_current_from_field("ihold")
return run_current, hold_current, self.req_hold_current, MAX_CURRENT
return (run_current, hold_current, MAX_CURRENT)
def set_current(self, run_current, hold_current, print_time):
self.req_hold_current = hold_current
gscaler, irun, ihold = self._calc_current(run_current, hold_current)
val = self.fields.set_field("globalscaler", gscaler)
self.mcu_tmc.set_register("GLOBALSCALER", val, print_time)