Move endstop handling into a time-based procedure.
Before, endstops were checked on every step, wasting precious time. Checking them 500 times a second should be more than sufficient. Additionally, an endstop stop now properly decelerates the movement. This is one important step towards handling accidental endstop hits gracefully, as it avoids step losses in such situations.
This commit is contained in:
parent
da085670f4
commit
13ec2d7521
217
dda.c
217
dda.c
|
|
@ -19,7 +19,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "sersendf.h"
|
#include "sersendf.h"
|
||||||
#include "pinio.h"
|
#include "pinio.h"
|
||||||
#include "config.h"
|
#include "memory_barrier.h"
|
||||||
//#include "graycode.c"
|
//#include "graycode.c"
|
||||||
|
|
||||||
#ifdef DC_EXTRUDER
|
#ifdef DC_EXTRUDER
|
||||||
|
|
@ -461,35 +461,9 @@ void dda_start(DDA *dda) {
|
||||||
Finally we de-assert any asserted step pins.
|
Finally we de-assert any asserted step pins.
|
||||||
*/
|
*/
|
||||||
void dda_step(DDA *dda) {
|
void dda_step(DDA *dda) {
|
||||||
uint8_t endstop_stop; ///< Stop due to endstop trigger
|
|
||||||
uint8_t endstop_not_done = 0; ///< Which axes haven't finished homing
|
|
||||||
|
|
||||||
#if defined X_MIN_PIN || defined X_MAX_PIN
|
|
||||||
if (dda->endstop_check & 0x1) {
|
|
||||||
#if defined X_MIN_PIN
|
|
||||||
if (x_min() == dda->endstop_stop_cond)
|
|
||||||
move_state.debounce_count_xmin++;
|
|
||||||
else
|
|
||||||
move_state.debounce_count_xmin = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined X_MAX_PIN
|
|
||||||
if (x_max() == dda->endstop_stop_cond)
|
|
||||||
move_state.debounce_count_xmax++;
|
|
||||||
else
|
|
||||||
move_state.debounce_count_xmax = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
endstop_stop = move_state.debounce_count_xmin >= ENDSTOP_STEPS ||
|
|
||||||
move_state.debounce_count_xmax >= ENDSTOP_STEPS;
|
|
||||||
if (!endstop_stop)
|
|
||||||
endstop_not_done |= 0x1;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
endstop_stop = 0;
|
|
||||||
|
|
||||||
#if ! defined ACCELERATION_TEMPORAL
|
#if ! defined ACCELERATION_TEMPORAL
|
||||||
if ((move_state.x_steps) && ! endstop_stop) {
|
if (move_state.x_steps) {
|
||||||
move_state.x_counter -= dda->x_delta;
|
move_state.x_counter -= dda->x_delta;
|
||||||
if (move_state.x_counter < 0) {
|
if (move_state.x_counter < 0) {
|
||||||
x_step();
|
x_step();
|
||||||
|
|
@ -498,7 +472,7 @@ void dda_step(DDA *dda) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else // ACCELERATION_TEMPORAL
|
#else // ACCELERATION_TEMPORAL
|
||||||
if ((dda->axis_to_step == 'x') && ! endstop_stop) {
|
if (dda->axis_to_step == 'x') {
|
||||||
x_step();
|
x_step();
|
||||||
move_state.x_steps--;
|
move_state.x_steps--;
|
||||||
move_state.x_time += dda->x_step_interval;
|
move_state.x_time += dda->x_step_interval;
|
||||||
|
|
@ -506,32 +480,8 @@ void dda_step(DDA *dda) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined Y_MIN_PIN || defined Y_MAX_PIN
|
|
||||||
if (dda->endstop_check & 0x2) {
|
|
||||||
#if defined Y_MIN_PIN
|
|
||||||
if (y_min() == dda->endstop_stop_cond)
|
|
||||||
move_state.debounce_count_ymin++;
|
|
||||||
else
|
|
||||||
move_state.debounce_count_ymin = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined Y_MAX_PIN
|
|
||||||
if (y_max() == dda->endstop_stop_cond)
|
|
||||||
move_state.debounce_count_ymax++;
|
|
||||||
else
|
|
||||||
move_state.debounce_count_ymax = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
endstop_stop = move_state.debounce_count_ymin >= ENDSTOP_STEPS ||
|
|
||||||
move_state.debounce_count_ymax >= ENDSTOP_STEPS;
|
|
||||||
if (!endstop_stop)
|
|
||||||
endstop_not_done |= 0x2;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
endstop_stop = 0;
|
|
||||||
|
|
||||||
#if ! defined ACCELERATION_TEMPORAL
|
#if ! defined ACCELERATION_TEMPORAL
|
||||||
if ((move_state.y_steps) && ! endstop_stop) {
|
if (move_state.y_steps) {
|
||||||
move_state.y_counter -= dda->y_delta;
|
move_state.y_counter -= dda->y_delta;
|
||||||
if (move_state.y_counter < 0) {
|
if (move_state.y_counter < 0) {
|
||||||
y_step();
|
y_step();
|
||||||
|
|
@ -548,32 +498,8 @@ void dda_step(DDA *dda) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined Z_MIN_PIN || defined Z_MAX_PIN
|
|
||||||
if (dda->endstop_check & 0x4) {
|
|
||||||
#if defined Z_MIN_PIN
|
|
||||||
if (z_min() == dda->endstop_stop_cond)
|
|
||||||
move_state.debounce_count_zmin++;
|
|
||||||
else
|
|
||||||
move_state.debounce_count_zmin = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined Z_MAX_PIN
|
|
||||||
if (z_max() == dda->endstop_stop_cond)
|
|
||||||
move_state.debounce_count_zmax++;
|
|
||||||
else
|
|
||||||
move_state.debounce_count_zmax = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
endstop_stop = move_state.debounce_count_zmin >= ENDSTOP_STEPS ||
|
|
||||||
move_state.debounce_count_zmax >= ENDSTOP_STEPS;
|
|
||||||
if (!endstop_stop)
|
|
||||||
endstop_not_done |= 0x4;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
endstop_stop = 0;
|
|
||||||
|
|
||||||
#if ! defined ACCELERATION_TEMPORAL
|
#if ! defined ACCELERATION_TEMPORAL
|
||||||
if ((move_state.z_steps) && ! endstop_stop) {
|
if (move_state.z_steps) {
|
||||||
move_state.z_counter -= dda->z_delta;
|
move_state.z_counter -= dda->z_delta;
|
||||||
if (move_state.z_counter < 0) {
|
if (move_state.z_counter < 0) {
|
||||||
z_step();
|
z_step();
|
||||||
|
|
@ -582,7 +508,7 @@ void dda_step(DDA *dda) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else // ACCELERATION_TEMPORAL
|
#else // ACCELERATION_TEMPORAL
|
||||||
if ((dda->axis_to_step == 'z') && ! endstop_stop) {
|
if (dda->axis_to_step == 'z') {
|
||||||
z_step();
|
z_step();
|
||||||
move_state.z_steps--;
|
move_state.z_steps--;
|
||||||
move_state.z_time += dda->z_step_interval;
|
move_state.z_time += dda->z_step_interval;
|
||||||
|
|
@ -673,6 +599,17 @@ void dda_step(DDA *dda) {
|
||||||
// move_state.c, move_state.step_no, move_state.y_steps);
|
// move_state.c, move_state.step_no, move_state.y_steps);
|
||||||
}
|
}
|
||||||
move_state.step_no++;
|
move_state.step_no++;
|
||||||
|
|
||||||
|
#ifdef ACCELERATION_RAMPING
|
||||||
|
// This is a hack which deals with movements with an unknown number of
|
||||||
|
// acceleration steps. dda_create() sets a very high number, then.
|
||||||
|
if (move_state.c < dda->c_min &&
|
||||||
|
dda->rampup_steps > move_state.step_no + 5) {
|
||||||
|
dda->rampup_steps = move_state.step_no;
|
||||||
|
dda->rampdown_steps = dda->total_steps - dda->rampup_steps;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Print the number of steps actually needed for ramping up
|
// Print the number of steps actually needed for ramping up
|
||||||
// Needed for comparing the number with the one calculated in dda_create()
|
// Needed for comparing the number with the one calculated in dda_create()
|
||||||
//static char printed = 0;
|
//static char printed = 0;
|
||||||
|
|
@ -689,13 +626,6 @@ void dda_step(DDA *dda) {
|
||||||
// move_state.c, dda->c_min, move_state.n);
|
// move_state.c, dda->c_min, move_state.n);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: If we stop axes individually, could we home two or more axes at the same time?
|
|
||||||
if (dda->endstop_check != 0x0 && endstop_not_done == 0x0) {
|
|
||||||
move_state.x_steps = move_state.y_steps = move_state.z_steps = move_state.e_steps = 0;
|
|
||||||
endstops_off();
|
|
||||||
// as we stop without ramping down, we have to re-init our ramping here
|
|
||||||
dda_init();
|
|
||||||
}
|
|
||||||
#ifdef ACCELERATION_TEMPORAL
|
#ifdef ACCELERATION_TEMPORAL
|
||||||
/** How is this ACCELERATION TEMPORAL expected to work?
|
/** How is this ACCELERATION TEMPORAL expected to work?
|
||||||
|
|
||||||
|
|
@ -737,9 +667,10 @@ void dda_step(DDA *dda) {
|
||||||
dda->c <<= 8;
|
dda->c <<= 8;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If there are no steps left, we have finished.
|
// If there are no steps left or an endstop stop happened, we have finished.
|
||||||
if (move_state.x_steps == 0 && move_state.y_steps == 0 &&
|
if ((move_state.x_steps == 0 && move_state.y_steps == 0 &&
|
||||||
move_state.z_steps == 0 && move_state.e_steps == 0) {
|
move_state.z_steps == 0 && move_state.e_steps == 0) ||
|
||||||
|
(dda->endstop_check && move_state.n == -3)) {
|
||||||
dda->live = 0;
|
dda->live = 0;
|
||||||
#ifdef LOOKAHEAD
|
#ifdef LOOKAHEAD
|
||||||
// If look-ahead was using this move, it could have missed our activation:
|
// If look-ahead was using this move, it could have missed our activation:
|
||||||
|
|
@ -773,6 +704,112 @@ void dda_step(DDA *dda) {
|
||||||
unstep();
|
unstep();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Do regular movement maintenance.
|
||||||
|
|
||||||
|
This should be called pretty often, like once every 1 ot 2 milliseconds.
|
||||||
|
|
||||||
|
Currently, this is checking the endstops. These don't need to be checked on
|
||||||
|
every single step, so this code can be moved out of the highly time critical
|
||||||
|
dda_step(). At high precision (slow) searches of the endstop, this function
|
||||||
|
is called more often than dda_step() anyways.
|
||||||
|
|
||||||
|
In the future, acceleration and arc movement calculations might go here, too.
|
||||||
|
Updating speed 500 times a second is easily enough for smooth acceleration!
|
||||||
|
*/
|
||||||
|
void dda_clock() {
|
||||||
|
DDA *dda;
|
||||||
|
static DDA *last_dda = NULL;
|
||||||
|
static uint8_t endstop_stop = 0; ///< Stop due to endstop trigger
|
||||||
|
|
||||||
|
dda = queue_current_movement();
|
||||||
|
if (dda != last_dda) {
|
||||||
|
move_state.debounce_count_xmin = move_state.debounce_count_ymin =
|
||||||
|
move_state.debounce_count_zmin = move_state.debounce_count_xmax =
|
||||||
|
move_state.debounce_count_ymax = move_state.debounce_count_zmax = 0;
|
||||||
|
endstop_stop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dda == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Caution: we mangle step counters here without locking interrupts. This
|
||||||
|
// means, we trust dda isn't changed behind our back, which could
|
||||||
|
// in principle (but rarely) happen if endstops are checked not as
|
||||||
|
// endstop search, but as part of normal operations.
|
||||||
|
if (endstop_stop == 0) {
|
||||||
|
#if defined X_MIN_PIN || defined X_MAX_PIN
|
||||||
|
if (dda->endstop_check & 0x1) {
|
||||||
|
#if defined X_MIN_PIN
|
||||||
|
if (x_min() == dda->endstop_stop_cond)
|
||||||
|
move_state.debounce_count_xmin++;
|
||||||
|
else
|
||||||
|
move_state.debounce_count_xmin = 0;
|
||||||
|
#endif
|
||||||
|
#if defined X_MAX_PIN
|
||||||
|
if (x_max() == dda->endstop_stop_cond)
|
||||||
|
move_state.debounce_count_xmax++;
|
||||||
|
else
|
||||||
|
move_state.debounce_count_xmax = 0;
|
||||||
|
#endif
|
||||||
|
endstop_stop = move_state.debounce_count_xmin >= ENDSTOP_STEPS ||
|
||||||
|
move_state.debounce_count_xmax >= ENDSTOP_STEPS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined Y_MIN_PIN || defined Y_MAX_PIN
|
||||||
|
if (dda->endstop_check & 0x2) {
|
||||||
|
#if defined Y_MIN_PIN
|
||||||
|
if (y_min() == dda->endstop_stop_cond)
|
||||||
|
move_state.debounce_count_ymin++;
|
||||||
|
else
|
||||||
|
move_state.debounce_count_ymin = 0;
|
||||||
|
#endif
|
||||||
|
#if defined Y_MAX_PIN
|
||||||
|
if (y_max() == dda->endstop_stop_cond)
|
||||||
|
move_state.debounce_count_ymax++;
|
||||||
|
else
|
||||||
|
move_state.debounce_count_ymax = 0;
|
||||||
|
#endif
|
||||||
|
endstop_stop = move_state.debounce_count_ymin >= ENDSTOP_STEPS ||
|
||||||
|
move_state.debounce_count_ymax >= ENDSTOP_STEPS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined Z_MIN_PIN || defined Z_MAX_PIN
|
||||||
|
if (dda->endstop_check & 0x4) {
|
||||||
|
#if defined Z_MIN_PIN
|
||||||
|
if (z_min() == dda->endstop_stop_cond)
|
||||||
|
move_state.debounce_count_zmin++;
|
||||||
|
else
|
||||||
|
move_state.debounce_count_zmin = 0;
|
||||||
|
#endif
|
||||||
|
#if defined Z_MAX_PIN
|
||||||
|
if (z_max() == dda->endstop_stop_cond)
|
||||||
|
move_state.debounce_count_zmax++;
|
||||||
|
else
|
||||||
|
move_state.debounce_count_zmax = 0;
|
||||||
|
#endif
|
||||||
|
endstop_stop = move_state.debounce_count_zmin >= ENDSTOP_STEPS ||
|
||||||
|
move_state.debounce_count_zmax >= ENDSTOP_STEPS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If an endstop is definitely triggered, stop the movement.
|
||||||
|
if (endstop_stop) {
|
||||||
|
// For always smooth operations, don't halt apruptly,
|
||||||
|
// but start deceleration here.
|
||||||
|
ATOMIC_START
|
||||||
|
dda->rampdown_steps = move_state.step_no;
|
||||||
|
dda->rampup_steps = 0; // in case we're still accelerating
|
||||||
|
ATOMIC_END
|
||||||
|
|
||||||
|
endstops_off();
|
||||||
|
}
|
||||||
|
} /* if (endstop_stop == 0) */
|
||||||
|
|
||||||
|
last_dda = dda;
|
||||||
|
}
|
||||||
|
|
||||||
/// update global current_position struct
|
/// update global current_position struct
|
||||||
void update_current_position() {
|
void update_current_position() {
|
||||||
DDA *dda = &movebuffer[mb_tail];
|
DDA *dda = &movebuffer[mb_tail];
|
||||||
|
|
|
||||||
3
dda.h
3
dda.h
|
|
@ -205,6 +205,9 @@ void dda_start(DDA *dda) __attribute__ ((hot));
|
||||||
// DDA takes one step (called from timer interrupt)
|
// DDA takes one step (called from timer interrupt)
|
||||||
void dda_step(DDA *dda) __attribute__ ((hot));
|
void dda_step(DDA *dda) __attribute__ ((hot));
|
||||||
|
|
||||||
|
// regular movement maintenance
|
||||||
|
void dda_clock(void);
|
||||||
|
|
||||||
// update current_position
|
// update current_position
|
||||||
void update_current_position(void);
|
void update_current_position(void);
|
||||||
|
|
||||||
|
|
|
||||||
14
dda_queue.c
14
dda_queue.c
|
|
@ -56,6 +56,20 @@ uint8_t queue_empty() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the current movement, or NULL, if there's no movement going on.
|
||||||
|
DDA *queue_current_movement() {
|
||||||
|
DDA* current;
|
||||||
|
|
||||||
|
ATOMIC_START
|
||||||
|
current = &movebuffer[mb_tail];
|
||||||
|
|
||||||
|
if ( ! current->live || current->waitfor_temp || current->nullmove)
|
||||||
|
current = NULL;
|
||||||
|
ATOMIC_END
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------
|
// -------------------------------------------------------
|
||||||
// This is the one function called by the timer interrupt.
|
// This is the one function called by the timer interrupt.
|
||||||
// It calls a few other functions, though.
|
// It calls a few other functions, though.
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ extern DDA movebuffer[MOVEBUFFER_SIZE];
|
||||||
// queue status methods
|
// queue status methods
|
||||||
uint8_t queue_full(void);
|
uint8_t queue_full(void);
|
||||||
uint8_t queue_empty(void);
|
uint8_t queue_empty(void);
|
||||||
|
DDA *queue_current_movement(void);
|
||||||
|
|
||||||
// take one step
|
// take one step
|
||||||
void queue_step(void);
|
void queue_step(void);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue