DDA: convert um_to_steps_* to generic implementation.

A generic implementation here will allow callers to pass the
target axis in as a parameter so the callers can also be made more
generic.

Traumflug notes:

Split out application of the new implementation in dda.c into its
own commit.

This actually costs 128 bytes, but as we can access axes from within
a loop now, I expect to get more savings elsewhere.

Interestingly, binary size is raised by another 18 bytes if

  um_to_steps(int32_t, enum axis_e)

is changed to

  um_to_steps(enum axis_e, int32_t)

even on the 8-bit ATmega. While putting the axis number to the
front might be a bit more logical (think of additional parameters,
the axis number position would move), NXP application note
AN10963 states on page 10ff, 16-bit data should be 16-bit aligned
and 32-bit data should be 32-bit aligned for best performance.
Well, so let's do it this way.
This commit is contained in:
Phil Hord 2013-11-19 17:41:56 -05:00 committed by Markus Hitter
parent 84cbf2a42a
commit 62bdbd86d6
3 changed files with 44 additions and 14 deletions

6
dda.h
View File

@ -11,6 +11,12 @@
#endif
#endif
#ifndef SIMULATOR
#include <avr/pgmspace.h>
#else
#define PROGMEM
#endif
/*
types
*/

View File

@ -8,6 +8,26 @@
#include <stdlib.h>
#include <stdint.h>
/*!
Pre-calculated constant values for axis um <=> steps conversions.
These should be calculated at run-time once in dda_init() if the
STEPS_PER_M_* constants are ever replaced with run-time options.
*/
const axes_uint32_t PROGMEM axis_qn = {
(uint32_t)STEPS_PER_M_X / UM_PER_METER,
(uint32_t)STEPS_PER_M_Y / UM_PER_METER,
(uint32_t)STEPS_PER_M_Z / UM_PER_METER,
(uint32_t)STEPS_PER_M_E / UM_PER_METER
};
const axes_uint32_t PROGMEM axis_qr = {
(uint32_t)STEPS_PER_M_X % UM_PER_METER,
(uint32_t)STEPS_PER_M_Y % UM_PER_METER,
(uint32_t)STEPS_PER_M_Z % UM_PER_METER,
(uint32_t)STEPS_PER_M_E % UM_PER_METER
};
/*!
Integer multiply-divide algorithm. Returns the same as muldiv(multiplicand, multiplier, divisor), but also allowing to use precalculated quotients and remainders.

View File

@ -4,6 +4,7 @@
#include <stdint.h>
#include "config_wrapper.h"
#include "dda.h"
// return rounded result of multiplicand * multiplier / divisor
// this version is with quotient and remainder precalculated elsewhere
@ -18,36 +19,39 @@ inline int32_t muldiv(int32_t multiplicand, uint32_t multiplier,
multiplier % divisor, divisor);
}
/*
micrometer distance <=> motor step distance conversions
/*!
Micrometer distance <=> motor step distance conversions.
*/
// Like shown in the patch attached to this post:
// http://forums.reprap.org/read.php?147,89710,130225#msg-130225 ,
// it might be worth pre-calculating muldivQR()'s qn and rn in dda_init()
// as soon as STEPS_PER_M_{XYZE} is no longer a compile-time variable.
#define UM_PER_METER (1000000UL)
extern const axes_uint32_t PROGMEM axis_qn;
extern const axes_uint32_t PROGMEM axis_qr;
static int32_t um_to_steps(int32_t, enum axis_e) __attribute__ ((always_inline));
inline int32_t um_to_steps(int32_t distance, enum axis_e a) {
return muldivQR(distance, pgm_read_dword(&axis_qn[a]),
pgm_read_dword(&axis_qr[a]), UM_PER_METER);
}
static int32_t um_to_steps_x(int32_t) __attribute__ ((always_inline));
inline int32_t um_to_steps_x(int32_t distance) {
return muldivQR(distance, STEPS_PER_M_X / 1000000UL,
STEPS_PER_M_X % 1000000UL, 1000000UL);
return um_to_steps(distance, X);
}
static int32_t um_to_steps_y(int32_t) __attribute__ ((always_inline));
inline int32_t um_to_steps_y(int32_t distance) {
return muldivQR(distance, STEPS_PER_M_Y / 1000000UL,
STEPS_PER_M_Y % 1000000UL, 1000000UL);
return um_to_steps(distance, Y);
}
static int32_t um_to_steps_z(int32_t) __attribute__ ((always_inline));
inline int32_t um_to_steps_z(int32_t distance) {
return muldivQR(distance, STEPS_PER_M_Z / 1000000UL,
STEPS_PER_M_Z % 1000000UL, 1000000UL);
return um_to_steps(distance, Z);
}
static int32_t um_to_steps_e(int32_t) __attribute__ ((always_inline));
inline int32_t um_to_steps_e(int32_t distance) {
return muldivQR(distance, STEPS_PER_M_E / 1000000UL,
STEPS_PER_M_E % 1000000UL, 1000000UL);
return um_to_steps(distance, E);
}
// approximate 2D distance