diff --git a/docs/MCU_Commands.md b/docs/MCU_Commands.md index 51505545..edbaef11 100644 --- a/docs/MCU_Commands.md +++ b/docs/MCU_Commands.md @@ -118,16 +118,16 @@ Common micro-controller objects This section lists some commonly used config commands. -* `config_digital_out oid=%c pin=%u default_value=%c +* `config_digital_out oid=%c pin=%u value=%c default_value=%c max_duration=%u` : This command creates an internal micro-controller object for the given GPIO 'pin'. The pin will be configured in digital output mode and set to an initial value as specified by - 'default_value' (0 for low, 1 for high). Creating a digital_out - object allows the host to schedule GPIO updates for the given pin at + 'value' (0 for low, 1 for high). Creating a digital_out object + allows the host to schedule GPIO updates for the given pin at specified times (see the schedule_digital_out command described below). Should the micro-controller software go into shutdown mode - then all configured digital_out objects will be set back to their - default values. The 'max_duration' parameter is used to implement a + then all configured digital_out objects will be set to + 'default_value'. The 'max_duration' parameter is used to implement a safety check - if it is non-zero then it is the maximum number of clock ticks that the host may set the given GPIO to a non-default value without further updates. For example, if the default_value is @@ -137,23 +137,23 @@ This section lists some commonly used config commands. feature can be used with heater pins to ensure the host does not enable the heater and then go off-line. -* `config_pwm_out oid=%c pin=%u cycle_ticks=%u default_value=%hu - max_duration=%u` : This command creates an internal object for - hardware based PWM pins that the host may schedule updates for. Its - usage is analogous to config_digital_out - see the description of - the 'set_pwm_out' and 'config_digital_out' commands for parameter - description. +* `config_pwm_out oid=%c pin=%u cycle_ticks=%u value=%hu + default_value=%hu max_duration=%u` : This command creates an + internal object for hardware based PWM pins that the host may + schedule updates for. Its usage is analogous to config_digital_out - + see the description of the 'set_pwm_out' and 'config_digital_out' + commands for parameter description. -* `config_soft_pwm_out oid=%c pin=%u cycle_ticks=%u default_value=%c - max_duration=%u` : This command creates an internal micro-controller - object for software implemented PWM. Unlike hardware pwm pins, a - software pwm object does not require any special hardware support - (other than the ability to configure the pin as a digital output - GPIO). Because the output switching is implemented in the - micro-controller software, it is recommended that the cycle_ticks - parameter correspond to a time of 10ms or greater. See the - description of the 'set_pwm_out' and 'config_digital_out' commands - for parameter description. +* `config_soft_pwm_out oid=%c pin=%u cycle_ticks=%u value=%c + default_value=%c max_duration=%u` : This command creates an internal + micro-controller object for software implemented PWM. Unlike + hardware pwm pins, a software pwm object does not require any + special hardware support (other than the ability to configure the + pin as a digital output GPIO). Because the output switching is + implemented in the micro-controller software, it is recommended that + the cycle_ticks parameter correspond to a time of 10ms or + greater. See the description of the 'set_pwm_out' and + 'config_digital_out' commands for parameter description. * `config_analog_in oid=%c pin=%u` : This command is used to configure a pin in analog input sampling mode. Once configured, the pin can be diff --git a/klippy/mcu.py b/klippy/mcu.py index a89e6106..9d76e0fa 100644 --- a/klippy/mcu.py +++ b/klippy/mcu.py @@ -226,7 +226,7 @@ class MCU_digital_out: self._oid = None self._static_value = None self._pin = pin_params['pin'] - self._invert = pin_params['invert'] + self._invert = self._shutdown_value = pin_params['invert'] self._max_duration = 2. self._last_clock = 0 self._last_value = None @@ -238,6 +238,8 @@ class MCU_digital_out: self._max_duration = max_duration def setup_static(self): self._static_value = not self._invert + def setup_shutdown_value(self, value): + self._shutdown_value = (not not value) ^ self._invert def build_config(self): if self._static_value is not None: self._mcu.add_config_cmd("set_digital_out pin=%s value=%d" % ( @@ -245,16 +247,16 @@ class MCU_digital_out: return self._oid = self._mcu.create_oid() self._mcu.add_config_cmd( - "config_digital_out oid=%d pin=%s default_value=%d" + "config_digital_out oid=%d pin=%s value=%d default_value=%d" " max_duration=%d" % ( - self._oid, self._pin, self._invert, + self._oid, self._pin, self._invert, self._shutdown_value, self._mcu.seconds_to_clock(self._max_duration))) self._set_cmd = self._mcu.lookup_command( "schedule_digital_out oid=%c clock=%u value=%c") def set_digital(self, print_time, value): clock = self._mcu.print_time_to_clock(print_time) msg = self._set_cmd.encode( - self._oid, clock, not not (value ^ self._invert)) + self._oid, clock, (not not value) ^ self._invert) self._mcu.send(msg, minclock=self._last_clock, reqclock=clock , cq=self._cmd_queue) self._last_clock = clock @@ -274,6 +276,7 @@ class MCU_pwm: self._static_value = None self._pin = pin_params['pin'] self._invert = pin_params['invert'] + self._shutdown_value = float(self._invert) self._last_clock = 0 self._pwm_max = 0. self._cmd_queue = mcu.alloc_command_queue() @@ -294,6 +297,10 @@ class MCU_pwm: if self._invert: value = 1. - value self._static_value = max(0., min(1., value)) + def setup_shutdown_value(self, value): + if self._invert: + value = 1. - value + self._shutdown_value = max(0., min(1., value)) def build_config(self): if self._hard_pwm: self._pwm_max = self._mcu.get_constant_float("PWM_MAX") @@ -305,27 +312,33 @@ class MCU_pwm: return self._oid = self._mcu.create_oid() self._mcu.add_config_cmd( - "config_pwm_out oid=%d pin=%s cycle_ticks=%d default_value=%d" - " max_duration=%d" % ( - self._oid, self._pin, self._cycle_time, self._invert, + "config_pwm_out oid=%d pin=%s cycle_ticks=%d value=%d" + " default_value=%d max_duration=%d" % ( + self._oid, self._pin, self._cycle_time, + self._invert * self._pwm_max, + self._shutdown_value * self._pwm_max, self._mcu.seconds_to_clock(self._max_duration))) self._set_cmd = self._mcu.lookup_command( "schedule_pwm_out oid=%c clock=%u value=%hu") else: self._pwm_max = self._mcu.get_constant_float("SOFT_PWM_MAX") if self._static_value is not None: - if self._static_value != 0. and self._static_value != 1.: - raise pins.error("static value on soft pwm not supported") + if self._static_value not in [0., 1.]: + raise pins.error( + "static value must be 0.0 or 1.0 on soft pwm") self._mcu.add_config_cmd("set_digital_out pin=%s value=%d" % ( self._pin, self._static_value >= 0.5)) return + if self._shutdown_value not in [0., 1.]: + raise pins.error( + "shutdown value must be 0.0 or 1.0 on soft pwm") self._oid = self._mcu.create_oid() self._mcu.add_config_cmd( - "config_soft_pwm_out oid=%d pin=%s cycle_ticks=%d" + "config_soft_pwm_out oid=%d pin=%s cycle_ticks=%d value=%d" " default_value=%d max_duration=%d" % ( self._oid, self._pin, self._mcu.seconds_to_clock(self._cycle_time), - self._invert, + self._invert, self._shutdown_value >= 0.5, self._mcu.seconds_to_clock(self._max_duration))) self._set_cmd = self._mcu.lookup_command( "schedule_soft_pwm_out oid=%c clock=%u value=%hu") diff --git a/src/gpiocmds.c b/src/gpiocmds.c index 69f60f97..52e3d8d5 100644 --- a/src/gpiocmds.c +++ b/src/gpiocmds.c @@ -44,14 +44,15 @@ digital_out_event(struct timer *timer) void command_config_digital_out(uint32_t *args) { + struct gpio_out pin = gpio_out_setup(args[1], args[2]); struct digital_out_s *d = oid_alloc(args[0], command_config_digital_out , sizeof(*d)); - d->default_value = args[2]; - d->pin = gpio_out_setup(args[1], d->default_value); - d->max_duration = args[3]; + d->pin = pin; + d->default_value = args[3]; + d->max_duration = args[4]; } DECL_COMMAND(command_config_digital_out, - "config_digital_out oid=%c pin=%u default_value=%c" + "config_digital_out oid=%c pin=%u value=%c default_value=%c" " max_duration=%u"); void @@ -159,17 +160,18 @@ soft_pwm_load_event(struct timer *timer) void command_config_soft_pwm_out(uint32_t *args) { + struct gpio_out pin = gpio_out_setup(args[1], !!args[3]); struct soft_pwm_s *s = oid_alloc(args[0], command_config_soft_pwm_out , sizeof(*s)); + s->pin = pin; s->cycle_time = args[2]; - s->default_value = !!args[3]; - s->max_duration = args[4]; + s->default_value = !!args[4]; + s->max_duration = args[5]; s->flags = s->default_value ? SPF_ON : 0; - s->pin = gpio_out_setup(args[1], s->default_value); } DECL_COMMAND(command_config_soft_pwm_out, - "config_soft_pwm_out oid=%c pin=%u cycle_ticks=%u default_value=%c" - " max_duration=%u"); + "config_soft_pwm_out oid=%c pin=%u cycle_ticks=%u value=%c" + " default_value=%c max_duration=%u"); void command_schedule_soft_pwm_out(uint32_t *args) diff --git a/src/pwmcmds.c b/src/pwmcmds.c index 82326b9d..cf025ddb 100644 --- a/src/pwmcmds.c +++ b/src/pwmcmds.c @@ -37,14 +37,15 @@ pwm_event(struct timer *timer) void command_config_pwm_out(uint32_t *args) { + struct gpio_pwm pin = gpio_pwm_setup(args[1], args[2], args[3]); struct pwm_out_s *p = oid_alloc(args[0], command_config_pwm_out, sizeof(*p)); - p->default_value = args[3]; - p->pin = gpio_pwm_setup(args[1], args[2], p->default_value); - p->max_duration = args[4]; + p->pin = pin; + p->default_value = args[4]; + p->max_duration = args[5]; } DECL_COMMAND(command_config_pwm_out, - "config_pwm_out oid=%c pin=%u cycle_ticks=%u default_value=%hu" - " max_duration=%u"); + "config_pwm_out oid=%c pin=%u cycle_ticks=%u value=%hu" + " default_value=%hu max_duration=%u"); void command_schedule_pwm_out(uint32_t *args)