Fix stepper/planner block handling, race conditions (#11098)

- Allow planner to alter the deceleration phase of the currently executing block.
- Remove BUSY flag, as it is NON ATOMIC to set bits in the Stepper ISR and Planner at the same time.
This commit is contained in:
Eduardo José Tagle
2018-06-27 20:11:16 -03:00
committed by Scott Lahteine
parent 4d3a9930c5
commit edb21f349a
4 changed files with 177 additions and 98 deletions

View File

@ -107,8 +107,6 @@ Stepper stepper; // Singleton
// public:
block_t* Stepper::current_block = NULL; // A pointer to the block currently being traced
#if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
bool Stepper::homing_dual_axis = false;
#endif
@ -119,6 +117,8 @@ block_t* Stepper::current_block = NULL; // A pointer to the block currently bei
// private:
block_t* Stepper::current_block = NULL; // A pointer to the block currently being traced
uint8_t Stepper::last_direction_bits = 0,
Stepper::axis_did_move;
@ -1665,6 +1665,7 @@ uint32_t Stepper::stepper_block_phase_isr() {
acceleration_time = deceleration_time = 0;
uint8_t oversampling = 0; // Assume we won't use it
#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
// At this point, we must decide if we can use Stepper movement axis smoothing.
uint32_t max_rate = current_block->nominal_rate; // Get the maximum rate (maximum event speed)
@ -1874,6 +1875,34 @@ uint32_t Stepper::stepper_block_phase_isr() {
}
#endif // LIN_ADVANCE
// Check if the given block is busy or not - Must not be called from ISR contexts
// The current_block could change in the middle of the read by an Stepper ISR, so
// we must explicitly prevent that!
bool Stepper::is_block_busy(const block_t* const block) {
#ifdef __AVR__
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() asm volatile("": : :"memory");
// Keep reading until 2 consecutive reads return the same value,
// meaning there was no update in-between caused by an interrupt.
// This works because stepper ISRs happen at a slower rate than
// successive reads of a variable, so 2 consecutive reads with
// the same value means no interrupt updated it.
block_t* vold, *vnew = current_block;
sw_barrier();
do {
vold = vnew;
vnew = current_block;
sw_barrier();
} while (vold != vnew);
#else
block_t *vnew = current_block;
#endif
// Return if the block is busy or not
return block == vnew;
}
void Stepper::init() {
// Init Digipot Motor Current