mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2026-01-24 14:16:44 -07:00
parent
f6dbb59748
commit
e176df1e6d
5 changed files with 34 additions and 23 deletions
|
|
@ -484,7 +484,7 @@ xyze_float_t FTMotion::calc_traj_point(const float dist) {
|
|||
|
||||
stepper_plan_t FTMotion::calc_stepper_plan(xyze_float_t traj_coords) {
|
||||
// 1) Convert trajectory to step delta
|
||||
#define _TOSTEPS_q32(A, B) int64_t(traj_coords.A * planner.settings.axis_steps_per_mm[B] * (1ull << 32))
|
||||
#define _TOSTEPS_q32(A, B) int64_t(traj_coords.A * planner.settings.axis_steps_per_mm[B] * (1ULL << 32))
|
||||
XYZEval<int64_t> next_steps_q32_32 = LOGICAL_AXIS_ARRAY(
|
||||
_TOSTEPS_q32(e, block_extruder_axis),
|
||||
_TOSTEPS_q32(x, X_AXIS), _TOSTEPS_q32(y, Y_AXIS), _TOSTEPS_q32(z, Z_AXIS),
|
||||
|
|
@ -493,7 +493,7 @@ stepper_plan_t FTMotion::calc_stepper_plan(xyze_float_t traj_coords) {
|
|||
);
|
||||
#undef _TOSTEPS_q32
|
||||
|
||||
constexpr uint32_t ITERATIONS_PER_TRAJ_INV_uq0_32 = (1ull << 32) / ITERATIONS_PER_TRAJ;
|
||||
constexpr uint32_t ITERATIONS_PER_TRAJ_INV_uq0_32 = (1ULL << 32) / ITERATIONS_PER_TRAJ;
|
||||
stepper_plan_t stepper_plan;
|
||||
|
||||
#define _RUN_AXIS(A) do{ \
|
||||
|
|
@ -525,10 +525,21 @@ stepper_plan_t FTMotion::calc_stepper_plan(xyze_float_t traj_coords) {
|
|||
*/
|
||||
void FTMotion::fill_stepper_plan_buffer() {
|
||||
while (!stepper_plan_is_full()) {
|
||||
float total_duration = currentGenerator->getTotalDuration(); // if the current plan is empty, it will have zero duration.
|
||||
float total_duration = currentGenerator->getTotalDuration(); // If the current plan is empty, it will have zero duration.
|
||||
while (tau + FTM_TS > total_duration) {
|
||||
// Previous block plan consumed, try to get the next one.
|
||||
tau -= total_duration; // The exact end of the last block may be in-between trajectory points, so the next one may start anywhere of (-FTM_TS, 0].
|
||||
/**
|
||||
* We’ve reached the end of the current block.
|
||||
*
|
||||
* `tau` is the time that has elapsed inside this block. After a block is finished, the next one may
|
||||
* start at any point between *just before* the last sampled time (one step earlier, i.e. `-FTM_TS`)
|
||||
* and *exactly at* the last sampled time (0). IOW the real start of the next block could be anywhere
|
||||
* in the interval (-FTM_TS, 0].
|
||||
*
|
||||
* To account for that uncertainty we simply subtract the duration of the finished block from `tau`.
|
||||
* This brings us back to a time value that is valid for the next block, while still allowing the next
|
||||
* block’s start to be offset by up to one time step into the past.
|
||||
*/
|
||||
tau -= total_duration;
|
||||
const bool plan_available = plan_next_block();
|
||||
if (!plan_available) return;
|
||||
total_duration = currentGenerator->getTotalDuration();
|
||||
|
|
|
|||
|
|
@ -29,20 +29,20 @@
|
|||
|
||||
void Stepping::reset() {
|
||||
stepper_plan.reset();
|
||||
delta_error_q32.set(LOGICAL_AXIS_ARRAY_1(_BV32(31))); // start as 0.5 in q32 so steps are rounded
|
||||
delta_error_q32.set(LOGICAL_AXIS_LIST_1(1 << 31)); // Start as 0.5 in q32 so steps are rounded
|
||||
step_bits = 0;
|
||||
bresenham_iterations_pending = 0;
|
||||
}
|
||||
|
||||
uint32_t Stepping::advance_until_step() {
|
||||
xyze_ulong_t space_q32 = -delta_error_q32 + UINT32_MAX; // How much accumulation until a step in any axis is ALMOST due
|
||||
// scalar in the right hand because types.h is missing scalar on left cases
|
||||
// TODO: Add operators to types.h for scalar destination.
|
||||
|
||||
xyze_ulong_t advance_q32 = stepper_plan.advance_dividend_q0_32;
|
||||
uint32_t iterations = bresenham_iterations_pending;
|
||||
// Per-axis lower-bound approx of floor(space_q32/adv), min across axes (lower bound because this fast division underestimates result by up to 1)
|
||||
// #define RUN_AXIS(A) if(advance_q32.A > 0) NOMORE(iterations, space_q32.A/advance_q32.A);
|
||||
#define RUN_AXIS(A) if(advance_q32.A > 0) NOMORE(iterations, uint32_t((uint64_t(space_q32.A) * advance_dividend_reciprocal.A) >> 32));
|
||||
//#define RUN_AXIS(A) if (advance_q32.A > 0) NOMORE(iterations, space_q32.A / advance_q32.A);
|
||||
#define RUN_AXIS(A) if (advance_q32.A > 0) NOMORE(iterations, uint32_t((uint64_t(space_q32.A) * advance_dividend_reciprocal.A) >> 32));
|
||||
LOGICAL_AXIS_MAP(RUN_AXIS);
|
||||
#undef RUN_AXIS
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ uint32_t Stepping::plan() {
|
|||
if (bresenham_iterations_pending > 0) {
|
||||
intervals = advance_until_step();
|
||||
if (bool(step_bits)) return intervals; // steps to make => return the wait time so it gets done in due time
|
||||
// Else all bresenham iterations were advanced without steps => this is just the frame end, so plan the next one directly and accumulate the wait
|
||||
// Else all Bresenham iterations were advanced without steps => this is just the frame end, so plan the next one directly and accumulate the wait
|
||||
}
|
||||
|
||||
if (ftMotion.stepper_plan_is_empty()) {
|
||||
|
|
@ -97,7 +97,7 @@ uint32_t Stepping::plan() {
|
|||
return INTERVAL_PER_TRAJ_POINT;
|
||||
}
|
||||
|
||||
// This vector division is unavoidable, but it saves a division per step during bresenham
|
||||
// This vector division is unavoidable, but it saves a division per step during Bresenham
|
||||
// The reciprocal is actually 2^32/dividend, but that requires dividing a uint64_t, which quite expensive
|
||||
// Since even the real reciprocal may underestimate the quotient by 1 anyway already, this optimisation doesn't
|
||||
// make things worse. This underestimation is compensated for in advance_until_step.
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ uint32_t Stepper::advance_divisor = 0,
|
|||
|
||||
hal_timer_t Stepper::ticks_nominal = 0;
|
||||
#if DISABLED(S_CURVE_ACCELERATION)
|
||||
uint32_t Stepper::acc_step_rate; // needed for deceleration start point
|
||||
uint32_t Stepper::acc_step_rate; // Needed for deceleration start point
|
||||
#endif
|
||||
|
||||
xyz_long_t Stepper::endstops_trigsteps;
|
||||
|
|
@ -1989,7 +1989,7 @@ void Stepper::pulse_phase_isr() {
|
|||
|
||||
#if HAS_ROUGH_LIN_ADVANCE
|
||||
if (la_active && step_needed.e) {
|
||||
// don't actually step here, but do subtract movements steps
|
||||
// Don't actually step here, but do subtract movements steps
|
||||
// from the linear advance step count
|
||||
step_needed.e = false;
|
||||
la_advance_steps--;
|
||||
|
|
@ -2000,14 +2000,14 @@ void Stepper::pulse_phase_isr() {
|
|||
#endif
|
||||
|
||||
#if HAS_ZV_SHAPING
|
||||
// record an echo if a step is needed in the primary bresenham
|
||||
// Record an echo if a step is needed in the primary Bresenham
|
||||
const bool x_step = TERN0(INPUT_SHAPING_X, step_needed.x && shaping_x.enabled),
|
||||
y_step = TERN0(INPUT_SHAPING_Y, step_needed.y && shaping_y.enabled),
|
||||
z_step = TERN0(INPUT_SHAPING_Z, step_needed.z && shaping_z.enabled);
|
||||
if (x_step || y_step || z_step)
|
||||
ShapingQueue::enqueue(x_step, TERN0(INPUT_SHAPING_X, shaping_x.forward), y_step, TERN0(INPUT_SHAPING_Y, shaping_y.forward), z_step, TERN0(INPUT_SHAPING_Z, shaping_z.forward));
|
||||
|
||||
// do the first part of the secondary bresenham
|
||||
// Do the first part of the secondary Bresenham
|
||||
#if ENABLED(INPUT_SHAPING_X)
|
||||
if (x_step)
|
||||
PULSE_PREP_SHAPING(X, shaping_x.delta_error, shaping_x.forward ? shaping_x.factor1 : -shaping_x.factor1);
|
||||
|
|
@ -2195,7 +2195,7 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) {
|
|||
|
||||
#else
|
||||
|
||||
if (step_rate >= 0x0800) { // higher step rate
|
||||
if (step_rate >= 0x0800) { // Higher step rate
|
||||
// AVR is able to keep up at around 65kHz Stepping ISR rate at most.
|
||||
// So values for step_rate > 65535 might as well be truncated.
|
||||
// Handle it as quickly as possible. i.e., assume highest byte is zero
|
||||
|
|
@ -2208,7 +2208,7 @@ hal_timer_t Stepper::calc_timer_interval(uint32_t step_rate) {
|
|||
const uint8_t gain = uint8_t(pgm_read_byte(table_address + 2));
|
||||
return base - MultiU8X8toH8(uint8_t(step_rate & 0x00FF), gain);
|
||||
}
|
||||
else if (step_rate > minimal_step_rate) { // lower step rates
|
||||
else if (step_rate > minimal_step_rate) { // Lower step rates
|
||||
step_rate -= minimal_step_rate; // Correct for minimal speed
|
||||
const uintptr_t table_address = uintptr_t(&speed_lookuptable_slow[uint8_t(step_rate >> 3)]);
|
||||
return uint16_t(pgm_read_word(table_address))
|
||||
|
|
@ -2388,7 +2388,7 @@ hal_timer_t Stepper::block_phase_isr() {
|
|||
ticks_nominal = 0;
|
||||
}
|
||||
#endif
|
||||
time_spent_in_isr = -time_spent; // unsigned but guaranteed to be +ve when needed
|
||||
time_spent_in_isr = -time_spent; // Unsigned but guaranteed to be +ve when needed
|
||||
time_spent_out_isr = 0;
|
||||
#endif
|
||||
|
||||
|
|
@ -3295,7 +3295,7 @@ void Stepper::init() {
|
|||
}
|
||||
|
||||
void Stepper::set_shaping_frequency(const AxisEnum axis, const float freq) {
|
||||
// enabling or disabling shaping whilst moving can result in lost steps
|
||||
// Enabling or disabling shaping whilst moving can result in lost steps
|
||||
planner.synchronize();
|
||||
|
||||
const bool was_on = hal.isr_state();
|
||||
|
|
@ -3373,7 +3373,7 @@ void Stepper::_set_position(const abce_long_t &spos) {
|
|||
);
|
||||
TERN_(HAS_EXTRUDERS, count_position.e = spos.e);
|
||||
#else
|
||||
// default non-h-bot planning
|
||||
// Default non-h-bot planning
|
||||
count_position = spos;
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ constexpr ena_mask_t enable_overlap[] = {
|
|||
float zeta;
|
||||
bool enabled : 1;
|
||||
bool forward : 1;
|
||||
int16_t delta_error = 0; // delta_error for seconday bresenham mod 128
|
||||
int16_t delta_error = 0; // delta_error for secondary Bresenham mod 128
|
||||
uint8_t factor1;
|
||||
uint8_t factor2;
|
||||
int32_t last_block_end_pos = 0;
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ constexpr uint32_t min_isr_loop_cycles = isr_mixing_stepper_cycles + LOGICAL_AXE
|
|||
// Calculate the minimum MPU cycles needed per pulse to enforce
|
||||
constexpr uint32_t min_stepper_pulse_cycles = _min_pulse_high_ns * CYCLES_PER_MICROSECOND / 1000;
|
||||
|
||||
// The loop takes the base time plus the time for all the bresenham logic for 1 << R pulses plus the time
|
||||
// The loop takes the base time plus the time for all the Bresenham logic for 1 << R pulses plus the time
|
||||
// between pulses for ((1 << R) - 1) pulses. But the user could be enforcing a minimum time so the loop time is:
|
||||
constexpr uint32_t isr_loop_cycles(const int R) { return ((isr_loop_base_cycles + min_isr_loop_cycles + min_stepper_pulse_cycles) * ((1UL << R) - 1) + _MAX(min_isr_loop_cycles, min_stepper_pulse_cycles)); }
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ constexpr uint32_t isr_shaping_loop_cycles(const int R) {
|
|||
// HELP ME: What is what?
|
||||
// Directions are set up for MIXING_STEPPERS - like before.
|
||||
// Finding the right stepper may last up to MIXING_STEPPERS loops in get_next_stepper().
|
||||
// These loops are a bit faster than advancing a bresenham counter.
|
||||
// These loops are a bit faster than advancing a Bresenham counter.
|
||||
// Always only one E stepper is stepped.
|
||||
* TERN1(MIXING_EXTRUDER, (MIXING_STEPPERS))
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue