Pārlūkot izejas kodu

Removed the non-working pressure advance feature.
Improved accuracy of diagonal moves by oversampling the path discretization.
Accelerated the planner by rewriting time critical routines from floating
point to fixed point arithmetics.

bubnikv 7 gadi atpakaļ
vecāks
revīzija
29cb4b2b5d

+ 4 - 14
Firmware/Marlin_main.cpp

@@ -1038,22 +1038,15 @@ void setup()
   // is being written into the EEPROM, so the update procedure will be triggered only once.
     lang_selected = eeprom_read_byte((uint8_t*)EEPROM_LANG);
     if (lang_selected >= LANG_NUM){
-    lcd_mylang();
+      lcd_mylang();
     }
     
   if (eeprom_read_byte((uint8_t*)EEPROM_BABYSTEP_Z_SET) == 0x0ff) {
       // Reset the babystepping values, so the printer will not move the Z axis up when the babystepping is enabled.
-      // eeprom_update_byte((uint8_t*)EEPROM_BABYSTEP_X, 0x0ff);
-      // eeprom_update_byte((uint8_t*)EEPROM_BABYSTEP_Y, 0x0ff);
-      eeprom_update_byte((uint8_t*)EEPROM_BABYSTEP_Z, 0x0ff);
-      // Get the selected laugnage index before display update.
-      lang_selected = eeprom_read_byte((uint8_t*)EEPROM_LANG);
-      if (lang_selected >= LANG_NUM)
-          lang_selected = LANG_ID_DEFAULT; // Czech language
+      eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0);
       // Show the message.
       lcd_show_fullscreen_message_and_wait_P(MSG_BABYSTEP_Z_NOT_SET);
       lcd_update_enable(true);
-      // lcd_implementation_clear();
   }
 
   // Store the currently running firmware into an eeprom,
@@ -2961,8 +2954,9 @@ void process_commands()
                 bool result = sample_mesh_and_store_reference();
                 // if (result) babystep_apply();
             } else {
-                // Reset the baby step value.
+                // Reset the baby step value and the baby step applied flag.
                 eeprom_write_byte((unsigned char*)EEPROM_BABYSTEP_Z_SET, 0xFF);
+                eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0);
                 // Complete XYZ calibration.
                 BedSkewOffsetDetectionResultType result = find_bed_offset_and_skew(verbosity_level);
                 uint8_t point_too_far_mask = 0;
@@ -4820,11 +4814,7 @@ void prepare_move()
 
   // Do not use feedmultiply for E or Z only moves
   if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) {
-#ifdef MESH_BED_LEVELING
-      mesh_plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
-#else
       plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
-#endif
   }
   else {
 #ifdef MESH_BED_LEVELING

+ 158 - 109
Firmware/planner.cpp

@@ -110,6 +110,11 @@ block_t block_buffer[BLOCK_BUFFER_SIZE];            // A ring buffer for motion
 volatile unsigned char block_buffer_head;           // Index of the next block to be pushed
 volatile unsigned char block_buffer_tail;           // Index of the block to process now
 
+#ifdef PLANNER_DIAGNOSTICS
+// Diagnostic function: Minimum number of planned moves since the last 
+static uint8_t g_cntr_planner_queue_min = 0;
+#endif /* PLANNER_DIAGNOSTICS */
+
 //===========================================================================
 //=============================private variables ============================
 //===========================================================================
@@ -171,59 +176,86 @@ FORCE_INLINE float intersection_distance(float initial_rate, float final_rate, f
   }
 }
 
-// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors.
+#define MINIMAL_STEP_RATE 120
 
