diff options
Diffstat (limited to 'klippy/extras/tmc.py')
-rw-r--r-- | klippy/extras/tmc.py | 321 |
1 files changed, 203 insertions, 118 deletions
diff --git a/klippy/extras/tmc.py b/klippy/extras/tmc.py index aad19cf4..4a7bcc9c 100644 --- a/klippy/extras/tmc.py +++ b/klippy/extras/tmc.py @@ -12,23 +12,29 @@ from . import bulk_sensor # Field helpers ###################################################################### + # Return the position of the first bit set in a mask def ffs(mask): return (mask & -mask).bit_length() - 1 + class FieldHelper: - def __init__(self, all_fields, signed_fields=[], field_formatters={}, - registers=None): + def __init__( + self, all_fields, signed_fields=[], field_formatters={}, registers=None + ): self.all_fields = all_fields self.signed_fields = {sf: 1 for sf in signed_fields} self.field_formatters = field_formatters self.registers = registers if self.registers is None: self.registers = collections.OrderedDict() - self.field_to_register = { f: r for r, fields in self.all_fields.items() - for f in fields } + self.field_to_register = { + f: r for r, fields in self.all_fields.items() for f in fields + } + def lookup_register(self, field_name, default=None): return self.field_to_register.get(field_name, default) + def get_field(self, field_name, reg_value=None, reg_name=None): # Returns value of the register field if reg_name is None: @@ -37,9 +43,10 @@ class FieldHelper: reg_value = self.registers.get(reg_name, 0) mask = self.all_fields[reg_name][field_name] field_value = (reg_value & mask) >> ffs(mask) - if field_name in self.signed_fields and ((reg_value & mask)<<1) > mask: - field_value -= (1 << field_value.bit_length()) + if field_name in self.signed_fields and ((reg_value & mask) << 1) > mask: + field_value -= 1 << field_value.bit_length() return field_value + def set_field(self, field_name, field_value, reg_value=None, reg_name=None): # Returns register value with field bits filled with supplied value if reg_name is None: @@ -50,6 +57,7 @@ class FieldHelper: new_value = (reg_value & ~mask) | ((field_value << ffs(mask)) & mask) self.registers[reg_name] = new_value return new_value + def set_config_field(self, config, field_name, default): # Allow a field to be set from the config file config_name = "driver_" + field_name.upper() @@ -59,11 +67,13 @@ class FieldHelper: if maxval == 1: val = config.getboolean(config_name, default) elif field_name in self.signed_fields: - val = config.getint(config_name, default, - minval=-(maxval//2 + 1), maxval=maxval//2) + val = config.getint( + config_name, default, minval=-(maxval // 2 + 1), maxval=maxval // 2 + ) else: val = config.getint(config_name, default, minval=0, maxval=maxval) return self.set_field(field_name, val) + def pretty_format(self, reg_name, reg_value): # Provide a string description of a register reg_fields = self.all_fields.get(reg_name, {}) @@ -75,22 +85,26 @@ class FieldHelper: if sval and sval != "0": fields.append(" %s=%s" % (field_name, sval)) return "%-11s %08x%s" % (reg_name + ":", reg_value, "".join(fields)) + def get_reg_fields(self, reg_name, reg_value): # Provide fields found in a register reg_fields = self.all_fields.get(reg_name, {}) - return {field_name: self.get_field(field_name, reg_value, reg_name) - for field_name, mask in reg_fields.items()} + return { + field_name: self.get_field(field_name, reg_value, reg_name) + for field_name, mask in reg_fields.items() + } ###################################################################### # Periodic error checking ###################################################################### + class TMCErrorCheck: def __init__(self, config, mcu_tmc): self.printer = config.get_printer() name_parts = config.get_name().split() - self.stepper_name = ' '.join(name_parts[1:]) + self.stepper_name = " ".join(name_parts[1:]) self.mcu_tmc = mcu_tmc self.fields = mcu_tmc.get_fields() self.check_timer = None @@ -98,7 +112,7 @@ class TMCErrorCheck: # Setup for GSTAT query reg_name = self.fields.lookup_register("drv_err") if reg_name is not None: - self.gstat_reg_info = [0, reg_name, 0xffffffff, 0xffffffff, 0] + self.gstat_reg_info = [0, reg_name, 0xFFFFFFFF, 0xFFFFFFFF, 0] else: self.gstat_reg_info = None self.clear_gstat = True @@ -106,11 +120,11 @@ class TMCErrorCheck: self.irun_field = "irun" reg_name = "DRV_STATUS" mask = err_mask = cs_actual_mask = 0 - if name_parts[0] == 'tmc2130': + if name_parts[0] == "tmc2130": # TMC2130 driver quirks self.clear_gstat = False cs_actual_mask = self.fields.all_fields[reg_name]["cs_actual"] - elif name_parts[0] == 'tmc2660': + elif name_parts[0] == "tmc2660": # TMC2660 driver quirks self.irun_field = "cs" reg_name = "READRSP@RDSEL2" @@ -127,8 +141,9 @@ class TMCErrorCheck: self.adc_temp = None self.adc_temp_reg = self.fields.lookup_register("adc_temp") if self.adc_temp_reg is not None: - pheaters = self.printer.load_object(config, 'heaters') + pheaters = self.printer.load_object(config, "heaters") pheaters.register_monitor(config) + def _query_register(self, reg_info, try_clear=False): last_value, reg_name, mask, err_mask, cs_actual_mask = reg_info cleared_flags = 0 @@ -154,20 +169,21 @@ class TMCErrorCheck: irun = self.fields.get_field(self.irun_field) if self.check_timer is None or irun < 4: break - if (self.irun_field == "irun" - and not self.fields.get_field("ihold")): + if self.irun_field == "irun" and not self.fields.get_field("ihold"): break # CS_ACTUAL field of zero - indicates a driver reset count += 1 if count >= 3: fmt = self.fields.pretty_format(reg_name, val) - raise self.printer.command_error("TMC '%s' reports error: %s" - % (self.stepper_name, fmt)) + raise self.printer.command_error( + "TMC '%s' reports error: %s" % (self.stepper_name, fmt) + ) if try_clear and val & err_mask: try_clear = False cleared_flags |= val & err_mask self.mcu_tmc.set_register(reg_name, val & err_mask) return cleared_flags + def _query_temperature(self): try: self.adc_temp = self.mcu_tmc.get_register(self.adc_temp_reg) @@ -175,6 +191,7 @@ class TMCErrorCheck: # Ignore comms error for temperature self.adc_temp = None return + def _do_periodic_check(self, eventtime): try: self._query_register(self.drv_status_reg_info) @@ -185,32 +202,37 @@ class TMCErrorCheck: except self.printer.command_error as e: self.printer.invoke_shutdown(str(e)) return self.printer.get_reactor().NEVER - return eventtime + 1. + return eventtime + 1.0 + def stop_checks(self): if self.check_timer is None: return self.printer.get_reactor().unregister_timer(self.check_timer) self.check_timer = None + def start_checks(self): if self.check_timer is not None: self.stop_checks() cleared_flags = 0 self._query_register(self.drv_status_reg_info) if self.gstat_reg_info is not None: - cleared_flags = self._query_register(self.gstat_reg_info, - try_clear=self.clear_gstat) + cleared_flags = self._query_register( + self.gstat_reg_info, try_clear=self.clear_gstat + ) reactor = self.printer.get_reactor() curtime = reactor.monotonic() - self.check_timer = reactor.register_timer(self._do_periodic_check, - curtime + 1.) + self.check_timer = reactor.register_timer( + self._do_periodic_check, curtime + 1.0 + ) if cleared_flags: reset_mask = self.fields.all_fields["GSTAT"]["reset"] if cleared_flags & reset_mask: return True return False + def get_status(self, eventtime=None): if self.check_timer is None: - return {'drv_status': None, 'temperature': None} + return {"drv_status": None, "temperature": None} temp = None if self.adc_temp is not None: temp = round((self.adc_temp - 2038) / 7.7, 2) @@ -219,16 +241,18 @@ class TMCErrorCheck: self.last_drv_status = last_value fields = self.fields.get_reg_fields(reg_name, last_value) self.last_drv_fields = {n: v for n, v in fields.items() if v} - return {'drv_status': self.last_drv_fields, 'temperature': temp} + return {"drv_status": self.last_drv_fields, "temperature": temp} + ###################################################################### # Record driver status ###################################################################### + class TMCStallguardDump: def __init__(self, config, mcu_tmc): self.printer = config.get_printer() - self.stepper_name = ' '.join(config.get_name().split()[1:]) + self.stepper_name = " ".join(config.get_name().split()[1:]) self.mcu_tmc = mcu_tmc self.mcu = self.mcu_tmc.get_mcu() self.fields = self.mcu_tmc.get_fields() @@ -256,29 +280,33 @@ class TMCStallguardDump: self.query_timer = None self.error = None self.batch_bulk = bulk_sensor.BatchBulkHelper( - self.printer, self._dump, self._start, self._stop) - api_resp = {'header': ('time', 'sg_result', 'cs_actual')} - self.batch_bulk.add_mux_endpoint("tmc/stallguard_dump", "name", - self.stepper_name, api_resp) + self.printer, self._dump, self._start, self._stop + ) + api_resp = {"header": ("time", "sg_result", "cs_actual")} + self.batch_bulk.add_mux_endpoint( + "tmc/stallguard_dump", "name", self.stepper_name, api_resp + ) + def _start(self): self.error = None status = self.mcu_tmc.get_register_raw("DRV_STATUS") if status.get("spi_status"): self.optimized_spi = True reactor = self.printer.get_reactor() - self.query_timer = reactor.register_timer(self._query_tmc, - reactor.NOW) + self.query_timer = reactor.register_timer(self._query_tmc, reactor.NOW) + def _stop(self): self.printer.get_reactor().unregister_timer(self.query_timer) self.query_timer = None self.samples = [] + def _query_tmc(self, eventtime): sg_result = -1 cs_actual = -1 recv_time = eventtime try: if self.optimized_spi or self.sg4_reg_name == "SG4_RESULT": - #TMC2130/TMC5160/TMC2240 + # TMC2130/TMC5160/TMC2240 status = self.mcu_tmc.get_register_raw("DRV_STATUS") reg_val = status["data"] cs_actual = self.fields.get_field("cs_actual", reg_val) @@ -304,22 +332,24 @@ class TMCStallguardDump: return eventtime + 0.001 # UART queried as fast as possible return eventtime + 0.005 + def _dump(self, eventtime): - if self.error: - raise self.error - samples = self.samples - self.samples = [] - return {"data": samples} + if self.error: + raise self.error + samples = self.samples + self.samples = [] + return {"data": samples} ###################################################################### # G-Code command helpers ###################################################################### + class TMCCommandHelper: def __init__(self, config, mcu_tmc, current_helper): self.printer = config.get_printer() - self.stepper_name = ' '.join(config.get_name().split()[1:]) + self.stepper_name = " ".join(config.get_name().split()[1:]) self.name = config.get_name().split()[-1] self.mcu_tmc = mcu_tmc self.current_helper = current_helper @@ -331,69 +361,87 @@ class TMCCommandHelper: self.mcu_phase_offset = None self.stepper = None self.stepper_enable = self.printer.load_object(config, "stepper_enable") - self.printer.register_event_handler("stepper:sync_mcu_position", - self._handle_sync_mcu_pos) - self.printer.register_event_handler("stepper:set_sdir_inverted", - self._handle_sync_mcu_pos) - self.printer.register_event_handler("klippy:mcu_identify", - self._handle_mcu_identify) - self.printer.register_event_handler("klippy:connect", - self._handle_connect) + self.printer.register_event_handler( + "stepper:sync_mcu_position", self._handle_sync_mcu_pos + ) + self.printer.register_event_handler( + "stepper:set_sdir_inverted", self._handle_sync_mcu_pos + ) + self.printer.register_event_handler( + "klippy:mcu_identify", self._handle_mcu_identify + ) + self.printer.register_event_handler("klippy:connect", self._handle_connect) # Set microstep config options TMCMicrostepHelper(config, mcu_tmc) # Register commands gcode = self.printer.lookup_object("gcode") - gcode.register_mux_command("SET_TMC_FIELD", "STEPPER", self.name, - self.cmd_SET_TMC_FIELD, - desc=self.cmd_SET_TMC_FIELD_help) - gcode.register_mux_command("INIT_TMC", "STEPPER", self.name, - self.cmd_INIT_TMC, - desc=self.cmd_INIT_TMC_help) - gcode.register_mux_command("SET_TMC_CURRENT", "STEPPER", self.name, - self.cmd_SET_TMC_CURRENT, - desc=self.cmd_SET_TMC_CURRENT_help) + gcode.register_mux_command( + "SET_TMC_FIELD", + "STEPPER", + self.name, + self.cmd_SET_TMC_FIELD, + desc=self.cmd_SET_TMC_FIELD_help, + ) + gcode.register_mux_command( + "INIT_TMC", + "STEPPER", + self.name, + self.cmd_INIT_TMC, + desc=self.cmd_INIT_TMC_help, + ) + gcode.register_mux_command( + "SET_TMC_CURRENT", + "STEPPER", + self.name, + self.cmd_SET_TMC_CURRENT, + desc=self.cmd_SET_TMC_CURRENT_help, + ) + def _init_registers(self, print_time=None): # Send registers for reg_name in list(self.fields.registers.keys()): - val = self.fields.registers[reg_name] # Val may change during loop + val = self.fields.registers[reg_name] # Val may change during loop self.mcu_tmc.set_register(reg_name, val, print_time) + cmd_INIT_TMC_help = "Initialize TMC stepper driver registers" + def cmd_INIT_TMC(self, gcmd): logging.info("INIT_TMC %s", self.name) - print_time = self.printer.lookup_object('toolhead').get_last_move_time() + print_time = self.printer.lookup_object("toolhead").get_last_move_time() self._init_registers(print_time) + cmd_SET_TMC_FIELD_help = "Set a register field of a TMC driver" + def cmd_SET_TMC_FIELD(self, gcmd): - field_name = gcmd.get('FIELD').lower() + field_name = gcmd.get("FIELD").lower() reg_name = self.fields.lookup_register(field_name, None) if reg_name is None: raise gcmd.error("Unknown field name '%s'" % (field_name,)) - value = gcmd.get_int('VALUE', None) - velocity = gcmd.get_float('VELOCITY', None, minval=0.) + value = gcmd.get_int("VALUE", None) + velocity = gcmd.get_float("VELOCITY", None, minval=0.0) if (value is None) == (velocity is None): raise gcmd.error("Specify either VALUE or VELOCITY") if velocity is not None: if self.mcu_tmc.get_tmc_frequency() is None: - raise gcmd.error( - "VELOCITY parameter not supported by this driver") - value = TMCtstepHelper(self.mcu_tmc, velocity, - pstepper=self.stepper) + raise gcmd.error("VELOCITY parameter not supported by this driver") + value = TMCtstepHelper(self.mcu_tmc, velocity, pstepper=self.stepper) reg_val = self.fields.set_field(field_name, value) - print_time = self.printer.lookup_object('toolhead').get_last_move_time() + print_time = self.printer.lookup_object("toolhead").get_last_move_time() self.mcu_tmc.set_register(reg_name, reg_val, print_time) + 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) + run_current = gcmd.get_float("CURRENT", None, minval=0.0, maxval=max_cur) + hold_current = gcmd.get_float("HOLDCURRENT", None, above=0.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 - toolhead = self.printer.lookup_object('toolhead') + 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() @@ -401,13 +449,17 @@ class TMCCommandHelper: if prev_hold_cur is None: gcmd.respond_info("Run Current: %0.2fA" % (prev_cur,)) 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" % (prev_cur, prev_hold_cur) + ) + # Stepper phase tracking def _get_phases(self): return (256 >> self.fields.get_field("mres")) * 4 + def get_phase_offset(self): return self.mcu_phase_offset, self._get_phases() + def _query_phase(self): field_name = "mscnt" if self.fields.lookup_register(field_name, None) is None: @@ -415,6 +467,7 @@ class TMCCommandHelper: field_name = "mstep" reg = self.mcu_tmc.get_register(self.fields.lookup_register(field_name)) return self.fields.get_field(field_name, reg) + def _handle_sync_mcu_pos(self, stepper): if stepper.get_name() != self.stepper_name: return @@ -430,12 +483,17 @@ class TMCCommandHelper: if not stepper.get_dir_inverted()[0]: driver_phase = 1023 - driver_phase phases = self._get_phases() - phase = int(float(driver_phase) / 1024 * phases + .5) % phases + phase = int(float(driver_phase) / 1024 * phases + 0.5) % phases moff = (phase - stepper.get_mcu_position()) % phases if self.mcu_phase_offset is not None and self.mcu_phase_offset != moff: - logging.warning("Stepper %s phase change (was %d now %d)", - self.stepper_name, self.mcu_phase_offset, moff) + logging.warning( + "Stepper %s phase change (was %d now %d)", + self.stepper_name, + self.mcu_phase_offset, + moff, + ) self.mcu_phase_offset = moff + # Stepper enable/disable tracking def _do_enable(self, print_time): try: @@ -453,12 +511,14 @@ class TMCCommandHelper: with gcode.get_mutex(): if self.mcu_phase_offset is not None: return - logging.info("Pausing toolhead to calculate %s phase offset", - self.stepper_name) - self.printer.lookup_object('toolhead').wait_moves() + logging.info( + "Pausing toolhead to calculate %s phase offset", self.stepper_name + ) + self.printer.lookup_object("toolhead").wait_moves() self._handle_sync_mcu_pos(self.stepper) except self.printer.command_error as e: self.printer.invoke_shutdown(str(e)) + def _do_disable(self, print_time): try: if self.toff is not None: @@ -468,18 +528,21 @@ class TMCCommandHelper: self.echeck_helper.stop_checks() except self.printer.command_error as e: self.printer.invoke_shutdown(str(e)) + def _handle_mcu_identify(self): # Lookup stepper object force_move = self.printer.lookup_object("force_move") self.stepper = force_move.lookup_stepper(self.stepper_name) # Note pulse duration and step_both_edge optimizations available - self.stepper.setup_default_pulse_duration(.000000100, True) + self.stepper.setup_default_pulse_duration(0.000000100, True) + def _handle_stepper_enable(self, print_time, is_enable): if is_enable: - cb = (lambda ev: self._do_enable(print_time)) + cb = lambda ev: self._do_enable(print_time) else: - cb = (lambda ev: self._do_disable(print_time)) + cb = lambda ev: self._do_disable(print_time) self.printer.get_reactor().register_callback(cb) + def _handle_connect(self): # Check if using step on both edges optimization pulse_duration, step_both_edge = self.stepper.get_pulse_duration() @@ -491,37 +554,46 @@ class TMCCommandHelper: if not enable_line.has_dedicated_enable(): self.toff = self.fields.get_field("toff") self.fields.set_field("toff", 0) - logging.info("Enabling TMC virtual enable for '%s'", - self.stepper_name) + logging.info("Enabling TMC virtual enable for '%s'", self.stepper_name) # Send init try: self._init_registers() except self.printer.command_error as e: logging.info("TMC %s failed to init: %s", self.name, str(e)) + # get_status information export def get_status(self, eventtime=None): cpos = None if self.stepper is not None and self.mcu_phase_offset is not None: cpos = self.stepper.mcu_to_commanded_position(self.mcu_phase_offset) current = self.current_helper.get_current() - res = {'mcu_phase_offset': self.mcu_phase_offset, - 'phase_offset_position': cpos, - 'run_current': current[0], - 'hold_current': current[1]} + res = { + "mcu_phase_offset": self.mcu_phase_offset, + "phase_offset_position": cpos, + "run_current": current[0], + "hold_current": current[1], + } res.update(self.echeck_helper.get_status(eventtime)) return res + # DUMP_TMC support def setup_register_dump(self, read_registers, read_translate=None): self.read_registers = read_registers self.read_translate = read_translate gcode = self.printer.lookup_object("gcode") - gcode.register_mux_command("DUMP_TMC", "STEPPER", self.name, - self.cmd_DUMP_TMC, - desc=self.cmd_DUMP_TMC_help) + gcode.register_mux_command( + "DUMP_TMC", + "STEPPER", + self.name, + self.cmd_DUMP_TMC, + desc=self.cmd_DUMP_TMC_help, + ) + cmd_DUMP_TMC_help = "Read and display TMC stepper driver registers" + def cmd_DUMP_TMC(self, gcmd): logging.info("DUMP_TMC %s", self.name) - reg_name = gcmd.get('REGISTER', None) + reg_name = gcmd.get("REGISTER", None) if reg_name is not None: reg_name = reg_name.upper() val = self.fields.registers.get(reg_name) @@ -553,21 +625,22 @@ class TMCCommandHelper: # TMC virtual pins ###################################################################### + # Helper class for "sensorless homing" class TMCVirtualPinHelper: def __init__(self, config, mcu_tmc): self.printer = config.get_printer() self.mcu_tmc = mcu_tmc self.fields = mcu_tmc.get_fields() - if self.fields.lookup_register('diag0_stall') is not None: - if config.get('diag0_pin', None) is not None: - self.diag_pin = config.get('diag0_pin') - self.diag_pin_field = 'diag0_stall' + if self.fields.lookup_register("diag0_stall") is not None: + if config.get("diag0_pin", None) is not None: + self.diag_pin = config.get("diag0_pin") + self.diag_pin_field = "diag0_stall" else: - self.diag_pin = config.get('diag1_pin', None) - self.diag_pin_field = 'diag1_stall' + self.diag_pin = config.get("diag1_pin", None) + self.diag_pin_field = "diag1_stall" else: - self.diag_pin = config.get('diag_pin', None) + self.diag_pin = config.get("diag_pin", None) self.diag_pin_field = None self.mcu_endstop = None self.en_pwm = False @@ -576,22 +649,26 @@ class TMCVirtualPinHelper: name_parts = config.get_name().split() ppins = self.printer.lookup_object("pins") ppins.register_chip("%s_%s" % (name_parts[0], name_parts[-1]), self) + def setup_pin(self, pin_type, pin_params): # Validate pin - ppins = self.printer.lookup_object('pins') - if pin_type != 'endstop' or pin_params['pin'] != 'virtual_endstop': + ppins = self.printer.lookup_object("pins") + if pin_type != "endstop" or pin_params["pin"] != "virtual_endstop": raise ppins.error("tmc virtual endstop only useful as endstop") - if pin_params['invert'] or pin_params['pullup']: + if pin_params["invert"] or pin_params["pullup"]: raise ppins.error("Can not pullup/invert tmc virtual pin") if self.diag_pin is None: raise ppins.error("tmc virtual endstop requires diag pin config") # Setup for sensorless homing - self.printer.register_event_handler("homing:homing_move_begin", - self.handle_homing_move_begin) - self.printer.register_event_handler("homing:homing_move_end", - self.handle_homing_move_end) - self.mcu_endstop = ppins.setup_pin('endstop', self.diag_pin) + self.printer.register_event_handler( + "homing:homing_move_begin", self.handle_homing_move_begin + ) + self.printer.register_event_handler( + "homing:homing_move_end", self.handle_homing_move_end + ) + self.mcu_endstop = ppins.setup_pin("endstop", self.diag_pin) return self.mcu_endstop + def handle_homing_move_begin(self, hmove): if self.mcu_endstop not in hmove.get_mcu_endstops(): return @@ -613,7 +690,7 @@ class TMCVirtualPinHelper: # Enable tcoolthrs (if not already) self.coolthrs = self.fields.get_field("tcoolthrs") if self.coolthrs == 0: - tc_val = self.fields.set_field("tcoolthrs", 0xfffff) + tc_val = self.fields.set_field("tcoolthrs", 0xFFFFF) self.mcu_tmc.set_register("TCOOLTHRS", tc_val) # Disable thigh reg = self.fields.lookup_register("thigh", None) @@ -621,6 +698,7 @@ class TMCVirtualPinHelper: self.thigh = self.fields.get_field("thigh") th_val = self.fields.set_field("thigh", 0) self.mcu_tmc.set_register(reg, th_val) + def handle_homing_move_end(self, hmove): if self.mcu_endstop not in hmove.get_mcu_endstops(): return @@ -648,6 +726,7 @@ class TMCVirtualPinHelper: # Config reading helpers ###################################################################### + # Helper to initialize the wave table from config or defaults def TMCWaveTableHelper(config, mcu_tmc): set_config_field = mcu_tmc.get_fields().set_config_field @@ -669,6 +748,7 @@ def TMCWaveTableHelper(config, mcu_tmc): set_config_field(config, "start_sin", 0) set_config_field(config, "start_sin90", 247) + # Helper to configure the microstep settings def TMCMicrostepHelper(config, mcu_tmc): fields = mcu_tmc.get_fields() @@ -676,17 +756,19 @@ def TMCMicrostepHelper(config, mcu_tmc): if not config.has_section(stepper_name): raise config.error( "Could not find config section '[%s]' required by tmc driver" - % (stepper_name,)) + % (stepper_name,) + ) sconfig = config.getsection(stepper_name) steps = {256: 0, 128: 1, 64: 2, 32: 3, 16: 4, 8: 5, 4: 6, 2: 7, 1: 8} - mres = sconfig.getchoice('microsteps', steps) + mres = sconfig.getchoice("microsteps", steps) fields.set_field("mres", mres) fields.set_field("intpol", config.getboolean("interpolate", True)) + # Helper for calculating TSTEP based values from velocity def TMCtstepHelper(mcu_tmc, velocity, pstepper=None, config=None): - if velocity <= 0.: - return 0xfffff + if velocity <= 0.0: + return 0xFFFFF if pstepper is not None: step_dist = pstepper.get_step_dist() else: @@ -697,15 +779,16 @@ def TMCtstepHelper(mcu_tmc, velocity, pstepper=None, config=None): mres = mcu_tmc.get_fields().get_field("mres") step_dist_256 = step_dist / (1 << mres) tmc_freq = mcu_tmc.get_tmc_frequency() - threshold = int(tmc_freq * step_dist_256 / velocity + .5) - return max(0, min(0xfffff, threshold)) + threshold = int(tmc_freq * step_dist_256 / velocity + 0.5) + return max(0, min(0xFFFFF, threshold)) + # Helper to configure stealthChop-spreadCycle transition velocity def TMCStealthchopHelper(config, mcu_tmc): fields = mcu_tmc.get_fields() en_pwm_mode = False - velocity = config.getfloat('stealthchop_threshold', None, minval=0.) - tpwmthrs = 0xfffff + velocity = config.getfloat("stealthchop_threshold", None, minval=0.0) + tpwmthrs = 0xFFFFF if velocity is not None: en_pwm_mode = True @@ -719,20 +802,22 @@ def TMCStealthchopHelper(config, mcu_tmc): # TMC2208 uses en_spreadCycle fields.set_field("en_spreadcycle", not en_pwm_mode) + # Helper to configure StallGuard and CoolStep minimum velocity def TMCVcoolthrsHelper(config, mcu_tmc): fields = mcu_tmc.get_fields() - velocity = config.getfloat('coolstep_threshold', None, minval=0.) + velocity = config.getfloat("coolstep_threshold", None, minval=0.0) tcoolthrs = 0 if velocity is not None: tcoolthrs = TMCtstepHelper(mcu_tmc, velocity, config=config) fields.set_field("tcoolthrs", tcoolthrs) + # Helper to configure StallGuard and CoolStep maximum velocity and # SpreadCycle-FullStepping (High velocity) mode threshold. def TMCVhighHelper(config, mcu_tmc): fields = mcu_tmc.get_fields() - velocity = config.getfloat('high_velocity_threshold', None, minval=0.) + velocity = config.getfloat("high_velocity_threshold", None, minval=0.0) thigh = 0 if velocity is not None: thigh = TMCtstepHelper(mcu_tmc, velocity, config=config) |