diff --git a/config/example-extras.cfg b/config/example-extras.cfg index c10d2732..29255c48 100644 --- a/config/example-extras.cfg +++ b/config/example-extras.cfg @@ -741,8 +741,8 @@ #[tmc2660 stepper_x] #cs_pin: # The pin corresponding to the TMC2660 chip select line. This pin -# will be set to low at the start of SPI messages and raised to high -# after the message completes. This parameter must be provided. +# will be set to low at the start of SPI messages and set to high +# after the message transfer completes. This parameter must be provided. #bus: # Select the SPI bus the TMC2660 stepper driver is connected to. This # depends on the physical connections on your board, as well as the @@ -760,20 +760,17 @@ # step at a rate of 256 micro-steps). This only works if microsteps # is set to 16. The default is True. #run_current: -# The amount of current (in amps) to configure the driver to use -# during stepper movement. This parameter must be provided. -#idle_timeout: 0 -# The amount of time in seconds after which the run_current of the -# stepper driver will be lowered to this percentage of run_current. -# Set to 0 to disable the idle timeout. The default is 0. -#idle_current_percent: 30 +# The amount of current (in ampere) used by the driver during stepper +# movement. This parameter must be provided. +#idle_current_percent: 100 # The percentage of the run_current the stepper driver will be -# lowered to after the idle_timeout has expired. The current will +# lowered to when the idle timeout expires (you need to set up the +# timeout using a [idle_timeout] config section). 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 a delay of up to 100 ms until the -# current is raised again, so take this into account commanding fast -# moves when the stepper is idling. The default is 30. +# their position. There is also small delay until the current is +# raised again, so take this into account when commanding fast moves +# while the stepper is idling. The default is 100 (no reduction). #driver_DEDGE: False #driver_TBL: 36 # Valid values are 16, 24, 36, 54. @@ -804,10 +801,10 @@ #driver_VSENSE: high # Valid values are 'high' and 'low' # -# Set the given register during the configuration of the TMC2660 -# chip. This may be used to set custom motor parameters. The +# Set the given parameter during the configuration of the TMC2660 +# chip. This may be used to set custom driver parameters. The # defaults for each parameter are next to the parameter name in the -# above list. See the TMC2660 datasheet about what each parameter +# list above. See the TMC2660 datasheet about what each parameter # does and what the restrictions on parameter combinations are. diff --git a/klippy/extras/tmc2660.py b/klippy/extras/tmc2660.py index 6f14f7ac..373c3f07 100644 --- a/klippy/extras/tmc2660.py +++ b/klippy/extras/tmc2660.py @@ -82,7 +82,7 @@ class TMC2660: self.name = config.get_name().split()[1] self.toolhead = None - # pin setup + # Generic setup ppins = self.printer.lookup_object("pins") cs_pin = config.get('cs_pin') cs_pin_params = ppins.lookup_pin(cs_pin) @@ -91,24 +91,19 @@ class TMC2660: raise pins.error("tmc2660 can not invert pin") pin = cs_pin_params['pin'] self.oid = self.mcu.create_oid() + self.bus = config.getint('bus', minval=0, maxval=3) + self.freq = config.getint('freq', default=2000000, minval=1000000, maxval=4000000) + self.mcu.add_config_cmd( + "config_spi oid=%d bus=%d pin=%s mode=%d rate=%d shutdown_msg=" % ( + self.oid, self.bus, cs_pin_params['pin'], 0, self.freq)) + self.spi_send_cmd = self.spi_transfer_cmd = None + self.mcu.register_config_callback(self.build_config) # Add SET_CURRENT command gcode = self.printer.lookup_object("gcode") gcode.register_mux_command( "SET_TMC_CURRENT", "STEPPER", self.name, self.cmd_SET_TMC_CURRENT, desc=self.cmd_SET_TMC_CURRENT_help) # Setup driver registers - self.bus = config.getint('bus', minval=0, maxval=3) - self.freq = config.getint('freq', default=2000000, minval=1000000, maxval=4000000) - self.mcu.add_config_cmd( - "config_spi oid=%d bus=%d pin=%s mode=%d rate=%d shutdown_msg=" % ( - self.oid, self.bus, cs_pin_params['pin'], 0, self.freq)) - - self.spi_send_cmd = self.spi_transfer_cmd = None - self.mcu.register_config_callback(self.build_config) - - self.idle_current_percentage = config.getint('idle_current_percent', default=30, minval=0, maxval=100) - self.idle_timeout = config.getfloat('idle_timeout', default=0., minval=0) - self.is_idle = False # DRVCTRL steps = {'256': 0, '128': 1, '64': 2, '32': 3, '16': 4, '8': 5, '4': 6, '2': 7, '1': 8} @@ -164,7 +159,6 @@ class TMC2660: self.driver_vsense = config.getchoice('driver_VSENSE', vsense, default='high') self.driver_rdsel = 0 # Microsteps (used by endstop phase) - # Build and send registers self.reg_drvconf = REG_DRVCONF | \ get_bits(DRVCONF, "TST", 0) | \ @@ -207,6 +201,14 @@ class TMC2660: get_bits(SMARTEN, "SEMIN", self.driver_semin) self.add_config_cmd(self.reg_smarten) + # Idle timeout + 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 add_config_cmd(self, val): self.mcu.add_config_cmd("spi_send oid=%d data=%06x" % ( self.oid, val & 0xffffff)) @@ -218,36 +220,6 @@ class TMC2660: self.spi_transfer_cmd = self.mcu.lookup_command( "spi_transfer oid=%c data=%*s", cq=cmd_queue) - # register timeout handler which will lower the current to current * idle_current_percent / 100 after idle_timeout seconds - # and raise it back to current if the printer needs to move the steppers - def printer_state(self, state): - if state == 'ready' and self.idle_timeout > 0: - self.toolhead = self.printer.lookup_object('toolhead') - reactor = self.printer.get_reactor() - reactor.register_timer(self.idle_timeout_handler, reactor.NOW) - - # timeout handler to lower/raise current when entering/leaving the idle state - def idle_timeout_handler(self, eventtime): - info = self.toolhead.get_status(eventtime) - status = info['status'] - print_time = info['print_time'] - if status == 'Printing': - if self.is_idle: - self.set_current(self.current) - self.is_idle = False - return eventtime + self.idle_timeout - estimated_print_time = info['estimated_print_time'] - elapsed_time = estimated_print_time - print_time - if elapsed_time < self.idle_timeout: - if self.is_idle: - self.set_current(self.current) - self.is_idle = False - return eventtime + self.idle_timeout - elapsed_time - if not self.is_idle: - self.set_current(float(self.idle_current_percentage) * self.current / 100) - self.is_idle = True - return eventtime + 0.1 - def get_microsteps(self): return 256 >> self.driver_mres @@ -259,22 +231,27 @@ class TMC2660: steps = (((pr[0] << 16) | (pr[1] << 8) | pr[2]) & READRSP['MSTEP'][1]) >> READRSP['MSTEP'][0] return steps >> self.driver_mres - def set_current(self, current): + def handle_printing(self, print_time): + self.set_current(print_time, self.current) + + def handle_ready(self, print_time): + self.set_current(print_time, float(self.idle_current_percentage) * self.current / 100) + + def set_current(self, print_time, current): self.driver_cs = current_to_reg(current) reg = self.reg_sgcsconf reg &= ~(SGCSCONF["CS"][1]) reg |= get_bits(SGCSCONF, "CS", self.driver_cs) reg_data = [(reg >> 16) & 0xff, (reg >> 8) & 0xff, reg & 0xff] - params = self.spi_transfer_cmd.send_with_response([self.oid, reg_data], 'spi_transfer_response', self.oid) + clock = self.mcu.print_time_to_clock(print_time) + params = self.spi_send_cmd.send([self.oid, reg_data], minclock=clock, reqclock=clock) cmd_SET_TMC_CURRENT_help = "Set the current of a TMC2660 driver (between %d and %d)" % (CURRENT_MIN, CURRENT_MAX) def cmd_SET_TMC_CURRENT(self, params): - self.printer.lookup_object('toolhead').get_last_move_time() gcode = self.printer.lookup_object('gcode') if 'CURRENT' in params: self.current = gcode.get_float('CURRENT', params, minval=CURRENT_MIN, maxval=CURRENT_MAX) - if not self.is_idle: - self.set_current(self.current) + self.set_current(self.printer.lookup_object('toolhead').get_last_move_time(), self.current) def load_config_prefix(config): return TMC2660(config)