-void calculate_trapezoid_for_block(block_t *block, float entry_factor, float exit_factor) {
-  unsigned long initial_rate = ceil(block->nominal_rate*entry_factor); // (step/min)
-  unsigned long final_rate = ceil(block->nominal_rate*exit_factor); // (step/min)
+// 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.
+  uint32_t initial_rate = ceil(entry_speed * block->speed_factor); // (step/min)
+  uint32_t final_rate   = ceil(exit_speed  * block->speed_factor); // (step/min)
 
   // Limit minimal step rate (Otherwise the timer will overflow.)
-  if(initial_rate <120) {
-    initial_rate=120; 
-  }
-  if(final_rate < 120) {
-    final_rate=120;  
-  }
-
-  long acceleration = block->acceleration_st;
-  int32_t accelerate_steps =
-    ceil(estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration));
-  int32_t decelerate_steps =
-    floor(estimate_acceleration_distance(block->nominal_rate, final_rate, -acceleration));
-
-  // Calculate the size of Plateau of Nominal Rate.
-  int32_t plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps;
+  if (initial_rate < MINIMAL_STEP_RATE)
+      initial_rate = MINIMAL_STEP_RATE;
+  if (initial_rate > block->nominal_rate)
+      initial_rate = block->nominal_rate;
+  if (final_rate < MINIMAL_STEP_RATE)
+      final_rate = MINIMAL_STEP_RATE;
+  if (final_rate > block->nominal_rate)
+      final_rate = block->nominal_rate;
+
+  uint32_t acceleration      = block->acceleration_st;
+  if (acceleration == 0)
+      // Don't allow zero acceleration.
+      acceleration = 1;
+  // estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration)
+  // (target_rate*target_rate-initial_rate*initial_rate)/(2.0*acceleration));
+  uint32_t initial_rate_sqr  = initial_rate*initial_rate;
+  //FIXME assert that this result fits a 64bit unsigned int.
+  uint32_t nominal_rate_sqr  = block->nominal_rate*block->nominal_rate;
+  uint32_t final_rate_sqr    = final_rate*final_rate;
+  uint32_t acceleration_x2   = acceleration << 1;
+  // ceil(estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration));
+  uint32_t accelerate_steps  = (nominal_rate_sqr - initial_rate_sqr + acceleration_x2 - 1) / acceleration_x2;
+  // floor(estimate_acceleration_distance(block->nominal_rate, final_rate, -acceleration));
+  uint32_t decelerate_steps  = (nominal_rate_sqr - final_rate_sqr) / acceleration_x2;
+  uint32_t accel_decel_steps = accelerate_steps + decelerate_steps;
+  // Size of Plateau of Nominal Rate.
+  uint32_t plateau_steps     = 0;
 
   // 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 (plateau_steps < 0) {
-    accelerate_steps = ceil(intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count));
-    accelerate_steps = max(accelerate_steps,0); // Check limits due to numerical round-off
-    accelerate_steps = min((uint32_t)accelerate_steps,block->step_event_count);//(We can cast here to unsigned, because the above line ensures that we are above zero)
-    plateau_steps = 0;
+  if (accel_decel_steps < block->step_event_count) {
+    plateau_steps = block->step_event_count - accel_decel_steps;
+  } else {
+    uint32_t acceleration_x4  = acceleration << 2;
+    // Avoid negative numbers
+    if (final_rate_sqr >= initial_rate_sqr) {
+        // accelerate_steps = ceil(intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count));
+        // intersection_distance(float initial_rate, float final_rate, float acceleration, float distance) 
+        // (2.0*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/(4.0*acceleration);
+//        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;
+        accelerate_steps = final_rate_sqr - initial_rate_sqr + acceleration_x4 - 1;
+        if (block->step_event_count & 1)
+            accelerate_steps += acceleration_x2;
+        accelerate_steps += block->step_event_count >> 1;
+        accelerate_steps /= acceleration_x4;
+        if (accelerate_steps > block->step_event_count)
+            accelerate_steps = block->step_event_count;
+    } else {
+//        decelerate_steps = (block->step_event_count >> 1) + (initial_rate_sqr - final_rate_sqr + (block->step_event_count & 1) * acceleration_x2) / acceleration_x4;
+        decelerate_steps = initial_rate_sqr - final_rate_sqr;
+        if (block->step_event_count & 1)
+            decelerate_steps += acceleration_x2;
+        decelerate_steps += block->step_event_count >> 1;
+        decelerate_steps /= acceleration_x4;
+        if (decelerate_steps > block->step_event_count)
+            decelerate_steps = block->step_event_count;
+        accelerate_steps = block->step_event_count - decelerate_steps;
+    }
   }
 
