mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2024-11-26 21:36:21 +00:00
Fix, improve Linear Advance (#24533)
This commit is contained in:
parent
5dad7e0d03
commit
fd319928d2
@ -788,7 +788,7 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
|
|||||||
NOLESS(initial_rate, uint32_t(MINIMAL_STEP_RATE));
|
NOLESS(initial_rate, uint32_t(MINIMAL_STEP_RATE));
|
||||||
NOLESS(final_rate, uint32_t(MINIMAL_STEP_RATE));
|
NOLESS(final_rate, uint32_t(MINIMAL_STEP_RATE));
|
||||||
|
|
||||||
#if ENABLED(S_CURVE_ACCELERATION)
|
#if EITHER(S_CURVE_ACCELERATION, LIN_ADVANCE)
|
||||||
// If we have some plateau time, the cruise rate will be the nominal rate
|
// If we have some plateau time, the cruise rate will be the nominal rate
|
||||||
uint32_t cruise_rate = block->nominal_rate;
|
uint32_t cruise_rate = block->nominal_rate;
|
||||||
#endif
|
#endif
|
||||||
@ -820,7 +820,7 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
|
|||||||
accelerate_steps = _MIN(uint32_t(_MAX(accelerate_steps_float, 0)), block->step_event_count);
|
accelerate_steps = _MIN(uint32_t(_MAX(accelerate_steps_float, 0)), block->step_event_count);
|
||||||
decelerate_steps = block->step_event_count - accelerate_steps;
|
decelerate_steps = block->step_event_count - accelerate_steps;
|
||||||
|
|
||||||
#if ENABLED(S_CURVE_ACCELERATION)
|
#if EITHER(S_CURVE_ACCELERATION, LIN_ADVANCE)
|
||||||
// We won't reach the cruising rate. Let's calculate the speed we will reach
|
// We won't reach the cruising rate. Let's calculate the speed we will reach
|
||||||
cruise_rate = final_speed(initial_rate, accel, accelerate_steps);
|
cruise_rate = final_speed(initial_rate, accel, accelerate_steps);
|
||||||
#endif
|
#endif
|
||||||
@ -849,6 +849,14 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
|
|||||||
#endif
|
#endif
|
||||||
block->final_rate = final_rate;
|
block->final_rate = final_rate;
|
||||||
|
|
||||||
|
#if ENABLED(LIN_ADVANCE)
|
||||||
|
if (block->la_advance_rate) {
|
||||||
|
const float comp = extruder_advance_K[block->extruder] * block->steps.e / block->step_event_count;
|
||||||
|
block->max_adv_steps = cruise_rate * comp;
|
||||||
|
block->final_adv_steps = final_rate * comp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ENABLED(LASER_POWER_TRAP)
|
#if ENABLED(LASER_POWER_TRAP)
|
||||||
/**
|
/**
|
||||||
* Laser Trapezoid Calculations
|
* Laser Trapezoid Calculations
|
||||||
@ -899,75 +907,76 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
|
|||||||
#endif // LASER_POWER_TRAP
|
#endif // LASER_POWER_TRAP
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PLANNER SPEED DEFINITION
|
/**
|
||||||
+--------+ <- current->nominal_speed
|
* PLANNER SPEED DEFINITION
|
||||||
/ \
|
* +--------+ <- current->nominal_speed
|
||||||
current->entry_speed -> + \
|
* / \
|
||||||
| + <- next->entry_speed (aka exit speed)
|
* current->entry_speed -> + \
|
||||||
+-------------+
|
* | + <- next->entry_speed (aka exit speed)
|
||||||
time -->
|
* +-------------+
|
||||||
|
* time -->
|
||||||
Recalculates the motion plan according to the following basic guidelines:
|
*
|
||||||
|
* Recalculates the motion plan according to the following basic guidelines:
|
||||||
1. Go over every feasible block sequentially in reverse order and calculate the junction speeds
|
*
|
||||||
(i.e. current->entry_speed) such that:
|
* 1. Go over every feasible block sequentially in reverse order and calculate the junction speeds
|
||||||
a. No junction speed exceeds the pre-computed maximum junction speed limit or nominal speeds of
|
* (i.e. current->entry_speed) such that:
|
||||||
neighboring blocks.
|
* a. No junction speed exceeds the pre-computed maximum junction speed limit or nominal speeds of
|
||||||
b. A block entry speed cannot exceed one reverse-computed from its exit speed (next->entry_speed)
|
* neighboring blocks.
|
||||||
with a maximum allowable deceleration over the block travel distance.
|
* b. A block entry speed cannot exceed one reverse-computed from its exit speed (next->entry_speed)
|
||||||
c. The last (or newest appended) block is planned from a complete stop (an exit speed of zero).
|
* with a maximum allowable deceleration over the block travel distance.
|
||||||
2. Go over every block in chronological (forward) order and dial down junction speed values if
|
* c. The last (or newest appended) block is planned from a complete stop (an exit speed of zero).
|
||||||
a. The exit speed exceeds the one forward-computed from its entry speed with the maximum allowable
|
* 2. Go over every block in chronological (forward) order and dial down junction speed values if
|
||||||
acceleration over the block travel distance.
|
* a. The exit speed exceeds the one forward-computed from its entry speed with the maximum allowable
|
||||||
|
* acceleration over the block travel distance.
|
||||||
When these stages are complete, the planner will have maximized the velocity profiles throughout the all
|
*
|
||||||
of the planner blocks, where every block is operating at its maximum allowable acceleration limits. In
|
* When these stages are complete, the planner will have maximized the velocity profiles throughout the all
|
||||||
other words, for all of the blocks in the planner, the plan is optimal and no further speed improvements
|
* of the planner blocks, where every block is operating at its maximum allowable acceleration limits. In
|
||||||
are possible. If a new block is added to the buffer, the plan is recomputed according to the said
|
* other words, for all of the blocks in the planner, the plan is optimal and no further speed improvements
|
||||||
guidelines for a new optimal plan.
|
* are possible. If a new block is added to the buffer, the plan is recomputed according to the said
|
||||||
|
* guidelines for a new optimal plan.
|
||||||
To increase computational efficiency of these guidelines, a set of planner block pointers have been
|
*
|
||||||
created to indicate stop-compute points for when the planner guidelines cannot logically make any further
|
* To increase computational efficiency of these guidelines, a set of planner block pointers have been
|
||||||
changes or improvements to the plan when in normal operation and new blocks are streamed and added to the
|
* created to indicate stop-compute points for when the planner guidelines cannot logically make any further
|
||||||
planner buffer. For example, if a subset of sequential blocks in the planner have been planned and are
|
* changes or improvements to the plan when in normal operation and new blocks are streamed and added to the
|
||||||
bracketed by junction velocities at their maximums (or by the first planner block as well), no new block
|
* planner buffer. For example, if a subset of sequential blocks in the planner have been planned and are
|
||||||
added to the planner buffer will alter the velocity profiles within them. So we no longer have to compute
|
* bracketed by junction velocities at their maximums (or by the first planner block as well), no new block
|
||||||
them. Or, if a set of sequential blocks from the first block in the planner (or a optimal stop-compute
|
* added to the planner buffer will alter the velocity profiles within them. So we no longer have to compute
|
||||||
point) are all accelerating, they are all optimal and can not be altered by a new block added to the
|
* them. Or, if a set of sequential blocks from the first block in the planner (or a optimal stop-compute
|
||||||
planner buffer, as this will only further increase the plan speed to chronological blocks until a maximum
|
* point) are all accelerating, they are all optimal and can not be altered by a new block added to the
|
||||||
junction velocity is reached. However, if the operational conditions of the plan changes from infrequently
|
* planner buffer, as this will only further increase the plan speed to chronological blocks until a maximum
|
||||||
used feed holds or feedrate overrides, the stop-compute pointers will be reset and the entire plan is
|
* junction velocity is reached. However, if the operational conditions of the plan changes from infrequently
|
||||||
recomputed as stated in the general guidelines.
|
* used feed holds or feedrate overrides, the stop-compute pointers will be reset and the entire plan is
|
||||||
|
* recomputed as stated in the general guidelines.
|
||||||
Planner buffer index mapping:
|
*
|
||||||
- block_buffer_tail: Points to the beginning of the planner buffer. First to be executed or being executed.
|
* Planner buffer index mapping:
|
||||||
- block_buffer_head: Points to the buffer block after the last block in the buffer. Used to indicate whether
|
* - block_buffer_tail: Points to the beginning of the planner buffer. First to be executed or being executed.
|
||||||
the buffer is full or empty. As described for standard ring buffers, this block is always empty.
|
* - block_buffer_head: Points to the buffer block after the last block in the buffer. Used to indicate whether
|
||||||
- block_buffer_planned: Points to the first buffer block after the last optimally planned block for normal
|
* the buffer is full or empty. As described for standard ring buffers, this block is always empty.
|
||||||
streaming operating conditions. Use for planning optimizations by avoiding recomputing parts of the
|
* - block_buffer_planned: Points to the first buffer block after the last optimally planned block for normal
|
||||||
planner buffer that don't change with the addition of a new block, as describe above. In addition,
|
* streaming operating conditions. Use for planning optimizations by avoiding recomputing parts of the
|
||||||
this block can never be less than block_buffer_tail and will always be pushed forward and maintain
|
* planner buffer that don't change with the addition of a new block, as describe above. In addition,
|
||||||
this requirement when encountered by the Planner::release_current_block() routine during a cycle.
|
* this block can never be less than block_buffer_tail and will always be pushed forward and maintain
|
||||||
|
* this requirement when encountered by the Planner::release_current_block() routine during a cycle.
|
||||||
NOTE: Since the planner only computes on what's in the planner buffer, some motions with many short
|
*
|
||||||
segments (e.g., complex curves) may seem to move slowly. This is because there simply isn't
|
* NOTE: Since the planner only computes on what's in the planner buffer, some motions with many short
|
||||||
enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and
|
* segments (e.g., complex curves) may seem to move slowly. This is because there simply isn't
|
||||||
then decelerate to a complete stop at the end of the buffer, as stated by the guidelines. If this
|
* enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and
|
||||||
happens and becomes an annoyance, there are a few simple solutions:
|
* then decelerate to a complete stop at the end of the buffer, as stated by the guidelines. If this
|
||||||
|
* happens and becomes an annoyance, there are a few simple solutions:
|
||||||
- Maximize the machine acceleration. The planner will be able to compute higher velocity profiles
|
*
|
||||||
within the same combined distance.
|
* - Maximize the machine acceleration. The planner will be able to compute higher velocity profiles
|
||||||
|
* within the same combined distance.
|
||||||
- Maximize line motion(s) distance per block to a desired tolerance. The more combined distance the
|
*
|
||||||
planner has to use, the faster it can go.
|
* - Maximize line motion(s) distance per block to a desired tolerance. The more combined distance the
|
||||||
|
* planner has to use, the faster it can go.
|
||||||
- Maximize the planner buffer size. This also will increase the combined distance for the planner to
|
*
|
||||||
compute over. It also increases the number of computations the planner has to perform to compute an
|
* - Maximize the planner buffer size. This also will increase the combined distance for the planner to
|
||||||
optimal plan, so select carefully.
|
* compute over. It also increases the number of computations the planner has to perform to compute an
|
||||||
|
* optimal plan, so select carefully.
|
||||||
- Use G2/G3 arcs instead of many short segments. Arcs inform the planner of a safe exit speed at the
|
*
|
||||||
end of the last segment, which alleviates this problem.
|
* - Use G2/G3 arcs instead of many short segments. Arcs inform the planner of a safe exit speed at the
|
||||||
*/
|
* end of the last segment, which alleviates this problem.
|
||||||
|
*/
|
||||||
|
|
||||||
// The kernel called by recalculate() when scanning the plan from last to first entry.
|
// The kernel called by recalculate() when scanning the plan from last to first entry.
|
||||||
void Planner::reverse_pass_kernel(block_t * const current, const block_t * const next
|
void Planner::reverse_pass_kernel(block_t * const current, const block_t * const next
|
||||||
@ -1211,13 +1220,6 @@ void Planner::recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t
|
|||||||
// NOTE: Entry and exit factors always > 0 by all previous logic operations.
|
// NOTE: Entry and exit factors always > 0 by all previous logic operations.
|
||||||
const float nomr = 1.0f / block->nominal_speed;
|
const float nomr = 1.0f / block->nominal_speed;
|
||||||
calculate_trapezoid_for_block(block, current_entry_speed * nomr, next_entry_speed * nomr);
|
calculate_trapezoid_for_block(block, current_entry_speed * nomr, next_entry_speed * nomr);
|
||||||
#if ENABLED(LIN_ADVANCE)
|
|
||||||
if (block->use_advance_lead) {
|
|
||||||
const float comp = block->e_D_ratio * extruder_advance_K[active_extruder] * settings.axis_steps_per_mm[E_AXIS];
|
|
||||||
block->max_adv_steps = block->nominal_speed * comp;
|
|
||||||
block->final_adv_steps = next_entry_speed * comp;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset current only to ensure next trapezoid is computed - The
|
// Reset current only to ensure next trapezoid is computed - The
|
||||||
@ -1251,13 +1253,6 @@ void Planner::recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t
|
|||||||
|
|
||||||
const float nomr = 1.0f / block->nominal_speed;
|
const float nomr = 1.0f / block->nominal_speed;
|
||||||
calculate_trapezoid_for_block(block, current_entry_speed * nomr, next_entry_speed * nomr);
|
calculate_trapezoid_for_block(block, current_entry_speed * nomr, next_entry_speed * nomr);
|
||||||
#if ENABLED(LIN_ADVANCE)
|
|
||||||
if (block->use_advance_lead) {
|
|
||||||
const float comp = block->e_D_ratio * extruder_advance_K[active_extruder] * settings.axis_steps_per_mm[E_AXIS];
|
|
||||||
block->max_adv_steps = block->nominal_speed * comp;
|
|
||||||
block->final_adv_steps = next_entry_speed * comp;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset block to ensure its trapezoid is computed - The stepper is free to use
|
// Reset block to ensure its trapezoid is computed - The stepper is free to use
|
||||||
@ -2502,13 +2497,15 @@ bool Planner::_populate_block(
|
|||||||
// Compute and limit the acceleration rate for the trapezoid generator.
|
// Compute and limit the acceleration rate for the trapezoid generator.
|
||||||
const float steps_per_mm = block->step_event_count * inverse_millimeters;
|
const float steps_per_mm = block->step_event_count * inverse_millimeters;
|
||||||
uint32_t accel;
|
uint32_t accel;
|
||||||
|
#if ENABLED(LIN_ADVANCE)
|
||||||
|
bool use_advance_lead = false;
|
||||||
|
#endif
|
||||||
if (NUM_AXIS_GANG(
|
if (NUM_AXIS_GANG(
|
||||||
!block->steps.a, && !block->steps.b, && !block->steps.c,
|
!block->steps.a, && !block->steps.b, && !block->steps.c,
|
||||||
&& !block->steps.i, && !block->steps.j, && !block->steps.k,
|
&& !block->steps.i, && !block->steps.j, && !block->steps.k,
|
||||||
&& !block->steps.u, && !block->steps.v, && !block->steps.w)
|
&& !block->steps.u, && !block->steps.v, && !block->steps.w)
|
||||||
) { // Is this a retract / recover move?
|
) { // Is this a retract / recover move?
|
||||||
accel = CEIL(settings.retract_acceleration * steps_per_mm); // Convert to: acceleration steps/sec^2
|
accel = CEIL(settings.retract_acceleration * steps_per_mm); // Convert to: acceleration steps/sec^2
|
||||||
TERN_(LIN_ADVANCE, block->use_advance_lead = false); // No linear advance for simple retract/recover
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#define LIMIT_ACCEL_LONG(AXIS,INDX) do{ \
|
#define LIMIT_ACCEL_LONG(AXIS,INDX) do{ \
|
||||||
@ -2535,33 +2532,29 @@ bool Planner::_populate_block(
|
|||||||
/**
|
/**
|
||||||
* Use LIN_ADVANCE for blocks if all these are true:
|
* Use LIN_ADVANCE for blocks if all these are true:
|
||||||
*
|
*
|
||||||
* esteps : This is a print move, because we checked for A, B, C steps before.
|
* esteps : This is a print move, because we checked for A, B, C steps before.
|
||||||
*
|
*
|
||||||
* extruder_advance_K[active_extruder] : There is an advance factor set for this extruder.
|
* extruder_advance_K[extruder] : There is an advance factor set for this extruder.
|
||||||
*
|
*
|
||||||
* de > 0 : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves)
|
* de > 0 : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves)
|
||||||
*/
|
*/
|
||||||
block->use_advance_lead = esteps
|
use_advance_lead = esteps && extruder_advance_K[extruder] && de > 0;
|
||||||
&& extruder_advance_K[active_extruder]
|
|
||||||
&& de > 0;
|
|
||||||
|
|
||||||
if (block->use_advance_lead) {
|
if (use_advance_lead) {
|
||||||
block->e_D_ratio = (target_float.e - position_float.e) /
|
float e_D_ratio = (target_float.e - position_float.e) /
|
||||||
#if IS_KINEMATIC
|
TERN(IS_KINEMATIC, block->millimeters,
|
||||||
block->millimeters
|
|
||||||
#else
|
|
||||||
SQRT(sq(target_float.x - position_float.x)
|
SQRT(sq(target_float.x - position_float.x)
|
||||||
+ sq(target_float.y - position_float.y)
|
+ sq(target_float.y - position_float.y)
|
||||||
+ sq(target_float.z - position_float.z))
|
+ sq(target_float.z - position_float.z))
|
||||||
#endif
|
);
|
||||||
;
|
|
||||||
|
|
||||||
// Check for unusual high e_D ratio to detect if a retract move was combined with the last print move due to min. steps per segment. Never execute this with advance!
|
// Check for unusual high e_D ratio to detect if a retract move was combined with the last print move due to min. steps per segment. Never execute this with advance!
|
||||||
// This assumes no one will use a retract length of 0mm < retr_length < ~0.2mm and no one will print 100mm wide lines using 3mm filament or 35mm wide lines using 1.75mm filament.
|
// This assumes no one will use a retract length of 0mm < retr_length < ~0.2mm and no one will print 100mm wide lines using 3mm filament or 35mm wide lines using 1.75mm filament.
|
||||||
if (block->e_D_ratio > 3.0f)
|
if (e_D_ratio > 3.0f)
|
||||||
block->use_advance_lead = false;
|
use_advance_lead = false;
|
||||||
else {
|
else {
|
||||||
const uint32_t max_accel_steps_per_s2 = MAX_E_JERK(extruder) / (extruder_advance_K[active_extruder] * block->e_D_ratio) * steps_per_mm;
|
// Scale E acceleration so that it will be possible to jump to the advance speed.
|
||||||
|
const uint32_t max_accel_steps_per_s2 = MAX_E_JERK(extruder) / (extruder_advance_K[extruder] * e_D_ratio) * steps_per_mm;
|
||||||
if (TERN0(LA_DEBUG, accel > max_accel_steps_per_s2))
|
if (TERN0(LA_DEBUG, accel > max_accel_steps_per_s2))
|
||||||
SERIAL_ECHOLNPGM("Acceleration limited.");
|
SERIAL_ECHOLNPGM("Acceleration limited.");
|
||||||
NOMORE(accel, max_accel_steps_per_s2);
|
NOMORE(accel, max_accel_steps_per_s2);
|
||||||
@ -2593,13 +2586,21 @@ bool Planner::_populate_block(
|
|||||||
block->acceleration_rate = (uint32_t)(accel * (float(1UL << 24) / (STEPPER_TIMER_RATE)));
|
block->acceleration_rate = (uint32_t)(accel * (float(1UL << 24) / (STEPPER_TIMER_RATE)));
|
||||||
#endif
|
#endif
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
if (block->use_advance_lead) {
|
block->la_advance_rate = 0;
|
||||||
block->advance_speed = (STEPPER_TIMER_RATE) / (extruder_advance_K[active_extruder] * block->e_D_ratio * block->acceleration * settings.axis_steps_per_mm[E_AXIS_N(extruder)]);
|
block->la_scaling = 0;
|
||||||
|
|
||||||
|
if (use_advance_lead) {
|
||||||
|
// the Bresenham algorithm will convert this step rate into extruder steps
|
||||||
|
block->la_advance_rate = extruder_advance_K[extruder] * block->acceleration_steps_per_s2;
|
||||||
|
|
||||||
|
// reduce LA ISR frequency by calling it only often enough to ensure that there will
|
||||||
|
// never be more than four extruder steps per call
|
||||||
|
for (uint32_t dividend = block->steps.e << 1; dividend <= (block->step_event_count >> 2); dividend <<= 1)
|
||||||
|
block->la_scaling++;
|
||||||
|
|
||||||
#if ENABLED(LA_DEBUG)
|
#if ENABLED(LA_DEBUG)
|
||||||
if (extruder_advance_K[active_extruder] * block->e_D_ratio * block->acceleration * 2 < block->nominal_speed * block->e_D_ratio)
|
if (block->la_advance_rate >> block->la_scaling > 10000)
|
||||||
SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed.");
|
SERIAL_ECHOLNPGM("eISR running at > 10kHz: ", block->la_advance_rate);
|
||||||
if (block->advance_speed < 200)
|
|
||||||
SERIAL_ECHOLNPGM("eISR running at > 10kHz.");
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -239,11 +239,10 @@ typedef struct PlannerBlock {
|
|||||||
|
|
||||||
// Advance extrusion
|
// Advance extrusion
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
bool use_advance_lead;
|
uint32_t la_advance_rate; // The rate at which steps are added whilst accelerating
|
||||||
uint16_t advance_speed, // STEP timer value for extruder speed offset ISR
|
uint8_t la_scaling; // Scale ISR frequency down and step frequency up by 2 ^ la_scaling
|
||||||
max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!)
|
uint16_t max_adv_steps, // Max advance steps to get cruising speed pressure
|
||||||
final_adv_steps; // advance steps due to exit speed
|
final_adv_steps; // Advance steps for exit speed pressure
|
||||||
float e_D_ratio;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t nominal_rate, // The nominal step rate for this block in step_events/sec
|
uint32_t nominal_rate, // The nominal step rate for this block in step_events/sec
|
||||||
@ -1018,7 +1017,7 @@ class Planner {
|
|||||||
return target_velocity_sqr - 2 * accel * distance;
|
return target_velocity_sqr - 2 * accel * distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLED(S_CURVE_ACCELERATION)
|
#if EITHER(S_CURVE_ACCELERATION, LIN_ADVANCE)
|
||||||
/**
|
/**
|
||||||
* Calculate the speed reached given initial speed, acceleration and distance
|
* Calculate the speed reached given initial speed, acceleration and distance
|
||||||
*/
|
*/
|
||||||
|
@ -217,18 +217,12 @@ uint32_t Stepper::advance_divisor = 0,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
|
|
||||||
uint32_t Stepper::nextAdvanceISR = LA_ADV_NEVER,
|
uint32_t Stepper::nextAdvanceISR = LA_ADV_NEVER,
|
||||||
Stepper::LA_isr_rate = LA_ADV_NEVER;
|
Stepper::la_interval = LA_ADV_NEVER;
|
||||||
uint16_t Stepper::LA_current_adv_steps = 0,
|
int32_t Stepper::la_delta_error = 0,
|
||||||
Stepper::LA_final_adv_steps,
|
Stepper::la_dividend = 0,
|
||||||
Stepper::LA_max_adv_steps;
|
Stepper::la_advance_steps = 0;
|
||||||
|
#endif
|
||||||
int8_t Stepper::LA_steps = 0;
|
|
||||||
|
|
||||||
bool Stepper::LA_use_advance_lead;
|
|
||||||
|
|
||||||
#endif // LIN_ADVANCE
|
|
||||||
|
|
||||||
#if ENABLED(INTEGRATED_BABYSTEPPING)
|
#if ENABLED(INTEGRATED_BABYSTEPPING)
|
||||||
uint32_t Stepper::nextBabystepISR = BABYSTEP_NEVER;
|
uint32_t Stepper::nextBabystepISR = BABYSTEP_NEVER;
|
||||||
@ -588,29 +582,27 @@ void Stepper::set_directions() {
|
|||||||
TERN_(HAS_V_DIR, SET_STEP_DIR(V));
|
TERN_(HAS_V_DIR, SET_STEP_DIR(V));
|
||||||
TERN_(HAS_W_DIR, SET_STEP_DIR(W));
|
TERN_(HAS_W_DIR, SET_STEP_DIR(W));
|
||||||
|
|
||||||
#if DISABLED(LIN_ADVANCE)
|
#if ENABLED(MIXING_EXTRUDER)
|
||||||
#if ENABLED(MIXING_EXTRUDER)
|
// Because this is valid for the whole block we don't know
|
||||||
// Because this is valid for the whole block we don't know
|
// what E steppers will step. Likely all. Set all.
|
||||||
// what E steppers will step. Likely all. Set all.
|
if (motor_direction(E_AXIS)) {
|
||||||
if (motor_direction(E_AXIS)) {
|
MIXER_STEPPER_LOOP(j) REV_E_DIR(j);
|
||||||
MIXER_STEPPER_LOOP(j) REV_E_DIR(j);
|
count_direction.e = -1;
|
||||||
count_direction.e = -1;
|
}
|
||||||
}
|
else {
|
||||||
else {
|
MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
|
||||||
MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
|
count_direction.e = 1;
|
||||||
count_direction.e = 1;
|
}
|
||||||
}
|
#elif HAS_EXTRUDERS
|
||||||
#elif HAS_EXTRUDERS
|
if (motor_direction(E_AXIS)) {
|
||||||
if (motor_direction(E_AXIS)) {
|
REV_E_DIR(stepper_extruder);
|
||||||
REV_E_DIR(stepper_extruder);
|
count_direction.e = -1;
|
||||||
count_direction.e = -1;
|
}
|
||||||
}
|
else {
|
||||||
else {
|
NORM_E_DIR(stepper_extruder);
|
||||||
NORM_E_DIR(stepper_extruder);
|
count_direction.e = 1;
|
||||||
count_direction.e = 1;
|
}
|
||||||
}
|
#endif
|
||||||
#endif
|
|
||||||
#endif // !LIN_ADVANCE
|
|
||||||
|
|
||||||
DIR_WAIT_AFTER();
|
DIR_WAIT_AFTER();
|
||||||
}
|
}
|
||||||
@ -1467,14 +1459,19 @@ void Stepper::isr() {
|
|||||||
// Enable ISRs to reduce USART processing latency
|
// Enable ISRs to reduce USART processing latency
|
||||||
hal.isr_on();
|
hal.isr_on();
|
||||||
|
|
||||||
if (!nextMainISR) pulse_phase_isr(); // 0 = Do coordinated axes Stepper pulses
|
if (!nextMainISR) pulse_phase_isr(); // 0 = Do coordinated axes Stepper pulses
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
if (!nextAdvanceISR) nextAdvanceISR = advance_isr(); // 0 = Do Linear Advance E Stepper pulses
|
if (!nextAdvanceISR) { // 0 = Do Linear Advance E Stepper pulses
|
||||||
|
advance_isr();
|
||||||
|
nextAdvanceISR = la_interval;
|
||||||
|
}
|
||||||
|
else if (nextAdvanceISR == LA_ADV_NEVER) // Start LA steps if necessary
|
||||||
|
nextAdvanceISR = la_interval;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(INTEGRATED_BABYSTEPPING)
|
#if ENABLED(INTEGRATED_BABYSTEPPING)
|
||||||
const bool is_babystep = (nextBabystepISR == 0); // 0 = Do Babystepping (XY)Z pulses
|
const bool is_babystep = (nextBabystepISR == 0); // 0 = Do Babystepping (XY)Z pulses
|
||||||
if (is_babystep) nextBabystepISR = babystepping_isr();
|
if (is_babystep) nextBabystepISR = babystepping_isr();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1796,20 +1793,18 @@ void Stepper::pulse_phase_isr() {
|
|||||||
PULSE_PREP(W);
|
PULSE_PREP(W);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if EITHER(LIN_ADVANCE, MIXING_EXTRUDER)
|
#if EITHER(HAS_E0_STEP, MIXING_EXTRUDER)
|
||||||
delta_error.e += advance_dividend.e;
|
|
||||||
if (delta_error.e >= 0) {
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
|
||||||
delta_error.e -= advance_divisor;
|
|
||||||
// Don't step E here - But remember the number of steps to perform
|
|
||||||
motor_direction(E_AXIS) ? --LA_steps : ++LA_steps;
|
|
||||||
#else
|
|
||||||
count_position.e += count_direction.e;
|
|
||||||
step_needed.e = true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#elif HAS_E0_STEP
|
|
||||||
PULSE_PREP(E);
|
PULSE_PREP(E);
|
||||||
|
|
||||||
|
#if ENABLED(LIN_ADVANCE)
|
||||||
|
if (step_needed.e && current_block->la_advance_rate) {
|
||||||
|
// don't actually step here, but do subtract movements steps
|
||||||
|
// from the linear advance step count
|
||||||
|
step_needed.e = false;
|
||||||
|
count_position.e -= count_direction.e;
|
||||||
|
la_advance_steps--;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1849,12 +1844,10 @@ void Stepper::pulse_phase_isr() {
|
|||||||
PULSE_START(W);
|
PULSE_START(W);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DISABLED(LIN_ADVANCE)
|
#if ENABLED(MIXING_EXTRUDER)
|
||||||
#if ENABLED(MIXING_EXTRUDER)
|
if (step_needed.e) E_STEP_WRITE(mixer.get_next_stepper(), !INVERT_E_STEP_PIN);
|
||||||
if (step_needed.e) E_STEP_WRITE(mixer.get_next_stepper(), !INVERT_E_STEP_PIN);
|
#elif HAS_E0_STEP
|
||||||
#elif HAS_E0_STEP
|
PULSE_START(E);
|
||||||
PULSE_START(E);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TERN_(I2S_STEPPER_STREAM, i2s_push_sample());
|
TERN_(I2S_STEPPER_STREAM, i2s_push_sample());
|
||||||
@ -1894,15 +1887,10 @@ void Stepper::pulse_phase_isr() {
|
|||||||
PULSE_STOP(W);
|
PULSE_STOP(W);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DISABLED(LIN_ADVANCE)
|
#if ENABLED(MIXING_EXTRUDER)
|
||||||
#if ENABLED(MIXING_EXTRUDER)
|
if (step_needed.e) E_STEP_WRITE(mixer.get_stepper(), INVERT_E_STEP_PIN);
|
||||||
if (delta_error.e >= 0) {
|
#elif HAS_E0_STEP
|
||||||
delta_error.e -= advance_divisor;
|
PULSE_STOP(E);
|
||||||
E_STEP_WRITE(mixer.get_stepper(), INVERT_E_STEP_PIN);
|
|
||||||
}
|
|
||||||
#elif HAS_E0_STEP
|
|
||||||
PULSE_STOP(E);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ISR_MULTI_STEPS
|
#if ISR_MULTI_STEPS
|
||||||
@ -1912,6 +1900,69 @@ void Stepper::pulse_phase_isr() {
|
|||||||
} while (--events_to_do);
|
} while (--events_to_do);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate timer interval, with all limits applied.
|
||||||
|
uint32_t Stepper::calc_timer_interval(uint32_t step_rate) {
|
||||||
|
#ifdef CPU_32_BIT
|
||||||
|
// In case of high-performance processor, it is able to calculate in real-time
|
||||||
|
return uint32_t(STEPPER_TIMER_RATE) / step_rate;
|
||||||
|
#else
|
||||||
|
// AVR is able to keep up at 30khz Stepping ISR rate.
|
||||||
|
constexpr uint32_t min_step_rate = (F_CPU) / 500000U;
|
||||||
|
if (step_rate <= min_step_rate) {
|
||||||
|
step_rate = 0;
|
||||||
|
uintptr_t table_address = (uintptr_t)&speed_lookuptable_slow[0][0];
|
||||||
|
return uint16_t(pgm_read_word(table_address));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
step_rate -= min_step_rate; // Correct for minimal speed
|
||||||
|
if (step_rate >= 0x0800) { // higher step rate
|
||||||
|
const uint8_t rate_mod_256 = (step_rate & 0x00FF);
|
||||||
|
const uintptr_t table_address = uintptr_t(&speed_lookuptable_fast[uint8_t(step_rate >> 8)][0]),
|
||||||
|
gain = uint16_t(pgm_read_word(table_address + 2));
|
||||||
|
return uint16_t(pgm_read_word(table_address)) - MultiU16X8toH16(rate_mod_256, gain);
|
||||||
|
}
|
||||||
|
else { // lower step rates
|
||||||
|
uintptr_t table_address = uintptr_t(&speed_lookuptable_slow[0][0]);
|
||||||
|
table_address += (step_rate >> 1) & 0xFFFC;
|
||||||
|
return uint16_t(pgm_read_word(table_address))
|
||||||
|
- ((uint16_t(pgm_read_word(table_address + 2)) * uint8_t(step_rate & 0x0007)) >> 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the timer interval and the number of loops to perform per tick
|
||||||
|
uint32_t Stepper::calc_timer_interval(uint32_t step_rate, uint8_t &loops) {
|
||||||
|
uint8_t multistep = 1;
|
||||||
|
#if DISABLED(DISABLE_MULTI_STEPPING)
|
||||||
|
|
||||||
|
// The stepping frequency limits for each multistepping rate
|
||||||
|
static const uint32_t limit[] PROGMEM = {
|
||||||
|
( MAX_STEP_ISR_FREQUENCY_1X ),
|
||||||
|
( MAX_STEP_ISR_FREQUENCY_2X >> 1),
|
||||||
|
( MAX_STEP_ISR_FREQUENCY_4X >> 2),
|
||||||
|
( MAX_STEP_ISR_FREQUENCY_8X >> 3),
|
||||||
|
( MAX_STEP_ISR_FREQUENCY_16X >> 4),
|
||||||
|
( MAX_STEP_ISR_FREQUENCY_32X >> 5),
|
||||||
|
( MAX_STEP_ISR_FREQUENCY_64X >> 6),
|
||||||
|
(MAX_STEP_ISR_FREQUENCY_128X >> 7)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Select the proper multistepping
|
||||||
|
uint8_t idx = 0;
|
||||||
|
while (idx < 7 && step_rate > (uint32_t)pgm_read_dword(&limit[idx])) {
|
||||||
|
step_rate >>= 1;
|
||||||
|
multistep <<= 1;
|
||||||
|
++idx;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
NOMORE(step_rate, uint32_t(MAX_STEP_ISR_FREQUENCY_1X));
|
||||||
|
#endif
|
||||||
|
loops = multistep;
|
||||||
|
|
||||||
|
return calc_timer_interval(step_rate);
|
||||||
|
}
|
||||||
|
|
||||||
// This is the last half of the stepper interrupt: This one processes and
|
// This is the last half of the stepper interrupt: This one processes and
|
||||||
// properly schedules blocks from the planner. This is executed after creating
|
// properly schedules blocks from the planner. This is executed after creating
|
||||||
// the step pulses, so it is not time critical, as pulses are already done.
|
// the step pulses, so it is not time critical, as pulses are already done.
|
||||||
@ -1964,15 +2015,14 @@ uint32_t Stepper::block_phase_isr() {
|
|||||||
// acc_step_rate is in steps/second
|
// acc_step_rate is in steps/second
|
||||||
|
|
||||||
// step_rate to timer interval and steps per stepper isr
|
// step_rate to timer interval and steps per stepper isr
|
||||||
interval = calc_timer_interval(acc_step_rate, &steps_per_isr);
|
interval = calc_timer_interval(acc_step_rate << oversampling_factor, steps_per_isr);
|
||||||
acceleration_time += interval;
|
acceleration_time += interval;
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
if (LA_use_advance_lead) {
|
if (current_block->la_advance_rate) {
|
||||||
// Fire ISR if final adv_rate is reached
|
const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0;
|
||||||
if (LA_steps && LA_isr_rate != current_block->advance_speed) nextAdvanceISR = 0;
|
la_interval = calc_timer_interval(acc_step_rate + la_step_rate) << current_block->la_scaling;
|
||||||
}
|
}
|
||||||
else if (LA_steps) nextAdvanceISR = 0;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2035,18 +2085,41 @@ uint32_t Stepper::block_phase_isr() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// step_rate to timer interval and steps per stepper isr
|
// step_rate to timer interval and steps per stepper isr
|
||||||
interval = calc_timer_interval(step_rate, &steps_per_isr);
|
interval = calc_timer_interval(step_rate << oversampling_factor, steps_per_isr);
|
||||||
deceleration_time += interval;
|
deceleration_time += interval;
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
if (LA_use_advance_lead) {
|
if (current_block->la_advance_rate) {
|
||||||
// Wake up eISR on first deceleration loop and fire ISR if final adv_rate is reached
|
const uint32_t la_step_rate = la_advance_steps > current_block->final_adv_steps ? current_block->la_advance_rate : 0;
|
||||||
if (step_events_completed <= decelerate_after + steps_per_isr || (LA_steps && LA_isr_rate != current_block->advance_speed)) {
|
if (la_step_rate != step_rate) {
|
||||||
initiateLA();
|
bool reverse_e = la_step_rate > step_rate;
|
||||||
LA_isr_rate = current_block->advance_speed;
|
la_interval = calc_timer_interval(reverse_e ? la_step_rate - step_rate : step_rate - la_step_rate) << current_block->la_scaling;
|
||||||
|
|
||||||
|
if (reverse_e != motor_direction(E_AXIS)) {
|
||||||
|
TBI(last_direction_bits, E_AXIS);
|
||||||
|
count_direction.e = -count_direction.e;
|
||||||
|
|
||||||
|
DIR_WAIT_BEFORE();
|
||||||
|
|
||||||
|
if (reverse_e) {
|
||||||
|
#if ENABLED(MIXING_EXTRUDER)
|
||||||
|
MIXER_STEPPER_LOOP(j) REV_E_DIR(j);
|
||||||
|
#else
|
||||||
|
REV_E_DIR(stepper_extruder);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#if ENABLED(MIXING_EXTRUDER)
|
||||||
|
MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
|
||||||
|
#else
|
||||||
|
NORM_E_DIR(stepper_extruder);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR_WAIT_AFTER();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (LA_steps) nextAdvanceISR = 0;
|
|
||||||
#endif // LIN_ADVANCE
|
#endif // LIN_ADVANCE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2069,15 +2142,15 @@ uint32_t Stepper::block_phase_isr() {
|
|||||||
}
|
}
|
||||||
else { // Must be in cruise phase otherwise
|
else { // Must be in cruise phase otherwise
|
||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
|
||||||
// If there are any esteps, fire the next advance_isr "now"
|
|
||||||
if (LA_steps && LA_isr_rate != current_block->advance_speed) initiateLA();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Calculate the ticks_nominal for this nominal speed, if not done yet
|
// Calculate the ticks_nominal for this nominal speed, if not done yet
|
||||||
if (ticks_nominal < 0) {
|
if (ticks_nominal < 0) {
|
||||||
// step_rate to timer interval and loops for the nominal speed
|
// step_rate to timer interval and loops for the nominal speed
|
||||||
ticks_nominal = calc_timer_interval(current_block->nominal_rate, &steps_per_isr);
|
ticks_nominal = calc_timer_interval(current_block->nominal_rate << oversampling_factor, steps_per_isr);
|
||||||
|
|
||||||
|
#if ENABLED(LIN_ADVANCE)
|
||||||
|
if (current_block->la_advance_rate)
|
||||||
|
la_interval = calc_timer_interval(current_block->nominal_rate) << current_block->la_scaling;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// The timer interval is just the nominal value for the nominal speed
|
// The timer interval is just the nominal value for the nominal speed
|
||||||
@ -2291,7 +2364,7 @@ uint32_t Stepper::block_phase_isr() {
|
|||||||
step_event_count = current_block->step_event_count << oversampling;
|
step_event_count = current_block->step_event_count << oversampling;
|
||||||
|
|
||||||
// Initialize Bresenham delta errors to 1/2
|
// Initialize Bresenham delta errors to 1/2
|
||||||
delta_error = -int32_t(step_event_count);
|
delta_error = TERN_(LIN_ADVANCE, la_delta_error =) -int32_t(step_event_count);
|
||||||
|
|
||||||
// Calculate Bresenham dividends and divisors
|
// Calculate Bresenham dividends and divisors
|
||||||
advance_dividend = current_block->steps << 1;
|
advance_dividend = current_block->steps << 1;
|
||||||
@ -2312,16 +2385,12 @@ uint32_t Stepper::block_phase_isr() {
|
|||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
#if DISABLED(MIXING_EXTRUDER) && E_STEPPERS > 1
|
#if DISABLED(MIXING_EXTRUDER) && E_STEPPERS > 1
|
||||||
// If the now active extruder wasn't in use during the last move, its pressure is most likely gone.
|
// If the now active extruder wasn't in use during the last move, its pressure is most likely gone.
|
||||||
if (stepper_extruder != last_moved_extruder) LA_current_adv_steps = 0;
|
if (stepper_extruder != last_moved_extruder) la_advance_steps = 0;
|
||||||
#endif
|
#endif
|
||||||
|
if (current_block->la_advance_rate) {
|
||||||
if ((LA_use_advance_lead = current_block->use_advance_lead)) {
|
// apply LA scaling and discount the effect of frequency scaling
|
||||||
LA_final_adv_steps = current_block->final_adv_steps;
|
la_dividend = (advance_dividend.e << current_block->la_scaling) << oversampling;
|
||||||
LA_max_adv_steps = current_block->max_adv_steps;
|
|
||||||
initiateLA(); // Start the ISR
|
|
||||||
LA_isr_rate = current_block->advance_speed;
|
|
||||||
}
|
}
|
||||||
else LA_isr_rate = LA_ADV_NEVER;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( ENABLED(DUAL_X_CARRIAGE) // TODO: Find out why this fixes "jittery" small circles
|
if ( ENABLED(DUAL_X_CARRIAGE) // TODO: Find out why this fixes "jittery" small circles
|
||||||
@ -2375,7 +2444,15 @@ uint32_t Stepper::block_phase_isr() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Calculate the initial timer interval
|
// Calculate the initial timer interval
|
||||||
interval = calc_timer_interval(current_block->initial_rate, &steps_per_isr);
|
interval = calc_timer_interval(current_block->initial_rate << oversampling_factor, steps_per_isr);
|
||||||
|
acceleration_time += interval;
|
||||||
|
|
||||||
|
#if ENABLED(LIN_ADVANCE)
|
||||||
|
if (current_block->la_advance_rate) {
|
||||||
|
const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0;
|
||||||
|
la_interval = calc_timer_interval(current_block->initial_rate + la_step_rate) << current_block->la_scaling;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2386,71 +2463,15 @@ uint32_t Stepper::block_phase_isr() {
|
|||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
|
|
||||||
// Timer interrupt for E. LA_steps is set in the main routine
|
// Timer interrupt for E. LA_steps is set in the main routine
|
||||||
uint32_t Stepper::advance_isr() {
|
void Stepper::advance_isr() {
|
||||||
uint32_t interval;
|
// Apply Bresenham algorithm so that linear advance can piggy back on
|
||||||
|
// the acceleration and speed values calculated in block_phase_isr().
|
||||||
if (LA_use_advance_lead) {
|
// This helps keep LA in sync with, for example, S_CURVE_ACCELERATION.
|
||||||
if (step_events_completed > decelerate_after && LA_current_adv_steps > LA_final_adv_steps) {
|
la_delta_error += la_dividend;
|
||||||
LA_steps--;
|
if (la_delta_error >= 0) {
|
||||||
LA_current_adv_steps--;
|
|
||||||
interval = LA_isr_rate;
|
|
||||||
}
|
|
||||||
else if (step_events_completed < decelerate_after && LA_current_adv_steps < LA_max_adv_steps) {
|
|
||||||
LA_steps++;
|
|
||||||
LA_current_adv_steps++;
|
|
||||||
interval = LA_isr_rate;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
interval = LA_isr_rate = LA_ADV_NEVER;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
interval = LA_ADV_NEVER;
|
|
||||||
|
|
||||||
if (!LA_steps) return interval; // Leave pins alone if there are no steps!
|
|
||||||
|
|
||||||
DIR_WAIT_BEFORE();
|
|
||||||
|
|
||||||
#if ENABLED(MIXING_EXTRUDER)
|
|
||||||
// We don't know which steppers will be stepped because LA loop follows,
|
|
||||||
// with potentially multiple steps. Set all.
|
|
||||||
if (LA_steps > 0) {
|
|
||||||
MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
|
|
||||||
count_direction.e = 1;
|
|
||||||
}
|
|
||||||
else if (LA_steps < 0) {
|
|
||||||
MIXER_STEPPER_LOOP(j) REV_E_DIR(j);
|
|
||||||
count_direction.e = -1;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (LA_steps > 0) {
|
|
||||||
NORM_E_DIR(stepper_extruder);
|
|
||||||
count_direction.e = 1;
|
|
||||||
}
|
|
||||||
else if (LA_steps < 0) {
|
|
||||||
REV_E_DIR(stepper_extruder);
|
|
||||||
count_direction.e = -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DIR_WAIT_AFTER();
|
|
||||||
|
|
||||||
//const hal_timer_t added_step_ticks = hal_timer_t(ADDED_STEP_TICKS);
|
|
||||||
|
|
||||||
// Step E stepper if we have steps
|
|
||||||
#if ISR_MULTI_STEPS
|
|
||||||
bool firstStep = true;
|
|
||||||
USING_TIMED_PULSE();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (LA_steps) {
|
|
||||||
#if ISR_MULTI_STEPS
|
|
||||||
if (firstStep)
|
|
||||||
firstStep = false;
|
|
||||||
else
|
|
||||||
AWAIT_LOW_PULSE();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
count_position.e += count_direction.e;
|
count_position.e += count_direction.e;
|
||||||
|
la_advance_steps += count_direction.e;
|
||||||
|
la_delta_error -= advance_divisor;
|
||||||
|
|
||||||
// Set the STEP pulse ON
|
// Set the STEP pulse ON
|
||||||
#if ENABLED(MIXING_EXTRUDER)
|
#if ENABLED(MIXING_EXTRUDER)
|
||||||
@ -2461,12 +2482,8 @@ uint32_t Stepper::block_phase_isr() {
|
|||||||
|
|
||||||
// Enforce a minimum duration for STEP pulse ON
|
// Enforce a minimum duration for STEP pulse ON
|
||||||
#if ISR_PULSE_CONTROL
|
#if ISR_PULSE_CONTROL
|
||||||
|
USING_TIMED_PULSE();
|
||||||
START_HIGH_PULSE();
|
START_HIGH_PULSE();
|
||||||
#endif
|
|
||||||
|
|
||||||
LA_steps < 0 ? ++LA_steps : --LA_steps;
|
|
||||||
|
|
||||||
#if ISR_PULSE_CONTROL
|
|
||||||
AWAIT_HIGH_PULSE();
|
AWAIT_HIGH_PULSE();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -2476,15 +2493,7 @@ uint32_t Stepper::block_phase_isr() {
|
|||||||
#else
|
#else
|
||||||
E_STEP_WRITE(stepper_extruder, INVERT_E_STEP_PIN);
|
E_STEP_WRITE(stepper_extruder, INVERT_E_STEP_PIN);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
// For minimum pulse time wait before looping
|
|
||||||
// Just wait for the requested pulse duration
|
|
||||||
#if ISR_PULSE_CONTROL
|
|
||||||
if (LA_steps) START_LOW_PULSE();
|
|
||||||
#endif
|
|
||||||
} // LA_steps
|
|
||||||
|
|
||||||
return interval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // LIN_ADVANCE
|
#endif // LIN_ADVANCE
|
||||||
|
@ -417,10 +417,11 @@ class Stepper {
|
|||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
static constexpr uint32_t LA_ADV_NEVER = 0xFFFFFFFF;
|
static constexpr uint32_t LA_ADV_NEVER = 0xFFFFFFFF;
|
||||||
static uint32_t nextAdvanceISR, LA_isr_rate;
|
static uint32_t nextAdvanceISR,
|
||||||
static uint16_t LA_current_adv_steps, LA_final_adv_steps, LA_max_adv_steps; // Copy from current executed block. Needed because current_block is set to NULL "too early".
|
la_interval; // Interval between ISR calls for LA
|
||||||
static int8_t LA_steps;
|
static int32_t la_delta_error, // Analogue of delta_error.e for E steps in LA ISR
|
||||||
static bool LA_use_advance_lead;
|
la_dividend, // Analogue of advance_dividend.e for E steps in LA ISR
|
||||||
|
la_advance_steps; // Count of steps added to increase nozzle pressure
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(INTEGRATED_BABYSTEPPING)
|
#if ENABLED(INTEGRATED_BABYSTEPPING)
|
||||||
@ -475,8 +476,7 @@ class Stepper {
|
|||||||
|
|
||||||
#if ENABLED(LIN_ADVANCE)
|
#if ENABLED(LIN_ADVANCE)
|
||||||
// The Linear advance ISR phase
|
// The Linear advance ISR phase
|
||||||
static uint32_t advance_isr();
|
static void advance_isr();
|
||||||
FORCE_INLINE static void initiateLA() { nextAdvanceISR = 0; }
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(INTEGRATED_BABYSTEPPING)
|
#if ENABLED(INTEGRATED_BABYSTEPPING)
|
||||||
@ -512,6 +512,7 @@ class Stepper {
|
|||||||
current_block = nullptr;
|
current_block = nullptr;
|
||||||
axis_did_move = 0;
|
axis_did_move = 0;
|
||||||
planner.release_current_block();
|
planner.release_current_block();
|
||||||
|
TERN_(LIN_ADVANCE, la_interval = nextAdvanceISR = LA_ADV_NEVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quickly stop all steppers
|
// Quickly stop all steppers
|
||||||
@ -631,65 +632,9 @@ class Stepper {
|
|||||||
// Set the current position in steps
|
// Set the current position in steps
|
||||||
static void _set_position(const abce_long_t &spos);
|
static void _set_position(const abce_long_t &spos);
|
||||||
|
|
||||||
FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate, uint8_t *loops) {
|
// Calculate timing interval for the given step rate
|
||||||
uint32_t timer;
|
static uint32_t calc_timer_interval(uint32_t step_rate);
|
||||||
|
static uint32_t calc_timer_interval(uint32_t step_rate, uint8_t &loops);
|
||||||
// Scale the frequency, as requested by the caller
|
|
||||||
step_rate <<= oversampling_factor;
|
|
||||||
|
|
||||||
uint8_t multistep = 1;
|
|
||||||
#if DISABLED(DISABLE_MULTI_STEPPING)
|
|
||||||
|
|
||||||
// The stepping frequency limits for each multistepping rate
|
|
||||||
static const uint32_t limit[] PROGMEM = {
|
|
||||||
( MAX_STEP_ISR_FREQUENCY_1X ),
|
|
||||||
( MAX_STEP_ISR_FREQUENCY_2X >> 1),
|
|
||||||
( MAX_STEP_ISR_FREQUENCY_4X >> 2),
|
|
||||||
( MAX_STEP_ISR_FREQUENCY_8X >> 3),
|
|
||||||
( MAX_STEP_ISR_FREQUENCY_16X >> 4),
|
|
||||||
( MAX_STEP_ISR_FREQUENCY_32X >> 5),
|
|
||||||
( MAX_STEP_ISR_FREQUENCY_64X >> 6),
|
|
||||||
(MAX_STEP_ISR_FREQUENCY_128X >> 7)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Select the proper multistepping
|
|
||||||
uint8_t idx = 0;
|
|
||||||
while (idx < 7 && step_rate > (uint32_t)pgm_read_dword(&limit[idx])) {
|
|
||||||
step_rate >>= 1;
|
|
||||||
multistep <<= 1;
|
|
||||||
++idx;
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
NOMORE(step_rate, uint32_t(MAX_STEP_ISR_FREQUENCY_1X));
|
|
||||||
#endif
|
|
||||||
*loops = multistep;
|
|
||||||
|
|
||||||
#ifdef CPU_32_BIT
|
|
||||||
// In case of high-performance processor, it is able to calculate in real-time
|
|
||||||
timer = uint32_t(STEPPER_TIMER_RATE) / step_rate;
|
|
||||||
#else
|
|
||||||
constexpr uint32_t min_step_rate = (F_CPU) / 500000U;
|
|
||||||
NOLESS(step_rate, min_step_rate);
|
|
||||||
step_rate -= min_step_rate; // Correct for minimal speed
|
|
||||||
if (step_rate >= (8 * 256)) { // higher step rate
|
|
||||||
const uint8_t tmp_step_rate = (step_rate & 0x00FF);
|
|
||||||
const uint16_t table_address = (uint16_t)&speed_lookuptable_fast[(uint8_t)(step_rate >> 8)][0],
|
|
||||||
gain = (uint16_t)pgm_read_word(table_address + 2);
|
|
||||||
timer = MultiU16X8toH16(tmp_step_rate, gain);
|
|
||||||
timer = (uint16_t)pgm_read_word(table_address) - timer;
|
|
||||||
}
|
|
||||||
else { // lower step rates
|
|
||||||
uint16_t table_address = (uint16_t)&speed_lookuptable_slow[0][0];
|
|
||||||
table_address += ((step_rate) >> 1) & 0xFFFC;
|
|
||||||
timer = (uint16_t)pgm_read_word(table_address)
|
|
||||||
- (((uint16_t)pgm_read_word(table_address + 2) * (uint8_t)(step_rate & 0x0007)) >> 3);
|
|
||||||
}
|
|
||||||
// (there is no need to limit the timer value here. All limits have been
|
|
||||||
// applied above, and AVR is able to keep up at 30khz Stepping ISR rate)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return timer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ENABLED(S_CURVE_ACCELERATION)
|
#if ENABLED(S_CURVE_ACCELERATION)
|
||||||
static void _calc_bezier_curve_coeffs(const int32_t v0, const int32_t v1, const uint32_t av);
|
static void _calc_bezier_curve_coeffs(const int32_t v0, const int32_t v1, const uint32_t av);
|
||||||
|
Loading…
Reference in New Issue
Block a user