stepper: Support an optimized step/unstep function on ARM

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2019-03-09 18:18:24 -05:00
parent 9466c2d66c
commit 34d32c7823
3 changed files with 58 additions and 32 deletions

View File

@ -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.

View File

@ -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

View File

@ -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;