-#ifdef ADVANCE
-  volatile long initial_advance = block->advance*entry_factor*entry_factor; 
-  volatile long final_advance = block->advance*exit_factor*exit_factor;
-#endif // ADVANCE
-
-  // block->accelerate_until = accelerate_steps;
-  // block->decelerate_after = accelerate_steps+plateau_steps;
   CRITICAL_SECTION_START;  // Fill variables used by the stepper in a critical section
   if (! block->busy) { // Don't update variables if block is busy.
     block->accelerate_until = accelerate_steps;
     block->decelerate_after = accelerate_steps+plateau_steps;
     block->initial_rate = initial_rate;
     block->final_rate = final_rate;
-#ifdef ADVANCE
-    block->initial_advance = initial_advance;
-    block->final_advance = final_advance;
-#endif //ADVANCE
   }
   CRITICAL_SECTION_END;
-}                    
+}
 
 // Calculates the maximum allowable entry speed, when you must be able to reach target_velocity using the 
 // decceleration within the allotted distance.
@@ -249,6 +281,27 @@ FORCE_INLINE float max_allowable_entry_speed(float decceleration, float target_v
 // the set limit. Finally it will:
 //
 //   3. Recalculate trapezoids for all blocks.
+//
+//FIXME This routine is called 15x every time a new line is added to the planner,
+// therefore it is a bottle neck and it shall be rewritten into a Fixed Point arithmetics,
+// if the CPU is found lacking computational power.
+//
+// Following sources may be used to optimize the 8-bit AVR code:
+// http://www.mikrocontroller.net/articles/AVR_Arithmetik
+// http://darcy.rsgc.on.ca/ACES/ICE4M/FixedPoint/avrfix.pdf
+// 
+// https://github.com/gcc-mirror/gcc/blob/master/libgcc/config/avr/lib1funcs-fixed.S
+// https://gcc.gnu.org/onlinedocs/gcc/Fixed-Point.html
+// https://gcc.gnu.org/onlinedocs/gccint/Fixed-point-fractional-library-routines.html
+// 
+// https://ucexperiment.wordpress.com/2015/04/04/arduino-s15-16-fixed-point-math-routines/
+// https://mekonik.wordpress.com/2009/03/18/arduino-avr-gcc-multiplication/
+// https://github.com/rekka/avrmultiplication
+// 
+// https://people.ece.cornell.edu/land/courses/ece4760/Math/Floating_point/
+// https://courses.cit.cornell.edu/ee476/Math/
+// https://courses.cit.cornell.edu/ee476/Math/GCC644/fixedPt/multASM.S
+//
 void planner_recalculate(const float &safe_final_speed) 
 {
     // Reverse pass
@@ -291,8 +344,12 @@ void planner_recalculate(const float &safe_final_speed)
                 // segment and the maximum acceleration allowed for this segment.
                 // If nominal length true, max junction speed is guaranteed to be reached even if decelerating to a jerk-from-zero velocity.
                 // Only compute for max allowable speed if block is decelerating and nominal length is false.
+                // entry_speed is uint16_t, 24 bits would be sufficient for block->acceleration and block->millimiteres, if scaled to um.
+                // therefore an optimized assembly 24bit x 24bit -> 32bit multiply would be more than sufficient
+                // together with an assembly 32bit->16bit sqrt function.
                 current->entry_speed = ((current->flag & BLOCK_FLAG_NOMINAL_LENGTH) || current->max_entry_speed <= next->entry_speed) ?
                     current->max_entry_speed :
+                    // min(current->max_entry_speed, sqrt(next->entry_speed*next->entry_speed+2*current->acceleration*current->millimeters));
                     min(current->max_entry_speed, max_allowable_entry_speed(-current->acceleration,next->entry_speed,current->millimeters));
                 current->flag |= BLOCK_FLAG_RECALCULATE;
             }
@@ -325,7 +382,7 @@ void planner_recalculate(const float &safe_final_speed)
             // Recalculate if current block entry or exit junction speed has changed.
             if ((prev->flag | current->flag) & BLOCK_FLAG_RECALCULATE) {
                 // NOTE: Entry and exit factors always > 0 by all previous logic operations.
-                calculate_trapezoid_for_block(prev, prev->entry_speed/prev->nominal_speed, current->entry_speed/prev->nominal_speed);
+                calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed);
                 // Reset current only to ensure next trapezoid is computed.
                 prev->flag &= ~BLOCK_FLAG_RECALCULATE;
             }
