stepper: Support an optimized step/unstep function on ARM
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
9466c2d66c
commit
34d32c7823
15
src/Kconfig
15
src/Kconfig
|
@ -76,16 +76,17 @@ config STEP_DELAY
|
|||
help
|
||||
Specify the duration of the stepper step pulse time. This
|
||||
setting applies to all stepper drivers controlled by the
|
||||
micro-controller. If this value is set to zero then the code
|
||||
will "step" and "unstep" in the same C function.
|
||||
micro-controller. If this value is set to zero (or less) then
|
||||
the code will "step" and "unstep" in the same C function.
|
||||
|
||||
The default is zero for 8-bit AVR based micro-controllers, as
|
||||
it takes a little over 2us to step and unstep with this
|
||||
setting.
|
||||
A setting of zero (or less) on 8-bit AVR micro-controllers
|
||||
results in a minimum step pulse time a little over 2us.
|
||||
|
||||
The default for all other micro-controllers is 2us.
|
||||
A setting of zero on ARM micro-controllers typically results
|
||||
in a minimum step pulse time of 20 cpu cycles.
|
||||
|
||||
CUSTOMIZING THIS VALUE DOES NOT IMPROVE PERFORMANCE!
|
||||
The default for AVR is -1, for all other micro-controllers it
|
||||
is 2us.
|
||||
|
||||
# The HAVE_GPIO_x options allow boards to disable support for some
|
||||
# commands if the hardware does not support the feature.
|
||||
|
|
|
@ -13,7 +13,7 @@ config AVR_SELECT
|
|||
select HAVE_GPIO_BITBANGING if !MACH_atmega168
|
||||
|
||||
config STEP_DELAY
|
||||
default 0
|
||||
default -1
|
||||
|
||||
config BOARD_DIRECTORY
|
||||
string
|
||||
|
|
|
@ -34,8 +34,8 @@ struct stepper {
|
|||
struct timer time;
|
||||
uint32_t interval;
|
||||
int16_t add;
|
||||
#if !CONFIG_STEP_DELAY
|
||||
uint16_t count;
|
||||
#if CONFIG_STEP_DELAY <= 0
|
||||
uint_fast16_t count;
|
||||
#define next_step_time time.waketime
|
||||
#else
|
||||
uint32_t count;
|
||||
|
@ -70,9 +70,10 @@ stepper_load_next(struct stepper *s, uint32_t min_next_time)
|
|||
s->next_step_time += m->interval;
|
||||
s->add = m->add;
|
||||
s->interval = m->interval + m->add;
|
||||
if (!CONFIG_STEP_DELAY) {
|
||||
// On slow mcus see if the add can be optimized away
|
||||
s->flags = m->add ? s->flags | SF_HAVE_ADD : s->flags & ~SF_HAVE_ADD;
|
||||
if (CONFIG_STEP_DELAY <= 0) {
|
||||
if (CONFIG_MACH_AVR)
|
||||
// On AVR see if the add can be optimized away
|
||||
s->flags = m->add ? s->flags|SF_HAVE_ADD : s->flags & ~SF_HAVE_ADD;
|
||||
s->count = m->count;
|
||||
} else {
|
||||
// On faster mcus, it is necessary to schedule unstep events
|
||||
|
@ -100,30 +101,54 @@ stepper_load_next(struct stepper *s, uint32_t min_next_time)
|
|||
return SF_RESCHEDULE;
|
||||
}
|
||||
|
||||
// AVR optimized step function
|
||||
static uint_fast8_t
|
||||
stepper_event_avr(struct stepper *s)
|
||||
{
|
||||
gpio_out_toggle_noirq(s->step_pin);
|
||||
uint_fast16_t count = s->count - 1;
|
||||
if (likely(count)) {
|
||||
s->count = count;
|
||||
s->time.waketime += s->interval;
|
||||
gpio_out_toggle_noirq(s->step_pin);
|
||||
if (s->flags & SF_HAVE_ADD)
|
||||
s->interval += s->add;
|
||||
return SF_RESCHEDULE;
|
||||
}
|
||||
uint_fast8_t ret = stepper_load_next(s, 0);
|
||||
gpio_out_toggle_noirq(s->step_pin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Optimized step function for stepping and unstepping in same function
|
||||
static uint_fast8_t
|
||||
stepper_event_nodelay(struct stepper *s)
|
||||
{
|
||||
gpio_out_toggle_noirq(s->step_pin);
|
||||
uint_fast16_t count = s->count - 1;
|
||||
if (likely(count)) {
|
||||
s->count = count;
|
||||
s->time.waketime += s->interval;
|
||||
s->interval += s->add;
|
||||
gpio_out_toggle_noirq(s->step_pin);
|
||||
return SF_RESCHEDULE;
|
||||
}
|
||||
uint_fast8_t ret = stepper_load_next(s, 0);
|
||||
gpio_out_toggle_noirq(s->step_pin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Timer callback - step the given stepper.
|
||||
uint_fast8_t
|
||||
stepper_event(struct timer *t)
|
||||
{
|
||||
struct stepper *s = container_of(t, struct stepper, time);
|
||||
if (!CONFIG_STEP_DELAY) {
|
||||
// On slower mcus it is possible to simply step and unstep in
|
||||
// the same timer event.
|
||||
gpio_out_toggle_noirq(s->step_pin);
|
||||
uint16_t count = s->count - 1;
|
||||
if (likely(count)) {
|
||||
s->count = count;
|
||||
s->time.waketime += s->interval;
|
||||
gpio_out_toggle_noirq(s->step_pin);
|
||||
if (s->flags & SF_HAVE_ADD)
|
||||
s->interval += s->add;
|
||||
return SF_RESCHEDULE;
|
||||
}
|
||||
uint_fast8_t ret = stepper_load_next(s, 0);
|
||||
gpio_out_toggle_noirq(s->step_pin);
|
||||
return ret;
|
||||
}
|
||||
if (CONFIG_STEP_DELAY <= 0 && CONFIG_MACH_AVR)
|
||||
return stepper_event_avr(s);
|
||||
if (CONFIG_STEP_DELAY <= 0)
|
||||
return stepper_event_nodelay(s);
|
||||
|
||||
// On faster mcus, it is necessary to schedule the unstep event
|
||||
// Normal step code - schedule the unstep event
|
||||
uint32_t step_delay = timer_from_us(CONFIG_STEP_DELAY);
|
||||
uint32_t min_next_time = timer_read_time() + step_delay;
|
||||
gpio_out_toggle_noirq(s->step_pin);
|
||||
|
@ -243,7 +268,7 @@ static uint32_t
|
|||
stepper_get_position(struct stepper *s)
|
||||
{
|
||||
uint32_t position = s->position;
|
||||
if (!CONFIG_STEP_DELAY)
|
||||
if (CONFIG_STEP_DELAY <= 0)
|
||||
position -= s->count;
|
||||
else
|
||||
position -= s->count / 2;
|
||||
|
|
Loading…
Reference in New Issue