aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras
diff options
context:
space:
mode:
Diffstat (limited to 'klippy/extras')
-rw-r--r--klippy/extras/pwm_tool.py79
1 files changed, 52 insertions, 27 deletions
diff --git a/klippy/extras/pwm_tool.py b/klippy/extras/pwm_tool.py
index e3a7377c..0b3dd0c0 100644
--- a/klippy/extras/pwm_tool.py
+++ b/klippy/extras/pwm_tool.py
@@ -5,8 +5,8 @@
# This file may be distributed under the terms of the GNU GPLv3 license.
import chelper
-PIN_MIN_TIME = 0.100
MAX_SCHEDULE_TIME = 5.0
+CLOCK_SYNC_EXTRA_TIME = 0.050
class error(Exception):
pass
@@ -27,9 +27,15 @@ class MCU_queued_pwm:
self._pin = pin_params['pin']
self._invert = pin_params['invert']
self._start_value = self._shutdown_value = float(self._invert)
- self._last_clock = self._cycle_ticks = 0
+ self._last_clock = self._last_value = self._default_value = 0
+ self._duration_ticks = 0
self._pwm_max = 0.
self._set_cmd_tag = None
+ self._toolhead = None
+ printer = self._mcu.get_printer()
+ printer.register_event_handler("klippy:connect", self._handle_connect)
+ def _handle_connect(self):
+ self._toolhead = self._mcu.get_printer().lookup_object("toolhead")
def get_mcu(self):
return self._mcu
def setup_max_duration(self, max_duration):
@@ -52,20 +58,26 @@ class MCU_queued_pwm:
printtime = self._mcu.estimated_print_time(curtime)
self._last_clock = self._mcu.print_time_to_clock(printtime + 0.200)
cycle_ticks = self._mcu.seconds_to_clock(self._cycle_time)
- mdur_ticks = self._mcu.seconds_to_clock(self._max_duration)
- if mdur_ticks >= 1<<31:
+ if cycle_ticks >= 1<<31:
+ raise pins.error("PWM pin cycle time too large")
+ self._duration_ticks = self._mcu.seconds_to_clock(self._max_duration)
+ if self._duration_ticks >= 1<<31:
raise pins.error("PWM pin max duration too large")
+ if self._duration_ticks:
+ self._mcu.register_flush_callback(self._flush_notification)
if self._hardware_pwm:
self._pwm_max = self._mcu.get_constant_float("PWM_MAX")
+ self._default_value = self._shutdown_value * self._pwm_max
self._mcu.add_config_cmd(
"config_pwm_out oid=%d pin=%s cycle_ticks=%d value=%d"
" default_value=%d max_duration=%d"
% (self._oid, self._pin, cycle_ticks,
self._start_value * self._pwm_max,
- self._shutdown_value * self._pwm_max, mdur_ticks))
- svalue = int(self._start_value * self._pwm_max + 0.5)
+ self._default_value, self._duration_ticks))
+ self._last_value = int(self._start_value * self._pwm_max + 0.5)
self._mcu.add_config_cmd("queue_pwm_out oid=%d clock=%d value=%d"
- % (self._oid, self._last_clock, svalue),
+ % (self._oid, self._last_clock,
+ self._last_value),
on_restart=True)
self._set_cmd_tag = self._mcu.lookup_command(
"queue_pwm_out oid=%c clock=%u value=%hu",
@@ -74,39 +86,50 @@ class MCU_queued_pwm:
# Software PWM
if self._shutdown_value not in [0., 1.]:
raise pins.error("shutdown value must be 0.0 or 1.0 on soft pwm")
- if cycle_ticks >= 1<<31:
- raise pins.error("PWM pin cycle time too large")
self._mcu.add_config_cmd(
"config_digital_out oid=%d pin=%s value=%d"
" default_value=%d max_duration=%d"
% (self._oid, self._pin, self._start_value >= 1.0,
- self._shutdown_value >= 0.5, mdur_ticks))
+ self._shutdown_value >= 0.5, self._duration_ticks))
+ self._default_value = int(self._shutdown_value >= 0.5) * cycle_ticks
self._mcu.add_config_cmd(
"set_digital_out_pwm_cycle oid=%d cycle_ticks=%d"
% (self._oid, cycle_ticks))
- self._cycle_ticks = cycle_ticks
- svalue = int(self._start_value * cycle_ticks + 0.5)
+ self._pwm_max = float(cycle_ticks)
+ self._last_value = int(self._start_value * self._pwm_max + 0.5)
self._mcu.add_config_cmd(
"queue_digital_out oid=%d clock=%d on_ticks=%d"
- % (self._oid, self._last_clock, svalue), is_init=True)
+ % (self._oid, self._last_clock, self._last_value), is_init=True)
self._set_cmd_tag = self._mcu.lookup_command(
"queue_digital_out oid=%c clock=%u on_ticks=%u",
cq=cmd_queue).get_command_tag()
- def set_pwm(self, print_time, value):
- clock = self._mcu.print_time_to_clock(print_time)
- minclock = self._last_clock
- self._last_clock = clock
- if self._invert:
- value = 1. - value
- max_count = self._cycle_ticks
- if self._hardware_pwm:
- max_count = self._pwm_max
- v = int(max(0., min(1., value)) * max_count + 0.5)
- data = (self._set_cmd_tag, self._oid, clock & 0xffffffff, v)
+ def _send_update(self, clock, val):
+ self._last_clock = clock = max(self._last_clock, clock)
+ self._last_value = val
+ data = (self._set_cmd_tag, self._oid, clock & 0xffffffff, val)
ret = self._stepcompress_queue_mq_msg(self._stepqueue, clock,
data, len(data))
if ret:
raise error("Internal error in stepcompress")
+ # Notify toolhead so that it will flush this update
+ wakeclock = clock
+ if self._last_value != self._default_value:
+ # Continue flushing to resend time
+ wakeclock += self._duration_ticks
+ wake_print_time = self._mcu.clock_to_print_time(wakeclock)
+ self._toolhead.note_kinematic_activity(wake_print_time
+ + CLOCK_SYNC_EXTRA_TIME)
+ def set_pwm(self, print_time, value):
+ clock = self._mcu.print_time_to_clock(print_time)
+ if self._invert:
+ value = 1. - value
+ v = int(max(0., min(1., value)) * self._pwm_max + 0.5)
+ self._send_update(clock, v)
+ def _flush_notification(self, print_time, clock):
+ if self._last_value != self._default_value:
+ while clock >= self._last_clock + self._duration_ticks:
+ self._send_update(self._last_clock + self._duration_ticks,
+ self._last_value)
class PrinterOutputPin:
def __init__(self, config):
@@ -121,7 +144,11 @@ class PrinterOutputPin:
self.mcu_pin.setup_cycle_time(cycle_time, hardware_pwm)
self.scale = config.getfloat('scale', 1., above=0.)
self.last_print_time = 0.
- self.mcu_pin.setup_max_duration(0.)
+ # Support mcu checking for maximum duration
+ max_mcu_duration = config.getfloat('maximum_mcu_duration', 0.,
+ minval=0.500,
+ maxval=MAX_SCHEDULE_TIME)
+ self.mcu_pin.setup_max_duration(max_mcu_duration)
# Determine start and shutdown values
self.last_value = config.getfloat(
'value', 0., minval=0., maxval=self.scale) / self.scale
@@ -143,8 +170,6 @@ class PrinterOutputPin:
self.mcu_pin.set_pwm(print_time, value)
self.last_value = value
self.last_print_time = print_time
- toolhead = self.printer.lookup_object('toolhead')
- toolhead.note_kinematic_activity(print_time)
cmd_SET_PIN_help = "Set the value of an output pin"
def cmd_SET_PIN(self, gcmd):
# Read requested value