diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 95b2501c..e4e1e0b2 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -7116,7 +7116,6 @@ Sigma_Exit: { float e = code_value(); #ifndef LA_NOCOMPAT - e = la10c_jerk(e); #endif cs.max_jerk[E_AXIS] = e; diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 57d7b89b..0d77900e 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -1061,16 +1061,16 @@ Having the real displacement of the head, we can calculate the total movement le /** * Use LIN_ADVANCE within this block if all these are true: * - * block->steps_e : This is a print move, because we checked for X, Y, Z steps before. * extruder_advance_K : There is an advance factor set. - * delta_mm[E_AXIS] > 0 : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves) + * delta_mm[E_AXIS] >= 0 : Extruding or traveling, but _not_ retracting. * |delta_mm[Z_AXIS]| < 0.5 : Z is only moved for leveling (_not_ for priming) */ - block->use_advance_lead = block->steps_e.wide - && extruder_advance_K - && delta_mm[E_AXIS] > 0 + block->use_advance_lead = extruder_advance_K > 0 + && delta_mm[E_AXIS] >= 0 && abs(delta_mm[Z_AXIS]) < 0.5; if (block->use_advance_lead) { + // all extrusion moves with LA require a compression which is proportional to the + // extrusion_length to distance ratio (e/D) e_D_ratio = (e - position_float[E_AXIS]) / sqrt(sq(x - position_float[X_AXIS]) + sq(y - position_float[Y_AXIS]) @@ -1082,10 +1082,10 @@ Having the real displacement of the head, we can calculate the total movement le // 100mm wide lines using 3mm filament or 35mm wide lines using 1.75mm filament. if (e_D_ratio > 3.0) block->use_advance_lead = false; - else { - const uint32_t max_accel_steps_per_s2 = cs.max_jerk[E_AXIS] / (extruder_advance_K * e_D_ratio) * steps_per_mm; - if (block->acceleration_st > max_accel_steps_per_s2) { - block->acceleration_st = max_accel_steps_per_s2; + else if (e_D_ratio > 0) { + const float max_accel_per_s2 = cs.max_jerk[E_AXIS] / (extruder_advance_K * e_D_ratio); + if (cs.acceleration > max_accel_per_s2) { + block->acceleration_st = ceil(max_accel_per_s2 * steps_per_mm); #ifdef LA_DEBUG SERIAL_ECHOLNPGM("LA: Block acceleration limited due to max E-jerk"); #endif @@ -1133,9 +1133,14 @@ Having the real displacement of the head, we can calculate the total movement le block->adv_comp = extruder_advance_K * e_D_ratio * cs.axis_steps_per_unit[E_AXIS]; block->max_adv_steps = block->nominal_speed * block->adv_comp; + float advance_speed; + if (e_D_ratio > 0) + advance_speed = (extruder_advance_K * e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]); + else + advance_speed = cs.max_jerk[E_AXIS] * cs.axis_steps_per_unit[E_AXIS]; + // to save more space we avoid another copy of calc_timer and go through slow division, but we // still need to replicate the *exact* same step grouping policy (see below) - float advance_speed = (extruder_advance_K * e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]); if (advance_speed > MAX_STEP_FREQUENCY) advance_speed = MAX_STEP_FREQUENCY; float advance_rate = (F_CPU / 8.0) / advance_speed; if (advance_speed > 20000) { diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 6e0937cf..1b4c3b9a 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -117,8 +117,8 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1}; void advance_isr(); static const uint16_t ADV_NEVER = 0xFFFF; - static const uint8_t ADV_INIT = 0b01; - static const uint8_t ADV_DECELERATE = 0b10; + static const uint8_t ADV_INIT = 0b01; // initialize LA + static const uint8_t ADV_ACC_VARY = 0b10; // varying acceleration phase static uint16_t nextMainISR; static uint16_t nextAdvanceISR; @@ -128,13 +128,12 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1}; static uint16_t eISR_Err; static uint16_t current_adv_steps; - static uint16_t final_adv_steps; - static uint16_t max_adv_steps; - static uint32_t LA_decelerate_after; + static uint16_t target_adv_steps; - static int8_t e_steps; - static uint8_t e_step_loops; - static int8_t LA_phase; + static int8_t e_steps; // scheduled e-steps during each isr loop + static uint8_t e_step_loops; // e-steps to execute at most in each isr loop + static uint8_t e_extruding; // current move is an extrusion move + static int8_t LA_phase; // LA compensation phase #define _NEXT_ISR(T) main_Rate = nextMainISR = T #else @@ -349,15 +348,12 @@ FORCE_INLINE void stepper_next_block() #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - LA_decelerate_after = current_block->decelerate_after; - final_adv_steps = current_block->final_adv_steps; - max_adv_steps = current_block->max_adv_steps; e_step_loops = current_block->advance_step_loops; + target_adv_steps = current_block->max_adv_steps; } else { - e_steps = 0; e_step_loops = 1; - current_adv_steps = 0; } + e_steps = 0; nextAdvanceISR = ADV_NEVER; LA_phase = -1; #endif @@ -371,11 +367,17 @@ FORCE_INLINE void stepper_next_block() counter_y.lo = counter_x.lo; counter_z.lo = counter_x.lo; counter_e.lo = counter_x.lo; +#ifdef LIN_ADVANCE + e_extruding = current_block->steps_e.lo != 0; +#endif } else { counter_x.wide = -(current_block->step_event_count.wide >> 1); counter_y.wide = counter_x.wide; counter_z.wide = counter_x.wide; counter_e.wide = counter_x.wide; +#ifdef LIN_ADVANCE + e_extruding = current_block->steps_e.wide != 0; +#endif } step_events_completed.wide = 0; // Set directions. @@ -811,7 +813,7 @@ FORCE_INLINE void isr() { #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { if (step_events_completed.wide <= (unsigned long int)step_loops) - la_state = ADV_INIT; + la_state = ADV_INIT | ADV_ACC_VARY; } #endif } @@ -827,11 +829,13 @@ FORCE_INLINE void isr() { uint16_t timer = calc_timer(step_rate, step_loops); _NEXT_ISR(timer); deceleration_time += timer; + #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - la_state = ADV_DECELERATE; - if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops) - la_state |= ADV_INIT; + if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops) { + target_adv_steps = current_block->final_adv_steps; + la_state = ADV_INIT | ADV_ACC_VARY; + } } #endif } @@ -841,6 +845,17 @@ FORCE_INLINE void isr() { // the initial interrupt blocking. OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate), step_loops); step_loops_nominal = step_loops; + +#ifdef LIN_ADVANCE + if(current_block->use_advance_lead) { + if (!nextAdvanceISR) { + // Due to E-jerk, there can be discontinuities in pressure state where an + // acceleration or deceleration can be skipped or joined with the previous block. + // If LA was not previously active, re-check the pressure level + la_state = ADV_INIT; + } + } +#endif } _NEXT_ISR(OCR1A_nominal); } @@ -849,10 +864,23 @@ FORCE_INLINE void isr() { #ifdef LIN_ADVANCE // avoid multiple instances or function calls to advance_spread - if (la_state & ADV_INIT) eISR_Err = current_block->advance_rate / 4; + if (la_state & ADV_INIT) { + if (current_adv_steps == target_adv_steps) { + // nothing to be done in this phase + la_state = 0; + } + else { + eISR_Err = current_block->advance_rate / 4; + if ((la_state & ADV_ACC_VARY) && e_extruding && (current_adv_steps > target_adv_steps)) { + // LA could reverse the direction of extrusion in this phase + LA_phase = 0; + } + } + } if (la_state & ADV_INIT || nextAdvanceISR != ADV_NEVER) { + // update timers & phase for the next iteration advance_spread(main_Rate); - if (la_state & ADV_DECELERATE) { + if (LA_phase >= 0) { if (step_loops == e_step_loops) LA_phase = (eISR_Rate > main_Rate); else { @@ -898,7 +926,7 @@ FORCE_INLINE void isr() { // Timer interrupt for E. e_steps is set in the main routine. FORCE_INLINE void advance_isr() { - if (step_events_completed.wide > LA_decelerate_after && current_adv_steps > final_adv_steps) { + if (current_adv_steps > target_adv_steps) { // decompression e_steps -= e_step_loops; if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); @@ -908,7 +936,7 @@ FORCE_INLINE void advance_isr() { current_adv_steps = 0; nextAdvanceISR = eISR_Rate; } - else if (step_events_completed.wide < LA_decelerate_after && current_adv_steps < max_adv_steps) { + else if (current_adv_steps < target_adv_steps) { // compression e_steps += e_step_loops; if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); @@ -1233,9 +1261,6 @@ void st_init() nextMainISR = 0; nextAdvanceISR = ADV_NEVER; main_Rate = ADV_NEVER; - e_steps = 0; - e_step_loops = 1; - LA_phase = -1; current_adv_steps = 0; #endif