aboutsummaryrefslogtreecommitdiffstats
path: root/klippy
diff options
context:
space:
mode:
authorFlorian Heilmann <Florian.Heilmann@gmx.net>2018-10-26 09:58:40 +0200
committerKevinOConnor <kevin@koconnor.net>2018-10-27 10:34:28 -0400
commitf57c29442cac6b110937af8960c9375192bb645e (patch)
treee6273b8ed373358c92326cefa6c9b5a23cc2ab17 /klippy
parent99989a668faa7e2f5c7cd0aea9ccffeb71f9905c (diff)
downloadkutter-f57c29442cac6b110937af8960c9375192bb645e.tar.gz
kutter-f57c29442cac6b110937af8960c9375192bb645e.tar.xz
kutter-f57c29442cac6b110937af8960c9375192bb645e.zip
Add SX1509 extra
Signed-off-by: Florian Heilmann <Florian.Heilmann@gmx.net>
Diffstat (limited to 'klippy')
-rw-r--r--klippy/extras/sx1509.py201
1 files changed, 201 insertions, 0 deletions
diff --git a/klippy/extras/sx1509.py b/klippy/extras/sx1509.py
new file mode 100644
index 00000000..71336ea6
--- /dev/null
+++ b/klippy/extras/sx1509.py
@@ -0,0 +1,201 @@
+# SX1509 Extra
+#
+# Copyright (C) 2018 Florian Heilmann <Florian.Heilmann@gmx.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import mcu
+import pins
+
+# Word registers
+REG_RESET = 0x7D
+REG_CLOCK = 0x1E
+REG_MISC = 0x1F
+REG_DIR = 0x0E
+REG_DATA = 0x10
+REG_PULLUP = 0x06
+REG_PULLDOWN = 0x08
+REG_INPUT_DISABLE = 0x00
+REG_ANALOG_DRIVER_ENABLE = 0x20
+
+
+# Byte registers
+REG_I_ON = [0x2A, 0x2D, 0x30, 0x33, 0x36, 0x3B, 0x40, 0x45,
+ 0x4A, 0x4D, 0x50, 0x53, 0x56, 0x5B, 0x5F, 0x65]
+class SX1509(object):
+ def __init__(self, config):
+ self._printer = config.get_printer()
+ self._name = config.get_name().split()[1]
+ self._chip_address = int(config.get('address'), 0)
+ self._bus = config.getint('bus', minval=0, default=0)
+ self._ppins = self._printer.lookup_object("pins")
+ self._ppins.register_chip("sx1509_" + self._name, self)
+ self._mcu = mcu.get_printer_mcu(self._printer, config.get('mcu', 'mcu'))
+ self._mcu.register_config_callback(self._build_config)
+ self._oid = self._mcu.create_oid()
+ self._i2c_write_cmd = self._i2c_modify_cmd = None
+ self._last_clock = 0
+ self._freq = 400000 # Fixed frequency for SX1509
+ # Set up registers default values
+ self.reg_dict = {REG_DIR : 0xFFFF, REG_DATA : 0, REG_PULLUP : 0, REG_PULLDOWN : 0,
+ REG_INPUT_DISABLE : 0, REG_ANALOG_DRIVER_ENABLE : 0}
+ self.reg_i_on_dict = {reg : 0 for reg in REG_I_ON}
+ def _build_config(self):
+ self._mcu.add_config_cmd("config_i2c oid=%d bus=%d rate=%d addr=%d" % (
+ self._oid, self._bus, self._freq, self._chip_address))
+ # Reset the chip
+ self._mcu.add_config_cmd("i2c_write oid=%d data=%02x%02x" % (
+ self._oid, REG_RESET, 0x12))
+ self._mcu.add_config_cmd("i2c_write oid=%d data=%02x%02x" % (
+ self._oid, REG_RESET, 0x34))
+ # Enable Oscillator
+ self._mcu.add_config_cmd("i2c_modify_bits oid=%d reg=%02x clear_set_bits=%02x%02x" % (
+ self._oid, REG_CLOCK, 0, (1 << 6)))
+ # Setup Clock Divider
+ self._mcu.add_config_cmd("i2c_modify_bits oid=%d reg=%02x clear_set_bits=%02x%02x" % (
+ self._oid, REG_MISC, 0, (1 << 4)))
+ # Transfer all regs with their initial cached state
+ for _reg, _data in self.reg_dict.iteritems():
+ self._mcu.add_config_cmd("i2c_write oid=%d data=%02x%04x" % (
+ self._oid, _reg, _data), is_init=True)
+ # Build commands
+ cmd_queue = self._mcu.alloc_command_queue()
+ self._i2c_write_cmd = self._mcu.lookup_command(
+ "i2c_write oid=%c data=%*s", cq=cmd_queue)
+ self._i2c_modify_cmd = self._mcu.lookup_command(
+ "i2c_modify_bits oid=%c reg=%*s clear_set_bits=%*s", cq=cmd_queue)
+ def setup_pin(self, pin_type, pin_params):
+ if pin_type == 'digital_out' and pin_params['pin'][0:4] == "PIN_":
+ return SX1509_digital_out(self, pin_params)
+ elif pin_type == 'pwm' and pin_params['pin'][0:4] == "PIN_":
+ return SX1509_pwm(self, pin_params)
+ raise pins.error("Wrong pin or incompatible type: %s with type %s! " % (
+ pin_params['pin'][0:4], pin_type))
+ def get_mcu(self):
+ return self._mcu
+ def get_oid(self):
+ return self._oid
+ def clear_bits_in_register(self, reg, bitmask):
+ if reg in self.reg_dict:
+ self.reg_dict[reg] &= ~(bitmask)
+ elif reg in self.reg_i_on_dict:
+ self.reg_i_on_dict[reg] &= ~(bitmask)
+ def set_bits_in_register(self, reg, bitmask):
+ if reg in self.reg_dict:
+ self.reg_dict[reg] |= bitmask
+ elif reg in self.reg_i_on_dict:
+ self.reg_i_on_dict[reg] |= bitmask
+ def set_register(self, reg, value):
+ if reg in self.reg_dict:
+ self.reg_dict[reg] = value
+ elif reg in self.reg_i_on_dict:
+ self.reg_i_on_dict[reg] = value
+ def send_register(self, reg, print_time=0):
+ data = [reg & 0xFF]
+ if reg in self.reg_dict:
+ # Word
+ data += [(self.reg_dict[reg] >> 8) & 0xFF, self.reg_dict[reg] & 0xFF]
+ elif reg in self.reg_i_on_dict:
+ # Byte
+ data += [self.reg_i_on_dict[reg] & 0xFF]
+ clock = self._mcu.print_time_to_clock(print_time)
+ self._i2c_write_cmd.send([self._oid, data],
+ minclock=self._last_clock, reqclock=clock)
+ self._last_clock = clock
+
+class SX1509_digital_out(object):
+ def __init__(self, sx1509, pin_params):
+ self._sx1509 = sx1509
+ self._mcu = sx1509.get_mcu()
+ self._sxpin = int(pin_params['pin'].split('_')[1])
+ self._bitmask = 1 << self._sxpin
+ self._pin = pin_params['pin']
+ self._invert = pin_params['invert']
+ self._start_value = self._shutdown_value = self._invert
+ self._is_static = False
+ self._set_cmd = self._clear_cmd = None
+ # Set direction to output
+ self._sx1509.clear_bits_in_register(REG_DIR, self._bitmask)
+ def get_mcu(self):
+ return self._mcu
+ def setup_max_duration(self, max_duration):
+ pass
+ def setup_start_value(self, start_value, shutdown_value, is_static=False):
+ if is_static or shutdown_value:
+ raise pins.error("SX1509 Pins should not be declared static or have a shutdown value")
+ self._start_value = (not not start_value) ^ self._invert
+ self._shutdown_value = self._invert
+ self._is_static = False
+ # We need to set the start value here so the register is
+ # updated before the SX1509 class writes it.
+ if self._start_value:
+ self._sx1509.set_bits_in_register(REG_DATA, self._bitmask)
+ else:
+ self._sx1509.clear_bits_in_register(REG_DATA, self._bitmask)
+ def set_digital(self, print_time, value):
+ if int(value) ^ self._invert:
+ self._sx1509.set_bits_in_register(REG_DATA, self._bitmask)
+ else:
+ self._sx1509.clear_bits_in_register(REG_DATA, self._bitmask)
+ self._sx1509.send_register(REG_DATA, print_time)
+ def set_pwm(self, print_time, value):
+ self.set_digital(print_time, value >= 0.5)
+
+class SX1509_pwm(object):
+ def __init__(self, sx1509, pin_params):
+ self._sx1509 = sx1509
+ self._mcu = sx1509.get_mcu()
+ self._sxpin = int(pin_params['pin'].split('_')[1])
+ self._bitmask = 1 << self._sxpin
+ self._i_on_reg = REG_I_ON[self._sxpin]
+ self._pin = pin_params['pin']
+ self._invert = pin_params['invert']
+ self._mcu.register_config_callback(self._build_config)
+ self._start_value = self._shutdown_value = float(self._invert)
+ self._is_static = False
+ self._max_duration = 2.
+ self._hardware_pwm = False
+ self._pwm_max = 0.
+ self._set_cmd = None
+ self._cycle_time = 0.
+ # Set required registers
+ self._sx1509.set_bits_in_register(REG_INPUT_DISABLE, self._bitmask)
+ self._sx1509.clear_bits_in_register(REG_PULLUP, self._bitmask)
+ self._sx1509.clear_bits_in_register(REG_DIR, self._bitmask)
+ self._sx1509.set_bits_in_register(REG_ANALOG_DRIVER_ENABLE, self._bitmask)
+ self._sx1509.clear_bits_in_register(REG_DATA, self._bitmask)
+ def _build_config(self):
+ if not self._hardware_pwm:
+ raise pins.error("SX1509_pwm must have hardware_pwm enabled")
+ # Send initial value
+ self._sx1509.set_register(self._i_on_reg, ~int(255 * self._start_value) & 0xFF)
+ self._mcu.add_config_cmd("i2c_write oid=%d data=%02x%02x" % (
+ self._sx1509.get_oid(),
+ self._i_on_reg,
+ self._sx1509.reg_i_on_dict[self._i_on_reg]
+ ),
+ is_init=True)
+ def get_mcu(self):
+ return self._mcu
+ def setup_max_duration(self, max_duration):
+ self._max_duration = max_duration
+ def setup_cycle_time(self, cycle_time, hardware_pwm=False):
+ self._cycle_time = cycle_time
+ self._hardware_pwm = hardware_pwm
+ def setup_start_value(self, start_value, shutdown_value, is_static=False):
+ if is_static or shutdown_value:
+ raise pins.error("SX1509 Pins should not be declared static or have a shutdown value")
+ if self._invert:
+ start_value = 1. - start_value
+ shutdown_value = 1. - shutdown_value
+ self._start_value = max(0., min(1., start_value))
+ self._shutdown_value = max(0., min(1., shutdown_value))
+ self._is_static = False
+ def set_pwm(self, print_time, value):
+ self._sx1509.set_register(self._i_on_reg, ~int(255 * value)
+ if not self._invert
+ else int(255 * value) & 0xFF)
+ self._sx1509.send_register(self._i_on_reg, print_time)
+
+def load_config_prefix(config):
+ return SX1509(config)