forked from nicholaskell/Teacup_Firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdda.h
261 lines (219 loc) · 9.08 KB
/
dda.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#ifndef _DDA_H
#define _DDA_H
#include <stdint.h>
#include "config.h"
/*
micrometer to steps conversion
handle a few cases to avoid overflow while keeping reasonable accuracy
input is up to 20 bits, so we can multiply by 4096 at most
*/
#if STEPS_PER_M_X >= 4096000
#define um_to_steps_x(dest, src) \
do { dest = (src * (STEPS_PER_M_X / 10000L) + 50L) / 100L; } while (0)
#elif STEPS_PER_M_X >= 409600
#define um_to_steps_x(dest, src) \
do { dest = (src * (STEPS_PER_M_X / 1000L) + 500L) / 1000L; } while (0)
#elif STEPS_PER_M_X >= 40960
#define um_to_steps_x(dest, src) \
do { dest = (src * (STEPS_PER_M_X / 100L) + 5000L) / 10000L; } while (0)
#elif STEPS_PER_M_X >= 4096
#define um_to_steps_x(dest, src) \
do { dest = (src * (STEPS_PER_M_X / 10L) + 50000L) / 100000L; } while (0)
#else
#define um_to_steps_x(dest, src) \
do { dest = (src * (STEPS_PER_M_X / 1L) + 500000L) / 1000000L; } while (0)
#endif
#if STEPS_PER_M_Y >= 4096000
#define um_to_steps_y(dest, src) \
do { dest = (src * (STEPS_PER_M_Y / 10000L) + 50L) / 100L; } while (0)
#elif STEPS_PER_M_Y >= 409600
#define um_to_steps_y(dest, src) \
do { dest = (src * (STEPS_PER_M_Y / 1000L) + 500L) / 1000L; } while (0)
#elif STEPS_PER_M_Y >= 40960
#define um_to_steps_y(dest, src) \
do { dest = (src * (STEPS_PER_M_Y / 100L) + 5000L) / 10000L; } while (0)
#elif STEPS_PER_M_Y >= 4096
#define um_to_steps_y(dest, src) \
do { dest = (src * (STEPS_PER_M_Y / 10L) + 50000L) / 100000L; } while (0)
#else
#define um_to_steps_y(dest, src) \
do { dest = (src * (STEPS_PER_M_Y / 1L) + 500000L) / 1000000L; } while (0)
#endif
#if STEPS_PER_M_Z >= 4096000
#define um_to_steps_z(dest, src) \
do { dest = (src * (STEPS_PER_M_Z / 10000L) + 50L) / 100L; } while (0)
#elif STEPS_PER_M_Z >= 409600
#define um_to_steps_z(dest, src) \
do { dest = (src * (STEPS_PER_M_Z / 1000L) + 500L) / 1000L; } while (0)
#elif STEPS_PER_M_Z >= 40960
#define um_to_steps_z(dest, src) \
do { dest = (src * (STEPS_PER_M_Z / 100L) + 5000L) / 10000L; } while (0)
#elif STEPS_PER_M_Z >= 4096
#define um_to_steps_z(dest, src) \
do { dest = (src * (STEPS_PER_M_Z / 10L) + 50000L) / 100000L; } while (0)
#else
#define um_to_steps_z(dest, src) \
do { dest = (src * (STEPS_PER_M_Z / 1L) + 500000L) / 1000000L; } while (0)
#endif
#if STEPS_PER_M_E >= 4096000
#define um_to_steps_e(dest, src) \
do { dest = (src * (STEPS_PER_M_E / 10000L) + 50L) / 100L; } while (0)
#elif STEPS_PER_M_E >= 409600
#define um_to_steps_e(dest, src) \
do { dest = (src * (STEPS_PER_M_E / 1000L) + 500L) / 1000L; } while (0)
#elif STEPS_PER_M_E >= 40960
#define um_to_steps_e(dest, src) \
do { dest = (src * (STEPS_PER_M_E / 100L) + 5000L) / 10000L; } while (0)
#elif STEPS_PER_M_E >= 4096
#define um_to_steps_e(dest, src) \
do { dest = (src * (STEPS_PER_M_E / 10L) + 50000L) / 100000L; } while (0)
#else
#define um_to_steps_e(dest, src) \
do { dest = (src * (STEPS_PER_M_E / 1L) + 500000L) / 1000000L; } while (0)
#endif
#ifdef ACCELERATION_REPRAP
#ifdef ACCELERATION_RAMPING
#error Cant use ACCELERATION_REPRAP and ACCELERATION_RAMPING together.
#endif
#endif
/*
types
*/
/**
\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 {
// TODO TODO: We should really make up a loop for all axes.
// Think of what happens when a sixth axis (multi colour extruder)
// appears?
int32_t X;
int32_t Y;
int32_t Z;
int32_t E;
uint32_t F;
uint8_t e_relative :1; ///< bool: e axis relative? Overrides all_relative
} 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
int32_t x_counter; ///< counter for total_steps vs this axis
int32_t y_counter; ///< counter for total_steps vs this axis
int32_t z_counter; ///< counter for total_steps vs this axis
int32_t e_counter; ///< counter for total_steps vs this axis
// step counters
uint32_t x_steps; ///< number of steps on X axis
uint32_t y_steps; ///< number of steps on Y axis
uint32_t z_steps; ///< number of steps on Z axis
uint32_t e_steps; ///< number of steps on E axis
#ifdef ACCELERATION_RAMPING
/// counts actual steps done
uint32_t step_no;
/// time until next step
uint32_t c;
/// tracking variable
int32_t n;
#endif
#ifdef ACCELERATION_TEMPORAL
uint32_t x_time; ///< time of the last x step
uint32_t y_time; ///< time of the last y step
uint32_t z_time; ///< time of the last z step
uint32_t e_time; ///< time of the last e step
uint32_t all_time; ///< time of the last step of any axis
#endif
/// Endstop debouncing
uint8_t debounce_count_xmin, debounce_count_ymin, debounce_count_zmin;
uint8_t debounce_count_xmax, debounce_count_ymax, debounce_count_zmax;
} 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
#ifdef ACCELERATION_REPRAP
uint8_t accel :1; ///< bool: speed changes during this move, run accel code
#endif
// wait for temperature to stabilise flag
uint8_t waitfor_temp :1; ///< bool: wait for temperatures to reach their set values
// directions
uint8_t x_direction :1; ///< direction flag for X axis
uint8_t y_direction :1; ///< direction flag for Y axis
uint8_t z_direction :1; ///< direction flag for Z axis
uint8_t e_direction :1; ///< direction flag for E axis
};
uint8_t allflags; ///< used for clearing all flags
};
// distances
uint32_t x_delta; ///< number of steps on X axis
uint32_t y_delta; ///< number of steps on Y axis
uint32_t z_delta; ///< number of steps on Z axis
uint32_t e_delta; ///< number of steps on E axis
/// total number of steps: set to \f$\max(\Delta x, \Delta y, \Delta z, \Delta e)\f$
uint32_t total_steps;
uint32_t c; ///< time until next step, 24.8 fixed point
#ifdef ACCELERATION_REPRAP
uint32_t end_c; ///< time between 2nd last step and last step
int32_t n; ///< precalculated step time offset variable. At every step we calculate \f$c = c - (2 c / n)\f$; \f$n+=4\f$. See http://www.embedded.com/columns/technicalinsights/56800129?printable=true for full description
#endif
#ifdef ACCELERATION_RAMPING
/// 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;
#endif
#ifdef ACCELERATION_TEMPORAL
uint32_t x_step_interval; ///< time between steps on X axis
uint32_t y_step_interval; ///< time between steps on Y axis
uint32_t z_step_interval; ///< time between steps on Z axis
uint32_t e_step_interval; ///< time between steps on E axis
uint8_t axis_to_step; ///< axis to be stepped on the next interrupt
#endif
/// 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
} 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
*/
uint32_t approx_distance( uint32_t dx, uint32_t dy ) __attribute__ ((hot));
uint32_t approx_distance_3( uint32_t dx, uint32_t dy, uint32_t dz ) __attribute__ ((hot));
// const because return value is always the same given the same v
const uint8_t msbloc (uint32_t v) __attribute__ ((const));
// initialize dda structures
void dda_init(void);
// distribute a new startpoint
void dda_new_startpoint(void);
// create a DDA
void dda_create(DDA *dda, TARGET *target);
// start a created DDA (called from timer interrupt)
void dda_start(DDA *dda) __attribute__ ((hot));
// DDA takes one step (called from timer interrupt)
void dda_step(DDA *dda) __attribute__ ((hot));
// update current_position
void update_current_position(void);
#endif /* _DDA_H */