From eeea2725cba04a94c78bfd1cf58c7465087a6c25 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 17 Mar 2019 19:49:21 +0100 Subject: [PATCH 01/64] Partial LA15 support --- Firmware/ConfigurationStore.cpp | 4 +- Firmware/Configuration_adv.h | 51 +++++---------- Firmware/Marlin_main.cpp | 28 +++------ Firmware/planner.cpp | 107 ++++++++++++++++++++------------ Firmware/planner.h | 7 ++- 5 files changed, 99 insertions(+), 98 deletions(-) diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index f2df8fc6..8ed2dd70 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -165,8 +165,8 @@ void Config_PrintSettings(uint8_t level) #endif if (level >= 10) { #ifdef LIN_ADVANCE - printf_P(PSTR("%SLinear advance settings:\n M900 K%.2f E/D = %.2f\n"), - echomagic, extruder_advance_k, advance_ed_ratio); + printf_P(PSTR("%SLinear advance settings:\n M900 K%.2f\n"), + echomagic, extruder_advance_K); #endif //LIN_ADVANCE } } diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 95130287..d731e863 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -276,43 +276,26 @@ #endif /** - * Implementation of linear pressure control - * - * Assumption: advance = k * (delta velocity) - * K=0 means advance disabled. - * See Marlin documentation for calibration instructions. - */ + * Linear Pressure Control v1.5 + * + * Assumption: advance [steps] = k * (delta velocity [steps/s]) + * K=0 means advance disabled. + * + * NOTE: K values for LIN_ADVANCE 1.5 differ from earlier versions! + * + * Set K around 0.22 for 3mm PLA Direct Drive with ~6.5cm between the drive gear and heatbreak. + * Larger K values will be needed for flexible filament and greater distances. + * If this algorithm produces a higher speed offset than the extruder can handle (compared to E jerk) + * print acceleration will be reduced during the affected moves to keep within the limit. + * + * See http://marlinfw.org/docs/features/lin_advance.html for full instructions. + * Mention @Sebastianv650 on GitHub to alert the author of any issues. + */ #define LIN_ADVANCE #ifdef LIN_ADVANCE - #define LIN_ADVANCE_K 0 //Try around 45 for PLA, around 25 for ABS. - - /** - * Some Slicers produce Gcode with randomly jumping extrusion widths occasionally. - * For example within a 0.4mm perimeter it may produce a single segment of 0.05mm width. - * While this is harmless for normal printing (the fluid nature of the filament will - * close this very, very tiny gap), it throws off the LIN_ADVANCE pressure adaption. - * - * For this case LIN_ADVANCE_E_D_RATIO can be used to set the extrusion:distance ratio - * to a fixed value. Note that using a fixed ratio will lead to wrong nozzle pressures - * if the slicer is using variable widths or layer heights within one print! - * - * This option sets the default E:D ratio at startup. Use `M900` to override this value. - * - * Example: `M900 W0.4 H0.2 D1.75`, where: - * - W is the extrusion width in mm - * - H is the layer height in mm - * - D is the filament diameter in mm - * - * Example: `M900 R0.0458` to set the ratio directly. - * - * Set to 0 to auto-detect the ratio based on given Gcode G1 print moves. - * - * Slic3r (including Prusa Slic3r) produces Gcode compatible with the automatic mode. - * Cura (as of this writing) may produce Gcode incompatible with the automatic mode. - */ -#define LIN_ADVANCE_E_D_RATIO 0 // The calculated ratio (or 0) according to the formula W * H / ((D / 2) ^ 2 * PI) - // Example: 0.4 * 0.2 / ((1.75 / 2) ^ 2 * PI) = 0.033260135 + #define LIN_ADVANCE_K 0 // Unit: mm compression per 1mm/s extruder speed + //#define LA_DEBUG // If enabled, this will generate debug information output over USB. #endif // Arc interpretation settings: diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index d37fbb38..b9af28b7 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -2073,35 +2073,23 @@ static float probe_pt(float x, float y, float z_before) { #ifdef LIN_ADVANCE /** - * M900: Set and/or Get advance K factor and WH/D ratio + * M900: Set and/or Get advance K factor * * K Set advance K factor - * R Set ratio directly (overrides WH/D) - * W H D Set ratio from WH/D */ inline void gcode_M900() { st_synchronize(); const float newK = code_seen('K') ? code_value_float() : -1; - if (newK >= 0) extruder_advance_k = newK; - - float newR = code_seen('R') ? code_value_float() : -1; - if (newR < 0) { - const float newD = code_seen('D') ? code_value_float() : -1, - newW = code_seen('W') ? code_value_float() : -1, - newH = code_seen('H') ? code_value_float() : -1; - if (newD >= 0 && newW >= 0 && newH >= 0) - newR = newD ? (newW * newH) / (sq(newD * 0.5) * M_PI) : 0; - } - if (newR >= 0) advance_ed_ratio = newR; - + if (newK >= 0 && newK < 10) + extruder_advance_K = newK; + else + SERIAL_ECHOLNPGM("K out of allowed range!"); + SERIAL_ECHO_START; SERIAL_ECHOPGM("Advance K="); - SERIAL_ECHOLN(extruder_advance_k); - SERIAL_ECHOPGM(" E/D="); - const float ratio = advance_ed_ratio; - if (ratio) SERIAL_ECHOLN(ratio); else SERIAL_ECHOLNPGM("Auto"); - } + SERIAL_ECHOLN(extruder_advance_K); +} #endif // LIN_ADVANCE bool check_commands() { diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 4a8d6659..43c9f10b 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -126,8 +126,7 @@ float extrude_min_temp=EXTRUDE_MINTEMP; #endif #ifdef LIN_ADVANCE - float extruder_advance_k = LIN_ADVANCE_K, - advance_ed_ratio = LIN_ADVANCE_E_D_RATIO, + float extruder_advance_K = LIN_ADVANCE_K, position_float[NUM_AXIS] = { 0 }; #endif @@ -402,6 +401,13 @@ void planner_recalculate(const float &safe_final_speed) if ((prev->flag | current->flag) & BLOCK_FLAG_RECALCULATE) { // NOTE: Entry and exit factors always > 0 by all previous logic operations. calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed); + #ifdef LIN_ADVANCE + if (current->use_advance_lead) { + const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_unit[E_AXIS]; + current->max_adv_steps = current->nominal_speed * comp; + current->final_adv_steps = next->entry_speed * comp; + } + #endif // Reset current only to ensure next trapezoid is computed. prev->flag &= ~BLOCK_FLAG_RECALCULATE; } @@ -415,6 +421,13 @@ void planner_recalculate(const float &safe_final_speed) // Last/newest block in buffer. Exit speed is set with safe_final_speed. Always recalculated. current = block_buffer + prev_block_index(block_buffer_head); calculate_trapezoid_for_block(current, current->entry_speed, safe_final_speed); + #ifdef LIN_ADVANCE + if (current->use_advance_lead) { + const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_unit[E_AXIS]; + current->max_adv_steps = current->nominal_speed * comp; + current->final_adv_steps = safe_final_speed * comp; + } + #endif current->flag &= ~BLOCK_FLAG_RECALCULATE; // SERIAL_ECHOLNPGM("planner_recalculate - 4"); @@ -748,11 +761,6 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate #endif // ENABLE_MESH_BED_LEVELING target[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]); -#ifdef LIN_ADVANCE - const float mm_D_float = sqrt(sq(x - position_float[X_AXIS]) + sq(y - position_float[Y_AXIS])); - float de_float = e - position_float[E_AXIS]; -#endif - #ifdef PREVENT_DANGEROUS_EXTRUDE if(target[E_AXIS]!=position[E_AXIS]) { @@ -761,7 +769,6 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part #ifdef LIN_ADVANCE position_float[E_AXIS] = e; - de_float = 0; #endif SERIAL_ECHO_START; SERIAL_ECHOLNRPGM(_n(" cold extrusion prevented"));////MSG_ERR_COLD_EXTRUDE_STOP @@ -773,7 +780,6 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part #ifdef LIN_ADVANCE position_float[E_AXIS] = e; - de_float = 0; #endif SERIAL_ECHO_START; SERIAL_ECHOLNRPGM(_n(" too long extrusion prevented"));////MSG_ERR_LONG_EXTRUDE_STOP @@ -1001,10 +1007,50 @@ Having the real displacement of the head, we can calculate the total movement le if(block->steps_x.wide == 0 && block->steps_y.wide == 0 && block->steps_z.wide == 0) { block->acceleration_st = ceil(cs.retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 + #ifdef LIN_ADVANCE + block->use_advance_lead = false; + #endif } else { block->acceleration_st = ceil(cs.acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 + + #ifdef LIN_ADVANCE + /** + * + * Use LIN_ADVANCE for blocks 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) + */ + block->use_advance_lead = block->steps_e + && extruder_advance_K + && delta_mm[E_AXIS] > 0; + + if (block->use_advance_lead) { + block->e_D_ratio = (e - position_float[E_AXIS]) / + sqrt(sq(x - position_float[X_AXIS]) + + sq(y - position_float[Y_AXIS]) + + sq(z - position_float[Z_AXIS])); + + // 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. + if (block->e_D_ratio > 3.0) + block->use_advance_lead = false; + else { + const uint32_t max_accel_steps_per_s2 = max_jerk[E_AXIS] / (extruder_advance_K * block->e_D_ratio) * steps_per_mm; + #ifdef LA_DEBUG + if (block->acceleration_st > max_accel_steps_per_s2) + SERIAL_ECHOLNPGM("Acceleration limited."); + #endif + NOMORE(block->acceleration_st, max_accel_steps_per_s2); + } + } + #endif + // Limit acceleration per axis //FIXME Vojtech: One shall rather limit a projection of the acceleration vector instead of using the limit. if(((float)block->acceleration_st * (float)block->steps_x.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[X_AXIS]) @@ -1037,6 +1083,18 @@ Having the real displacement of the head, we can calculate the total movement le block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0))); + #ifdef LIN_ADVANCE + if (block->use_advance_lead) { + block->advance_speed = ((F_CPU) * 0.125) / (extruder_advance_K * block->e_D_ratio * block->acceleration * axis_steps_per_unit[E_AXIS]); + #ifdef LA_DEBUG + if (extruder_advance_K * block->e_D_ratio * block->acceleration * 2 < block->nominal_speed * block->e_D_ratio) + SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed."); + if (block->advance_speed < 200) + SERIAL_ECHOLNPGM("eISR running at > 10kHz."); + #endif + } + #endif + // Start with a safe speed. // Safe speed is the speed, from which the machine may halt to stop immediately. float safe_speed = block->nominal_speed; @@ -1153,37 +1211,6 @@ Having the real displacement of the head, we can calculate the total movement le previous_nominal_speed = block->nominal_speed; previous_safe_speed = safe_speed; -#ifdef LIN_ADVANCE - - // - // Use LIN_ADVANCE for blocks if all these are true: - // - // esteps : We have E steps todo (a printing move) - // - // block->steps[X_AXIS] || block->steps[Y_AXIS] : We have a movement in XY direction (i.e., not retract / prime). - // - // extruder_advance_k : There is an advance factor set. - // - // block->steps[E_AXIS] != block->step_event_count : A problem occurs if the move before a retract is too small. - // In that case, the retract and move will be executed together. - // This leads to too many advance steps due to a huge e_acceleration. - // The math is good, but we must avoid retract moves with advance! - // de_float > 0.0 : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves) - // - block->use_advance_lead = block->steps_e.wide - && (block->steps_x.wide || block->steps_y.wide) - && extruder_advance_k - && (uint32_t)block->steps_e.wide != block->step_event_count.wide - && de_float > 0.0; - if (block->use_advance_lead) - block->abs_adv_steps_multiplier8 = lround( - extruder_advance_k - * ((advance_ed_ratio < 0.000001) ? de_float / mm_D_float : advance_ed_ratio) // Use the fixed ratio, if set - * (block->nominal_speed / (float)block->nominal_rate) - * cs.axis_steps_per_unit[E_AXIS] * 256.0 - ); -#endif - // Precalculate the division, so when all the trapezoids in the planner queue get recalculated, the division is not repeated. block->speed_factor = block->nominal_rate / block->nominal_speed; calculate_trapezoid_for_block(block, block->entry_speed, safe_speed); diff --git a/Firmware/planner.h b/Firmware/planner.h index b6a9f836..a99f02ed 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -113,14 +113,17 @@ typedef struct { #ifdef LIN_ADVANCE bool use_advance_lead; - unsigned long abs_adv_steps_multiplier8; // Factorised by 2^8 to avoid float + uint16_t advance_speed, // Timer value for extruder speed offset + max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!) + final_adv_steps; // advance steps due to exit speed + float e_D_ratio; #endif uint16_t sdlen; } block_t; #ifdef LIN_ADVANCE - extern float extruder_advance_k, advance_ed_ratio; + extern float extruder_advance_K; #endif #ifdef ENABLE_AUTO_BED_LEVELING From 45563bfdd3d3cb2df1e08c9ea39e6a3abbb94dc5 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 18 Mar 2019 18:43:22 +0100 Subject: [PATCH 02/64] Formatting sanity --- Firmware/planner.cpp | 134 +++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 69 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 43c9f10b..a8441198 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -126,8 +126,8 @@ float extrude_min_temp=EXTRUDE_MINTEMP; #endif #ifdef LIN_ADVANCE - float extruder_advance_K = LIN_ADVANCE_K, - position_float[NUM_AXIS] = { 0 }; +float extruder_advance_K = LIN_ADVANCE_K; +float position_float[NUM_AXIS] = { 0 }; #endif // Returns the index of the next block in the ring buffer @@ -402,11 +402,11 @@ void planner_recalculate(const float &safe_final_speed) // NOTE: Entry and exit factors always > 0 by all previous logic operations. calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed); #ifdef LIN_ADVANCE - if (current->use_advance_lead) { - const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_unit[E_AXIS]; - current->max_adv_steps = current->nominal_speed * comp; - current->final_adv_steps = next->entry_speed * comp; - } + if (current->use_advance_lead) { + const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_unit[E_AXIS]; + current->max_adv_steps = current->nominal_speed * comp; + current->final_adv_steps = next->entry_speed * comp; + } #endif // Reset current only to ensure next trapezoid is computed. prev->flag &= ~BLOCK_FLAG_RECALCULATE; @@ -422,11 +422,11 @@ void planner_recalculate(const float &safe_final_speed) current = block_buffer + prev_block_index(block_buffer_head); calculate_trapezoid_for_block(current, current->entry_speed, safe_final_speed); #ifdef LIN_ADVANCE - if (current->use_advance_lead) { - const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_unit[E_AXIS]; - current->max_adv_steps = current->nominal_speed * comp; - current->final_adv_steps = safe_final_speed * comp; - } + if (current->use_advance_lead) { + const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_unit[E_AXIS]; + current->max_adv_steps = current->nominal_speed * comp; + current->final_adv_steps = safe_final_speed * comp; + } #endif current->flag &= ~BLOCK_FLAG_RECALCULATE; @@ -437,9 +437,9 @@ void plan_init() { block_buffer_head = 0; block_buffer_tail = 0; memset(position, 0, sizeof(position)); // clear position -#ifdef LIN_ADVANCE + #ifdef LIN_ADVANCE memset(position_float, 0, sizeof(position)); // clear position -#endif + #endif previous_speed[0] = 0.0; previous_speed[1] = 0.0; previous_speed[2] = 0.0; @@ -767,9 +767,9 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate if(degHotend(active_extruder)cs.axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH) { position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part -#ifdef LIN_ADVANCE - position_float[E_AXIS] = e; -#endif + #ifdef LIN_ADVANCE + position_float[E_AXIS] = e; + #endif SERIAL_ECHO_START; SERIAL_ECHOLNRPGM(_n(" too long extrusion prevented"));////MSG_ERR_LONG_EXTRUDE_STOP } @@ -1008,7 +1008,7 @@ Having the real displacement of the head, we can calculate the total movement le { block->acceleration_st = ceil(cs.retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 #ifdef LIN_ADVANCE - block->use_advance_lead = false; + block->use_advance_lead = false; #endif } else @@ -1016,39 +1016,35 @@ Having the real displacement of the head, we can calculate the total movement le block->acceleration_st = ceil(cs.acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 #ifdef LIN_ADVANCE - /** - * - * Use LIN_ADVANCE for blocks 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) - */ - block->use_advance_lead = block->steps_e - && extruder_advance_K - && delta_mm[E_AXIS] > 0; + /** + * Use LIN_ADVANCE for blocks 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) + */ + block->use_advance_lead = block->steps_e + && extruder_advance_K + && delta_mm[E_AXIS] > 0; + if (block->use_advance_lead) { + block->e_D_ratio = (e - position_float[E_AXIS]) / + sqrt(sq(x - position_float[X_AXIS]) + + sq(y - position_float[Y_AXIS]) + + sq(z - position_float[Z_AXIS])); - if (block->use_advance_lead) { - block->e_D_ratio = (e - position_float[E_AXIS]) / - sqrt(sq(x - position_float[X_AXIS]) - + sq(y - position_float[Y_AXIS]) - + sq(z - position_float[Z_AXIS])); - - // 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. - if (block->e_D_ratio > 3.0) - block->use_advance_lead = false; - else { - const uint32_t max_accel_steps_per_s2 = max_jerk[E_AXIS] / (extruder_advance_K * block->e_D_ratio) * steps_per_mm; - #ifdef LA_DEBUG - if (block->acceleration_st > max_accel_steps_per_s2) - SERIAL_ECHOLNPGM("Acceleration limited."); - #endif - NOMORE(block->acceleration_st, max_accel_steps_per_s2); - } + // 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. + if (block->e_D_ratio > 3.0) + block->use_advance_lead = false; + else { + const uint32_t max_accel_steps_per_s2 = max_jerk[E_AXIS] / (extruder_advance_K * block->e_D_ratio) * steps_per_mm; + #ifdef LA_DEBUG + if (block->acceleration_st > max_accel_steps_per_s2) + SERIAL_ECHOLNPGM("Acceleration limited."); + #endif + NOMORE(block->acceleration_st, max_accel_steps_per_s2); } + } #endif // Limit acceleration per axis @@ -1084,15 +1080,15 @@ Having the real displacement of the head, we can calculate the total movement le block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0))); #ifdef LIN_ADVANCE - if (block->use_advance_lead) { - block->advance_speed = ((F_CPU) * 0.125) / (extruder_advance_K * block->e_D_ratio * block->acceleration * axis_steps_per_unit[E_AXIS]); - #ifdef LA_DEBUG - if (extruder_advance_K * block->e_D_ratio * block->acceleration * 2 < block->nominal_speed * block->e_D_ratio) - SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed."); - if (block->advance_speed < 200) - SERIAL_ECHOLNPGM("eISR running at > 10kHz."); - #endif - } + if (block->use_advance_lead) { + block->advance_speed = (F_CPU / 8.0) / (extruder_advance_K * block->e_D_ratio * block->acceleration * axis_steps_per_unit[E_AXIS]); + #ifdef LA_DEBUG + if (extruder_advance_K * block->e_D_ratio * block->acceleration * 2 < block->nominal_speed * block->e_D_ratio) + SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed."); + if (block->advance_speed < 200) + SERIAL_ECHOLNPGM("eISR running at > 10kHz."); + #endif + } #endif // Start with a safe speed. @@ -1224,12 +1220,12 @@ Having the real displacement of the head, we can calculate the total movement le // Update position memcpy(position, target, sizeof(target)); // position[] = target[] -#ifdef LIN_ADVANCE + #ifdef LIN_ADVANCE position_float[X_AXIS] = x; position_float[Y_AXIS] = y; position_float[Z_AXIS] = z; position_float[E_AXIS] = e; -#endif + #endif // Recalculate the trapezoids to maximize speed at the segment transitions while respecting // the machine limits (maximum acceleration and maximum jerk). @@ -1292,12 +1288,12 @@ void plan_set_position(float x, float y, float z, const float &e) position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]); #endif // ENABLE_MESH_BED_LEVELING position[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]); -#ifdef LIN_ADVANCE + #ifdef LIN_ADVANCE position_float[X_AXIS] = x; position_float[Y_AXIS] = y; position_float[Z_AXIS] = z; position_float[E_AXIS] = e; -#endif + #endif st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]); previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest. previous_speed[0] = 0.0; @@ -1309,11 +1305,11 @@ void plan_set_position(float x, float y, float z, const float &e) // Only useful in the bed leveling routine, when the mesh bed leveling is off. void plan_set_z_position(const float &z) { - #ifdef LIN_ADVANCE - position_float[Z_AXIS] = z; - #endif - position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]); - st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]); + #ifdef LIN_ADVANCE + position_float[Z_AXIS] = z; + #endif + position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]); + st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]); } void plan_set_e_position(const float &e) From 124540a06f2f9140bcb1478433a24c7337633a7e Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 18 Mar 2019 20:58:01 +0100 Subject: [PATCH 03/64] Adapt LA changes to ConfigurationStore --- Firmware/planner.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index a8441198..f8ac2f59 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -127,7 +127,7 @@ float extrude_min_temp=EXTRUDE_MINTEMP; #ifdef LIN_ADVANCE float extruder_advance_K = LIN_ADVANCE_K; -float position_float[NUM_AXIS] = { 0 }; +float position_float[NUM_AXIS] = { 0, 0, 0, 0 }; #endif // Returns the index of the next block in the ring buffer @@ -403,7 +403,7 @@ void planner_recalculate(const float &safe_final_speed) calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed); #ifdef LIN_ADVANCE if (current->use_advance_lead) { - const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_unit[E_AXIS]; + const float comp = current->e_D_ratio * extruder_advance_K * cs.axis_steps_per_unit[E_AXIS]; current->max_adv_steps = current->nominal_speed * comp; current->final_adv_steps = next->entry_speed * comp; } @@ -423,7 +423,7 @@ void planner_recalculate(const float &safe_final_speed) calculate_trapezoid_for_block(current, current->entry_speed, safe_final_speed); #ifdef LIN_ADVANCE if (current->use_advance_lead) { - const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_unit[E_AXIS]; + const float comp = current->e_D_ratio * extruder_advance_K * cs.axis_steps_per_unit[E_AXIS]; current->max_adv_steps = current->nominal_speed * comp; current->final_adv_steps = safe_final_speed * comp; } @@ -1023,7 +1023,7 @@ Having the real displacement of the head, we can calculate the total movement le * 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) */ - block->use_advance_lead = block->steps_e + block->use_advance_lead = block->steps_e.wide && extruder_advance_K && delta_mm[E_AXIS] > 0; if (block->use_advance_lead) { @@ -1037,12 +1037,13 @@ Having the real displacement of the head, we can calculate the total movement le if (block->e_D_ratio > 3.0) block->use_advance_lead = false; else { - const uint32_t max_accel_steps_per_s2 = max_jerk[E_AXIS] / (extruder_advance_K * block->e_D_ratio) * steps_per_mm; + const uint32_t max_accel_steps_per_s2 = cs.max_jerk[E_AXIS] / (extruder_advance_K * block->e_D_ratio) * steps_per_mm; + if (block->acceleration_st > max_accel_steps_per_s2) { + block->acceleration_st = max_accel_steps_per_s2; #ifdef LA_DEBUG - if (block->acceleration_st > max_accel_steps_per_s2) SERIAL_ECHOLNPGM("Acceleration limited."); #endif - NOMORE(block->acceleration_st, max_accel_steps_per_s2); + } } } #endif @@ -1081,7 +1082,7 @@ Having the real displacement of the head, we can calculate the total movement le #ifdef LIN_ADVANCE if (block->use_advance_lead) { - block->advance_speed = (F_CPU / 8.0) / (extruder_advance_K * block->e_D_ratio * block->acceleration * axis_steps_per_unit[E_AXIS]); + block->advance_speed = (F_CPU / 8.0) / (extruder_advance_K * block->e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]); #ifdef LA_DEBUG if (extruder_advance_K * block->e_D_ratio * block->acceleration * 2 < block->nominal_speed * block->e_D_ratio) SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed."); From bf0c60dd4563d1dbaa2fdf72dd67b60f680702ad Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 29 Apr 2019 16:09:13 +0200 Subject: [PATCH 04/64] Factor-out some repetition into fsensor_step --- Firmware/stepper.cpp | 75 ++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 48 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 74d25777..c80581a5 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -352,6 +352,30 @@ FORCE_INLINE unsigned short calc_timer(uint16_t step_rate) { return timer; } + +#ifndef FILAMENT_SENSOR +#define fsensor_step(cnt) +#else +FORCE_INLINE void fsensor_step(uint8_t cnt) +{ + if (READ(E0_DIR_PIN) == INVERT_E0_DIR) + { + if (count_direction[E_AXIS] == 1) + fsensor_counter -= cnt; + else + fsensor_counter += cnt; + } + else + { + if (count_direction[E_AXIS] == 1) + fsensor_counter += cnt; + else + fsensor_counter -= cnt; + } +} +#endif + + // "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. // It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. ISR(TIMER1_COMPA_vect) { @@ -372,22 +396,7 @@ ISR(TIMER1_COMPA_vect) { cnt++; WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); } -#ifdef FILAMENT_SENSOR - if (READ(E0_DIR_PIN) == INVERT_E0_DIR) - { - if (count_direction[E_AXIS] == 1) - fsensor_counter -= cnt; - else - fsensor_counter += cnt; - } - else - { - if (count_direction[E_AXIS] == 1) - fsensor_counter += cnt; - else - fsensor_counter -= cnt; - } -#endif //FILAMENT_SENSOR + fsensor_step(cnt); if (e_steps) { // Plan another Linear Advance tick. OCR1A = eISR_Rate; @@ -916,22 +925,7 @@ FORCE_INLINE void isr() { estep_loops = (e_steps & 0x0ff00) ? 4 : e_steps; if (step_loops < estep_loops) estep_loops = step_loops; -#ifdef FILAMENT_SENSOR - if (READ(E0_DIR_PIN) == INVERT_E0_DIR) - { - if (count_direction[E_AXIS] == 1) - fsensor_counter -= estep_loops; - else - fsensor_counter += estep_loops; - } - else - { - if (count_direction[E_AXIS] == 1) - fsensor_counter += estep_loops; - else - fsensor_counter -= estep_loops; - } -#endif //FILAMENT_SENSOR + fsensor_step(estep_loops); do { WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); -- e_steps; @@ -1056,22 +1050,7 @@ FORCE_INLINE void isr() { // There is not enough time to fit even a single additional tick. // Tick all the extruder ticks now. MSerial.checkRx(); // Check for serial chars. -#ifdef FILAMENT_SENSOR - if (READ(E0_DIR_PIN) == INVERT_E0_DIR) - { - if (count_direction[E_AXIS] == 1) - fsensor_counter -= e_steps; - else - fsensor_counter += e_steps; - } - else - { - if (count_direction[E_AXIS] == 1) - fsensor_counter += e_steps; - else - fsensor_counter -= e_steps; - } -#endif //FILAMENT_SENSOR + fsensor_step(e_steps); do { WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); -- e_steps; From cbf1a85ec38fc57ca27fe77abf8f2be34e03ebf6 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 4 May 2019 21:02:33 +0200 Subject: [PATCH 05/64] Switch original LA implementation with LA1.5 This discards several Prusa optimizations for LA1.0. We'll re-implement those later if needed. Debugging is turned on. --- Firmware/Configuration_adv.h | 2 + Firmware/planner.h | 10 +- Firmware/stepper.cpp | 356 +++++++++++++---------------------- Firmware/stepper.h | 4 +- 4 files changed, 140 insertions(+), 232 deletions(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index d731e863..45503302 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -292,6 +292,8 @@ * Mention @Sebastianv650 on GitHub to alert the author of any issues. */ #define LIN_ADVANCE +#define LA_DEBUG +#define DEBUG_STEPPER_TIMER_MISSED #ifdef LIN_ADVANCE #define LIN_ADVANCE_K 0 // Unit: mm compression per 1mm/s extruder speed diff --git a/Firmware/planner.h b/Firmware/planner.h index a99f02ed..41e4c61b 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -112,10 +112,10 @@ typedef struct { float speed_factor; #ifdef LIN_ADVANCE - bool use_advance_lead; - uint16_t advance_speed, // Timer value for extruder speed offset - max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!) - final_adv_steps; // advance steps due to exit speed + bool use_advance_lead; // Whether the current block uses LA + uint16_t advance_speed, // Step-rate for extruder speed + max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!) + final_adv_steps; // advance steps due to exit speed float e_D_ratio; #endif @@ -123,7 +123,7 @@ typedef struct { } block_t; #ifdef LIN_ADVANCE - extern float extruder_advance_K; +extern float extruder_advance_K; // Linear-advance K factor #endif #ifdef ENABLE_AUTO_BED_LEVELING diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index c80581a5..6b52c5ac 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -113,21 +113,24 @@ volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0}; volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1}; #ifdef LIN_ADVANCE + void advance_isr_scheduler(); + void advance_isr(); + + static const uint16_t ADV_NEVER = 0xFFFF; static uint16_t nextMainISR = 0; - static uint16_t eISR_Rate; + static uint16_t nextAdvanceISR = ADV_NEVER; - // Extrusion steps to be executed by the stepper. - // If set to non zero, the timer ISR routine will tick the Linear Advance extruder ticks first. - // If e_steps is zero, then the timer ISR routine will perform the usual DDA step. - static volatile int16_t e_steps = 0; - // How many extruder steps shall be ticked at a single ISR invocation? - static uint8_t estep_loops; - // The current speed of the extruder, scaled by the linear advance constant, so it has the same measure - // as current_adv_steps. - static int current_estep_rate; - // The current pretension of filament expressed in extruder micro steps. - static int current_adv_steps; + static uint16_t eISR_Rate = ADV_NEVER; + + static bool use_advance_lead; + + 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 volatile int8_t e_steps; #define _NEXT_ISR(T) nextMainISR = T #else @@ -353,29 +356,6 @@ FORCE_INLINE unsigned short calc_timer(uint16_t step_rate) { } -#ifndef FILAMENT_SENSOR -#define fsensor_step(cnt) -#else -FORCE_INLINE void fsensor_step(uint8_t cnt) -{ - if (READ(E0_DIR_PIN) == INVERT_E0_DIR) - { - if (count_direction[E_AXIS] == 1) - fsensor_counter -= cnt; - else - fsensor_counter += cnt; - } - else - { - if (count_direction[E_AXIS] == 1) - fsensor_counter += cnt; - else - fsensor_counter -= cnt; - } -} -#endif - - // "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. // It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. ISR(TIMER1_COMPA_vect) { @@ -385,38 +365,10 @@ ISR(TIMER1_COMPA_vect) { #endif //DEBUG_STACK_MONITOR #ifdef LIN_ADVANCE - // If there are any e_steps planned, tick them. - bool run_main_isr = false; - if (e_steps) { - //WRITE_NC(LOGIC_ANALYZER_CH7, true); - uint8_t cnt = 0; - for (uint8_t i = estep_loops; e_steps && i --;) { - WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); - -- e_steps; - cnt++; - WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); - } - fsensor_step(cnt); - if (e_steps) { - // Plan another Linear Advance tick. - OCR1A = eISR_Rate; - nextMainISR -= eISR_Rate; - } else if (! (nextMainISR & 0x8000) || nextMainISR < 16) { - // The timer did not overflow and it is big enough, so it makes sense to plan it. - OCR1A = nextMainISR; - } else { - // The timer has overflown, or it is too small. Run the main ISR just after the Linear Advance routine - // in the current interrupt tick. - run_main_isr = true; - //FIXME pick the serial line. - } - //WRITE_NC(LOGIC_ANALYZER_CH7, false); - } else - run_main_isr = true; - - if (run_main_isr) -#endif + advance_isr_scheduler(); +#else isr(); +#endif // Don't run the ISR faster than possible // Is there a 8us time left before the next interrupt triggers? @@ -517,9 +469,14 @@ FORCE_INLINE void stepper_next_block() step_loops_nominal = 0; acc_step_rate = uint16_t(current_block->initial_rate); acceleration_time = calc_timer(acc_step_rate); + #ifdef LIN_ADVANCE - current_estep_rate = ((unsigned long)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; -#endif /* LIN_ADVANCE */ + if ((use_advance_lead = 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; + } +#endif if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) { counter_x.lo = -(current_block->step_event_count.lo >> 1); @@ -788,7 +745,7 @@ FORCE_INLINE void stepper_tick_lowres() counter_e.lo -= current_block->step_event_count.lo; count_position[E_AXIS] += count_direction[E_AXIS]; #ifdef LIN_ADVANCE - ++ e_steps; + e_steps += count_direction[E_AXIS]; #else #ifdef FILAMENT_SENSOR ++ fsensor_counter; @@ -850,11 +807,11 @@ FORCE_INLINE void stepper_tick_highres() counter_e.wide -= current_block->step_event_count.wide; count_position[E_AXIS]+=count_direction[E_AXIS]; #ifdef LIN_ADVANCE - ++ e_steps; + e_steps += count_direction[E_AXIS]; #else - #ifdef FILAMENT_SENSOR + #ifdef FILAMENT_SENSOR ++ fsensor_counter; - #endif //FILAMENT_SENSOR + #endif //FILAMENT_SENSOR WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #endif } @@ -863,9 +820,6 @@ FORCE_INLINE void stepper_tick_highres() } } -// 50us delay -#define LIN_ADV_FIRST_TICK_DELAY 100 - FORCE_INLINE void isr() { //WRITE_NC(LOGIC_ANALYZER_CH0, true); @@ -877,65 +831,11 @@ FORCE_INLINE void isr() { if (current_block != NULL) { stepper_check_endstops(); -#ifdef LIN_ADVANCE - e_steps = 0; -#endif /* LIN_ADVANCE */ if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) stepper_tick_lowres(); else stepper_tick_highres(); -#ifdef LIN_ADVANCE - if (out_bits&(1<use_advance_lead) { - //int esteps_inc = 0; - //esteps_inc = current_estep_rate - current_adv_steps; - //e_steps += esteps_inc; - e_steps += current_estep_rate - current_adv_steps; -#if 0 - if (abs(esteps_inc) > 4) { - LOGIC_ANALYZER_SERIAL_TX_WRITE(esteps_inc); - if (esteps_inc < -511 || esteps_inc > 511) - LOGIC_ANALYZER_SERIAL_TX_WRITE(esteps_inc >> 9); - } -#endif - current_adv_steps = current_estep_rate; - } - // If we have esteps to execute, step some of them now. - if (e_steps) { - //WRITE_NC(LOGIC_ANALYZER_CH7, true); - // Set the step direction. - bool neg = e_steps < 0; - { - bool dir = - #ifdef SNMM - (neg == (mmu_extruder & 1)) - #else - neg - #endif - ? INVERT_E0_DIR : !INVERT_E0_DIR; //If we have SNMM, reverse every second extruder. - WRITE_NC(E0_DIR_PIN, dir); - if (neg) - // Flip the e_steps counter to be always positive. - e_steps = - e_steps; - } - // Tick min(step_loops, abs(e_steps)). - estep_loops = (e_steps & 0x0ff00) ? 4 : e_steps; - if (step_loops < estep_loops) - estep_loops = step_loops; - fsensor_step(estep_loops); - do { - WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); - -- e_steps; - WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); - } while (-- estep_loops != 0); - //WRITE_NC(LOGIC_ANALYZER_CH7, false); - MSerial.checkRx(); // Check for serial chars. - } -#endif - // Calculare new timer value // 13.38-14.63us for steady state, // 25.12us for acceleration / deceleration. @@ -952,11 +852,18 @@ FORCE_INLINE void isr() { uint16_t timer = calc_timer(acc_step_rate); _NEXT_ISR(timer); acceleration_time += timer; - #ifdef LIN_ADVANCE - if (current_block->use_advance_lead) - // int32_t = (uint16_t * uint32_t) >> 17 - current_estep_rate = ((uint32_t)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; - #endif +#ifdef LIN_ADVANCE + if (current_block->use_advance_lead) { + if (step_events_completed.wide == (unsigned long int)step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) { + nextAdvanceISR = 0; // Wake up eISR on first acceleration loop and fire ISR if final adv_rate is reached + eISR_Rate = current_block->advance_speed; + } + } + else { + eISR_Rate = ADV_NEVER; + if (e_steps) nextAdvanceISR = 0; + } +#endif } else if (step_events_completed.wide > (unsigned long int)current_block->decelerate_after) { uint16_t step_rate; @@ -970,103 +877,35 @@ FORCE_INLINE void isr() { uint16_t timer = calc_timer(step_rate); _NEXT_ISR(timer); deceleration_time += timer; - #ifdef LIN_ADVANCE - if (current_block->use_advance_lead) - current_estep_rate = ((uint32_t)step_rate * current_block->abs_adv_steps_multiplier8) >> 17; - #endif +#ifdef LIN_ADVANCE + if (current_block->use_advance_lead) { + if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) { + nextAdvanceISR = 0; // Wake up eISR on first deceleration loop + eISR_Rate = current_block->advance_speed; + } + } + else { + eISR_Rate = ADV_NEVER; + if (e_steps) nextAdvanceISR = 0; + } +#endif } else { +#ifdef LIN_ADVANCE + // If we have esteps to execute, fire the next advance_isr "now" + if (e_steps && eISR_Rate != current_block->advance_speed) nextAdvanceISR = 0; +#endif if (! step_loops_nominal) { // Calculation of the steady state timer rate has been delayed to the 1st tick of the steady state to lower // the initial interrupt blocking. OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate)); step_loops_nominal = step_loops; - #ifdef LIN_ADVANCE - if (current_block->use_advance_lead) - current_estep_rate = (current_block->nominal_rate * current_block->abs_adv_steps_multiplier8) >> 17; - #endif } _NEXT_ISR(OCR1A_nominal); } //WRITE_NC(LOGIC_ANALYZER_CH1, false); } -#ifdef LIN_ADVANCE - if (e_steps && current_block->use_advance_lead) { - //WRITE_NC(LOGIC_ANALYZER_CH7, true); - MSerial.checkRx(); // Check for serial chars. - // Some of the E steps were not ticked yet. Plan additional interrupts. - uint16_t now = TCNT1; - // Plan the first linear advance interrupt after 50us from now. - uint16_t to_go = nextMainISR - now - LIN_ADV_FIRST_TICK_DELAY; - eISR_Rate = 0; - if ((to_go & 0x8000) == 0) { - // The to_go number is not negative. - // Count the number of 7812,5 ticks, that fit into to_go 2MHz ticks. - uint8_t ticks = to_go >> 8; - if (ticks == 1) { - // Avoid running the following loop for a very short interval. - estep_loops = 255; - eISR_Rate = 1; - } else if ((e_steps & 0x0ff00) == 0) { - // e_steps <= 0x0ff - if (uint8_t(e_steps) <= ticks) { - // Spread the e_steps along the whole go_to interval. - eISR_Rate = to_go / uint8_t(e_steps); - estep_loops = 1; - } else if (ticks != 0) { - // At least one tick fits into the to_go interval. Calculate the e-step grouping. - uint8_t e = uint8_t(e_steps) >> 1; - estep_loops = 2; - while (e > ticks) { - e >>= 1; - estep_loops <<= 1; - } - // Now the estep_loops contains the number of loops of power of 2, that will be sufficient - // to squeeze enough of Linear Advance ticks until nextMainISR. - // Calculate the tick rate. - eISR_Rate = to_go / ticks; - } - } else { - // This is an exterme case with too many e_steps inserted by the linear advance. - // At least one tick fits into the to_go interval. Calculate the e-step grouping. - estep_loops = 2; - uint16_t e = e_steps >> 1; - while (e & 0x0ff00) { - e >>= 1; - estep_loops <<= 1; - } - while (uint8_t(e) > ticks) { - e >>= 1; - estep_loops <<= 1; - } - // Now the estep_loops contains the number of loops of power of 2, that will be sufficient - // to squeeze enough of Linear Advance ticks until nextMainISR. - // Calculate the tick rate. - eISR_Rate = to_go / ticks; - } - } - if (eISR_Rate == 0) { - // There is not enough time to fit even a single additional tick. - // Tick all the extruder ticks now. - MSerial.checkRx(); // Check for serial chars. - fsensor_step(e_steps); - do { - WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); - -- e_steps; - WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); - } while (e_steps); - OCR1A = nextMainISR; - } else { - // Tick the 1st Linear Advance interrupt after 50us from now. - nextMainISR -= LIN_ADV_FIRST_TICK_DELAY; - OCR1A = now + LIN_ADV_FIRST_TICK_DELAY; - } - //WRITE_NC(LOGIC_ANALYZER_CH7, false); - } else - OCR1A = nextMainISR; -#endif - // If current block is finished, reset pointer if (step_events_completed.wide >= current_block->step_event_count.wide) { #ifdef FILAMENT_SENSOR @@ -1094,14 +933,84 @@ FORCE_INLINE void isr() { } #ifdef LIN_ADVANCE +// Timer interrupt for E. e_steps is set in the main routine. + +FORCE_INLINE void advance_isr() { + if (use_advance_lead) { + if (step_events_completed.wide > LA_decelerate_after && current_adv_steps > final_adv_steps) { + e_steps--; + current_adv_steps--; + nextAdvanceISR = eISR_Rate; + } + else if (step_events_completed.wide < LA_decelerate_after && current_adv_steps < max_adv_steps) { + e_steps++; + current_adv_steps++; + nextAdvanceISR = eISR_Rate; + } + else { + nextAdvanceISR = ADV_NEVER; + eISR_Rate = ADV_NEVER; + } + } + else + nextAdvanceISR = ADV_NEVER; + + if (e_steps) { + MSerial.checkRx(); // Check for serial chars. + + bool dir = +#ifdef SNMM + ((e_steps < 0) == (snmm_extruder & 1)) +#else + (e_steps < 0) +#endif + ? INVERT_E0_DIR : !INVERT_E0_DIR; //If we have SNMM, reverse every second extruder. + WRITE(E0_DIR_PIN, dir); + + if(e_steps < 0) e_steps = -e_steps; + fsensor_counter += e_steps; + while (e_steps) { + WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); + --e_steps; + WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); + } + } +} + +FORCE_INLINE void advance_isr_scheduler() { + // Run main stepping ISR if flagged + if (!nextMainISR) isr(); + + // Run Advance stepping ISR if flagged + if (!nextAdvanceISR) advance_isr(); + + // Is the next advance ISR scheduled before the next main ISR? + if (nextAdvanceISR <= nextMainISR) { + // Set up the next interrupt + OCR1A = nextAdvanceISR; + // New interval for the next main ISR + if (nextMainISR) nextMainISR -= nextAdvanceISR; + // Will call Stepper::advance_isr on the next interrupt + nextAdvanceISR = 0; + } + else { + // The next main ISR comes first + OCR1A = nextMainISR; + // New interval for the next advance ISR, if any + if (nextAdvanceISR && nextAdvanceISR != ADV_NEVER) + nextAdvanceISR -= nextMainISR; + // Will call Stepper::isr on the next interrupt + nextMainISR = 0; + } +} void clear_current_adv_vars() { - e_steps = 0; //Should be already 0 at an filament change event, but just to be sure.. - current_adv_steps = 0; + e_steps = 0; + current_adv_steps = 0; } #endif // LIN_ADVANCE - + void st_init() { #ifdef TMC2130 @@ -1326,10 +1235,9 @@ void st_init() ENABLE_STEPPER_DRIVER_INTERRUPT(); #ifdef LIN_ADVANCE - e_steps = 0; - current_adv_steps = 0; + clear_current_adv_vars(); #endif - + enable_endstops(true); // Start with endstops active. After homing they can be disabled sei(); } diff --git a/Firmware/stepper.h b/Firmware/stepper.h index 6130f3bb..23b79184 100644 --- a/Firmware/stepper.h +++ b/Firmware/stepper.h @@ -38,9 +38,7 @@ void st_init(); void isr(); #ifdef LIN_ADVANCE - void advance_isr(); - void advance_isr_scheduler(); - void clear_current_adv_vars(); //Used to reset the built up pretension and remaining esteps on filament change. +void clear_current_adv_vars(); // Used to reset the built up pretension and remaining esteps on filament change. #endif // Block until all buffered steps are executed From ebdc5e35e7587035f783466def32fed7922af72d Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 4 May 2019 23:05:30 +0200 Subject: [PATCH 06/64] Remove two more OCR1A direct manipulations Use _NEXT_ISR and st_reset_timer to correctly reinitialize and re-schedule the advance ticks. --- Firmware/stepper.cpp | 33 +++++++++++++++++++++++++++------ Firmware/stepper.h | 10 +--------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 6b52c5ac..5a3d4010 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -535,7 +535,7 @@ FORCE_INLINE void stepper_next_block() } } else { - OCR1A = 2000; // 1kHz. + _NEXT_ISR(2000); // 1kHz. } //WRITE_NC(LOGIC_ANALYZER_CH2, false); } @@ -1229,20 +1229,41 @@ void st_init() // create_speed_lookuptable.py TCCR1B = (TCCR1B & ~(0x07< Date: Sun, 5 May 2019 17:22:27 +0200 Subject: [PATCH 07/64] Move speed lookup defs into a separate source --- Firmware/speed_lookuptable.cpp | 147 ++++++++++++++++++++++ Firmware/speed_lookuptable.h | 217 ++++++++++++--------------------- Firmware/stepper.cpp | 86 ------------- 3 files changed, 224 insertions(+), 226 deletions(-) create mode 100644 Firmware/speed_lookuptable.cpp diff --git a/Firmware/speed_lookuptable.cpp b/Firmware/speed_lookuptable.cpp new file mode 100644 index 00000000..b8930e7b --- /dev/null +++ b/Firmware/speed_lookuptable.cpp @@ -0,0 +1,147 @@ +#include "speed_lookuptable.h" + +#if F_CPU == 16000000 + +const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {\ +{ 62500, 55556}, { 6944, 3268}, { 3676, 1176}, { 2500, 607}, { 1893, 369}, { 1524, 249}, { 1275, 179}, { 1096, 135}, +{ 961, 105}, { 856, 85}, { 771, 69}, { 702, 58}, { 644, 49}, { 595, 42}, { 553, 37}, { 516, 32}, +{ 484, 28}, { 456, 25}, { 431, 23}, { 408, 20}, { 388, 19}, { 369, 16}, { 353, 16}, { 337, 14}, +{ 323, 13}, { 310, 11}, { 299, 11}, { 288, 11}, { 277, 9}, { 268, 9}, { 259, 8}, { 251, 8}, +{ 243, 8}, { 235, 7}, { 228, 6}, { 222, 6}, { 216, 6}, { 210, 6}, { 204, 5}, { 199, 5}, +{ 194, 5}, { 189, 4}, { 185, 4}, { 181, 4}, { 177, 4}, { 173, 4}, { 169, 4}, { 165, 3}, +{ 162, 3}, { 159, 4}, { 155, 3}, { 152, 3}, { 149, 2}, { 147, 3}, { 144, 3}, { 141, 2}, +{ 139, 3}, { 136, 2}, { 134, 2}, { 132, 3}, { 129, 2}, { 127, 2}, { 125, 2}, { 123, 2}, +{ 121, 2}, { 119, 1}, { 118, 2}, { 116, 2}, { 114, 1}, { 113, 2}, { 111, 2}, { 109, 1}, +{ 108, 2}, { 106, 1}, { 105, 2}, { 103, 1}, { 102, 1}, { 101, 1}, { 100, 2}, { 98, 1}, +{ 97, 1}, { 96, 1}, { 95, 2}, { 93, 1}, { 92, 1}, { 91, 1}, { 90, 1}, { 89, 1}, +{ 88, 1}, { 87, 1}, { 86, 1}, { 85, 1}, { 84, 1}, { 83, 0}, { 83, 1}, { 82, 1}, +{ 81, 1}, { 80, 1}, { 79, 1}, { 78, 0}, { 78, 1}, { 77, 1}, { 76, 1}, { 75, 0}, +{ 75, 1}, { 74, 1}, { 73, 1}, { 72, 0}, { 72, 1}, { 71, 1}, { 70, 0}, { 70, 1}, +{ 69, 0}, { 69, 1}, { 68, 1}, { 67, 0}, { 67, 1}, { 66, 0}, { 66, 1}, { 65, 0}, +{ 65, 1}, { 64, 1}, { 63, 0}, { 63, 1}, { 62, 0}, { 62, 1}, { 61, 0}, { 61, 1}, +{ 60, 0}, { 60, 0}, { 60, 1}, { 59, 0}, { 59, 1}, { 58, 0}, { 58, 1}, { 57, 0}, +{ 57, 1}, { 56, 0}, { 56, 0}, { 56, 1}, { 55, 0}, { 55, 1}, { 54, 0}, { 54, 0}, +{ 54, 1}, { 53, 0}, { 53, 0}, { 53, 1}, { 52, 0}, { 52, 0}, { 52, 1}, { 51, 0}, +{ 51, 0}, { 51, 1}, { 50, 0}, { 50, 0}, { 50, 1}, { 49, 0}, { 49, 0}, { 49, 1}, +{ 48, 0}, { 48, 0}, { 48, 1}, { 47, 0}, { 47, 0}, { 47, 0}, { 47, 1}, { 46, 0}, +{ 46, 0}, { 46, 1}, { 45, 0}, { 45, 0}, { 45, 0}, { 45, 1}, { 44, 0}, { 44, 0}, +{ 44, 0}, { 44, 1}, { 43, 0}, { 43, 0}, { 43, 0}, { 43, 1}, { 42, 0}, { 42, 0}, +{ 42, 0}, { 42, 1}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 1}, { 40, 0}, +{ 40, 0}, { 40, 0}, { 40, 0}, { 40, 1}, { 39, 0}, { 39, 0}, { 39, 0}, { 39, 0}, +{ 39, 1}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 1}, { 37, 0}, { 37, 0}, +{ 37, 0}, { 37, 0}, { 37, 0}, { 37, 1}, { 36, 0}, { 36, 0}, { 36, 0}, { 36, 0}, +{ 36, 1}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 1}, +{ 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 1}, { 33, 0}, { 33, 0}, +{ 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 1}, { 32, 0}, { 32, 0}, { 32, 0}, +{ 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 1}, { 31, 0}, { 31, 0}, { 31, 0}, +{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0} +}; + +const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {\ +{ 62500, 12500}, { 50000, 8334}, { 41666, 5952}, { 35714, 4464}, { 31250, 3473}, { 27777, 2777}, { 25000, 2273}, { 22727, 1894}, +{ 20833, 1603}, { 19230, 1373}, { 17857, 1191}, { 16666, 1041}, { 15625, 920}, { 14705, 817}, { 13888, 731}, { 13157, 657}, +{ 12500, 596}, { 11904, 541}, { 11363, 494}, { 10869, 453}, { 10416, 416}, { 10000, 385}, { 9615, 356}, { 9259, 331}, +{ 8928, 308}, { 8620, 287}, { 8333, 269}, { 8064, 252}, { 7812, 237}, { 7575, 223}, { 7352, 210}, { 7142, 198}, +{ 6944, 188}, { 6756, 178}, { 6578, 168}, { 6410, 160}, { 6250, 153}, { 6097, 145}, { 5952, 139}, { 5813, 132}, +{ 5681, 126}, { 5555, 121}, { 5434, 115}, { 5319, 111}, { 5208, 106}, { 5102, 102}, { 5000, 99}, { 4901, 94}, +{ 4807, 91}, { 4716, 87}, { 4629, 84}, { 4545, 81}, { 4464, 79}, { 4385, 75}, { 4310, 73}, { 4237, 71}, +{ 4166, 68}, { 4098, 66}, { 4032, 64}, { 3968, 62}, { 3906, 60}, { 3846, 59}, { 3787, 56}, { 3731, 55}, +{ 3676, 53}, { 3623, 52}, { 3571, 50}, { 3521, 49}, { 3472, 48}, { 3424, 46}, { 3378, 45}, { 3333, 44}, +{ 3289, 43}, { 3246, 41}, { 3205, 41}, { 3164, 39}, { 3125, 39}, { 3086, 38}, { 3048, 36}, { 3012, 36}, +{ 2976, 35}, { 2941, 35}, { 2906, 33}, { 2873, 33}, { 2840, 32}, { 2808, 31}, { 2777, 30}, { 2747, 30}, +{ 2717, 29}, { 2688, 29}, { 2659, 28}, { 2631, 27}, { 2604, 27}, { 2577, 26}, { 2551, 26}, { 2525, 25}, +{ 2500, 25}, { 2475, 25}, { 2450, 23}, { 2427, 24}, { 2403, 23}, { 2380, 22}, { 2358, 22}, { 2336, 22}, +{ 2314, 21}, { 2293, 21}, { 2272, 20}, { 2252, 20}, { 2232, 20}, { 2212, 20}, { 2192, 19}, { 2173, 18}, +{ 2155, 19}, { 2136, 18}, { 2118, 18}, { 2100, 17}, { 2083, 17}, { 2066, 17}, { 2049, 17}, { 2032, 16}, +{ 2016, 16}, { 2000, 16}, { 1984, 16}, { 1968, 15}, { 1953, 16}, { 1937, 14}, { 1923, 15}, { 1908, 15}, +{ 1893, 14}, { 1879, 14}, { 1865, 14}, { 1851, 13}, { 1838, 14}, { 1824, 13}, { 1811, 13}, { 1798, 13}, +{ 1785, 12}, { 1773, 13}, { 1760, 12}, { 1748, 12}, { 1736, 12}, { 1724, 12}, { 1712, 12}, { 1700, 11}, +{ 1689, 12}, { 1677, 11}, { 1666, 11}, { 1655, 11}, { 1644, 11}, { 1633, 10}, { 1623, 11}, { 1612, 10}, +{ 1602, 10}, { 1592, 10}, { 1582, 10}, { 1572, 10}, { 1562, 10}, { 1552, 9}, { 1543, 10}, { 1533, 9}, +{ 1524, 9}, { 1515, 9}, { 1506, 9}, { 1497, 9}, { 1488, 9}, { 1479, 9}, { 1470, 9}, { 1461, 8}, +{ 1453, 8}, { 1445, 9}, { 1436, 8}, { 1428, 8}, { 1420, 8}, { 1412, 8}, { 1404, 8}, { 1396, 8}, +{ 1388, 7}, { 1381, 8}, { 1373, 7}, { 1366, 8}, { 1358, 7}, { 1351, 7}, { 1344, 8}, { 1336, 7}, +{ 1329, 7}, { 1322, 7}, { 1315, 7}, { 1308, 6}, { 1302, 7}, { 1295, 7}, { 1288, 6}, { 1282, 7}, +{ 1275, 6}, { 1269, 7}, { 1262, 6}, { 1256, 6}, { 1250, 7}, { 1243, 6}, { 1237, 6}, { 1231, 6}, +{ 1225, 6}, { 1219, 6}, { 1213, 6}, { 1207, 6}, { 1201, 5}, { 1196, 6}, { 1190, 6}, { 1184, 5}, +{ 1179, 6}, { 1173, 5}, { 1168, 6}, { 1162, 5}, { 1157, 5}, { 1152, 6}, { 1146, 5}, { 1141, 5}, +{ 1136, 5}, { 1131, 5}, { 1126, 5}, { 1121, 5}, { 1116, 5}, { 1111, 5}, { 1106, 5}, { 1101, 5}, +{ 1096, 5}, { 1091, 5}, { 1086, 4}, { 1082, 5}, { 1077, 5}, { 1072, 4}, { 1068, 5}, { 1063, 4}, +{ 1059, 5}, { 1054, 4}, { 1050, 4}, { 1046, 5}, { 1041, 4}, { 1037, 4}, { 1033, 5}, { 1028, 4}, +{ 1024, 4}, { 1020, 4}, { 1016, 4}, { 1012, 4}, { 1008, 4}, { 1004, 4}, { 1000, 4}, { 996, 4}, +{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3} +}; + +#elif F_CPU == 20000000 + +const uint16_t speed_lookuptable_fast[256][2] PROGMEM = { + {62500, 54055}, {8445, 3917}, {4528, 1434}, {3094, 745}, {2349, 456}, {1893, 307}, {1586, 222}, {1364, 167}, + {1197, 131}, {1066, 105}, {961, 86}, {875, 72}, {803, 61}, {742, 53}, {689, 45}, {644, 40}, + {604, 35}, {569, 32}, {537, 28}, {509, 25}, {484, 23}, {461, 21}, {440, 19}, {421, 17}, + {404, 16}, {388, 15}, {373, 14}, {359, 13}, {346, 12}, {334, 11}, {323, 10}, {313, 10}, + {303, 9}, {294, 9}, {285, 8}, {277, 7}, {270, 8}, {262, 7}, {255, 6}, {249, 6}, + {243, 6}, {237, 6}, {231, 5}, {226, 5}, {221, 5}, {216, 5}, {211, 4}, {207, 5}, + {202, 4}, {198, 4}, {194, 4}, {190, 3}, {187, 4}, {183, 3}, {180, 3}, {177, 4}, + {173, 3}, {170, 3}, {167, 2}, {165, 3}, {162, 3}, {159, 2}, {157, 3}, {154, 2}, + {152, 3}, {149, 2}, {147, 2}, {145, 2}, {143, 2}, {141, 2}, {139, 2}, {137, 2}, + {135, 2}, {133, 2}, {131, 2}, {129, 1}, {128, 2}, {126, 2}, {124, 1}, {123, 2}, + {121, 1}, {120, 2}, {118, 1}, {117, 1}, {116, 2}, {114, 1}, {113, 1}, {112, 2}, + {110, 1}, {109, 1}, {108, 1}, {107, 2}, {105, 1}, {104, 1}, {103, 1}, {102, 1}, + {101, 1}, {100, 1}, {99, 1}, {98, 1}, {97, 1}, {96, 1}, {95, 1}, {94, 1}, + {93, 1}, {92, 1}, {91, 0}, {91, 1}, {90, 1}, {89, 1}, {88, 1}, {87, 0}, + {87, 1}, {86, 1}, {85, 1}, {84, 0}, {84, 1}, {83, 1}, {82, 1}, {81, 0}, + {81, 1}, {80, 1}, {79, 0}, {79, 1}, {78, 0}, {78, 1}, {77, 1}, {76, 0}, + {76, 1}, {75, 0}, {75, 1}, {74, 1}, {73, 0}, {73, 1}, {72, 0}, {72, 1}, + {71, 0}, {71, 1}, {70, 0}, {70, 1}, {69, 0}, {69, 1}, {68, 0}, {68, 1}, + {67, 0}, {67, 1}, {66, 0}, {66, 1}, {65, 0}, {65, 0}, {65, 1}, {64, 0}, + {64, 1}, {63, 0}, {63, 1}, {62, 0}, {62, 0}, {62, 1}, {61, 0}, {61, 1}, + {60, 0}, {60, 0}, {60, 1}, {59, 0}, {59, 0}, {59, 1}, {58, 0}, {58, 0}, + {58, 1}, {57, 0}, {57, 0}, {57, 1}, {56, 0}, {56, 0}, {56, 1}, {55, 0}, + {55, 0}, {55, 1}, {54, 0}, {54, 0}, {54, 1}, {53, 0}, {53, 0}, {53, 0}, + {53, 1}, {52, 0}, {52, 0}, {52, 1}, {51, 0}, {51, 0}, {51, 0}, {51, 1}, + {50, 0}, {50, 0}, {50, 0}, {50, 1}, {49, 0}, {49, 0}, {49, 0}, {49, 1}, + {48, 0}, {48, 0}, {48, 0}, {48, 1}, {47, 0}, {47, 0}, {47, 0}, {47, 1}, + {46, 0}, {46, 0}, {46, 0}, {46, 0}, {46, 1}, {45, 0}, {45, 0}, {45, 0}, + {45, 1}, {44, 0}, {44, 0}, {44, 0}, {44, 0}, {44, 1}, {43, 0}, {43, 0}, + {43, 0}, {43, 0}, {43, 1}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, + {42, 1}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 1}, {40, 0}, + {40, 0}, {40, 0}, {40, 0}, {40, 1}, {39, 0}, {39, 0}, {39, 0}, {39, 0}, + {39, 0}, {39, 0}, {39, 1}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, +}; + +const uint16_t speed_lookuptable_slow[256][2] PROGMEM = { + {62500, 10417}, {52083, 7441}, {44642, 5580}, {39062, 4340}, {34722, 3472}, {31250, 2841}, {28409, 2368}, {26041, 2003}, + {24038, 1717}, {22321, 1488}, {20833, 1302}, {19531, 1149}, {18382, 1021}, {17361, 914}, {16447, 822}, {15625, 745}, + {14880, 676}, {14204, 618}, {13586, 566}, {13020, 520}, {12500, 481}, {12019, 445}, {11574, 414}, {11160, 385}, + {10775, 359}, {10416, 336}, {10080, 315}, {9765, 296}, {9469, 278}, {9191, 263}, {8928, 248}, {8680, 235}, + {8445, 222}, {8223, 211}, {8012, 200}, {7812, 191}, {7621, 181}, {7440, 173}, {7267, 165}, {7102, 158}, + {6944, 151}, {6793, 145}, {6648, 138}, {6510, 133}, {6377, 127}, {6250, 123}, {6127, 118}, {6009, 113}, + {5896, 109}, {5787, 106}, {5681, 101}, {5580, 98}, {5482, 95}, {5387, 91}, {5296, 88}, {5208, 86}, + {5122, 82}, {5040, 80}, {4960, 78}, {4882, 75}, {4807, 73}, {4734, 70}, {4664, 69}, {4595, 67}, + {4528, 64}, {4464, 63}, {4401, 61}, {4340, 60}, {4280, 58}, {4222, 56}, {4166, 55}, {4111, 53}, + {4058, 52}, {4006, 51}, {3955, 49}, {3906, 48}, {3858, 48}, {3810, 45}, {3765, 45}, {3720, 44}, + {3676, 43}, {3633, 42}, {3591, 40}, {3551, 40}, {3511, 39}, {3472, 38}, {3434, 38}, {3396, 36}, + {3360, 36}, {3324, 35}, {3289, 34}, {3255, 34}, {3221, 33}, {3188, 32}, {3156, 31}, {3125, 31}, + {3094, 31}, {3063, 30}, {3033, 29}, {3004, 28}, {2976, 28}, {2948, 28}, {2920, 27}, {2893, 27}, + {2866, 26}, {2840, 25}, {2815, 25}, {2790, 25}, {2765, 24}, {2741, 24}, {2717, 24}, {2693, 23}, + {2670, 22}, {2648, 22}, {2626, 22}, {2604, 22}, {2582, 21}, {2561, 21}, {2540, 20}, {2520, 20}, + {2500, 20}, {2480, 20}, {2460, 19}, {2441, 19}, {2422, 19}, {2403, 18}, {2385, 18}, {2367, 18}, + {2349, 17}, {2332, 18}, {2314, 17}, {2297, 16}, {2281, 17}, {2264, 16}, {2248, 16}, {2232, 16}, + {2216, 16}, {2200, 15}, {2185, 15}, {2170, 15}, {2155, 15}, {2140, 15}, {2125, 14}, {2111, 14}, + {2097, 14}, {2083, 14}, {2069, 14}, {2055, 13}, {2042, 13}, {2029, 13}, {2016, 13}, {2003, 13}, + {1990, 13}, {1977, 12}, {1965, 12}, {1953, 13}, {1940, 11}, {1929, 12}, {1917, 12}, {1905, 12}, + {1893, 11}, {1882, 11}, {1871, 11}, {1860, 11}, {1849, 11}, {1838, 11}, {1827, 11}, {1816, 10}, + {1806, 11}, {1795, 10}, {1785, 10}, {1775, 10}, {1765, 10}, {1755, 10}, {1745, 9}, {1736, 10}, + {1726, 9}, {1717, 10}, {1707, 9}, {1698, 9}, {1689, 9}, {1680, 9}, {1671, 9}, {1662, 9}, + {1653, 9}, {1644, 8}, {1636, 9}, {1627, 8}, {1619, 9}, {1610, 8}, {1602, 8}, {1594, 8}, + {1586, 8}, {1578, 8}, {1570, 8}, {1562, 8}, {1554, 7}, {1547, 8}, {1539, 8}, {1531, 7}, + {1524, 8}, {1516, 7}, {1509, 7}, {1502, 7}, {1495, 7}, {1488, 7}, {1481, 7}, {1474, 7}, + {1467, 7}, {1460, 7}, {1453, 7}, {1446, 6}, {1440, 7}, {1433, 7}, {1426, 6}, {1420, 6}, + {1414, 7}, {1407, 6}, {1401, 6}, {1395, 7}, {1388, 6}, {1382, 6}, {1376, 6}, {1370, 6}, + {1364, 6}, {1358, 6}, {1352, 6}, {1346, 5}, {1341, 6}, {1335, 6}, {1329, 5}, {1324, 6}, + {1318, 5}, {1313, 6}, {1307, 5}, {1302, 6}, {1296, 5}, {1291, 5}, {1286, 6}, {1280, 5}, + {1275, 5}, {1270, 5}, {1265, 5}, {1260, 5}, {1255, 5}, {1250, 5}, {1245, 5}, {1240, 5}, + {1235, 5}, {1230, 5}, {1225, 5}, {1220, 5}, {1215, 4}, {1211, 5}, {1206, 5}, {1201, 5}, +}; + +#endif diff --git a/Firmware/speed_lookuptable.h b/Firmware/speed_lookuptable.h index b7c00f1a..6a1a44ef 100644 --- a/Firmware/speed_lookuptable.h +++ b/Firmware/speed_lookuptable.h @@ -3,150 +3,87 @@ #include "Marlin.h" -#if F_CPU == 16000000 +extern const uint16_t speed_lookuptable_fast[256][2] PROGMEM; +extern const uint16_t speed_lookuptable_slow[256][2] PROGMEM; -const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {\ -{ 62500, 55556}, { 6944, 3268}, { 3676, 1176}, { 2500, 607}, { 1893, 369}, { 1524, 249}, { 1275, 179}, { 1096, 135}, -{ 961, 105}, { 856, 85}, { 771, 69}, { 702, 58}, { 644, 49}, { 595, 42}, { 553, 37}, { 516, 32}, -{ 484, 28}, { 456, 25}, { 431, 23}, { 408, 20}, { 388, 19}, { 369, 16}, { 353, 16}, { 337, 14}, -{ 323, 13}, { 310, 11}, { 299, 11}, { 288, 11}, { 277, 9}, { 268, 9}, { 259, 8}, { 251, 8}, -{ 243, 8}, { 235, 7}, { 228, 6}, { 222, 6}, { 216, 6}, { 210, 6}, { 204, 5}, { 199, 5}, -{ 194, 5}, { 189, 4}, { 185, 4}, { 181, 4}, { 177, 4}, { 173, 4}, { 169, 4}, { 165, 3}, -{ 162, 3}, { 159, 4}, { 155, 3}, { 152, 3}, { 149, 2}, { 147, 3}, { 144, 3}, { 141, 2}, -{ 139, 3}, { 136, 2}, { 134, 2}, { 132, 3}, { 129, 2}, { 127, 2}, { 125, 2}, { 123, 2}, -{ 121, 2}, { 119, 1}, { 118, 2}, { 116, 2}, { 114, 1}, { 113, 2}, { 111, 2}, { 109, 1}, -{ 108, 2}, { 106, 1}, { 105, 2}, { 103, 1}, { 102, 1}, { 101, 1}, { 100, 2}, { 98, 1}, -{ 97, 1}, { 96, 1}, { 95, 2}, { 93, 1}, { 92, 1}, { 91, 1}, { 90, 1}, { 89, 1}, -{ 88, 1}, { 87, 1}, { 86, 1}, { 85, 1}, { 84, 1}, { 83, 0}, { 83, 1}, { 82, 1}, -{ 81, 1}, { 80, 1}, { 79, 1}, { 78, 0}, { 78, 1}, { 77, 1}, { 76, 1}, { 75, 0}, -{ 75, 1}, { 74, 1}, { 73, 1}, { 72, 0}, { 72, 1}, { 71, 1}, { 70, 0}, { 70, 1}, -{ 69, 0}, { 69, 1}, { 68, 1}, { 67, 0}, { 67, 1}, { 66, 0}, { 66, 1}, { 65, 0}, -{ 65, 1}, { 64, 1}, { 63, 0}, { 63, 1}, { 62, 0}, { 62, 1}, { 61, 0}, { 61, 1}, -{ 60, 0}, { 60, 0}, { 60, 1}, { 59, 0}, { 59, 1}, { 58, 0}, { 58, 1}, { 57, 0}, -{ 57, 1}, { 56, 0}, { 56, 0}, { 56, 1}, { 55, 0}, { 55, 1}, { 54, 0}, { 54, 0}, -{ 54, 1}, { 53, 0}, { 53, 0}, { 53, 1}, { 52, 0}, { 52, 0}, { 52, 1}, { 51, 0}, -{ 51, 0}, { 51, 1}, { 50, 0}, { 50, 0}, { 50, 1}, { 49, 0}, { 49, 0}, { 49, 1}, -{ 48, 0}, { 48, 0}, { 48, 1}, { 47, 0}, { 47, 0}, { 47, 0}, { 47, 1}, { 46, 0}, -{ 46, 0}, { 46, 1}, { 45, 0}, { 45, 0}, { 45, 0}, { 45, 1}, { 44, 0}, { 44, 0}, -{ 44, 0}, { 44, 1}, { 43, 0}, { 43, 0}, { 43, 0}, { 43, 1}, { 42, 0}, { 42, 0}, -{ 42, 0}, { 42, 1}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 1}, { 40, 0}, -{ 40, 0}, { 40, 0}, { 40, 0}, { 40, 1}, { 39, 0}, { 39, 0}, { 39, 0}, { 39, 0}, -{ 39, 1}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 1}, { 37, 0}, { 37, 0}, -{ 37, 0}, { 37, 0}, { 37, 0}, { 37, 1}, { 36, 0}, { 36, 0}, { 36, 0}, { 36, 0}, -{ 36, 1}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 1}, -{ 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 1}, { 33, 0}, { 33, 0}, -{ 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 1}, { 32, 0}, { 32, 0}, { 32, 0}, -{ 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 1}, { 31, 0}, { 31, 0}, { 31, 0}, -{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0} -}; +#ifndef _NO_ASM -const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {\ -{ 62500, 12500}, { 50000, 8334}, { 41666, 5952}, { 35714, 4464}, { 31250, 3473}, { 27777, 2777}, { 25000, 2273}, { 22727, 1894}, -{ 20833, 1603}, { 19230, 1373}, { 17857, 1191}, { 16666, 1041}, { 15625, 920}, { 14705, 817}, { 13888, 731}, { 13157, 657}, -{ 12500, 596}, { 11904, 541}, { 11363, 494}, { 10869, 453}, { 10416, 416}, { 10000, 385}, { 9615, 356}, { 9259, 331}, -{ 8928, 308}, { 8620, 287}, { 8333, 269}, { 8064, 252}, { 7812, 237}, { 7575, 223}, { 7352, 210}, { 7142, 198}, -{ 6944, 188}, { 6756, 178}, { 6578, 168}, { 6410, 160}, { 6250, 153}, { 6097, 145}, { 5952, 139}, { 5813, 132}, -{ 5681, 126}, { 5555, 121}, { 5434, 115}, { 5319, 111}, { 5208, 106}, { 5102, 102}, { 5000, 99}, { 4901, 94}, -{ 4807, 91}, { 4716, 87}, { 4629, 84}, { 4545, 81}, { 4464, 79}, { 4385, 75}, { 4310, 73}, { 4237, 71}, -{ 4166, 68}, { 4098, 66}, { 4032, 64}, { 3968, 62}, { 3906, 60}, { 3846, 59}, { 3787, 56}, { 3731, 55}, -{ 3676, 53}, { 3623, 52}, { 3571, 50}, { 3521, 49}, { 3472, 48}, { 3424, 46}, { 3378, 45}, { 3333, 44}, -{ 3289, 43}, { 3246, 41}, { 3205, 41}, { 3164, 39}, { 3125, 39}, { 3086, 38}, { 3048, 36}, { 3012, 36}, -{ 2976, 35}, { 2941, 35}, { 2906, 33}, { 2873, 33}, { 2840, 32}, { 2808, 31}, { 2777, 30}, { 2747, 30}, -{ 2717, 29}, { 2688, 29}, { 2659, 28}, { 2631, 27}, { 2604, 27}, { 2577, 26}, { 2551, 26}, { 2525, 25}, -{ 2500, 25}, { 2475, 25}, { 2450, 23}, { 2427, 24}, { 2403, 23}, { 2380, 22}, { 2358, 22}, { 2336, 22}, -{ 2314, 21}, { 2293, 21}, { 2272, 20}, { 2252, 20}, { 2232, 20}, { 2212, 20}, { 2192, 19}, { 2173, 18}, -{ 2155, 19}, { 2136, 18}, { 2118, 18}, { 2100, 17}, { 2083, 17}, { 2066, 17}, { 2049, 17}, { 2032, 16}, -{ 2016, 16}, { 2000, 16}, { 1984, 16}, { 1968, 15}, { 1953, 16}, { 1937, 14}, { 1923, 15}, { 1908, 15}, -{ 1893, 14}, { 1879, 14}, { 1865, 14}, { 1851, 13}, { 1838, 14}, { 1824, 13}, { 1811, 13}, { 1798, 13}, -{ 1785, 12}, { 1773, 13}, { 1760, 12}, { 1748, 12}, { 1736, 12}, { 1724, 12}, { 1712, 12}, { 1700, 11}, -{ 1689, 12}, { 1677, 11}, { 1666, 11}, { 1655, 11}, { 1644, 11}, { 1633, 10}, { 1623, 11}, { 1612, 10}, -{ 1602, 10}, { 1592, 10}, { 1582, 10}, { 1572, 10}, { 1562, 10}, { 1552, 9}, { 1543, 10}, { 1533, 9}, -{ 1524, 9}, { 1515, 9}, { 1506, 9}, { 1497, 9}, { 1488, 9}, { 1479, 9}, { 1470, 9}, { 1461, 8}, -{ 1453, 8}, { 1445, 9}, { 1436, 8}, { 1428, 8}, { 1420, 8}, { 1412, 8}, { 1404, 8}, { 1396, 8}, -{ 1388, 7}, { 1381, 8}, { 1373, 7}, { 1366, 8}, { 1358, 7}, { 1351, 7}, { 1344, 8}, { 1336, 7}, -{ 1329, 7}, { 1322, 7}, { 1315, 7}, { 1308, 6}, { 1302, 7}, { 1295, 7}, { 1288, 6}, { 1282, 7}, -{ 1275, 6}, { 1269, 7}, { 1262, 6}, { 1256, 6}, { 1250, 7}, { 1243, 6}, { 1237, 6}, { 1231, 6}, -{ 1225, 6}, { 1219, 6}, { 1213, 6}, { 1207, 6}, { 1201, 5}, { 1196, 6}, { 1190, 6}, { 1184, 5}, -{ 1179, 6}, { 1173, 5}, { 1168, 6}, { 1162, 5}, { 1157, 5}, { 1152, 6}, { 1146, 5}, { 1141, 5}, -{ 1136, 5}, { 1131, 5}, { 1126, 5}, { 1121, 5}, { 1116, 5}, { 1111, 5}, { 1106, 5}, { 1101, 5}, -{ 1096, 5}, { 1091, 5}, { 1086, 4}, { 1082, 5}, { 1077, 5}, { 1072, 4}, { 1068, 5}, { 1063, 4}, -{ 1059, 5}, { 1054, 4}, { 1050, 4}, { 1046, 5}, { 1041, 4}, { 1037, 4}, { 1033, 5}, { 1028, 4}, -{ 1024, 4}, { 1020, 4}, { 1016, 4}, { 1012, 4}, { 1008, 4}, { 1004, 4}, { 1000, 4}, { 996, 4}, -{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3} -}; +// intRes = intIn1 * intIn2 >> 16 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 24 bit result +#define MultiU16X8toH16(intRes, charIn1, intIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %A1, %A2 \n\t" \ +"add %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r0 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (charIn1), \ +"d" (intIn2) \ +: \ +"r26" \ +) -#elif F_CPU == 20000000 +// intRes = longIn1 * longIn2 >> 24 +// uses: +// r26 to store 0 +// r27 to store the byte 1 of the 48bit result +#define MultiU24X24toH16(intRes, longIn1, longIn2) \ +asm volatile ( \ +"clr r26 \n\t" \ +"mul %A1, %B2 \n\t" \ +"mov r27, r1 \n\t" \ +"mul %B1, %C2 \n\t" \ +"movw %A0, r0 \n\t" \ +"mul %C1, %C2 \n\t" \ +"add %B0, r0 \n\t" \ +"mul %C1, %B2 \n\t" \ +"add %A0, r0 \n\t" \ +"adc %B0, r1 \n\t" \ +"mul %A1, %C2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %B2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %C1, %A2 \n\t" \ +"add r27, r0 \n\t" \ +"adc %A0, r1 \n\t" \ +"adc %B0, r26 \n\t" \ +"mul %B1, %A2 \n\t" \ +"add r27, r1 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"lsr r27 \n\t" \ +"adc %A0, r26 \n\t" \ +"adc %B0, r26 \n\t" \ +"clr r1 \n\t" \ +: \ +"=&r" (intRes) \ +: \ +"d" (longIn1), \ +"d" (longIn2) \ +: \ +"r26" , "r27" \ +) -const uint16_t speed_lookuptable_fast[256][2] PROGMEM = { - {62500, 54055}, {8445, 3917}, {4528, 1434}, {3094, 745}, {2349, 456}, {1893, 307}, {1586, 222}, {1364, 167}, - {1197, 131}, {1066, 105}, {961, 86}, {875, 72}, {803, 61}, {742, 53}, {689, 45}, {644, 40}, - {604, 35}, {569, 32}, {537, 28}, {509, 25}, {484, 23}, {461, 21}, {440, 19}, {421, 17}, - {404, 16}, {388, 15}, {373, 14}, {359, 13}, {346, 12}, {334, 11}, {323, 10}, {313, 10}, - {303, 9}, {294, 9}, {285, 8}, {277, 7}, {270, 8}, {262, 7}, {255, 6}, {249, 6}, - {243, 6}, {237, 6}, {231, 5}, {226, 5}, {221, 5}, {216, 5}, {211, 4}, {207, 5}, - {202, 4}, {198, 4}, {194, 4}, {190, 3}, {187, 4}, {183, 3}, {180, 3}, {177, 4}, - {173, 3}, {170, 3}, {167, 2}, {165, 3}, {162, 3}, {159, 2}, {157, 3}, {154, 2}, - {152, 3}, {149, 2}, {147, 2}, {145, 2}, {143, 2}, {141, 2}, {139, 2}, {137, 2}, - {135, 2}, {133, 2}, {131, 2}, {129, 1}, {128, 2}, {126, 2}, {124, 1}, {123, 2}, - {121, 1}, {120, 2}, {118, 1}, {117, 1}, {116, 2}, {114, 1}, {113, 1}, {112, 2}, - {110, 1}, {109, 1}, {108, 1}, {107, 2}, {105, 1}, {104, 1}, {103, 1}, {102, 1}, - {101, 1}, {100, 1}, {99, 1}, {98, 1}, {97, 1}, {96, 1}, {95, 1}, {94, 1}, - {93, 1}, {92, 1}, {91, 0}, {91, 1}, {90, 1}, {89, 1}, {88, 1}, {87, 0}, - {87, 1}, {86, 1}, {85, 1}, {84, 0}, {84, 1}, {83, 1}, {82, 1}, {81, 0}, - {81, 1}, {80, 1}, {79, 0}, {79, 1}, {78, 0}, {78, 1}, {77, 1}, {76, 0}, - {76, 1}, {75, 0}, {75, 1}, {74, 1}, {73, 0}, {73, 1}, {72, 0}, {72, 1}, - {71, 0}, {71, 1}, {70, 0}, {70, 1}, {69, 0}, {69, 1}, {68, 0}, {68, 1}, - {67, 0}, {67, 1}, {66, 0}, {66, 1}, {65, 0}, {65, 0}, {65, 1}, {64, 0}, - {64, 1}, {63, 0}, {63, 1}, {62, 0}, {62, 0}, {62, 1}, {61, 0}, {61, 1}, - {60, 0}, {60, 0}, {60, 1}, {59, 0}, {59, 0}, {59, 1}, {58, 0}, {58, 0}, - {58, 1}, {57, 0}, {57, 0}, {57, 1}, {56, 0}, {56, 0}, {56, 1}, {55, 0}, - {55, 0}, {55, 1}, {54, 0}, {54, 0}, {54, 1}, {53, 0}, {53, 0}, {53, 0}, - {53, 1}, {52, 0}, {52, 0}, {52, 1}, {51, 0}, {51, 0}, {51, 0}, {51, 1}, - {50, 0}, {50, 0}, {50, 0}, {50, 1}, {49, 0}, {49, 0}, {49, 0}, {49, 1}, - {48, 0}, {48, 0}, {48, 0}, {48, 1}, {47, 0}, {47, 0}, {47, 0}, {47, 1}, - {46, 0}, {46, 0}, {46, 0}, {46, 0}, {46, 1}, {45, 0}, {45, 0}, {45, 0}, - {45, 1}, {44, 0}, {44, 0}, {44, 0}, {44, 0}, {44, 1}, {43, 0}, {43, 0}, - {43, 0}, {43, 0}, {43, 1}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, - {42, 1}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 1}, {40, 0}, - {40, 0}, {40, 0}, {40, 0}, {40, 1}, {39, 0}, {39, 0}, {39, 0}, {39, 0}, - {39, 0}, {39, 0}, {39, 1}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, -}; +#else //_NO_ASM -const uint16_t speed_lookuptable_slow[256][2] PROGMEM = { - {62500, 10417}, {52083, 7441}, {44642, 5580}, {39062, 4340}, {34722, 3472}, {31250, 2841}, {28409, 2368}, {26041, 2003}, - {24038, 1717}, {22321, 1488}, {20833, 1302}, {19531, 1149}, {18382, 1021}, {17361, 914}, {16447, 822}, {15625, 745}, - {14880, 676}, {14204, 618}, {13586, 566}, {13020, 520}, {12500, 481}, {12019, 445}, {11574, 414}, {11160, 385}, - {10775, 359}, {10416, 336}, {10080, 315}, {9765, 296}, {9469, 278}, {9191, 263}, {8928, 248}, {8680, 235}, - {8445, 222}, {8223, 211}, {8012, 200}, {7812, 191}, {7621, 181}, {7440, 173}, {7267, 165}, {7102, 158}, - {6944, 151}, {6793, 145}, {6648, 138}, {6510, 133}, {6377, 127}, {6250, 123}, {6127, 118}, {6009, 113}, - {5896, 109}, {5787, 106}, {5681, 101}, {5580, 98}, {5482, 95}, {5387, 91}, {5296, 88}, {5208, 86}, - {5122, 82}, {5040, 80}, {4960, 78}, {4882, 75}, {4807, 73}, {4734, 70}, {4664, 69}, {4595, 67}, - {4528, 64}, {4464, 63}, {4401, 61}, {4340, 60}, {4280, 58}, {4222, 56}, {4166, 55}, {4111, 53}, - {4058, 52}, {4006, 51}, {3955, 49}, {3906, 48}, {3858, 48}, {3810, 45}, {3765, 45}, {3720, 44}, - {3676, 43}, {3633, 42}, {3591, 40}, {3551, 40}, {3511, 39}, {3472, 38}, {3434, 38}, {3396, 36}, - {3360, 36}, {3324, 35}, {3289, 34}, {3255, 34}, {3221, 33}, {3188, 32}, {3156, 31}, {3125, 31}, - {3094, 31}, {3063, 30}, {3033, 29}, {3004, 28}, {2976, 28}, {2948, 28}, {2920, 27}, {2893, 27}, - {2866, 26}, {2840, 25}, {2815, 25}, {2790, 25}, {2765, 24}, {2741, 24}, {2717, 24}, {2693, 23}, - {2670, 22}, {2648, 22}, {2626, 22}, {2604, 22}, {2582, 21}, {2561, 21}, {2540, 20}, {2520, 20}, - {2500, 20}, {2480, 20}, {2460, 19}, {2441, 19}, {2422, 19}, {2403, 18}, {2385, 18}, {2367, 18}, - {2349, 17}, {2332, 18}, {2314, 17}, {2297, 16}, {2281, 17}, {2264, 16}, {2248, 16}, {2232, 16}, - {2216, 16}, {2200, 15}, {2185, 15}, {2170, 15}, {2155, 15}, {2140, 15}, {2125, 14}, {2111, 14}, - {2097, 14}, {2083, 14}, {2069, 14}, {2055, 13}, {2042, 13}, {2029, 13}, {2016, 13}, {2003, 13}, - {1990, 13}, {1977, 12}, {1965, 12}, {1953, 13}, {1940, 11}, {1929, 12}, {1917, 12}, {1905, 12}, - {1893, 11}, {1882, 11}, {1871, 11}, {1860, 11}, {1849, 11}, {1838, 11}, {1827, 11}, {1816, 10}, - {1806, 11}, {1795, 10}, {1785, 10}, {1775, 10}, {1765, 10}, {1755, 10}, {1745, 9}, {1736, 10}, - {1726, 9}, {1717, 10}, {1707, 9}, {1698, 9}, {1689, 9}, {1680, 9}, {1671, 9}, {1662, 9}, - {1653, 9}, {1644, 8}, {1636, 9}, {1627, 8}, {1619, 9}, {1610, 8}, {1602, 8}, {1594, 8}, - {1586, 8}, {1578, 8}, {1570, 8}, {1562, 8}, {1554, 7}, {1547, 8}, {1539, 8}, {1531, 7}, - {1524, 8}, {1516, 7}, {1509, 7}, {1502, 7}, {1495, 7}, {1488, 7}, {1481, 7}, {1474, 7}, - {1467, 7}, {1460, 7}, {1453, 7}, {1446, 6}, {1440, 7}, {1433, 7}, {1426, 6}, {1420, 6}, - {1414, 7}, {1407, 6}, {1401, 6}, {1395, 7}, {1388, 6}, {1382, 6}, {1376, 6}, {1370, 6}, - {1364, 6}, {1358, 6}, {1352, 6}, {1346, 5}, {1341, 6}, {1335, 6}, {1329, 5}, {1324, 6}, - {1318, 5}, {1313, 6}, {1307, 5}, {1302, 6}, {1296, 5}, {1291, 5}, {1286, 6}, {1280, 5}, - {1275, 5}, {1270, 5}, {1265, 5}, {1260, 5}, {1255, 5}, {1250, 5}, {1245, 5}, {1240, 5}, - {1235, 5}, {1230, 5}, {1225, 5}, {1220, 5}, {1215, 4}, {1211, 5}, {1206, 5}, {1201, 5}, -}; - -#endif +// NOTE: currently not implemented +void MultiU16X8toH16(unsigned short& intRes, unsigned char& charIn1, unsigned short& intIn2); +void MultiU24X24toH16(uint16_t& intRes, int32_t& longIn1, long& longIn2); + +#endif //_NO_ASM #endif diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 5a3d4010..ddf69c8c 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -146,92 +146,6 @@ extern uint16_t stepper_timer_overflow_last; //=============================functions ============================ //=========================================================================== -#ifndef _NO_ASM - -// intRes = intIn1 * intIn2 >> 16 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 24 bit result -#define MultiU16X8toH16(intRes, charIn1, intIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %A1, %A2 \n\t" \ -"add %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r0 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (charIn1), \ -"d" (intIn2) \ -: \ -"r26" \ -) - -// intRes = longIn1 * longIn2 >> 24 -// uses: -// r26 to store 0 -// r27 to store the byte 1 of the 48bit result -#define MultiU24X24toH16(intRes, longIn1, longIn2) \ -asm volatile ( \ -"clr r26 \n\t" \ -"mul %A1, %B2 \n\t" \ -"mov r27, r1 \n\t" \ -"mul %B1, %C2 \n\t" \ -"movw %A0, r0 \n\t" \ -"mul %C1, %C2 \n\t" \ -"add %B0, r0 \n\t" \ -"mul %C1, %B2 \n\t" \ -"add %A0, r0 \n\t" \ -"adc %B0, r1 \n\t" \ -"mul %A1, %C2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %B2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %C1, %A2 \n\t" \ -"add r27, r0 \n\t" \ -"adc %A0, r1 \n\t" \ -"adc %B0, r26 \n\t" \ -"mul %B1, %A2 \n\t" \ -"add r27, r1 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"lsr r27 \n\t" \ -"adc %A0, r26 \n\t" \ -"adc %B0, r26 \n\t" \ -"clr r1 \n\t" \ -: \ -"=&r" (intRes) \ -: \ -"d" (longIn1), \ -"d" (longIn2) \ -: \ -"r26" , "r27" \ -) - -#else //_NO_ASM - -void MultiU16X8toH16(unsigned short& intRes, unsigned char& charIn1, unsigned short& intIn2) -{ -} - -void MultiU24X24toH16(uint16_t& intRes, int32_t& longIn1, long& longIn2) -{ -} - -#endif //_NO_ASM - -// Some useful constants - void checkHitEndstops() { if( endstop_x_hit || endstop_y_hit || endstop_z_hit) { From 3b528196dd22db2237b6bd7e9699c8ea0f7c164d Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 18 May 2019 16:41:25 +0200 Subject: [PATCH 08/64] Fixup prefix echomagic for the LA config report --- Firmware/ConfigurationStore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index 8ed2dd70..0bd13a3a 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -165,8 +165,8 @@ void Config_PrintSettings(uint8_t level) #endif if (level >= 10) { #ifdef LIN_ADVANCE - printf_P(PSTR("%SLinear advance settings:\n M900 K%.2f\n"), - echomagic, extruder_advance_K); + printf_P(PSTR("%SLinear advance settings:%S M900 K%.2f\n"), + echomagic, echomagic, extruder_advance_K); #endif //LIN_ADVANCE } } From 2c8e04bd5f7ee847203afae796c6546996453e24 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 18 May 2019 18:03:20 +0200 Subject: [PATCH 09/64] Planner: use the correct block when updating LA factors --- Firmware/planner.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index f8ac2f59..af87f77e 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -402,10 +402,10 @@ void planner_recalculate(const float &safe_final_speed) // NOTE: Entry and exit factors always > 0 by all previous logic operations. calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed); #ifdef LIN_ADVANCE - if (current->use_advance_lead) { - const float comp = current->e_D_ratio * extruder_advance_K * cs.axis_steps_per_unit[E_AXIS]; - current->max_adv_steps = current->nominal_speed * comp; - current->final_adv_steps = next->entry_speed * comp; + if (prev->use_advance_lead) { + const float comp = prev->e_D_ratio * extruder_advance_K * cs.axis_steps_per_unit[E_AXIS]; + prev->max_adv_steps = prev->nominal_speed * comp; + prev->final_adv_steps = current->entry_speed * comp; } #endif // Reset current only to ensure next trapezoid is computed. From 9425b6b07a69b7d7c75e9e5488822b36709f3ed5 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 18 May 2019 20:10:20 +0200 Subject: [PATCH 10/64] Planner: do not recalculate max_adv_steps, since it doesn't change --- Firmware/planner.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index af87f77e..76b53fbb 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -404,7 +404,6 @@ void planner_recalculate(const float &safe_final_speed) #ifdef LIN_ADVANCE if (prev->use_advance_lead) { const float comp = prev->e_D_ratio * extruder_advance_K * cs.axis_steps_per_unit[E_AXIS]; - prev->max_adv_steps = prev->nominal_speed * comp; prev->final_adv_steps = current->entry_speed * comp; } #endif From 2d3fe3197c0344a88fd954f8f3e94a74f8d0af6b Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 18 May 2019 20:16:05 +0200 Subject: [PATCH 11/64] Move calc_timer into speed_lookup_table for planner reuse --- Firmware/speed_lookuptable.h | 36 +++++++++++++++++++++++++++++ Firmware/stepper.cpp | 45 ++++-------------------------------- 2 files changed, 40 insertions(+), 41 deletions(-) diff --git a/Firmware/speed_lookuptable.h b/Firmware/speed_lookuptable.h index 6a1a44ef..2748dd71 100644 --- a/Firmware/speed_lookuptable.h +++ b/Firmware/speed_lookuptable.h @@ -86,4 +86,40 @@ void MultiU24X24toH16(uint16_t& intRes, int32_t& longIn1, long& longIn2); #endif //_NO_ASM + +FORCE_INLINE unsigned short calc_timer(uint16_t step_rate, uint8_t& step_loops) { + unsigned short timer; + if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY; + + if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times + step_rate = (step_rate >> 2)&0x3fff; + step_loops = 4; + } + else if(step_rate > 10000) { // If steprate > 10kHz >> step 2 times + step_rate = (step_rate >> 1)&0x7fff; + step_loops = 2; + } + else { + step_loops = 1; + } + + if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000); + step_rate -= (F_CPU/500000); // Correct for minimal speed + if(step_rate >= (8*256)){ // higher step rate + unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; + unsigned char tmp_step_rate = (step_rate & 0x00ff); + unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); + MultiU16X8toH16(timer, tmp_step_rate, gain); + timer = (unsigned short)pgm_read_word_near(table_address) - timer; + } + else { // lower step rates + unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; + table_address += ((step_rate)>>1) & 0xfffc; + timer = (unsigned short)pgm_read_word_near(table_address); + timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); + } + if(timer < 100) { timer = 100; }//(20kHz this should never happen)////MSG_STEPPER_TOO_HIGH c=0 r=0 + return timer; +} + #endif diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index ddf69c8c..19cd5d81 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -233,43 +233,6 @@ void invert_z_endstop(bool endstop_invert) // step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset. // The slope of acceleration is calculated with the leib ramp alghorithm. -FORCE_INLINE unsigned short calc_timer(uint16_t step_rate) { - unsigned short timer; - if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY; - - if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times - step_rate = (step_rate >> 2)&0x3fff; - step_loops = 4; - } - else if(step_rate > 10000) { // If steprate > 10kHz >> step 2 times - step_rate = (step_rate >> 1)&0x7fff; - step_loops = 2; - } - else { - step_loops = 1; - } -// step_loops = 1; - - if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000); - step_rate -= (F_CPU/500000); // Correct for minimal speed - if(step_rate >= (8*256)){ // higher step rate - unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0]; - unsigned char tmp_step_rate = (step_rate & 0x00ff); - unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2); - MultiU16X8toH16(timer, tmp_step_rate, gain); - timer = (unsigned short)pgm_read_word_near(table_address) - timer; - } - else { // lower step rates - unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; - table_address += ((step_rate)>>1) & 0xfffc; - timer = (unsigned short)pgm_read_word_near(table_address); - timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); - } - if(timer < 100) { timer = 100; MYSERIAL.print(_N("Steprate too high: ")); MYSERIAL.println(step_rate); }//(20kHz this should never happen)////MSG_STEPPER_TOO_HIGH - return timer; -} - - // "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. // It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately. ISR(TIMER1_COMPA_vect) { @@ -382,7 +345,7 @@ FORCE_INLINE void stepper_next_block() // state is reached. step_loops_nominal = 0; acc_step_rate = uint16_t(current_block->initial_rate); - acceleration_time = calc_timer(acc_step_rate); + acceleration_time = calc_timer(acc_step_rate, step_loops); #ifdef LIN_ADVANCE if ((use_advance_lead = current_block->use_advance_lead)) { @@ -763,7 +726,7 @@ FORCE_INLINE void isr() { if(acc_step_rate > uint16_t(current_block->nominal_rate)) acc_step_rate = current_block->nominal_rate; // step_rate to timer interval - uint16_t timer = calc_timer(acc_step_rate); + uint16_t timer = calc_timer(acc_step_rate, step_loops); _NEXT_ISR(timer); acceleration_time += timer; #ifdef LIN_ADVANCE @@ -788,7 +751,7 @@ FORCE_INLINE void isr() { step_rate = uint16_t(current_block->final_rate); } // Step_rate to timer interval. - uint16_t timer = calc_timer(step_rate); + uint16_t timer = calc_timer(step_rate, step_loops); _NEXT_ISR(timer); deceleration_time += timer; #ifdef LIN_ADVANCE @@ -812,7 +775,7 @@ FORCE_INLINE void isr() { if (! step_loops_nominal) { // Calculation of the steady state timer rate has been delayed to the 1st tick of the steady state to lower // the initial interrupt blocking. - OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate)); + OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate), step_loops); step_loops_nominal = step_loops; } _NEXT_ISR(OCR1A_nominal); From a2fa8e5313f7f393b3dcd9381ea9bce37d99a893 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 18 May 2019 21:55:03 +0200 Subject: [PATCH 12/64] Rewrite the advance_isr scheduler --- Firmware/Configuration_adv.h | 2 - Firmware/planner.cpp | 53 ++++---- Firmware/planner.h | 3 +- Firmware/stepper.cpp | 230 +++++++++++++++++++++-------------- 4 files changed, 167 insertions(+), 121 deletions(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 45503302..d731e863 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -292,8 +292,6 @@ * Mention @Sebastianv650 on GitHub to alert the author of any issues. */ #define LIN_ADVANCE -#define LA_DEBUG -#define DEBUG_STEPPER_TIMER_MISSED #ifdef LIN_ADVANCE #define LIN_ADVANCE_K 0 // Unit: mm compression per 1mm/s extruder speed diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 76b53fbb..078abac4 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -58,6 +58,7 @@ #include "ultralcd.h" #include "language.h" #include "ConfigurationStore.h" +#include "speed_lookuptable.h" #ifdef MESH_BED_LEVELING #include "mesh_bed_leveling.h" @@ -1023,27 +1024,27 @@ Having the real displacement of the head, we can calculate the total movement le * delta_mm[E_AXIS] > 0 : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves) */ block->use_advance_lead = block->steps_e.wide - && extruder_advance_K - && delta_mm[E_AXIS] > 0; + && extruder_advance_K + && delta_mm[E_AXIS] > 0; if (block->use_advance_lead) { - block->e_D_ratio = (e - position_float[E_AXIS]) / - sqrt(sq(x - position_float[X_AXIS]) - + sq(y - position_float[Y_AXIS]) - + sq(z - position_float[Z_AXIS])); + block->e_D_ratio = (e - position_float[E_AXIS]) / + sqrt(sq(x - position_float[X_AXIS]) + + sq(y - position_float[Y_AXIS]) + + sq(z - position_float[Z_AXIS])); - // 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. - if (block->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 * block->e_D_ratio) * steps_per_mm; - if (block->acceleration_st > max_accel_steps_per_s2) { - block->acceleration_st = max_accel_steps_per_s2; - #ifdef LA_DEBUG - SERIAL_ECHOLNPGM("Acceleration limited."); - #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! + // 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.0) + block->use_advance_lead = false; + else { + const uint32_t max_accel_steps_per_s2 = cs.max_jerk[E_AXIS] / (extruder_advance_K * block->e_D_ratio) * steps_per_mm; + if (block->acceleration_st > max_accel_steps_per_s2) { + block->acceleration_st = max_accel_steps_per_s2; + #ifdef LA_DEBUG + SERIAL_ECHOLNPGM("Acceleration limited."); + #endif + } + } } #endif @@ -1081,13 +1082,13 @@ Having the real displacement of the head, we can calculate the total movement le #ifdef LIN_ADVANCE if (block->use_advance_lead) { - block->advance_speed = (F_CPU / 8.0) / (extruder_advance_K * block->e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]); - #ifdef LA_DEBUG - if (extruder_advance_K * block->e_D_ratio * block->acceleration * 2 < block->nominal_speed * block->e_D_ratio) - SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed."); - if (block->advance_speed < 200) - SERIAL_ECHOLNPGM("eISR running at > 10kHz."); - #endif + float advance_speed = (extruder_advance_K * block->e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]); + block->advance_rate = calc_timer(advance_speed, block->advance_step_loops); + + #ifdef LA_DEBUG + if (block->advance_step_loops > 2) + SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed."); + #endif } #endif diff --git a/Firmware/planner.h b/Firmware/planner.h index 41e4c61b..56e1c66c 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -113,9 +113,10 @@ typedef struct { #ifdef LIN_ADVANCE bool use_advance_lead; // Whether the current block uses LA - uint16_t advance_speed, // Step-rate for extruder speed + uint16_t advance_rate, // Step-rate for extruder speed max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!) final_adv_steps; // advance steps due to exit speed + uint8_t advance_step_loops; // Number of stepper ticks for each advance isr float e_D_ratio; #endif diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 19cd5d81..a98c8ff2 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -117,22 +117,24 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1}; void advance_isr(); static const uint16_t ADV_NEVER = 0xFFFF; - - static uint16_t nextMainISR = 0; - static uint16_t nextAdvanceISR = ADV_NEVER; - - static uint16_t eISR_Rate = ADV_NEVER; - static bool use_advance_lead; - static uint16_t current_adv_steps; + static uint16_t nextMainISR; + static uint16_t nextAdvanceISR; + + static uint16_t main_Rate; + static uint16_t eISR_Rate; + + static volatile uint16_t current_adv_steps; static uint16_t final_adv_steps; static uint16_t max_adv_steps; static uint32_t LA_decelerate_after; - static volatile int8_t e_steps; + static int8_t e_steps; + static uint8_t e_step_loops; + static int8_t LA_phase; - #define _NEXT_ISR(T) nextMainISR = T + #define _NEXT_ISR(T) main_Rate = nextMainISR = T #else #define _NEXT_ISR(T) OCR1A = T #endif @@ -352,6 +354,13 @@ FORCE_INLINE void stepper_next_block() 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; + LA_phase = -1; + } else { + nextAdvanceISR = ADV_NEVER; + eISR_Rate = ADV_NEVER; + e_step_loops = 1; + LA_phase = -1; } #endif @@ -731,15 +740,12 @@ FORCE_INLINE void isr() { acceleration_time += timer; #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - if (step_events_completed.wide == (unsigned long int)step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) { - nextAdvanceISR = 0; // Wake up eISR on first acceleration loop and fire ISR if final adv_rate is reached - eISR_Rate = current_block->advance_speed; + if (step_events_completed.wide <= (unsigned long int)step_loops) { + // First acceleration loop + eISR_Rate = current_block->advance_rate; + nextAdvanceISR = 0; } } - else { - eISR_Rate = ADV_NEVER; - if (e_steps) nextAdvanceISR = 0; - } #endif } else if (step_events_completed.wide > (unsigned long int)current_block->decelerate_after) { @@ -756,22 +762,15 @@ FORCE_INLINE void isr() { deceleration_time += timer; #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) { - nextAdvanceISR = 0; // Wake up eISR on first deceleration loop - eISR_Rate = current_block->advance_speed; + if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops) { + // First deceleration loop + eISR_Rate = current_block->advance_rate; + nextAdvanceISR = 0; } } - else { - eISR_Rate = ADV_NEVER; - if (e_steps) nextAdvanceISR = 0; - } #endif } else { -#ifdef LIN_ADVANCE - // If we have esteps to execute, fire the next advance_isr "now" - if (e_steps && eISR_Rate != current_block->advance_speed) nextAdvanceISR = 0; -#endif if (! step_loops_nominal) { // Calculation of the steady state timer rate has been delayed to the 1st tick of the steady state to lower // the initial interrupt blocking. @@ -813,76 +812,111 @@ FORCE_INLINE void isr() { // Timer interrupt for E. e_steps is set in the main routine. FORCE_INLINE void advance_isr() { - if (use_advance_lead) { - if (step_events_completed.wide > LA_decelerate_after && current_adv_steps > final_adv_steps) { - e_steps--; - current_adv_steps--; - nextAdvanceISR = eISR_Rate; + if (step_events_completed.wide > LA_decelerate_after && current_adv_steps > final_adv_steps) { + // decompression + e_steps -= e_step_loops; + current_adv_steps -= e_step_loops; + nextAdvanceISR = eISR_Rate; + if(nextAdvanceISR == ADV_NEVER) + { + LA_phase = 1; + e_step_loops = 1; } - else if (step_events_completed.wide < LA_decelerate_after && current_adv_steps < max_adv_steps) { - e_steps++; - current_adv_steps++; - nextAdvanceISR = eISR_Rate; - } - else { - nextAdvanceISR = ADV_NEVER; - eISR_Rate = ADV_NEVER; + else + { + if (step_loops == e_step_loops) + LA_phase = (eISR_Rate > main_Rate); + else + { + // avoid overflow through division (TODO: this can be + // improved as both step_loops and e_step_loops are + // guaranteed to be powers of two) + LA_phase = (eISR_Rate / step_loops > main_Rate / e_step_loops); + } } } - else + else if (step_events_completed.wide < LA_decelerate_after && current_adv_steps < max_adv_steps) { + // compression + e_steps += e_step_loops; + current_adv_steps += e_step_loops; + nextAdvanceISR = eISR_Rate; + LA_phase = -1; + if(nextAdvanceISR == ADV_NEVER) + e_step_loops = 1; + } + else { + // advance steps completed nextAdvanceISR = ADV_NEVER; - - if (e_steps) { - MSerial.checkRx(); // Check for serial chars. - - bool dir = -#ifdef SNMM - ((e_steps < 0) == (snmm_extruder & 1)) -#else - (e_steps < 0) -#endif - ? INVERT_E0_DIR : !INVERT_E0_DIR; //If we have SNMM, reverse every second extruder. - WRITE(E0_DIR_PIN, dir); - - if(e_steps < 0) e_steps = -e_steps; - fsensor_counter += e_steps; - while (e_steps) { - WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); - --e_steps; - WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); - } + eISR_Rate = ADV_NEVER; + LA_phase = -1; + e_step_loops = 1; } } FORCE_INLINE void advance_isr_scheduler() { - // Run main stepping ISR if flagged - if (!nextMainISR) isr(); - - // Run Advance stepping ISR if flagged - if (!nextAdvanceISR) advance_isr(); - - // Is the next advance ISR scheduled before the next main ISR? - if (nextAdvanceISR <= nextMainISR) { - // Set up the next interrupt - OCR1A = nextAdvanceISR; - // New interval for the next main ISR - if (nextMainISR) nextMainISR -= nextAdvanceISR; - // Will call Stepper::advance_isr on the next interrupt - nextAdvanceISR = 0; + // Integrate the final timer value, accounting for scheduling adjustments + if(nextAdvanceISR && nextAdvanceISR != ADV_NEVER) + { + if(nextAdvanceISR > OCR1A) + nextAdvanceISR -= OCR1A; + else + nextAdvanceISR = 0; } - else { - // The next main ISR comes first - OCR1A = nextMainISR; - // New interval for the next advance ISR, if any - if (nextAdvanceISR && nextAdvanceISR != ADV_NEVER) - nextAdvanceISR -= nextMainISR; - // Will call Stepper::isr on the next interrupt + if(nextMainISR > OCR1A) + nextMainISR -= OCR1A; + else nextMainISR = 0; + + // Run main stepping ISR if flagged + if (!nextMainISR) + { +#ifdef LA_DEBUG_LOGIC + WRITE_NC(LOGIC_ANALYZER_CH0, true); +#endif + isr(); +#ifdef LA_DEBUG_LOGIC + WRITE_NC(LOGIC_ANALYZER_CH0, false); +#endif } + + // Run the next advance isr if triggered now or soon enough + bool eisr = nextAdvanceISR < (TCNT1 + nextAdvanceISR / 8); + if (eisr) + { +#ifdef LA_DEBUG_LOGIC + WRITE_NC(LOGIC_ANALYZER_CH1, true); +#endif + advance_isr(); +#ifdef LA_DEBUG_LOGIC + WRITE_NC(LOGIC_ANALYZER_CH1, false); +#endif + } + + // Tick E steps if any + if (e_steps && (LA_phase < 0 || LA_phase == eisr)) { + uint8_t max_ticks = max(e_step_loops, step_loops); + max_ticks = min(abs(e_steps), max_ticks); +#ifdef FILAMENT_SENSOR + fsensor_counter += max_ticks; +#endif + WRITE(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); + while(max_ticks--) + { + WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); + e_steps += (e_steps < 0)? 1: -1; + WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); + } + } + + // Schedule the next closest tick, ignoring advance if scheduled to + // soon in order to avoid skewing the regular stepper acceleration + if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + nextAdvanceISR / 8) < nextMainISR) + OCR1A = nextAdvanceISR; + else + OCR1A = nextMainISR; } void clear_current_adv_vars() { - e_steps = 0; current_adv_steps = 0; } @@ -1106,15 +1140,28 @@ void st_init() // create_speed_lookuptable.py TCCR1B = (TCCR1B & ~(0x07< Date: Sun, 19 May 2019 14:23:37 +0200 Subject: [PATCH 13/64] Use a define instead of hard-coding a divider --- Firmware/stepper.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index a98c8ff2..8f0fef2a 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -853,6 +853,10 @@ FORCE_INLINE void advance_isr() { } } +#define LA_FREQ_MDIV 8 // divider for the advance frequency for maximum + // time allotted to merge regular and advance + // ticks (stick to a power-of-two) + FORCE_INLINE void advance_isr_scheduler() { // Integrate the final timer value, accounting for scheduling adjustments if(nextAdvanceISR && nextAdvanceISR != ADV_NEVER) @@ -880,7 +884,7 @@ FORCE_INLINE void advance_isr_scheduler() { } // Run the next advance isr if triggered now or soon enough - bool eisr = nextAdvanceISR < (TCNT1 + nextAdvanceISR / 8); + bool eisr = nextAdvanceISR < (TCNT1 + nextAdvanceISR / LA_FREQ_MDIV); if (eisr) { #ifdef LA_DEBUG_LOGIC @@ -910,7 +914,7 @@ FORCE_INLINE void advance_isr_scheduler() { // Schedule the next closest tick, ignoring advance if scheduled to // soon in order to avoid skewing the regular stepper acceleration - if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + nextAdvanceISR / 8) < nextMainISR) + if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + nextAdvanceISR / LA_FREQ_MDIV) < nextMainISR) OCR1A = nextAdvanceISR; else OCR1A = nextMainISR; From a1be8b6784f7363dbf5436c2d212942d7d363ce8 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 19 May 2019 14:26:23 +0200 Subject: [PATCH 14/64] Initialize current_adv_steps correctly Initialize at 0 both on startup and on reset on regular (non-LA) segments to avoid cumulating errors. --- Firmware/stepper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 8f0fef2a..9339b4bf 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -361,6 +361,7 @@ FORCE_INLINE void stepper_next_block() eISR_Rate = ADV_NEVER; e_step_loops = 1; LA_phase = -1; + current_adv_steps = 0; } #endif @@ -1165,6 +1166,7 @@ void st_init() e_steps = 0; e_step_loops = 1; LA_phase = -1; + current_adv_steps = 0; #endif enable_endstops(true); // Start with endstops active. After homing they can be disabled From 9586d71adbbaf4e459961b491216801f0c963397 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 19 May 2019 14:31:26 +0200 Subject: [PATCH 15/64] Mention LA_DEBUG_LOGIC --- Firmware/Configuration_adv.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index d731e863..e464b4de 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -294,8 +294,9 @@ #define LIN_ADVANCE #ifdef LIN_ADVANCE - #define LIN_ADVANCE_K 0 // Unit: mm compression per 1mm/s extruder speed - //#define LA_DEBUG // If enabled, this will generate debug information output over USB. + #define LIN_ADVANCE_K 0 // Unit: mm compression per 1mm/s extruder speed + //#define LA_DEBUG // If enabled, this will generate debug information output over USB. + //#define LA_DEBUG_LOGIC // @wavexx: setup logic channels for isr debugging #endif // Arc interpretation settings: From 942c38c18bbc28cf2f68dd1aafa3dc9cf3b62c9d Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 19 May 2019 14:34:03 +0200 Subject: [PATCH 16/64] Minor reformatting --- Firmware/planner.cpp | 18 ++++++++++-------- Firmware/planner.h | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 078abac4..0d0f3e36 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -1019,21 +1019,23 @@ Having the real displacement of the head, we can calculate the total movement le /** * Use LIN_ADVANCE for blocks 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) + * 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) */ - block->use_advance_lead = block->steps_e.wide - && extruder_advance_K - && delta_mm[E_AXIS] > 0; + block->use_advance_lead = block->steps_e.wide + && extruder_advance_K + && delta_mm[E_AXIS] > 0; if (block->use_advance_lead) { block->e_D_ratio = (e - position_float[E_AXIS]) / sqrt(sq(x - position_float[X_AXIS]) + sq(y - position_float[Y_AXIS]) + sq(z - position_float[Z_AXIS])); - // 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. + // 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. if (block->e_D_ratio > 3.0) block->use_advance_lead = false; else { diff --git a/Firmware/planner.h b/Firmware/planner.h index 56e1c66c..44c57ea5 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -110,10 +110,10 @@ typedef struct { // Pre-calculated division for the calculate_trapezoid_for_block() routine to run faster. float speed_factor; - + #ifdef LIN_ADVANCE bool use_advance_lead; // Whether the current block uses LA - uint16_t advance_rate, // Step-rate for extruder speed + uint16_t advance_rate, // Step-rate for extruder speed max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!) final_adv_steps; // advance steps due to exit speed uint8_t advance_step_loops; // Number of stepper ticks for each advance isr From c6dbcc494f6fff2915fcb1f29c451f4d41079a9b Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 19 May 2019 15:42:14 +0200 Subject: [PATCH 17/64] Typo --- Firmware/stepper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 9339b4bf..5fc0006b 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -913,7 +913,7 @@ FORCE_INLINE void advance_isr_scheduler() { } } - // Schedule the next closest tick, ignoring advance if scheduled to + // Schedule the next closest tick, ignoring advance if scheduled too // soon in order to avoid skewing the regular stepper acceleration if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + nextAdvanceISR / LA_FREQ_MDIV) < nextMainISR) OCR1A = nextAdvanceISR; From aae5cce28f177a65df8823ddf8d908723036b45d Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 19 May 2019 16:32:14 +0200 Subject: [PATCH 18/64] Use the nominal frequency to merge ticks --- Firmware/stepper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 5fc0006b..65f39c7d 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -885,7 +885,7 @@ FORCE_INLINE void advance_isr_scheduler() { } // Run the next advance isr if triggered now or soon enough - bool eisr = nextAdvanceISR < (TCNT1 + nextAdvanceISR / LA_FREQ_MDIV); + bool eisr = nextAdvanceISR < (TCNT1 + eISR_Rate / LA_FREQ_MDIV); if (eisr) { #ifdef LA_DEBUG_LOGIC @@ -915,7 +915,7 @@ FORCE_INLINE void advance_isr_scheduler() { // Schedule the next closest tick, ignoring advance if scheduled too // soon in order to avoid skewing the regular stepper acceleration - if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + nextAdvanceISR / LA_FREQ_MDIV) < nextMainISR) + if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + eISR_Rate / LA_FREQ_MDIV) < nextMainISR) OCR1A = nextAdvanceISR; else OCR1A = nextMainISR; From 53b77bab360349d88936785a934cee24bbb74108 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Tue, 21 May 2019 11:54:14 +0200 Subject: [PATCH 19/64] Do not operate on the prev block when already in use --- Firmware/planner.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 0d0f3e36..b9e693e7 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -400,14 +400,18 @@ void planner_recalculate(const float &safe_final_speed) } // Recalculate if current block entry or exit junction speed has changed. if ((prev->flag | current->flag) & BLOCK_FLAG_RECALCULATE) { - // NOTE: Entry and exit factors always > 0 by all previous logic operations. - calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed); - #ifdef LIN_ADVANCE - if (prev->use_advance_lead) { - const float comp = prev->e_D_ratio * extruder_advance_K * cs.axis_steps_per_unit[E_AXIS]; - prev->final_adv_steps = current->entry_speed * comp; + // @wavexx: FIXME: the following check is not really enough. calculate_trapezoid does block + // the isr to update the rates, but we don't. we should update atomically + if (!prev->busy) { + // NOTE: Entry and exit factors always > 0 by all previous logic operations. + calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed); + #ifdef LIN_ADVANCE + if (prev->use_advance_lead) { + const float comp = prev->e_D_ratio * extruder_advance_K * cs.axis_steps_per_unit[E_AXIS]; + prev->final_adv_steps = current->entry_speed * comp; + } + #endif } - #endif // Reset current only to ensure next trapezoid is computed. prev->flag &= ~BLOCK_FLAG_RECALCULATE; } From 294bf4068de454ed2c86f8096722621db51ee888 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Tue, 21 May 2019 21:28:31 +0200 Subject: [PATCH 20/64] Improve debug messages --- Firmware/planner.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index b9e693e7..466cd340 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -1047,7 +1047,7 @@ Having the real displacement of the head, we can calculate the total movement le if (block->acceleration_st > max_accel_steps_per_s2) { block->acceleration_st = max_accel_steps_per_s2; #ifdef LA_DEBUG - SERIAL_ECHOLNPGM("Acceleration limited."); + SERIAL_ECHOLNPGM("LA: Block acceleration limited due to max E-jerk"); #endif } } @@ -1093,7 +1093,11 @@ Having the real displacement of the head, we can calculate the total movement le #ifdef LA_DEBUG if (block->advance_step_loops > 2) - SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed."); + // @wavexx: we should really check for the difference between step_loops and + // advance_step_loops instead. A difference of more than 1 will lead + // to uneven speed and *should* be adjusted here by furthermore + // reducing the speed. + SERIAL_ECHOLNPGM("LA: More than 2 steps per eISR loop executed."); #endif } #endif From 282b5023932358fa4d5c49c746e7b4ddf830a882 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Tue, 21 May 2019 21:32:38 +0200 Subject: [PATCH 21/64] Improve the distribution of the advance steps --- Firmware/stepper.cpp | 117 ++++++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 46 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 65f39c7d..f0b39905 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -124,8 +124,9 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1}; static uint16_t main_Rate; static uint16_t eISR_Rate; + static uint16_t eISR_Err; - static volatile uint16_t current_adv_steps; + static uint16_t current_adv_steps; static uint16_t final_adv_steps; static uint16_t max_adv_steps; static uint32_t LA_decelerate_after; @@ -355,14 +356,13 @@ FORCE_INLINE void stepper_next_block() final_adv_steps = current_block->final_adv_steps; max_adv_steps = current_block->max_adv_steps; e_step_loops = current_block->advance_step_loops; - LA_phase = -1; } else { - nextAdvanceISR = ADV_NEVER; - eISR_Rate = ADV_NEVER; + e_steps = 0; e_step_loops = 1; - LA_phase = -1; current_adv_steps = 0; } + nextAdvanceISR = ADV_NEVER; + LA_phase = -1; #endif if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) { @@ -707,6 +707,39 @@ FORCE_INLINE void stepper_tick_highres() } } + +#ifdef LIN_ADVANCE +FORCE_INLINE void advance_spread(uint16_t timer) +{ + if(eISR_Err > timer) + { + // advance-step skipped + eISR_Err -= timer; + eISR_Rate = timer; + nextAdvanceISR = timer; + return; + } + + // at least one step + uint8_t ticks = 1; + uint32_t block = current_block->advance_rate; + uint16_t max_t = timer - eISR_Err; + while (block < max_t) + { + ++ticks; + block += current_block->advance_rate; + } + if (block > timer) + eISR_Err += block - timer; + else + eISR_Err -= timer - block; + + eISR_Rate = timer / ticks; + nextAdvanceISR = eISR_Rate / 2; +} +#endif + + FORCE_INLINE void isr() { //WRITE_NC(LOGIC_ANALYZER_CH0, true); @@ -741,11 +774,10 @@ FORCE_INLINE void isr() { acceleration_time += timer; #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - if (step_events_completed.wide <= (unsigned long int)step_loops) { - // First acceleration loop - eISR_Rate = current_block->advance_rate; - nextAdvanceISR = 0; - } + bool first = (step_events_completed.wide <= (unsigned long int)step_loops); + if (first) eISR_Err = current_block->advance_rate / 2; + if (first || nextAdvanceISR != ADV_NEVER) + advance_spread(timer); } #endif } @@ -763,10 +795,20 @@ FORCE_INLINE void isr() { deceleration_time += timer; #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops) { - // First deceleration loop - eISR_Rate = current_block->advance_rate; - nextAdvanceISR = 0; + bool first = (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops); + if (first) eISR_Err = current_block->advance_rate / 2; + if (first || nextAdvanceISR != ADV_NEVER) + { + advance_spread(timer); + if (step_loops == e_step_loops) + LA_phase = (eISR_Rate > main_Rate); + else + { + // avoid overflow through division (TODO: this can be + // improved as both step_loops and e_step_loops are + // currently guaranteed to be powers of two) + LA_phase = (eISR_Rate / step_loops > main_Rate / e_step_loops); + } } } #endif @@ -779,6 +821,11 @@ FORCE_INLINE void isr() { step_loops_nominal = step_loops; } _NEXT_ISR(OCR1A_nominal); +#ifdef LIN_ADVANCE + if (current_block->use_advance_lead && nextAdvanceISR != ADV_NEVER) { + advance_spread(OCR1A_nominal); + } +#endif } //WRITE_NC(LOGIC_ANALYZER_CH1, false); } @@ -816,48 +863,26 @@ FORCE_INLINE void advance_isr() { if (step_events_completed.wide > LA_decelerate_after && current_adv_steps > final_adv_steps) { // decompression e_steps -= e_step_loops; - current_adv_steps -= e_step_loops; - nextAdvanceISR = eISR_Rate; - if(nextAdvanceISR == ADV_NEVER) - { - LA_phase = 1; - e_step_loops = 1; - } + if(current_adv_steps > e_step_loops) + current_adv_steps -= e_step_loops; else - { - if (step_loops == e_step_loops) - LA_phase = (eISR_Rate > main_Rate); - else - { - // avoid overflow through division (TODO: this can be - // improved as both step_loops and e_step_loops are - // guaranteed to be powers of two) - LA_phase = (eISR_Rate / step_loops > main_Rate / e_step_loops); - } - } + current_adv_steps = 0; + nextAdvanceISR = eISR_Rate; } else if (step_events_completed.wide < LA_decelerate_after && current_adv_steps < max_adv_steps) { // compression e_steps += e_step_loops; current_adv_steps += e_step_loops; nextAdvanceISR = eISR_Rate; - LA_phase = -1; - if(nextAdvanceISR == ADV_NEVER) - e_step_loops = 1; } else { // advance steps completed nextAdvanceISR = ADV_NEVER; - eISR_Rate = ADV_NEVER; LA_phase = -1; e_step_loops = 1; } } -#define LA_FREQ_MDIV 8 // divider for the advance frequency for maximum - // time allotted to merge regular and advance - // ticks (stick to a power-of-two) - FORCE_INLINE void advance_isr_scheduler() { // Integrate the final timer value, accounting for scheduling adjustments if(nextAdvanceISR && nextAdvanceISR != ADV_NEVER) @@ -884,8 +909,8 @@ FORCE_INLINE void advance_isr_scheduler() { #endif } - // Run the next advance isr if triggered now or soon enough - bool eisr = nextAdvanceISR < (TCNT1 + eISR_Rate / LA_FREQ_MDIV); + // Run the next advance isr if triggered + bool eisr = !nextAdvanceISR; if (eisr) { #ifdef LA_DEBUG_LOGIC @@ -899,23 +924,24 @@ FORCE_INLINE void advance_isr_scheduler() { // Tick E steps if any if (e_steps && (LA_phase < 0 || LA_phase == eisr)) { - uint8_t max_ticks = max(e_step_loops, step_loops); + uint8_t max_ticks = (eisr? e_step_loops: step_loops); max_ticks = min(abs(e_steps), max_ticks); #ifdef FILAMENT_SENSOR fsensor_counter += max_ticks; #endif WRITE(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); - while(max_ticks--) + do { WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); e_steps += (e_steps < 0)? 1: -1; WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); } + while(--max_ticks); } // Schedule the next closest tick, ignoring advance if scheduled too // soon in order to avoid skewing the regular stepper acceleration - if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + eISR_Rate / LA_FREQ_MDIV) < nextMainISR) + if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + 40) < nextMainISR) OCR1A = nextAdvanceISR; else OCR1A = nextMainISR; @@ -1162,7 +1188,6 @@ void st_init() nextMainISR = 0; nextAdvanceISR = ADV_NEVER; main_Rate = ADV_NEVER; - eISR_Rate = ADV_NEVER; e_steps = 0; e_step_loops = 1; LA_phase = -1; From 0a26de1e7f2aeb544273ef48969140bff32cb4d2 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 25 May 2019 17:49:18 +0200 Subject: [PATCH 22/64] Allow to live-tune K during a print --- Firmware/menu.cpp | 4 +-- Firmware/menu.h | 3 +++ Firmware/ultralcd.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/Firmware/menu.cpp b/Firmware/menu.cpp index 847e63c8..42bfd0d9 100755 --- a/Firmware/menu.cpp +++ b/Firmware/menu.cpp @@ -96,7 +96,7 @@ void menu_back(void) menu_back(1); } -static void menu_back_no_reset(void) +void menu_back_no_reset(void) { if (menu_depth > 0) { @@ -130,7 +130,7 @@ void menu_submenu(menu_func_t submenu) } } -static void menu_submenu_no_reset(menu_func_t submenu) +void menu_submenu_no_reset(menu_func_t submenu) { if (menu_depth < MENU_DEPTH_MAX) { diff --git a/Firmware/menu.h b/Firmware/menu.h index 9800550b..a129dfc8 100755 --- a/Firmware/menu.h +++ b/Firmware/menu.h @@ -54,6 +54,7 @@ void menu_start(void); extern void menu_end(void); extern void menu_back(void); +extern void menu_back_no_reset(void); extern void menu_back(uint8_t nLevel); extern void menu_back_if_clicked(void); @@ -61,6 +62,7 @@ extern void menu_back_if_clicked(void); extern void menu_back_if_clicked_fb(void); extern void menu_submenu(menu_func_t submenu); +extern void menu_submenu_no_reset(menu_func_t submenu); extern uint8_t menu_item_ret(void); @@ -98,6 +100,7 @@ extern const char menu_fmt_int3[]; extern const char menu_fmt_float31[]; extern const char menu_fmt_float13[]; +extern const char menu_fmt_float13off[]; extern void menu_draw_float31(const char* str, float val); diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 97304adb..8036c3a8 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -6606,6 +6606,60 @@ static void lcd_colorprint_change() { lcd_draw_update = 3; } + +#ifdef LIN_ADVANCE +// @wavexx: looks like there's no generic float editing function in menu.cpp so we +// redefine our custom handling functions to mimick other tunables +#define MSG_ADVANCE_K PSTR("Advance K:") + +static void lcd_advance_draw_K(char chr, float val) +{ + if (val <= 0) + lcd_printf_P(menu_fmt_float13off, chr, MSG_ADVANCE_K, " [off]"); + else + lcd_printf_P(menu_fmt_float13, chr, MSG_ADVANCE_K, val); +} + +static void lcd_advance_edit_K(void) +{ + if (lcd_draw_update) + { + if (lcd_encoder < 0) lcd_encoder = 0; + if (lcd_encoder > 999) lcd_encoder = 999; + lcd_set_cursor(0, 1); + lcd_advance_draw_K(' ', 0.01 * lcd_encoder); + } + if (LCD_CLICKED) + { + extruder_advance_K = 0.01 * lcd_encoder; + menu_back_no_reset(); + } +} + +static uint8_t lcd_advance_K() +{ + if (menu_item == menu_line) + { + if (lcd_draw_update) + { + lcd_set_cursor(0, menu_row); + lcd_advance_draw_K((lcd_encoder == menu_item)?'>':' ', extruder_advance_K); + } + if (menu_clicked && (lcd_encoder == menu_item)) + { + menu_submenu_no_reset(lcd_advance_edit_K); + lcd_encoder = 100. * extruder_advance_K; + return menu_item_ret(); + } + } + menu_item++; + return 0; +} + +#define MENU_ITEM_EDIT_advance_K() do { if (lcd_advance_K()) return; } while (0) +#endif + + static void lcd_tune_menu() { typedef struct @@ -6644,8 +6698,11 @@ static void lcd_tune_menu() MENU_ITEM_EDIT_int3_P(_T(MSG_FAN_SPEED), &fanSpeed, 0, 255);//5 MENU_ITEM_EDIT_int3_P(_i("Flow"), &extrudemultiply, 10, 999);//6////MSG_FLOW +#ifdef LIN_ADVANCE + MENU_ITEM_EDIT_advance_K();//7 +#endif #ifdef FILAMENTCHANGEENABLE - MENU_ITEM_FUNCTION_P(_T(MSG_FILAMENTCHANGE), lcd_colorprint_change);//7 + MENU_ITEM_FUNCTION_P(_T(MSG_FILAMENTCHANGE), lcd_colorprint_change);//8 #endif #ifdef FILAMENT_SENSOR From fa7ecfc38e534c5623068b3d7eed76e8fee91af9 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 25 May 2019 18:39:50 +0200 Subject: [PATCH 23/64] Check for serial roughtly in the middle of the stepper isr --- Firmware/stepper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index f0b39905..37898f9c 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -830,6 +830,12 @@ FORCE_INLINE void isr() { //WRITE_NC(LOGIC_ANALYZER_CH1, false); } +#ifdef LIN_ADVANCE + // Check for serial chars. This executes roughtly between 50-60% of the total length of the isr, + // making this spot a much better choice than checking during esteps + MSerial.checkRx(); +#endif + // If current block is finished, reset pointer if (step_events_completed.wide >= current_block->step_event_count.wide) { #ifdef FILAMENT_SENSOR From 935a7982369da88b56d6d6b10453559f9448c46b Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 25 May 2019 21:38:59 +0200 Subject: [PATCH 24/64] Speedup advance_spread for common divisors --- Firmware/stepper.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 37898f9c..b3e6427a 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -734,7 +734,14 @@ FORCE_INLINE void advance_spread(uint16_t timer) else eISR_Err -= timer - block; - eISR_Rate = timer / ticks; + if (ticks == 1) + eISR_Rate = timer; + else if (ticks == 2) + eISR_Rate = timer / 2; + else if (ticks == 4) + eISR_Rate = timer / 4; + else + eISR_Rate = timer / ticks; nextAdvanceISR = eISR_Rate / 2; } #endif @@ -822,9 +829,8 @@ FORCE_INLINE void isr() { } _NEXT_ISR(OCR1A_nominal); #ifdef LIN_ADVANCE - if (current_block->use_advance_lead && nextAdvanceISR != ADV_NEVER) { + if (current_block->use_advance_lead && nextAdvanceISR != ADV_NEVER) advance_spread(OCR1A_nominal); - } #endif } //WRITE_NC(LOGIC_ANALYZER_CH1, false); From aae03ad83eac79afb49e6e3899abc4e00fade6e5 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 25 May 2019 21:49:43 +0200 Subject: [PATCH 25/64] Correctly handle direction for the filament sensor --- Firmware/stepper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index b3e6427a..ffbfed19 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -939,7 +939,7 @@ FORCE_INLINE void advance_isr_scheduler() { uint8_t max_ticks = (eisr? e_step_loops: step_loops); max_ticks = min(abs(e_steps), max_ticks); #ifdef FILAMENT_SENSOR - fsensor_counter += max_ticks; + fsensor_counter += (e_steps < 0? -max_ticks: max_ticks); #endif WRITE(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); do From bddc3e84ab5ee72a00af426e4ef055b0d60ab4db Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 25 May 2019 21:50:53 +0200 Subject: [PATCH 26/64] Use WRITE_NC directly in the isr --- Firmware/stepper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index ffbfed19..4a34105e 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -941,7 +941,7 @@ FORCE_INLINE void advance_isr_scheduler() { #ifdef FILAMENT_SENSOR fsensor_counter += (e_steps < 0? -max_ticks: max_ticks); #endif - WRITE(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); + WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); do { WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); From 6f6cef65b5c254b17565e029fb6925ff2b6fefee Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 15:35:13 +0200 Subject: [PATCH 27/64] Revert "Correctly handle direction for the filament sensor" This reverts commit aae03ad83eac79afb49e6e3899abc4e00fade6e5. --- Firmware/stepper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 4a34105e..e45e5eaf 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -939,7 +939,7 @@ FORCE_INLINE void advance_isr_scheduler() { uint8_t max_ticks = (eisr? e_step_loops: step_loops); max_ticks = min(abs(e_steps), max_ticks); #ifdef FILAMENT_SENSOR - fsensor_counter += (e_steps < 0? -max_ticks: max_ticks); + fsensor_counter += max_ticks; #endif WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); do From daa8007de5903c43100971cd1bcce26cbd5c007c Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 16:30:59 +0200 Subject: [PATCH 28/64] Allow to exclude Live K from the build --- Firmware/Configuration_adv.h | 1 + Firmware/ultralcd.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index e464b4de..f739cde2 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -295,6 +295,7 @@ #ifdef LIN_ADVANCE #define LIN_ADVANCE_K 0 // Unit: mm compression per 1mm/s extruder speed + #define LA_LIVE_K // Allow adjusting K in the Tune menu //#define LA_DEBUG // If enabled, this will generate debug information output over USB. //#define LA_DEBUG_LOGIC // @wavexx: setup logic channels for isr debugging #endif diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 8036c3a8..dd1da720 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -6607,7 +6607,7 @@ static void lcd_colorprint_change() { } -#ifdef LIN_ADVANCE +#ifdef LA_LIVE_K // @wavexx: looks like there's no generic float editing function in menu.cpp so we // redefine our custom handling functions to mimick other tunables #define MSG_ADVANCE_K PSTR("Advance K:") @@ -6698,7 +6698,7 @@ static void lcd_tune_menu() MENU_ITEM_EDIT_int3_P(_T(MSG_FAN_SPEED), &fanSpeed, 0, 255);//5 MENU_ITEM_EDIT_int3_P(_i("Flow"), &extrudemultiply, 10, 999);//6////MSG_FLOW -#ifdef LIN_ADVANCE +#ifdef LA_LIVE_K MENU_ITEM_EDIT_advance_K();//7 #endif #ifdef FILAMENTCHANGEENABLE From a28fb65bb21e1cb65a42934dd974cb666de000fa Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 14:58:57 +0200 Subject: [PATCH 29/64] Optimize advance_spread further --- Firmware/stepper.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index e45e5eaf..63ded9d5 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -709,6 +709,14 @@ FORCE_INLINE void stepper_tick_highres() #ifdef LIN_ADVANCE +// @wavexx: fast uint16_t division for small dividends<5 +// q/3 based on "Hacker's delight" formula +FORCE_INLINE uint16_t fastdiv(uint16_t q, uint8_t d) +{ + if(d != 3) return q >> (d / 2); + else return ((uint32_t)0xAAAB * q) >> 17; +} + FORCE_INLINE void advance_spread(uint16_t timer) { if(eISR_Err > timer) @@ -734,14 +742,14 @@ FORCE_INLINE void advance_spread(uint16_t timer) else eISR_Err -= timer - block; - if (ticks == 1) - eISR_Rate = timer; - else if (ticks == 2) - eISR_Rate = timer / 2; - else if (ticks == 4) - eISR_Rate = timer / 4; + if (ticks <= 4) + eISR_Rate = fastdiv(timer, ticks); else + { + // >4 ticks are still possible on slow moves eISR_Rate = timer / ticks; + } + nextAdvanceISR = eISR_Rate / 2; } #endif @@ -811,10 +819,9 @@ FORCE_INLINE void isr() { LA_phase = (eISR_Rate > main_Rate); else { - // avoid overflow through division (TODO: this can be - // improved as both step_loops and e_step_loops are - // currently guaranteed to be powers of two) - LA_phase = (eISR_Rate / step_loops > main_Rate / e_step_loops); + // avoid overflow through division. warning: we need to _guarantee_ step_loops + // and e_step_loops are <= 4 due to fastdiv's limit + LA_phase = (fastdiv(eISR_Rate, step_loops) > fastdiv(main_Rate, e_step_loops)); } } } From 20694aeabc8d23a1680f6c22f7819f54abd948ac Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 15:34:05 +0200 Subject: [PATCH 30/64] Save 316 bytes by avoiding advance_spread copies --- Firmware/stepper.cpp | 51 ++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 63ded9d5..372f16f0 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -116,7 +116,10 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1}; void advance_isr_scheduler(); void advance_isr(); - static const uint16_t ADV_NEVER = 0xFFFF; + static const uint16_t ADV_NEVER = 0xFFFF; + static const uint8_t ADV_INIT = 0b01; + static const uint8_t ADV_DECELERATE = 0b10; + static bool use_advance_lead; static uint16_t nextMainISR; @@ -771,6 +774,11 @@ FORCE_INLINE void isr() { else stepper_tick_highres(); + +#ifdef LIN_ADVANCE + uint8_t la_state = 0; +#endif + // Calculare new timer value // 13.38-14.63us for steady state, // 25.12us for acceleration / deceleration. @@ -789,10 +797,8 @@ FORCE_INLINE void isr() { acceleration_time += timer; #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - bool first = (step_events_completed.wide <= (unsigned long int)step_loops); - if (first) eISR_Err = current_block->advance_rate / 2; - if (first || nextAdvanceISR != ADV_NEVER) - advance_spread(timer); + if (step_events_completed.wide <= (unsigned long int)step_loops) + la_state = ADV_INIT; } #endif } @@ -810,20 +816,8 @@ FORCE_INLINE void isr() { deceleration_time += timer; #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - bool first = (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops); - if (first) eISR_Err = current_block->advance_rate / 2; - if (first || nextAdvanceISR != ADV_NEVER) - { - advance_spread(timer); - if (step_loops == e_step_loops) - LA_phase = (eISR_Rate > main_Rate); - else - { - // avoid overflow through division. warning: we need to _guarantee_ step_loops - // and e_step_loops are <= 4 due to fastdiv's limit - LA_phase = (fastdiv(eISR_Rate, step_loops) > fastdiv(main_Rate, e_step_loops)); - } - } + if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops) + la_state = ADV_INIT | ADV_DECELERATE; } #endif } @@ -835,15 +829,26 @@ FORCE_INLINE void isr() { step_loops_nominal = step_loops; } _NEXT_ISR(OCR1A_nominal); -#ifdef LIN_ADVANCE - if (current_block->use_advance_lead && nextAdvanceISR != ADV_NEVER) - advance_spread(OCR1A_nominal); -#endif } //WRITE_NC(LOGIC_ANALYZER_CH1, false); } #ifdef LIN_ADVANCE + // avoid multiple instances or function calls to advance_spread + if (la_state & ADV_INIT) eISR_Rate = current_block->advance_rate; + if (la_state & ADV_INIT || nextAdvanceISR != ADV_NEVER) { + advance_spread(main_Rate); + if (la_state & ADV_DECELERATE) { + if (step_loops == e_step_loops) + LA_phase = (eISR_Rate > main_Rate); + else { + // avoid overflow through division. warning: we need to _guarantee_ step_loops + // and e_step_loops are <= 4 due to fastdiv's limit + LA_phase = (fastdiv(eISR_Rate, step_loops) > fastdiv(main_Rate, e_step_loops)); + } + } + } + // Check for serial chars. This executes roughtly between 50-60% of the total length of the isr, // making this spot a much better choice than checking during esteps MSerial.checkRx(); From ab478ec2810700689698cad48b9f343792f263aa Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 16:05:41 +0200 Subject: [PATCH 31/64] Save another 144b by avoiding a calc_timer copy --- Firmware/planner.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 466cd340..ddf94cb8 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -1088,8 +1088,17 @@ Having the real displacement of the head, we can calculate the total movement le #ifdef LIN_ADVANCE if (block->use_advance_lead) { + // 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 * block->e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]); - block->advance_rate = calc_timer(advance_speed, block->advance_step_loops); + if (advance_speed > MAX_STEP_FREQUENCY) advance_speed = MAX_STEP_FREQUENCY; + block->advance_rate = (F_CPU / 8.0) / advance_speed; + if (block->advance_rate > 20000) + block->advance_step_loops = 4; + else if (block->advance_rate > 10000) + block->advance_step_loops = 2; + else + block->advance_step_loops = 1; #ifdef LA_DEBUG if (block->advance_step_loops > 2) From 3abb2188dff6c781e93ac6bb7ff78312fc65024d Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 16:58:57 +0200 Subject: [PATCH 32/64] Fixup initial error by defect --- Firmware/stepper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 372f16f0..6eaa9003 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -835,7 +835,7 @@ FORCE_INLINE void isr() { #ifdef LIN_ADVANCE // avoid multiple instances or function calls to advance_spread - if (la_state & ADV_INIT) eISR_Rate = current_block->advance_rate; + if (la_state & ADV_INIT) eISR_Rate = current_block->advance_rate / 2; if (la_state & ADV_INIT || nextAdvanceISR != ADV_NEVER) { advance_spread(main_Rate); if (la_state & ADV_DECELERATE) { From 9d834925c03f82994cb1c93471966eca536c8d01 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 17:05:47 +0200 Subject: [PATCH 33/64] Recalculate LA_phase correctly --- Firmware/stepper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 6eaa9003..ed265da6 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -816,8 +816,9 @@ FORCE_INLINE void isr() { 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 | ADV_DECELERATE; + la_state |= ADV_INIT; } #endif } From 823f7b069c6e047291990b458b1e8a1663809f87 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 19:56:31 +0200 Subject: [PATCH 34/64] Fix filament sensor direction again --- Firmware/stepper.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index ed265da6..d0b1d312 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -951,14 +951,18 @@ FORCE_INLINE void advance_isr_scheduler() { if (e_steps && (LA_phase < 0 || LA_phase == eisr)) { uint8_t max_ticks = (eisr? e_step_loops: step_loops); max_ticks = min(abs(e_steps), max_ticks); + bool rev = (e_steps < 0); #ifdef FILAMENT_SENSOR - fsensor_counter += max_ticks; + if (count_direction[E_AXIS] == 1) + fsensor_counter += (rev? -max_ticks: max_ticks); + else + fsensor_counter -= (rev? -max_ticks: max_ticks); #endif - WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); + WRITE_NC(E0_DIR_PIN, rev? INVERT_E0_DIR: !INVERT_E0_DIR); do { WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); - e_steps += (e_steps < 0)? 1: -1; + e_steps += (rev? 1: -1); WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); } while(--max_ticks); From 47d2562510c7dd7c3bb9a0b86ee779040558b0a8 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 17:14:06 +0200 Subject: [PATCH 35/64] Typos --- Firmware/Configuration_adv.h | 2 +- Firmware/stepper.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index f739cde2..9225ec25 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -281,7 +281,7 @@ * Assumption: advance [steps] = k * (delta velocity [steps/s]) * K=0 means advance disabled. * - * NOTE: K values for LIN_ADVANCE 1.5 differ from earlier versions! + * NOTE: K values for LIN_ADVANCE 1.5 differs from earlier versions! * * Set K around 0.22 for 3mm PLA Direct Drive with ~6.5cm between the drive gear and heatbreak. * Larger K values will be needed for flexible filament and greater distances. diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index d0b1d312..fda9f11c 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -779,7 +779,7 @@ FORCE_INLINE void isr() { uint8_t la_state = 0; #endif - // Calculare new timer value + // Calculate new timer value // 13.38-14.63us for steady state, // 25.12us for acceleration / deceleration. { @@ -850,8 +850,8 @@ FORCE_INLINE void isr() { } } - // Check for serial chars. This executes roughtly between 50-60% of the total length of the isr, - // making this spot a much better choice than checking during esteps + // Check for serial chars. This executes roughtly inbetween 50-60% of the total runtime of the + // entire isr, making this spot a much better choice than checking during esteps MSerial.checkRx(); #endif From 4772532524327bf92f398b1113c82c3c0b42a462 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 22:14:31 +0200 Subject: [PATCH 36/64] Allow Live-K to be used on stock 3.7.1 using a stub --- Firmware/ultralcd.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index dd1da720..ceccfbe5 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -6612,6 +6612,18 @@ static void lcd_colorprint_change() { // redefine our custom handling functions to mimick other tunables #define MSG_ADVANCE_K PSTR("Advance K:") +#if FW_COMMIT_NR <= 2266 +// TODO: this is a stub to be removed for FW >3.7.1 +const static char menu_fmt_float13_k[] PROGMEM = "%c%-13.13S%+5.3f"; +const static char menu_fmt_float13off_k[] PROGMEM = "%c%-13.13S%6.6s"; +static void lcd_advance_draw_K(char chr, float val) +{ + if (val <= 0) + lcd_printf_P(menu_fmt_float13off_k, chr, MSG_ADVANCE_K, " [off]"); + else + lcd_printf_P(menu_fmt_float13_k, chr, MSG_ADVANCE_K, val); +} +#else static void lcd_advance_draw_K(char chr, float val) { if (val <= 0) @@ -6619,6 +6631,7 @@ static void lcd_advance_draw_K(char chr, float val) else lcd_printf_P(menu_fmt_float13, chr, MSG_ADVANCE_K, val); } +#endif static void lcd_advance_edit_K(void) { From a742afcebd743920791937da6c7b0eee7839adbe Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 26 May 2019 22:43:06 +0200 Subject: [PATCH 37/64] Remove version check --- Firmware/ultralcd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index ceccfbe5..5d774eb1 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -6612,7 +6612,7 @@ static void lcd_colorprint_change() { // redefine our custom handling functions to mimick other tunables #define MSG_ADVANCE_K PSTR("Advance K:") -#if FW_COMMIT_NR <= 2266 +#if 1 // TODO: this is a stub to be removed for FW >3.7.1 const static char menu_fmt_float13_k[] PROGMEM = "%c%-13.13S%+5.3f"; const static char menu_fmt_float13off_k[] PROGMEM = "%c%-13.13S%6.6s"; From 51d6904dad10e1554233e508dfa23f8e0db97018 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 27 May 2019 00:44:17 +0200 Subject: [PATCH 38/64] Multiply the step rate when grouping advance steps --- Firmware/planner.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index ddf94cb8..67aa3c9a 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -1093,10 +1093,14 @@ Having the real displacement of the head, we can calculate the total movement le float advance_speed = (extruder_advance_K * block->e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]); if (advance_speed > MAX_STEP_FREQUENCY) advance_speed = MAX_STEP_FREQUENCY; block->advance_rate = (F_CPU / 8.0) / advance_speed; - if (block->advance_rate > 20000) + if (block->advance_rate > 20000) { + block->advance_rate = (block->advance_rate >> 2)&0x3fff; block->advance_step_loops = 4; - else if (block->advance_rate > 10000) + } + else if (block->advance_rate > 10000) { + block->advance_rate = (block->advance_rate >> 1)&0x7fff; block->advance_step_loops = 2; + } else block->advance_step_loops = 1; From c50b1c035156a0abfc4f0bd8c688b9ed420ed711 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 1 Jun 2019 19:59:39 +0200 Subject: [PATCH 39/64] Rework the filament counter logic - Move direction checks out of fsensor: fsensor_counter is now always in the same direction as e_steps - Check the filament chunk after e_steps have been physically done, using the real e_step count so far --- Firmware/fsensor.cpp | 11 +++++------ Firmware/fsensor.h | 4 ++-- Firmware/stepper.cpp | 33 +++++++++++++++++++-------------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Firmware/fsensor.cpp b/Firmware/fsensor.cpp index d520ba53..d296a6e7 100644 --- a/Firmware/fsensor.cpp +++ b/Firmware/fsensor.cpp @@ -492,11 +492,10 @@ void fsensor_setup_interrupt(void) #endif //PAT9125 -void fsensor_st_block_begin(block_t* bl) +void fsensor_st_block_begin(bool rev) { if (!fsensor_enabled) return; - if (((fsensor_st_cnt > 0) && (bl->direction_bits & 0x8)) || - ((fsensor_st_cnt < 0) && !(bl->direction_bits & 0x8))) + if (fsensor_st_cnt && ((fsensor_st_cnt > 0) ^ rev)) { // !!! bit toggling (PINxn <- 1) (for PinChangeInterrupt) does not work for some MCU pins if (PIN_GET(FSENSOR_INT_PIN)) {PIN_VAL(FSENSOR_INT_PIN, LOW);} @@ -504,11 +503,11 @@ void fsensor_st_block_begin(block_t* bl) } } -void fsensor_st_block_chunk(block_t* bl, int cnt) +void fsensor_st_block_chunk(int cnt) { if (!fsensor_enabled) return; - fsensor_st_cnt += (bl->direction_bits & 0x8)?-cnt:cnt; - if ((fsensor_st_cnt >= fsensor_chunk_len) || (fsensor_st_cnt <= -fsensor_chunk_len)) + fsensor_st_cnt += cnt; + if (abs(fsensor_st_cnt) >= fsensor_chunk_len) { // !!! bit toggling (PINxn <- 1) (for PinChangeInterrupt) does not work for some MCU pins if (PIN_GET(FSENSOR_INT_PIN)) {PIN_VAL(FSENSOR_INT_PIN, LOW);} diff --git a/Firmware/fsensor.h b/Firmware/fsensor.h index 71922fbf..85992d39 100644 --- a/Firmware/fsensor.h +++ b/Firmware/fsensor.h @@ -60,8 +60,8 @@ extern bool fsensor_oq_result(void); #include "planner.h" //! @name callbacks from stepper //! @{ -extern void fsensor_st_block_begin(block_t* bl); -extern void fsensor_st_block_chunk(block_t* bl, int cnt); +extern void fsensor_st_block_begin(bool rev); +extern void fsensor_st_block_chunk(int cnt); //! @} #endif //FSENSOR_H diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index fda9f11c..111d1fa7 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -339,7 +339,7 @@ FORCE_INLINE void stepper_next_block() #ifdef FILAMENT_SENSOR fsensor_counter = 0; - fsensor_st_block_begin(current_block); + fsensor_st_block_begin(count_direction[E_AXIS] < 0); #endif //FILAMENT_SENSOR // The busy flag is set by the plan_get_current_block() call. // current_block->busy = true; @@ -638,7 +638,7 @@ FORCE_INLINE void stepper_tick_lowres() e_steps += count_direction[E_AXIS]; #else #ifdef FILAMENT_SENSOR - ++ fsensor_counter; + fsensor_counter += count_direction[E_AXIS]; #endif //FILAMENT_SENSOR WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #endif @@ -700,7 +700,7 @@ FORCE_INLINE void stepper_tick_highres() e_steps += count_direction[E_AXIS]; #else #ifdef FILAMENT_SENSOR - ++ fsensor_counter; + fsensor_counter += count_direction[E_AXIS]; #endif //FILAMENT_SENSOR WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #endif @@ -857,18 +857,18 @@ FORCE_INLINE void isr() { // If current block is finished, reset pointer if (step_events_completed.wide >= current_block->step_event_count.wide) { -#ifdef FILAMENT_SENSOR - fsensor_st_block_chunk(current_block, fsensor_counter); +#if !defined(LIN_ADVANCE) && defined(FILAMENT_SENSOR) + fsensor_st_block_chunk(fsensor_counter); fsensor_counter = 0; #endif //FILAMENT_SENSOR current_block = NULL; plan_discard_current_block(); } -#ifdef FILAMENT_SENSOR - else if ((fsensor_counter >= fsensor_chunk_len)) +#if !defined(LIN_ADVANCE) && defined(FILAMENT_SENSOR) + else if ((abs(fsensor_counter) >= fsensor_chunk_len)) { - fsensor_st_block_chunk(current_block, fsensor_counter); + fsensor_st_block_chunk(fsensor_counter); fsensor_counter = 0; } #endif //FILAMENT_SENSOR @@ -952,20 +952,25 @@ FORCE_INLINE void advance_isr_scheduler() { uint8_t max_ticks = (eisr? e_step_loops: step_loops); max_ticks = min(abs(e_steps), max_ticks); bool rev = (e_steps < 0); -#ifdef FILAMENT_SENSOR - if (count_direction[E_AXIS] == 1) - fsensor_counter += (rev? -max_ticks: max_ticks); - else - fsensor_counter -= (rev? -max_ticks: max_ticks); -#endif WRITE_NC(E0_DIR_PIN, rev? INVERT_E0_DIR: !INVERT_E0_DIR); do { WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); e_steps += (rev? 1: -1); WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); +#ifdef FILAMENT_SENSOR + fsensor_counter += (rev? -1: 1); +#endif } while(--max_ticks); + +#ifdef FILAMENT_SENSOR + if (!current_block || (abs(fsensor_counter) >= fsensor_chunk_len)) + { + fsensor_st_block_chunk(fsensor_counter); + fsensor_counter = 0; + } +#endif } // Schedule the next closest tick, ignoring advance if scheduled too From b4bf79297f804568f2f1cb82a3bfd0968e8e4a94 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 2 Jun 2019 00:42:32 +0200 Subject: [PATCH 40/64] Remove unneeded includes from fsensor --- Firmware/fsensor.cpp | 3 --- Firmware/fsensor.h | 2 -- 2 files changed, 5 deletions(-) diff --git a/Firmware/fsensor.cpp b/Firmware/fsensor.cpp index d296a6e7..471518b2 100644 --- a/Firmware/fsensor.cpp +++ b/Firmware/fsensor.cpp @@ -6,12 +6,9 @@ #include #include "pat9125.h" #include "stepper.h" -#include "planner.h" -#include "fastio.h" #include "io_atmega2560.h" #include "cmdqueue.h" #include "ultralcd.h" -#include "ConfigurationStore.h" #include "mmu.h" #include "cardreader.h" diff --git a/Firmware/fsensor.h b/Firmware/fsensor.h index 85992d39..1abf13b9 100644 --- a/Firmware/fsensor.h +++ b/Firmware/fsensor.h @@ -56,8 +56,6 @@ extern void fsensor_oq_meassure_stop(void); extern bool fsensor_oq_result(void); //! @} - -#include "planner.h" //! @name callbacks from stepper //! @{ extern void fsensor_st_block_begin(bool rev); From 5cd0177389c5f0dc93da3b70dd404582e3022f4a Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 2 Jun 2019 15:01:56 +0200 Subject: [PATCH 41/64] Cleanup fsensor_st_block_begin --- Firmware/fsensor.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Firmware/fsensor.cpp b/Firmware/fsensor.cpp index 471518b2..563d37d6 100644 --- a/Firmware/fsensor.cpp +++ b/Firmware/fsensor.cpp @@ -489,15 +489,13 @@ void fsensor_setup_interrupt(void) #endif //PAT9125 -void fsensor_st_block_begin(bool rev) +void fsensor_st_block_begin(bool rev __attribute__((unused))) { - if (!fsensor_enabled) return; - if (fsensor_st_cnt && ((fsensor_st_cnt > 0) ^ rev)) - { -// !!! bit toggling (PINxn <- 1) (for PinChangeInterrupt) does not work for some MCU pins - if (PIN_GET(FSENSOR_INT_PIN)) {PIN_VAL(FSENSOR_INT_PIN, LOW);} - else {PIN_VAL(FSENSOR_INT_PIN, HIGH);} - } + // There's really nothing to do here: the stepper ISR likely has called us + // already at the end of the last block, making this integration redundant. + // LA1.5 might not always do that during a coasting move, so attempt to drain + // fsensor_st_cnt anyway at the beginning of the new block. + fsensor_st_block_chunk(0); } void fsensor_st_block_chunk(int cnt) From d2432056bdcb570884f92f53ab6d2468d82260f5 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 3 Jun 2019 11:48:36 +0200 Subject: [PATCH 42/64] Elide fsensor_st_block_begin, saving some cycles/bytes --- Firmware/fsensor.cpp | 9 --------- Firmware/fsensor.h | 7 ++++++- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Firmware/fsensor.cpp b/Firmware/fsensor.cpp index 563d37d6..4ab87586 100644 --- a/Firmware/fsensor.cpp +++ b/Firmware/fsensor.cpp @@ -489,15 +489,6 @@ void fsensor_setup_interrupt(void) #endif //PAT9125 -void fsensor_st_block_begin(bool rev __attribute__((unused))) -{ - // There's really nothing to do here: the stepper ISR likely has called us - // already at the end of the last block, making this integration redundant. - // LA1.5 might not always do that during a coasting move, so attempt to drain - // fsensor_st_cnt anyway at the beginning of the new block. - fsensor_st_block_chunk(0); -} - void fsensor_st_block_chunk(int cnt) { if (!fsensor_enabled) return; diff --git a/Firmware/fsensor.h b/Firmware/fsensor.h index 1abf13b9..e40568bb 100644 --- a/Firmware/fsensor.h +++ b/Firmware/fsensor.h @@ -58,8 +58,13 @@ extern bool fsensor_oq_result(void); //! @name callbacks from stepper //! @{ -extern void fsensor_st_block_begin(bool rev); extern void fsensor_st_block_chunk(int cnt); + +// There's really nothing to do in block_begin: the stepper ISR likely has +// called us already at the end of the last block, making this integration +// redundant. LA1.5 might not always do that during a coasting move, so attempt +// to drain fsensor_st_cnt anyway at the beginning of the new block. +#define fsensor_st_block_begin(rev) fsensor_st_block_chunk(0) //! @} #endif //FSENSOR_H From fa7c0fb2c92f5bfaa0f996ee2c650df7116d1694 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 3 Jun 2019 12:24:08 +0200 Subject: [PATCH 43/64] Avoid triggering LA during a Z-priming move When recovering from a pause, the nozzle is often primed while being lowered. If LA is triggered under such a move, the pressure advance will be wasted. --- Firmware/planner.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 67aa3c9a..e1b04702 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -1023,13 +1023,15 @@ Having the real displacement of the head, we can calculate the total movement le /** * Use LIN_ADVANCE for blocks 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) + * 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[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; + && delta_mm[E_AXIS] > 0 + && abs(delta_mm[Z_AXIS]) < 0.5; if (block->use_advance_lead) { block->e_D_ratio = (e - position_float[E_AXIS]) / sqrt(sq(x - position_float[X_AXIS]) From 84009e1e8e80ccc48374beed9d3e90272b1ed1dd Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 3 Jun 2019 14:52:12 +0200 Subject: [PATCH 44/64] Do a full fsensor_update() when initializing the sensor This correctly populates the "extruder info" details even when the menu is entered for the first time after starting a print. --- Firmware/fsensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/fsensor.cpp b/Firmware/fsensor.cpp index 4ab87586..29673231 100644 --- a/Firmware/fsensor.cpp +++ b/Firmware/fsensor.cpp @@ -216,7 +216,7 @@ void fsensor_autoload_check_start(void) if (!fsensor_enabled) return; if (!fsensor_autoload_enabled) return; if (fsensor_watch_autoload) return; - if (!pat9125_update_y()) //update sensor + if (!pat9125_update()) //update sensor { fsensor_disable(); fsensor_not_responding = true; From bca5618145dcee174f01ba82aa66742f1bb5b173 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 3 Jun 2019 16:53:55 +0200 Subject: [PATCH 45/64] Save/restore K during a power panic --- Firmware/Marlin_main.cpp | 6 ++++++ Firmware/eeprom.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index b9af28b7..663d36e5 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -8801,6 +8801,9 @@ void uvlo_() #endif #endif eeprom_update_word((uint16_t*)(EEPROM_EXTRUDEMULTIPLY), (uint16_t)extrudemultiply); +#ifdef LIN_ADVANCE + eeprom_update_float((float*)(EEPROM_UVLO_LA_K), extruder_advance_K); +#endif // Finaly store the "power outage" flag. if(sd_print) eeprom_update_byte((uint8_t*)EEPROM_UVLO, 1); @@ -9046,6 +9049,9 @@ void recover_machine_state_after_power_panic(bool bTiny) #endif #endif extrudemultiply = (int)eeprom_read_word((uint16_t*)(EEPROM_EXTRUDEMULTIPLY)); +#ifdef LIN_ADVANCE + extruder_advance_K = eeprom_read_float((float*)EEPROM_UVLO_LA_K); +#endif } void restore_print_from_eeprom() { diff --git a/Firmware/eeprom.h b/Firmware/eeprom.h index c96e1d8d..624025e8 100644 --- a/Firmware/eeprom.h +++ b/Firmware/eeprom.h @@ -160,6 +160,8 @@ #define EEPROM_MBL_POINTS_NR (EEPROM_MBL_MAGNET_ELIMINATION -1) //uint8_t number of points in one exis for mesh bed leveling #define EEPROM_MBL_PROBE_NR (EEPROM_MBL_POINTS_NR-1) //number of measurements for each point #define EEPROM_MMU_STEALTH (EEPROM_MBL_PROBE_NR-1) + +#define EEPROM_UVLO_LA_K (EEPROM_MMU_STEALTH-4) // float // !!!!! // !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!! // !!!!! From 8ce1c047405aec9fd383e55f47fbcd9297e15461 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Tue, 4 Jun 2019 14:36:41 +0200 Subject: [PATCH 46/64] Remove useless "extruder under pressure" flag That's exactly what LA does --- Firmware/Marlin_main.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 663d36e5..a1eec5a6 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -356,10 +356,6 @@ unsigned long starttime=0; unsigned long stoptime=0; unsigned long _usb_timer = 0; - -bool extruder_under_pressure = true; - - bool Stopped=false; #if NUM_SERVOS > 0 @@ -385,7 +381,6 @@ static float saved_pos[4] = { 0, 0, 0, 0 }; static float saved_feedrate2 = 0; static uint8_t saved_active_extruder = 0; static float saved_extruder_temperature = 0.0; //!< Active extruder temperature -static bool saved_extruder_under_pressure = false; static bool saved_extruder_relative_mode = false; static int saved_fanSpeed = 0; //!< Print fan speed //! @} @@ -9270,8 +9265,6 @@ void stop_and_save_print_to_ram(float z_move, float e_move) memcpy(saved_pos, current_position, sizeof(saved_pos)); saved_active_extruder = active_extruder; //save active_extruder saved_extruder_temperature = degTargetHotend(active_extruder); - - saved_extruder_under_pressure = extruder_under_pressure; //extruder under pressure flag - currently unused saved_extruder_relative_mode = axis_relative_modes[E_AXIS]; saved_fanSpeed = fanSpeed; cmdqueue_reset(); //empty cmdqueue From 1bed8cfa941a29ec304f0cbc19677c24338fbc78 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Tue, 4 Jun 2019 16:02:03 +0200 Subject: [PATCH 47/64] Don't call fsensor_st_next_block repeatedly during the last step Rely on st_block_begin to perform a single call instead of calling block_chunk for each advance tick in the last step --- Firmware/stepper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 111d1fa7..68f36342 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -965,7 +965,7 @@ FORCE_INLINE void advance_isr_scheduler() { while(--max_ticks); #ifdef FILAMENT_SENSOR - if (!current_block || (abs(fsensor_counter) >= fsensor_chunk_len)) + if (abs(fsensor_counter) >= fsensor_chunk_len) { fsensor_st_block_chunk(fsensor_counter); fsensor_counter = 0; From cda9ed4a1d404d676fd975b3d4e4fdadcf74a079 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Tue, 4 Jun 2019 14:37:35 +0200 Subject: [PATCH 48/64] Reset LA state more carefully during stop conditions --- Firmware/stepper.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 68f36342..cd590013 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -426,6 +426,13 @@ FORCE_INLINE void stepper_next_block() } else { _NEXT_ISR(2000); // 1kHz. + +#ifdef LIN_ADVANCE + // reset LA state and pressure when there's no block + nextAdvanceISR = ADV_NEVER; + e_steps = 0; + current_adv_steps = 0; +#endif } //WRITE_NC(LOGIC_ANALYZER_CH2, false); } @@ -982,6 +989,8 @@ FORCE_INLINE void advance_isr_scheduler() { } void clear_current_adv_vars() { + nextAdvanceISR = ADV_NEVER; + e_steps = 0; current_adv_steps = 0; } @@ -1336,6 +1345,9 @@ void quickStop() DISABLE_STEPPER_DRIVER_INTERRUPT(); while (blocks_queued()) plan_discard_current_block(); current_block = NULL; +#ifdef LIN_ADVANCE + clear_current_adv_vars(); +#endif st_reset_timer(); ENABLE_STEPPER_DRIVER_INTERRUPT(); } From fa454f61e41c9373de27c255be7694842f40e102 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Wed, 5 Jun 2019 15:23:59 +0200 Subject: [PATCH 49/64] Drop unused "speed_lookup_table.h" from planner.cpp --- Firmware/planner.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index e1b04702..57c312e8 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -58,7 +58,6 @@ #include "ultralcd.h" #include "language.h" #include "ConfigurationStore.h" -#include "speed_lookuptable.h" #ifdef MESH_BED_LEVELING #include "mesh_bed_leveling.h" From dc436b71fe6052b8b31192bd113197895c4c277a Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Wed, 5 Jun 2019 13:00:26 +0200 Subject: [PATCH 50/64] Fix position_float after a quickStop condition --- Firmware/planner.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 57c312e8..c8f18f41 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -127,7 +127,7 @@ float extrude_min_temp=EXTRUDE_MINTEMP; #ifdef LIN_ADVANCE float extruder_advance_K = LIN_ADVANCE_K; -float position_float[NUM_AXIS] = { 0, 0, 0, 0 }; +float position_float[NUM_AXIS]; #endif // Returns the index of the next block in the ring buffer @@ -441,7 +441,7 @@ void plan_init() { block_buffer_tail = 0; memset(position, 0, sizeof(position)); // clear position #ifdef LIN_ADVANCE - memset(position_float, 0, sizeof(position)); // clear position + memset(position_float, 0, sizeof(position_float)); // clear position #endif previous_speed[0] = 0.0; previous_speed[1] = 0.0; @@ -655,7 +655,9 @@ void planner_abort_hard() // Apply inverse world correction matrix. machine2world(current_position[X_AXIS], current_position[Y_AXIS]); memcpy(destination, current_position, sizeof(destination)); - +#ifdef LIN_ADVANCE + memcpy(position_float, current_position, sizeof(position_float)); +#endif // Resets planner junction speeds. Assumes start from rest. previous_nominal_speed = 0.0; previous_speed[0] = 0.0; From 7d33089d9aa1a3442149f2362aa6a90cef0a72e3 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Wed, 5 Jun 2019 13:02:04 +0200 Subject: [PATCH 51/64] Remove use_advance_lead The per-step state is kept implicitly using nextAdvanceISR, while the current pressure is decoupled anyway. --- Firmware/stepper.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index cd590013..6daddaa4 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -120,8 +120,6 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1}; static const uint8_t ADV_INIT = 0b01; static const uint8_t ADV_DECELERATE = 0b10; - static bool use_advance_lead; - static uint16_t nextMainISR; static uint16_t nextAdvanceISR; @@ -354,7 +352,7 @@ FORCE_INLINE void stepper_next_block() acceleration_time = calc_timer(acc_step_rate, step_loops); #ifdef LIN_ADVANCE - if ((use_advance_lead = current_block->use_advance_lead)) { + 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; @@ -1227,7 +1225,6 @@ void st_init() #endif // Initialize state for the linear advance scheduler - use_advance_lead = false; nextMainISR = 0; nextAdvanceISR = ADV_NEVER; main_Rate = ADV_NEVER; From 048628083a637c356bec59a5a1f8ffff331d85dd Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Wed, 5 Jun 2019 13:03:25 +0200 Subject: [PATCH 52/64] Remove clear_current_adv_vars() The pressure state is already reset implicitly at the end of each block, meaning an extruder switch will never have to reset the internal state anyway. We clear the internal backpressure in the following conditions: - when switching to a non-LA block - when quickStop is called - when the scheduler is idling (losing pressure) --- Firmware/Marlin_main.cpp | 7 ------- Firmware/stepper.cpp | 17 +++++++---------- Firmware/stepper.h | 4 ---- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index a1eec5a6..c423df1b 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -7086,15 +7086,8 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) else { #ifdef SNMM - -#ifdef LIN_ADVANCE - if (mmu_extruder != tmp_extruder) - clear_current_adv_vars(); //Check if the selected extruder is not the active one and reset LIN_ADVANCE variables if so. -#endif - mmu_extruder = tmp_extruder; - _delay(100); disable_e0(); diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 6daddaa4..ba5e8414 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -426,10 +426,13 @@ FORCE_INLINE void stepper_next_block() _NEXT_ISR(2000); // 1kHz. #ifdef LIN_ADVANCE - // reset LA state and pressure when there's no block + // reset LA state when there's no block nextAdvanceISR = ADV_NEVER; e_steps = 0; - current_adv_steps = 0; + + // incrementally lose pressure + if(current_adv_steps) + --current_adv_steps; #endif } //WRITE_NC(LOGIC_ANALYZER_CH2, false); @@ -985,13 +988,6 @@ FORCE_INLINE void advance_isr_scheduler() { else OCR1A = nextMainISR; } - -void clear_current_adv_vars() { - nextAdvanceISR = ADV_NEVER; - e_steps = 0; - current_adv_steps = 0; -} - #endif // LIN_ADVANCE void st_init() @@ -1343,7 +1339,8 @@ void quickStop() while (blocks_queued()) plan_discard_current_block(); current_block = NULL; #ifdef LIN_ADVANCE - clear_current_adv_vars(); + nextAdvanceISR = ADV_NEVER; + current_adv_steps = 0; #endif st_reset_timer(); ENABLE_STEPPER_DRIVER_INTERRUPT(); diff --git a/Firmware/stepper.h b/Firmware/stepper.h index 1bdb1f17..7c41743c 100644 --- a/Firmware/stepper.h +++ b/Firmware/stepper.h @@ -37,10 +37,6 @@ void st_init(); void isr(); -#ifdef LIN_ADVANCE -void clear_current_adv_vars(); // Used to reset the built up pretension and remaining esteps on filament change. -#endif - // Block until all buffered steps are executed void st_synchronize(); From 0239f4bce19f1dabe430c51087771798b7449d6f Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Wed, 5 Jun 2019 15:10:31 +0200 Subject: [PATCH 53/64] Update/compute advance steps inside calculate_trapezoid_for_block Do not store the block e_D ratio, store directly the computed compression factor so that we can recompute the advance steps quickly and update them in sync with the acceleration rates. --- Firmware/planner.cpp | 59 ++++++++++++++++++++++---------------------- Firmware/planner.h | 2 +- Firmware/stepper.cpp | 3 ++- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index c8f18f41..cb286c58 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -261,6 +261,13 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit } } +#ifdef LIN_ADVANCE + uint16_t final_adv_steps = 0; + if (block->use_advance_lead) { + final_adv_steps = exit_speed * block->adv_comp; + } +#endif + CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section // This block locks the interrupts globally for 4.38 us, // which corresponds to a maximum repeat frequency of 228.57 kHz. @@ -271,6 +278,9 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit block->decelerate_after = accelerate_steps+plateau_steps; block->initial_rate = initial_rate; block->final_rate = final_rate; +#ifdef LIN_ADVANCE + block->final_adv_steps = final_adv_steps; +#endif } CRITICAL_SECTION_END; } @@ -399,18 +409,8 @@ void planner_recalculate(const float &safe_final_speed) } // Recalculate if current block entry or exit junction speed has changed. if ((prev->flag | current->flag) & BLOCK_FLAG_RECALCULATE) { - // @wavexx: FIXME: the following check is not really enough. calculate_trapezoid does block - // the isr to update the rates, but we don't. we should update atomically - if (!prev->busy) { - // NOTE: Entry and exit factors always > 0 by all previous logic operations. - calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed); - #ifdef LIN_ADVANCE - if (prev->use_advance_lead) { - const float comp = prev->e_D_ratio * extruder_advance_K * cs.axis_steps_per_unit[E_AXIS]; - prev->final_adv_steps = current->entry_speed * comp; - } - #endif - } + // NOTE: Entry and exit factors always > 0 by all previous logic operations. + calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed); // Reset current only to ensure next trapezoid is computed. prev->flag &= ~BLOCK_FLAG_RECALCULATE; } @@ -424,13 +424,6 @@ void planner_recalculate(const float &safe_final_speed) // Last/newest block in buffer. Exit speed is set with safe_final_speed. Always recalculated. current = block_buffer + prev_block_index(block_buffer_head); calculate_trapezoid_for_block(current, current->entry_speed, safe_final_speed); - #ifdef LIN_ADVANCE - if (current->use_advance_lead) { - const float comp = current->e_D_ratio * extruder_advance_K * cs.axis_steps_per_unit[E_AXIS]; - current->max_adv_steps = current->nominal_speed * comp; - current->final_adv_steps = safe_final_speed * comp; - } - #endif current->flag &= ~BLOCK_FLAG_RECALCULATE; // SERIAL_ECHOLNPGM("planner_recalculate - 4"); @@ -1005,6 +998,9 @@ Having the real displacement of the head, we can calculate the total movement le block->nominal_rate *= speed_factor; } +#ifdef LIN_ADVANCE + float e_D_ratio = 0; +#endif // Compute and limit the acceleration rate for the trapezoid generator. // block->step_event_count ... event count of the fastest axis // block->millimeters ... Euclidian length of the XYZ movement or the E length, if no XYZ movement. @@ -1022,7 +1018,7 @@ Having the real displacement of the head, we can calculate the total movement le #ifdef LIN_ADVANCE /** - * Use LIN_ADVANCE for blocks if all these are true: + * 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. @@ -1034,19 +1030,19 @@ Having the real displacement of the head, we can calculate the total movement le && delta_mm[E_AXIS] > 0 && abs(delta_mm[Z_AXIS]) < 0.5; if (block->use_advance_lead) { - block->e_D_ratio = (e - position_float[E_AXIS]) / - sqrt(sq(x - position_float[X_AXIS]) - + sq(y - position_float[Y_AXIS]) - + sq(z - position_float[Z_AXIS])); + e_D_ratio = (e - position_float[E_AXIS]) / + sqrt(sq(x - position_float[X_AXIS]) + + sq(y - position_float[Y_AXIS]) + + sq(z - position_float[Z_AXIS])); // 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. - if (block->e_D_ratio > 3.0) + 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 * block->e_D_ratio) * steps_per_mm; + 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; #ifdef LA_DEBUG @@ -1089,11 +1085,16 @@ Having the real displacement of the head, we can calculate the total movement le block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0))); - #ifdef LIN_ADVANCE +#ifdef LIN_ADVANCE if (block->use_advance_lead) { + // the nominal speed doesn't change past this point: calculate the compression ratio for the + // segment and the required advance steps + 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; + // 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 * block->e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]); + 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; block->advance_rate = (F_CPU / 8.0) / advance_speed; if (block->advance_rate > 20000) { @@ -1116,7 +1117,7 @@ Having the real displacement of the head, we can calculate the total movement le SERIAL_ECHOLNPGM("LA: More than 2 steps per eISR loop executed."); #endif } - #endif +#endif // Start with a safe speed. // Safe speed is the speed, from which the machine may halt to stop immediately. diff --git a/Firmware/planner.h b/Firmware/planner.h index 44c57ea5..bb7b17c8 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -117,7 +117,7 @@ typedef struct { max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!) final_adv_steps; // advance steps due to exit speed uint8_t advance_step_loops; // Number of stepper ticks for each advance isr - float e_D_ratio; + float adv_comp; // Precomputed E compression factor #endif uint16_t sdlen; diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index ba5e8414..d6faee96 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -430,7 +430,8 @@ FORCE_INLINE void stepper_next_block() nextAdvanceISR = ADV_NEVER; e_steps = 0; - // incrementally lose pressure + // incrementally lose pressure to give a chance for + // a new LA block to be scheduled and recover if(current_adv_steps) --current_adv_steps; #endif From c40e3b550dde8118d1c1ba8c7e0662c09e9913cf Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 10 Jun 2019 19:34:00 +0200 Subject: [PATCH 54/64] Remove stubs and live K by default --- Firmware/Configuration_adv.h | 2 +- Firmware/ultralcd.cpp | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 9225ec25..50496704 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -295,7 +295,7 @@ #ifdef LIN_ADVANCE #define LIN_ADVANCE_K 0 // Unit: mm compression per 1mm/s extruder speed - #define LA_LIVE_K // Allow adjusting K in the Tune menu + //#define LA_LIVE_K // Allow adjusting K in the Tune menu //#define LA_DEBUG // If enabled, this will generate debug information output over USB. //#define LA_DEBUG_LOGIC // @wavexx: setup logic channels for isr debugging #endif diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 5d774eb1..dd1da720 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -6612,18 +6612,6 @@ static void lcd_colorprint_change() { // redefine our custom handling functions to mimick other tunables #define MSG_ADVANCE_K PSTR("Advance K:") -#if 1 -// TODO: this is a stub to be removed for FW >3.7.1 -const static char menu_fmt_float13_k[] PROGMEM = "%c%-13.13S%+5.3f"; -const static char menu_fmt_float13off_k[] PROGMEM = "%c%-13.13S%6.6s"; -static void lcd_advance_draw_K(char chr, float val) -{ - if (val <= 0) - lcd_printf_P(menu_fmt_float13off_k, chr, MSG_ADVANCE_K, " [off]"); - else - lcd_printf_P(menu_fmt_float13_k, chr, MSG_ADVANCE_K, val); -} -#else static void lcd_advance_draw_K(char chr, float val) { if (val <= 0) @@ -6631,7 +6619,6 @@ static void lcd_advance_draw_K(char chr, float val) else lcd_printf_P(menu_fmt_float13, chr, MSG_ADVANCE_K, val); } -#endif static void lcd_advance_edit_K(void) { From 4b3af0d2dfc82cb5a605ed2ea5cbad5b32111c18 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Tue, 18 Jun 2019 17:49:59 +0200 Subject: [PATCH 55/64] Respect minimum direction change delay --- Firmware/stepper.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index d6faee96..b9d15126 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -785,6 +785,7 @@ FORCE_INLINE void isr() { #ifdef LIN_ADVANCE + WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); uint8_t la_state = 0; #endif @@ -897,6 +898,7 @@ FORCE_INLINE void advance_isr() { if (step_events_completed.wide > LA_decelerate_after && current_adv_steps > final_adv_steps) { // decompression e_steps -= e_step_loops; + WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); if(current_adv_steps > e_step_loops) current_adv_steps -= e_step_loops; else @@ -906,6 +908,7 @@ FORCE_INLINE void advance_isr() { else if (step_events_completed.wide < LA_decelerate_after && current_adv_steps < max_adv_steps) { // compression e_steps += e_step_loops; + WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); current_adv_steps += e_step_loops; nextAdvanceISR = eISR_Rate; } @@ -961,7 +964,6 @@ FORCE_INLINE void advance_isr_scheduler() { uint8_t max_ticks = (eisr? e_step_loops: step_loops); max_ticks = min(abs(e_steps), max_ticks); bool rev = (e_steps < 0); - WRITE_NC(E0_DIR_PIN, rev? INVERT_E0_DIR: !INVERT_E0_DIR); do { WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); From 2e073527fb872021555d1248f05a8ae79f15d780 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Wed, 19 Jun 2019 14:18:23 +0200 Subject: [PATCH 56/64] Also avoid E direction inversions while coasting --- Firmware/stepper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index b9d15126..1283675c 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -785,7 +785,7 @@ FORCE_INLINE void isr() { #ifdef LIN_ADVANCE - WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); + if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); uint8_t la_state = 0; #endif @@ -898,7 +898,7 @@ FORCE_INLINE void advance_isr() { if (step_events_completed.wide > LA_decelerate_after && current_adv_steps > final_adv_steps) { // decompression e_steps -= e_step_loops; - WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); + if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); if(current_adv_steps > e_step_loops) current_adv_steps -= e_step_loops; else @@ -908,7 +908,7 @@ FORCE_INLINE void advance_isr() { else if (step_events_completed.wide < LA_decelerate_after && current_adv_steps < max_adv_steps) { // compression e_steps += e_step_loops; - WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); + if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); current_adv_steps += e_step_loops; nextAdvanceISR = eISR_Rate; } From b6bcb901f35a2558c349e468b28c9e3b04c8e022 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Thu, 27 Jun 2019 12:50:53 +0200 Subject: [PATCH 57/64] Correct initialization of eISR_Err Further tweak the initial term to improve the linearity of the resulting speed after BW filtering. --- Firmware/stepper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 1283675c..b30f77e6 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -846,7 +846,7 @@ FORCE_INLINE void isr() { #ifdef LIN_ADVANCE // avoid multiple instances or function calls to advance_spread - if (la_state & ADV_INIT) eISR_Rate = current_block->advance_rate / 2; + if (la_state & ADV_INIT) eISR_Err = current_block->advance_rate / 4; if (la_state & ADV_INIT || nextAdvanceISR != ADV_NEVER) { advance_spread(main_Rate); if (la_state & ADV_DECELERATE) { From 1435e4a68d3be539fa55b6f4cbb0e054dd4816b7 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Tue, 16 Jul 2019 18:12:21 +0200 Subject: [PATCH 58/64] Use the computed direction in fsensor_st_block_begin --- Firmware/stepper.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index b30f77e6..15e809b4 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -335,10 +335,6 @@ FORCE_INLINE void stepper_next_block() } #endif -#ifdef FILAMENT_SENSOR - fsensor_counter = 0; - fsensor_st_block_begin(count_direction[E_AXIS] < 0); -#endif //FILAMENT_SENSOR // The busy flag is set by the plan_get_current_block() call. // current_block->busy = true; // Initializes the trapezoid generator from the current block. Called whenever a new @@ -421,6 +417,10 @@ FORCE_INLINE void stepper_next_block() #endif /* LIN_ADVANCE */ count_direction[E_AXIS] = 1; } +#ifdef FILAMENT_SENSOR + fsensor_counter = 0; + fsensor_st_block_begin(count_direction[E_AXIS] < 0); +#endif //FILAMENT_SENSOR } else { _NEXT_ISR(2000); // 1kHz. From 7cae064611c7dfae0b20df623d4095ac5b7c4f99 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 4 Aug 2019 18:39:28 +0200 Subject: [PATCH 59/64] Update EEPROM_LAST_ITEM --- Firmware/eeprom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/eeprom.h b/Firmware/eeprom.h index 6b4b3318..4cd616cb 100644 --- a/Firmware/eeprom.h +++ b/Firmware/eeprom.h @@ -206,7 +206,7 @@ static Sheets * const EEPROM_Sheets_base = (Sheets*)(EEPROM_SHEETS_BASE); #define EEPROM_UVLO_LA_K (EEPROM_SHEETS_BASE-4) // float //This is supposed to point to last item to allow EEPROM overrun check. Please update when adding new items. -#define EEPROM_LAST_ITEM EEPROM_SHEETS_BASE +#define EEPROM_LAST_ITEM EEPROM_UVLO_LA_K // !!!!! // !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!! // !!!!! From 0b9123ce24a31f9247cc0af2282ede488dd8b641 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Thu, 5 Dec 2019 15:18:24 +0100 Subject: [PATCH 60/64] Fix Live K, allow "Advance K" to be translated --- Firmware/menu.h | 2 -- Firmware/messages.c | 3 +++ Firmware/messages.h | 3 +++ Firmware/ultralcd.cpp | 6 +++--- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Firmware/menu.h b/Firmware/menu.h index 2ab0c365..88363359 100755 --- a/Firmware/menu.h +++ b/Firmware/menu.h @@ -132,8 +132,6 @@ extern const char menu_fmt_int3[]; extern const char menu_fmt_float31[]; extern const char menu_fmt_float13[]; -extern const char menu_fmt_float13off[]; - extern void menu_draw_float31(const char* str, float val); diff --git a/Firmware/messages.c b/Firmware/messages.c index bb2e9510..3c2fc9bb 100644 --- a/Firmware/messages.c +++ b/Firmware/messages.c @@ -131,6 +131,9 @@ const char MSG_MAGNETS_COMP[] PROGMEM_I1 = ISTR("Magnets comp."); //// const char MSG_FS_ACTION[] PROGMEM_I1 = ISTR("FS Action"); //// const char MSG_FS_CONTINUE[] PROGMEM_I1 = ISTR("Cont."); //// const char MSG_FS_PAUSE[] PROGMEM_I1 = ISTR("Pause"); //// +#ifdef LA_LIVE_K +const char MSG_ADVANCE_K[] PROGMEM_I1 = ISTR("Advance K:"); //// +#endif //not internationalized messages const char MSG_SD_WORKDIR_FAIL[] PROGMEM_N1 = "workDir open failed"; //// diff --git a/Firmware/messages.h b/Firmware/messages.h index 60a4cc1c..ec3ab96e 100644 --- a/Firmware/messages.h +++ b/Firmware/messages.h @@ -131,6 +131,9 @@ extern const char MSG_MAGNETS_COMP[]; extern const char MSG_FS_ACTION[]; extern const char MSG_FS_CONTINUE[]; extern const char MSG_FS_PAUSE[]; +#ifdef LA_LIVE_K +extern const char MSG_ADVANCE_K[]; +#endif //not internationalized messages extern const char MSG_BROWNOUT_RESET[]; diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index ddfab61f..9de5ec95 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -7065,14 +7065,14 @@ static void lcd_colorprint_change() { #ifdef LA_LIVE_K // @wavexx: looks like there's no generic float editing function in menu.cpp so we // redefine our custom handling functions to mimick other tunables -#define MSG_ADVANCE_K PSTR("Advance K:") +const char menu_fmt_float13off[] PROGMEM = "%c%-13.13S%6.6S"; static void lcd_advance_draw_K(char chr, float val) { if (val <= 0) - lcd_printf_P(menu_fmt_float13off, chr, MSG_ADVANCE_K, " [off]"); + lcd_printf_P(menu_fmt_float13off, chr, _T(MSG_ADVANCE_K), _T(MSG_OFF)); else - lcd_printf_P(menu_fmt_float13, chr, MSG_ADVANCE_K, val); + lcd_printf_P(menu_fmt_float13, chr, _T(MSG_ADVANCE_K), val); } static void lcd_advance_edit_K(void) From 7b29ce29b45c0bef41bfe604c43014ba88c2c139 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 21 Dec 2019 22:48:30 +0100 Subject: [PATCH 61/64] Add a Linear Advance 1.0->1.5 compatibility layer Allow existing gcode using LA10 to transparently take advantage of LA15 by using a simple linear conversion function based on experimental results with the MK3 implementation of linear advance. Autodetect LA10 values based on the first M900 instruction contained in the print. In order to support printing mixed files without resetting the printer we also reset the autodetection status when starting a new SD print and/or when explicitly disabling LA. Since we cannot reliably detect whether a new print is started when printing via USB, also reset the detection status when homing in G28, which is generally performed once at each print. Note that this doesn't clear the previous K value, it only allows a subsequent M900 to provide LA10 values when printed after a LA15 file. --- Firmware/Configuration_adv.h | 1 + Firmware/Marlin_main.cpp | 29 +++++++++++++++++++++++--- Firmware/la10compat.cpp | 40 ++++++++++++++++++++++++++++++++++++ Firmware/la10compat.h | 39 +++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 Firmware/la10compat.cpp create mode 100644 Firmware/la10compat.h diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 7f25f07d..d25b345c 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -287,6 +287,7 @@ #ifdef LIN_ADVANCE #define LIN_ADVANCE_K 0 // Unit: mm compression per 1mm/s extruder speed + //#define LA_NOCOMPAT // Disable Linear Advance 1.0 compatibility //#define LA_LIVE_K // Allow adjusting K in the Tune menu //#define LA_DEBUG // If enabled, this will generate debug information output over USB. //#define LA_DEBUG_LOGIC // @wavexx: setup logic channels for isr debugging diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 816763ac..8959bdd3 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -83,6 +83,9 @@ #include "Dcodes.h" #include "AutoDeplete.h" +#ifndef LA_NOCOMPAT +#include "la10compat.h" +#endif #ifdef SWSPI #include "swspi.h" @@ -2068,12 +2071,23 @@ static float probe_pt(float x, float y, float z_before) { */ inline void gcode_M900() { st_synchronize(); - + const float newK = code_seen('K') ? code_value_float() : -1; +#ifdef LA_NOCOMPAT if (newK >= 0 && newK < 10) - extruder_advance_K = newK; + extruder_advance_K = newK; else - SERIAL_ECHOLNPGM("K out of allowed range!"); + SERIAL_ECHOLNPGM("K out of allowed range!"); +#else + if (newK == 0) { + la10c_reset(); + extruder_advance_K = 0; + } + else if(newK > 0) + extruder_advance_K = la10c_value(newK); + else + SERIAL_ECHOLNPGM("K out of allowed range!"); +#endif SERIAL_ECHO_START; SERIAL_ECHOPGM("Advance K="); @@ -4136,6 +4150,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) // -------------------------------------------- case 28: { +#ifndef LA_NOCOMPAT + la10c_reset(); +#endif long home_x_value = 0; long home_y_value = 0; long home_z_value = 0; @@ -5372,6 +5389,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) else { failstats_reset_print(); +#ifndef LA_NOCOMPAT + la10c_reset(); +#endif card.startFileprint(); starttime=_millis(); } @@ -5465,6 +5485,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) if(code_seen('S')) if(strchr_pointerLA15 conversion +// +// When the current mode is UNKNOWN autodetection is active and any K<10 +// will set the mode to LA15, LA10 is set otherwise. When LA10 +// compatbility mode is active the K factor is converted to a LA15 +// equivalent (that is, the return value is always a LA15 value). +// +// Once the interpretation mode has been set it is kept until the mode +// is explicitly reset. This is done to handle transparent fallback for +// old firmware revisions in combination with the following gcode +// sequence: +// +// M900 K0.01 ; set LA15 value (interpreted by any firmware) +// M900 K10 ; set LA10 value (ignored by LA15 firmware) +// +// A LA15 firmware without this module will only parse the first +// correctly, rejecting the second. A LA10 FW will parse both, but keep +// the last value. Since the LA15 value, if present, corresponds to the +// truth value, the compatibility stub needs to "lock" onto the first +// seen value for the current print. +// +// The mode needs to be carefully reset for each print in order for +// diffent versions of M900 to be interpreted independently. + +#pragma once + +enum __attribute__((packed)) LA10C_MODE +{ + LA10C_UNKNOWN = 0, + LA10C_LA15 = 1, + LA10C_LA10 = 2 +}; + +// Explicitly set/reset the interpretation mode for la10c_value() +void la10c_mode_change(LA10C_MODE mode); +static inline void la10c_reset() { la10c_mode_change(LA10C_UNKNOWN); } + +// Return a LA15 K value according to the supplied value and mode +float la10c_value(float k); From d78636c308c0285fe2773d404c64811ecfea19a9 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 29 Dec 2019 23:25:16 +0100 Subject: [PATCH 62/64] Do not synchronize on M900 Since the advance factor is computed per-segment in LA15, there's no need to stop the planner. Allow changing K freely at each segment. This allows varying quality factors for different filling roles, see: https://github.com/supermerill/Slic3r/issues/108 During pause/resume/crashdetect or powerpanic K might temporarily be out of sync when used this way. If this becomes an issue, we might need to store K for each block, as done for the feedrate. --- Firmware/Marlin_main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 8959bdd3..9a0977ab 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -2070,8 +2070,6 @@ static float probe_pt(float x, float y, float z_before) { * K Set advance K factor */ inline void gcode_M900() { - st_synchronize(); - const float newK = code_seen('K') ? code_value_float() : -1; #ifdef LA_NOCOMPAT if (newK >= 0 && newK < 10) From fd0ed1f0eac44b5564110ce8db2d632dad13c66f Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 30 Dec 2019 11:32:27 +0100 Subject: [PATCH 63/64] Move LA reset from G28 to G80, do not reset on 0 In preparation for #2161, use MBL (G80) as a "new print" boundary instead of just re-homing to ensure the reset is issued only once for each print. Similarly, do not reset the autodetection when LA is disabled via M900 K0. This can/will be used during a print if different quality settings are used for different filling roles. --- Firmware/Marlin_main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 9a0977ab..97fbdf7f 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -2078,7 +2078,6 @@ inline void gcode_M900() { SERIAL_ECHOLNPGM("K out of allowed range!"); #else if (newK == 0) { - la10c_reset(); extruder_advance_K = 0; } else if(newK > 0) @@ -4148,9 +4147,6 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) // -------------------------------------------- case 28: { -#ifndef LA_NOCOMPAT - la10c_reset(); -#endif long home_x_value = 0; long home_y_value = 0; long home_z_value = 0; @@ -4674,6 +4670,11 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) case_G80: { mesh_bed_leveling_flag = true; +#ifndef LA_NOCOMPAT + // When printing via USB there's no clear boundary between prints. Abuse MBL to indicate + // the beginning of a new print, allowing a new autodetected setting just after G80. + la10c_reset(); +#endif #ifndef PINDA_THERMISTOR static bool run = false; // thermistor-less PINDA temperature compensation is running #endif // ndef PINDA_THERMISTOR From 86696156af0a17cfea873e01e7cf81d9f0a3e5a2 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 30 Dec 2019 13:17:12 +0100 Subject: [PATCH 64/64] Improve K error checking, allow to manually reset the version Properly check K independently for each version by delegating it to la10c_value() Handle -1 as a special case to allow manual reset. --- Firmware/Marlin_main.cpp | 17 +++++++++++------ Firmware/la10compat.cpp | 12 ++++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 97fbdf7f..71e952a5 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -2070,20 +2070,25 @@ static float probe_pt(float x, float y, float z_before) { * K Set advance K factor */ inline void gcode_M900() { - const float newK = code_seen('K') ? code_value_float() : -1; + float newK = code_seen('K') ? code_value_float() : -2; #ifdef LA_NOCOMPAT if (newK >= 0 && newK < 10) extruder_advance_K = newK; else SERIAL_ECHOLNPGM("K out of allowed range!"); #else - if (newK == 0) { + if (newK == 0) extruder_advance_K = 0; - } - else if(newK > 0) - extruder_advance_K = la10c_value(newK); + else if (newK == -1) + la10c_reset(); else - SERIAL_ECHOLNPGM("K out of allowed range!"); + { + newK = la10c_value(newK); + if (newK < 0) + SERIAL_ECHOLNPGM("K out of allowed range!"); + else + extruder_advance_K = newK; + } #endif SERIAL_ECHO_START; diff --git a/Firmware/la10compat.cpp b/Firmware/la10compat.cpp index 41c3a8e6..d54e5ace 100644 --- a/Firmware/la10compat.cpp +++ b/Firmware/la10compat.cpp @@ -31,10 +31,18 @@ static float la10c_convert(float k) float la10c_value(float k) { if(la10c_mode == LA10C_UNKNOWN) + { + // do not autodetect until a valid value is seen + if(k == 0) + return 0; + else if(k < 0) + return -1; + la10c_mode_change(k < 10? LA10C_LA15: LA10C_LA10); + } if(la10c_mode == LA10C_LA15) - return k; + return (k >= 0 && k < 10? k: -1); else - return la10c_convert(k); + return (k >= 0? la10c_convert(k): -1); }