#ifndef _DDA_H #define _DDA_H #include #include "config.h" // The distance of any move and a single axis should never go above this limit. // Check move_duration and c_limit calculations in dda.c #define MAX_DELTA_UM ((int32_t)(UINT32_MAX / 2400L)) // Enum to denote an axis enum axis_e { X = 0, Y, #ifdef STEPS_PER_M_Z Z, #endif #ifdef STEPS_PER_M_E E, #endif AXIS_COUNT }; /** \typedef axes_uint32_t \brief n-dimensional vector used to describe uint32_t axis information. Stored value can be anything unsigned. Units should be specified when declared. */ typedef uint32_t axes_uint32_t[AXIS_COUNT]; /** \typedef axes_int32_t \brief n-dimensional vector used to describe int32_t axis information. Stored value can be anything unsigned. Units should be specified when declared. */ typedef int32_t axes_int32_t[AXIS_COUNT]; /** \struct TARGET \brief target is simply a point in space/time X, Y, Z and E are in micrometers unless explcitely stated. F is in mm/min. */ typedef struct { axes_int32_t axis; uint32_t F; uint16_t f_multiplier; #ifdef STEPS_PER_M_E uint16_t e_multiplier; uint8_t e_relative :1; ///< bool: e axis relative? Overrides all_relative #endif } __attribute__ ((__packed__)) TARGET; /** \struct MOVE_STATE \brief this struct is made for tracking the current state of the movement Parts of this struct are initialised only once per reboot, so make sure dda_step() leaves them with a value compatible to begin a new movement at the end of the movement. Other parts are filled in by dda_start(). */ typedef struct { // bresenham counters axes_int32_t counter; ///< counter for total_steps vs each axis // step counters axes_uint32_t steps; ///< number of steps on each axis /// counts actual steps done uint32_t step_no; /// Endstop handling. uint8_t endstop_stop; ///< Stop due to endstop trigger uint8_t debounce_count_x, debounce_count_y; #ifdef STEPS_PER_M_Z uint8_t debounce_count_z; #endif } __attribute__ ((__packed__)) MOVE_STATE; /** \struct DDA \brief this is a digital differential analyser data struct This struct holds all the details of an individual multi-axis move, including pre-calculated acceleration data. This struct is filled in by dda_create(), called from enqueue(), called mostly from gcode_process() and from a few other places too (eg \file homing.c) */ typedef struct { /// this is where we should finish TARGET endpoint; union { struct { // status fields uint8_t nullmove :1; ///< bool: no axes move, maybe we wait for temperatures or change speed uint8_t live :1; ///< bool: this DDA is running and still has steps to do uint8_t done :1; ///< bool: this DDA is done. // wait for temperature to stabilise flag uint8_t waitfor :1; ///< bool: wait for something // directions // As we have muldiv() now, overflows became much less an issue and // it's likely time to get rid of these flags and use int instead of // uint for distance/speed calculations. --Traumflug 2014-07-04 uint8_t x_direction :1; ///< direction flag for X axis uint8_t y_direction :1; ///< direction flag for Y axis #ifdef STEPS_PER_M_Z uint8_t z_direction :1; ///< direction flag for Z axis #endif #ifdef STEPS_PER_M_E uint8_t e_direction :1; ///< direction flag for E axis #endif }; uint16_t allflags; ///< used for clearing all flags }__attribute__ ((__packed__)); // distances axes_uint32_t delta; ///< number of steps on each axis // uint8_t fast_axis; (see below) uint32_t total_steps; ///< steps of the "fast" axis uint32_t fast_um; ///< movement length of this fast axis uint32_t fast_spm; ///< steps per meter of the fast axis uint32_t c; ///< time until next step, 24.8 fixed point /// precalculated step time offset variable int32_t n; /// number of steps accelerating uint32_t rampup_steps; /// number of last step before decelerating uint32_t rampdown_steps; /// 24.8 fixed point timer value, maximum speed uint32_t c_min; #ifdef LOOKAHEAD // With the look-ahead functionality, it is possible to retain physical // movement between G1 moves. These variables keep track of the entry and // exit speeds between moves. uint32_t distance; uint32_t crossF; // These two are based on the "fast" axis, the axis with the most steps. uint32_t start_steps; ///< would be required to reach start feedrate uint32_t end_steps; ///< would be required to stop from end feedrate // Displacement vector, in um, based between the difference of the starting // point and the target. Required to obtain the jerk between 2 moves. // Note: x_delta and co are in steps, not um. axes_int32_t delta_um; // Number the moves to be able to test at the end of lookahead if the moves // are the same. Note: we do not need a lot of granularity here: more than // MOVEBUFFER_SIZE is already enough. #endif uint8_t id; /// Small variables. Many CPUs can access 32-bit variables at word or double /// word boundaries only and fill smaller variables in between with gaps, /// so keep small variables grouped together to reduce the amount of these /// gaps. See e.g. NXP application note AN10963, page 10f. uint8_t fast_axis; ///< number of the fast axis /// Endstop homing uint8_t endstop_check; ///< Do we need to check endstops? 0x1=Check X, 0x2=Check Y, 0x4=Check Z uint8_t endstop_stop_cond; ///< Endstop condition on which to stop motion: 0=Stop on detrigger, 1=Stop on trigger int16_t dc_motor_speed; /// speed change for spindle motor }__attribute__ ((__packed__)) DDA; /* variables */ /// startpoint holds the endpoint of the most recently created DDA, so we know where the next one created starts. could also be called last_endpoint extern TARGET startpoint; /// the same as above, counted in motor steps extern TARGET startpoint_steps; /// current_position holds the machine's current position. this is only updated when we step, or when G92 (set home) is received. extern TARGET current_position; /* methods */ #ifdef __cplusplus extern "C" { #endif // initialize dda structures void dda_init(void); #ifdef __cplusplus } #endif // distribute a new startpoint void dda_new_startpoint(void); // create a DDA void dda_create(DDA *dda, const TARGET *target); // start a created DDA (called from timer interrupt) void dda_start(DDA *dda); // DDA takes one step (called from timer interrupt) void dda_step(DDA *dda); // regular movement maintenance void dda_clock(void); // update current_position void update_current_position(void); // Sanity: E axis must be enabled along with Z #if ! defined STEPS_PER_M_Z && defined STEPS_PER_M_E #error Your config.h does specify STEPS_PER_M_E without STEPS_PER_M_Z #endif /*********************PLANNER*********************/ #ifdef LOOKAHEAD // Sanity: make sure the defines are in place #if ! defined MAX_JERK_X || ! defined MAX_JERK_Y #error Your config.h does not specify one of MAX_JERK_X, #error MAX_JERK_Y while LOOKAHEAD is enabled! #endif #if ! defined MAX_JERK_Z && defined STEPS_PER_M_Z || \ ! defined MAX_JERK_E && defined STEPS_PER_M_E #error Your config.h does not specify one or both of MAX_JERK_Z or #error MAX_JERK_E while LOOKAHEAD and STEPS_PER_M_Z or STEPS_PER_M_E is enabled! #endif // Sanity: the acceleration of Teacup is not implemented properly; as such we can only // do move joining when all axis use the same steps per mm. This is usually not an issue // for X and Y. #if STEPS_PER_M_X != STEPS_PER_M_Y #error "Look-ahead requires steps per m to be identical on the X and Y axis (for now)" #endif #define MAX(a,b) (((a)>(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b)) void dda_find_crossing_speed(DDA *prev, DDA *current); void dda_join_moves(DDA *prev, DDA *current); #endif /* LOOKAHEAD */ #endif /* _DDA_H */