Skip to content

Commit

Permalink
replicape: add support for Linux hardware PWM (#1443)
Browse files Browse the repository at this point in the history
The servo pins (P9_14/P9_16) are muxed to the SOCs hardware PWM unit
driven by a 13MHz GP timer. They have to be driven by the linux host
mcu. This commits adds hardware PWM support using the linux sysfs
user space interface.

The servo pins can be specified as "replicape:servo0" and
"replicape:servo1". Removes the "servo0_enable", "servo1_enable"
configuration parameters.
Fixes #1105.

Signed-off-by: Janne Grunau <janne-3d@jannau.net>
  • Loading branch information
jannau authored and KevinOConnor committed Apr 6, 2019
1 parent 8c54fc8 commit 478a916
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 16 deletions.
14 changes: 8 additions & 6 deletions config/generic-replicape.cfg
Expand Up @@ -38,12 +38,6 @@ host_mcu: host
# This parameter controls the CFG6_ENN line on all stepper
# motors. True sets the enable lines to "open". The default is
# False.
#servo0_enable: False
# This parameter controls whether end_stop_X_2 is used for endstops
# (via P9_11) or for servo_0 (via P9_14). The default is False.
#servo1_enable: False
# This parameter controls whether end_stop_Y_2 is used for endstops
# (via P9_28) or for servo_1 (via P9_16). The default is False.
stepper_x_microstep_mode: spread16
# This parameter controls the CFG1 and CFG2 pins of the given
# stepper motor driver. Available options are: disable, 1, 2,
Expand Down Expand Up @@ -132,3 +126,11 @@ max_temp: 130

[fan]
pin: replicape:power_fan0

# The alternative servo pins channels on the endstops x2 and y2 can be used
# via the special relicape pins servo0 (P9_14) and servo1 (P9_16).
#[servo servo_x2]
#pin: replicape:servo0
# PWM output pin controlling the servo. This parameter must be
# provided.
#...
51 changes: 41 additions & 10 deletions klippy/extras/replicape.py
Expand Up @@ -108,6 +108,32 @@ def set_digital(self, print_time, value):
else:
self.pwm.set_pwm(print_time, 0.)

SERVO_PINS = {
"servo0": ("pwmchip0/pwm0", "gpio0_30", "gpio1_18"), # P9_11, P9_14
"servo1": ("pwmchip0/pwm1", "gpio3_17", "gpio1_19"), # P9_28, P9_16
}

class servo_pwm:
def __init__(self, replicape, pin_params):
config_name = pin_params['pin']
pwm_pin, resv1, resv2 = SERVO_PINS[config_name]
pin_params = dict(pin_params)
pin_params['pin'] = 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
self.setup_max_duration = self.mcu_pwm.setup_max_duration
self.setup_start_value = self.mcu_pwm.setup_start_value
self.set_pwm = self.mcu_pwm.set_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.reserve_pin(pru_mcu.get_name(), resv1, config_name)
ppins.reserve_pin(pru_mcu.get_name(), 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),
Expand Down Expand Up @@ -135,6 +161,8 @@ def __init__(self, config):
"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 }
# Setup stepper config
self.last_stepper_time = 0.
self.stepper_dacs = {}
Expand All @@ -159,11 +187,7 @@ def __init__(self, config):
self.stepper_dacs[channel] = cur / REPLICAPE_MAX_CURRENT
self.pins[prefix + 'enable'] = (ReplicapeDACEnable, channel)
self.enabled_channels = {ch: False for cl, ch in self.pins.values()}
if config.getboolean('servo0_enable', False):
shift_registers[1] |= 1
if config.getboolean('servo1_enable', False):
shift_registers[2] |= 1
self.sr_disabled = tuple(reversed(shift_registers))
self.sr_disabled = list(reversed(shift_registers))
if [i for i in [0, 1, 2] if 11+i in self.stepper_dacs]:
# Enable xyz steppers
shift_registers[0] &= ~1
Expand All @@ -173,7 +197,7 @@ def __init__(self, config):
if (config.getboolean('standstill_power_down', False)
and self.stepper_dacs):
shift_registers[4] &= ~1
self.sr_enabled = tuple(reversed(shift_registers))
self.sr_enabled = list(reversed(shift_registers))
self.sr_spi = bus.MCU_SPI(self.host_mcu, REPLICAPE_SHIFT_REGISTER_BUS,
None, 0, 50000000, self.sr_disabled)
self.sr_spi.spi_send(self.sr_disabled)
Expand Down Expand Up @@ -211,10 +235,17 @@ def note_pwm_enable(self, print_time, channel, value):
self.sr_spi.spi_send(sr, minclock=clock, reqclock=clock)
def setup_pin(self, pin_type, pin_params):
pin = pin_params['pin']
if pin not in self.pins:
raise pins.error("Unknown replicape pin %s" % (pin,))
pclass, channel = self.pins[pin]
return pclass(self, channel, pin_type, pin_params)
if pin in self.pins:
pclass, channel = self.pins[pin]
return pclass(self, channel, pin_type, pin_params)
elif pin in self.servo_pins:
# enable servo pins via shift registers
index = self.servo_pins[pin]
self.sr_enabled[index] |= 1
self.sr_disabled[index] |= 1
self.sr_spi.spi_send(self.sr_disabled)
return servo_pwm(self, pin_params)
raise pins.error("Unknown replicape pin %s" % (pin,))

def load_config(config):
return Replicape(config)

0 comments on commit 478a916

Please sign in to comment.