replicape: add support for Linux hardware PWM (#1443)

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>
This commit is contained in:
Janne Grunau 2019-04-06 19:51:51 +02:00 committed by KevinOConnor
parent 8c54fc8753
commit 478a916f51
2 changed files with 49 additions and 16 deletions

View File

@ -38,12 +38,6 @@ host_mcu: host
# This parameter controls the CFG6_ENN line on all stepper # This parameter controls the CFG6_ENN line on all stepper
# motors. True sets the enable lines to "open". The default is # motors. True sets the enable lines to "open". The default is
# False. # 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 stepper_x_microstep_mode: spread16
# This parameter controls the CFG1 and CFG2 pins of the given # This parameter controls the CFG1 and CFG2 pins of the given
# stepper motor driver. Available options are: disable, 1, 2, # stepper motor driver. Available options are: disable, 1, 2,
@ -132,3 +126,11 @@ max_temp: 130
[fan] [fan]
pin: replicape:power_fan0 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.
#...

View File

@ -108,6 +108,32 @@ class ReplicapeDACEnable:
else: else:
self.pwm.set_pwm(print_time, 0.) 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 = { ReplicapeStepConfig = {
'disable': None, 'disable': None,
'1': (1<<7)|(1<<5), '2': (1<<7)|(1<<5)|(1<<6), 'spread2': (1<<5), '1': (1<<7)|(1<<5), '2': (1<<7)|(1<<5)|(1<<6), 'spread2': (1<<5),
@ -135,6 +161,8 @@ class Replicape:
"power_hotbed": (pca9685_pwm, 4), "power_hotbed": (pca9685_pwm, 4),
"power_fan0": (pca9685_pwm, 7), "power_fan1": (pca9685_pwm, 8), "power_fan0": (pca9685_pwm, 7), "power_fan1": (pca9685_pwm, 8),
"power_fan2": (pca9685_pwm, 9), "power_fan3": (pca9685_pwm, 10) } "power_fan2": (pca9685_pwm, 9), "power_fan3": (pca9685_pwm, 10) }
self.servo_pins = {
"servo0": 3, "servo1": 2 }
# Setup stepper config # Setup stepper config
self.last_stepper_time = 0. self.last_stepper_time = 0.
self.stepper_dacs = {} self.stepper_dacs = {}
@ -159,11 +187,7 @@ class Replicape:
self.stepper_dacs[channel] = cur / 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.enabled_channels = {ch: False for cl, ch in self.pins.values()}
if config.getboolean('servo0_enable', False): self.sr_disabled = list(reversed(shift_registers))
shift_registers[1] |= 1
if config.getboolean('servo1_enable', False):
shift_registers[2] |= 1
self.sr_disabled = tuple(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 # Enable xyz steppers
shift_registers[0] &= ~1 shift_registers[0] &= ~1
@ -173,7 +197,7 @@ class Replicape:
if (config.getboolean('standstill_power_down', False) if (config.getboolean('standstill_power_down', False)
and self.stepper_dacs): and self.stepper_dacs):
shift_registers[4] &= ~1 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, self.sr_spi = bus.MCU_SPI(self.host_mcu, REPLICAPE_SHIFT_REGISTER_BUS,
None, 0, 50000000, self.sr_disabled) None, 0, 50000000, self.sr_disabled)
self.sr_spi.spi_send(self.sr_disabled) self.sr_spi.spi_send(self.sr_disabled)
@ -211,10 +235,17 @@ class Replicape:
self.sr_spi.spi_send(sr, minclock=clock, reqclock=clock) self.sr_spi.spi_send(sr, minclock=clock, reqclock=clock)
def setup_pin(self, pin_type, pin_params): def setup_pin(self, pin_type, pin_params):
pin = pin_params['pin'] pin = pin_params['pin']
if pin not in self.pins: if pin in self.pins:
raise pins.error("Unknown replicape pin %s" % (pin,))
pclass, channel = self.pins[pin] pclass, channel = self.pins[pin]
return pclass(self, channel, pin_type, pin_params) 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): def load_config(config):
return Replicape(config) return Replicape(config)