From e8edc8be9c1e9660f7a0476c682ca0a3baad7025 Mon Sep 17 00:00:00 2001 From: Timofey Titovets Date: Sat, 7 Feb 2026 23:59:14 +0100 Subject: [PATCH 1/3] tmc: simplify homing start/end Signed-off-by: Timofey Titovets --- klippy/extras/tmc.py | 62 +++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/klippy/extras/tmc.py b/klippy/extras/tmc.py index 23b05305e..720be2059 100644 --- a/klippy/extras/tmc.py +++ b/klippy/extras/tmc.py @@ -575,8 +575,8 @@ class TMCVirtualPinHelper: self.diag_pin = config.get('diag_pin', None) self.diag_pin_field = None self.mcu_endstop = None - self.en_pwm = False - self.pwmthrs = self.coolthrs = self.thigh = 0 + self._dirty_regs = collections.OrderedDict() + self._state = collections.OrderedDict() # Register virtual_endstop pin name_parts = config.get_name().split() ppins = self.printer.lookup_object("pins") @@ -597,56 +597,46 @@ class TMCVirtualPinHelper: self.handle_homing_move_end) self.mcu_endstop = ppins.setup_pin('endstop', self.diag_pin) return self.mcu_endstop + def set_field(self, field_name, value): + self._state[field_name] = self.fields.get_field(field_name) + reg_name = self.fields.lookup_register(field_name) + self._dirty_regs[reg_name] = self.fields.set_field(field_name, value) + def flush(self): + regs = self._dirty_regs + self._dirty_regs = {} + for k in list(regs.keys()): + reg_val = regs[k] + self.mcu_tmc.set_register(k, reg_val) def handle_homing_move_begin(self, hmove): if self.mcu_endstop not in hmove.get_mcu_endstops(): return # Enable/disable stealthchop - self.pwmthrs = self.fields.get_field("tpwmthrs") reg = self.fields.lookup_register("en_pwm_mode", None) if reg is None: # On "stallguard4" drivers, "stealthchop" must be enabled - self.en_pwm = not self.fields.get_field("en_spreadcycle") - tp_val = self.fields.set_field("tpwmthrs", 0) - self.mcu_tmc.set_register("TPWMTHRS", tp_val) - val = self.fields.set_field("en_spreadcycle", 0) + self.set_field("tpwmthrs", 0) + self.set_field("en_spreadcycle", 0) else: # On earlier drivers, "stealthchop" must be disabled - self.en_pwm = self.fields.get_field("en_pwm_mode") - self.fields.set_field("en_pwm_mode", 0) - val = self.fields.set_field(self.diag_pin_field, 1) - self.mcu_tmc.set_register("GCONF", val) + self.set_field("en_pwm_mode", 0) + self.set_field(self.diag_pin_field, 1) # Enable tcoolthrs (if not already) - self.coolthrs = self.fields.get_field("tcoolthrs") - if self.coolthrs == 0: - tc_val = self.fields.set_field("tcoolthrs", 0xfffff) - self.mcu_tmc.set_register("TCOOLTHRS", tc_val) + self.set_field("tcoolthrs", 0xfffff) # Disable thigh reg = self.fields.lookup_register("thigh", None) if reg is not None: - self.thigh = self.fields.get_field("thigh") - th_val = self.fields.set_field("thigh", 0) - self.mcu_tmc.set_register(reg, th_val) + self.set_field("thigh", 0) + self.flush() def handle_homing_move_end(self, hmove): if self.mcu_endstop not in hmove.get_mcu_endstops(): return - # Restore stealthchop/spreadcycle - reg = self.fields.lookup_register("en_pwm_mode", None) - if reg is None: - tp_val = self.fields.set_field("tpwmthrs", self.pwmthrs) - self.mcu_tmc.set_register("TPWMTHRS", tp_val) - val = self.fields.set_field("en_spreadcycle", not self.en_pwm) - else: - self.fields.set_field("en_pwm_mode", self.en_pwm) - val = self.fields.set_field(self.diag_pin_field, 0) - self.mcu_tmc.set_register("GCONF", val) - # Restore tcoolthrs - tc_val = self.fields.set_field("tcoolthrs", self.coolthrs) - self.mcu_tmc.set_register("TCOOLTHRS", tc_val) - # Restore thigh - reg = self.fields.lookup_register("thigh", None) - if reg is not None: - th_val = self.fields.set_field("thigh", self.thigh) - self.mcu_tmc.set_register(reg, th_val) + # Restore previous state + fields = self._state + self._state = collections.OrderedDict() + for field in list(fields.keys()): + val = fields[field] + self.set_field(field, val) + self.flush() ###################################################################### From a94bbf98808e94bd75ef6dcf7b2a0d8412a999d1 Mon Sep 17 00:00:00 2001 From: Timofey Titovets Date: Sat, 7 Feb 2026 23:19:03 +0100 Subject: [PATCH 2/3] tmc2240: allow enable SG4 threshold Signed-off-by: Timofey Titovets --- docs/Config_Reference.md | 5 +++-- klippy/extras/tmc2240.py | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index 8b17d9502..200b9de11 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -4163,6 +4163,7 @@ run_current: #driver_SEDN: 0 #driver_SEIMIN: 0 #driver_SFILT: 0 +#driver_SG4_THRS: 0 #driver_SG4_ANGLE_OFFSET: 1 #driver_SLOPE_CONTROL: 0 # Set the given register during the configuration of the TMC2240 @@ -4176,8 +4177,8 @@ run_current: # is "active low" and is thus normally prefaced with "^!". Setting # this creates a "tmc2240_stepper_x:virtual_endstop" virtual pin # which may be used as the stepper's endstop_pin. Doing this enables -# "sensorless homing". (Be sure to also set driver_SGT to an -# appropriate sensitivity value.) The default is to not enable +# "sensorless homing". (Be sure to also set driver_SGT OR driver_SG4_THRS +# to an appropriate sensitivity value.) The default is to not enable # sensorless homing. ``` diff --git a/klippy/extras/tmc2240.py b/klippy/extras/tmc2240.py index d57a93b83..2f114c2aa 100644 --- a/klippy/extras/tmc2240.py +++ b/klippy/extras/tmc2240.py @@ -411,6 +411,7 @@ class TMC2240: # TPOWERDOWN set_config_field(config, "tpowerdown", 10) # SG4_THRS + set_config_field(config, "sg4_thrs", 0) set_config_field(config, "sg4_angle_offset", 1) # DRV_CONF set_config_field(config, "slope_control", 0) From d6247b4d0f897b148cf278fdda727a1c6e2c749f Mon Sep 17 00:00:00 2001 From: Timofey Titovets Date: Sun, 8 Feb 2026 00:12:56 +0100 Subject: [PATCH 3/3] tmc: support tmc2240 sg4 homing Signed-off-by: Timofey Titovets --- klippy/extras/tmc.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/klippy/extras/tmc.py b/klippy/extras/tmc.py index 720be2059..2b8b9eeea 100644 --- a/klippy/extras/tmc.py +++ b/klippy/extras/tmc.py @@ -612,14 +612,22 @@ class TMCVirtualPinHelper: return # Enable/disable stealthchop reg = self.fields.lookup_register("en_pwm_mode", None) + sg4_thrs = 0 + if self.fields.lookup_register("sg4_thrs", None) is not None: + sg4_thrs = self.fields.get_field("sg4_thrs") if reg is None: # On "stallguard4" drivers, "stealthchop" must be enabled self.set_field("tpwmthrs", 0) self.set_field("en_spreadcycle", 0) - else: + elif sg4_thrs == 0: # On earlier drivers, "stealthchop" must be disabled self.set_field("en_pwm_mode", 0) self.set_field(self.diag_pin_field, 1) + else: + # TMC2240 in SG4 + self.set_field("en_pwm_mode", 1) + self.set_field("tpwmthrs", 0) + self.set_field(self.diag_pin_field, 1) # Enable tcoolthrs (if not already) self.set_field("tcoolthrs", 0xfffff) # Disable thigh