tmc2130: Use FieldHelper() to set/get driver fields

Use the field helper to simplify the bit manipulation in the driver.
This also enables the extended DUMP_TMC output.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2019-02-21 11:35:58 -05:00
parent 328bd89fc1
commit 5bc47d9416
2 changed files with 106 additions and 57 deletions

View File

@ -3,12 +3,10 @@
# Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import math, logging
import math, logging, collections
import bus
TMC_FREQUENCY=13200000.
GCONF_EN_PWM_MODE=1<<2
GCONF_DIAG1_STALL=1<<8
Registers = {
"GCONF": 0x00, "GSTAT": 0x01, "IOIN": 0x04, "IHOLD_IRUN": 0x10,
@ -25,6 +23,69 @@ ReadRegisters = [
]
Fields = {}
Fields["GCONF"] = {
"I_scale_analog": 1<<0, "internal_Rsense": 1<<1, "en_pwm_mode": 1<<2,
"enc_commutation": 1<<3, "shaft": 1<<4, "diag0_error": 1<<5,
"diag0_otpw": 1<<6, "diag0_stall": 1<<7, "diag1_stall": 1<<8,
"diag1_index": 1<<9, "diag1_onstate": 1<<10, "diag1_steps_skipped": 1<<11,
"diag0_int_pushpull": 1<<12, "diag1_pushpull": 1<<13,
"small_hysteresis": 1<<14, "stop_enable": 1<<15, "direct_mode": 1<<16,
"test_mode": 1<<17
}
Fields["GSTAT"] = { "reset": 1<<0, "drv_err": 1<<1, "uv_cp": 1<<2 }
Fields["IOIN"] = {
"STEP": 1<<0, "DIR": 1<<1, "DCEN_CFG4": 1<<2, "DCIN_CFG5": 1<<3,
"DRV_ENN_CFG6": 1<<4, "DCO": 1<<5, "VERSION": 0xff << 24
}
Fields["IHOLD_IRUN"] = {
"IHOLD": 0x1f << 0, "IRUN": 0x1f << 8, "IHOLDDELAY": 0x0f << 16
}
Fields["TPOWERDOWN"] = { "TPOWERDOWN": 0xff }
Fields["TSTEP"] = { "TSTEP": 0xfffff }
Fields["TPWMTHRS"] = { "TPWMTHRS": 0xfffff }
Fields["TCOOLTHRS"] = { "TCOOLTHRS": 0xfffff }
Fields["THIGH"] = { "THIGH": 0xfffff }
Fields["MSCNT"] = { "MSCNT": 0x3ff }
Fields["MSCURACT"] = { "CUR_A": 0x1ff, "CUR_B": 0x1ff << 16 }
Fields["CHOPCONF"] = {
"toff": 0x0f, "hstrt": 0x07 << 4, "hend": 0x0f << 7, "fd3": 1<<11,
"disfdcc": 1<<12, "rndtf": 1<<13, "chm": 1<<14, "TBL": 0x03 << 15,
"vsense": 1<<17, "vhighfs": 1<<18, "vhighchm": 1<<19, "sync": 0x0f << 20,
"MRES": 0x0f << 24, "intpol": 1<<28, "dedge": 1<<29, "diss2g": 1<<30
}
Fields["COOLCONF"] = {
"semin": 0x0f, "seup": 0x03 << 5, "semax": 0x0f << 8, "sedn": 0x03 << 13,
"seimin": 1<<15, "sgt": 0x7f << 16, "sfilt": 1<<24
}
Fields["DRV_STATUS"] = {
"SG_RESULT": 0x3ff, "fsactive": 1<<15, "CS_ACTUAL": 0x1f << 16,
"stallGuard": 1<<24, "ot": 1<<25, "otpw": 1<<26, "s2ga": 1<<27,
"s2gb": 1<<28, "ola": 1<<29, "olb": 1<<30, "stst": 1<<31
}
Fields["PWMCONF"] = {
"PWM_AMPL": 0xff, "PWM_GRAD": 0xff << 8, "pwm_freq": 0x03 << 16,
"pwm_autoscale": 1<<18, "pwm_symmetric": 1<<19, "freewheel": 0x03 << 20
}
Fields["PWM_SCALE"] = { "PWM_SCALE": 0xff }
Fields["LOST_STEPS"] = { "LOST_STEPS": 0xfffff }
FieldFormatters = {
"I_scale_analog": (lambda v: "1(ExtVREF)" if v else ""),
"shaft": (lambda v: "1(Reverse)" if v else ""),
"drv_err": (lambda v: "1(ErrorShutdown!)" if v else ""),
"uv_cp": (lambda v: "1(Undervoltage!)" if v else ""),
"VERSION": (lambda v: "%#x" % v),
"CUR_A": (lambda v: decode_signed_int(v, 9)),
"CUR_B": (lambda v: decode_signed_int(v, 9)),
"MRES": (lambda v: "%d(%dusteps)" % (v, 0x100 >> v)),
"otpw": (lambda v: "1(OvertempWarning!)" if v else ""),
"ot": (lambda v: "1(OvertempError!)" if v else ""),
"s2ga": (lambda v: "1(ShortToGND_A!)" if v else ""),
"s2gb": (lambda v: "1(ShortToGND_B!)" if v else ""),
"ola": (lambda v: "1(OpenLoad_A!)" if v else ""),
"olb": (lambda v: "1(OpenLoad_B!)" if v else ""),
"sgt": (lambda v: decode_signed_int(v, 7)),
}
######################################################################
@ -155,37 +216,35 @@ class TMC2130:
gcode.register_mux_command(
"DUMP_TMC", "STEPPER", self.name,
self.cmd_DUMP_TMC, desc=self.cmd_DUMP_TMC_help)
# Get config for initial driver settings
self.fields = FieldHelper(Fields)
interpolate = config.getboolean('interpolate', True)
self.mres, en_pwm, sc_threshold = get_config_stealthchop(
config, TMC_FREQUENCY)
iholddelay = config.getint('driver_IHOLDDELAY', 8, minval=0, maxval=15)
tpowerdown = config.getint('driver_TPOWERDOWN', 0, minval=0, maxval=255)
blank_time_select = config.getint('driver_BLANK_TIME_SELECT', 1,
minval=0, maxval=3)
toff = config.getint('driver_TOFF', 4, minval=1, maxval=15)
hend = config.getint('driver_HEND', 7, minval=0, maxval=15)
hstrt = config.getint('driver_HSTRT', 0, minval=0, maxval=7)
sgt = config.getint('driver_SGT', 0, minval=-64, maxval=63) & 0x7f
pwm_scale = config.getboolean('driver_PWM_AUTOSCALE', True)
pwm_freq = config.getint('driver_PWM_FREQ', 1, minval=0, maxval=3)
pwm_grad = config.getint('driver_PWM_GRAD', 4, minval=0, maxval=255)
pwm_ampl = config.getint('driver_PWM_AMPL', 128, minval=0, maxval=255)
# Setup basic register values
self.regs = collections.OrderedDict()
self.fields = FieldHelper(Fields, FieldFormatters, self.regs)
vsense, irun, ihold = get_config_current(config)
# Configure registers
self.reg_GCONF = en_pwm << 2
self.set_register("GCONF", self.reg_GCONF)
self.set_register("CHOPCONF", (
toff | (hstrt << 4) | (hend << 7) | (blank_time_select << 15)
| (vsense << 17) | (self.mres << 24) | (interpolate << 28)))
self.set_register("IHOLD_IRUN",
ihold | (irun << 8) | (iholddelay << 16))
self.set_register("TPOWERDOWN", tpowerdown)
self.set_register("TPWMTHRS", sc_threshold)
self.set_register("COOLCONF", sgt << 16)
self.set_register("PWMCONF", (
pwm_ampl | (pwm_grad << 8) | (pwm_freq << 16) | (pwm_scale << 18)))
self.fields.set_field("vsense", vsense)
self.fields.set_field("IHOLD", ihold)
self.fields.set_field("IRUN", irun)
mres, en_pwm, thresh = get_config_stealthchop(config, TMC_FREQUENCY)
self.fields.set_field("MRES", mres)
self.fields.set_field("en_pwm_mode", en_pwm)
self.fields.set_field("TPWMTHRS", thresh)
# Allow other registers to be set from the config
set_config_field = self.fields.set_config_field
set_config_field(config, "toff", 4)
set_config_field(config, "hstrt", 0)
set_config_field(config, "hend", 7)
set_config_field(config, "TBL", 1, "driver_BLANK_TIME_SELECT")
set_config_field(config, "intpol", True, "interpolate")
set_config_field(config, "IHOLDDELAY", 8)
set_config_field(config, "TPOWERDOWN", 0)
set_config_field(config, "PWM_AMPL", 128)
set_config_field(config, "PWM_GRAD", 4)
set_config_field(config, "pwm_freq", 1)
set_config_field(config, "pwm_autoscale", True)
sgt = config.getint('driver_SGT', 0, minval=-64, maxval=63) & 0x7f
self.fields.set_field("sgt", sgt)
# Send registers
for reg_name, val in self.regs.items():
self.set_register(reg_name, val)
def setup_pin(self, pin_type, pin_params):
if pin_type != 'endstop' or pin_params['pin'] != 'virtual_endstop':
raise pins.error("tmc2130 virtual endstop only useful as endstop")
@ -204,9 +263,10 @@ class TMC2130:
(val >> 8) & 0xff, val & 0xff]
self.spi.spi_send(data)
def get_microsteps(self):
return 256 >> self.mres
return 256 >> self.fields.get_field("MRES")
def get_phase(self):
return (self.get_register("MSCNT") & 0x3ff) >> self.mres
mscnt = self.fields.get_field("MSCNT", self.get_register("MSCNT"))
return mscnt >> self.fields.get_field("MRES")
cmd_DUMP_TMC_help = "Read and display TMC stepper driver registers"
def cmd_DUMP_TMC(self, params):
self.printer.lookup_object('toolhead').get_last_move_time()
@ -228,6 +288,7 @@ class TMC2130VirtualEndstop:
self.mcu_endstop = ppins.setup_pin('endstop', tmc2130.diag1_pin)
if self.mcu_endstop.get_mcu() is not tmc2130.spi.get_mcu():
raise pins.error("tmc2130 virtual endstop must be on same mcu")
self.en_pwm = tmc2130.fields.get_field("en_pwm_mode")
# Wrappers
self.get_mcu = self.mcu_endstop.get_mcu
self.add_stepper = self.mcu_endstop.add_stepper
@ -238,14 +299,15 @@ class TMC2130VirtualEndstop:
self.query_endstop_wait = self.mcu_endstop.query_endstop_wait
self.TimeoutError = self.mcu_endstop.TimeoutError
def home_prepare(self):
gconf = self.tmc2130.reg_GCONF
gconf &= ~GCONF_EN_PWM_MODE
gconf |= GCONF_DIAG1_STALL
self.tmc2130.set_register("GCONF", gconf)
self.tmc2130.fields.set_field("en_pwm_mode", 0)
self.tmc2130.fields.set_field("diag1_stall", 1)
self.tmc2130.set_register("GCONF", self.tmc2130.regs['GCONF'])
self.tmc2130.set_register("TCOOLTHRS", 0xfffff)
self.mcu_endstop.home_prepare()
def home_finalize(self):
self.tmc2130.set_register("GCONF", self.tmc2130.reg_GCONF)
self.tmc2130.fields.set_field("en_pwm_mode", self.en_pwm)
self.tmc2130.fields.set_field("diag1_stall", 0)
self.tmc2130.set_register("GCONF", self.tmc2130.regs['GCONF'])
self.tmc2130.set_register("TCOOLTHRS", 0)
self.mcu_endstop.home_finalize()

