Implement idle event support in the TMC2660 extra

Signed-off-by: Florian Heilmann <Florian.Heilmann@gmx.net>
This commit is contained in:
Florian Heilmann 2018-10-24 16:17:49 +00:00 committed by Kevin O'Connor
parent d25e02144c
commit 4372d1812c
2 changed files with 39 additions and 65 deletions

View File

@ -741,8 +741,8 @@
#[tmc2660 stepper_x] #[tmc2660 stepper_x]
#cs_pin: #cs_pin:
# The pin corresponding to the TMC2660 chip select line. This 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 # will be set to low at the start of SPI messages and set to high
# after the message completes. This parameter must be provided. # after the message transfer completes. This parameter must be provided.
#bus: #bus:
# Select the SPI bus the TMC2660 stepper driver is connected to. This # Select the SPI bus the TMC2660 stepper driver is connected to. This
# depends on the physical connections on your board, as well as the # 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 # step at a rate of 256 micro-steps). This only works if microsteps
# is set to 16. The default is True. # is set to 16. The default is True.
#run_current: #run_current:
# The amount of current (in amps) to configure the driver to use # The amount of current (in ampere) used by the driver during stepper
# during stepper movement. This parameter must be provided. # movement. This parameter must be provided.
#idle_timeout: 0 #idle_current_percent: 100
# 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 percentage of the run_current the stepper driver will be # 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 # 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 # 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 # their position. There is also small delay until the current is
# current is raised again, so take this into account commanding fast # raised again, so take this into account when commanding fast moves
# moves when the stepper is idling. The default is 30. # while the stepper is idling. The default is 100 (no reduction).
#driver_DEDGE: False #driver_DEDGE: False
#driver_TBL: 36 #driver_TBL: 36
# Valid values are 16, 24, 36, 54. # Valid values are 16, 24, 36, 54.
@ -804,10 +801,10 @@
#driver_VSENSE: high #driver_VSENSE: high
# Valid values are 'high' and 'low' # Valid values are 'high' and 'low'
# #
# Set the given register during the configuration of the TMC2660 # Set the given parameter during the configuration of the TMC2660
# chip. This may be used to set custom motor parameters. The # chip. This may be used to set custom driver parameters. The
# defaults for each parameter are next to the parameter name in 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. # does and what the restrictions on parameter combinations are.

View File

@ -82,7 +82,7 @@ class TMC2660:
self.name = config.get_name().split()[1] self.name = config.get_name().split()[1]
self.toolhead = None self.toolhead = None
# pin setup # Generic setup
ppins = self.printer.lookup_object("pins") ppins = self.printer.lookup_object("pins")
cs_pin = config.get('cs_pin') cs_pin = config.get('cs_pin')
cs_pin_params = ppins.lookup_pin(cs_pin) cs_pin_params = ppins.lookup_pin(cs_pin)
@ -91,24 +91,19 @@ class TMC2660:
raise pins.error("tmc2660 can not invert pin") raise pins.error("tmc2660 can not invert pin")
pin = cs_pin_params['pin'] pin = cs_pin_params['pin']
self.oid = self.mcu.create_oid() 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 # Add SET_CURRENT command
gcode = self.printer.lookup_object("gcode") gcode = self.printer.lookup_object("gcode")
gcode.register_mux_command( gcode.register_mux_command(
"SET_TMC_CURRENT", "STEPPER", self.name, "SET_TMC_CURRENT", "STEPPER", self.name,
self.cmd_SET_TMC_CURRENT, desc=self.cmd_SET_TMC_CURRENT_help) self.cmd_SET_TMC_CURRENT, desc=self.cmd_SET_TMC_CURRENT_help)
# Setup driver registers # 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 # DRVCTRL
steps = {'256': 0, '128': 1, '64': 2, '32': 3, '16': 4, steps = {'256': 0, '128': 1, '64': 2, '32': 3, '16': 4,
'8': 5, '4': 6, '2': 7, '1': 8} '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_vsense = config.getchoice('driver_VSENSE', vsense, default='high')
self.driver_rdsel = 0 # Microsteps (used by endstop phase) self.driver_rdsel = 0 # Microsteps (used by endstop phase)
# Build and send registers # Build and send registers
self.reg_drvconf = REG_DRVCONF | \ self.reg_drvconf = REG_DRVCONF | \
get_bits(DRVCONF, "TST", 0) | \ get_bits(DRVCONF, "TST", 0) | \
@ -207,6 +201,14 @@ class TMC2660:
get_bits(SMARTEN, "SEMIN", self.driver_semin) get_bits(SMARTEN, "SEMIN", self.driver_semin)
self.add_config_cmd(self.reg_smarten) 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): def add_config_cmd(self, val):
self.mcu.add_config_cmd("spi_send oid=%d data=%06x" % ( self.mcu.add_config_cmd("spi_send oid=%d data=%06x" % (
self.oid, val & 0xffffff)) self.oid, val & 0xffffff))
@ -218,36 +220,6 @@ class TMC2660:
self.spi_transfer_cmd = self.mcu.lookup_command( self.spi_transfer_cmd = self.mcu.lookup_command(
"spi_transfer oid=%c data=%*s", cq=cmd_queue) "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): def get_microsteps(self):
return 256 >> self.driver_mres 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] steps = (((pr[0] << 16) | (pr[1] << 8) | pr[2]) & READRSP['MSTEP'][1]) >> READRSP['MSTEP'][0]
return steps >> self.driver_mres 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) self.driver_cs = current_to_reg(current)
reg = self.reg_sgcsconf reg = self.reg_sgcsconf
reg &= ~(SGCSCONF["CS"][1]) reg &= ~(SGCSCONF["CS"][1])
reg |= get_bits(SGCSCONF, "CS", self.driver_cs) reg |= get_bits(SGCSCONF, "CS", self.driver_cs)
reg_data = [(reg >> 16) & 0xff, (reg >> 8) & 0xff, reg & 0xff] 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) 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): def cmd_SET_TMC_CURRENT(self, params):
self.printer.lookup_object('toolhead').get_last_move_time()
gcode = self.printer.lookup_object('gcode') gcode = self.printer.lookup_object('gcode')
if 'CURRENT' in params: if 'CURRENT' in params:
self.current = gcode.get_float('CURRENT', params, minval=CURRENT_MIN, maxval=CURRENT_MAX) self.current = gcode.get_float('CURRENT', params, minval=CURRENT_MIN, maxval=CURRENT_MAX)
if not self.is_idle: self.set_current(self.printer.lookup_object('toolhead').get_last_move_time(), self.current)
self.set_current(self.current)
def load_config_prefix(config): def load_config_prefix(config):
return TMC2660(config) return TMC2660(config)