@@ -338,7 +395,7 @@ void planner_recalculate(const float &safe_final_speed)
 
     // Last/newest block in buffer. Exit speed is set with safe_final_speed. Always recalculated.
     current = block_buffer + prev_block_index(block_buffer_head);
-    calculate_trapezoid_for_block(current, current->entry_speed/current->nominal_speed, safe_final_speed/current->nominal_speed);
+    calculate_trapezoid_for_block(current, current->entry_speed, safe_final_speed);
     current->flag &= ~BLOCK_FLAG_RECALCULATE;
 
 //    SERIAL_ECHOLNPGM("planner_recalculate - 4");
@@ -471,6 +528,15 @@ void planner_abort_soft()
 }
 */
 
+#ifdef PLANNER_DIAGNOSTICS
+static inline void planner_update_queue_min_counter()
+{
+  uint8_t new_counter = moves_planned();
+  if (new_counter < g_cntr_planner_queue_min)
+    g_cntr_planner_queue_min = new_counter;
+}
+#endif /* PLANNER_DIAGNOSTICS */
+
 void planner_abort_hard()
 {
     // Abort the stepper routine and flush the planner queue.
@@ -527,11 +593,18 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
           manage_inactivity(false); 
           lcd_update();
       } while (block_buffer_tail == next_buffer_head);
-      if (waiting_inside_plan_buffer_line_print_aborted)
+      if (waiting_inside_plan_buffer_line_print_aborted) {
           // Inside the lcd_update() routine the print has been aborted.
           // Cancel the print, do not plan the current line this routine is waiting on.
+#ifdef PLANNER_DIAGNOSTICS
+          planner_update_queue_min_counter();
+#endif /* PLANNER_DIAGNOSTICS */
           return;
+      }
   }
+#ifdef PLANNER_DIAGNOSTICS
+  planner_update_queue_min_counter();
+#endif /* PLANNER_DIAGNOSTICS */
 
 #ifdef ENABLE_AUTO_BED_LEVELING
   apply_rotation_xyz(plan_bed_level_matrix, x, y, z);
@@ -637,14 +710,20 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi
 #endif
   block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]);
   block->steps_e = labs(target[E_AXIS]-position[E_AXIS]);
-  block->steps_e *= volumetric_multiplier[active_extruder];
-  block->steps_e *= extrudemultiply;
-  block->steps_e /= 100;
+  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)));
 
   // Bail if this is a zero-length block
   if (block->step_event_count <= dropsegments)
   { 
+#ifdef PLANNER_DIAGNOSTICS
+    planner_update_queue_min_counter();
+#endif /* PLANNER_DIAGNOSTICS */
     return; 
   }
 
@@ -869,6 +948,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)
   {
@@ -888,49 +969,27 @@ Having the real displacement of the head, we can calculate the total movement le
     if(((float)block->acceleration_st * (float)block->steps_z / (float)block->step_event_count ) > axis_steps_per_sqr_second[Z_AXIS])
       block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS];
   }
+  // Acceleration of the segment, in mm/sec^2
   block->acceleration = block->acceleration_st / steps_per_mm;
-  block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0)));
 
