kopia lustrzana https://gitlab.com/markol/Teathimble_Firmware
248 wiersze
7.9 KiB
C
248 wiersze
7.9 KiB
C
#ifndef _DDA_H
|
|
#define _DDA_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#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 */
|