diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index f2df8fc6..0bd13a3a 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -165,8 +165,8 @@ void Config_PrintSettings(uint8_t level) #endif if (level >= 10) { #ifdef LIN_ADVANCE - printf_P(PSTR("%SLinear advance settings:\n M900 K%.2f E/D = %.2f\n"), - echomagic, extruder_advance_k, advance_ed_ratio); + printf_P(PSTR("%SLinear advance settings:%S M900 K%.2f\n"), + echomagic, echomagic, extruder_advance_K); #endif //LIN_ADVANCE } } diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index dd77c91c..d25b345c 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -268,43 +268,29 @@ #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 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. + * 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_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 #endif // Arc interpretation settings: diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 6684cf68..86fa2044 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" @@ -357,9 +360,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 @@ -384,7 +384,6 @@ static uint16_t saved_feedrate2 = 0; //!< Default feedrate (truncated from float static int saved_feedmultiply2 = 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 //! @} @@ -2062,35 +2061,36 @@ 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; + 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) + extruder_advance_K = 0; + else if (newK == -1) + la10c_reset(); + else + { + newK = la10c_value(newK); + if (newK < 0) + SERIAL_ECHOLNPGM("K out of allowed range!"); + else + extruder_advance_K = newK; } - if (newR >= 0) advance_ed_ratio = newR; - +#endif + 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() { @@ -4677,6 +4677,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 @@ -5394,6 +5399,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) else { failstats_reset_print(); +#ifndef LA_NOCOMPAT + la10c_reset(); +#endif card.startFileprint(); starttime=_millis(); } @@ -5487,6 +5495,9 @@ if(eSoundMode!=e_SOUND_MODE_SILENT) if(code_seen('S')) if(strchr_pointer #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" @@ -261,7 +258,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; @@ -534,23 +531,11 @@ void fsensor_setup_interrupt(void) #endif //PAT9125 -void fsensor_st_block_begin(block_t* bl) +void fsensor_st_block_chunk(int cnt) { if (!fsensor_enabled) return; - if (((fsensor_st_cnt > 0) && (bl->direction_bits & 0x8)) || - ((fsensor_st_cnt < 0) && !(bl->direction_bits & 0x8))) - { -// !!! 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);} - } -} - -void fsensor_st_block_chunk(block_t* bl, 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 aa4963af..5ed7f7fc 100755 --- a/Firmware/fsensor.h +++ b/Firmware/fsensor.h @@ -60,12 +60,15 @@ 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(block_t* bl); -extern void fsensor_st_block_chunk(block_t* bl, int cnt); +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) //! @} diff --git a/Firmware/la10compat.cpp b/Firmware/la10compat.cpp new file mode 100644 index 00000000..d54e5ace --- /dev/null +++ b/Firmware/la10compat.cpp @@ -0,0 +1,48 @@ +#include "la10compat.h" +#include "Marlin.h" + + +static LA10C_MODE la10c_mode = LA10C_UNKNOWN; + + +void la10c_mode_change(LA10C_MODE mode) +{ + if(mode == la10c_mode) return; + + SERIAL_ECHOPGM("LA10C: Linear Advance mode: "); + switch(mode) + { + case LA10C_UNKNOWN: SERIAL_ECHOLNPGM("UNKNOWN"); break; + case LA10C_LA15: SERIAL_ECHOLNPGM("1.5"); break; + case LA10C_LA10: SERIAL_ECHOLNPGM("1.0"); break; + } + la10c_mode = mode; +} + + +// Approximate a LA10 value to a LA15 equivalent. +static float la10c_convert(float k) +{ + float new_K = k * 0.004 - 0.06; + return (new_K < 0? 0: new_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 >= 0 && k < 10? k: -1); + else + return (k >= 0? la10c_convert(k): -1); +} diff --git a/Firmware/la10compat.h b/Firmware/la10compat.h new file mode 100644 index 00000000..e6ffbc37 --- /dev/null +++ b/Firmware/la10compat.h @@ -0,0 +1,39 @@ +// la10compat: LA10->LA15 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); diff --git a/Firmware/menu.cpp b/Firmware/menu.cpp index 38f5d4e8..d31dce7e 100755 --- a/Firmware/menu.cpp +++ b/Firmware/menu.cpp @@ -102,7 +102,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) { @@ -136,7 +136,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 a9526c31..88363359 100755 --- a/Firmware/menu.h +++ b/Firmware/menu.h @@ -76,6 +76,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); @@ -83,6 +84,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); @@ -131,7 +133,6 @@ extern const char menu_fmt_int3[]; extern const char menu_fmt_float31[]; extern const char menu_fmt_float13[]; - extern void menu_draw_float31(const char* str, float val); extern void menu_draw_float13(const char* str, float val); diff --git a/Firmware/messages.c b/Firmware/messages.c index 3813b89d..68bad5ff 100644 --- a/Firmware/messages.c +++ b/Firmware/messages.c @@ -168,3 +168,6 @@ const char MSG_OCTOPRINT_CANCEL[] PROGMEM_N1 = "// action:cancel"; //// const char MSG_FANCHECK_EXTRUDER[] PROGMEM_N1 = "Err: EXTR. FAN ERROR"; ////c=20 const char MSG_FANCHECK_PRINT[] PROGMEM_N1 = "Err: PRINT FAN ERROR"; ////c=20 const char MSG_M112_KILL[] PROGMEM_N1 = "M112 called. Emergency Stop."; ////c=20 +#ifdef LA_LIVE_K +const char MSG_ADVANCE_K[] PROGMEM_N1 = "Advance K:"; ////c=13 +#endif diff --git a/Firmware/messages.h b/Firmware/messages.h index 0a6710b9..678524ab 100644 --- a/Firmware/messages.h +++ b/Firmware/messages.h @@ -169,6 +169,7 @@ extern const char MSG_OCTOPRINT_CANCEL[]; extern const char MSG_FANCHECK_EXTRUDER[]; extern const char MSG_FANCHECK_PRINT[]; extern const char MSG_M112_KILL[]; +extern const char MSG_ADVANCE_K[]; #if defined(__cplusplus) } diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 0ccf54f8..f5270d4a 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -126,9 +126,8 @@ 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, - position_float[NUM_AXIS] = { 0 }; +float extruder_advance_K = LIN_ADVANCE_K; +float position_float[NUM_AXIS]; #endif // Returns the index of the next block in the ring buffer @@ -262,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. @@ -272,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; } @@ -424,9 +433,9 @@ void plan_init() { block_buffer_head = 0; block_buffer_tail = 0; memset(position, 0, sizeof(position)); // clear position -#ifdef LIN_ADVANCE - memset(position_float, 0, sizeof(position)); // clear position -#endif + #ifdef LIN_ADVANCE + memset(position_float, 0, sizeof(position_float)); // clear position + #endif previous_speed[0] = 0.0; previous_speed[1] = 0.0; previous_speed[2] = 0.0; @@ -639,7 +648,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; @@ -775,21 +786,15 @@ 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]) { 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; - de_float = 0; -#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 } @@ -1012,6 +1016,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. @@ -1019,10 +1026,51 @@ 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 within this block if all these are true: + * + * block->steps_e : This is a print move, because we checked for X, Y, Z steps before. + * extruder_advance_K : There is an advance factor set. + * delta_mm[E_AXIS] > 0 : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves) + * |delta_mm[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 + && abs(delta_mm[Z_AXIS]) < 0.5; + if (block->use_advance_lead) { + 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 (e_D_ratio > 3.0) + block->use_advance_lead = false; + else { + const uint32_t max_accel_steps_per_s2 = cs.max_jerk[E_AXIS] / (extruder_advance_K * e_D_ratio) * steps_per_mm; + if (block->acceleration_st > max_accel_steps_per_s2) { + block->acceleration_st = max_accel_steps_per_s2; + #ifdef LA_DEBUG + SERIAL_ECHOLNPGM("LA: Block acceleration limited due to max E-jerk"); + #endif + } + } + } + #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]) @@ -1055,6 +1103,40 @@ 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) { + // 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 * 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) { + block->advance_rate = (block->advance_rate >> 2)&0x3fff; + block->advance_step_loops = 4; + } + 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; + + #ifdef LA_DEBUG + if (block->advance_step_loops > 2) + // @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 + // 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; @@ -1171,37 +1253,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); @@ -1215,12 +1266,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). @@ -1283,12 +1334,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; @@ -1300,11 +1351,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) diff --git a/Firmware/planner.h b/Firmware/planner.h index 0d0cb41a..8cb3218c 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -110,10 +110,14 @@ 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; - unsigned long abs_adv_steps_multiplier8; // Factorised by 2^8 to avoid float + bool use_advance_lead; // Whether the current block uses LA + 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 adv_comp; // Precomputed E compression factor #endif // Save/recovery state data @@ -123,7 +127,7 @@ typedef struct { } block_t; #ifdef LIN_ADVANCE - extern float extruder_advance_k, advance_ed_ratio; +extern float extruder_advance_K; // Linear-advance K factor #endif #ifdef ENABLE_AUTO_BED_LEVELING diff --git a/Firmware/speed_lookuptable.cpp b/Firmware/speed_lookuptable.cpp new file mode 100644 index 00000000..b8930e7b --- /dev/null +++ b/Firmware/speed_lookuptable.cpp @@ -0,0 +1,147 @@ +#include "speed_lookuptable.h" + +#if F_CPU == 16000000 + +const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {\ +{ 62500, 55556}, { 6944, 3268}, { 3676, 1176}, { 2500, 607}, { 1893, 369}, { 1524, 249}, { 1275, 179}, { 1096, 135}, +{ 961, 105}, { 856, 85}, { 771, 69}, { 702, 58}, { 644, 49}, { 595, 42}, { 553, 37}, { 516, 32}, +{ 484, 28}, { 456, 25}, { 431, 23}, { 408, 20}, { 388, 19}, { 369, 16}, { 353, 16}, { 337, 14}, +{ 323, 13}, { 310, 11}, { 299, 11}, { 288, 11}, { 277, 9}, { 268, 9}, { 259, 8}, { 251, 8}, +{ 243, 8}, { 235, 7}, { 228, 6}, { 222, 6}, { 216, 6}, { 210, 6}, { 204, 5}, { 199, 5}, +{ 194, 5}, { 189, 4}, { 185, 4}, { 181, 4}, { 177, 4}, { 173, 4}, { 169, 4}, { 165, 3}, +{ 162, 3}, { 159, 4}, { 155, 3}, { 152, 3}, { 149, 2}, { 147, 3}, { 144, 3}, { 141, 2}, +{ 139, 3}, { 136, 2}, { 134, 2}, { 132, 3}, { 129, 2}, { 127, 2}, { 125, 2}, { 123, 2}, +{ 121, 2}, { 119, 1}, { 118, 2}, { 116, 2}, { 114, 1}, { 113, 2}, { 111, 2}, { 109, 1}, +{ 108, 2}, { 106, 1}, { 105, 2}, { 103, 1}, { 102, 1}, { 101, 1}, { 100, 2}, { 98, 1}, +{ 97, 1}, { 96, 1}, { 95, 2}, { 93, 1}, { 92, 1}, { 91, 1}, { 90, 1}, { 89, 1}, +{ 88, 1}, { 87, 1}, { 86, 1}, { 85, 1}, { 84, 1}, { 83, 0}, { 83, 1}, { 82, 1}, +{ 81, 1}, { 80, 1}, { 79, 1}, { 78, 0}, { 78, 1}, { 77, 1}, { 76, 1}, { 75, 0}, +{ 75, 1}, { 74, 1}, { 73, 1}, { 72, 0}, { 72, 1}, { 71, 1}, { 70, 0}, { 70, 1}, +{ 69, 0}, { 69, 1}, { 68, 1}, { 67, 0}, { 67, 1}, { 66, 0}, { 66, 1}, { 65, 0}, +{ 65, 1}, { 64, 1}, { 63, 0}, { 63, 1}, { 62, 0}, { 62, 1}, { 61, 0}, { 61, 1}, +{ 60, 0}, { 60, 0}, { 60, 1}, { 59, 0}, { 59, 1}, { 58, 0}, { 58, 1}, { 57, 0}, +{ 57, 1}, { 56, 0}, { 56, 0}, { 56, 1}, { 55, 0}, { 55, 1}, { 54, 0}, { 54, 0}, +{ 54, 1}, { 53, 0}, { 53, 0}, { 53, 1}, { 52, 0}, { 52, 0}, { 52, 1}, { 51, 0}, +{ 51, 0}, { 51, 1}, { 50, 0}, { 50, 0}, { 50, 1}, { 49, 0}, { 49, 0}, { 49, 1}, +{ 48, 0}, { 48, 0}, { 48, 1}, { 47, 0}, { 47, 0}, { 47, 0}, { 47, 1}, { 46, 0}, +{ 46, 0}, { 46, 1}, { 45, 0}, { 45, 0}, { 45, 0}, { 45, 1}, { 44, 0}, { 44, 0}, +{ 44, 0}, { 44, 1}, { 43, 0}, { 43, 0}, { 43, 0}, { 43, 1}, { 42, 0}, { 42, 0}, +{ 42, 0}, { 42, 1}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 1}, { 40, 0}, +{ 40, 0}, { 40, 0}, { 40, 0}, { 40, 1}, { 39, 0}, { 39, 0}, { 39, 0}, { 39, 0}, +{ 39, 1}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 1}, { 37, 0}, { 37, 0}, +{ 37, 0}, { 37, 0}, { 37, 0}, { 37, 1}, { 36, 0}, { 36, 0}, { 36, 0}, { 36, 0}, +{ 36, 1}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 1}, +{ 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 1}, { 33, 0}, { 33, 0}, +{ 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 1}, { 32, 0}, { 32, 0}, { 32, 0}, +{ 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 1}, { 31, 0}, { 31, 0}, { 31, 0}, +{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0} +}; + +const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {\ +{ 62500, 12500}, { 50000, 8334}, { 41666, 5952}, { 35714, 4464}, { 31250, 3473}, { 27777, 2777}, { 25000, 2273}, { 22727, 1894}, +{ 20833, 1603}, { 19230, 1373}, { 17857, 1191}, { 16666, 1041}, { 15625, 920}, { 14705, 817}, { 13888, 731}, { 13157, 657}, +{ 12500, 596}, { 11904, 541}, { 11363, 494}, { 10869, 453}, { 10416, 416}, { 10000, 385}, { 9615, 356}, { 9259, 331}, +{ 8928, 308}, { 8620, 287}, { 8333, 269}, { 8064, 252}, { 7812, 237}, { 7575, 223}, { 7352, 210}, { 7142, 198}, +{ 6944, 188}, { 6756, 178}, { 6578, 168}, { 6410, 160}, { 6250, 153}, { 6097, 145}, { 5952, 139}, { 5813, 132}, +{ 5681, 126}, { 5555, 121}, { 5434, 115}, { 5319, 111}, { 5208, 106}, { 5102, 102}, { 5000, 99}, { 4901, 94}, +{ 4807, 91}, { 4716, 87}, { 4629, 84}, { 4545, 81}, { 4464, 79}, { 4385, 75}, { 4310, 73}, { 4237, 71}, +{ 4166, 68}, { 4098, 66}, { 4032, 64}, { 3968, 62}, { 3906, 60}, { 3846, 59}, { 3787, 56}, { 3731, 55}, +{ 3676, 53}, { 3623, 52}, { 3571, 50}, { 3521, 49}, { 3472, 48}, { 3424, 46}, { 3378, 45}, { 3333, 44}, +{ 3289, 43}, { 3246, 41}, { 3205, 41}, { 3164, 39}, { 3125, 39}, { 3086, 38}, { 3048, 36}, { 3012, 36}, +{ 2976, 35}, { 2941, 35}, { 2906, 33}, { 2873, 33}, { 2840, 32}, { 2808, 31}, { 2777, 30}, { 2747, 30}, +{ 2717, 29}, { 2688, 29}, { 2659, 28}, { 2631, 27}, { 2604, 27}, { 2577, 26}, { 2551, 26}, { 2525, 25}, +{ 2500, 25}, { 2475, 25}, { 2450, 23}, { 2427, 24}, { 2403, 23}, { 2380, 22}, { 2358, 22}, { 2336, 22}, +{ 2314, 21}, { 2293, 21}, { 2272, 20}, { 2252, 20}, { 2232, 20}, { 2212, 20}, { 2192, 19}, { 2173, 18}, +{ 2155, 19}, { 2136, 18}, { 2118, 18}, { 2100, 17}, { 2083, 17}, { 2066, 17}, { 2049, 17}, { 2032, 16}, +{ 2016, 16}, { 2000, 16}, { 1984, 16}, { 1968, 15}, { 1953, 16}, { 1937, 14}, { 1923, 15}, { 1908, 15}, +{ 1893, 14}, { 1879, 14}, { 1865, 14}, { 1851, 13}, { 1838, 14}, { 1824, 13}, { 1811, 13}, { 1798, 13}, +{ 1785, 12}, { 1773, 13}, { 1760, 12}, { 1748, 12}, { 1736, 12}, { 1724, 12}, { 1712, 12}, { 1700, 11}, +{ 1689, 12}, { 1677, 11}, { 1666, 11}, { 1655, 11}, { 1644, 11}, { 1633, 10}, { 1623, 11}, { 1612, 10}, +{ 1602, 10}, { 1592, 10}, { 1582, 10}, { 1572, 10}, { 1562, 10}, { 1552, 9}, { 1543, 10}, { 1533, 9}, +{ 1524, 9}, { 1515, 9}, { 1506, 9}, { 1497, 9}, { 1488, 9}, { 1479, 9}, { 1470, 9}, { 1461, 8}, +{ 1453, 8}, { 1445, 9}, { 1436, 8}, { 1428, 8}, { 1420, 8}, { 1412, 8}, { 1404, 8}, { 1396, 8}, +{ 1388, 7}, { 1381, 8}, { 1373, 7}, { 1366, 8}, { 1358, 7}, { 1351, 7}, { 1344, 8}, { 1336, 7}, +{ 1329, 7}, { 1322, 7}, { 1315, 7}, { 1308, 6}, { 1302, 7}, { 1295, 7}, { 1288, 6}, { 1282, 7}, +{ 1275, 6}, { 1269, 7}, { 1262, 6}, { 1256, 6}, { 1250, 7}, { 1243, 6}, { 1237, 6}, { 1231, 6}, +{ 1225, 6}, { 1219, 6}, { 1213, 6}, { 1207, 6}, { 1201, 5}, { 1196, 6}, { 1190, 6}, { 1184, 5}, +{ 1179, 6}, { 1173, 5}, { 1168, 6}, { 1162, 5}, { 1157, 5}, { 1152, 6}, { 1146, 5}, { 1141, 5}, +{ 1136, 5}, { 1131, 5}, { 1126, 5}, { 1121, 5}, { 1116, 5}, { 1111, 5}, { 1106, 5}, { 1101, 5}, +{ 1096, 5}, { 1091, 5}, { 1086, 4}, { 1082, 5}, { 1077, 5}, { 1072, 4}, { 1068, 5}, { 1063, 4}, +{ 1059, 5}, { 1054, 4}, { 1050, 4}, { 1046, 5}, { 1041, 4}, { 1037, 4}, { 1033, 5}, { 1028, 4}, +{ 1024, 4}, { 1020, 4}, { 1016, 4}, { 1012, 4}, { 1008, 4}, { 1004, 4}, { 1000, 4}, { 996, 4}, +{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3} +}; + +#elif F_CPU == 20000000 + +const uint16_t speed_lookuptable_fast[256][2] PROGMEM = { + {62500, 54055}, {8445, 3917}, {4528, 1434}, {3094, 745}, {2349, 456}, {1893, 307}, {1586, 222}, {1364, 167}, + {1197, 131}, {1066, 105}, {961, 86}, {875, 72}, {803, 61}, {742, 53}, {689, 45}, {644, 40}, + {604, 35}, {569, 32}, {537, 28}, {509, 25}, {484, 23}, {461, 21}, {440, 19}, {421, 17}, + {404, 16}, {388, 15}, {373, 14}, {359, 13}, {346, 12}, {334, 11}, {323, 10}, {313, 10}, + {303, 9}, {294, 9}, {285, 8}, {277, 7}, {270, 8}, {262, 7}, {255, 6}, {249, 6}, + {243, 6}, {237, 6}, {231, 5}, {226, 5}, {221, 5}, {216, 5}, {211, 4}, {207, 5}, + {202, 4}, {198, 4}, {194, 4}, {190, 3}, {187, 4}, {183, 3}, {180, 3}, {177, 4}, + {173, 3}, {170, 3}, {167, 2}, {165, 3}, {162, 3}, {159, 2}, {157, 3}, {154, 2}, + {152, 3}, {149, 2}, {147, 2}, {145, 2}, {143, 2}, {141, 2}, {139, 2}, {137, 2}, + {135, 2}, {133, 2}, {131, 2}, {129, 1}, {128, 2}, {126, 2}, {124, 1}, {123, 2}, + {121, 1}, {120, 2}, {118, 1}, {117, 1}, {116, 2}, {114, 1}, {113, 1}, {112, 2}, + {110, 1}, {109, 1}, {108, 1}, {107, 2}, {105, 1}, {104, 1}, {103, 1}, {102, 1}, + {101, 1}, {100, 1}, {99, 1}, {98, 1}, {97, 1}, {96, 1}, {95, 1}, {94, 1}, + {93, 1}, {92, 1}, {91, 0}, {91, 1}, {90, 1}, {89, 1}, {88, 1}, {87, 0}, + {87, 1}, {86, 1}, {85, 1}, {84, 0}, {84, 1}, {83, 1}, {82, 1}, {81, 0}, + {81, 1}, {80, 1}, {79, 0}, {79, 1}, {78, 0}, {78, 1}, {77, 1}, {76, 0}, + {76, 1}, {75, 0}, {75, 1}, {74, 1}, {73, 0}, {73, 1}, {72, 0}, {72, 1}, + {71, 0}, {71, 1}, {70, 0}, {70, 1}, {69, 0}, {69, 1}, {68, 0}, {68, 1}, + {67, 0}, {67, 1}, {66, 0}, {66, 1}, {65, 0}, {65, 0}, {65, 1}, {64, 0}, + {64, 1}, {63, 0}, {63, 1}, {62, 0}, {62, 0}, {62, 1}, {61, 0}, {61, 1}, + {60, 0}, {60, 0}, {60, 1}, {59, 0}, {59, 0}, {59, 1}, {58, 0}, {58, 0}, + {58, 1}, {57, 0}, {57, 0}, {57, 1}, {56, 0}, {56, 0}, {56, 1}, {55, 0}, + {55, 0}, {55, 1}, {54, 0}, {54, 0}, {54, 1}, {53, 0}, {53, 0}, {53, 0}, + {53, 1}, {52, 0}, {52, 0}, {52, 1}, {51, 0}, {51, 0}, {51, 0}, {51, 1}, + {50, 0}, {50, 0}, {50, 0}, {50, 1}, {49, 0}, {49, 0}, {49, 0}, {49, 1}, + {48, 0}, {48, 0}, {48, 0}, {48, 1}, {47, 0}, {47, 0}, {47, 0}, {47, 1}, + {46, 0}, {46, 0}, {46, 0}, {46, 0}, {46, 1}, {45, 0}, {45, 0}, {45, 0}, + {45, 1}, {44, 0}, {44, 0}, {44, 0}, {44, 0}, {44, 1}, {43, 0}, {43, 0}, + {43, 0}, {43, 0}, {43, 1}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, + {42, 1}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 1}, {40, 0}, + {40, 0}, {40, 0}, {40, 0}, {40, 1}, {39, 0}, {39, 0}, {39, 0}, {39, 0}, + {39, 0}, {39, 0}, {39, 1}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, +}; + +const uint16_t speed_lookuptable_slow[256][2] PROGMEM = { + {62500, 10417}, {52083, 7441}, {44642, 5580}, {39062, 4340}, {34722, 3472}, {31250, 2841}, {28409, 2368}, {26041, 2003}, + {24038, 1717}, {22321, 1488}, {20833, 1302}, {19531, 1149}, {18382, 1021}, {17361, 914}, {16447, 822}, {15625, 745}, + {14880, 676}, {14204, 618}, {13586, 566}, {13020, 520}, {12500, 481}, {12019, 445}, {11574, 414}, {11160, 385}, + {10775, 359}, {10416, 336}, {10080, 315}, {9765, 296}, {9469, 278}, {9191, 263}, {8928, 248}, {8680, 235}, + {8445, 222}, {8223, 211}, {8012, 200}, {7812, 191}, {7621, 181}, {7440, 173}, {7267, 165}, {7102, 158}, + {6944, 151}, {6793, 145}, {6648, 138}, {6510, 133}, {6377, 127}, {6250, 123}, {6127, 118}, {6009, 113}, + {5896, 109}, {5787, 106}, {5681, 101}, {5580, 98}, {5482, 95}, {5387, 91}, {5296, 88}, {5208, 86}, + {5122, 82}, {5040, 80}, {4960, 78}, {4882, 75}, {4807, 73}, {4734, 70}, {4664, 69}, {4595, 67}, + {4528, 64}, {4464, 63}, {4401, 61}, {4340, 60}, {4280, 58}, {4222, 56}, {4166, 55}, {4111, 53}, + {4058, 52}, {4006, 51}, {3955, 49}, {3906, 48}, {3858, 48}, {3810, 45}, {3765, 45}, {3720, 44}, + {3676, 43}, {3633, 42}, {3591, 40}, {3551, 40}, {3511, 39}, {3472, 38}, {3434, 38}, {3396, 36}, + {3360, 36}, {3324, 35}, {3289, 34}, {3255, 34}, {3221, 33}, {3188, 32}, {3156, 31}, {3125, 31}, + {3094, 31}, {3063, 30}, {3033, 29}, {3004, 28}, {2976, 28}, {2948, 28}, {2920, 27}, {2893, 27}, + {2866, 26}, {2840, 25}, {2815, 25}, {2790, 25}, {2765, 24}, {2741, 24}, {2717, 24}, {2693, 23}, + {2670, 22}, {2648, 22}, {2626, 22}, {2604, 22}, {2582, 21}, {2561, 21}, {2540, 20}, {2520, 20}, + {2500, 20}, {2480, 20}, {2460, 19}, {2441, 19}, {2422, 19}, {2403, 18}, {2385, 18}, {2367, 18}, + {2349, 17}, {2332, 18}, {2314, 17}, {2297, 16}, {2281, 17}, {2264, 16}, {2248, 16}, {2232, 16}, + {2216, 16}, {2200, 15}, {2185, 15}, {2170, 15}, {2155, 15}, {2140, 15}, {2125, 14}, {2111, 14}, + {2097, 14}, {2083, 14}, {2069, 14}, {2055, 13}, {2042, 13}, {2029, 13}, {2016, 13}, {2003, 13}, + {1990, 13}, {1977, 12}, {1965, 12}, {1953, 13}, {1940, 11}, {1929, 12}, {1917, 12}, {1905, 12}, + {1893, 11}, {1882, 11}, {1871, 11}, {1860, 11}, {1849, 11}, {1838, 11}, {1827, 11}, {1816, 10}, + {1806, 11}, {1795, 10}, {1785, 10}, {1775, 10}, {1765, 10}, {1755, 10}, {1745, 9}, {1736, 10}, + {1726, 9}, {1717, 10}, {1707, 9}, {1698, 9}, {1689, 9}, {1680, 9}, {1671, 9}, {1662, 9}, + {1653, 9}, {1644, 8}, {1636, 9}, {1627, 8}, {1619, 9}, {1610, 8}, {1602, 8}, {1594, 8}, + {1586, 8}, {1578, 8}, {1570, 8}, {1562, 8}, {1554, 7}, {1547, 8}, {1539, 8}, {1531, 7}, + {1524, 8}, {1516, 7}, {1509, 7}, {1502, 7}, {1495, 7}, {1488, 7}, {1481, 7}, {1474, 7}, + {1467, 7}, {1460, 7}, {1453, 7}, {1446, 6}, {1440, 7}, {1433, 7}, {1426, 6}, {1420, 6}, + {1414, 7}, {1407, 6}, {1401, 6}, {1395, 7}, {1388, 6}, {1382, 6}, {1376, 6}, {1370, 6}, + {1364, 6}, {1358, 6}, {1352, 6}, {1346, 5}, {1341, 6}, {1335, 6}, {1329, 5}, {1324, 6}, + {1318, 5}, {1313, 6}, {1307, 5}, {1302, 6}, {1296, 5}, {1291, 5}, {1286, 6}, {1280, 5}, + {1275, 5}, {1270, 5}, {1265, 5}, {1260, 5}, {1255, 5}, {1250, 5}, {1245, 5}, {1240, 5}, + {1235, 5}, {1230, 5}, {1225, 5}, {1220, 5}, {1215, 4}, {1211, 5}, {1206, 5}, {1201, 5}, +}; + +#endif diff --git a/Firmware/speed_lookuptable.h b/Firmware/speed_lookuptable.h index b7c00f1a..2748dd71 100644 --- a/Firmware/speed_lookuptable.h +++ b/Firmware/speed_lookuptable.h @@ -3,150 +3,123 @@ #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 + + +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 52fedcde..ff17c845 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -113,23 +113,30 @@ 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 uint16_t nextMainISR = 0; + static const uint16_t ADV_NEVER = 0xFFFF; + static const uint8_t ADV_INIT = 0b01; + static const uint8_t ADV_DECELERATE = 0b10; + + static uint16_t nextMainISR; + static uint16_t nextAdvanceISR; + + static uint16_t main_Rate; static uint16_t eISR_Rate; + static uint16_t eISR_Err; - // 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 current_adv_steps; + static uint16_t final_adv_steps; + static uint16_t max_adv_steps; + static uint32_t LA_decelerate_after; - #define _NEXT_ISR(T) nextMainISR = T + static int8_t e_steps; + static uint8_t e_step_loops; + static int8_t LA_phase; + + #define _NEXT_ISR(T) main_Rate = nextMainISR = T #else #define _NEXT_ISR(T) OCR1A = T #endif @@ -143,92 +150,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) { @@ -316,42 +237,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) { @@ -361,53 +246,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); - } -#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 - 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? @@ -493,10 +335,6 @@ FORCE_INLINE void stepper_next_block() } #endif -#ifdef FILAMENT_SENSOR - fsensor_counter = 0; - fsensor_st_block_begin(current_block); -#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 @@ -507,10 +345,22 @@ 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 - current_estep_rate = ((unsigned long)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; -#endif /* LIN_ADVANCE */ + if (current_block->use_advance_lead) { + LA_decelerate_after = current_block->decelerate_after; + final_adv_steps = current_block->final_adv_steps; + max_adv_steps = current_block->max_adv_steps; + e_step_loops = current_block->advance_step_loops; + } else { + e_steps = 0; + e_step_loops = 1; + current_adv_steps = 0; + } + nextAdvanceISR = ADV_NEVER; + LA_phase = -1; +#endif if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) { counter_x.lo = -(current_block->step_event_count.lo >> 1); @@ -567,9 +417,24 @@ 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 { - OCR1A = 2000; // 1kHz. + _NEXT_ISR(2000); // 1kHz. + +#ifdef LIN_ADVANCE + // reset LA state when there's no block + nextAdvanceISR = ADV_NEVER; + e_steps = 0; + + // 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 } //WRITE_NC(LOGIC_ANALYZER_CH2, false); } @@ -779,10 +644,10 @@ 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; + fsensor_counter += count_direction[E_AXIS]; #endif //FILAMENT_SENSOR WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #endif @@ -841,11 +706,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 - ++ fsensor_counter; - #endif //FILAMENT_SENSOR + #ifdef FILAMENT_SENSOR + fsensor_counter += count_direction[E_AXIS]; + #endif //FILAMENT_SENSOR WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #endif } @@ -854,8 +719,53 @@ FORCE_INLINE void stepper_tick_highres() } } -// 50us delay -#define LIN_ADV_FIRST_TICK_DELAY 100 + +#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) + { + // 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; + + 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 + FORCE_INLINE void isr() { //WRITE_NC(LOGIC_ANALYZER_CH0, true); @@ -868,81 +778,18 @@ 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; -#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 - 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. - } + if (e_steps) WRITE_NC(E0_DIR_PIN, e_steps < 0? INVERT_E0_DIR: !INVERT_E0_DIR); + 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. { @@ -955,14 +802,15 @@ 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 - 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) + la_state = ADV_INIT; + } +#endif } else if (step_events_completed.wide > (unsigned long int)current_block->decelerate_after) { uint16_t step_rate; @@ -973,24 +821,23 @@ 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 - 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) { + la_state = ADV_DECELERATE; + if (step_events_completed.wide <= (unsigned long int)current_block->decelerate_after + step_loops) + la_state |= ADV_INIT; + } +#endif } else { 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; - #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); } @@ -998,110 +845,40 @@ FORCE_INLINE void isr() { } #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; + // avoid multiple instances or function calls to advance_spread + if (la_state & ADV_INIT) eISR_Err = current_block->advance_rate / 4; + if (la_state & ADV_INIT || 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)); } - // 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. -#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 - 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; + } + + // 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 // 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 @@ -1115,12 +892,105 @@ FORCE_INLINE void isr() { } #ifdef LIN_ADVANCE +// Timer interrupt for E. e_steps is set in the main routine. -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; +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; + 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 + 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; + 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; + } + else { + // advance steps completed + nextAdvanceISR = ADV_NEVER; + LA_phase = -1; + e_step_loops = 1; + } } +FORCE_INLINE void advance_isr_scheduler() { + // Integrate the final timer value, accounting for scheduling adjustments + if(nextAdvanceISR && nextAdvanceISR != ADV_NEVER) + { + if(nextAdvanceISR > OCR1A) + nextAdvanceISR -= OCR1A; + else + nextAdvanceISR = 0; + } + 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 + bool eisr = !nextAdvanceISR; + 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 = (eisr? e_step_loops: step_loops); + max_ticks = min(abs(e_steps), max_ticks); + bool rev = (e_steps < 0); + 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 (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 + // soon in order to avoid skewing the regular stepper acceleration + if (nextAdvanceISR != ADV_NEVER && (nextAdvanceISR + TCNT1 + 40) < nextMainISR) + OCR1A = nextAdvanceISR; + else + OCR1A = nextMainISR; +} #endif // LIN_ADVANCE void st_init() @@ -1347,18 +1217,49 @@ void st_init() // Plan the first interrupt after 8ms from now. OCR1A = 0x4000; TCNT1 = 0; - ENABLE_STEPPER_DRIVER_INTERRUPT(); #ifdef LIN_ADVANCE - e_steps = 0; - current_adv_steps = 0; +#ifdef LA_DEBUG_LOGIC + LOGIC_ANALYZER_CH0_ENABLE; + LOGIC_ANALYZER_CH1_ENABLE; + WRITE_NC(LOGIC_ANALYZER_CH0, false); + WRITE_NC(LOGIC_ANALYZER_CH1, false); #endif - + + // Initialize state for the linear advance scheduler + nextMainISR = 0; + nextAdvanceISR = ADV_NEVER; + main_Rate = ADV_NEVER; + 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 + + ENABLE_STEPPER_DRIVER_INTERRUPT(); sei(); } +void st_reset_timer() +{ + // Clear a possible pending interrupt on OCR1A overflow. + TIFR1 |= 1 << OCF1A; + // Reset the counter. + TCNT1 = 0; + // Wake up after 1ms from now. + OCR1A = 2000; + +#ifdef LIN_ADVANCE + nextMainISR = 0; + if(nextAdvanceISR && nextAdvanceISR != ADV_NEVER) + nextAdvanceISR = 0; +#endif +} + + // Block until all buffered steps are executed void st_synchronize() { @@ -1443,6 +1344,10 @@ void quickStop() DISABLE_STEPPER_DRIVER_INTERRUPT(); while (blocks_queued()) plan_discard_current_block(); current_block = NULL; +#ifdef LIN_ADVANCE + 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 6130f3bb..7c41743c 100644 --- a/Firmware/stepper.h +++ b/Firmware/stepper.h @@ -37,12 +37,6 @@ 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. -#endif - // Block until all buffered steps are executed void st_synchronize(); @@ -62,15 +56,7 @@ float st_get_position_mm(uint8_t axis); // Call this function just before re-enabling the stepper driver interrupt and the global interrupts // to avoid a stepper timer overflow. -FORCE_INLINE void st_reset_timer() -{ - // Clear a possible pending interrupt on OCR1A overflow. - TIFR1 |= 1 << OCF1A; - // Reset the counter. - TCNT1 = 0; - // Wake up after 1ms from now. - OCR1A = 2000; -} +void st_reset_timer(); void checkHitEndstops(); //call from somewhere to create an serial error message with the locations the endstops where hit, in case they were triggered bool endstops_hit_on_purpose(); //avoid creation of the message, i.e. after homing and before a routine call of checkHitEndstops(); diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index cfcbadf0..3fcc6515 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -7085,6 +7085,60 @@ static void lcd_colorprint_change() { lcd_draw_update = 3; } + +#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 +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, _T(MSG_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 @@ -7123,8 +7177,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 LA_LIVE_K + 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