tmc2208: Use field definitions during driver init
Reduce the amount of bit manipulations by using the FieldHelper class. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
51f14b9c8c
commit
83001959f1
|
@ -45,13 +45,18 @@ class FieldHelper:
|
||||||
def __init__(self, all_fields, field_formatters={}):
|
def __init__(self, all_fields, field_formatters={}):
|
||||||
self.all_fields = all_fields
|
self.all_fields = all_fields
|
||||||
self.field_formatters = field_formatters
|
self.field_formatters = field_formatters
|
||||||
|
self.field_to_register = { f: r for r, fields in self.all_fields.items()
|
||||||
|
for f in fields }
|
||||||
|
def lookup_register(self, field_name):
|
||||||
|
# Return the name of the register containing the given field
|
||||||
|
return self.field_to_register[field_name]
|
||||||
def get_field(self, reg_name, field_name, reg_value):
|
def get_field(self, reg_name, field_name, reg_value):
|
||||||
# Returns value of the register field
|
# Returns value of the register field
|
||||||
mask = self.all_fields.get(reg_name, {})[field_name]
|
mask = self.all_fields[reg_name][field_name]
|
||||||
return (reg_value & mask) >> ffs(mask)
|
return (reg_value & mask) >> ffs(mask)
|
||||||
def set_field(self, reg_name, field_name, reg_value, field_value):
|
def set_field(self, reg_name, field_name, reg_value, field_value):
|
||||||
# Returns register value with field bits filled with supplied value
|
# Returns register value with field bits filled with supplied value
|
||||||
mask = self.all_fields.get(reg_name, {})[field_name]
|
mask = self.all_fields[reg_name][field_name]
|
||||||
return (reg_value & ~mask) | ((field_value << ffs(mask)) & mask)
|
return (reg_value & ~mask) | ((field_value << ffs(mask)) & mask)
|
||||||
def pretty_format(self, reg_name, value):
|
def pretty_format(self, reg_name, value):
|
||||||
# Provide a string description of a register
|
# Provide a string description of a register
|
||||||
|
|
|
@ -7,9 +7,6 @@ import math, logging, collections
|
||||||
import tmc2130
|
import tmc2130
|
||||||
|
|
||||||
TMC_FREQUENCY=12000000.
|
TMC_FREQUENCY=12000000.
|
||||||
GCONF_PDN_DISABLE = 1<<6
|
|
||||||
GCONF_MSTEP_REG_SELECT = 1<<7
|
|
||||||
GCONF_MULTISTEP_FILT = 1<<8
|
|
||||||
|
|
||||||
Registers = {
|
Registers = {
|
||||||
"GCONF": 0x00, "GSTAT": 0x01, "IFCNT": 0x02, "SLAVECONF": 0x03,
|
"GCONF": 0x00, "GSTAT": 0x01, "IFCNT": 0x02, "SLAVECONF": 0x03,
|
||||||
|
@ -296,10 +293,10 @@ class TMC2208:
|
||||||
sense_resistor = config.getfloat('sense_resistor', 0.110, above=0.)
|
sense_resistor = config.getfloat('sense_resistor', 0.110, above=0.)
|
||||||
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}
|
||||||
self.mres = config.getchoice('microsteps', steps)
|
mres = config.getchoice('microsteps', steps)
|
||||||
interpolate = config.getboolean('interpolate', True)
|
interpolate = config.getboolean('interpolate', True)
|
||||||
sc_velocity = config.getfloat('stealthchop_threshold', 0., minval=0.)
|
sc_velocity = config.getfloat('stealthchop_threshold', 0., minval=0.)
|
||||||
sc_threshold = self.velocity_to_clock(config, sc_velocity)
|
sc_threshold = self.velocity_to_clock(config, sc_velocity, mres)
|
||||||
iholddelay = config.getint('driver_IHOLDDELAY', 8, minval=0, maxval=15)
|
iholddelay = config.getint('driver_IHOLDDELAY', 8, minval=0, maxval=15)
|
||||||
tpowerdown = config.getint('driver_TPOWERDOWN', 20, minval=0, maxval=255)
|
tpowerdown = config.getint('driver_TPOWERDOWN', 20, minval=0, maxval=255)
|
||||||
blank_time_select = config.getint('driver_BLANK_TIME_SELECT', 2,
|
blank_time_select = config.getint('driver_BLANK_TIME_SELECT', 2,
|
||||||
|
@ -324,20 +321,30 @@ class TMC2208:
|
||||||
ihold = self.current_bits(hold_current, sense_resistor, vsense)
|
ihold = self.current_bits(hold_current, sense_resistor, vsense)
|
||||||
# Configure registers
|
# Configure registers
|
||||||
self.ifcnt = None
|
self.ifcnt = None
|
||||||
self.init_regs = collections.OrderedDict()
|
self.regs = collections.OrderedDict()
|
||||||
self.init_regs['GCONF'] = (
|
self.set_field("en_spreadCycle", not sc_velocity)
|
||||||
((sc_velocity == 0.) << 2) | GCONF_PDN_DISABLE
|
self.set_field("pdn_disable", True)
|
||||||
| GCONF_MSTEP_REG_SELECT | GCONF_MULTISTEP_FILT)
|
self.set_field("mstep_reg_select", True)
|
||||||
self.init_regs['CHOPCONF'] = (
|
self.set_field("multistep_filt", True)
|
||||||
toff | (hstrt << 4) | (hend << 7) | (blank_time_select << 15)
|
self.set_field("toff", toff)
|
||||||
| (vsense << 17) | (self.mres << 24) | (interpolate << 28))
|
self.set_field("hstrt", hstrt)
|
||||||
self.init_regs['IHOLD_IRUN'] = ihold | (irun << 8) | (iholddelay << 16)
|
self.set_field("hend", hend)
|
||||||
self.init_regs['TPOWERDOWN'] = tpowerdown
|
self.set_field("TBL", blank_time_select)
|
||||||
self.init_regs['TPWMTHRS'] = max(0, min(0xfffff, sc_threshold))
|
self.set_field("vsense", vsense)
|
||||||
self.init_regs['PWMCONF'] = (
|
self.set_field("MRES", mres)
|
||||||
pwm_ofs | (pwm_grad << 8) | (pwm_freq << 16)
|
self.set_field("intpol", interpolate)
|
||||||
| (pwm_autoscale << 18) | (pwm_autograd << 19)
|
self.set_field("IHOLD", ihold)
|
||||||
| (pwm_reg << 24) | (pwm_lim << 28))
|
self.set_field("IRUN", irun)
|
||||||
|
self.set_field("IHOLDDELAY", iholddelay)
|
||||||
|
self.set_field("TPOWERDOWN", tpowerdown)
|
||||||
|
self.set_field("TPWMTHRS", max(0, min(0xfffff, sc_threshold)))
|
||||||
|
self.set_field("PWM_OFS", pwm_ofs)
|
||||||
|
self.set_field("PWM_GRAD", pwm_grad)
|
||||||
|
self.set_field("pwm_freq", pwm_freq)
|
||||||
|
self.set_field("pwm_autoscale", pwm_autoscale)
|
||||||
|
self.set_field("pwm_autograd", pwm_autograd)
|
||||||
|
self.set_field("PWM_REG", pwm_reg)
|
||||||
|
self.set_field("PWM_LIM", pwm_lim)
|
||||||
def current_bits(self, current, sense_resistor, vsense_on):
|
def current_bits(self, current, sense_resistor, vsense_on):
|
||||||
sense_resistor += 0.020
|
sense_resistor += 0.020
|
||||||
vsense = 0.32
|
vsense = 0.32
|
||||||
|
@ -346,13 +353,13 @@ class TMC2208:
|
||||||
cs = int(32. * current * sense_resistor * math.sqrt(2.) / vsense
|
cs = int(32. * current * sense_resistor * math.sqrt(2.) / vsense
|
||||||
- 1. + .5)
|
- 1. + .5)
|
||||||
return max(0, min(31, cs))
|
return max(0, min(31, cs))
|
||||||
def velocity_to_clock(self, config, velocity):
|
def velocity_to_clock(self, config, velocity, mres):
|
||||||
if not velocity:
|
if not velocity:
|
||||||
return 0
|
return 0
|
||||||
stepper_name = config.get_name().split()[1]
|
stepper_name = config.get_name().split()[1]
|
||||||
stepper_config = config.getsection(stepper_name)
|
stepper_config = config.getsection(stepper_name)
|
||||||
step_dist = stepper_config.getfloat('step_distance')
|
step_dist = stepper_config.getfloat('step_distance')
|
||||||
step_dist_256 = step_dist / (1 << self.mres)
|
step_dist_256 = step_dist / (1 << mres)
|
||||||
return int(TMC_FREQUENCY * step_dist_256 / velocity + .5)
|
return int(TMC_FREQUENCY * step_dist_256 / velocity + .5)
|
||||||
def build_config(self):
|
def build_config(self):
|
||||||
bit_ticks = int(self.mcu.get_adjusted_freq() / 9000.)
|
bit_ticks = int(self.mcu.get_adjusted_freq() / 9000.)
|
||||||
|
@ -362,8 +369,18 @@ class TMC2208:
|
||||||
cmd_queue = self.mcu.alloc_command_queue()
|
cmd_queue = self.mcu.alloc_command_queue()
|
||||||
self.tmcuart_send_cmd = self.mcu.lookup_command(
|
self.tmcuart_send_cmd = self.mcu.lookup_command(
|
||||||
"tmcuart_send oid=%c write=%*s read=%c", cq=cmd_queue)
|
"tmcuart_send oid=%c write=%*s read=%c", cq=cmd_queue)
|
||||||
|
def get_field(self, field_name):
|
||||||
|
# Return a field from the local cache of register values
|
||||||
|
reg_name = self.field_helper.lookup_register(field_name)
|
||||||
|
return self.field_helper.get_field(
|
||||||
|
reg_name, field_name, self.regs.get(reg_name, 0))
|
||||||
|
def set_field(self, field_name, field_value):
|
||||||
|
# Set a field in the local cache of register values
|
||||||
|
reg_name = self.field_helper.lookup_register(field_name)
|
||||||
|
self.regs[reg_name] = self.field_helper.set_field(
|
||||||
|
reg_name, field_name, self.regs.get(reg_name, 0), field_value)
|
||||||
def handle_connect(self):
|
def handle_connect(self):
|
||||||
for reg_name, val in self.init_regs.items():
|
for reg_name, val in self.regs.items():
|
||||||
self.set_register(reg_name, val)
|
self.set_register(reg_name, val)
|
||||||
def get_register(self, reg_name):
|
def get_register(self, reg_name):
|
||||||
reg = Registers[reg_name]
|
reg = Registers[reg_name]
|
||||||
|
@ -394,9 +411,11 @@ class TMC2208:
|
||||||
raise self.printer.config_error(
|
raise self.printer.config_error(
|
||||||
"Unable to write tmc2208 '%s' register %s" % (self.name, reg_name))
|
"Unable to write tmc2208 '%s' register %s" % (self.name, reg_name))
|
||||||
def get_microsteps(self):
|
def get_microsteps(self):
|
||||||
return 256 >> self.mres
|
return 256 >> self.get_field("MRES")
|
||||||
def get_phase(self):
|
def get_phase(self):
|
||||||
return (self.get_register("MSCNT") & 0x3ff) >> self.mres
|
mscnt = self.get_register("MSCNT")
|
||||||
|
mscnt = self.field_helper.get_field("MSCNT", "MSCNT", mscnt)
|
||||||
|
return mscnt >> self.get_field("MRES")
|
||||||
cmd_DUMP_TMC_help = "Read and display TMC stepper driver registers"
|
cmd_DUMP_TMC_help = "Read and display TMC stepper driver registers"
|
||||||
def cmd_DUMP_TMC(self, params):
|
def cmd_DUMP_TMC(self, params):
|
||||||
self.printer.lookup_object('toolhead').get_last_move_time()
|
self.printer.lookup_object('toolhead').get_last_move_time()
|
||||||
|
|
Loading…
Reference in New Issue