View File

@ -168,26 +168,13 @@ Fields["PWM_AUTO"] = {
"PWM_GRAD_AUTO": 0xff << 16
}
FieldFormatters = {
"I_scale_analog": (lambda v: "1(ExtVREF)" if v else ""),
"shaft": (lambda v: "1(Reverse)" if v else ""),
"drv_err": (lambda v: "1(ErrorShutdown!)" if v else ""),
"uv_cp": (lambda v: "1(Undervoltage!)" if v else ""),
FieldFormatters = dict(tmc2130.FieldFormatters)
FieldFormatters.update({
"SEL_A": (lambda v: "%d(%s)" % (v, ["TMC222x", "TMC220x"][v])),
"VERSION": (lambda v: "%#x" % v),
"CUR_A": (lambda v: str(tmc2130.decode_signed_int(v, 9))),
"CUR_B": (lambda v: str(tmc2130.decode_signed_int(v, 9))),
"MRES": (lambda v: "%d(%dusteps)" % (v, 0x100 >> v)),
"otpw": (lambda v: "1(OvertempWarning!)" if v else ""),
"ot": (lambda v: "1(OvertempError!)" if v else ""),
"s2ga": (lambda v: "1(ShortToGND_A!)" if v else ""),
"s2gb": (lambda v: "1(ShortToGND_B!)" if v else ""),
"s2vsa": (lambda v: "1(LowSideShort_A!)" if v else ""),
"s2vsb": (lambda v: "1(LowSideShort_B!)" if v else ""),
"ola": (lambda v: "1(OpenLoad_A!)" if v else ""),
"olb": (lambda v: "1(OpenLoad_B!)" if v else ""),
"PWM_SCALE_AUTO": (lambda v: str(tmc2130.decode_signed_int(v, 9)))
}
"PWM_SCALE_AUTO": (lambda v: tmc2130.decode_signed_int(v, 9))
})
######################################################################