From 469aa100974072bbec469608a84cd181b503f336 Mon Sep 17 00:00:00 2001 From: Marek Bel Date: Fri, 29 Mar 2019 07:27:29 +0100 Subject: [PATCH 01/76] Enable MMU cutter. --- Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h | 2 +- Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h | 2 +- Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h | 2 +- Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h | 2 +- Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h | 2 +- Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h index b5e9c1af0..cd6367422 100644 --- a/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25-RAMBo10a-E3Dv6full.h @@ -500,7 +500,7 @@ #define MMU_REQUIRED_FW_BUILDNR 132 #define MMU_FORCE_STEALTH_MODE #define MMU_DEBUG //print communication between MMU2 and printer on serial -//#define MMU_HAS_CUTTER +#define MMU_HAS_CUTTER #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning diff --git a/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h index 05b5e0923..4d76675ce 100644 --- a/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25-RAMBo13a-E3Dv6full.h @@ -501,7 +501,7 @@ #define MMU_REQUIRED_FW_BUILDNR 132 #define MMU_FORCE_STEALTH_MODE #define MMU_DEBUG //print communication between MMU2 and printer on serial -//#define MMU_HAS_CUTTER +#define MMU_HAS_CUTTER #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning diff --git a/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h index a1822970c..1c24d1a17 100644 --- a/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25S-RAMBo10a-E3Dv6full.h @@ -500,7 +500,7 @@ #define MMU_REQUIRED_FW_BUILDNR 132 #define MMU_FORCE_STEALTH_MODE #define MMU_DEBUG //print communication between MMU2 and printer on serial -//#define MMU_HAS_CUTTER +#define MMU_HAS_CUTTER #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning diff --git a/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h b/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h index 92773807c..997929941 100644 --- a/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK25S-RAMBo13a-E3Dv6full.h @@ -501,7 +501,7 @@ #define MMU_REQUIRED_FW_BUILDNR 132 #define MMU_FORCE_STEALTH_MODE #define MMU_DEBUG //print communication between MMU2 and printer on serial -//#define MMU_HAS_CUTTER +#define MMU_HAS_CUTTER #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning diff --git a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h index 4a1fe53cf..d5ff5dfa4 100644 --- a/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3-EINSy10a-E3Dv6full.h @@ -626,7 +626,7 @@ #define MMU_REQUIRED_FW_BUILDNR 83 #define MMU_HWRESET #define MMU_DEBUG //print communication between MMU2 and printer on serial -//#define MMU_HAS_CUTTER +#define MMU_HAS_CUTTER #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning #endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h index 1c0c6d28e..d0227fdf7 100644 --- a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h @@ -626,7 +626,7 @@ #define MMU_REQUIRED_FW_BUILDNR 83 #define MMU_HWRESET #define MMU_DEBUG //print communication between MMU2 and printer on serial -//#define MMU_HAS_CUTTER +#define MMU_HAS_CUTTER #define MMU_IDLER_SENSOR_ATTEMPTS_NR 21 //max. number of attempts to load filament if first load failed; value for max bowden length and case when loading fails right at the beginning #endif //__CONFIGURATION_PRUSA_H From eeea2725cba04a94c78bfd1cf58c7465087a6c25 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 17 Mar 2019 19:49:21 +0100 Subject: [PATCH 02/76] 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 f2df8fc6c..8ed2dd708 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 951302877..d731e8633 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 d37fbb38e..b9af28b7a 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 4a8d6659a..43c9f10b7 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 b6a9f8361..a99f02ede 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 03/76] Formatting sanity --- Firmware/planner.cpp | 134 +++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 69 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 43c9f10b7..a84411980 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 04/76] 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 a84411980..f8ac2f596 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 05/76] 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 74d25777c..c80581a5e 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 06/76] 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 d731e8633..455033024 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 a99f02ede..41e4c61bf 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 c80581a5e..6b52c5ace 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 6130f3bb1..23b791848 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 07/76] 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 6b52c5ace..5a3d4010a 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 08/76] 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 000000000..b8930e7bb --- /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 b7c00f1ae..6a1a44ef1 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 5a3d4010a..ddf69c8cb 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 09/76] 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 8ed2dd708..0bd13a3a1 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 10/76] 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 f8ac2f596..af87f77e6 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 11/76] 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 af87f77e6..76b53fbbc 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 12/76] 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 6a1a44ef1..2748dd71a 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 ddf69c8cb..19cd5d816 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 13/76] 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 455033024..d731e8633 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 76b53fbbc..078abac4c 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 41e4c61bf..56e1c66c3 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 19cd5d816..a98c8ff29 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 14/76] 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 a98c8ff29..8f0fef2ac 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 15/76] 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 8f0fef2ac..9339b4bf3 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 16/76] 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 d731e8633..e464b4de4 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 17/76] 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 078abac4c..0d0f3e36e 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 56e1c66c3..44c57ea5e 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 18/76] Typo --- Firmware/stepper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 9339b4bf3..5fc0006b3 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 19/76] 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 5fc0006b3..65f39c7d9 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 20/76] 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 0d0f3e36e..b9e693e7c 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 21/76] 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 b9e693e7c..466cd340c 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 22/76] 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 65f39c7d9..f0b39905f 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 23/76] 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 847e63c80..42bfd0d93 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 9800550b9..a129dfc82 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 97304adb2..8036c3a82 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 24/76] 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 f0b39905f..37898f9ce 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 25/76] 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 37898f9ce..b3e6427a8 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 26/76] 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 b3e6427a8..ffbfed195 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 27/76] 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 ffbfed195..4a34105e5 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 28/76] 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 4a34105e5..e45e5eaf5 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 29/76] 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 e464b4de4..f739cde26 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 8036c3a82..dd1da7201 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 30/76] 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 e45e5eaf5..63ded9d59 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 31/76] 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 63ded9d59..372f16f09 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 32/76] 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 466cd340c..ddf94cb81 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 33/76] 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 372f16f09..6eaa9003d 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 34/76] 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 6eaa9003d..ed265da61 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 35/76] 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 ed265da61..d0b1d3120 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 36/76] 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 f739cde26..9225ec250 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 d0b1d3120..fda9f11c7 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 37/76] 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 dd1da7201..ceccfbe57 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 38/76] 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 ceccfbe57..5d774eb14 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 39/76] 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 ddf94cb81..67aa3c9a1 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 40/76] 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 d520ba533..d296a6e74 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 71922fbfc..85992d39d 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 fda9f11c7..111d1fa7a 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 41/76] 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 d296a6e74..471518b22 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 85992d39d..1abf13b9a 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 42/76] 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 471518b22..563d37d65 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 43/76] 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 563d37d65..4ab87586c 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 1abf13b9a..e40568bb1 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 44/76] 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 67aa3c9a1..e1b04702a 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 45/76] 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 4ab87586c..29673231f 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 46/76] 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 b9af28b7a..663d36e57 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 c96e1d8db..624025e8b 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 47/76] 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 663d36e57..a1eec5a61 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 48/76] 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 111d1fa7a..68f36342f 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 49/76] 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 68f36342f..cd590013b 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 50/76] 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 e1b04702a..57c312e84 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 51/76] 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 57c312e84..c8f18f417 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 52/76] 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 cd590013b..6daddaa43 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 53/76] 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 a1eec5a61..c423df1bf 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 6daddaa43..ba5e84141 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 1bdb1f17a..7c41743cd 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 54/76] 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 c8f18f417..cb286c586 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 44c57ea5e..bb7b17c8a 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 ba5e84141..d6faee967 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 55/76] 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 9225ec250..50496704a 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 5d774eb14..dd1da7201 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 56/76] 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 d6faee967..b9d151266 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 57/76] 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 b9d151266..1283675c4 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 58/76] 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 1283675c4..b30f77e67 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 59/76] 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 b30f77e67..15e809b47 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 60/76] 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 6b4b3318f..4cd616cbb 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 608aa6ff3c1293cec62393c395adc188fb7a3b4c Mon Sep 17 00:00:00 2001 From: Marek Bel Date: Tue, 10 Sep 2019 18:49:23 +0200 Subject: [PATCH 61/76] Increase number of MMU load tries, so the same number of retries are done without cutter as before enabling cutter. --- Firmware/mmu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/mmu.cpp b/Firmware/mmu.cpp index f44bad97b..8f2c0400b 100755 --- a/Firmware/mmu.cpp +++ b/Firmware/mmu.cpp @@ -1566,7 +1566,7 @@ void mmu_continue_loading(bool blocking) }; Ls state = Ls::Enter; - const uint_least8_t max_retry = 2; + const uint_least8_t max_retry = 3; uint_least8_t retry = 0; while (!success) From 0b9123ce24a31f9247cc0af2282ede488dd8b641 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Thu, 5 Dec 2019 15:18:24 +0100 Subject: [PATCH 62/76] 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 2ab0c3659..88363359b 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 bb2e9510a..3c2fc9bb1 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 60a4cc1c1..ec3ab96ec 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 ddfab61f0..9de5ec95b 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 0cc68228f8c7b00ec99693e6da4bd6cfa7b1a524 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 14 Dec 2019 18:05:08 +0100 Subject: [PATCH 63/76] Unretract when resuming a paused print --- Firmware/Marlin.h | 1 + Firmware/Marlin_main.cpp | 4 ---- Firmware/ultralcd.cpp | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h index 7dedc8a4b..ad1407ae3 100755 --- a/Firmware/Marlin.h +++ b/Firmware/Marlin.h @@ -308,6 +308,7 @@ extern float max_pos[3]; extern bool axis_known_position[3]; extern int fanSpeed; extern int8_t lcd_change_fil_state; +extern float default_retraction; #ifdef TMC2130 void homeaxis(int axis, uint8_t cnt = 1, uint8_t* pstep = 0); diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 4970091ea..3327f8f8e 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -9571,10 +9571,6 @@ void long_pause() //long pause print // Stop heaters setAllTargetHotends(0); - //retract - current_position[E_AXIS] -= default_retraction; - plan_buffer_line_curposXYZE(400, active_extruder); - //lift z current_position[Z_AXIS] += Z_PAUSE_LIFT; if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS; diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 5d0abeac9..d29e40617 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -1662,7 +1662,7 @@ void lcd_return_to_status() //! @brief Pause print, disable nozzle heater, move to park position void lcd_pause_print() { - stop_and_save_print_to_ram(0.0,0.0); + stop_and_save_print_to_ram(0.0, -default_retraction); lcd_return_to_status(); isPrintPaused = true; if (LcdCommands::Idle == lcd_commands_type) @@ -6771,7 +6771,7 @@ void lcd_resume_print() if (fan_error_selftest()) return; //abort if error persists isPrintPaused = false; - restore_print_from_ram_and_continue(0.0); + restore_print_from_ram_and_continue(default_retraction); pause_time += (_millis() - start_pause_print); //accumulate time when print is paused for correct statistics calculation refresh_cmd_timeout(); SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_RESUMED); //resume octoprint From 7b29ce29b45c0bef41bfe604c43014ba88c2c139 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 21 Dec 2019 22:48:30 +0100 Subject: [PATCH 64/76] 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 7f25f07d5..d25b345c3 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 816763ac1..8959bdd31 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 a31319888c3d6660fc7ecd9869a6e5b2488339fc Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 23 Dec 2019 19:06:13 +0100 Subject: [PATCH 65/76] Fix fan_check_error check in usb print resume Also check for fan_check_error == EFCE_OK in addition to EFCE_FIXED. Reorganize the check in order to fix both #if[n]def FANCHECK cases, as similarly done in the SDSUPPORT case a few lines below. --- Firmware/ultralcd.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 5d0abeac9..588cb2480 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -6910,10 +6910,15 @@ static void lcd_main_menu() } + if(isPrintPaused && saved_printing_type == PRINTING_TYPE_USB) + { #ifdef FANCHECK - if((fan_check_error == EFCE_FIXED) && (saved_printing_type == PRINTING_TYPE_USB)) - MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT + if((fan_check_error == EFCE_FIXED) || (fan_check_error == EFCE_OK)) + MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT +#else + MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT #endif + } #ifdef SDSUPPORT if (card.cardOK || lcd_commands_type == LcdCommands::Layer1Cal) From f5d382f9f4d77b32f1779099cc7fad1f1277d7e9 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 28 Dec 2019 20:35:04 +0100 Subject: [PATCH 66/76] Remove useless st_synchronize calls when unparking --- Firmware/Marlin_main.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 4970091ea..994fba7bb 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -10312,12 +10312,10 @@ void restore_print_from_ram_and_continue(float e_move) //first move print head in XY to the saved position: plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], current_position[Z_AXIS], saved_pos[E_AXIS] - e_move, homing_feedrate[Z_AXIS]/13, active_extruder); - st_synchronize(); //then move Z plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS] - e_move, homing_feedrate[Z_AXIS]/13, active_extruder); - st_synchronize(); //and finaly unretract (35mm/s) - plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS], 35, active_extruder); + plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder); st_synchronize(); #ifdef FANCHECK From d78636c308c0285fe2773d404c64811ecfea19a9 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sun, 29 Dec 2019 23:25:16 +0100 Subject: [PATCH 67/76] 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 8959bdd31..9a0977ab3 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 68/76] 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 9a0977ab3..97fbdf7f7 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 57be14fca6d791a550be515fc1c074d11296dcbd Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Sat, 28 Dec 2019 20:26:19 +0100 Subject: [PATCH 69/76] Complete all pending moves before restoring a saved print --- Firmware/mmu.cpp | 1 + Firmware/ultralcd.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Firmware/mmu.cpp b/Firmware/mmu.cpp index 2bb2afa76..bc369fd53 100755 --- a/Firmware/mmu.cpp +++ b/Firmware/mmu.cpp @@ -1589,6 +1589,7 @@ void mmu_continue_loading(bool blocking) if (blocking) { marlin_wait_for_click(); + st_synchronize(); restore_print_from_ram_and_continue(0); state = Ls::Retry; } diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 5d0abeac9..f5b73d3ed 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -6764,12 +6764,13 @@ static bool fan_error_selftest() void lcd_resume_print() { lcd_return_to_status(); - lcd_reset_alert_level(); - lcd_setstatuspgm(_T(MSG_RESUMING_PRINT)); lcd_reset_alert_level(); //for fan speed error - if (fan_error_selftest()) return; //abort if error persists + lcd_setstatuspgm(_T(MSG_FINISHING_MOVEMENTS)); + st_synchronize(); + + lcd_setstatuspgm(_T(MSG_RESUMING_PRINT)); isPrintPaused = false; restore_print_from_ram_and_continue(0.0); pause_time += (_millis() - start_pause_print); //accumulate time when print is paused for correct statistics calculation From 86696156af0a17cfea873e01e7cf81d9f0a3e5a2 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 30 Dec 2019 13:17:12 +0100 Subject: [PATCH 70/76] 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 97fbdf7f7..71e952a58 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 41c3a8e6f..d54e5acea 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); } From 5660fcffb08841742103e67f32eb3cd3da30ae23 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Mon, 30 Dec 2019 14:49:07 +0100 Subject: [PATCH 71/76] Do not enqueue a E/Z moves unless requested Do not unconditionally enqueue a Z move if no move has been requested. Since Z is calculated using the absolute current (saved) position and scheduled for later execution, the queue order becomes relevant. --- Firmware/Marlin_main.cpp | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 3327f8f8e..c8e142c47 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -10238,23 +10238,29 @@ void stop_and_save_print_to_ram(float z_move, float e_move) // move away from the print. char buf[48]; - // First unretract (relative extrusion) - if(!saved_extruder_relative_mode){ - enquecommand(PSTR("M83"), true); - } - //retract 45mm/s - // A single sprintf may not be faster, but is definitely 20B shorter - // than a sequence of commands building the string piece by piece - // A snprintf would have been a safer call, but since it is not used - // in the whole program, its implementation would bring more bytes to the total size - // The behavior of dtostrf 8,3 should be roughly the same as %-0.3 - sprintf_P(buf, PSTR("G1 E%-0.3f F2700"), e_move); - enquecommand(buf, false); + if(e_move) + { + // First unretract (relative extrusion) + if(!saved_extruder_relative_mode){ + enquecommand(PSTR("M83"), true); + } + //retract 45mm/s + // A single sprintf may not be faster, but is definitely 20B shorter + // than a sequence of commands building the string piece by piece + // A snprintf would have been a safer call, but since it is not used + // in the whole program, its implementation would bring more bytes to the total size + // The behavior of dtostrf 8,3 should be roughly the same as %-0.3 + sprintf_P(buf, PSTR("G1 E%-0.3f F2700"), e_move); + enquecommand(buf, false); + } + + if(z_move) + { + // Then lift Z axis + sprintf_P(buf, PSTR("G1 Z%-0.3f F%-0.3f"), saved_pos[Z_AXIS] + z_move, homing_feedrate[Z_AXIS]); + enquecommand(buf, false); + } - // Then lift Z axis - sprintf_P(buf, PSTR("G1 Z%-0.3f F%-0.3f"), saved_pos[Z_AXIS] + z_move, homing_feedrate[Z_AXIS]); - // At this point the command queue is empty. - enquecommand(buf, false); // If this call is invoked from the main Arduino loop() function, let the caller know that the command // in the command queue is not the original command, but a new one, so it should not be removed from the queue. repeatcommand_front(); From f8a0d5d7737476f13c0699b1b9a879df4eddd78a Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Tue, 7 Jan 2020 19:51:30 +0200 Subject: [PATCH 72/76] Fix lcd_print_stop function --- Firmware/Marlin_main.cpp | 29 ++++++++++++----------- Firmware/ultralcd.cpp | 50 ++++++++++++++++++++++++++++++---------- 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 507a8f83e..62bfb68da 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -4692,13 +4692,13 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) // We don't know where we are! HOME! // Push the commands to the front of the message queue in the reverse order! // There shall be always enough space reserved for these commands. - if (lcd_commands_type != LcdCommands::StopPrint) { + // if (lcd_commands_type != LcdCommands::StopPrint) { repeatcommand_front(); // repeat G80 with all its parameters enquecommand_front_P((PSTR("G28 W0"))); - } - else { - mesh_bed_leveling_flag = false; - } + // } + // else { + // mesh_bed_leveling_flag = false; + // } break; } @@ -4728,23 +4728,23 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) #ifndef PINDA_THERMISTOR if (run == false && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) { - if (lcd_commands_type != LcdCommands::StopPrint) { + // if (lcd_commands_type != LcdCommands::StopPrint) { temp_compensation_start(); run = true; repeatcommand_front(); // repeat G80 with all its parameters enquecommand_front_P((PSTR("G28 W0"))); - } - else { - mesh_bed_leveling_flag = false; - } + // } + // else { + // mesh_bed_leveling_flag = false; + // } break; } run = false; #endif //PINDA_THERMISTOR - if (lcd_commands_type == LcdCommands::StopPrint) { - mesh_bed_leveling_flag = false; - break; - } + // if (lcd_commands_type == LcdCommands::StopPrint) { + // mesh_bed_leveling_flag = false; + // break; + // } // Save custom message state, set a new custom message state to display: Calibrating point 9. CustomMsg custom_message_type_old = custom_message_type; unsigned int custom_message_state_old = custom_message_state; @@ -8948,6 +8948,7 @@ static void wait_for_heater(long codenum, uint8_t extruder) { residencyStart = -1; /* continue to loop until we have reached the target temp _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */ + cancel_heatup = false; while ((!cancel_heatup) && ((residencyStart == -1) || (residencyStart >= 0 && (((unsigned int)(_millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL))))) { #else diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index d988e5488..d8b3e817b 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -250,7 +250,9 @@ static void fil_unload_menu(); static void lcd_disable_farm_mode(); static void lcd_set_fan_check(); static void lcd_cutter_enabled(); +#ifdef SNMM static char snmm_stop_print_menu(); +#endif //SNMM #ifdef SDCARD_SORT_ALPHA static void lcd_sort_type_set(); #endif @@ -1056,7 +1058,7 @@ static void lcd_status_screen() } if (current_click - && (lcd_commands_type != LcdCommands::StopPrint) //click is aborted unless stop print finishes + // && (lcd_commands_type != LcdCommands::StopPrint) //click is aborted unless stop print finishes && ( menu_block_entering_on_serious_errors == SERIOUS_ERR_NONE ) // or a serious error blocks entering the menu ) { @@ -1466,7 +1468,7 @@ void lcd_commands() } #endif // not SNMM - +/* if (lcd_commands_type == LcdCommands::StopPrint) /// stop print { @@ -1558,6 +1560,7 @@ void lcd_commands() lcd_commands_step = 7; } } +*/ if (lcd_commands_type == LcdCommands::FarmModeConfirm) /// farm mode confirm { @@ -6051,7 +6054,7 @@ void bowden_menu() { } } -//#ifdef SNMM +#ifdef SNMM static char snmm_stop_print_menu() { //menu for choosing which filaments will be unloaded in stop print lcd_clear(); @@ -6102,6 +6105,8 @@ static char snmm_stop_print_menu() { //menu for choosing which filaments will be } +#endif //SNMM + //! @brief Select one of numbered items //! //! Create list of items with header. Header can not be selected. @@ -7320,7 +7325,6 @@ void lcd_print_stop() // Clear any saved printing state cancel_saved_printing(); - cancel_heatup = true; // Abort the planner/queue/sd planner_abort_hard(); @@ -7331,19 +7335,41 @@ void lcd_print_stop() CRITICAL_SECTION_END; +#ifdef MESH_BED_LEVELING + mbl.active = false; //also prevents undoing the mbl compensation a second time in the second planner_abort_hard() +#endif + lcd_setstatuspgm(_T(MSG_PRINT_ABORTED)); stoptime = _millis(); unsigned long t = (stoptime - starttime - pause_time) / 1000; //time in s pause_time = 0; save_statistics(total_filament_used, t); - lcd_return_to_status(); - lcd_ignore_click(true); - lcd_commands_step = 0; - lcd_commands_type = LcdCommands::StopPrint; - // Turn off the print fan - SET_OUTPUT(FAN_PIN); - WRITE(FAN_PIN, 0); - fanSpeed = 0; + + lcd_commands_step = 0; + lcd_commands_type = LcdCommands::Idle; + + lcd_cooldown(); //turns off heaters and fan; goes to status screen. + cancel_heatup = true; //unroll temperature wait loop stack. + + current_position[Z_AXIS] += 10; //lift Z. + plan_buffer_line_curposXYZE(manual_feedrate[Z_AXIS] / 60, active_extruder); + + if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) //if axis are homed, move to parked position. + { + current_position[X_AXIS] = X_CANCEL_POS; + current_position[Y_AXIS] = Y_CANCEL_POS; + plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder); + } + st_synchronize(); + + if (mmu_enabled) extr_unload(); //M702 C + + finishAndDisableSteppers(); //M84 + + lcd_setstatuspgm(_T(WELCOME_MSG)); + custom_message_type = CustomMsg::Status; + + planner_abort_hard(); //needs to be done since plan_buffer_line resets waiting_inside_plan_buffer_line_print_aborted to false. Also copies current to destination. } void lcd_sdcard_stop() From 4422fc29f8c020347133e63b3fab67b4fd2cbe18 Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Tue, 7 Jan 2020 20:42:21 +0200 Subject: [PATCH 73/76] Set XYZ to absolute and E to relative --- Firmware/ultralcd.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index d8b3e817b..44e9b4371 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -7370,6 +7370,11 @@ void lcd_print_stop() custom_message_type = CustomMsg::Status; planner_abort_hard(); //needs to be done since plan_buffer_line resets waiting_inside_plan_buffer_line_print_aborted to false. Also copies current to destination. + + axis_relative_modes[X_AXIS] = false; + axis_relative_modes[Y_AXIS] = false; + axis_relative_modes[Z_AXIS] = false; + axis_relative_modes[E_AXIS] = true; } void lcd_sdcard_stop() From 1996fc79409789d09dcc4c8bb21b4732df920679 Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Tue, 7 Jan 2020 20:43:56 +0200 Subject: [PATCH 74/76] Remove commented-out code --- Firmware/Marlin_main.cpp | 26 +++-------- Firmware/ultralcd.cpp | 94 ---------------------------------------- 2 files changed, 6 insertions(+), 114 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 62bfb68da..94dd7dba4 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -4692,13 +4692,8 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) // We don't know where we are! HOME! // Push the commands to the front of the message queue in the reverse order! // There shall be always enough space reserved for these commands. - // if (lcd_commands_type != LcdCommands::StopPrint) { - repeatcommand_front(); // repeat G80 with all its parameters - enquecommand_front_P((PSTR("G28 W0"))); - // } - // else { - // mesh_bed_leveling_flag = false; - // } + repeatcommand_front(); // repeat G80 with all its parameters + enquecommand_front_P((PSTR("G28 W0"))); break; } @@ -4728,23 +4723,14 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) #ifndef PINDA_THERMISTOR if (run == false && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) { - // if (lcd_commands_type != LcdCommands::StopPrint) { - temp_compensation_start(); - run = true; - repeatcommand_front(); // repeat G80 with all its parameters - enquecommand_front_P((PSTR("G28 W0"))); - // } - // else { - // mesh_bed_leveling_flag = false; - // } + temp_compensation_start(); + run = true; + repeatcommand_front(); // repeat G80 with all its parameters + enquecommand_front_P((PSTR("G28 W0"))); break; } run = false; #endif //PINDA_THERMISTOR - // if (lcd_commands_type == LcdCommands::StopPrint) { - // mesh_bed_leveling_flag = false; - // break; - // } // Save custom message state, set a new custom message state to display: Calibrating point 9. CustomMsg custom_message_type_old = custom_message_type; unsigned int custom_message_state_old = custom_message_state; diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 44e9b4371..75d233620 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -1058,7 +1058,6 @@ static void lcd_status_screen() } if (current_click - // && (lcd_commands_type != LcdCommands::StopPrint) //click is aborted unless stop print finishes && ( menu_block_entering_on_serious_errors == SERIOUS_ERR_NONE ) // or a serious error blocks entering the menu ) { @@ -1468,99 +1467,6 @@ void lcd_commands() } #endif // not SNMM -/* - if (lcd_commands_type == LcdCommands::StopPrint) /// stop print - { - - - if (lcd_commands_step == 0) - { - lcd_commands_step = 6; - } - - if (lcd_commands_step == 1 && !blocks_queued()) - { - lcd_commands_step = 0; - lcd_commands_type = LcdCommands::Idle; - lcd_setstatuspgm(_T(WELCOME_MSG)); - custom_message_type = CustomMsg::Status; - isPrintPaused = false; - } - if (lcd_commands_step == 2 && !blocks_queued()) - { - setTargetBed(0); - enquecommand_P(PSTR("M104 S0")); //set hotend temp to 0 - - manage_heater(); - lcd_setstatuspgm(_T(WELCOME_MSG)); - cancel_heatup = false; - lcd_commands_step = 1; - } - if (lcd_commands_step == 3 && !blocks_queued()) - { - // M84: Disable steppers. - enquecommand_P(PSTR("M84")); - autotempShutdown(); - lcd_commands_step = 2; - } - if (lcd_commands_step == 4 && !blocks_queued()) - { - lcd_setstatuspgm(_T(MSG_PLEASE_WAIT)); - // G90: Absolute positioning. - enquecommand_P(PSTR("G90")); - // M83: Set extruder to relative mode. - enquecommand_P(PSTR("M83")); - #ifdef X_CANCEL_POS - enquecommand_P(PSTR("G1 X" STRINGIFY(X_CANCEL_POS) " Y" STRINGIFY(Y_CANCEL_POS) " E0 F7000")); - #else - enquecommand_P(PSTR("G1 X50 Y" STRINGIFY(Y_MAX_POS) " E0 F7000")); - #endif - lcd_ignore_click(false); - if (mmu_enabled) - lcd_commands_step = 8; - else - lcd_commands_step = 3; - } - if (lcd_commands_step == 5 && !blocks_queued()) - { - lcd_setstatuspgm(_T(MSG_PRINT_ABORTED)); - // G91: Set to relative positioning. - enquecommand_P(PSTR("G91")); - // Lift up. - enquecommand_P(PSTR("G1 Z15 F1500")); - if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) lcd_commands_step = 4; - else lcd_commands_step = 3; - } - if (lcd_commands_step == 6 && !blocks_queued()) - { - lcd_setstatuspgm(_T(MSG_PRINT_ABORTED)); - cancel_heatup = true; - setTargetBed(0); - if (mmu_enabled) - setAllTargetHotends(0); - manage_heater(); - custom_message_type = CustomMsg::FilamentLoading; - lcd_commands_step = 5; - } - if (lcd_commands_step == 7 && !blocks_queued()) - { - if (mmu_enabled) - enquecommand_P(PSTR("M702 C")); //current - else - switch(snmm_stop_print_menu()) - { - case 0: enquecommand_P(PSTR("M702")); break;//all - case 1: enquecommand_P(PSTR("M702 U")); break; //used - case 2: enquecommand_P(PSTR("M702 C")); break; //current - default: enquecommand_P(PSTR("M702")); break; - } - lcd_commands_step = 3; - } - if (lcd_commands_step == 8 && !blocks_queued()) { //step 8 is here for delay (going to next step after execution of all gcodes from step 4) - lcd_commands_step = 7; - } - } -*/ if (lcd_commands_type == LcdCommands::FarmModeConfirm) /// farm mode confirm { From d9e52835260b5780f076551ca35c1c4cb3eb5453 Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Tue, 7 Jan 2020 21:02:13 +0200 Subject: [PATCH 75/76] Fix pause->stop->PrintFromSD scenario --- Firmware/ultralcd.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 75d233620..75031f46b 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -7281,6 +7281,8 @@ void lcd_print_stop() axis_relative_modes[Y_AXIS] = false; axis_relative_modes[Z_AXIS] = false; axis_relative_modes[E_AXIS] = true; + + isPrintPaused = false; //clear isPrintPaused flag to allow starting next print after pause->stop scenario. } void lcd_sdcard_stop() From bab756699f182a1733e62b2d59926bb09f8a9152 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Tue, 14 Jan 2020 20:24:14 +0100 Subject: [PATCH 76/76] Fix incorrect usage of plan_set_e_position() in G92 E* To maintain an accurate step count (which is required for correct position recovery), any call to plan_set_position&co needs to be done synchronously and from a halted state. However, G92 E* is currently special-cased to skip the sync (likely to avoid the associated performance cost), causing an incorrect E step count and position to be set. This breaks absolute position recovery, miscalculation of the LA factor and possibly other weird issues. We rewrite the handling of G92 to always sync but still special-case the frequent "G92 E0" for performance by using a free bit in the block flags. To avoid a sync, we relay the request for reset first to the planner which clears its internal state and then relays the request to the final stepper isr. --- Firmware/Marlin_main.cpp | 63 ++++++++++++++++++++++++++++++---------- Firmware/planner.cpp | 35 ++++++++++++++++++++++ Firmware/planner.h | 5 ++++ Firmware/stepper.cpp | 4 +++ 4 files changed, 91 insertions(+), 16 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 72a24312c..1cea6c59d 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -3356,6 +3356,49 @@ static void gcode_PRUSA_BadRAMBoFanTest(){ #endif } + +// G92 - Set current position to coordinates given +static void gcode_G92() +{ + bool codes[NUM_AXIS]; + float values[NUM_AXIS]; + + // Check which axes need to be set + for(uint8_t i = 0; i < NUM_AXIS; ++i) + { + codes[i] = code_seen(axis_codes[i]); + if(codes[i]) + values[i] = code_value(); + } + + if((codes[E_AXIS] && values[E_AXIS] == 0) && + (!codes[X_AXIS] && !codes[Y_AXIS] && !codes[Z_AXIS])) + { + // As a special optimization, when _just_ clearing the E position + // we schedule a flag asynchronously along with the next block to + // reset the starting E position instead of stopping the planner + current_position[E_AXIS] = 0; + plan_reset_next_e(); + } + else + { + // In any other case we're forced to synchronize + st_synchronize(); + for(uint8_t i = 0; i < 3; ++i) + { + if(codes[i]) + current_position[i] = values[i] + cs.add_homing[i]; + } + if(codes[E_AXIS]) + current_position[E_AXIS] = values[E_AXIS]; + + // Set all at once + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], + current_position[Z_AXIS], current_position[E_AXIS]); + } +} + + #ifdef BACKLASH_X extern uint8_t st_backlash_x; #endif //BACKLASH_X @@ -5217,22 +5260,10 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) //! ### G92 - Set position // ----------------------------- - case 92: - if(!code_seen(axis_codes[E_AXIS])) - st_synchronize(); - for(int8_t i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) { - if(i == E_AXIS) { - current_position[i] = code_value(); - plan_set_e_position(current_position[E_AXIS]); - } - else { - current_position[i] = code_value()+cs.add_homing[i]; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - } - } - } - break; + case 92: { + gcode_G92(); + } + break; //! ### G98 - Activate farm mode diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index f5270d4a2..8c26cef9b 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -130,6 +130,10 @@ float extruder_advance_K = LIN_ADVANCE_K; float position_float[NUM_AXIS]; #endif +// Request the next block to start at zero E count +static bool plan_reset_next_e_queue; +static bool plan_reset_next_e_sched; + // Returns the index of the next block in the ring buffer // NOTE: Removed modulo (%) operator, which uses an expensive divide and multiplication. static inline int8_t next_block_index(int8_t block_index) { @@ -441,6 +445,8 @@ void plan_init() { previous_speed[2] = 0.0; previous_speed[3] = 0.0; previous_nominal_speed = 0.0; + plan_reset_next_e_queue = false; + plan_reset_next_e_sched = false; } @@ -658,6 +664,9 @@ void planner_abort_hard() previous_speed[2] = 0.0; previous_speed[3] = 0.0; + plan_reset_next_e_queue = false; + plan_reset_next_e_sched = false; + // Relay to planner wait routine, that the current line shall be canceled. waiting_inside_plan_buffer_line_print_aborted = true; } @@ -721,6 +730,20 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate // Save the global feedrate at scheduling time block->gcode_feedrate = feedrate; + // Reset the starting E position when requested + if (plan_reset_next_e_queue) + { + position[E_AXIS] = 0; +#ifdef LIN_ADVANCE + position_float[E_AXIS] = 0; +#endif + + // the block might still be discarded later, but we need to ensure the lower-level + // count_position is also reset correctly for consistent results! + plan_reset_next_e_queue = false; + plan_reset_next_e_sched = true; + } + #ifdef ENABLE_AUTO_BED_LEVELING apply_rotation_xyz(plan_bed_level_matrix, x, y, z); #endif // ENABLE_AUTO_BED_LEVELING @@ -1165,6 +1188,13 @@ Having the real displacement of the head, we can calculate the total movement le // Reset the block flag. block->flag = 0; + if (plan_reset_next_e_sched) + { + // finally propagate a pending reset + block->flag |= BLOCK_FLAG_E_RESET; + plan_reset_next_e_sched = false; + } + // Initial limit on the segment entry velocity. float vmax_junction; @@ -1367,6 +1397,11 @@ void plan_set_e_position(const float &e) st_set_e_position(position[E_AXIS]); } +void plan_reset_next_e() +{ + plan_reset_next_e_queue = true; +} + #ifdef PREVENT_DANGEROUS_EXTRUDE void set_extrude_min_temp(float temp) { diff --git a/Firmware/planner.h b/Firmware/planner.h index 8cb3218c1..23509acfc 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -44,6 +44,8 @@ enum BlockFlag { // than 32767, therefore the DDA algorithm may run with 16bit resolution only. // In addition, the stepper routine will not do any end stop checking for higher performance. BLOCK_FLAG_DDA_LOWRES = 8, + // Block starts with Zeroed E counter + BLOCK_FLAG_E_RESET = 16, }; union dda_isteps_t @@ -168,6 +170,9 @@ void plan_set_position(float x, float y, float z, const float &e); void plan_set_z_position(const float &z); void plan_set_e_position(const float &e); +// Reset the E position to zero at the start of the next segment +void plan_reset_next_e(); + extern bool e_active(); void check_axes_activity(); diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index ff17c845c..74625a633 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -362,6 +362,10 @@ FORCE_INLINE void stepper_next_block() LA_phase = -1; #endif + if (current_block->flag & BLOCK_FLAG_E_RESET) { + count_position[E_AXIS] = 0; + } + if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) { counter_x.lo = -(current_block->step_event_count.lo >> 1); counter_y.lo = counter_x.lo;