-#if 0  // Use old jerk for now
-  // Compute path unit vector
-  double unit_vec[3];
-
-  unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters;
-  unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters;
-  unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;
-
-  // Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
-  // Let a circle be tangent to both previous and current path line segments, where the junction
-  // deviation is defined as the distance from the junction to the closest edge of the circle,
-  // colinear with the circle center. The circular segment joining the two paths represents the
-  // path of centripetal acceleration. Solve for max velocity based on max acceleration about the
-  // radius of the circle, defined indirectly by junction deviation. This may be also viewed as
-  // path width or max_jerk in the previous grbl version. This approach does not actually deviate
-  // from path, but used as a robust way to compute cornering speeds, as it takes into account the
-  // nonlinearities of both the junction angle and junction velocity.
-  double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed
-
-  // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
-  if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) {
-    // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
-    // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
-    double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
-      - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
-      - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;
-
-    // Skip and use default max junction speed for 0 degree acute junction.
-    if (cos_theta < 0.95) {
-      vmax_junction = min(previous_nominal_speed,block->nominal_speed);
-      // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.
-      if (cos_theta > -0.95) {
-        // Compute maximum junction velocity based on maximum acceleration and junction deviation
-        double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive.
-        vmax_junction = min(vmax_junction,
-        sqrt(block->acceleration * junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) );
-      }
-    }
+#if 1
+  // Oversample diagonal movements by a power of 2 up to 8x
+  // to achieve more accurate diagonal movements.
+  uint8_t bresenham_oversample = 1;
+  for (uint8_t i = 0; i < 3; ++ i) {
+    if (block->nominal_rate >= 5000) // 5kHz
+      break;
+    block->nominal_rate << 1;
+    bresenham_oversample << 1;
+    block->step_event_count << 1;
   }
+  if (bresenham_oversample > 1)
+    // Lower the acceleration steps/sec^2 to account for the oversampling.
+    block->acceleration_st = (block->acceleration_st + (bresenham_oversample >> 1)) / bresenham_oversample;
 #endif
+
+  block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0)));
+
   // Start with a safe speed.
   // Safe speed is the speed, from which the machine may halt to stop immediately.
   float safe_speed = block->nominal_speed;
@@ -1047,34 +1106,9 @@ Having the real displacement of the head, we can calculate the total movement le
   previous_nominal_speed = block->nominal_speed;
   previous_safe_speed = safe_speed;
 
-#ifdef ADVANCE
-  // Calculate advance rate
-  if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) {
-    block->advance_rate = 0;
-    block->advance = 0;
-  }
-  else {
-    long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st);
-    float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * 
-      (current_speed[E_AXIS] * current_speed[E_AXIS] * EXTRUSION_AREA * EXTRUSION_AREA)*256;
-    block->advance = advance;
-    if(acc_dist == 0) {
-      block->advance_rate = 0;
-    } 
-    else {
-      block->advance_rate = advance / (float)acc_dist;
-    }
-  }
-  /*
-    SERIAL_ECHO_START;
-   SERIAL_ECHOPGM("advance :");
-   SERIAL_ECHO(block->advance/256.0);
-   SERIAL_ECHOPGM("advance rate :");
-   SERIAL_ECHOLN(block->advance_rate/256.0);
-   */
-#endif // ADVANCE
-
-  calculate_trapezoid_for_block(block, block->entry_speed/block->nominal_speed, safe_speed/block->nominal_speed);
+  // Precalculate the division, so when all the trapezoids in the planner queue get recalculated, the division is not repeated.
+  block->speed_factor = block->nominal_rate / block->nominal_speed;
+  calculate_trapezoid_for_block(block, block->entry_speed, safe_speed);
 
   // Move the buffer head. From now the block may be picked up by the stepper interrupt controller.
   block_buffer_head = next_buffer_head;
@@ -1092,6 +1126,9 @@ Having the real displacement of the head, we can calculate the total movement le
 //  SERIAL_ECHO(int(moves_planned()));
 //  SERIAL_ECHOLNPGM("");
 
+#ifdef PLANNER_DIAGNOSTICS
+  planner_update_queue_min_counter();
+#endif /* PLANNER_DIAGNOSTIC */
   st_wake_up();
 }
 
@@ -1172,3 +1209,15 @@ void reset_acceleration_rates()
         axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i];
         }
 }
+
+#ifdef PLANNER_DIAGNOSTICS
+uint8_t planner_queue_min()
+{
+  return g_cntr_planner_queue_min;
+}
+
+void planner_queue_min_reset()
+{
+  g_cntr_planner_queue_min = moves_planned();
+}
+#endif /* PLANNER_DIAGNOSTICS */

+ 14 - 6
Firmware/planner.h

