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

- 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.

Co-Authored-By: ejtagle <ejtagle@hotmail.com>
This commit is contained in:
Scott Lahteine
2018-06-27 18:11:23 -05:00
committed by GitHub
parent cff2201629
commit b880028334
4 changed files with 183 additions and 104 deletions

View File

@@ -96,8 +96,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
@@ -108,6 +106,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;
@@ -1128,6 +1128,8 @@ HAL_STEP_TIMER_ISR {
#define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B)
void Stepper::isr() {
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
@@ -1615,6 +1617,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)
@@ -1824,6 +1827,29 @@ 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) {
#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);
// Return if the block is busy or not
return block == vnew;
}
void Stepper::init() {
// Init Digipot Motor Current
@@ -2021,7 +2047,9 @@ void Stepper::_set_position(const int32_t &a, const int32_t &b, const int32_t &c
int32_t Stepper::position(const AxisEnum axis) {
const bool was_enabled = STEPPER_ISR_ENABLED();
if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
const int32_t v = count_position[axis];
if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
return v;
}
@@ -2059,8 +2087,11 @@ void Stepper::endstop_triggered(const AxisEnum axis) {
int32_t Stepper::triggered_position(const AxisEnum axis) {
const bool was_enabled = STEPPER_ISR_ENABLED();
if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
const int32_t v = endstops_trigsteps[axis];
if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
return v;
}