aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras/tmc2208.py
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2019-06-10 19:51:43 -0400
committerKevin O'Connor <kevin@koconnor.net>2019-06-12 22:14:41 -0400
commitf6864da58bfd5c1c1da4274a01b49597a203cf98 (patch)
tree0b17dfbb8c39fa91a8f5145a0055f25a875b449d /klippy/extras/tmc2208.py
parent88fe2787a9a215bc5a214dc3f4329bca09e25acb (diff)
downloadkutter-f6864da58bfd5c1c1da4274a01b49597a203cf98.tar.gz
kutter-f6864da58bfd5c1c1da4274a01b49597a203cf98.tar.xz
kutter-f6864da58bfd5c1c1da4274a01b49597a203cf98.zip
tmc2208: Add support for using an analog mux to access TMC uarts
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'klippy/extras/tmc2208.py')
-rw-r--r--klippy/extras/tmc2208.py110
1 files changed, 92 insertions, 18 deletions
diff --git a/klippy/extras/tmc2208.py b/klippy/extras/tmc2208.py
index c0d0d718..8f68b576 100644
--- a/klippy/extras/tmc2208.py
+++ b/klippy/extras/tmc2208.py
@@ -179,27 +179,65 @@ FieldFormatters.update({
######################################################################
+# TMC uart analog mux support
+######################################################################
+
+class MCU_analog_mux:
+ def __init__(self, mcu, cmd_queue, select_pins_desc):
+ self.mcu = mcu
+ self.cmd_queue = cmd_queue
+ ppins = mcu.get_printer().lookup_object("pins")
+ select_pin_params = [ppins.lookup_pin(spd, can_invert=True)
+ for spd in select_pins_desc.split(',')]
+ self.oids = [self.mcu.create_oid() for pp in select_pin_params]
+ self.pins = [pp['pin'] for pp in select_pin_params]
+ self.pin_values = tuple([0 for pp in select_pin_params])
+ for oid, pin, value in zip(self.oids, self.pins, self.pin_values):
+ self.mcu.add_config_cmd("config_digital_out oid=%d pin=%s"
+ " value=%d default_value=0 max_duration=0"
+ % (oid, pin, value))
+ self.update_pin_cmd = None
+ self.mcu.register_config_callback(self.build_config)
+ def build_config(self):
+ self.update_pin_cmd = self.mcu.lookup_command(
+ "update_digital_out oid=%c value=%c", cq=self.cmd_queue)
+ def get_instance_id(self, select_pins_desc):
+ ppins = self.mcu.get_printer().lookup_object("pins")
+ select_pin_params = [ppins.parse_pin(spd, can_invert=True)
+ for spd in select_pins_desc.split(',')]
+ for pin_params in select_pin_params:
+ if pin_params['chip'] != self.mcu:
+ raise self.mcu.get_printer().config_error(
+ "TMC mux pins must be on the same mcu")
+ pins = [pp['pin'] for pp in select_pin_params]
+ if pins != self.pins:
+ raise self.mcu.get_printer().config_error(
+ "All TMC mux instances must use identical pins")
+ return tuple([not pp['invert'] for pp in select_pin_params])
+ def activate(self, instance_id):
+ for oid, old, new in zip(self.oids, self.pin_values, instance_id):
+ if old != new:
+ self.update_pin_cmd.send([oid, new])
+ self.pin_values = instance_id
+
+
+######################################################################
# TMC2208 uart communication
######################################################################
# Code for sending messages on a TMC uart
class MCU_TMC_uart_bitbang:
- def __init__(self, config):
- ppins = config.get_printer().lookup_object("pins")
- rx_pin_params = ppins.lookup_pin(
- config.get('uart_pin'), can_pullup=True)
- tx_pin_desc = config.get('tx_pin', None)
- if tx_pin_desc is None:
- tx_pin_params = rx_pin_params
- else:
- tx_pin_params = ppins.lookup_pin(tx_pin_desc)
- if rx_pin_params['chip'] is not tx_pin_params['chip']:
- raise ppins.error("TMC uart rx and tx pins must be on the same mcu")
+ def __init__(self, rx_pin_params, tx_pin_params, select_pins_desc):
self.mcu = rx_pin_params['chip']
self.pullup = rx_pin_params['pullup']
self.rx_pin = rx_pin_params['pin']
self.tx_pin = tx_pin_params['pin']
self.oid = self.mcu.create_oid()
+ self.cmd_queue = self.mcu.alloc_command_queue()
+ self.analog_mux = None
+ if select_pins_desc is not None:
+ self.analog_mux = MCU_analog_mux(self.mcu, self.cmd_queue,
+ select_pins_desc)
self.tmcuart_send_cmd = None
self.mcu.register_config_callback(self.build_config)
def build_config(self):
@@ -207,9 +245,18 @@ class MCU_TMC_uart_bitbang:
self.mcu.add_config_cmd(
"config_tmcuart oid=%d rx_pin=%s pull_up=%d tx_pin=%s bit_time=%d"
% (self.oid, self.rx_pin, self.pullup, self.tx_pin, bit_ticks))
- cmd_queue = self.mcu.alloc_command_queue()
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=self.cmd_queue)
+ def register_instance(self, rx_pin_params, tx_pin_params, select_pins_desc):
+ if (rx_pin_params['pin'] != self.rx_pin
+ or tx_pin_params['pin'] != self.tx_pin
+ or (select_pins_desc is None) != (self.analog_mux is None)):
+ raise self.mcu.get_printer().config_error(
+ "Shared TMC uart must use identical pins")
+ instance_id = None
+ if self.analog_mux is not None:
+ instance_id = self.analog_mux.get_instance_id(select_pins_desc)
+ return instance_id
def _calc_crc8(self, data):
# Generate a CRC8-ATM value for a bytearray
crc = 0
@@ -262,16 +309,42 @@ class MCU_TMC_uart_bitbang:
if data != encoded_data:
return None
return val
- def reg_read(self, addr, reg):
+ def reg_read(self, instance_id, addr, reg):
+ if self.analog_mux is not None:
+ self.analog_mux.activate(instance_id)
msg = self._encode_read(0xf5, addr, reg)
params = self.tmcuart_send_cmd.send_with_response(
[self.oid, msg, 10], 'tmcuart_response', self.oid)
return self._decode_read(reg, params['read'])
- def reg_write(self, addr, reg, val):
+ def reg_write(self, instance_id, addr, reg, val):
+ if self.analog_mux is not None:
+ self.analog_mux.activate(instance_id)
msg = self._encode_write(0xf5, 0x00, reg | 0x80, val)
self.tmcuart_send_cmd.send_with_response(
[self.oid, msg, 0], 'tmcuart_response', self.oid)
+# Lookup a (possibly shared) tmc uart
+def lookup_tmc_uart_bitbang(config):
+ ppins = config.get_printer().lookup_object("pins")
+ rx_pin_params = ppins.lookup_pin(
+ config.get('uart_pin'), can_pullup=True, share_type="tmc_uart_rx")
+ tx_pin_desc = config.get('tx_pin', None)
+ if tx_pin_desc is None:
+ tx_pin_params = rx_pin_params
+ else:
+ tx_pin_params = ppins.lookup_pin(tx_pin_desc, share_type="tmc_uart_tx")
+ if rx_pin_params['chip'] is not tx_pin_params['chip']:
+ raise ppins.error("TMC uart rx and tx pins must be on the same mcu")
+ select_pins_desc = config.get('select_pins', None)
+ mcu_uart = rx_pin_params.get('class')
+ if mcu_uart is None:
+ mcu_uart = MCU_TMC_uart_bitbang(rx_pin_params, tx_pin_params,
+ select_pins_desc)
+ rx_pin_params['class'] = mcu_uart
+ instance_id = mcu_uart.register_instance(rx_pin_params, tx_pin_params,
+ select_pins_desc)
+ return instance_id, mcu_uart
+
# Helper code for communicating via TMC uart
class MCU_TMC_uart:
def __init__(self, config, name_to_reg, fields):
@@ -280,7 +353,8 @@ class MCU_TMC_uart:
self.name_to_reg = name_to_reg
self.fields = fields
self.ifcnt = None
- self.mcu_uart = MCU_TMC_uart_bitbang(config)
+ self.addr = 0
+ self.instance_id, self.mcu_uart = lookup_tmc_uart_bitbang(config)
def get_fields(self):
return self.fields
def get_register(self, reg_name):
@@ -288,7 +362,7 @@ class MCU_TMC_uart:
if self.printer.get_start_args().get('debugoutput') is not None:
return 0
for retry in range(5):
- val = self.mcu_uart.reg_read(0x00, reg)
+ val = self.mcu_uart.reg_read(self.instance_id, self.addr, reg)
if val is not None:
return val
raise self.printer.command_error(
@@ -301,7 +375,7 @@ class MCU_TMC_uart:
ifcnt = self.ifcnt
if ifcnt is None:
self.ifcnt = ifcnt = self.get_register("IFCNT")
- self.mcu_uart.reg_write(0x00, reg, val)
+ self.mcu_uart.reg_write(self.instance_id, self.addr, reg, val)
self.ifcnt = self.get_register("IFCNT")
if self.ifcnt == (ifcnt + 1) & 0xff:
return