@@ -55,12 +55,6 @@ typedef struct {
   // accelerate_until and decelerate_after are set by calculate_trapezoid_for_block() and they need to be synchronized with the stepper interrupt controller.
   long accelerate_until;                    // The index of the step event on which to stop acceleration
   long decelerate_after;                    // The index of the step event on which to start decelerating
-  #ifdef ADVANCE
-    long advance_rate;
-    volatile long initial_advance;
-    volatile long final_advance;
-    float advance;
-  #endif
 
   // Fields used by the motion planner to manage acceleration
 //  float speed_x, speed_y, speed_z, speed_e;        // Nominal mm/sec for each axis
@@ -82,12 +76,18 @@ typedef struct {
 
   // 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.
+  //FIXME nominal_rate, initial_rate and final_rate are limited to uint16_t by MultiU24X24toH16 in the stepper interrupt anyway!
   unsigned long nominal_rate;                        // The nominal step rate for this block in step_events/sec 
   unsigned long initial_rate;                        // The jerk-adjusted step rate at start of block  
   unsigned long final_rate;                          // The minimal rate at exit
   unsigned long acceleration_st;                     // acceleration steps/sec^2
+  //FIXME does it have to be unsigned long? Probably uint8_t would be just fine.
   unsigned long fan_speed;
   volatile char busy;
+
+
+  // Pre-calculated division for the calculate_trapezoid_for_block() routine to run faster.
+  float speed_factor;
 } block_t;
 
 #ifdef ENABLE_AUTO_BED_LEVELING
@@ -196,3 +196,11 @@ void set_extrude_min_temp(float temp);
 
 void reset_acceleration_rates();
 #endif
+
+// #define PLANNER_DIAGNOSTICS
+#ifdef PLANNER_DIAGNOSTICS
+// Diagnostic functions to display planner buffer underflow on the display.
+extern uint8_t planner_queue_min();
+// Diagnostic function: Reset the minimum planner segments.
+extern void planner_queue_min_reset();
+#endif /* PLANNER_DIAGNOSTICS */

+ 20 - 142
Firmware/stepper.cpp

@@ -47,22 +47,17 @@ block_t *current_block;  // A pointer to the block currently being traced
 
 // Variables used by The Stepper Driver Interrupt
 static unsigned char out_bits;        // The next stepping-bits to be output
-static long counter_x,       // Counter variables for the bresenham line tracer
-            counter_y,
-            counter_z,
-            counter_e;
-volatile static unsigned long step_events_completed; // The number of step events executed in the current block
-#ifdef ADVANCE
-  static long advance_rate, advance, final_advance = 0;
-  static long old_advance = 0;
-  static long e_steps[3];
-#endif
-static long acceleration_time, deceleration_time;
+static int32_t counter_x,       // Counter variables for the bresenham line tracer
+               counter_y,
+               counter_z,
+               counter_e;
+volatile static uint32_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 unsigned short acc_step_rate; // needed for deccelaration start point
-static char step_loops;
-static unsigned short OCR1A_nominal;
-static unsigned short step_loops_nominal;
+static uint16_t acc_step_rate; // needed for deccelaration start point
+static uint8_t  step_loops;
+static uint16_t OCR1A_nominal;
+static uint8_t  step_loops_nominal;
 
 volatile long endstops_trigsteps[3]={0,0,0};
 volatile long endstops_stepsTotal,endstops_stepsDone;
@@ -306,13 +301,6 @@ FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
 // Initializes the trapezoid generator from the current block. Called whenever a new
 // block begins.
 FORCE_INLINE void trapezoid_generator_reset() {
-  #ifdef ADVANCE
-    advance = current_block->initial_advance;
-    final_advance = current_block->final_advance;
-    // Do E steps + advance steps
-    e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
-    old_advance = advance >>8;
-  #endif
   deceleration_time = 0;
   // step_rate to timer interval
   OCR1A_nominal = calc_timer(current_block->nominal_rate);
@@ -359,10 +347,6 @@ ISR(TIMER1_COMPA_vect)
           return;
         }
       #endif
-
-//      #ifdef ADVANCE
-//      e_steps[current_block->active_extruder] = 0;
-//      #endif
     }
     else {
         OCR1A=2000; // 1kHz.
@@ -531,37 +515,20 @@ ISR(TIMER1_COMPA_vect)
     }
     #endif
 
