mirror of https://github.com/Desuuuu/klipper.git
stepper: Add support for stepping on both edges of a step pulse
Add an optimized step function for drivers that support stepping on both rising and falling edges of the step pin. Enable this optimization on 32bit ARM micro-controllers. Automatically detect this capability in the host code and enable on TMC drivers running in SPI/UART mode. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
4acfd8d7c8
commit
689231df3a
|
@ -224,6 +224,8 @@ class TMCCommandHelper:
|
||||||
self.stepper_enable = self.printer.load_object(config, "stepper_enable")
|
self.stepper_enable = self.printer.load_object(config, "stepper_enable")
|
||||||
self.printer.register_event_handler("stepper:sync_mcu_position",
|
self.printer.register_event_handler("stepper:sync_mcu_position",
|
||||||
self._handle_sync_mcu_pos)
|
self._handle_sync_mcu_pos)
|
||||||
|
self.printer.register_event_handler("klippy:mcu_identify",
|
||||||
|
self._handle_mcu_identify)
|
||||||
self.printer.register_event_handler("klippy:connect",
|
self.printer.register_event_handler("klippy:connect",
|
||||||
self._handle_connect)
|
self._handle_connect)
|
||||||
# Set microstep config options
|
# Set microstep config options
|
||||||
|
@ -345,6 +347,12 @@ class TMCCommandHelper:
|
||||||
self.echeck_helper.stop_checks()
|
self.echeck_helper.stop_checks()
|
||||||
except self.printer.command_error as e:
|
except self.printer.command_error as e:
|
||||||
self.printer.invoke_shutdown(str(e))
|
self.printer.invoke_shutdown(str(e))
|
||||||
|
def _handle_mcu_identify(self):
|
||||||
|
# Lookup stepper object
|
||||||
|
force_move = self.printer.lookup_object("force_move")
|
||||||
|
self.stepper = force_move.lookup_stepper(self.stepper_name)
|
||||||
|
# Note pulse duration and step_both_edge optimizations available
|
||||||
|
self.stepper.setup_default_pulse_duration(.000000100, True)
|
||||||
def _handle_stepper_enable(self, print_time, is_enable):
|
def _handle_stepper_enable(self, print_time, is_enable):
|
||||||
if is_enable:
|
if is_enable:
|
||||||
cb = (lambda ev: self._do_enable(print_time))
|
cb = (lambda ev: self._do_enable(print_time))
|
||||||
|
@ -352,9 +360,10 @@ class TMCCommandHelper:
|
||||||
cb = (lambda ev: self._do_disable(print_time))
|
cb = (lambda ev: self._do_disable(print_time))
|
||||||
self.printer.get_reactor().register_callback(cb)
|
self.printer.get_reactor().register_callback(cb)
|
||||||
def _handle_connect(self):
|
def _handle_connect(self):
|
||||||
# Lookup stepper object
|
# Check if using step on both edges optimization
|
||||||
force_move = self.printer.lookup_object("force_move")
|
pulse_duration, step_both_edge = self.stepper.get_pulse_duration()
|
||||||
self.stepper = force_move.lookup_stepper(self.stepper_name)
|
if step_both_edge:
|
||||||
|
self.fields.set_field("dedge", 1)
|
||||||
# Check for soft stepper enable/disable
|
# Check for soft stepper enable/disable
|
||||||
enable_line = self.stepper_enable.lookup_enable(self.stepper_name)
|
enable_line = self.stepper_enable.lookup_enable(self.stepper_name)
|
||||||
enable_line.register_state_callback(self._handle_stepper_enable)
|
enable_line.register_state_callback(self._handle_stepper_enable)
|
||||||
|
|
|
@ -98,7 +98,6 @@ SignedFields = ["sgt"]
|
||||||
|
|
||||||
FieldFormatters = dict(tmc2130.FieldFormatters)
|
FieldFormatters = dict(tmc2130.FieldFormatters)
|
||||||
FieldFormatters.update({
|
FieldFormatters.update({
|
||||||
"dedge": (lambda v: "1(Both Edges Active!)" if v else ""),
|
|
||||||
"chm": (lambda v: "1(constant toff)" if v else "0(spreadCycle)"),
|
"chm": (lambda v: "1(constant toff)" if v else "0(spreadCycle)"),
|
||||||
"vsense": (lambda v: "1(165mV)" if v else "0(305mV)"),
|
"vsense": (lambda v: "1(165mV)" if v else "0(305mV)"),
|
||||||
"sdoff": (lambda v: "1(Step/Dir disabled!)" if v else ""),
|
"sdoff": (lambda v: "1(Step/Dir disabled!)" if v else ""),
|
||||||
|
|
|
@ -32,6 +32,7 @@ class MCU_stepper:
|
||||||
"Stepper dir pin must be on same mcu as step pin")
|
"Stepper dir pin must be on same mcu as step pin")
|
||||||
self._dir_pin = dir_pin_params['pin']
|
self._dir_pin = dir_pin_params['pin']
|
||||||
self._invert_dir = dir_pin_params['invert']
|
self._invert_dir = dir_pin_params['invert']
|
||||||
|
self._step_both_edge = self._req_step_both_edge = False
|
||||||
self._mcu_position_offset = 0.
|
self._mcu_position_offset = 0.
|
||||||
self._reset_cmd_tag = self._get_position_cmd = None
|
self._reset_cmd_tag = self._get_position_cmd = None
|
||||||
self._active_callbacks = []
|
self._active_callbacks = []
|
||||||
|
@ -54,6 +55,12 @@ class MCU_stepper:
|
||||||
def units_in_radians(self):
|
def units_in_radians(self):
|
||||||
# Returns true if distances are in radians instead of millimeters
|
# Returns true if distances are in radians instead of millimeters
|
||||||
return self._units_in_radians
|
return self._units_in_radians
|
||||||
|
def get_pulse_duration(self):
|
||||||
|
return self._step_pulse_duration, self._step_both_edge
|
||||||
|
def setup_default_pulse_duration(self, pulse_duration, step_both_edge):
|
||||||
|
if self._step_pulse_duration is None:
|
||||||
|
self._step_pulse_duration = pulse_duration
|
||||||
|
self._req_step_both_edge = step_both_edge
|
||||||
def setup_itersolve(self, alloc_func, *params):
|
def setup_itersolve(self, alloc_func, *params):
|
||||||
ffi_main, ffi_lib = chelper.get_ffi()
|
ffi_main, ffi_lib = chelper.get_ffi()
|
||||||
sk = ffi_main.gc(getattr(ffi_lib, alloc_func)(*params), ffi_lib.free)
|
sk = ffi_main.gc(getattr(ffi_lib, alloc_func)(*params), ffi_lib.free)
|
||||||
|
@ -61,11 +68,18 @@ class MCU_stepper:
|
||||||
def _build_config(self):
|
def _build_config(self):
|
||||||
if self._step_pulse_duration is None:
|
if self._step_pulse_duration is None:
|
||||||
self._step_pulse_duration = .000002
|
self._step_pulse_duration = .000002
|
||||||
|
invert_step = self._invert_step
|
||||||
|
sbe = int(self._mcu.get_constants().get('STEPPER_BOTH_EDGE', '0'))
|
||||||
|
if self._req_step_both_edge and sbe:
|
||||||
|
# Enable stepper optimized step on both edges
|
||||||
|
self._step_both_edge = True
|
||||||
|
self._step_pulse_duration = 0.
|
||||||
|
invert_step = -1
|
||||||
step_pulse_ticks = self._mcu.seconds_to_clock(self._step_pulse_duration)
|
step_pulse_ticks = self._mcu.seconds_to_clock(self._step_pulse_duration)
|
||||||
self._mcu.add_config_cmd(
|
self._mcu.add_config_cmd(
|
||||||
"config_stepper oid=%d step_pin=%s dir_pin=%s invert_step=%d"
|
"config_stepper oid=%d step_pin=%s dir_pin=%s invert_step=%d"
|
||||||
" step_pulse_ticks=%u" % (self._oid, self._step_pin, self._dir_pin,
|
" step_pulse_ticks=%u" % (self._oid, self._step_pin, self._dir_pin,
|
||||||
self._invert_step, step_pulse_ticks))
|
invert_step, step_pulse_ticks))
|
||||||
self._mcu.add_config_cmd("reset_step_clock oid=%d clock=0"
|
self._mcu.add_config_cmd("reset_step_clock oid=%d clock=0"
|
||||||
% (self._oid,), on_restart=True)
|
% (self._oid,), on_restart=True)
|
||||||
step_cmd_tag = self._mcu.lookup_command_tag(
|
step_cmd_tag = self._mcu.lookup_command_tag(
|
||||||
|
|
|
@ -108,6 +108,9 @@ config HAVE_STRICT_TIMING
|
||||||
config HAVE_CHIPID
|
config HAVE_CHIPID
|
||||||
bool
|
bool
|
||||||
default n
|
default n
|
||||||
|
config HAVE_STEPPER_BOTH_EDGE
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
|
||||||
config INLINE_STEPPER_HACK
|
config INLINE_STEPPER_HACK
|
||||||
# Enables gcc to inline stepper_event() into the main timer irq handler
|
# Enables gcc to inline stepper_event() into the main timer irq handler
|
||||||
|
|
|
@ -13,6 +13,7 @@ config ATSAM_SELECT
|
||||||
select HAVE_GPIO_BITBANGING
|
select HAVE_GPIO_BITBANGING
|
||||||
select HAVE_STRICT_TIMING
|
select HAVE_STRICT_TIMING
|
||||||
select HAVE_CHIPID
|
select HAVE_CHIPID
|
||||||
|
select HAVE_STEPPER_BOTH_EDGE
|
||||||
|
|
||||||
config BOARD_DIRECTORY
|
config BOARD_DIRECTORY
|
||||||
string
|
string
|
||||||
|
|
|
@ -13,6 +13,7 @@ config ATSAMD_SELECT
|
||||||
select HAVE_GPIO_BITBANGING
|
select HAVE_GPIO_BITBANGING
|
||||||
select HAVE_STRICT_TIMING
|
select HAVE_STRICT_TIMING
|
||||||
select HAVE_CHIPID
|
select HAVE_CHIPID
|
||||||
|
select HAVE_STEPPER_BOTH_EDGE
|
||||||
|
|
||||||
config HAVE_SERCOM
|
config HAVE_SERCOM
|
||||||
depends on HAVE_GPIO_I2C || HAVE_GPIO_SPI
|
depends on HAVE_GPIO_I2C || HAVE_GPIO_SPI
|
||||||
|
|
|
@ -13,6 +13,7 @@ config LPC_SELECT
|
||||||
select HAVE_STRICT_TIMING
|
select HAVE_STRICT_TIMING
|
||||||
select HAVE_CHIPID
|
select HAVE_CHIPID
|
||||||
select HAVE_GPIO_HARD_PWM
|
select HAVE_GPIO_HARD_PWM
|
||||||
|
select HAVE_STEPPER_BOTH_EDGE
|
||||||
|
|
||||||
config BOARD_DIRECTORY
|
config BOARD_DIRECTORY
|
||||||
string
|
string
|
||||||
|
|
|
@ -12,6 +12,7 @@ config RP2040_SELECT
|
||||||
select HAVE_STRICT_TIMING
|
select HAVE_STRICT_TIMING
|
||||||
select HAVE_CHIPID
|
select HAVE_CHIPID
|
||||||
select HAVE_GPIO_HARD_PWM
|
select HAVE_GPIO_HARD_PWM
|
||||||
|
select HAVE_STEPPER_BOTH_EDGE
|
||||||
|
|
||||||
config BOARD_DIRECTORY
|
config BOARD_DIRECTORY
|
||||||
string
|
string
|
||||||
|
|
|
@ -14,9 +14,18 @@
|
||||||
#include "stepper.h" // stepper_event
|
#include "stepper.h" // stepper_event
|
||||||
#include "trsync.h" // trsync_add_signal
|
#include "trsync.h" // trsync_add_signal
|
||||||
|
|
||||||
#if CONFIG_INLINE_STEPPER_HACK && CONFIG_MACH_AVR
|
#if CONFIG_INLINE_STEPPER_HACK && CONFIG_HAVE_STEPPER_BOTH_EDGE
|
||||||
|
#define HAVE_SINGLE_SCHEDULE 1
|
||||||
|
#define HAVE_EDGE_OPTIMIZATION 1
|
||||||
|
#define HAVE_AVR_OPTIMIZATION 0
|
||||||
|
DECL_CONSTANT("STEPPER_BOTH_EDGE", 1);
|
||||||
|
#elif CONFIG_INLINE_STEPPER_HACK && CONFIG_MACH_AVR
|
||||||
|
#define HAVE_SINGLE_SCHEDULE 1
|
||||||
|
#define HAVE_EDGE_OPTIMIZATION 0
|
||||||
#define HAVE_AVR_OPTIMIZATION 1
|
#define HAVE_AVR_OPTIMIZATION 1
|
||||||
#else
|
#else
|
||||||
|
#define HAVE_SINGLE_SCHEDULE 0
|
||||||
|
#define HAVE_EDGE_OPTIMIZATION 0
|
||||||
#define HAVE_AVR_OPTIMIZATION 0
|
#define HAVE_AVR_OPTIMIZATION 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -66,9 +75,10 @@ stepper_load_next(struct stepper *s, uint32_t min_next_time)
|
||||||
struct stepper_move *m = container_of(mn, struct stepper_move, node);
|
struct stepper_move *m = container_of(mn, struct stepper_move, node);
|
||||||
s->add = m->add;
|
s->add = m->add;
|
||||||
s->interval = m->interval + m->add;
|
s->interval = m->interval + m->add;
|
||||||
if (HAVE_AVR_OPTIMIZATION && s->flags & SF_SINGLE_SCHED) {
|
if (HAVE_SINGLE_SCHEDULE && s->flags & SF_SINGLE_SCHED) {
|
||||||
s->time.waketime += m->interval;
|
s->time.waketime += m->interval;
|
||||||
s->flags = m->add ? s->flags | SF_HAVE_ADD : s->flags & ~SF_HAVE_ADD;
|
if (HAVE_AVR_OPTIMIZATION)
|
||||||
|
s->flags = m->add ? s->flags|SF_HAVE_ADD : s->flags & ~SF_HAVE_ADD;
|
||||||
s->count = m->count;
|
s->count = m->count;
|
||||||
} else {
|
} else {
|
||||||
// On faster mcus, it is necessary to schedule unstep events
|
// On faster mcus, it is necessary to schedule unstep events
|
||||||
|
@ -97,6 +107,22 @@ stepper_load_next(struct stepper *s, uint32_t min_next_time)
|
||||||
return SF_RESCHEDULE;
|
return SF_RESCHEDULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optimized step function to step on each step pin edge
|
||||||
|
uint_fast8_t
|
||||||
|
stepper_event_edge(struct timer *t)
|
||||||
|
{
|
||||||
|
struct stepper *s = container_of(t, struct stepper, time);
|
||||||
|
gpio_out_toggle_noirq(s->step_pin);
|
||||||
|
uint32_t count = s->count - 1;
|
||||||
|
if (likely(count)) {
|
||||||
|
s->count = count;
|
||||||
|
s->time.waketime += s->interval;
|
||||||
|
s->interval += s->add;
|
||||||
|
return SF_RESCHEDULE;
|
||||||
|
}
|
||||||
|
return stepper_load_next(s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#define AVR_STEP_INSNS 40 // minimum instructions between step gpio pulses
|
#define AVR_STEP_INSNS 40 // minimum instructions between step gpio pulses
|
||||||
|
|
||||||
// AVR optimized step function
|
// AVR optimized step function
|
||||||
|
@ -150,6 +176,8 @@ reschedule_min:
|
||||||
uint_fast8_t
|
uint_fast8_t
|
||||||
stepper_event(struct timer *t)
|
stepper_event(struct timer *t)
|
||||||
{
|
{
|
||||||
|
if (HAVE_EDGE_OPTIMIZATION)
|
||||||
|
return stepper_event_edge(t);
|
||||||
if (HAVE_AVR_OPTIMIZATION)
|
if (HAVE_AVR_OPTIMIZATION)
|
||||||
return stepper_event_avr(t);
|
return stepper_event_avr(t);
|
||||||
return stepper_event_full(t);
|
return stepper_event_full(t);
|
||||||
|
@ -159,13 +187,19 @@ void
|
||||||
command_config_stepper(uint32_t *args)
|
command_config_stepper(uint32_t *args)
|
||||||
{
|
{
|
||||||
struct stepper *s = oid_alloc(args[0], command_config_stepper, sizeof(*s));
|
struct stepper *s = oid_alloc(args[0], command_config_stepper, sizeof(*s));
|
||||||
s->flags = args[3] ? SF_INVERT_STEP : 0;
|
int_fast8_t invert_step = args[3];
|
||||||
|
s->flags = invert_step > 0 ? SF_INVERT_STEP : 0;
|
||||||
s->step_pin = gpio_out_setup(args[1], s->flags & SF_INVERT_STEP);
|
s->step_pin = gpio_out_setup(args[1], s->flags & SF_INVERT_STEP);
|
||||||
s->dir_pin = gpio_out_setup(args[2], 0);
|
s->dir_pin = gpio_out_setup(args[2], 0);
|
||||||
s->position = -POSITION_BIAS;
|
s->position = -POSITION_BIAS;
|
||||||
s->step_pulse_ticks = args[4];
|
s->step_pulse_ticks = args[4];
|
||||||
move_queue_setup(&s->mq, sizeof(struct stepper_move));
|
move_queue_setup(&s->mq, sizeof(struct stepper_move));
|
||||||
if (HAVE_AVR_OPTIMIZATION) {
|
if (HAVE_EDGE_OPTIMIZATION) {
|
||||||
|
if (!s->step_pulse_ticks && invert_step < 0)
|
||||||
|
s->flags |= SF_SINGLE_SCHED;
|
||||||
|
else
|
||||||
|
s->time.func = stepper_event_full;
|
||||||
|
} else if (HAVE_AVR_OPTIMIZATION) {
|
||||||
if (s->step_pulse_ticks <= AVR_STEP_INSNS)
|
if (s->step_pulse_ticks <= AVR_STEP_INSNS)
|
||||||
s->flags |= SF_SINGLE_SCHED;
|
s->flags |= SF_SINGLE_SCHED;
|
||||||
else
|
else
|
||||||
|
@ -252,7 +286,7 @@ stepper_get_position(struct stepper *s)
|
||||||
{
|
{
|
||||||
uint32_t position = s->position;
|
uint32_t position = s->position;
|
||||||
// If stepper is mid-move, subtract out steps not yet taken
|
// If stepper is mid-move, subtract out steps not yet taken
|
||||||
if (HAVE_AVR_OPTIMIZATION && s->flags & SF_SINGLE_SCHED)
|
if (HAVE_SINGLE_SCHEDULE && s->flags & SF_SINGLE_SCHED)
|
||||||
position -= s->count;
|
position -= s->count;
|
||||||
else
|
else
|
||||||
position -= s->count / 2;
|
position -= s->count / 2;
|
||||||
|
@ -286,7 +320,8 @@ stepper_stop(struct trsync_signal *tss, uint8_t reason)
|
||||||
s->count = 0;
|
s->count = 0;
|
||||||
s->flags = (s->flags & (SF_INVERT_STEP|SF_SINGLE_SCHED)) | SF_NEED_RESET;
|
s->flags = (s->flags & (SF_INVERT_STEP|SF_SINGLE_SCHED)) | SF_NEED_RESET;
|
||||||
gpio_out_write(s->dir_pin, 0);
|
gpio_out_write(s->dir_pin, 0);
|
||||||
gpio_out_write(s->step_pin, s->flags & SF_INVERT_STEP);
|
if (!(HAVE_EDGE_OPTIMIZATION && s->flags & SF_SINGLE_SCHED))
|
||||||
|
gpio_out_write(s->step_pin, s->flags & SF_INVERT_STEP);
|
||||||
while (!move_queue_empty(&s->mq)) {
|
while (!move_queue_empty(&s->mq)) {
|
||||||
struct move_node *mn = move_queue_pop(&s->mq);
|
struct move_node *mn = move_queue_pop(&s->mq);
|
||||||
struct stepper_move *m = container_of(mn, struct stepper_move, node);
|
struct stepper_move *m = container_of(mn, struct stepper_move, node);
|
||||||
|
|
|
@ -13,6 +13,7 @@ config STM32_SELECT
|
||||||
select HAVE_GPIO_BITBANGING if !MACH_STM32F031
|
select HAVE_GPIO_BITBANGING if !MACH_STM32F031
|
||||||
select HAVE_STRICT_TIMING
|
select HAVE_STRICT_TIMING
|
||||||
select HAVE_CHIPID
|
select HAVE_CHIPID
|
||||||
|
select HAVE_STEPPER_BOTH_EDGE
|
||||||
|
|
||||||
config BOARD_DIRECTORY
|
config BOARD_DIRECTORY
|
||||||
string
|
string
|
||||||
|
|
Loading…
Reference in New Issue