diff options
Diffstat (limited to 'klippy/extras/replicape.py')
-rw-r--r-- | klippy/extras/replicape.py | 197 |
1 files changed, 123 insertions, 74 deletions
diff --git a/klippy/extras/replicape.py b/klippy/extras/replicape.py index f7f7bb64..8f62a959 100644 --- a/klippy/extras/replicape.py +++ b/klippy/extras/replicape.py @@ -10,14 +10,15 @@ from . import bus REPLICAPE_MAX_CURRENT = 3.84 REPLICAPE_PCA9685_BUS = 2 REPLICAPE_PCA9685_ADDRESS = 0x70 -REPLICAPE_PCA9685_CYCLE_TIME = .001 +REPLICAPE_PCA9685_CYCLE_TIME = 0.001 PIN_MIN_TIME = 0.100 + class pca9685_pwm: def __init__(self, replicape, channel, pin_type, pin_params): self._replicape = replicape self._channel = channel - if pin_type not in ['digital_out', 'pwm']: + if pin_type not in ["digital_out", "pwm"]: raise pins.error("Pin type not supported on replicape") self._mcu = replicape.host_mcu self._mcu.register_config_callback(self._build_config) @@ -25,33 +26,42 @@ class pca9685_pwm: self._bus = REPLICAPE_PCA9685_BUS self._address = REPLICAPE_PCA9685_ADDRESS self._cycle_time = REPLICAPE_PCA9685_CYCLE_TIME - self._max_duration = 2. + self._max_duration = 2.0 self._oid = None - self._invert = pin_params['invert'] + self._invert = pin_params["invert"] self._start_value = self._shutdown_value = float(self._invert) self._is_enable = not not self._start_value self._last_clock = 0 - self._pwm_max = 0. + self._pwm_max = 0.0 self._set_cmd = None + 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): if hardware_pwm: raise pins.error("pca9685 does not support hardware_pwm parameter") if cycle_time != self._cycle_time: - logging.info("Ignoring pca9685 cycle time of %.6f (using %.6f)", - cycle_time, self._cycle_time) + logging.info( + "Ignoring pca9685 cycle time of %.6f (using %.6f)", + cycle_time, + self._cycle_time, + ) + def setup_start_value(self, start_value, 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)) + start_value = 1.0 - start_value + shutdown_value = 1.0 - shutdown_value + self._start_value = max(0.0, min(1.0, start_value)) + self._shutdown_value = max(0.0, min(1.0, shutdown_value)) self._replicape.note_pwm_start_value( - self._channel, self._start_value, self._shutdown_value) + self._channel, self._start_value, self._shutdown_value + ) self._is_enable = not not self._start_value + def _build_config(self): self._pwm_max = self._mcu.get_constant_float("PCA9685_MAX") cycle_ticks = self._mcu.seconds_to_clock(self._cycle_time) @@ -59,62 +69,83 @@ class pca9685_pwm: self._oid = self._mcu.create_oid() self._mcu.add_config_cmd( "config_pca9685 oid=%d bus=%d addr=%d channel=%d cycle_ticks=%d" - " value=%d default_value=%d max_duration=%d" % ( - self._oid, self._bus, self._address, self._channel, cycle_ticks, + " value=%d default_value=%d max_duration=%d" + % ( + self._oid, + self._bus, + self._address, + self._channel, + cycle_ticks, self._start_value * self._pwm_max, self._shutdown_value * self._pwm_max, - self._mcu.seconds_to_clock(self._max_duration))) + self._mcu.seconds_to_clock(self._max_duration), + ) + ) cmd_queue = self._mcu.alloc_command_queue() self._set_cmd = self._mcu.lookup_command( - "queue_pca9685_out oid=%c clock=%u value=%hu", cq=cmd_queue) + "queue_pca9685_out oid=%c clock=%u value=%hu", cq=cmd_queue + ) + def set_pwm(self, print_time, value): clock = self._mcu.print_time_to_clock(print_time) if self._invert: - value = 1. - value - value = int(max(0., min(1., value)) * self._pwm_max + 0.5) + value = 1.0 - value + value = int(max(0.0, min(1.0, value)) * self._pwm_max + 0.5) is_enable = not not value if is_enable != self._is_enable: self._is_enable = is_enable self._reactor.register_async_callback( - (lambda e, s=self, pt=print_time, ie=is_enable: - s._replicape.note_pwm_enable(pt, s._channel, ie))) - self._set_cmd.send([self._oid, clock, value], - minclock=self._last_clock, reqclock=clock) + ( + lambda e, s=self, pt=print_time, ie=is_enable: s._replicape.note_pwm_enable( + pt, s._channel, ie + ) + ) + ) + self._set_cmd.send( + [self._oid, clock, value], minclock=self._last_clock, reqclock=clock + ) self._last_clock = clock + def set_digital(self, print_time, value): if value: - self.set_pwm(print_time, 1.) + self.set_pwm(print_time, 1.0) else: - self.set_pwm(print_time, 0.) + self.set_pwm(print_time, 0.0) + class ReplicapeDACEnable: def __init__(self, replicape, channel, pin_type, pin_params): - if pin_type != 'digital_out': + if pin_type != "digital_out": raise pins.error("Replicape virtual enable pin must be digital_out") - if pin_params['invert']: + if pin_params["invert"]: raise pins.error("Replicape virtual enable pin can not be inverted") self.mcu = replicape.host_mcu self.value = replicape.stepper_dacs[channel] self.pwm = pca9685_pwm(replicape, channel, pin_type, pin_params) + def get_mcu(self): return self.mcu + def setup_max_duration(self, max_duration): self.pwm.setup_max_duration(max_duration) + def set_digital(self, print_time, value): if value: self.pwm.set_pwm(print_time, self.value) else: - self.pwm.set_pwm(print_time, 0.) + self.pwm.set_pwm(print_time, 0.0) + SERVO_PINS = { - "servo0": ("/pwm0", "gpio0_30", "gpio1_18"), # P9_11, P9_14 - "servo1": ("/pwm1", "gpio3_17", "gpio1_19"), # P9_28, P9_16 + "servo0": ("/pwm0", "gpio0_30", "gpio1_18"), # P9_11, P9_14 + "servo1": ("/pwm1", "gpio3_17", "gpio1_19"), # P9_28, P9_16 } + class servo_pwm: def __init__(self, replicape, pin_params): - config_name = pin_params['pin'] - pwmchip = 'pwmchip0' + config_name = pin_params["pin"] + pwmchip = "pwmchip0" if not replicape.host_mcu.is_fileoutput(): try: # Determine the pwmchip number for the servo channels @@ -124,13 +155,14 @@ class servo_pwm: # /sys/class/pwm/ used by the Linux MCU should be a symlink # to this directory. pwmdev = os.listdir( - '/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/') - pwmchip = [pc for pc in pwmdev if pc.startswith('pwmchip')][0] + "/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/" + ) + pwmchip = [pc for pc in pwmdev if pc.startswith("pwmchip")][0] except: raise pins.error("Replicape unable to determine pwmchip") pwm_pin, resv1, resv2 = SERVO_PINS[config_name] pin_params = dict(pin_params) - pin_params['pin'] = pwmchip + pwm_pin + pin_params["pin"] = pwmchip + pwm_pin # Setup actual pwm pin using linux hardware pwm on host self.mcu_pwm = replicape.host_mcu.setup_pin("pwm", pin_params) self.get_mcu = self.mcu_pwm.get_mcu @@ -140,90 +172,106 @@ class servo_pwm: # Reserve pins to warn user of conflicts pru_mcu = replicape.mcu_pwm_enable.get_mcu() printer = pru_mcu.get_printer() - ppins = printer.lookup_object('pins') + ppins = printer.lookup_object("pins") pin_resolver = ppins.get_pin_resolver(pru_mcu.get_name()) pin_resolver.reserve_pin(resv1, config_name) pin_resolver.reserve_pin(resv2, config_name) + def setup_cycle_time(self, cycle_time, hardware_pwm=False): self.mcu_pwm.setup_cycle_time(cycle_time, True) + ReplicapeStepConfig = { - 'disable': None, - '1': (1<<7)|(1<<5), '2': (1<<7)|(1<<5)|(1<<6), 'spread2': (1<<5), - '4': (1<<7)|(1<<5)|(1<<4), '16': (1<<7)|(1<<5)|(1<<6)|(1<<4), - 'spread4': (1<<5)|(1<<4), 'spread16': (1<<7), 'stealth4': (1<<7)|(1<<6), - 'stealth16': 0 + "disable": None, + "1": (1 << 7) | (1 << 5), + "2": (1 << 7) | (1 << 5) | (1 << 6), + "spread2": (1 << 5), + "4": (1 << 7) | (1 << 5) | (1 << 4), + "16": (1 << 7) | (1 << 5) | (1 << 6) | (1 << 4), + "spread4": (1 << 5) | (1 << 4), + "spread16": (1 << 7), + "stealth4": (1 << 7) | (1 << 6), + "stealth16": 0, } + class Replicape: def __init__(self, config): printer = config.get_printer() - ppins = printer.lookup_object('pins') - ppins.register_chip('replicape', self) - revisions = ['B3'] - config.getchoice('revision', revisions) - self.host_mcu = mcu.get_printer_mcu(printer, config.get('host_mcu')) + ppins = printer.lookup_object("pins") + ppins.register_chip("replicape", self) + revisions = ["B3"] + config.getchoice("revision", revisions) + self.host_mcu = mcu.get_printer_mcu(printer, config.get("host_mcu")) # Setup enable pin - enable_pin = config.get('enable_pin', '!gpio0_20') - self.mcu_pwm_enable = ppins.setup_pin('digital_out', enable_pin) - self.mcu_pwm_enable.setup_max_duration(0.) + enable_pin = config.get("enable_pin", "!gpio0_20") + self.mcu_pwm_enable = ppins.setup_pin("digital_out", enable_pin) + self.mcu_pwm_enable.setup_max_duration(0.0) self.mcu_pwm_start_value = self.mcu_pwm_shutdown_value = False - self.last_pwm_enable_time = 0. + self.last_pwm_enable_time = 0.0 # Setup power pins self.pins = { - "power_e": (pca9685_pwm, 5), "power_h": (pca9685_pwm, 3), + "power_e": (pca9685_pwm, 5), + "power_h": (pca9685_pwm, 3), "power_hotbed": (pca9685_pwm, 4), - "power_fan0": (pca9685_pwm, 7), "power_fan1": (pca9685_pwm, 8), - "power_fan2": (pca9685_pwm, 9), "power_fan3": (pca9685_pwm, 10) } - self.servo_pins = { - "servo0": 3, "servo1": 2 } + "power_fan0": (pca9685_pwm, 7), + "power_fan1": (pca9685_pwm, 8), + "power_fan2": (pca9685_pwm, 9), + "power_fan3": (pca9685_pwm, 10), + } + self.servo_pins = {"servo0": 3, "servo1": 2} # Setup stepper config self.stepper_dacs = {} shift_registers = [1, 0, 0, 1, 1] - for port, name in enumerate('xyzeh'): - prefix = 'stepper_%s_' % (name,) + for port, name in enumerate("xyzeh"): + prefix = "stepper_%s_" % (name,) sc = config.getchoice( - prefix + 'microstep_mode', ReplicapeStepConfig, 'disable') + prefix + "microstep_mode", ReplicapeStepConfig, "disable" + ) if sc is None: continue sc |= shift_registers[port] - if config.getboolean(prefix + 'chopper_off_time_high', False): - sc |= 1<<3 - if config.getboolean(prefix + 'chopper_hysteresis_high', False): - sc |= 1<<2 - if config.getboolean(prefix + 'chopper_blank_time_high', True): - sc |= 1<<1 + if config.getboolean(prefix + "chopper_off_time_high", False): + sc |= 1 << 3 + if config.getboolean(prefix + "chopper_hysteresis_high", False): + sc |= 1 << 2 + if config.getboolean(prefix + "chopper_blank_time_high", True): + sc |= 1 << 1 shift_registers[port] = sc channel = port + 11 cur = config.getfloat( - prefix + 'current', above=0., maxval=REPLICAPE_MAX_CURRENT) + prefix + "current", above=0.0, maxval=REPLICAPE_MAX_CURRENT + ) self.stepper_dacs[channel] = cur / REPLICAPE_MAX_CURRENT - self.pins[prefix + 'enable'] = (ReplicapeDACEnable, channel) + self.pins[prefix + "enable"] = (ReplicapeDACEnable, channel) self.enabled_channels = {ch: False for cl, ch in self.pins.values()} self.sr_disabled = list(reversed(shift_registers)) - if [i for i in [0, 1, 2] if 11+i in self.stepper_dacs]: + if [i for i in [0, 1, 2] if 11 + i in self.stepper_dacs]: # Enable xyz steppers shift_registers[0] &= ~1 - if [i for i in [3, 4] if 11+i in self.stepper_dacs]: + if [i for i in [3, 4] if 11 + i in self.stepper_dacs]: # Enable eh steppers shift_registers[3] &= ~1 - if (config.getboolean('standstill_power_down', False) - and self.stepper_dacs): + if config.getboolean("standstill_power_down", False) and self.stepper_dacs: shift_registers[4] &= ~1 self.sr_enabled = list(reversed(shift_registers)) sr_spi_bus = "spidev1.1" if not self.host_mcu.is_fileoutput() and os.path.exists( - '/sys/devices/platform/ocp/481a0000.spi/spi_master/spi2'): + "/sys/devices/platform/ocp/481a0000.spi/spi_master/spi2" + ): sr_spi_bus = "spidev2.1" self.sr_spi = bus.MCU_SPI(self.host_mcu, sr_spi_bus, None, 0, 50000000) self.sr_spi.setup_shutdown_msg(self.sr_disabled) self.sr_spi.spi_send(self.sr_disabled) + def note_pwm_start_value(self, channel, start_value, shutdown_value): self.mcu_pwm_start_value |= not not start_value self.mcu_pwm_shutdown_value |= not not shutdown_value self.mcu_pwm_enable.setup_start_value( - self.mcu_pwm_start_value, self.mcu_pwm_shutdown_value) + self.mcu_pwm_start_value, self.mcu_pwm_shutdown_value + ) self.enabled_channels[channel] = not not start_value + def note_pwm_enable(self, print_time, channel, is_enable): self.enabled_channels[channel] = is_enable # Check if need to set the pca9685 enable pin @@ -238,8 +286,7 @@ class Replicape: # Check if need to set the stepper enable lines if channel not in self.stepper_dacs: return - on_dacs = [1 for c in self.stepper_dacs.keys() - if self.enabled_channels[c]] + on_dacs = [1 for c in self.stepper_dacs.keys() if self.enabled_channels[c]] if not on_dacs: sr = self.sr_disabled elif is_enable and len(on_dacs) == 1: @@ -248,8 +295,9 @@ class Replicape: return clock = self.host_mcu.print_time_to_clock(print_time) self.sr_spi.spi_send(sr, minclock=clock, reqclock=clock) + def setup_pin(self, pin_type, pin_params): - pin = pin_params['pin'] + pin = pin_params["pin"] if pin in self.pins: pclass, channel = self.pins[pin] return pclass(self, channel, pin_type, pin_params) @@ -262,5 +310,6 @@ class Replicape: return servo_pwm(self, pin_params) raise pins.error("Unknown replicape pin %s" % (pin,)) + def load_config(config): return Replicape(config) |