-    #ifndef ADVANCE
-      if ((out_bits & (1<<E_AXIS)) != 0) {  // -direction
-        REV_E_DIR();
-        count_direction[E_AXIS]=-1;
-      }
-      else { // +direction
-        NORM_E_DIR();
-        count_direction[E_AXIS]=1;
-      }
-    #endif //!ADVANCE
-
-
+    if ((out_bits & (1<<E_AXIS)) != 0) {  // -direction
+      REV_E_DIR();
+      count_direction[E_AXIS]=-1;
+    }
+    else { // +direction
+      NORM_E_DIR();
+      count_direction[E_AXIS]=1;
+    }
 
-    for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves)
+    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
 
-      #ifdef ADVANCE
-      counter_e += current_block->steps_e;
-      if (counter_e > 0) {
-        counter_e -= current_block->step_event_count;
-        if ((out_bits & (1<<E_AXIS)) != 0) { // - direction
-          e_steps[current_block->active_extruder]--;
-        }
-        else {
-          e_steps[current_block->active_extruder]++;
-        }
-      }
-      #endif //ADVANCE
-
         counter_x += current_block->steps_x;
         if (counter_x > 0) {
           WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
@@ -604,7 +571,6 @@ ISR(TIMER1_COMPA_vect)
         #endif
       }
 
-      #ifndef ADVANCE
         counter_e += current_block->steps_e;
         if (counter_e > 0) {
           WRITE_E_STEP(!INVERT_E_STEP_PIN);
@@ -612,7 +578,6 @@ ISR(TIMER1_COMPA_vect)
           count_position[E_AXIS]+=count_direction[E_AXIS];
           WRITE_E_STEP(INVERT_E_STEP_PIN);
         }
-      #endif //!ADVANCE
       step_events_completed += 1;
       if(step_events_completed >= current_block->step_event_count) break;
     }
@@ -620,7 +585,7 @@ ISR(TIMER1_COMPA_vect)
     unsigned short timer;
     unsigned short step_rate;
     if (step_events_completed <= (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;
 
@@ -632,16 +597,6 @@ ISR(TIMER1_COMPA_vect)
       timer = calc_timer(acc_step_rate);
       OCR1A = timer;
       acceleration_time += timer;
-      #ifdef ADVANCE
-        for(int8_t i=0; i < step_loops; i++) {
-          advance += advance_rate;
-        }
-        //if(advance > current_block->advance) advance = current_block->advance;
-        // Do E steps + advance steps
-        e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
-        old_advance = advance >>8;
-
-      #endif // ADVANCE
     }
     else if (step_events_completed > (unsigned long int)current_block->decelerate_after) {
       MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate);
@@ -661,15 +616,6 @@ ISR(TIMER1_COMPA_vect)
       timer = calc_timer(step_rate);
       OCR1A = timer;
       deceleration_time += timer;
-      #ifdef ADVANCE
-        for(int8_t i=0; i < step_loops; i++) {
-          advance -= advance_rate;
-        }
-        if(advance < final_advance) advance = final_advance;
-        // Do E steps + advance steps
-        e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
-        old_advance = advance >>8;
-      #endif //ADVANCE
     }
     else {
       OCR1A = OCR1A_nominal;
@@ -685,63 +631,6 @@ ISR(TIMER1_COMPA_vect)
   }
 }
 
