diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 952da0fa7e..b90a2ee7e2 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -457,6 +457,15 @@ #define MESH_MAX_Y (Y_MAX_POS - (MESH_INSET)) #endif +//Implementation of a linear pressure control +//Assumption: advance = k * (delta velocity) +//K=0 means advance disabled. A good value for a gregs wade extruder will be around K=75 +#define LIN_ADVANCE + +#if ENABLED(LIN_ADVANCE) + #define LIN_K 75 +#endif + // @section extras // Arc interpretation settings: diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 73c7478377..e48ef2e59e 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -6468,6 +6468,16 @@ inline void gcode_M503() { #endif // DUAL_X_CARRIAGE +#if ENABLED(LIN_ADVANCE) +/** + * M905: Set advance factor + */ +inline void gcode_M905() { + stepper.synchronize(); + stepper.advance_M905(); +} +#endif + /** * M907: Set digital trimpot motor current using axis codes X, Y, Z, E, B, S */ @@ -7339,6 +7349,12 @@ void process_next_command() { gcode_M605(); break; #endif // DUAL_X_CARRIAGE + + #if ENABLED(LIN_ADVANCE) + case 905: // M905 Set advance factor. + gcode_M905(); + break; + #endif case 907: // M907 Set digital trimpot motor current using axis codes. gcode_M907(); diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index bd60d75a1f..a0489c99fd 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -1045,6 +1045,18 @@ void Planner::check_axes_activity() { // the maximum junction speed and may always be ignored for any speed reduction checks. block->nominal_length_flag = (block->nominal_speed <= v_allowable); block->recalculate_flag = true; // Always calculate trapezoid for new block + + #ifdef LIN_ADVANCE + //bse = allsteps: A problem occures if there is a very tiny move before a retract. + //In this case, the retract and the move will be executed together. This leads to an enormus amount advance steps due to a hughe e_acceleration. + //The math is correct, but you don't want a retract move done with advance! This situation has to be filtered out. + if ((!bse || (!bsx && !bsy && !bsz)) || (stepper.get_advance_k() == 0) || (bse == allsteps)) { + block->use_advance_lead = false; + } else { + block->use_advance_lead = true; + block->e_speed_multiplier8 = (block->steps[E_AXIS] << 8) / block->step_event_count; + } + #endif // Update previous path unit_vector and nominal speed for (int i = 0; i < NUM_AXIS; i++) previous_speed[i] = current_speed[i]; diff --git a/Marlin/planner.h b/Marlin/planner.h index 07de37134e..5c0d5e12aa 100644 --- a/Marlin/planner.h +++ b/Marlin/planner.h @@ -70,6 +70,10 @@ typedef struct { volatile long final_advance; float advance; #endif + #ifdef LIN_ADVANCE + bool use_advance_lead; + int e_speed_multiplier8; //factorised by 2^8 to avoid float + #endif // Fields used by the motion planner to manage acceleration float nominal_speed, // The nominal speed for this block in mm/sec diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp index f8e8a853c9..46d0f21e9d 100644 --- a/Marlin/stepper.cpp +++ b/Marlin/stepper.cpp @@ -351,6 +351,22 @@ void Stepper::isr() { e_steps[current_block->active_extruder] += motor_direction(E_AXIS) ? -1 : 1; } #endif //ADVANCE + + #if ENABLED(LIN_ADVANCE) + counter_E += current_block->steps[E_AXIS]; + if (counter_E > 0) { + counter_E -= current_block->step_event_count; + count_position[_AXIS(E)] += count_direction[_AXIS(E)]; + e_steps[current_block->active_extruder] += motor_direction(E_AXIS) ? -1 : 1; + } + + if (current_block->use_advance_lead){ + int delta_adv_steps; //Maybe a char would be enough? + delta_adv_steps = (((long)extruder_advance_k * current_estep_rate[current_block->active_extruder]) >> 9) - current_adv_steps[current_block->active_extruder]; + e_steps[current_block->active_extruder] += delta_adv_steps; + current_adv_steps[current_block->active_extruder] += delta_adv_steps; + } + #endif //LIN_ADVANCE #define _COUNTER(AXIS) counter_## AXIS #define _APPLY_STEP(AXIS) AXIS ##_APPLY_STEP @@ -363,7 +379,7 @@ void Stepper::isr() { STEP_ADD(X); STEP_ADD(Y); STEP_ADD(Z); - #if DISABLED(ADVANCE) + #if (DISABLED(ADVANCE) && DISABLED(LIN_ADVANCE)) STEP_ADD(E); #endif @@ -377,7 +393,7 @@ void Stepper::isr() { STEP_IF_COUNTER(X); STEP_IF_COUNTER(Y); STEP_IF_COUNTER(Z); - #if DISABLED(ADVANCE) + #if (DISABLED(ADVANCE) && DISABLED(LIN_ADVANCE)) STEP_IF_COUNTER(E); #endif @@ -398,6 +414,12 @@ void Stepper::isr() { timer = calc_timer(acc_step_rate); OCR1A = timer; acceleration_time += timer; + + #if ENABLED(LIN_ADVANCE) + if (current_block->use_advance_lead){ + current_estep_rate[current_block->active_extruder] = ((unsigned long)acc_step_rate * current_block->e_speed_multiplier8) >> 8; + } + #endif #if ENABLED(ADVANCE) @@ -424,6 +446,12 @@ void Stepper::isr() { timer = calc_timer(step_rate); OCR1A = timer; deceleration_time += timer; + + #if ENABLED(LIN_ADVANCE) + if (current_block->use_advance_lead){ + current_estep_rate[current_block->active_extruder] = ((unsigned long)step_rate * current_block->e_speed_multiplier8) >> 8; + } + #endif #if ENABLED(ADVANCE) advance -= advance_rate * step_loops; @@ -436,6 +464,12 @@ void Stepper::isr() { #endif //ADVANCE } else { + #ifdef LIN_ADVANCE + if (current_block->use_advance_lead){ + current_estep_rate[current_block->active_extruder] = final_estep_rate; + } + #endif + OCR1A = OCR1A_nominal; // ensure we're running at the correct step rate, even if we just came off an acceleration step_loops = step_loops_nominal; @@ -491,6 +525,55 @@ void Stepper::isr() { #endif // ADVANCE +#if ENABLED(LIN_ADVANCE) +unsigned char old_OCR0A; +// Timer interrupt for E. e_steps is set in the main routine; +// Timer 0 is shared with millies +ISR(TIMER0_COMPA_vect) { stepper.advance_isr(); } + +void Stepper::advance_isr() { + old_OCR0A += 52; // ~10kHz interrupt (250000 / 26 = 9615kHz) war 52 + OCR0A = old_OCR0A; + +#define STEP_E_ONCE(INDEX) \ + if (e_steps[INDEX] != 0) { \ + E## INDEX ##_STEP_WRITE(INVERT_E_STEP_PIN); \ + if (e_steps[INDEX] < 0) { \ + E## INDEX ##_DIR_WRITE(INVERT_E## INDEX ##_DIR); \ + e_steps[INDEX]++; \ + } \ + else if (e_steps[INDEX] > 0) { \ + E## INDEX ##_DIR_WRITE(!INVERT_E## INDEX ##_DIR); \ + e_steps[INDEX]--; \ + } \ + E## INDEX ##_STEP_WRITE(!INVERT_E_STEP_PIN); \ + } + + // Step all E steppers that have steps, up to 4 steps per interrupt + for (unsigned char i = 0; i < 4; i++) { + #if EXTRUDERS > 3 + switch(current_block->active_extruder){case 3:STEP_E_ONCE(3);break;case 2:STEP_E_ONCE(2);break;case 1:STEP_E_ONCE(1);break;default:STEP_E_ONCE(0);} + #elif EXTRUDERS > 2 + switch(current_block->active_extruder){case 2:STEP_E_ONCE(2);break;case 1:STEP_E_ONCE(1);break;default:STEP_E_ONCE(0);} + #elif EXTRUDERS > 1 + #if DISABLED(DUAL_X_CARRIAGE) + if(current_block->active_extruder == 1){STEP_E_ONCE(1)}else{STEP_E_ONCE(0);} + #else + extern bool extruder_duplication_enabled; + if(extruder_duplication_enabled){ + STEP_E_ONCE(0); + STEP_E_ONCE(1); + }else { + if(current_block->active_extruder == 1){STEP_E_ONCE(1)}else{STEP_E_ONCE(0);} + } + #endif + #else + STEP_E_ONCE(0); + #endif + } +} +#endif // LIN_ADVANCE + void Stepper::init() { digipot_init(); //Initialize Digipot Motor Current @@ -655,6 +738,18 @@ void Stepper::init() { OCR1A = 0x4000; TCNT1 = 0; ENABLE_STEPPER_DRIVER_INTERRUPT(); + + #if ENABLED(LIN_ADVANCE) + for (int i = 0; i < EXTRUDERS; i++){ + e_steps[i] = 0; + current_adv_steps[i] = 0; + } + #if defined(TCCR0A) && defined(WGM01) + CBI(TCCR0A, WGM01); + CBI(TCCR0A, WGM00); + #endif + SBI(TIMSK0, OCIE0A); + #endif //LIN_ADVANCE #if ENABLED(ADVANCE) #if defined(TCCR0A) && defined(WGM01) @@ -1040,3 +1135,17 @@ void Stepper::microstep_readings() { SERIAL_PROTOCOLLN(digitalRead(E1_MS2_PIN)); #endif } + +#if ENABLED(LIN_ADVANCE) + void Stepper::advance_M905() { + if (code_seen('K')) extruder_advance_k = code_value(); + SERIAL_ECHO_START; + SERIAL_ECHOPGM("Advance factor:"); + SERIAL_CHAR(' '); + SERIAL_ECHOLN(extruder_advance_k); + } + + int Stepper::get_advance_k(){ + return extruder_advance_k; + } +#endif diff --git a/Marlin/stepper.h b/Marlin/stepper.h index 1aebe366c0..e9d1191bc3 100644 --- a/Marlin/stepper.h +++ b/Marlin/stepper.h @@ -93,6 +93,10 @@ class Stepper { #if ENABLED(ADVANCE) static long e_steps[EXTRUDERS]; #endif + + #if ENABLED(LIN_ADVANCE) + int extruder_advance_k = LIN_K; + #endif private: @@ -111,6 +115,14 @@ class Stepper { static unsigned char old_OCR0A; static long advance_rate, advance, old_advance, final_advance; #endif + + #if ENABLED(LIN_ADVANCE) + unsigned char old_OCR0A; + volatile int e_steps[EXTRUDERS]; + int final_estep_rate; + int current_estep_rate[EXTRUDERS]; //Actual extruder speed [steps/s] + int current_adv_steps[EXTRUDERS]; //The amount of current added esteps due to advance. Think of it as the current amount of pressure applied to the spring (=filament). + #endif static long acceleration_time, deceleration_time; //unsigned long accelerate_until, decelerate_after, acceleration_rate, initial_rate, final_rate, nominal_rate; @@ -159,6 +171,12 @@ class Stepper { #if ENABLED(ADVANCE) static void advance_isr(); #endif + + #if ENABLED(LIN_ADVANCE) + void advance_isr(); + void advance_M905(); + int get_advance_k(); + #endif // // Block until all buffered steps are executed @@ -315,6 +333,13 @@ class Stepper { acc_step_rate = current_block->initial_rate; acceleration_time = calc_timer(acc_step_rate); OCR1A = acceleration_time; + + #if ENABLED(LIN_ADVANCE) + if (current_block->use_advance_lead){ + current_estep_rate[current_block->active_extruder] = ((unsigned long)acc_step_rate * current_block->e_speed_multiplier8) >> 8; + final_estep_rate = (current_block->nominal_rate * current_block->e_speed_multiplier8) >> 8; + } + #endif // SERIAL_ECHO_START; // SERIAL_ECHOPGM("advance :"); @@ -332,4 +357,4 @@ class Stepper { }; -#endif // STEPPER_H \ No newline at end of file +#endif // STEPPER_H