[2.0.x] Small assorted collection of fixes and improvements (#10911)
* Misc fixes and improvements - Get rid of most critical sections on the Serial port drivers for AVR and DUE. Proper usage of FIFOs should allow interrupts to stay enabled without harm to queuing and dequeuing. Also, with 8-bit indices (for AVR) and up to 32-bit indices (for ARM), there is no need to protect reads and writes to those indices. - Simplify the XON/XOFF logic quite a bit. Much cleaner now (both for AVR and ARM) - Prevent a race condition (edge case) that could happen when estimating the proper value for the stepper timer (by reading it) and writing the calculated value for the time to the next ISR by disabling interrupts in those critical and small sections of the code - The problem could lead to lost steps. - Fix dual endstops not properly homing bug (maybe). * Set position immediately when possible
This commit is contained in:
committed by
Scott Lahteine
parent
ae1be0fa53
commit
d3c02410a8
@ -578,19 +578,22 @@ void Endstops::update() {
|
||||
|
||||
// Call the endstop triggered routine for single endstops
|
||||
#define PROCESS_ENDSTOP(AXIS,MINMAX) do { \
|
||||
if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX))) { \
|
||||
_ENDSTOP_HIT(AXIS, MINMAX); \
|
||||
planner.endstop_triggered(_AXIS(AXIS)); \
|
||||
} \
|
||||
}while(0)
|
||||
if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX))) { \
|
||||
_ENDSTOP_HIT(AXIS, MINMAX); \
|
||||
planner.endstop_triggered(_AXIS(AXIS)); \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
// Call the endstop triggered routine for single endstops
|
||||
// Call the endstop triggered routine for dual endstops
|
||||
#define PROCESS_DUAL_ENDSTOP(AXIS1, AXIS2, MINMAX) do { \
|
||||
if (TEST_ENDSTOP(_ENDSTOP(AXIS1, MINMAX)) || TEST_ENDSTOP(_ENDSTOP(AXIS2, MINMAX))) { \
|
||||
_ENDSTOP_HIT(AXIS1, MINMAX); \
|
||||
const byte dual_hit = TEST_ENDSTOP(_ENDSTOP(AXIS1, MINMAX)) | (TEST_ENDSTOP(_ENDSTOP(AXIS2, MINMAX)) << 1); \
|
||||
if (dual_hit) { \
|
||||
_ENDSTOP_HIT(AXIS1, MINMAX); \
|
||||
/* if not performing home or if both endstops were trigged during homing... */ \
|
||||
if (!stepper.performing_homing || dual_hit == 0x3) \
|
||||
planner.endstop_triggered(_AXIS(AXIS1)); \
|
||||
} \
|
||||
}while(0)
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
#if ENABLED(G38_PROBE_TARGET) && PIN_EXISTS(Z_MIN_PROBE) && !(CORE_IS_XY || CORE_IS_XZ)
|
||||
// If G38 command is active check Z_MIN_PROBE for ALL movement
|
||||
|
@ -108,7 +108,15 @@ class Endstops {
|
||||
/**
|
||||
* Get current endstops state
|
||||
*/
|
||||
FORCE_INLINE static esbits_t state() { return live_state; }
|
||||
FORCE_INLINE static esbits_t state() {
|
||||
return
|
||||
#if ENABLED(ENDSTOP_NOISE_FILTER)
|
||||
validated_live_state
|
||||
#else
|
||||
live_state
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report endstop hits to serial. Called from loop().
|
||||
|
@ -2467,9 +2467,13 @@ void Planner::_set_position_mm(const float &a, const float &b, const float &c, c
|
||||
position_float[C_AXIS] = c;
|
||||
position_float[E_AXIS] = e;
|
||||
#endif
|
||||
previous_nominal_speed_sqr = 0.0; // Resets planner junction speeds. Assumes start from rest.
|
||||
ZERO(previous_speed);
|
||||
buffer_sync_block();
|
||||
if (has_blocks_queued()) {
|
||||
//previous_nominal_speed_sqr = 0.0; // Reset planner junction speeds. Assume start from rest.
|
||||
//ZERO(previous_speed);
|
||||
buffer_sync_block();
|
||||
}
|
||||
else
|
||||
stepper.set_position(position[A_AXIS], position[B_AXIS], position[C_AXIS], position[E_AXIS]);
|
||||
}
|
||||
|
||||
void Planner::set_position_mm_kinematic(const float (&cart)[XYZE]) {
|
||||
@ -2501,8 +2505,12 @@ void Planner::set_position_mm(const AxisEnum axis, const float &v) {
|
||||
#if HAS_POSITION_FLOAT
|
||||
position_float[axis] = v;
|
||||
#endif
|
||||
previous_speed[axis] = 0.0;
|
||||
buffer_sync_block();
|
||||
if (has_blocks_queued()) {
|
||||
//previous_speed[axis] = 0.0;
|
||||
buffer_sync_block();
|
||||
}
|
||||
else
|
||||
stepper.set_position(axis, position[axis]);
|
||||
}
|
||||
|
||||
// Recalculate the steps/s^2 acceleration rates, based on the mm/s^2
|
||||
|
@ -102,13 +102,13 @@ uint8_t Stepper::last_direction_bits = 0,
|
||||
bool Stepper::abort_current_block;
|
||||
|
||||
#if ENABLED(X_DUAL_ENDSTOPS)
|
||||
bool Stepper::locked_x_motor = false, Stepper::locked_x2_motor = false;
|
||||
bool Stepper::locked_X_motor = false, Stepper::locked_X2_motor = false;
|
||||
#endif
|
||||
#if ENABLED(Y_DUAL_ENDSTOPS)
|
||||
bool Stepper::locked_y_motor = false, Stepper::locked_y2_motor = false;
|
||||
bool Stepper::locked_Y_motor = false, Stepper::locked_Y2_motor = false;
|
||||
#endif
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
bool Stepper::locked_z_motor = false, Stepper::locked_z2_motor = false;
|
||||
bool Stepper::locked_Z_motor = false, Stepper::locked_Z2_motor = false;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -182,26 +182,20 @@ uint8_t Stepper::step_loops, Stepper::step_loops_nominal;
|
||||
volatile int32_t Stepper::endstops_trigsteps[XYZ];
|
||||
|
||||
#if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
|
||||
#define LOCKED_X_MOTOR locked_x_motor
|
||||
#define LOCKED_Y_MOTOR locked_y_motor
|
||||
#define LOCKED_Z_MOTOR locked_z_motor
|
||||
#define LOCKED_X2_MOTOR locked_x2_motor
|
||||
#define LOCKED_Y2_MOTOR locked_y2_motor
|
||||
#define LOCKED_Z2_MOTOR locked_z2_motor
|
||||
#define DUAL_ENDSTOP_APPLY_STEP(A,V) \
|
||||
if (performing_homing) { \
|
||||
if (A##_HOME_DIR < 0) { \
|
||||
if (!(TEST(endstops.state(), A##_MIN) && count_direction[_AXIS(A)] < 0) && !LOCKED_##A##_MOTOR) A##_STEP_WRITE(V); \
|
||||
if (!(TEST(endstops.state(), A##2_MIN) && count_direction[_AXIS(A)] < 0) && !LOCKED_##A##2_MOTOR) A##2_STEP_WRITE(V); \
|
||||
} \
|
||||
else { \
|
||||
if (!(TEST(endstops.state(), A##_MAX) && count_direction[_AXIS(A)] > 0) && !LOCKED_##A##_MOTOR) A##_STEP_WRITE(V); \
|
||||
if (!(TEST(endstops.state(), A##2_MAX) && count_direction[_AXIS(A)] > 0) && !LOCKED_##A##2_MOTOR) A##2_STEP_WRITE(V); \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
A##_STEP_WRITE(V); \
|
||||
A##2_STEP_WRITE(V); \
|
||||
#define DUAL_ENDSTOP_APPLY_STEP(A,V) \
|
||||
if (performing_homing) { \
|
||||
if (A##_HOME_DIR < 0) { \
|
||||
if (!(TEST(endstops.state(), A##_MIN) && count_direction[_AXIS(A)] < 0) && !locked_##A##_motor) A##_STEP_WRITE(V); \
|
||||
if (!(TEST(endstops.state(), A##2_MIN) && count_direction[_AXIS(A)] < 0) && !locked_##A##2_motor) A##2_STEP_WRITE(V); \
|
||||
} \
|
||||
else { \
|
||||
if (!(TEST(endstops.state(), A##_MAX) && count_direction[_AXIS(A)] > 0) && !locked_##A##_motor) A##_STEP_WRITE(V); \
|
||||
if (!(TEST(endstops.state(), A##2_MAX) && count_direction[_AXIS(A)] > 0) && !locked_##A##2_motor) A##2_STEP_WRITE(V); \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
A##_STEP_WRITE(V); \
|
||||
A##2_STEP_WRITE(V); \
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1150,19 +1144,8 @@ void Stepper::set_directions() {
|
||||
HAL_STEP_TIMER_ISR {
|
||||
HAL_timer_isr_prologue(STEP_TIMER_NUM);
|
||||
|
||||
// Program timer compare for the maximum period, so it does NOT
|
||||
// flag an interrupt while this ISR is running - So changes from small
|
||||
// periods to big periods are respected and the timer does not reset to 0
|
||||
HAL_timer_set_compare(STEP_TIMER_NUM, HAL_TIMER_TYPE_MAX);
|
||||
|
||||
// Call the ISR scheduler
|
||||
hal_timer_t ticks = Stepper::isr_scheduler();
|
||||
|
||||
// Now 'ticks' contains the period to the next Stepper ISR - And we are
|
||||
// sure that the time has not arrived yet - Warrantied by the scheduler
|
||||
|
||||
// Set the next ISR to fire at the proper time
|
||||
HAL_timer_set_compare(STEP_TIMER_NUM, ticks);
|
||||
// Call the ISR
|
||||
Stepper::isr();
|
||||
|
||||
HAL_timer_isr_epilogue(STEP_TIMER_NUM);
|
||||
}
|
||||
@ -1173,8 +1156,15 @@ HAL_STEP_TIMER_ISR {
|
||||
#define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B)
|
||||
#endif
|
||||
|
||||
hal_timer_t Stepper::isr_scheduler() {
|
||||
uint32_t interval;
|
||||
void Stepper::isr() {
|
||||
|
||||
// Disable interrupts, to avoid ISR preemption while we reprogram the period
|
||||
DISABLE_ISRS();
|
||||
|
||||
// Program timer compare for the maximum period, so it does NOT
|
||||
// flag an interrupt while this ISR is running - So changes from small
|
||||
// periods to big periods are respected and the timer does not reset to 0
|
||||
HAL_timer_set_compare(STEP_TIMER_NUM, HAL_TIMER_TYPE_MAX);
|
||||
|
||||
// Count of ticks for the next ISR
|
||||
hal_timer_t next_isr_ticks = 0;
|
||||
@ -1185,6 +1175,9 @@ hal_timer_t Stepper::isr_scheduler() {
|
||||
// We need this variable here to be able to use it in the following loop
|
||||
hal_timer_t min_ticks;
|
||||
do {
|
||||
// Enable ISRs so the USART processing latency is reduced
|
||||
ENABLE_ISRS();
|
||||
|
||||
// Run main stepping pulse phase ISR if we have to
|
||||
if (!nextMainISR) Stepper::stepper_pulse_phase_isr();
|
||||
|
||||
@ -1198,13 +1191,15 @@ hal_timer_t Stepper::isr_scheduler() {
|
||||
// Run main stepping block processing ISR if we have to
|
||||
if (!nextMainISR) nextMainISR = Stepper::stepper_block_phase_isr();
|
||||
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
// Select the closest interval in time
|
||||
interval = (nextAdvanceISR <= nextMainISR) ? nextAdvanceISR : nextMainISR;
|
||||
#else
|
||||
// The interval is just the remaining time to the stepper ISR
|
||||
interval = nextMainISR;
|
||||
#endif
|
||||
uint32_t interval =
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
// Select the closest interval in time
|
||||
MIN(nextAdvanceISR, nextMainISR)
|
||||
#else
|
||||
// The interval is just the remaining time to the stepper ISR
|
||||
nextMainISR
|
||||
#endif
|
||||
;
|
||||
|
||||
// Limit the value to the maximum possible value of the timer
|
||||
NOMORE(interval, HAL_TIMER_TYPE_MAX);
|
||||
@ -1243,6 +1238,16 @@ hal_timer_t Stepper::isr_scheduler() {
|
||||
// Compute the tick count for the next ISR
|
||||
next_isr_ticks += interval;
|
||||
|
||||
/**
|
||||
* The following section must be done with global interrupts disabled.
|
||||
* We want nothing to interrupt it, as that could mess the calculations
|
||||
* we do for the next value to program in the period register of the
|
||||
* stepper timer and lead to skipped ISRs (if the value we happen to program
|
||||
* is less than the current count due to something preempting between the
|
||||
* read and the write of the new period value).
|
||||
*/
|
||||
DISABLE_ISRS();
|
||||
|
||||
/**
|
||||
* Get the current tick value + margin
|
||||
* Assuming at least 6µs between calls to this ISR...
|
||||
@ -1264,8 +1269,14 @@ hal_timer_t Stepper::isr_scheduler() {
|
||||
// Advance pulses if not enough time to wait for the next ISR
|
||||
} while (next_isr_ticks < min_ticks);
|
||||
|
||||
// Return the count of ticks for the next ISR
|
||||
return (hal_timer_t)next_isr_ticks;
|
||||
// Now 'next_isr_ticks' contains the period to the next Stepper ISR - And we are
|
||||
// sure that the time has not arrived yet - Warrantied by the scheduler
|
||||
|
||||
// Set the next ISR to fire at the proper time
|
||||
HAL_timer_set_compare(STEP_TIMER_NUM, hal_timer_t(next_isr_ticks));
|
||||
|
||||
// Don't forget to finally reenable interrupts
|
||||
ENABLE_ISRS();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,13 +81,13 @@ class Stepper {
|
||||
static bool abort_current_block; // Signals to the stepper that current block should be aborted
|
||||
|
||||
#if ENABLED(X_DUAL_ENDSTOPS)
|
||||
static bool locked_x_motor, locked_x2_motor;
|
||||
static bool locked_X_motor, locked_X2_motor;
|
||||
#endif
|
||||
#if ENABLED(Y_DUAL_ENDSTOPS)
|
||||
static bool locked_y_motor, locked_y2_motor;
|
||||
static bool locked_Y_motor, locked_Y2_motor;
|
||||
#endif
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
static bool locked_z_motor, locked_z2_motor;
|
||||
static bool locked_Z_motor, locked_Z2_motor;
|
||||
#endif
|
||||
|
||||
// Counter variables for the Bresenham line tracer
|
||||
@ -168,7 +168,7 @@ class Stepper {
|
||||
// Interrupt Service Routines
|
||||
|
||||
// The ISR scheduler
|
||||
static hal_timer_t isr_scheduler();
|
||||
static void isr();
|
||||
|
||||
// The stepper pulse phase ISR
|
||||
static void stepper_pulse_phase_isr();
|
||||
@ -222,18 +222,18 @@ class Stepper {
|
||||
|
||||
#if ENABLED(X_DUAL_ENDSTOPS)
|
||||
FORCE_INLINE static void set_homing_flag_x(const bool state) { performing_homing = state; }
|
||||
FORCE_INLINE static void set_x_lock(const bool state) { locked_x_motor = state; }
|
||||
FORCE_INLINE static void set_x2_lock(const bool state) { locked_x2_motor = state; }
|
||||
FORCE_INLINE static void set_x_lock(const bool state) { locked_X_motor = state; }
|
||||
FORCE_INLINE static void set_x2_lock(const bool state) { locked_X2_motor = state; }
|
||||
#endif
|
||||
#if ENABLED(Y_DUAL_ENDSTOPS)
|
||||
FORCE_INLINE static void set_homing_flag_y(const bool state) { performing_homing = state; }
|
||||
FORCE_INLINE static void set_y_lock(const bool state) { locked_y_motor = state; }
|
||||
FORCE_INLINE static void set_y2_lock(const bool state) { locked_y2_motor = state; }
|
||||
FORCE_INLINE static void set_y_lock(const bool state) { locked_Y_motor = state; }
|
||||
FORCE_INLINE static void set_y2_lock(const bool state) { locked_Y2_motor = state; }
|
||||
#endif
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
FORCE_INLINE static void set_homing_flag_z(const bool state) { performing_homing = state; }
|
||||
FORCE_INLINE static void set_z_lock(const bool state) { locked_z_motor = state; }
|
||||
FORCE_INLINE static void set_z2_lock(const bool state) { locked_z2_motor = state; }
|
||||
FORCE_INLINE static void set_z_lock(const bool state) { locked_Z_motor = state; }
|
||||
FORCE_INLINE static void set_z2_lock(const bool state) { locked_Z2_motor = state; }
|
||||
#endif
|
||||
|
||||
#if ENABLED(BABYSTEPPING)
|
||||
@ -247,16 +247,34 @@ class Stepper {
|
||||
// Set the current position in steps
|
||||
inline static void set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e) {
|
||||
planner.synchronize();
|
||||
CRITICAL_SECTION_START;
|
||||
|
||||
// Disable stepper interrupts, to ensure atomic setting of all the position variables
|
||||
const bool was_enabled = STEPPER_ISR_ENABLED();
|
||||
if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
|
||||
|
||||
// Set position
|
||||
_set_position(a, b, c, e);
|
||||
CRITICAL_SECTION_END;
|
||||
|
||||
// Reenable Stepper ISR
|
||||
if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
|
||||
}
|
||||
|
||||
inline static void set_position(const AxisEnum a, const int32_t &v) {
|
||||
planner.synchronize();
|
||||
CRITICAL_SECTION_START;
|
||||
|
||||
#ifdef __AVR__
|
||||
// Protect the access to the position. Only required for AVR, as
|
||||
// any 32bit CPU offers atomic access to 32bit variables
|
||||
const bool was_enabled = STEPPER_ISR_ENABLED();
|
||||
if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
|
||||
#endif
|
||||
|
||||
count_position[a] = v;
|
||||
CRITICAL_SECTION_END;
|
||||
|
||||
#ifdef __AVR__
|
||||
// Reenable Stepper ISR
|
||||
if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
|
Reference in New Issue
Block a user