-#ifdef 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)
-  {
-    old_OCR0A += 52; // ~10kHz interrupt (250000 / 26 = 9615kHz)
-    OCR0A = old_OCR0A;
-    // Set E direction (Depends on E direction + advance)
-    for(unsigned char i=0; i<4;i++) {
-      if (e_steps[0] != 0) {
-        WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN);
-        if (e_steps[0] < 0) {
-          WRITE(E0_DIR_PIN, INVERT_E0_DIR);
-          e_steps[0]++;
-          WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-        else if (e_steps[0] > 0) {
-          WRITE(E0_DIR_PIN, !INVERT_E0_DIR);
-          e_steps[0]--;
-          WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-      }
- #if EXTRUDERS > 1
-      if (e_steps[1] != 0) {
-        WRITE(E1_STEP_PIN, INVERT_E_STEP_PIN);
-        if (e_steps[1] < 0) {
-          WRITE(E1_DIR_PIN, INVERT_E1_DIR);
-          e_steps[1]++;
-          WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-        else if (e_steps[1] > 0) {
-          WRITE(E1_DIR_PIN, !INVERT_E1_DIR);
-          e_steps[1]--;
-          WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-      }
- #endif
- #if EXTRUDERS > 2
-      if (e_steps[2] != 0) {
-        WRITE(E2_STEP_PIN, INVERT_E_STEP_PIN);
-        if (e_steps[2] < 0) {
-          WRITE(E2_DIR_PIN, INVERT_E2_DIR);
-          e_steps[2]++;
-          WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-        else if (e_steps[2] > 0) {
-          WRITE(E2_DIR_PIN, !INVERT_E2_DIR);
-          e_steps[2]--;
-          WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN);
-        }
-      }
- #endif
-    }
-  }
-#endif // ADVANCE
-
 void st_init()
 {
   digipot_init(); //Initialize Digipot Motor Current
@@ -930,17 +819,6 @@ void st_init()
   TCNT1 = 0;
   ENABLE_STEPPER_DRIVER_INTERRUPT();
 
-  #ifdef ADVANCE
-  #if defined(TCCR0A) && defined(WGM01)
-    TCCR0A &= ~(1<<WGM01);
-    TCCR0A &= ~(1<<WGM00);
-  #endif
-    e_steps[0] = 0;
-    e_steps[1] = 0;
-    e_steps[2] = 0;
-    TIMSK0 |= (1<<OCIE0A);
-  #endif //ADVANCE
-
   enable_endstops(true); // Start with endstops active. After homing they can be disabled
   sei();
 }

+ 1 - 0
Firmware/temperature.cpp

@@ -1211,6 +1211,7 @@ void max_temp_error(uint8_t e) {
     WRITE(FAN_PIN, 1);
     WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1);
     WRITE(BEEPER, 1);
+    // fanSpeed will consumed by the check_axes_activity() routine.
     fanSpeed=255;
 }
 

+ 0 - 1
Firmware/ultralcd.cpp

@@ -327,7 +327,6 @@ void set_language_from_EEPROM() {
   }
 }
 
-void lcd_mylang();
 static void lcd_status_screen()
 {
 	

+ 26 - 4
Firmware/ultralcd_implementation_hitachi_HD44780.h

@@ -659,6 +659,7 @@ static void lcd_implementation_status_screen()
 
     //Print the Z coordinates
     lcd.setCursor(LCD_WIDTH - 8-2, 0);
+#if 1
     lcd_printPGM(PSTR("  Z"));
     if (custom_message_type == 1) {
         // In a bed calibration mode.
@@ -667,6 +668,11 @@ static void lcd_implementation_status_screen()
         lcd.print(ftostr32sp(current_position[Z_AXIS] + 0.00001));
         lcd.print(' ');
     }
+#else
+    lcd_printPGM(PSTR(" Queue:"));
+    lcd.print(int(moves_planned()));
+    lcd.print(' ');
+#endif
 
     //Print the Bedtemperature
     lcd.setCursor(0, 1);
@@ -679,15 +685,31 @@ static void lcd_implementation_status_screen()
     lcd_printPGM(PSTR(LCD_STR_DEGREE " "));
     lcd_printPGM(PSTR("  "));
 
+#if 1
     //Print Feedrate
     lcd.setCursor(LCD_WIDTH - 8-2, 1);
     lcd_printPGM(PSTR("  "));
     lcd.print(LCD_STR_FEEDRATE[0]);
     lcd.print(itostr3(feedmultiply));
-    lcd.print('%');
-    lcd_printPGM(PSTR("     "));
-
-
+    lcd_printPGM(PSTR("%%     "));
+#else
+    //Print Feedrate
+    lcd.setCursor(LCD_WIDTH - 8-2, 1);
+    lcd.print(LCD_STR_FEEDRATE[0]);
+    lcd.print(itostr3(feedmultiply));
+    lcd_printPGM(PSTR("%  Q"));
+    {
+      uint8_t queue = planner_queue_min();
+      if (queue < (BLOCK_BUFFER_SIZE >> 1)) {
+        lcd.print('!');
+      } else {
+        lcd.print((char)(queue / 10) + '0');
+        queue %= 10;
+      }
+      lcd.print((char)queue + '0');
+      planner_queue_min_reset();
+    }
+#endif
 	
     //Print SD status
     lcd.setCursor(0, 2);