aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras/angle.py
diff options
context:
space:
mode:
Diffstat (limited to 'klippy/extras/angle.py')
-rw-r--r--klippy/extras/angle.py151
1 files changed, 149 insertions, 2 deletions
diff --git a/klippy/extras/angle.py b/klippy/extras/angle.py
index aaaa8300..3b1f323e 100644
--- a/klippy/extras/angle.py
+++ b/klippy/extras/angle.py
@@ -457,6 +457,150 @@ class HelperMT6816:
gcmd.respond_info("No Mag: %i" % (val >> 1 & 0x1))
gcmd.respond_info("Parity: %i == %i" % (parity, val & 0x1))
+class HelperMT6826S:
+ SPI_MODE = 3
+ SPI_SPEED = 10000000
+ def __init__(self, config, spi, oid):
+ self.printer = config.get_printer()
+ self.stepper_name = config.get('stepper', None)
+ self.spi = spi
+ self.oid = oid
+ self.mcu = spi.get_mcu()
+ self.mcu.register_config_callback(self._build_config)
+ self.spi_angle_transfer_cmd = None
+ self.is_tcode_absolute = False
+ self.last_temperature = None
+ name = config.get_name().split()[-1]
+ gcode = self.printer.lookup_object("gcode")
+ gcode.register_mux_command("ANGLE_DEBUG_READ", "CHIP", name,
+ self.cmd_ANGLE_DEBUG_READ,
+ desc=self.cmd_ANGLE_DEBUG_READ_help)
+ gcode.register_mux_command("ANGLE_CHIP_CALIBRATE", "CHIP", name,
+ self.cmd_ANGLE_CHIP_CALIBRATE,
+ desc=self.cmd_ANGLE_CHIP_CALIBRATE_help)
+ self.status_map = {
+ 0: "No Calibration",
+ 1: "Running Calibration",
+ 2: "Calibration Failed",
+ 3: "Calibration Successful"
+ }
+ def _build_config(self):
+ cmdqueue = self.spi.get_command_queue()
+ self.spi_angle_transfer_cmd = self.mcu.lookup_query_command(
+ "spi_angle_transfer oid=%c data=%*s",
+ "spi_angle_transfer_response oid=%c clock=%u response=%*s",
+ oid=self.oid, cq=cmdqueue)
+ def _send_spi(self, msg):
+ params = self.spi.spi_transfer(msg)
+ return params
+ def get_static_delay(self):
+ return .00001
+ def _read_reg(self, reg):
+ reg = 0x3000 | reg
+ msg = [reg >> 8, reg & 0xff, 0]
+ params = self._send_spi(msg)
+ resp = bytearray(params['response'])
+ return resp[2]
+ def _write_reg(self, reg, data):
+ reg = 0x6000 | reg
+ msg = [reg >> 8, reg & 0xff, data]
+ self._send_spi(msg)
+ def crc8(self, data):
+ polynomial = 0x07
+ crc = 0x00
+ for byte in data:
+ crc ^= byte
+ for _ in range(8):
+ if crc & 0x80:
+ crc = (crc << 1) ^ polynomial
+ else:
+ crc <<= 1
+ crc &= 0xFF
+ return crc
+ def _read_angle(self, reg):
+ reg = 0x3000 | reg
+ msg = [reg >> 8, reg & 0xff, 0, 0, 0, 0]
+ params = self._send_spi(msg)
+ resp = bytearray(params['response'])
+ angle = (resp[2] << 7) | (resp[3] >> 1)
+ status = resp[4]
+ crc_computed = self.crc8([resp[2], resp[3], resp[4]])
+ crc = resp[5]
+ return angle, status, crc, crc_computed
+ def start(self):
+ val = self._read_reg(0x00d)
+ # Set histeresis to 0.003 degree
+ self._write_reg(0x00d, (val & 0xf8) | 0x5)
+ def get_microsteps(self):
+ configfile = self.printer.lookup_object('configfile')
+ sconfig = configfile.get_status(None)['settings']
+ stconfig = sconfig.get(self.stepper_name, {})
+ microsteps = stconfig['microsteps']
+ full_steps = stconfig['full_steps_per_rotation']
+ return microsteps, full_steps
+ cmd_ANGLE_CHIP_CALIBRATE_help = "Run MT6826s calibration sequence"
+ def cmd_ANGLE_CHIP_CALIBRATE(self, gcmd):
+ fmove = self.printer.lookup_object('force_move')
+ mcu_stepper = fmove.lookup_stepper(self.stepper_name)
+ if self.stepper_name is None:
+ gcmd.respond_info("stepper not defined")
+ return
+
+ gcmd.respond_info("MT6826S Run calibration sequence")
+ gcmd.respond_info("Motor will do 18+ rotations -" +
+ " ensure pulley is disconnected")
+ req_freq = self._read_reg(0x00e) >> 4 & 0x7
+ # Minimal calibration speed
+ rpm = (3200 >> req_freq) + 1
+ rps = rpm / 60
+ move = fmove.manual_move
+ # Move stepper several turns (to allow internal sensor calibration)
+ microsteps, full_steps = self.get_microsteps()
+ step_dist = mcu_stepper.get_step_dist()
+ full_step_dist = step_dist * microsteps
+ rotation_dist = full_steps * full_step_dist
+ move(mcu_stepper, 2 * rotation_dist, rps * rotation_dist)
+ self._write_reg(0x155, 0x5e)
+ move(mcu_stepper, 20 * rotation_dist, rps * rotation_dist)
+ val = self._read_reg(0x113)
+ code = val >> 6
+ gcmd.respond_info("Status: %s" % (self.status_map[code]))
+ while code == 1:
+ move(mcu_stepper, 5 * rotation_dist, rps * rotation_dist)
+ val = self._read_reg(0x113)
+ code = val >> 6
+ gcmd.respond_info("Status: %s" % (self.status_map[code]))
+ if code == 2:
+ gcmd.respond_info("Calibration failed")
+ if code == 3:
+ gcmd.respond_info("Calibration success, please poweroff sensor")
+ cmd_ANGLE_DEBUG_READ_help = "Query low-level angle sensor register"
+ def cmd_ANGLE_DEBUG_READ(self, gcmd):
+ reg = gcmd.get("REG", minval=0, maxval=0x155,
+ parser=lambda x: int(x, 0))
+ if reg == 0x003:
+ angle, status, crc1, crc2 = self._read_angle(reg)
+ gcmd.respond_info("ANGLE REG[0x003] = 0x%02x" %
+ (angle >> 7))
+ gcmd.respond_info("ANGLE REG[0x004] = 0x%02x" %
+ ((angle << 1) & 0xff))
+ gcmd.respond_info("Angle %i ~ %.2f" % (angle,
+ angle * 360 / (1 << 15)))
+ gcmd.respond_info("Weak Mag: %i" % (status >> 1 & 0x1))
+ gcmd.respond_info("Under Voltage: %i" % (status >> 2 & 0x1))
+ gcmd.respond_info("CRC: 0x%02x == 0x%02x" % (crc1, crc2))
+ elif reg == 0x00e:
+ val = self._read_reg(reg)
+ gcmd.respond_info("GPIO_DS = %i" % (val >> 7))
+ gcmd.respond_info("AUTOCAL_FREQ = %i" % (val >> 4 & 0x7))
+ elif reg == 0x113:
+ val = self._read_reg(reg)
+ gcmd.respond_info("Status: %s" % (self.cal_status[val >> 6]))
+ else:
+ val = self._read_reg(reg)
+ gcmd.respond_info("REG[0x%04x] = 0x%02x" % (reg, val))
+
+
BYTES_PER_SAMPLE = 3
SAMPLES_PER_BLOCK = bulk_sensor.MAX_BULK_MSG_SIZE // BYTES_PER_SAMPLE
@@ -473,8 +617,11 @@ class Angle:
self.start_clock = self.time_shift = self.sample_ticks = 0
self.last_sequence = self.last_angle = 0
# Sensor type
- sensors = { "a1333": HelperA1333, "as5047d": HelperAS5047D,
- "tle5012b": HelperTLE5012B, "mt6816": HelperMT6816 }
+ sensors = { "a1333": HelperA1333,
+ "as5047d": HelperAS5047D,
+ "tle5012b": HelperTLE5012B,
+ "mt6816": HelperMT6816,
+ "mt6826s": HelperMT6826S }
sensor_type = config.getchoice('sensor_type', {s: s for s in sensors})
sensor_class = sensors[sensor_type]
self.spi = bus.MCU_SPI_from_config(config, sensor_class.SPI_MODE,