From a1fd50ea9aaab1ae3a5d69446cf94ba6cc6117be Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 14 Jan 2018 14:45:27 +0100 Subject: [PATCH 01/11] Simlified the extruder ticking code. --- Firmware/stepper.cpp | 30 ++++++++---------------------- Firmware/stepper.h | 14 -------------- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 38ece7ea..5cf3d908 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -634,34 +634,20 @@ void isr() { if ((out_bits & (1 << E_AXIS)) != 0) { // -direction //AKU + WRITE(E0_DIR_PIN, #ifdef SNMM - if (snmm_extruder == 0 || snmm_extruder == 2) - { - NORM_E_DIR(); - } - else - { - REV_E_DIR(); - } -#else - REV_E_DIR(); + (snmm_extruder == 0 || snmm_extruder == 2) ? !INVERT_E0_DIR : #endif // SNMM + INVERT_E0_DIR); count_direction[E_AXIS] = -1; } else { // +direction + WRITE(E0_DIR_PIN, #ifdef SNMM - if (snmm_extruder == 0 || snmm_extruder == 2) - { - REV_E_DIR(); - } - else - { - NORM_E_DIR(); - } -#else - NORM_E_DIR(); + (snmm_extruder == 0 || snmm_extruder == 2) ? INVERT_E0_DIR : #endif // SNMM + !INVERT_E0_DIR); count_direction[E_AXIS] = 1; } @@ -738,10 +724,10 @@ void isr() { #ifndef LIN_ADVANCE counter_e += current_block->steps_e; if (counter_e > 0) { - WRITE_E_STEP(!INVERT_E_STEP_PIN); + WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); counter_e -= current_block->step_event_count; count_position[E_AXIS]+=count_direction[E_AXIS]; - WRITE_E_STEP(INVERT_E_STEP_PIN); + WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #ifdef PAT9125 fsensor_counter++; #endif //PAT9125 diff --git a/Firmware/stepper.h b/Firmware/stepper.h index 9915de90..5ca68a39 100644 --- a/Firmware/stepper.h +++ b/Firmware/stepper.h @@ -23,20 +23,6 @@ #include "planner.h" -#if EXTRUDERS > 2 - #define WRITE_E_STEP(v) { if(current_block->active_extruder == 2) { WRITE(E2_STEP_PIN, v); } else { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}} - #define NORM_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, !INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}} - #define REV_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}} -#elif EXTRUDERS > 1 - #define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }} - #define NORM_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }} - #define REV_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }} -#else - #define WRITE_E_STEP(v) WRITE(E0_STEP_PIN, v) - #define NORM_E_DIR() WRITE(E0_DIR_PIN, !INVERT_E0_DIR) - #define REV_E_DIR() WRITE(E0_DIR_PIN, INVERT_E0_DIR) -#endif - #ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED extern bool abort_on_endstop_hit; #endif From 30b06488ca2d097366af4a1c7d3a47ac1743a58c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 14 Jan 2018 17:01:04 +0100 Subject: [PATCH 02/11] Redefined the DDA step and accumulator values to unions to support access to the low / high words of the 32bit values. This is a prerequisity for an optimized 16bit only DDA in case the number of step is lower than 32767. --- Firmware/planner.cpp | 108 +++++++++++++++++++++---------------------- Firmware/planner.h | 26 ++++++++++- Firmware/stepper.cpp | 83 +++++++++++++++++---------------- 3 files changed, 119 insertions(+), 98 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index a5fa0261..5d0e703e 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -227,8 +227,8 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will // have to use intersection_distance() to calculate when to abort acceleration and start braking // in order to reach the final_rate exactly at the end of this block. - if (accel_decel_steps < block->step_event_count) { - plateau_steps = block->step_event_count - accel_decel_steps; + if (accel_decel_steps < block->step_event_count.wide) { + plateau_steps = block->step_event_count.wide - accel_decel_steps; } else { uint32_t acceleration_x4 = acceleration << 2; // Avoid negative numbers @@ -240,26 +240,26 @@ void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit accelerate_steps = (block->step_event_count >> 1) + (final_rate_sqr - initial_rate_sqr + acceleration_x4 - 1 + (block->step_event_count & 1) * acceleration_x2) / acceleration_x4; #else accelerate_steps = final_rate_sqr - initial_rate_sqr + acceleration_x4 - 1; - if (block->step_event_count & 1) + if (block->step_event_count.wide & 1) accelerate_steps += acceleration_x2; accelerate_steps /= acceleration_x4; - accelerate_steps += (block->step_event_count >> 1); + accelerate_steps += (block->step_event_count.wide >> 1); #endif - if (accelerate_steps > block->step_event_count) - accelerate_steps = block->step_event_count; + if (accelerate_steps > block->step_event_count.wide) + accelerate_steps = block->step_event_count.wide; } else { #if 0 decelerate_steps = (block->step_event_count >> 1) + (initial_rate_sqr - final_rate_sqr + (block->step_event_count & 1) * acceleration_x2) / acceleration_x4; #else decelerate_steps = initial_rate_sqr - final_rate_sqr; - if (block->step_event_count & 1) + if (block->step_event_count.wide & 1) decelerate_steps += acceleration_x2; decelerate_steps /= acceleration_x4; - decelerate_steps += (block->step_event_count >> 1); + decelerate_steps += (block->step_event_count.wide >> 1); #endif - if (decelerate_steps > block->step_event_count) - decelerate_steps = block->step_event_count; - accelerate_steps = block->step_event_count - decelerate_steps; + if (decelerate_steps > block->step_event_count.wide) + decelerate_steps = block->step_event_count.wide; + accelerate_steps = block->step_event_count.wide - decelerate_steps; } } @@ -449,10 +449,10 @@ void getHighESpeed() uint8_t block_index = block_buffer_tail; while(block_index != block_buffer_head) { - if((block_buffer[block_index].steps_x != 0) || - (block_buffer[block_index].steps_y != 0) || - (block_buffer[block_index].steps_z != 0)) { - float se=(float(block_buffer[block_index].steps_e)/float(block_buffer[block_index].step_event_count))*block_buffer[block_index].nominal_speed; + if((block_buffer[block_index].steps_x.wide != 0) || + (block_buffer[block_index].steps_y.wide != 0) || + (block_buffer[block_index].steps_z.wide != 0)) { + float se=(float(block_buffer[block_index].steps_e.wide)/float(block_buffer[block_index].step_event_count.wide))*block_buffer[block_index].nominal_speed; //se; mm/sec; if(se>high) { @@ -493,10 +493,10 @@ void check_axes_activity() while(block_index != block_buffer_head) { block = &block_buffer[block_index]; - if(block->steps_x != 0) x_active++; - if(block->steps_y != 0) y_active++; - if(block->steps_z != 0) z_active++; - if(block->steps_e != 0) e_active++; + if(block->steps_x.wide != 0) x_active++; + if(block->steps_y.wide != 0) y_active++; + if(block->steps_z.wide != 0) z_active++; + if(block->steps_e.wide != 0) e_active++; block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1); } } @@ -769,26 +769,24 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate // Number of steps for each axis #ifndef COREXY // default non-h-bot planning -block->steps_x = labs(target[X_AXIS]-position[X_AXIS]); -block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]); +block->steps_x.wide = labs(target[X_AXIS]-position[X_AXIS]); +block->steps_y.wide = labs(target[Y_AXIS]-position[Y_AXIS]); #else // corexy planning // these equations follow the form of the dA and dB equations on http://www.corexy.com/theory.html -block->steps_x = labs((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS])); -block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS])); +block->steps_x.wide = labs((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS])); +block->steps_y.wide = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS])); #endif - block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]); - block->steps_e = labs(target[E_AXIS]-position[E_AXIS]); + block->steps_z.wide = labs(target[Z_AXIS]-position[Z_AXIS]); + block->steps_e.wide = labs(target[E_AXIS]-position[E_AXIS]); if (volumetric_multiplier[active_extruder] != 1.f) - block->steps_e *= volumetric_multiplier[active_extruder]; - if (extrudemultiply != 100) { - block->steps_e *= extrudemultiply; - block->steps_e /= 100; - } - block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e))); + block->steps_e.wide *= volumetric_multiplier[active_extruder]; + if (extrudemultiply != 100) + block->steps_e.wide *= extrudemultiply * 0.01; + block->step_event_count.wide = max(block->steps_x.wide, max(block->steps_y.wide, max(block->steps_z.wide, block->steps_e.wide))); // Bail if this is a zero-length block - if (block->step_event_count <= dropsegments) + if (block->step_event_count.wide <= dropsegments) { #ifdef PLANNER_DIAGNOSTICS planner_update_queue_min_counter(); @@ -832,21 +830,21 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi //enable active axes #ifdef COREXY - if((block->steps_x != 0) || (block->steps_y != 0)) + if((block->steps_x.wide != 0) || (block->steps_y.wide != 0)) { enable_x(); enable_y(); } #else - if(block->steps_x != 0) enable_x(); - if(block->steps_y != 0) enable_y(); + if(block->steps_x.wide != 0) enable_x(); + if(block->steps_y.wide != 0) enable_y(); #endif #ifndef Z_LATE_ENABLE - if(block->steps_z != 0) enable_z(); + if(block->steps_z.wide != 0) enable_z(); #endif // Enable extruder(s) - if(block->steps_e != 0) + if(block->steps_e.wide != 0) { if (DISABLE_INACTIVE_EXTRUDER) //enable only selected extruder { @@ -888,7 +886,7 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi } } - if (block->steps_e == 0) + if (block->steps_e.wide == 0) { if(feed_ratesteps_x <=dropsegments && block->steps_y <=dropsegments && block->steps_z <=dropsegments ) + if ( block->steps_x.wide <=dropsegments && block->steps_y.wide <=dropsegments && block->steps_z.wide <=dropsegments ) { block->millimeters = fabs(delta_mm[E_AXIS]); } @@ -950,7 +948,7 @@ Having the real displacement of the head, we can calculate the total movement le #endif // SLOWDOWN block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0 - block->nominal_rate = ceil(block->step_event_count * inverse_second); // (step/sec) Always > 0 + block->nominal_rate = ceil(block->step_event_count.wide * inverse_second); // (step/sec) Always > 0 #ifdef FILAMENT_SENSOR //FMM update ring buffer used for delay with filament measurements @@ -1027,8 +1025,8 @@ Having the real displacement of the head, we can calculate the total movement le // 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. - float steps_per_mm = block->step_event_count/block->millimeters; - if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) + float steps_per_mm = block->step_event_count.wide/block->millimeters; + if(block->steps_x.wide == 0 && block->steps_y.wide == 0 && block->steps_z.wide == 0) { block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 } @@ -1038,29 +1036,29 @@ Having the real displacement of the head, we can calculate the total movement le #ifdef TMC2130 if (tmc2130_mode == TMC2130_MODE_SILENT) { - if(((float)block->acceleration_st * (float)block->steps_x / (float)block->step_event_count) > SILENT_MAX_ACCEL_X_ST) + if(((float)block->acceleration_st * (float)block->steps_x.wide / (float)block->step_event_count.wide) > SILENT_MAX_ACCEL_X_ST) block->acceleration_st = SILENT_MAX_ACCEL_X_ST; - if(((float)block->acceleration_st * (float)block->steps_y / (float)block->step_event_count) > SILENT_MAX_ACCEL_Y_ST) + if(((float)block->acceleration_st * (float)block->steps_y.wide / (float)block->step_event_count.wide) > SILENT_MAX_ACCEL_Y_ST) block->acceleration_st = SILENT_MAX_ACCEL_Y_ST; } - if(((float)block->acceleration_st * (float)block->steps_x / (float)block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) + if(((float)block->acceleration_st * (float)block->steps_x.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[X_AXIS]) block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; - if(((float)block->acceleration_st * (float)block->steps_y / (float)block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) + if(((float)block->acceleration_st * (float)block->steps_y.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[Y_AXIS]) block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; - if(((float)block->acceleration_st * (float)block->steps_e / (float)block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) + if(((float)block->acceleration_st * (float)block->steps_e.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[E_AXIS]) block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; - if(((float)block->acceleration_st * (float)block->steps_z / (float)block->step_event_count ) > axis_steps_per_sqr_second[Z_AXIS]) + if(((float)block->acceleration_st * (float)block->steps_z.wide / (float)block->step_event_count.wide ) > axis_steps_per_sqr_second[Z_AXIS]) block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; #else //TMC2130 // 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 / (float)block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) + if(((float)block->acceleration_st * (float)block->steps_x.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[X_AXIS]) block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; - if(((float)block->acceleration_st * (float)block->steps_y / (float)block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS]) + if(((float)block->acceleration_st * (float)block->steps_y.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[Y_AXIS]) block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; - if(((float)block->acceleration_st * (float)block->steps_e / (float)block->step_event_count) > axis_steps_per_sqr_second[E_AXIS]) + if(((float)block->acceleration_st * (float)block->steps_e.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[E_AXIS]) block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; - if(((float)block->acceleration_st * (float)block->steps_z / (float)block->step_event_count ) > axis_steps_per_sqr_second[Z_AXIS]) + if(((float)block->acceleration_st * (float)block->steps_z.wide / (float)block->step_event_count.wide ) > axis_steps_per_sqr_second[Z_AXIS]) block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; #endif //TMC2130 } @@ -1218,10 +1216,10 @@ Having the real displacement of the head, we can calculate the total movement le // 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 - && (block->steps_x || block->steps_y) + block->use_advance_lead = block->steps_e.wide + && (block->steps_x.wide || block->steps_y.wide) && extruder_advance_k - && (uint32_t)block->steps_e != block->step_event_count + && (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( diff --git a/Firmware/planner.h b/Firmware/planner.h index 3b9e65a1..91c5c5fa 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -40,6 +40,28 @@ enum BlockFlag { // If set, the machine will start from a halt at the start of this block, // respecting the maximum allowed jerk. BLOCK_FLAG_START_FROM_FULL_HALT = 4, + // If set, the stepper interrupt expects, that the number of steps to tick will be lower + // 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, +}; + +union dda_isteps_t +{ + int32_t wide; + struct { + uint16_t lo; + int16_t hi; + }; +}; + +union dda_usteps_t +{ + uint32_t wide; + struct { + uint16_t lo; + uint16_t hi; + }; }; // This struct is used when buffering the setup for each linear movement "nominal" values are as specified in @@ -47,8 +69,8 @@ enum BlockFlag { typedef struct { // Fields used by the bresenham algorithm for tracing the line // steps_x.y,z, step_event_count, acceleration_rate, direction_bits and active_extruder are set by plan_buffer_line(). - long steps_x, steps_y, steps_z, steps_e; // Step count along each axis - unsigned long step_event_count; // The number of step events required to complete this block + dda_isteps_t steps_x, steps_y, steps_z, steps_e; // Step count along each axis + dda_usteps_t step_event_count; // The number of step events required to complete this block long acceleration_rate; // The acceleration rate used for acceleration calculation unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h) unsigned char active_extruder; // Selects the active extruder diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 5cf3d908..4b53ee89 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -62,11 +62,12 @@ bool z_max_endstop = false; // Variables used by The Stepper Driver Interrupt static unsigned char out_bits; // The next stepping-bits to be output -static int32_t counter_x, // Counter variables for the bresenham line tracer +static dda_isteps_t + counter_x, // Counter variables for the bresenham line tracer counter_y, counter_z, counter_e; -volatile uint32_t step_events_completed; // The number of step events executed in the current block +volatile dda_usteps_t step_events_completed; // The number of step events executed in the current block static int32_t acceleration_time, deceleration_time; //static unsigned long accelerate_until, decelerate_after, acceleration_rate, initial_rate, final_rate, nominal_rate; static uint16_t acc_step_rate; // needed for deccelaration start point @@ -404,14 +405,14 @@ void isr() { // The busy flag is set by the plan_get_current_block() call. // current_block->busy = true; trapezoid_generator_reset(); - counter_x = -(current_block->step_event_count >> 1); - counter_y = counter_x; - counter_z = counter_x; - counter_e = counter_x; - step_events_completed = 0; + counter_x.wide = -(current_block->step_event_count.wide >> 1); + counter_y.wide = counter_x.wide; + counter_z.wide = counter_x.wide; + counter_e.wide = counter_x.wide; + step_events_completed.wide = 0; #ifdef Z_LATE_ENABLE - if(current_block->steps_z > 0) { + if(current_block->steps_z.wide > 0) { enable_z(); _NEXT_ISR(2000); //1ms wait return; @@ -476,10 +477,10 @@ void isr() { // Normal homing x_min_endstop = (READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); #endif - if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) { + if(x_min_endstop && old_x_min_endstop && (current_block->steps_x.wide > 0)) { endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; endstop_x_hit=true; - step_events_completed = current_block->step_event_count; + step_events_completed.wide = current_block->step_event_count.wide; } old_x_min_endstop = x_min_endstop; #endif @@ -499,10 +500,10 @@ void isr() { // Normal homing x_max_endstop = (READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); #endif - if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){ + if(x_max_endstop && old_x_max_endstop && (current_block->steps_x.wide > 0)){ endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; endstop_x_hit=true; - step_events_completed = current_block->step_event_count; + step_events_completed.wide = current_block->step_event_count.wide; } old_x_max_endstop = x_max_endstop; #endif @@ -527,10 +528,10 @@ void isr() { // Normal homing y_min_endstop = (READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING); #endif - if(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) { + if(y_min_endstop && old_y_min_endstop && (current_block->steps_y.wide > 0)) { endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; endstop_y_hit=true; - step_events_completed = current_block->step_event_count; + step_events_completed.wide = current_block->step_event_count.wide; } old_y_min_endstop = y_min_endstop; #endif @@ -548,10 +549,10 @@ void isr() { // Normal homing y_max_endstop = (READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING); #endif - if(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){ + if(y_max_endstop && old_y_max_endstop && (current_block->steps_y.wide > 0)){ endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; endstop_y_hit=true; - step_events_completed = current_block->step_event_count; + step_events_completed.wide = current_block->step_event_count.wide; } old_y_max_endstop = y_max_endstop; #endif @@ -575,10 +576,10 @@ void isr() { #else z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); #endif //TMC2130_SG_HOMING - if(z_min_endstop && old_z_min_endstop && (current_block->steps_z > 0)) { + if(z_min_endstop && old_z_min_endstop && (current_block->steps_z.wide > 0)) { endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; endstop_z_hit=true; - step_events_completed = current_block->step_event_count; + step_events_completed.wide = current_block->step_event_count.wide; } old_z_min_endstop = z_min_endstop; #endif @@ -601,10 +602,10 @@ void isr() { #else z_max_endstop = (READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING); #endif //TMC2130_SG_HOMING - if(z_max_endstop && old_z_max_endstop && (current_block->steps_z > 0)) { + if(z_max_endstop && old_z_max_endstop && (current_block->steps_z.wide > 0)) { endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; endstop_z_hit=true; - step_events_completed = current_block->step_event_count; + step_events_completed.wide = current_block->step_event_count.wide; } old_z_max_endstop = z_max_endstop; #endif @@ -625,7 +626,7 @@ void isr() { if(z_min_endstop && old_z_min_endstop) { endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; endstop_z_hit=true; - step_events_completed = current_block->step_event_count; + step_events_completed.wide = current_block->step_event_count.wide; } old_z_min_endstop = z_min_endstop; } @@ -657,22 +658,22 @@ void isr() { #endif //RP - returned, because missing characters #ifdef LIN_ADVANCE - counter_e += current_block->steps_e; - if (counter_e > 0) { - counter_e -= current_block->step_event_count; + counter_e.wide += current_block->steps_e.wide; + if (counter_e.wide > 0) { + counter_e.wide -= current_block->step_event_count.wide; count_position[E_AXIS] += count_direction[E_AXIS]; ((out_bits&(1<steps_x; - if (counter_x > 0) { + counter_x.wide += current_block->steps_x.wide; + if (counter_x.wide > 0) { WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN); LastStepMask |= X_AXIS_MASK; #ifdef DEBUG_XSTEP_DUP_PIN WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN); #endif //DEBUG_XSTEP_DUP_PIN - counter_x -= current_block->step_event_count; + counter_x.wide -= current_block->step_event_count.wide; count_position[X_AXIS]+=count_direction[X_AXIS]; WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN); #ifdef DEBUG_XSTEP_DUP_PIN @@ -680,8 +681,8 @@ void isr() { #endif //DEBUG_XSTEP_DUP_PIN } - counter_y += current_block->steps_y; - if (counter_y > 0) { + counter_y.wide += current_block->steps_y.wide; + if (counter_y.wide > 0) { WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN); LastStepMask |= Y_AXIS_MASK; #ifdef DEBUG_YSTEP_DUP_PIN @@ -692,7 +693,7 @@ void isr() { WRITE_NC(Y2_STEP_PIN, !INVERT_Y_STEP_PIN); #endif - counter_y -= current_block->step_event_count; + counter_y.wide -= current_block->step_event_count.wide; count_position[Y_AXIS]+=count_direction[Y_AXIS]; WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN); #ifdef DEBUG_YSTEP_DUP_PIN @@ -704,15 +705,15 @@ void isr() { #endif } - counter_z += current_block->steps_z; - if (counter_z > 0) { + counter_z.wide += current_block->steps_z.wide; + if (counter_z.wide > 0) { WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN); LastStepMask |= Z_AXIS_MASK; #ifdef Z_DUAL_STEPPER_DRIVERS WRITE_NC(Z2_STEP_PIN, !INVERT_Z_STEP_PIN); #endif - counter_z -= current_block->step_event_count; + counter_z.wide -= current_block->step_event_count.wide; count_position[Z_AXIS]+=count_direction[Z_AXIS]; WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN); @@ -722,10 +723,10 @@ void isr() { } #ifndef LIN_ADVANCE - counter_e += current_block->steps_e; - if (counter_e > 0) { + counter_e.wide += current_block->steps_e.wide; + if (counter_e.wide > 0) { WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); - counter_e -= current_block->step_event_count; + counter_e.wide -= current_block->step_event_count.wide; count_position[E_AXIS]+=count_direction[E_AXIS]; WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #ifdef PAT9125 @@ -734,8 +735,8 @@ void isr() { } #endif - step_events_completed += 1; - if(step_events_completed >= current_block->step_event_count) break; + ++ step_events_completed.wide; + if(step_events_completed.wide >= current_block->step_event_count.wide) break; } #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { @@ -750,7 +751,7 @@ void isr() { // Calculare new timer value unsigned short timer; uint16_t step_rate; - if (step_events_completed <= (unsigned long int)current_block->accelerate_until) { + if (step_events_completed.wide <= (unsigned long int)current_block->accelerate_until) { // v = t * a -> acc_step_rate = acceleration_time * current_block->acceleration_rate MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate); acc_step_rate += current_block->initial_rate; @@ -771,7 +772,7 @@ void isr() { eISR_Rate = ADV_RATE(timer, step_loops); #endif } - else if (step_events_completed > (unsigned long int)current_block->decelerate_after) { + else if (step_events_completed.wide > (unsigned long int)current_block->decelerate_after) { MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate); if(step_rate > acc_step_rate) { // Check step_rate stays positive @@ -811,7 +812,7 @@ void isr() { } // If current block is finished, reset pointer - if (step_events_completed >= current_block->step_event_count) { + if (step_events_completed.wide >= current_block->step_event_count.wide) { #ifdef PAT9125 fsensor_st_block_chunk(current_block, fsensor_counter); From 7a972fd9b07f3a6885ba06f5f7cc8f282361b50c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 14 Jan 2018 22:37:07 +0100 Subject: [PATCH 03/11] Split the stepper ISR routine into multiple inline functions, added an optimized DDA routine for moves with less than 32767 ticks. --- Firmware/planner.cpp | 5 +- Firmware/planner.h | 4 +- Firmware/stepper.cpp | 635 ++++++++++++++++++++++--------------------- 3 files changed, 331 insertions(+), 313 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 5d0e703e..41a4e8ea 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -839,9 +839,7 @@ block->steps_y.wide = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-p if(block->steps_x.wide != 0) enable_x(); if(block->steps_y.wide != 0) enable_y(); #endif -#ifndef Z_LATE_ENABLE if(block->steps_z.wide != 0) enable_z(); -#endif // Enable extruder(s) if(block->steps_e.wide != 0) @@ -1234,6 +1232,9 @@ Having the real displacement of the head, we can calculate the total movement le block->speed_factor = block->nominal_rate / block->nominal_speed; calculate_trapezoid_for_block(block, block->entry_speed, safe_speed); + if (block->step_event_count.wide <= 32767) + block->flag |= BLOCK_FLAG_DDA_LOWRES; + // Move the buffer head. From now the block may be picked up by the stepper interrupt controller. block_buffer_head = next_buffer_head; diff --git a/Firmware/planner.h b/Firmware/planner.h index 91c5c5fa..ecac73d1 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -50,7 +50,7 @@ union dda_isteps_t { int32_t wide; struct { - uint16_t lo; + int16_t lo; int16_t hi; }; }; @@ -94,7 +94,7 @@ typedef struct { float acceleration; // Bit flags defined by the BlockFlag enum. - bool flag; + uint8_t flag; // Settings for the trapezoid generator (runs inside an interrupt handler). // Changing the following values in the planner needs to be synchronized with the interrupt handler by disabling the interrupts. diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 4b53ee89..bb020c44 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -135,8 +135,6 @@ extern bool stepper_timer_overflow_state; //=============================functions ============================ //=========================================================================== -#define CHECK_ENDSTOPS if(check_endstops) - #ifndef _NO_ASM // intRes = intIn1 * intIn2 >> 16 @@ -320,7 +318,7 @@ void step_wait(){ } -FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { +FORCE_INLINE unsigned short calc_timer(uint16_t step_rate) { unsigned short timer; if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY; @@ -361,10 +359,10 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) { FORCE_INLINE void trapezoid_generator_reset() { deceleration_time = 0; // step_rate to timer interval - OCR1A_nominal = calc_timer(current_block->nominal_rate); + OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate)); // make a note of the number of step loops required at nominal speed step_loops_nominal = step_loops; - acc_step_rate = current_block->initial_rate; + acc_step_rate = uint16_t(current_block->initial_rate); acceleration_time = calc_timer(acc_step_rate); _NEXT_ISR(acceleration_time); @@ -374,7 +372,6 @@ FORCE_INLINE void trapezoid_generator_reset() { final_estep_rate = (current_block->nominal_rate * current_block->abs_adv_steps_multiplier8) >> 17; } #endif - } // "The Stepper Driver Interrupt" - This timer interrupt is the workhorse. @@ -391,157 +388,144 @@ ISR(TIMER1_COMPA_vect) { #endif } -void isr() { - //if (UVLO) uvlo(); - // If there is no current block, attempt to pop one from the buffer - if (current_block == NULL) { - // Anything in the buffer? - current_block = plan_get_current_block(); - if (current_block != NULL) { +FORCE_INLINE void stepper_next_block() +{ + // Anything in the buffer? + current_block = plan_get_current_block(); + if (current_block != NULL) { #ifdef PAT9125 - fsensor_counter = 0; - fsensor_st_block_begin(current_block); + fsensor_counter = 0; + fsensor_st_block_begin(current_block); #endif //PAT9125 - // The busy flag is set by the plan_get_current_block() call. - // current_block->busy = true; - trapezoid_generator_reset(); + // The busy flag is set by the plan_get_current_block() call. + // current_block->busy = true; + trapezoid_generator_reset(); + if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) { + counter_x.lo = -(current_block->step_event_count.lo >> 1); + counter_y.lo = counter_x.lo; + counter_z.lo = counter_x.lo; + counter_e.lo = counter_x.lo; + } else { counter_x.wide = -(current_block->step_event_count.wide >> 1); counter_y.wide = counter_x.wide; counter_z.wide = counter_x.wide; counter_e.wide = counter_x.wide; - step_events_completed.wide = 0; - - #ifdef Z_LATE_ENABLE - if(current_block->steps_z.wide > 0) { - enable_z(); - _NEXT_ISR(2000); //1ms wait - return; - } - #endif } - else { - _NEXT_ISR(2000); // 1kHz. - } - } - - LastStepMask = 0; - - if (current_block != NULL) { - // Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt + step_events_completed.wide = 0; + // Set directions. out_bits = current_block->direction_bits; - - // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY) if((out_bits & (1< -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_XMINLIMIT) - - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on - x_min_endstop = (READ(X_TMC2130_DIAG) != 0); - #else - // Normal homing - x_min_endstop = (READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); - #endif - if(x_min_endstop && old_x_min_endstop && (current_block->steps_x.wide > 0)) { - endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; - endstop_x_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; - } - old_x_min_endstop = x_min_endstop; - #endif - } - } + if ((out_bits & (1< -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_XMAXLIMIT) - - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on - x_max_endstop = (READ(X_TMC2130_DIAG) != 0); - #else - // Normal homing - x_max_endstop = (READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); - #endif - if(x_max_endstop && old_x_max_endstop && (current_block->steps_x.wide > 0)){ - endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; - endstop_x_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; - } - old_x_max_endstop = x_max_endstop; - #endif - } - } +#ifndef LIN_ADVANCE + if ((out_bits & (1 << E_AXIS)) != 0) { // -direction + WRITE(E0_DIR_PIN, + #ifdef SNMM + (snmm_extruder == 0 || snmm_extruder == 2) ? !INVERT_E0_DIR : + #endif // SNMM + INVERT_E0_DIR); + count_direction[E_AXIS] = -1; + } else { // +direction + WRITE(E0_DIR_PIN, + #ifdef SNMM + (snmm_extruder == 0 || snmm_extruder == 2) ? INVERT_E0_DIR : + #endif // SNMM + !INVERT_E0_DIR); + count_direction[E_AXIS] = 1; } +#endif /* LIN_ADVANCE */ + } + else { + _NEXT_ISR(2000); // 1kHz. + } +} +// Check limit switches. +FORCE_INLINE void stepper_check_endstops() +{ + if(check_endstops) + { #ifndef COREXY - if ((out_bits & (1< -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_YMINLIMIT) - + { + #if ( (defined(X_MIN_PIN) && (X_MIN_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_XMINLIMIT) + #ifdef TMC2130_SG_HOMING + // Stall guard homing turned on + x_min_endstop = (READ(X_TMC2130_DIAG) != 0); + #else + // Normal homing + x_min_endstop = (READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); + #endif + if(x_min_endstop && old_x_min_endstop && (current_block->steps_x.wide > 0)) { + endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; + endstop_x_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_x_min_endstop = x_min_endstop; + #endif + } else { // +direction + #if ( (defined(X_MAX_PIN) && (X_MAX_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_XMAXLIMIT) #ifdef TMC2130_SG_HOMING // Stall guard homing turned on - y_min_endstop = (READ(Y_TMC2130_DIAG) != 0); + x_max_endstop = (READ(X_TMC2130_DIAG) != 0); #else // Normal homing - y_min_endstop = (READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING); + x_max_endstop = (READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); #endif - if(y_min_endstop && old_y_min_endstop && (current_block->steps_y.wide > 0)) { - endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; - endstop_y_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; - } - old_y_min_endstop = y_min_endstop; - #endif - } + if(x_max_endstop && old_x_max_endstop && (current_block->steps_x.wide > 0)){ + endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; + endstop_x_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_x_max_endstop = x_max_endstop; + #endif } - else { // +direction - CHECK_ENDSTOPS - { - #if ( (defined(Y_MAX_PIN) && (Y_MAX_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_YMAXLIMIT) - + + #ifndef COREXY + if ((out_bits & (1< -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_YMINLIMIT) + #ifdef TMC2130_SG_HOMING + // Stall guard homing turned on + y_min_endstop = (READ(Y_TMC2130_DIAG) != 0); + #else + // Normal homing + y_min_endstop = (READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING); + #endif + if(y_min_endstop && old_y_min_endstop && (current_block->steps_y.wide > 0)) { + endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; + endstop_y_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_y_min_endstop = y_min_endstop; + #endif + } else { // +direction + #if ( (defined(Y_MAX_PIN) && (Y_MAX_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_YMAXLIMIT) #ifdef TMC2130_SG_HOMING // Stall guard homing turned on y_max_endstop = (READ(Y_TMC2130_DIAG) != 0); @@ -549,195 +533,226 @@ void isr() { // Normal homing y_max_endstop = (READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING); #endif - if(y_max_endstop && old_y_max_endstop && (current_block->steps_y.wide > 0)){ - endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; - endstop_y_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; - } - old_y_max_endstop = y_max_endstop; - #endif - } - } - - if ((out_bits & (1<steps_y.wide > 0)){ + endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; + endstop_y_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_y_max_endstop = y_max_endstop; #endif - - count_direction[Z_AXIS]=-1; - if(check_endstops && ! check_z_endstop) - { - #if defined(Z_MIN_PIN) && (Z_MIN_PIN > -1) && !defined(DEBUG_DISABLE_ZMINLIMIT) - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on - z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING) || (READ(Z_TMC2130_DIAG) != 0); - #else - z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); - #endif //TMC2130_SG_HOMING - if(z_min_endstop && old_z_min_endstop && (current_block->steps_z.wide > 0)) { - endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; - endstop_z_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; - } - old_z_min_endstop = z_min_endstop; - #endif - } - } - else { // +direction - WRITE_NC(Z_DIR_PIN,!INVERT_Z_DIR); - - #ifdef Z_DUAL_STEPPER_DRIVERS - WRITE_NC(Z2_DIR_PIN,!INVERT_Z_DIR); - #endif - - count_direction[Z_AXIS]=1; - CHECK_ENDSTOPS - { - #if defined(Z_MAX_PIN) && (Z_MAX_PIN > -1) && !defined(DEBUG_DISABLE_ZMAXLIMIT) - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on - z_max_endstop = (READ(Z_TMC2130_DIAG) != 0); - #else - z_max_endstop = (READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING); - #endif //TMC2130_SG_HOMING - if(z_max_endstop && old_z_max_endstop && (current_block->steps_z.wide > 0)) { - endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; - endstop_z_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; - } - old_z_max_endstop = z_max_endstop; - #endif - } } - // Supporting stopping on a trigger of the Z-stop induction sensor, not only for the Z-minus movements. - #if defined(Z_MIN_PIN) && (Z_MIN_PIN > -1) && !defined(DEBUG_DISABLE_ZMINLIMIT) - if(check_z_endstop) { - // Check the Z min end-stop no matter what. - // Good for searching for the center of an induction target. - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on - z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING) || (READ(Z_TMC2130_DIAG) != 0); - #else - z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); - #endif //TMC2130_SG_HOMING - if(z_min_endstop && old_z_min_endstop) { + if ((out_bits & (1< -1) && !defined(DEBUG_DISABLE_ZMINLIMIT) + if (check_z_endstop) { + #ifdef TMC2130_SG_HOMING + // Stall guard homing turned on + z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING) || (READ(Z_TMC2130_DIAG) != 0); + #else + z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); + #endif //TMC2130_SG_HOMING + if(z_min_endstop && old_z_min_endstop && (current_block->steps_z.wide > 0)) { endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; endstop_z_hit=true; step_events_completed.wide = current_block->step_event_count.wide; } old_z_min_endstop = z_min_endstop; - } - #endif - - if ((out_bits & (1 << E_AXIS)) != 0) - { // -direction - //AKU - WRITE(E0_DIR_PIN, -#ifdef SNMM - (snmm_extruder == 0 || snmm_extruder == 2) ? !INVERT_E0_DIR : -#endif // SNMM - INVERT_E0_DIR); - count_direction[E_AXIS] = -1; - } - else - { // +direction - WRITE(E0_DIR_PIN, -#ifdef SNMM - (snmm_extruder == 0 || snmm_extruder == 2) ? INVERT_E0_DIR : -#endif // SNMM - !INVERT_E0_DIR); - count_direction[E_AXIS] = 1; - } - - for(uint8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves) - #ifndef AT90USB - MSerial.checkRx(); // Check for serial chars. - #endif //RP - returned, because missing characters - -#ifdef LIN_ADVANCE - counter_e.wide += current_block->steps_e.wide; - if (counter_e.wide > 0) { - counter_e.wide -= current_block->step_event_count.wide; - count_position[E_AXIS] += count_direction[E_AXIS]; - ((out_bits&(1<steps_x.wide; - if (counter_x.wide > 0) { - WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN); - LastStepMask |= X_AXIS_MASK; -#ifdef DEBUG_XSTEP_DUP_PIN - WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN); -#endif //DEBUG_XSTEP_DUP_PIN - counter_x.wide -= current_block->step_event_count.wide; - count_position[X_AXIS]+=count_direction[X_AXIS]; - WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN); -#ifdef DEBUG_XSTEP_DUP_PIN - WRITE_NC(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN); -#endif //DEBUG_XSTEP_DUP_PIN - } - - counter_y.wide += current_block->steps_y.wide; - if (counter_y.wide > 0) { - WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN); - LastStepMask |= Y_AXIS_MASK; -#ifdef DEBUG_YSTEP_DUP_PIN - WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN); -#endif //DEBUG_YSTEP_DUP_PIN - - #ifdef Y_DUAL_STEPPER_DRIVERS - WRITE_NC(Y2_STEP_PIN, !INVERT_Y_STEP_PIN); - #endif - - counter_y.wide -= current_block->step_event_count.wide; - count_position[Y_AXIS]+=count_direction[Y_AXIS]; - WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN); -#ifdef DEBUG_YSTEP_DUP_PIN - WRITE_NC(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN); -#endif //DEBUG_YSTEP_DUP_PIN - - #ifdef Y_DUAL_STEPPER_DRIVERS - WRITE_NC(Y2_STEP_PIN, INVERT_Y_STEP_PIN); - #endif - } - - counter_z.wide += current_block->steps_z.wide; - if (counter_z.wide > 0) { - WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN); - LastStepMask |= Z_AXIS_MASK; - #ifdef Z_DUAL_STEPPER_DRIVERS - WRITE_NC(Z2_STEP_PIN, !INVERT_Z_STEP_PIN); - #endif - - counter_z.wide -= current_block->step_event_count.wide; - count_position[Z_AXIS]+=count_direction[Z_AXIS]; - WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN); - - #ifdef Z_DUAL_STEPPER_DRIVERS - WRITE_NC(Z2_STEP_PIN, INVERT_Z_STEP_PIN); - #endif } - -#ifndef LIN_ADVANCE - counter_e.wide += current_block->steps_e.wide; - if (counter_e.wide > 0) { - WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); - counter_e.wide -= current_block->step_event_count.wide; - count_position[E_AXIS]+=count_direction[E_AXIS]; - WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); -#ifdef PAT9125 - fsensor_counter++; -#endif //PAT9125 + #endif + } else { // +direction + #if defined(Z_MAX_PIN) && (Z_MAX_PIN > -1) && !defined(DEBUG_DISABLE_ZMAXLIMIT) + #ifdef TMC2130_SG_HOMING + // Stall guard homing turned on + z_max_endstop = (READ(Z_TMC2130_DIAG) != 0); + #else + z_max_endstop = (READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING); + #endif //TMC2130_SG_HOMING + if(z_max_endstop && old_z_max_endstop && (current_block->steps_z.wide > 0)) { + endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; + endstop_z_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; } -#endif - - ++ step_events_completed.wide; - if(step_events_completed.wide >= current_block->step_event_count.wide) break; + old_z_max_endstop = z_max_endstop; + #endif } + } + + // Supporting stopping on a trigger of the Z-stop induction sensor, not only for the Z-minus movements. + #if defined(Z_MIN_PIN) && (Z_MIN_PIN > -1) && !defined(DEBUG_DISABLE_ZMINLIMIT) + if (check_z_endstop) { + // Check the Z min end-stop no matter what. + // Good for searching for the center of an induction target. + #ifdef TMC2130_SG_HOMING + // Stall guard homing turned on + z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING) || (READ(Z_TMC2130_DIAG) != 0); + #else + z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); + #endif //TMC2130_SG_HOMING + if(z_min_endstop && old_z_min_endstop) { + endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; + endstop_z_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_z_min_endstop = z_min_endstop; + } + #endif +} + +FORCE_INLINE void stepper_tick_lowres() +{ + for (uint8_t i=0; i < step_loops; ++ i) { // Take multiple steps per interrupt (For high speed moves) + MSerial.checkRx(); // Check for serial chars. +#ifdef LIN_ADVANCE + counter_e.lo += current_block->steps_e.lo; + if (counter_e.lo > 0) { + counter_e.lo -= current_block->step_event_count.lo; + count_position[E_AXIS] += count_direction[E_AXIS]; + ((out_bits&(1<steps_x.lo; + if (counter_x.lo > 0) { + WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN); + LastStepMask |= X_AXIS_MASK; +#ifdef DEBUG_XSTEP_DUP_PIN + WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN); +#endif //DEBUG_XSTEP_DUP_PIN + counter_x.lo -= current_block->step_event_count.lo; + count_position[X_AXIS]+=count_direction[X_AXIS]; + WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN); +#ifdef DEBUG_XSTEP_DUP_PIN + WRITE_NC(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN); +#endif //DEBUG_XSTEP_DUP_PIN + } + // Step in Y axis + counter_y.lo += current_block->steps_y.lo; + if (counter_y.lo > 0) { + WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN); + LastStepMask |= Y_AXIS_MASK; +#ifdef DEBUG_YSTEP_DUP_PIN + WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN); +#endif //DEBUG_YSTEP_DUP_PIN + counter_y.lo -= current_block->step_event_count.lo; + count_position[Y_AXIS]+=count_direction[Y_AXIS]; + WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN); +#ifdef DEBUG_YSTEP_DUP_PIN + WRITE_NC(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN); +#endif //DEBUG_YSTEP_DUP_PIN + } + // Step in Z axis + counter_z.lo += current_block->steps_z.lo; + if (counter_z.lo > 0) { + WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN); + LastStepMask |= Z_AXIS_MASK; + counter_z.lo -= current_block->step_event_count.lo; + count_position[Z_AXIS]+=count_direction[Z_AXIS]; + WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN); + } +#ifndef LIN_ADVANCE + // Step in E axis + counter_e.lo += current_block->steps_e.lo; + if (counter_e.lo > 0) { + WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); + counter_e.lo -= current_block->step_event_count.lo; + count_position[E_AXIS]+=count_direction[E_AXIS]; + WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); +#ifdef PAT9125 + ++ fsensor_counter; +#endif //PAT9125 + } +#endif + if(++ step_events_completed.lo >= current_block->step_event_count.lo) + break; + } +} + +FORCE_INLINE void stepper_tick_highres() +{ + for (uint8_t i=0; i < step_loops; ++ i) { // Take multiple steps per interrupt (For high speed moves) + MSerial.checkRx(); // Check for serial chars. +#ifdef LIN_ADVANCE + counter_e.wide += current_block->steps_e.wide; + if (counter_e.wide > 0) { + counter_e.wide -= current_block->step_event_count.wide; + count_position[E_AXIS] += count_direction[E_AXIS]; + ((out_bits&(1<steps_x.wide; + if (counter_x.wide > 0) { + WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN); + LastStepMask |= X_AXIS_MASK; +#ifdef DEBUG_XSTEP_DUP_PIN + WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN); +#endif //DEBUG_XSTEP_DUP_PIN + counter_x.wide -= current_block->step_event_count.wide; + count_position[X_AXIS]+=count_direction[X_AXIS]; + WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN); +#ifdef DEBUG_XSTEP_DUP_PIN + WRITE_NC(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN); +#endif //DEBUG_XSTEP_DUP_PIN + } + // Step in Y axis + counter_y.wide += current_block->steps_y.wide; + if (counter_y.wide > 0) { + WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN); + LastStepMask |= Y_AXIS_MASK; +#ifdef DEBUG_YSTEP_DUP_PIN + WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN); +#endif //DEBUG_YSTEP_DUP_PIN + counter_y.wide -= current_block->step_event_count.wide; + count_position[Y_AXIS]+=count_direction[Y_AXIS]; + WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN); +#ifdef DEBUG_YSTEP_DUP_PIN + WRITE_NC(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN); +#endif //DEBUG_YSTEP_DUP_PIN + } + // Step in Z axis + counter_z.wide += current_block->steps_z.wide; + if (counter_z.wide > 0) { + WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN); + LastStepMask |= Z_AXIS_MASK; + counter_z.wide -= current_block->step_event_count.wide; + count_position[Z_AXIS]+=count_direction[Z_AXIS]; + WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN); + } +#ifndef LIN_ADVANCE + // Step in E axis + counter_e.wide += current_block->steps_e.wide; + if (counter_e.wide > 0) { + WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); + counter_e.wide -= current_block->step_event_count.wide; + count_position[E_AXIS]+=count_direction[E_AXIS]; + WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); +#ifdef PAT9125 + ++ fsensor_counter; +#endif //PAT9125 + } +#endif + if(++ step_events_completed.wide >= current_block->step_event_count.wide) + break; + } +} + +void isr() { + //if (UVLO) uvlo(); + // If there is no current block, attempt to pop one from the buffer + if (current_block == NULL) + stepper_next_block(); + + LastStepMask = 0; + + if (current_block != NULL) + { + stepper_check_endstops(); + if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) + stepper_tick_lowres(); + else + stepper_tick_highres(); + #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { const int delta_adv_steps = current_estep_rate - current_adv_steps; @@ -754,10 +769,10 @@ void isr() { if (step_events_completed.wide <= (unsigned long int)current_block->accelerate_until) { // v = t * a -> acc_step_rate = acceleration_time * current_block->acceleration_rate MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate); - acc_step_rate += current_block->initial_rate; + acc_step_rate += uint16_t(current_block->initial_rate); // upper limit - if(acc_step_rate > current_block->nominal_rate) + if(acc_step_rate > uint16_t(current_block->nominal_rate)) acc_step_rate = current_block->nominal_rate; // step_rate to timer interval @@ -776,15 +791,15 @@ void isr() { MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate); if(step_rate > acc_step_rate) { // Check step_rate stays positive - step_rate = current_block->final_rate; + step_rate = uint16_t(current_block->final_rate); } else { step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. } // lower limit - if(step_rate < current_block->final_rate) - step_rate = current_block->final_rate; + if(step_rate < uint16_t(current_block->final_rate)) + step_rate = uint16_t(current_block->final_rate); // step_rate to timer interval timer = calc_timer(step_rate); @@ -830,9 +845,11 @@ void isr() { } #endif //PAT9125 } + #ifdef TMC2130 tmc2130_st_isr(LastStepMask); #endif //TMC2130 + #ifdef DEBUG_STEPPER_TIMER_MISSED // Verify whether the next planned timer interrupt has not been missed already. // This debugging test takes < 1.125us From 1eac2b4ccbfdd353a050670caa519e16ae396a27 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 15 Jan 2018 12:00:28 +0100 Subject: [PATCH 04/11] Fixed a regression error from the last commit regarding Z homing. Removed unused Z_LATE_ENABLE symbol. --- Firmware/Configuration_adv.h | 2 -- Firmware/stepper.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 36b247cd..90f72462 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -127,8 +127,6 @@ //END AUTOSET LOCATIONS OF LIMIT SWITCHES -ZP -//#define Z_LATE_ENABLE // Enable Z the last moment. Needed if your Z driver overheats. - // A single Z stepper driver is usually used to drive 2 stepper motors. // Uncomment this define to utilize a separate stepper driver for each Z axis motor. // Only a few motherboards support this, like RAMPS, which have dual extruder support (the 2nd, often unused, extruder driver is used diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index bb020c44..8ea867de 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -545,7 +545,7 @@ FORCE_INLINE void stepper_check_endstops() if ((out_bits & (1< -1) && !defined(DEBUG_DISABLE_ZMINLIMIT) - if (check_z_endstop) { + if (! check_z_endstop) { #ifdef TMC2130_SG_HOMING // Stall guard homing turned on z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING) || (READ(Z_TMC2130_DIAG) != 0); From 3b312a42f898cac64232f4c446485aac9ce66b19 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 2 Feb 2018 20:37:03 +0100 Subject: [PATCH 05/11] Adjusted the features for the debug buid: Removed DEBUG_DISABLE_STARTMSGS. This macro defeats the purpose of the build server and the build messages of the non-release builds. Removed DEBUG_DUMP_TO_2ND_SERIAL for performance reasons. --- Firmware/Configuration_prusa.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Firmware/Configuration_prusa.h b/Firmware/Configuration_prusa.h index df209fe6..74b146c3 100644 --- a/Firmware/Configuration_prusa.h +++ b/Firmware/Configuration_prusa.h @@ -119,7 +119,7 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o //#define DEBUG_DISABLE_YMAXLIMIT //y max limit ignored //#define DEBUG_DISABLE_ZMINLIMIT //z min limit ignored //#define DEBUG_DISABLE_ZMAXLIMIT //z max limit ignored -#define DEBUG_DISABLE_STARTMSGS //no startup messages +//#define DEBUG_DISABLE_STARTMSGS //no startup messages //#define DEBUG_DISABLE_MINTEMP //mintemp error ignored //#define DEBUG_DISABLE_SWLIMITS //sw limits ignored //#define DEBUG_DISABLE_LCD_STATUS_LINE //empty four lcd line @@ -130,7 +130,7 @@ const bool Z_MIN_ENDSTOP_INVERTING = false; // set to true to invert the logic o //#define DEBUG_BLINK_ACTIVE //#define DEBUG_DISABLE_FANCHECK //disable fan check (no ISR INT7, check disabled) //#define DEBUG_DISABLE_FSENSORCHECK //disable fsensor check (no ISR INT7, check disabled) -#define DEBUG_DUMP_TO_2ND_SERIAL //dump received characters to 2nd serial line +//#define DEBUG_DUMP_TO_2ND_SERIAL //dump received characters to 2nd serial line #define DEBUG_STEPPER_TIMER_MISSED // Stop on stepper timer overflow, beep and display a message. #define PLANNER_DIAGNOSTICS // Show the planner queue status on printer display. #endif /* DEBUG_BUILD */ From c2950b01a6b99a29ac568b3d8617ad8ed6cbfb12 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 2 Feb 2018 20:42:09 +0100 Subject: [PATCH 06/11] Added macros for outputting serial data onto the logical analyzer line at 2 megabaud, 9bits, 1 stop bit. At this high rate the serial output takes next to no time, so it does not slow down the debugged firmware too much, and the data is nicely aligned with the other debug signals on the logical analyzer screen. --- Firmware/pins_Einy_0_4.h | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/Firmware/pins_Einy_0_4.h b/Firmware/pins_Einy_0_4.h index 1c408d45..dd63d86e 100644 --- a/Firmware/pins_Einy_0_4.h +++ b/Firmware/pins_Einy_0_4.h @@ -142,11 +142,24 @@ #define LOGIC_ANALYZER_CH6 17 // PH1 (TXD2) #define LOGIC_ANALYZER_CH7 76 // PJ5 -#define LOGIC_ANALYZER_CH0_ENABLE SET_OUTPUT(LOGIC_ANALYZER_CH0) -#define LOGIC_ANALYZER_CH1_ENABLE SET_OUTPUT(LOGIC_ANALYZER_CH1) -#define LOGIC_ANALYZER_CH2_ENABLE SET_OUTPUT(LOGIC_ANALYZER_CH2) -#define LOGIC_ANALYZER_CH3_ENABLE SET_OUTPUT(LOGIC_ANALYZER_CH3) -#define LOGIC_ANALYZER_CH4_ENABLE do { DDRK |= 1 << 0; } while (0) -#define LOGIC_ANALYZER_CH5_ENABLE do { cbi(UCSR2B, TXEN2); cbi(UCSR2B, RXEN2); cbi(UCSR2B, RXCIE2); SET_OUTPUT(LOGIC_ANALYZER_CH5); } while (0) -#define LOGIC_ANALYZER_CH6_ENABLE do { cbi(UCSR2B, TXEN2); cbi(UCSR2B, RXEN2); cbi(UCSR2B, RXCIE2); SET_OUTPUT(LOGIC_ANALYZER_CH6); } while (0) -#define LOGIC_ANALYZER_CH7_ENABLE SET_OUTPUT(LOGIC_ANALYZER_CH7) +#define LOGIC_ANALYZER_CH0_ENABLE do { SET_OUTPUT(LOGIC_ANALYZER_CH0); WRITE(LOGIC_ANALYZER_CH0, false); } while (0) +#define LOGIC_ANALYZER_CH1_ENABLE do { SET_OUTPUT(LOGIC_ANALYZER_CH1); WRITE(LOGIC_ANALYZER_CH1, false); } while (0) +#define LOGIC_ANALYZER_CH2_ENABLE do { SET_OUTPUT(LOGIC_ANALYZER_CH2); WRITE(LOGIC_ANALYZER_CH2, false); } while (0) +#define LOGIC_ANALYZER_CH3_ENABLE do { SET_OUTPUT(LOGIC_ANALYZER_CH3); WRITE(LOGIC_ANALYZER_CH3, false); } while (0) +#define LOGIC_ANALYZER_CH4_ENABLE do { DDRK |= 1 << 0; WRITE_LOGIC_ANALYZER_CH4(false); } while (0) +#define LOGIC_ANALYZER_CH5_ENABLE do { cbi(UCSR2B, TXEN2); cbi(UCSR2B, RXEN2); cbi(UCSR2B, RXCIE2); SET_OUTPUT(LOGIC_ANALYZER_CH5); WRITE(LOGIC_ANALYZER_CH5, false); } while (0) +#define LOGIC_ANALYZER_CH6_ENABLE do { cbi(UCSR2B, TXEN2); cbi(UCSR2B, RXEN2); cbi(UCSR2B, RXCIE2); SET_OUTPUT(LOGIC_ANALYZER_CH6); WRITE(LOGIC_ANALYZER_CH6, false); } while (0) +#define LOGIC_ANALYZER_CH7_ENABLE do { SET_OUTPUT(LOGIC_ANALYZER_CH7); WRITE(LOGIC_ANALYZER_CH7, false); } while (0) + +// Async output on channel 5 of the logical analyzer. +// Baud rate 2MBit, 9 bits, 1 stop bit. +#define LOGIC_ANALYZER_SERIAL_TX_ENABLE do { UBRR2H = 0; UBRR2L = 0; UCSR2B = (1 << TXEN2) | (1 << UCSZ02); UCSR2C = 0x06; } while (0) +// Non-checked (quicker) variant. Use it if you are sure that the transmit buffer is already empty. +#define LOGIC_ANALYZER_SERIAL_TX_WRITE_NC(C) do { if (C & 0x100) UCSR2B |= 1; else UCSR2B &= ~1; UDR2 = C; } while (0) +#define LOGIC_ANALYZER_SERIAL_TX_WRITE(C) do { \ + /* Wait for empty transmit buffer */ \ + while (!(UCSR2A & (1< Date: Fri, 2 Feb 2018 20:45:45 +0100 Subject: [PATCH 07/11] A bit of documentation. --- Firmware/planner.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index d7f30d23..880ab650 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -186,12 +186,16 @@ FORCE_INLINE float intersection_distance(float initial_rate, float final_rate, f } } +// Minimum stepper rate 120Hz. #define MINIMAL_STEP_RATE 120 // Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { // These two lines are the only floating point calculations performed in this routine. + // initial_rate, final_rate in Hz. + // Minimum stepper rate 120Hz, maximum 40kHz. If the stepper rate goes above 10kHz, + // the stepper interrupt routine groups the pulses by 2 or 4 pulses per interrupt tick. uint32_t initial_rate = ceil(entry_speed * block->speed_factor); // (step/min) uint32_t final_rate = ceil(exit_speed * block->speed_factor); // (step/min) From 9acd41a942f4a24febea7c01bf4273de3835e4ca Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 2 Feb 2018 22:55:50 +0100 Subject: [PATCH 08/11] Reworked the stepper routine: 1) The computational load is spread more evenly along the stepper ISR ticks by moving some of the timer and linear advance calculation from the block initialization into the 1st tick of the steady phase of the trapezoid. 2) Reworked planning of the Linear Advance ISR ticks to fit the time slot allocated for the main stepper ISR tick. This is achieved by grouping the Linear Advance extruder ticks by a power of two to tick the Linear Advance interrupts at a maximum 7kHz. Also some of the extruder ticks are performed just after the XYZ ticks and if the remaining time slot for the Linear Advance ticks is too short, all the Linear Advance steps are ticked inside the main stepper ISR invocation. 3) Added some calls to MSerial.checkRx() if the stepper ISR routine is delayed for too long by the additional LinearAdvance ticks. This implementation differs significantly from the original implementation by @Sebastianv650, as this implementation tries to follow the exact timing of the XYZ axes with the drawback of possibly ticking the extruder faster than it could handle, while the original implementation by @Sebastianv650 ticks the extruder slower with the drawback of possibly spreading the XYZ ticks, thus introducing jerk in the cartesian movement. --- Firmware/stepper.cpp | 502 +++++++++++++++++++++++++------------------ 1 file changed, 291 insertions(+), 211 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 61a2f7f6..c636ae39 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -109,22 +109,24 @@ uint8_t LastStepMask = 0; #ifdef LIN_ADVANCE - uint16_t ADV_NEVER = 65535; - static uint16_t nextMainISR = 0; - static uint16_t nextAdvanceISR = ADV_NEVER; - static uint16_t eISR_Rate = ADV_NEVER; + static uint16_t eISR_Rate; - static volatile int e_steps; //Extrusion steps to be executed by the stepper - static int final_estep_rate; //Speed of extruder at cruising speed - static int current_estep_rate; //The current speed of the extruder - static int current_adv_steps; //The current pretension of filament expressed in steps - - #define ADV_RATE(T, L) (e_steps ? (T) * (L) / abs(e_steps) : ADV_NEVER) - #define _NEXT_ISR(T) nextMainISR = T + // 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; + #define _NEXT_ISR(T) nextMainISR = T #else - #define _NEXT_ISR(T) OCR1A = T + #define _NEXT_ISR(T) OCR1A = T #endif #ifdef DEBUG_STEPPER_TIMER_MISSED @@ -339,26 +341,6 @@ FORCE_INLINE unsigned short calc_timer(uint16_t step_rate) { return timer; } -// Initializes the trapezoid generator from the current block. Called whenever a new -// block begins. -FORCE_INLINE void trapezoid_generator_reset() { - deceleration_time = 0; - // step_rate to timer interval - OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate)); - // make a note of the number of step loops required at nominal speed - step_loops_nominal = step_loops; - acc_step_rate = uint16_t(current_block->initial_rate); - acceleration_time = calc_timer(acc_step_rate); - _NEXT_ISR(acceleration_time); - - #ifdef LIN_ADVANCE - if (current_block->use_advance_lead) { - current_estep_rate = ((unsigned long)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; - final_estep_rate = (current_block->nominal_rate * current_block->abs_adv_steps_multiplier8) >> 17; - } - #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) { @@ -366,16 +348,61 @@ ISR(TIMER1_COMPA_vect) { uint16_t sp = SPL + 256 * SPH; if (sp < SP_min) SP_min = sp; #endif //DEBUG_STACK_MONITOR - #ifdef LIN_ADVANCE - advance_isr_scheduler(); - #else - isr(); - #endif + +#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); + for (uint8_t i = estep_loops; e_steps && i --;) { + WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); + -- e_steps; + WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); + } + 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 + isr(); + + // Don't run the ISR faster than possible +// if (OCR1A < TCNT1 + 16) OCR1A = TCNT1 + 16; +#ifdef DEBUG_STEPPER_TIMER_MISSED + // Verify whether the next planned timer interrupt has not been missed already. + // This debugging test takes < 1.125us + // This skews the profiling slightly as the fastest stepper timer + // interrupt repeats at a 100us rate (10kHz). + if (OCR1A < TCNT1) { + stepper_timer_overflow_state = true; + WRITE_NC(BEEPER, HIGH); + SERIAL_PROTOCOLPGM("Stepper timer overflow "); + SERIAL_PROTOCOL(OCR1A); + SERIAL_PROTOCOLPGM("<"); + SERIAL_PROTOCOL(TCNT1); + SERIAL_PROTOCOLLN("!"); + } +#endif } FORCE_INLINE void stepper_next_block() { // Anything in the buffer? + //WRITE_NC(LOGIC_ANALYZER_CH2, true); current_block = plan_get_current_block(); if (current_block != NULL) { #ifdef PAT9125 @@ -384,7 +411,19 @@ FORCE_INLINE void stepper_next_block() #endif //PAT9125 // The busy flag is set by the plan_get_current_block() call. // current_block->busy = true; - trapezoid_generator_reset(); + // Initializes the trapezoid generator from the current block. Called whenever a new + // block begins. + deceleration_time = 0; + // Set the nominal step loops to zero to indicate, that the timer value is not known yet. + // That means, delay the initialization of nominal step rate and step loops until the steady + // state is reached. + 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 (current_block->flag & BLOCK_FLAG_DDA_LOWRES) { counter_x.lo = -(current_block->step_event_count.lo >> 1); counter_y.lo = counter_x.lo; @@ -421,27 +460,30 @@ FORCE_INLINE void stepper_next_block() WRITE_NC(Z_DIR_PIN,!INVERT_Z_DIR); count_direction[Z_AXIS]=1; } -#ifndef LIN_ADVANCE if ((out_bits & (1 << E_AXIS)) != 0) { // -direction +#ifndef LIN_ADVANCE WRITE(E0_DIR_PIN, #ifdef SNMM (snmm_extruder == 0 || snmm_extruder == 2) ? !INVERT_E0_DIR : #endif // SNMM INVERT_E0_DIR); +#endif /* LIN_ADVANCE */ count_direction[E_AXIS] = -1; } else { // +direction +#ifndef LIN_ADVANCE WRITE(E0_DIR_PIN, #ifdef SNMM (snmm_extruder == 0 || snmm_extruder == 2) ? INVERT_E0_DIR : #endif // SNMM !INVERT_E0_DIR); +#endif /* LIN_ADVANCE */ count_direction[E_AXIS] = 1; } -#endif /* LIN_ADVANCE */ } else { - _NEXT_ISR(2000); // 1kHz. + OCR1A = 2000; // 1kHz. } + //WRITE_NC(LOGIC_ANALYZER_CH2, false); } // Check limit switches. @@ -588,14 +630,6 @@ FORCE_INLINE void stepper_tick_lowres() { for (uint8_t i=0; i < step_loops; ++ i) { // Take multiple steps per interrupt (For high speed moves) MSerial.checkRx(); // Check for serial chars. -#ifdef LIN_ADVANCE - counter_e.lo += current_block->steps_e.lo; - if (counter_e.lo > 0) { - counter_e.lo -= current_block->step_event_count.lo; - count_position[E_AXIS] += count_direction[E_AXIS]; - ((out_bits&(1<steps_x.lo; if (counter_x.lo > 0) { @@ -635,19 +669,23 @@ FORCE_INLINE void stepper_tick_lowres() count_position[Z_AXIS]+=count_direction[Z_AXIS]; WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN); } -#ifndef LIN_ADVANCE // Step in E axis counter_e.lo += current_block->steps_e.lo; if (counter_e.lo > 0) { +#ifndef LIN_ADVANCE WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); +#endif /* LIN_ADVANCE */ counter_e.lo -= current_block->step_event_count.lo; - count_position[E_AXIS]+=count_direction[E_AXIS]; - WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); -#ifdef PAT9125 + count_position[E_AXIS] += count_direction[E_AXIS]; +#ifdef LIN_ADVANCE + ++ e_steps; +#else + #ifdef PAT9125 ++ fsensor_counter; -#endif //PAT9125 - } + #endif //PAT9125 + WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #endif + } if(++ step_events_completed.lo >= current_block->step_event_count.lo) break; } @@ -657,14 +695,6 @@ FORCE_INLINE void stepper_tick_highres() { for (uint8_t i=0; i < step_loops; ++ i) { // Take multiple steps per interrupt (For high speed moves) MSerial.checkRx(); // Check for serial chars. -#ifdef LIN_ADVANCE - counter_e.wide += current_block->steps_e.wide; - if (counter_e.wide > 0) { - counter_e.wide -= current_block->step_event_count.wide; - count_position[E_AXIS] += count_direction[E_AXIS]; - ((out_bits&(1<steps_x.wide; if (counter_x.wide > 0) { @@ -704,25 +734,34 @@ FORCE_INLINE void stepper_tick_highres() count_position[Z_AXIS]+=count_direction[Z_AXIS]; WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN); } -#ifndef LIN_ADVANCE // Step in E axis counter_e.wide += current_block->steps_e.wide; if (counter_e.wide > 0) { +#ifndef LIN_ADVANCE WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); +#endif /* LIN_ADVANCE */ counter_e.wide -= current_block->step_event_count.wide; count_position[E_AXIS]+=count_direction[E_AXIS]; - WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); -#ifdef PAT9125 +#ifdef LIN_ADVANCE + ++ e_steps; +#else + #ifdef PAT9125 ++ fsensor_counter; -#endif //PAT9125 - } + #endif //PAT9125 + WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #endif + } if(++ step_events_completed.wide >= current_block->step_event_count.wide) break; } } -void isr() { +// 50us delay +#define LIN_ADV_FIRST_TICK_DELAY 100 + +FORCE_INLINE void isr() { + //WRITE_NC(LOGIC_ANALYZER_CH0, true); + //if (UVLO) uvlo(); // If there is no current block, attempt to pop one from the buffer if (current_block == NULL) @@ -733,101 +772,215 @@ 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) { - const int delta_adv_steps = current_estep_rate - current_adv_steps; - current_adv_steps += delta_adv_steps; - e_steps += delta_adv_steps; - } - // If we have esteps to execute, fire the next advance_isr "now" - if (e_steps) nextAdvanceISR = 0; -#endif - - // Calculare new timer value - unsigned short timer; - uint16_t step_rate; - if (step_events_completed.wide <= (unsigned long int)current_block->accelerate_until) { - // v = t * a -> acc_step_rate = acceleration_time * current_block->acceleration_rate - MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate); - acc_step_rate += uint16_t(current_block->initial_rate); - - // upper limit - if(acc_step_rate > uint16_t(current_block->nominal_rate)) - acc_step_rate = current_block->nominal_rate; - - // step_rate to timer interval - timer = calc_timer(acc_step_rate); - _NEXT_ISR(timer); - acceleration_time += timer; - -#ifdef LIN_ADVANCE - if (current_block->use_advance_lead) { - current_estep_rate = ((uint32_t)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; + //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); } - eISR_Rate = ADV_RATE(timer, step_loops); #endif - } - else if (step_events_completed.wide > (unsigned long int)current_block->decelerate_after) { - MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate); + 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 == (snmm_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 PAT9125 + fsensor_counter += estep_loops; + #endif //PAT9125 + 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 - if(step_rate > acc_step_rate) { // Check step_rate stays positive - step_rate = uint16_t(current_block->final_rate); + // Calculare new timer value + // 13.38-14.63us for steady state, + // 25.12us for acceleration / deceleration. + { + //WRITE_NC(LOGIC_ANALYZER_CH1, true); + if (step_events_completed.wide <= (unsigned long int)current_block->accelerate_until) { + // v = t * a -> acc_step_rate = acceleration_time * current_block->acceleration_rate + MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate); + acc_step_rate += uint16_t(current_block->initial_rate); + // upper limit + 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); + _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 + } + else if (step_events_completed.wide > (unsigned long int)current_block->decelerate_after) { + uint16_t step_rate; + MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate); + step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. + if ((step_rate & 0x8000) || step_rate < uint16_t(current_block->final_rate)) { + // Result is negative or too small. + step_rate = uint16_t(current_block->final_rate); + } + // Step_rate to timer interval. + 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 } else { - step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. - } - - // lower limit - if(step_rate < uint16_t(current_block->final_rate)) - step_rate = uint16_t(current_block->final_rate); - - // step_rate to timer interval - 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; + 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 } - eISR_Rate = ADV_RATE(timer, step_loops); -#endif + _NEXT_ISR(OCR1A_nominal); + } + //WRITE_NC(LOGIC_ANALYZER_CH1, false); } - else { + #ifdef LIN_ADVANCE - if (current_block->use_advance_lead) - current_estep_rate = final_estep_rate; - - eISR_Rate = ADV_RATE(OCR1A_nominal, step_loops_nominal); + 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. + #ifdef PAT9125 + fsensor_counter += e_steps; + #endif //PAT9125 + MSerial.checkRx(); // Check for serial chars. + 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 - _NEXT_ISR(OCR1A_nominal); - // ensure we're running at the correct step rate, even if we just came off an acceleration - step_loops = step_loops_nominal; - } - // If current block is finished, reset pointer if (step_events_completed.wide >= current_block->step_event_count.wide) { - #ifdef PAT9125 fsensor_st_block_chunk(current_block, fsensor_counter); - fsensor_counter = 0; + fsensor_counter = 0; #endif //PAT9125 - current_block = NULL; plan_discard_current_block(); } #ifdef PAT9125 - else if (fsensor_counter >= fsensor_chunk_len) - { + else if (fsensor_counter >= fsensor_chunk_len) + { fsensor_st_block_chunk(current_block, fsensor_counter); - fsensor_counter = 0; - } + fsensor_counter = 0; + } #endif //PAT9125 } @@ -835,83 +988,10 @@ void isr() { tmc2130_st_isr(LastStepMask); #endif //TMC2130 -#ifdef DEBUG_STEPPER_TIMER_MISSED - // Verify whether the next planned timer interrupt has not been missed already. - // This debugging test takes < 1.125us - // This skews the profiling slightly as the fastest stepper timer - // interrupt repeats at a 100us rate (10kHz). - if (OCR1A < TCNT1) { - stepper_timer_overflow_state = true; - WRITE_NC(BEEPER, HIGH); - SERIAL_PROTOCOLPGM("Stepper timer overflow "); - SERIAL_PROTOCOL(OCR1A); - SERIAL_PROTOCOLPGM("<"); - SERIAL_PROTOCOL(TCNT1); - SERIAL_PROTOCOLLN("!"); - } -#endif + //WRITE_NC(LOGIC_ANALYZER_CH0, false); } #ifdef LIN_ADVANCE - - // Timer interrupt for E. e_steps is set in the main routine. - -void advance_isr() { - if (e_steps) { - 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_NC(E0_DIR_PIN, dir); - - for (uint8_t i = step_loops; e_steps && i--;) { - WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); - e_steps < 0 ? ++e_steps : --e_steps; - WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); -#ifdef PAT9125 - fsensor_counter++; -#endif //PAT9125 - - } - } - else { - eISR_Rate = ADV_NEVER; - } - nextAdvanceISR = eISR_Rate; -} - -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; - } - - // Don't run the ISR faster than possible - if (OCR1A < TCNT1 + 16) OCR1A = TCNT1 + 16; -} void clear_current_adv_vars() { e_steps = 0; //Should be already 0 at an filament change event, but just to be sure.. From 2babbb3b112566e1076a98c27a5a1d02fe0ab687 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 2 Feb 2018 22:56:13 +0100 Subject: [PATCH 09/11] Enabled linear advance. --- Firmware/Configuration_adv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 90f72462..318036cd 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -316,7 +316,7 @@ * K=0 means advance disabled. * See Marlin documentation for calibration instructions. */ -//#define LIN_ADVANCE +#define LIN_ADVANCE #ifdef LIN_ADVANCE #define LIN_ADVANCE_K 0 //Try around 45 for PLA, around 25 for ABS. From dd2468d306b358d0645afa92baa162ccfd0220ac Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 15 Feb 2018 11:44:19 +0100 Subject: [PATCH 10/11] Avoid the stepper interrupt being missed by extending the tick time beyond the current time. This is a trick borrwed from upstream Marlin. In debug mode, watch for the missed stepper interrupt ticks where the interrupts are missed by more than 20% of the 10kHz stepper interrupt repeat rate, and show the statistics (number of missed ticks and by how many micro seconds was the interrupt missed, and what was the maximum missed interrupt delay) on the display and send it to the serial line. --- Firmware/stepper.cpp | 32 ++++++++++++++++++-------------- Firmware/ultralcd.cpp | 19 +++++++++++++------ 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index c636ae39..3ac2ffc2 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -131,6 +131,7 @@ uint8_t LastStepMask = 0; #ifdef DEBUG_STEPPER_TIMER_MISSED extern bool stepper_timer_overflow_state; +extern uint16_t stepper_timer_overflow_last; #endif /* DEBUG_STEPPER_TIMER_MISSED */ //=========================================================================== @@ -381,22 +382,25 @@ ISR(TIMER1_COMPA_vect) { isr(); // Don't run the ISR faster than possible -// if (OCR1A < TCNT1 + 16) OCR1A = TCNT1 + 16; + // Is there a 8us time left before the next interrupt triggers? + if (OCR1A < TCNT1 + 16) { #ifdef DEBUG_STEPPER_TIMER_MISSED - // Verify whether the next planned timer interrupt has not been missed already. - // This debugging test takes < 1.125us - // This skews the profiling slightly as the fastest stepper timer - // interrupt repeats at a 100us rate (10kHz). - if (OCR1A < TCNT1) { - stepper_timer_overflow_state = true; - WRITE_NC(BEEPER, HIGH); - SERIAL_PROTOCOLPGM("Stepper timer overflow "); - SERIAL_PROTOCOL(OCR1A); - SERIAL_PROTOCOLPGM("<"); - SERIAL_PROTOCOL(TCNT1); - SERIAL_PROTOCOLLN("!"); - } + // Verify whether the next planned timer interrupt has not been missed already. + // This debugging test takes < 1.125us + // This skews the profiling slightly as the fastest stepper timer + // interrupt repeats at a 100us rate (10kHz). + if (OCR1A + 40 < TCNT1) { + // The interrupt was delayed by more than 20us (which is 1/5th of the 10kHz ISR repeat rate). + // Give a warning. + stepper_timer_overflow_state = true; + stepper_timer_overflow_last = TCNT1 - OCR1A; + // Beep, the beeper will be cleared at the stepper_timer_overflow() called from the main thread. + WRITE(BEEPER, HIGH); + } #endif + // Fix the next interrupt to be executed after 8us from now. + OCR1A = TCNT1 + 16; + } } FORCE_INLINE void stepper_next_block() diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 29c0ed40..6a14a916 100644 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -5182,14 +5182,21 @@ void stack_error() { #ifdef DEBUG_STEPPER_TIMER_MISSED bool stepper_timer_overflow_state = false; +uint16_t stepper_timer_overflow_max = 0; +uint16_t stepper_timer_overflow_last = 0; +uint16_t stepper_timer_overflow_cnt = 0; void stepper_timer_overflow() { - SET_OUTPUT(BEEPER); - WRITE(BEEPER, HIGH); - delay(1000); + char msg[28]; + sprintf_P(msg, PSTR("#%d %d max %d"), ++ stepper_timer_overflow_cnt, stepper_timer_overflow_last >> 1, stepper_timer_overflow_max >> 1); + lcd_setstatus(msg); + stepper_timer_overflow_state = false; + if (stepper_timer_overflow_last > stepper_timer_overflow_max) + stepper_timer_overflow_max = stepper_timer_overflow_last; + SERIAL_ECHOPGM("Stepper timer overflow: "); + MYSERIAL.print(msg); + SERIAL_ECHOLNPGM(""); + WRITE(BEEPER, LOW); - lcd_display_message_fullscreen_P(MSG_STEPPER_TIMER_OVERFLOW_ERROR); - //err_triggered = 1; - while (1) delay_keep_alive(1000); } #endif /* DEBUG_STEPPER_TIMER_MISSED */ From a0bcfc7d95c5b9275872599dcf45a00a38eaa4bd Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 5 Mar 2018 19:28:57 +0100 Subject: [PATCH 11/11] Fix after merge (symbol calculate_volumetric_multipliers() renamed to calculate_extruder_multipliers()) --- Firmware/ConfigurationStore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index 253452fe..26cbc822 100644 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -378,8 +378,8 @@ bool Config_RetrieveSettings(uint16_t offset, uint8_t level) EEPROM_READ_VAR(i, extruder_advance_k); EEPROM_READ_VAR(i, advance_ed_ratio); } - calculate_volumetric_multipliers(); #endif //LIN_ADVANCE + calculate_extruder_multipliers(); // Call updatePID (similar to when we have processed M301) updatePID();