Adaptive multiaxis step smoothing

- Stepper bugs fixed
- Support MIXING_EXTRUDER with Linear Advance
- Miscellaneous cleanup
2.0.x
etagle 7 years ago committed by Scott Lahteine
parent ae15c5af88
commit 39a7e7720d

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 4, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -631,7 +631,7 @@
* Override with M201
* X, Y, Z, E0 [, E1[, E2[, E3[, E4]]]]
*/
#define DEFAULT_MAX_ACCELERATION { MAX_XYAXIS_ACCEL, MAX_XYAXIS_ACCEL, 100, 200 }
#define DEFAULT_MAX_ACCELERATION { MAX_XYAXIS_ACCEL, MAX_XYAXIS_ACCEL, 10, 200 }
/**
* Default Acceleration (change/s) change = mm/s

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -453,6 +453,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -452,6 +452,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -452,6 +452,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -452,6 +452,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -452,6 +452,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -452,6 +452,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -457,6 +457,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -452,6 +452,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -450,6 +450,14 @@
//#define JUNCTION_DEVIATION_INCLUDE_E
#endif
/**
* Adaptive Step Smoothing increases the resolution of multi-axis moves, particularly at step frequencies
* below 1kHz (for AVR) or 10kHz (for ARM), where aliasing between axes in multi-axis moves causes audible
* vibration and surface artifacts. The algorithm adapts to provide the best possible step smoothing at the
* lowest stepping frequencies.
*/
//#define ADAPTIVE_STEP_SMOOTHING
// Microstep setting (Only functional when stepper driver microstep pins are connected to MCU.
#define MICROSTEP_MODES { 16, 16, 16, 16, 16 } // [1,2,4,8,16]

@ -215,22 +215,6 @@
#define DEFAULT_KEEPALIVE_INTERVAL 2
#endif
#ifdef CPU_32_BIT
/**
* Hidden options for developer
*/
// Double stepping starts at STEP_DOUBLER_FREQUENCY + 1, quad stepping starts at STEP_DOUBLER_FREQUENCY * 2 + 1
#ifndef STEP_DOUBLER_FREQUENCY
#if ENABLED(LIN_ADVANCE)
#define STEP_DOUBLER_FREQUENCY 60000 // Hz
#else
#define STEP_DOUBLER_FREQUENCY 80000 // Hz
#endif
#endif
// Disable double / quad stepping
//#define DISABLE_MULTI_STEPPING
#endif
/**
* Provide a MAX_AUTORETRACT for older configs
*/
@ -238,23 +222,6 @@
#define MAX_AUTORETRACT 99
#endif
/**
* MAX_STEP_FREQUENCY differs for TOSHIBA
*/
#if ENABLED(CONFIG_STEPPERS_TOSHIBA)
#ifdef CPU_32_BIT
#define MAX_STEP_FREQUENCY STEP_DOUBLER_FREQUENCY // Max step frequency for Toshiba Stepper Controllers, 96kHz is close to maximum for an Arduino Due
#else
#define MAX_STEP_FREQUENCY 10000 // Max step frequency for Toshiba Stepper Controllers
#endif
#else
#ifdef CPU_32_BIT
#define MAX_STEP_FREQUENCY (STEP_DOUBLER_FREQUENCY * 4) // Max step frequency for the Due is approx. 330kHz
#else
#define MAX_STEP_FREQUENCY 40000 // Max step frequency for Ultimaker (5000 pps / half step)
#endif
#endif
// MS1 MS2 Stepper Driver Microstepping mode table
#define MICROSTEP1 LOW,LOW
#if ENABLED(HEROIC_STEPPER_DRIVERS)
@ -1346,15 +1313,6 @@
#define MANUAL_PROBE_HEIGHT Z_HOMING_HEIGHT
#endif
// Stepper pulse duration, in cycles
#define STEP_PULSE_CYCLES ((MINIMUM_STEPPER_PULSE) * CYCLES_PER_MICROSECOND)
#ifdef CPU_32_BIT
// Add additional delay for between direction signal and pulse signal of stepper
#ifndef STEPPER_DIRECTION_DELAY
#define STEPPER_DIRECTION_DELAY 0 // time in microseconds
#endif
#endif
#ifndef __SAM3X8E__ //todo: hal: broken hal encapsulation
#undef UI_VOLTAGE_LEVEL
#undef RADDS_DISPLAY
@ -1486,4 +1444,132 @@
#define USE_EXECUTE_COMMANDS_IMMEDIATE
#endif
//
// Estimate the amount of time the ISR will take to execute
//
#ifdef CPU_32_BIT
// The base ISR takes 792 cycles
#define ISR_BASE_CYCLES 792UL
// Linear advance base time is 64 cycles
#if ENABLED(LIN_ADVANCE)
#define ISR_LA_BASE_CYCLES 64UL
#else
#define ISR_LA_BASE_CYCLES 0UL
#endif
// S curve interpolation adds 40 cycles
#if ENABLED(S_CURVE_ACCELERATION)
#define ISR_S_CURVE_CYCLES 40UL
#else
#define ISR_S_CURVE_CYCLES 0UL
#endif
// Stepper Loop base cycles
#define ISR_LOOP_BASE_CYCLES 4UL
// And each stepper takes 16 cycles
#define ISR_STEPPER_CYCLES 16UL
#else
// The base ISR takes 752 cycles
#define ISR_BASE_CYCLES 752UL
// Linear advance base time is 32 cycles
#if ENABLED(LIN_ADVANCE)
#define ISR_LA_BASE_CYCLES 32UL
#else
#define ISR_LA_BASE_CYCLES 0UL
#endif
// S curve interpolation adds 160 cycles
#if ENABLED(S_CURVE_ACCELERATION)
#define ISR_S_CURVE_CYCLES 160UL
#else
#define ISR_S_CURVE_CYCLES 0UL
#endif
// Stepper Loop base cycles
#define ISR_LOOP_BASE_CYCLES 32UL
// And each stepper takes 88 cycles
#define ISR_STEPPER_CYCLES 88UL
#endif
// For each stepper, we add its time
#ifdef HAS_X_STEP
#define ISR_X_STEPPER_CYCLES ISR_STEPPER_CYCLES
#else
#define ISR_X_STEPPER_CYCLES 0UL
#endif
// For each stepper, we add its time
#ifdef HAS_Y_STEP
#define ISR_Y_STEPPER_CYCLES ISR_STEPPER_CYCLES
#else
#define ISR_Y_STEPPER_CYCLES 0UL
#endif
// For each stepper, we add its time
#ifdef HAS_Z_STEP
#define ISR_Z_STEPPER_CYCLES ISR_STEPPER_CYCLES
#else
#define ISR_Z_STEPPER_CYCLES 0UL
#endif
// E is always interpolated, even for mixing extruders
#define ISR_E_STEPPER_CYCLES ISR_STEPPER_CYCLES
// If linear advance is disabled, then the loop also handles them
#if DISABLED(LIN_ADVANCE) && ENABLED(MIXING_EXTRUDER)
#define ISR_MIXING_STEPPER_CYCLES ((MIXING_STEPPERS) * ISR_STEPPER_CYCLES)
#else
#define ISR_MIXING_STEPPER_CYCLES 0UL
#endif
// And the total minimum loop time is, without including the base
#define MIN_ISR_LOOP_CYCLES (ISR_X_STEPPER_CYCLES + ISR_Y_STEPPER_CYCLES + ISR_Z_STEPPER_CYCLES + ISR_E_STEPPER_CYCLES + ISR_MIXING_STEPPER_CYCLES)
// But the user could be enforcing a minimum time, so the loop time is
#define ISR_LOOP_CYCLES (ISR_LOOP_BASE_CYCLES + ((MINIMUM_STEPPER_PULSE*2UL) > MIN_ISR_LOOP_CYCLES ? (MINIMUM_STEPPER_PULSE*2UL) : MIN_ISR_LOOP_CYCLES))
// If linear advance is enabled, then it is handled separately
#if ENABLED(LIN_ADVANCE)
// Estimate the minimum LA loop time
#if ENABLED(MIXING_EXTRUDER)
#define MIN_ISR_LA_LOOP_CYCLES ((MIXING_STEPPERS) * (ISR_STEPPER_CYCLES))
#else
#define MIN_ISR_LA_LOOP_CYCLES ISR_STEPPER_CYCLES
#endif
// And the real loop time
#define ISR_LA_LOOP_CYCLES ((MINIMUM_STEPPER_PULSE*2UL) > MIN_ISR_LA_LOOP_CYCLES ? (MINIMUM_STEPPER_PULSE*2UL) : MIN_ISR_LA_LOOP_CYCLES)
#else
#define ISR_LA_LOOP_CYCLES 0UL
#endif
// Now estimate the total ISR execution time in cycles given a step per ISR multiplier
#define ISR_EXECUTION_CYCLES(rate) (((ISR_BASE_CYCLES + ISR_S_CURVE_CYCLES + (ISR_LOOP_CYCLES * rate) + ISR_LA_BASE_CYCLES + ISR_LA_LOOP_CYCLES)) / rate)
// The maximum allowable stepping frequency when doing x128-x1 stepping (in Hz)
#define MAX_128X_STEP_ISR_FREQUENCY (F_CPU / ISR_EXECUTION_CYCLES(128))
#define MAX_64X_STEP_ISR_FREQUENCY (F_CPU / ISR_EXECUTION_CYCLES(64))
#define MAX_32X_STEP_ISR_FREQUENCY (F_CPU / ISR_EXECUTION_CYCLES(32))
#define MAX_16X_STEP_ISR_FREQUENCY (F_CPU / ISR_EXECUTION_CYCLES(16))
#define MAX_8X_STEP_ISR_FREQUENCY (F_CPU / ISR_EXECUTION_CYCLES(8))
#define MAX_4X_STEP_ISR_FREQUENCY (F_CPU / ISR_EXECUTION_CYCLES(4))
#define MAX_2X_STEP_ISR_FREQUENCY (F_CPU / ISR_EXECUTION_CYCLES(2))
#define MAX_1X_STEP_ISR_FREQUENCY (F_CPU / ISR_EXECUTION_CYCLES(1))
// The minimum allowable frequency for step smoothing will be 1/10 of the maximum nominal frequency (in Hz)
#define MIN_STEP_ISR_FREQUENCY MAX_1X_STEP_ISR_FREQUENCY
// Disable multiple steps per ISR
//#define DISABLE_MULTI_STEPPING
#endif // CONDITIONALS_POST_H

@ -679,9 +679,9 @@ void Planner::init() {
return r11 | (uint16_t(r12) << 8) | (uint32_t(r13) << 16);
}
#else
// All the other 32 CPUs can easily perform the inverse using hardware division,
// All other 32-bit MPUs can easily do inverse using hardware division,
// so we don't need to reduce precision or to use assembly language at all.
// This routine, for all the other archs, returns 0x100000000 / d ~= 0xFFFFFFFF / d
// This routine, for all other archs, returns 0x100000000 / d ~= 0xFFFFFFFF / d
static FORCE_INLINE uint32_t get_period_inverse(const uint32_t d) { return 0xFFFFFFFF / d; }
#endif
#endif
@ -1646,10 +1646,16 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
// Bail if this is a zero-length block
if (block->step_event_count < MIN_STEPS_PER_SEGMENT) return false;
// For a mixing extruder, get a magnified step_event_count for each
// For a mixing extruder, get a magnified esteps for each
#if ENABLED(MIXING_EXTRUDER)
for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
block->mix_event_count[i] = mixing_factor[i] * block->step_event_count;
block->mix_steps[i] = mixing_factor[i] * (
#if ENABLED(LIN_ADVANCE)
esteps
#else
block->step_event_count
#endif
);
#endif
#if FAN_COUNT > 0

@ -108,7 +108,7 @@ typedef struct {
uint8_t active_extruder; // The extruder to move (if E move)
#if ENABLED(MIXING_EXTRUDER)
uint32_t mix_event_count[MIXING_STEPPERS]; // Scaled step_event_count for the mixing steppers
uint32_t mix_steps[MIXING_STEPPERS]; // Scaled steps[E_AXIS] for the mixing steppers
#endif
// Settings for the trapezoid generator
@ -130,7 +130,7 @@ typedef struct {
// Advance extrusion
#if ENABLED(LIN_ADVANCE)
bool use_advance_lead;
uint16_t advance_speed, // Timer value for extruder speed offset
uint16_t advance_speed, // STEP timer value for extruder speed offset ISR
max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!)
final_adv_steps; // advance steps due to exit speed
float e_D_ratio;

@ -46,6 +46,29 @@
* and Philipp Tiefenbacher.
*/
/**
* __________________________
* /| |\ _________________ ^
* / | | \ /| |\ |
* / | | \ / | | \ s
* / | | | | | \ p
* / | | | | | \ e
* +-----+------------------------+---+--+---------------+----+ e
* | BLOCK 1 | BLOCK 2 | d
*
* time ----->
*
* The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates
* first block->accelerate_until step_events_completed, then keeps going at constant speed until
* step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset.
* The slope of acceleration is calculated using v = u + at where t is the accumulated timer values of the steps so far.
*/
/**
* Marlin uses the Bresenham algorithm. For a detailed explanation of theory and
* method see https://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html
*/
/**
* Jerk controlled movements planner added Apr 2018 by Eduardo José Tagle.
* Equations based on Synthethos TinyG2 sources, but the fixed-point
@ -97,10 +120,14 @@ block_t* Stepper::current_block = NULL; // A pointer to the block currently bei
// private:
uint8_t Stepper::last_direction_bits = 0,
Stepper::last_movement_extruder = 0xFF,
Stepper::axis_did_move;
bool Stepper::abort_current_block;
#if DISABLED(MIXING_EXTRUDER)
uint8_t Stepper::last_moved_extruder = 0xFF;
#endif
#if ENABLED(X_DUAL_ENDSTOPS)
bool Stepper::locked_X_motor = false, Stepper::locked_X2_motor = false;
#endif
@ -111,19 +138,30 @@ bool Stepper::abort_current_block;
bool Stepper::locked_Z_motor = false, Stepper::locked_Z2_motor = false;
#endif
/**
* Marlin uses the Bresenham algorithm. For a detailed explanation of theory and
* method see https://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html
*
* The implementation used here additionally rounds up the starting seed.
*/
uint32_t Stepper::acceleration_time, Stepper::deceleration_time;
uint8_t Stepper::steps_per_isr;
#if DISABLED(ADAPTIVE_STEP_SMOOTHING)
constexpr
#endif
uint8_t Stepper::oversampling_factor;
int32_t Stepper::counter_X = 0,
Stepper::counter_Y = 0,
Stepper::counter_Z = 0,
Stepper::counter_E = 0;
int32_t Stepper::delta_error[XYZE] = { 0 };
uint32_t Stepper::step_events_completed = 0; // The number of step events executed in the current block
uint32_t Stepper::advance_dividend[XYZE] = { 0 },
Stepper::advance_divisor = 0,
Stepper::step_events_completed = 0, // The number of step events executed in the current block
Stepper::accelerate_until, // The point from where we need to stop acceleration
Stepper::decelerate_after, // The point from where we need to start decelerating
Stepper::step_event_count; // The total event count for the current block
#if ENABLED(MIXING_EXTRUDER)
int32_t Stepper::delta_error_m[MIXING_STEPPERS];
uint32_t Stepper::advance_dividend_m[MIXING_STEPPERS],
Stepper::advance_divisor_m;
#else
int8_t Stepper::active_extruder; // Active extruder
#endif
#if ENABLED(S_CURVE_ACCELERATION)
int32_t __attribute__((used)) Stepper::bezier_A __asm__("bezier_A"); // A coefficient in Bézier speed curve with alias for assembler
@ -138,49 +176,32 @@ uint32_t Stepper::step_events_completed = 0; // The number of step events execut
#endif
uint32_t Stepper::nextMainISR = 0;
bool Stepper::all_steps_done = false;
#if ENABLED(LIN_ADVANCE)
uint32_t Stepper::LA_decelerate_after;
constexpr uint32_t ADV_NEVER = 0xFFFFFFFF;
uint32_t Stepper::nextAdvanceISR = ADV_NEVER,
Stepper::eISR_Rate = ADV_NEVER;
uint16_t Stepper::current_adv_steps = 0,
Stepper::final_adv_steps,
Stepper::max_adv_steps;
constexpr uint32_t LA_ADV_NEVER = 0xFFFFFFFF;
uint32_t Stepper::nextAdvanceISR = LA_ADV_NEVER,
Stepper::LA_isr_rate = LA_ADV_NEVER;
uint16_t Stepper::LA_current_adv_steps = 0,
Stepper::LA_final_adv_steps,
Stepper::LA_max_adv_steps;
int8_t Stepper::e_steps = 0;
int8_t Stepper::LA_steps = 0;
#if E_STEPPERS > 1
int8_t Stepper::LA_active_extruder; // Copy from current executed block. Needed because current_block is set to NULL "too early".
#else
constexpr int8_t Stepper::LA_active_extruder;
#endif
bool Stepper::use_advance_lead;
bool Stepper::LA_use_advance_lead;
#endif // LIN_ADVANCE
uint32_t Stepper::acceleration_time, Stepper::deceleration_time;
volatile int32_t Stepper::count_position[NUM_AXIS] = { 0 };
int8_t Stepper::count_direction[NUM_AXIS] = { 1, 1, 1, 1 };
#if ENABLED(MIXING_EXTRUDER)
int32_t Stepper::counter_m[MIXING_STEPPERS];
#endif
uint32_t Stepper::ticks_nominal;
uint8_t Stepper::step_loops, Stepper::step_loops_nominal;
int32_t Stepper::ticks_nominal = -1;
#if DISABLED(S_CURVE_ACCELERATION)
uint32_t Stepper::acc_step_rate; // needed for deceleration start point
#endif
volatile int32_t Stepper::endstops_trigsteps[XYZ];
volatile int32_t Stepper::count_position[NUM_AXIS] = { 0 };
int8_t Stepper::count_direction[NUM_AXIS] = { 0, 0, 0, 0 };
#if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
#define DUAL_ENDSTOP_APPLY_STEP(A,V) \
if (homing_dual_axis) { \
@ -213,7 +234,7 @@ volatile int32_t Stepper::endstops_trigsteps[XYZ];
X2_DIR_WRITE(v); \
} \
else { \
if (current_block->active_extruder) X2_DIR_WRITE(v); else X_DIR_WRITE(v); \
if (movement_extruder()) X2_DIR_WRITE(v); else X_DIR_WRITE(v); \
}
#define X_APPLY_STEP(v,ALWAYS) \
if (extruder_duplication_enabled || ALWAYS) { \
@ -221,7 +242,7 @@ volatile int32_t Stepper::endstops_trigsteps[XYZ];
X2_STEP_WRITE(v); \
} \
else { \
if (current_block->active_extruder) X2_STEP_WRITE(v); else X_STEP_WRITE(v); \
if (movement_extruder()) X2_STEP_WRITE(v); else X_STEP_WRITE(v); \
}
#else
#define X_APPLY_DIR(v,Q) X_DIR_WRITE(v)
@ -253,26 +274,9 @@ volatile int32_t Stepper::endstops_trigsteps[XYZ];
#endif
#if DISABLED(MIXING_EXTRUDER)
#define E_APPLY_STEP(v,Q) E_STEP_WRITE(current_block->active_extruder, v)
#define E_APPLY_STEP(v,Q) E_STEP_WRITE(active_extruder, v)
#endif
/**
* __________________________
* /| |\ _________________ ^
* / | | \ /| |\ |
* / | | \ / | | \ s
* / | | | | | \ p
* / | | | | | \ e
* +-----+------------------------+---+--+---------------+----+ e
* | BLOCK 1 | BLOCK 2 | d
*
* time ----->
*
* The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates
* first block->accelerate_until step_events_completed, then keeps going at constant speed until
* step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset.
* The slope of acceleration is calculated using v = u + at where t is the accumulated timer values of the steps so far.
*/
void Stepper::wake_up() {
// TCNT1 = 0;
ENABLE_STEPPER_DRIVER_INTERRUPT();
@ -308,14 +312,25 @@ void Stepper::set_directions() {
#endif
#if DISABLED(LIN_ADVANCE)
#if ENABLED(MIXING_EXTRUDER)
if (motor_direction(E_AXIS)) {
MIXING_STEPPERS_LOOP(j) REV_E_DIR(j);
count_direction[E_AXIS] = -1;
}
else {
MIXING_STEPPERS_LOOP(j) NORM_E_DIR(j);
count_direction[E_AXIS] = 1;
}
#else
if (motor_direction(E_AXIS)) {
REV_E_DIR(current_block->active_extruder);
REV_E_DIR(active_extruder);
count_direction[E_AXIS] = -1;
}
else {
NORM_E_DIR(current_block->active_extruder);
NORM_E_DIR(active_extruder);
count_direction[E_AXIS] = 1;
}
#endif
#endif // !LIN_ADVANCE
}
@ -1128,17 +1143,6 @@ void Stepper::set_directions() {
* Stepper Driver Interrupt
*
* Directly pulses the stepper motors at high frequency.
*
* AVR :
* Timer 1 runs at a base frequency of 2MHz, with this ISR using OCR1A compare mode.
*
* OCR1A Frequency
* 1 2 MHz
* 50 40 KHz
* 100 20 KHz - capped max rate
* 200 10 KHz - nominal max rate
* 2000 1 KHz - sleep rate
* 4000 500 Hz - init rate
*/
HAL_STEP_TIMER_ISR {
@ -1156,9 +1160,11 @@ HAL_STEP_TIMER_ISR {
#endif
void Stepper::isr() {
#ifndef __AVR__
// Disable interrupts, to avoid ISR preemption while we reprogram the period
// (AVR enters the ISR with global interrupts disabled, so no need to do it here)
DISABLE_ISRS();
#endif
// Program timer compare for the maximum period, so it does NOT
// flag an interrupt while this ISR is running - So changes from small
@ -1206,7 +1212,7 @@ void Stepper::isr() {
#if ENABLED(LIN_ADVANCE)
// Compute the time remaining for the advance isr
if (nextAdvanceISR != ADV_NEVER) nextAdvanceISR -= interval;
if (nextAdvanceISR != LA_ADV_NEVER) nextAdvanceISR -= interval;
#endif
/**
@ -1248,12 +1254,17 @@ void Stepper::isr() {
/**
* Get the current tick value + margin
* Assuming at least 6µs between calls to this ISR...
* On AVR the ISR epilogue is estimated at 40 instructions - close to 2.5µS.
* On ARM the ISR epilogue is estimated at 10 instructions - close to 200nS.
* In either case leave at least 8µS for other tasks to execute - That allows
* up to 100khz stepping rates
* On AVR the ISR epilogue+prologue is estimated at 100 instructions - Give 8µs as margin
* On ARM the ISR epilogue+prologue is estimated at 20 instructions - Give 1µs as margin
*/
min_ticks = HAL_timer_get_count(STEP_TIMER_NUM) + hal_timer_t((HAL_TICKS_PER_US) * 8); // ISR never takes more than 1ms, so this shouldn't cause trouble
min_ticks = HAL_timer_get_count(STEP_TIMER_NUM) + hal_timer_t(
#ifdef __AVR__
8
#else
1
#endif
* (HAL_TICKS_PER_US)
);
/**
* NB: If for some reason the stepper monopolizes the MPU, eventually the
@ -1299,97 +1310,34 @@ void Stepper::stepper_pulse_phase_isr() {
if (!current_block) return;
// Take multiple steps per interrupt (For high speed moves)
all_steps_done = false;
for (uint8_t i = step_loops; i--;) {
for (uint8_t i = steps_per_isr; i--;) {
#define _COUNTER(AXIS) counter_## AXIS
#define _APPLY_STEP(AXIS) AXIS ##_APPLY_STEP
#define _INVERT_STEP_PIN(AXIS) INVERT_## AXIS ##_STEP_PIN
// Advance the Bresenham counter; start a pulse if the axis needs a step
// Start an active pulse, if Bresenham says so, and update position
#define PULSE_START(AXIS) do{ \
_COUNTER(AXIS) += current_block->steps[_AXIS(AXIS)]; \
if (_COUNTER(AXIS) >= 0) { _APPLY_STEP(AXIS)(!_INVERT_STEP_PIN(AXIS), 0); } \
}while(0)
// Advance the Bresenham counter; start a pulse if the axis needs a step
#define STEP_TICK(AXIS) do { \
if (_COUNTER(AXIS) >= 0) { \
_COUNTER(AXIS) -= current_block->step_event_count; \
delta_error[_AXIS(AXIS)] += advance_dividend[_AXIS(AXIS)]; \
if (delta_error[_AXIS(AXIS)] >= 0) { \
_APPLY_STEP(AXIS)(!_INVERT_STEP_PIN(AXIS), 0); \
count_position[_AXIS(AXIS)] += count_direction[_AXIS(AXIS)]; \
} \
}while(0)
// Stop an active pulse, if any
#define PULSE_STOP(AXIS) _APPLY_STEP(AXIS)(_INVERT_STEP_PIN(AXIS), 0)
/**
* Estimate the number of cycles that the stepper logic already takes
* up between the start and stop of the X stepper pulse.
*
* Currently this uses very modest estimates of around 5 cycles.
* True values may be derived by careful testing.
*
* Once any delay is added, the cost of the delay code itself
* may be subtracted from this value to get a more accurate delay.
* Delays under 20 cycles (1.25µs) will be very accurate, using NOPs.
* Longer delays use a loop. The resolution is 8 cycles.
*/
#if HAS_X_STEP
#define _CYCLE_APPROX_1 5
#else
#define _CYCLE_APPROX_1 0
#endif
#if ENABLED(X_DUAL_STEPPER_DRIVERS)
#define _CYCLE_APPROX_2 _CYCLE_APPROX_1 + 4
#else
#define _CYCLE_APPROX_2 _CYCLE_APPROX_1
#endif
#if HAS_Y_STEP
#define _CYCLE_APPROX_3 _CYCLE_APPROX_2 + 5
#else
#define _CYCLE_APPROX_3 _CYCLE_APPROX_2
#endif
#if ENABLED(Y_DUAL_STEPPER_DRIVERS)
#define _CYCLE_APPROX_4 _CYCLE_APPROX_3 + 4
#else
#define _CYCLE_APPROX_4 _CYCLE_APPROX_3
#endif
#if HAS_Z_STEP
#define _CYCLE_APPROX_5 _CYCLE_APPROX_4 + 5
#else
#define _CYCLE_APPROX_5 _CYCLE_APPROX_4
#endif
#if ENABLED(Z_DUAL_STEPPER_DRIVERS)
#define _CYCLE_APPROX_6 _CYCLE_APPROX_5 + 4
#else
#define _CYCLE_APPROX_6 _CYCLE_APPROX_5
#endif
#if DISABLED(LIN_ADVANCE)
#if ENABLED(MIXING_EXTRUDER)
#define _CYCLE_APPROX_7 _CYCLE_APPROX_6 + (MIXING_STEPPERS) * 6
#else
#define _CYCLE_APPROX_7 _CYCLE_APPROX_6 + 5
#endif
#else
#define _CYCLE_APPROX_7 _CYCLE_APPROX_6
#endif
#define CYCLES_EATEN_XYZE _CYCLE_APPROX_7
#define EXTRA_CYCLES_XYZE (STEP_PULSE_CYCLES - (CYCLES_EATEN_XYZE))
// Stop an active pulse, if any, and adjust error term
#define PULSE_STOP(AXIS) do { \
if (delta_error[_AXIS(AXIS)] >= 0) { \
delta_error[_AXIS(AXIS)] -= advance_divisor; \
_APPLY_STEP(AXIS)(_INVERT_STEP_PIN(AXIS), 0); \
} \
}while(0)
/**
* If a minimum pulse time was specified get the timer 0 value.
*
* On AVR the TCNT0 timer has an 8x prescaler, so it increments every 8 cycles.
* That's every 0.5µs on 16MHz and every 0.4µs on 20MHz.
* 20 counts of TCNT0 -by itself- is a good pulse delay.
* 10µs = 160 or 200 cycles.
*/
#if EXTRA_CYCLES_XYZE > 20
hal_timer_t pulse_start = HAL_timer_get_count(PULSE_TIMER_NUM);
#if MINIMUM_STEPPER_PULSE > 0
// Get the timer count and estimate the end of the pulse
hal_timer_t pulse_end = HAL_timer_get_count(PULSE_TIMER_NUM) + hal_timer_t((HAL_TICKS_PER_US) * (MINIMUM_STEPPER_PULSE));
#endif
// Pulse start
#if HAS_X_STEP
PULSE_START(X);
#endif
@ -1400,64 +1348,48 @@ void Stepper::stepper_pulse_phase_isr() {
PULSE_START(Z);
#endif
// Pulse E/Mixing extruders
#if ENABLED(LIN_ADVANCE)
counter_E += current_block->steps[E_AXIS];
if (counter_E >= 0) {
#if DISABLED(MIXING_EXTRUDER)
// Don't step E here for mixing extruder
motor_direction(E_AXIS) ? --e_steps : ++e_steps;
#endif
}
// Tick the E axis, correct error term and update position
delta_error[E_AXIS] += advance_dividend[E_AXIS];
if (delta_error[E_AXIS] >= 0) {
count_position[E_AXIS] += count_direction[E_AXIS];
delta_error[E_AXIS] -= advance_divisor;
#if ENABLED(MIXING_EXTRUDER)
// Step mixing steppers proportionally
const bool dir = motor_direction(E_AXIS);
MIXING_STEPPERS_LOOP(j) {
counter_m[j] += current_block->steps[E_AXIS];
if (counter_m[j] >= 0) {
counter_m[j] -= current_block->mix_event_count[j];
dir ? --e_steps[j] : ++e_steps[j];
}
// Don't step E here - But remember the number of steps to perform
motor_direction(E_AXIS) ? --LA_steps : ++LA_steps;
}
#endif
#else // !LIN_ADVANCE - use linear interpolation for E also
#if ENABLED(MIXING_EXTRUDER)
// Keep updating the single E axis
counter_E += current_block->steps[E_AXIS];
// Tick the counters used for this mix
// Tick the E axis
delta_error[E_AXIS] += advance_dividend[E_AXIS];
if (delta_error[E_AXIS] >= 0) {
count_position[E_AXIS] += count_direction[E_AXIS];
delta_error[E_AXIS] -= advance_divisor;
}
// Tick the counters used for this mix in proper proportion
MIXING_STEPPERS_LOOP(j) {
// Step mixing steppers (proportionally)
counter_m[j] += current_block->steps[E_AXIS];
delta_error_m[j] += advance_dividend_m[j];
// Step when the counter goes over zero
if (counter_m[j] >= 0) E_STEP_WRITE(j, !INVERT_E_STEP_PIN);
if (delta_error_m[j] >= 0) E_STEP_WRITE(j, !INVERT_E_STEP_PIN);
}
#else // !MIXING_EXTRUDER
PULSE_START(E);
#endif
#endif // !LIN_ADVANCE
#if HAS_X_STEP
STEP_TICK(X);
#endif
#if HAS_Y_STEP
STEP_TICK(Y);
#endif
#if HAS_Z_STEP
STEP_TICK(Z);
#endif
STEP_TICK(E); // Always tick the single E axis
// For minimum pulse time wait before stopping pulses
#if EXTRA_CYCLES_XYZE > 20
while (EXTRA_CYCLES_XYZE > (uint32_t)(HAL_timer_get_count(PULSE_TIMER_NUM) - pulse_start) * (PULSE_TIMER_PRESCALE)) { /* nada */ }
pulse_start = HAL_timer_get_count(PULSE_TIMER_NUM);
#elif EXTRA_CYCLES_XYZE > 0
DELAY_NS(EXTRA_CYCLES_XYZE * NANOSECONDS_PER_CYCLE);
#if MINIMUM_STEPPER_PULSE > 0
// Just wait for the requested pulse time.
while (HAL_timer_get_count(PULSE_TIMER_NUM) < pulse_end) { /* nada */ }
// Get the timer count and estimate the end of the pulse for the OFF phase
pulse_end = HAL_timer_get_count(PULSE_TIMER_NUM) + hal_timer_t((HAL_TICKS_PER_US) * (MINIMUM_STEPPER_PULSE));
#endif
// Pulse stop
#if HAS_X_STEP
PULSE_STOP(X);
#endif
@ -1471,8 +1403,8 @@ void Stepper::stepper_pulse_phase_isr() {
#if DISABLED(LIN_ADVANCE)
#if ENABLED(MIXING_EXTRUDER)
MIXING_STEPPERS_LOOP(j) {
if (counter_m[j] >= 0) {
counter_m[j] -= current_block->mix_event_count[j];
if (delta_error_m[j] >= 0) {
delta_error_m[j] -= advance_divisor_m;
E_STEP_WRITE(j, INVERT_E_STEP_PIN);
}
}
@ -1481,18 +1413,14 @@ void Stepper::stepper_pulse_phase_isr() {
#endif
#endif // !LIN_ADVANCE
if (++step_events_completed >= current_block->step_event_count) {
all_steps_done = true;
break;
}
// If all events done, break loop now
if (++step_events_completed >= step_event_count) break;
#if MINIMUM_STEPPER_PULSE
// For minimum pulse time wait after stopping pulses also
#if EXTRA_CYCLES_XYZE > 20
if (i) while (EXTRA_CYCLES_XYZE > (uint32_t)(HAL_timer_get_count(PULSE_TIMER_NUM) - pulse_start) * (PULSE_TIMER_PRESCALE)) { /* nada */ }
#elif EXTRA_CYCLES_XYZE > 0
if (i) DELAY_NS(EXTRA_CYCLES_XYZE * NANOSECONDS_PER_CYCLE);
// Just wait for the requested pulse time.
if (i) while (HAL_timer_get_count(PULSE_TIMER_NUM) < pulse_end) { /* nada */ }
#endif
} // steps_loop
}
@ -1508,8 +1436,17 @@ uint32_t Stepper::stepper_block_phase_isr() {
// If there is a current block
if (current_block) {
// Calculate new timer value
if (step_events_completed <= current_block->accelerate_until) {
// If current block is finished, reset pointer
if (step_events_completed >= step_event_count) {
axis_did_move = 0;
current_block = NULL;
planner.discard_current_block();
}
else {
// Step events not completed yet...
// Are we in acceleration phase ?
if (step_events_completed <= accelerate_until) { // Calculate new timer value
#if ENABLED(S_CURVE_ACCELERATION)
// Get the next speed to use (Jerk limited!)
@ -1522,24 +1459,28 @@ uint32_t Stepper::stepper_block_phase_isr() {
NOMORE(acc_step_rate, current_block->nominal_rate);
#endif
// step_rate to timer interval
interval = calc_timer_interval(acc_step_rate);
// acc_step_rate is in steps/second
// step_rate to timer interval and steps per stepper isr
interval = calc_timer_interval(acc_step_rate, oversampling_factor, &steps_per_isr);
acceleration_time += interval;
#if ENABLED(LIN_ADVANCE)
if (current_block->use_advance_lead) {
if (step_events_completed == step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) {
nextAdvanceISR = 0; // Wake up eISR on first acceleration loop and fire ISR if final adv_rate is reached
eISR_Rate = current_block->advance_speed;
if (LA_use_advance_lead) {
// Wake up eISR on first acceleration loop and fire ISR if final adv_rate is reached
if (step_events_completed == steps_per_isr || (LA_steps && LA_isr_rate != current_block->advance_speed)) {
nextAdvanceISR = 0;
LA_isr_rate = current_block->advance_speed;
}
}
else {
eISR_Rate = ADV_NEVER;
if (e_steps) nextAdvanceISR = 0;
LA_isr_rate = LA_ADV_NEVER;
if (LA_steps) nextAdvanceISR = 0;
}
#endif // LIN_ADVANCE
}
else if (step_events_completed > current_block->decelerate_after) {
// Are we in Deceleration phase ?
else if (step_events_completed > decelerate_after) {
uint32_t step_rate;
#if ENABLED(S_CURVE_ACCELERATION)
@ -1548,12 +1489,15 @@ uint32_t Stepper::stepper_block_phase_isr() {
// Initialize the Bézier speed curve
_calc_bezier_curve_coeffs(current_block->cruise_rate, current_block->final_rate, current_block->deceleration_time_inverse);
bezier_2nd_half = true;
// The first point starts at cruise rate. Just save evaluation of the Bézier curve
step_rate = current_block->cruise_rate;
}
else {
// Calculate the next speed to use
step_rate = deceleration_time < current_block->deceleration_time
? _eval_bezier_curve(deceleration_time)
: current_block->final_rate;
}
#else
// Using the old trapezoidal control
@ -1566,42 +1510,44 @@ uint32_t Stepper::stepper_block_phase_isr() {
step_rate = current_block->final_rate;
#endif
// step_rate to timer interval
interval = calc_timer_interval(step_rate);
// step_rate is in steps/second
// step_rate to timer interval and steps per stepper isr
interval = calc_timer_interval(step_rate, oversampling_factor, &steps_per_isr);
deceleration_time += interval;
#if ENABLED(LIN_ADVANCE)
if (current_block->use_advance_lead) {
if (step_events_completed <= current_block->decelerate_after + step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) {
if (LA_use_advance_lead) {
if (step_events_completed <= decelerate_after + steps_per_isr ||
(LA_steps && LA_isr_rate != current_block->advance_speed)
) {
nextAdvanceISR = 0; // Wake up eISR on first deceleration loop
eISR_Rate = current_block->advance_speed;
LA_isr_rate = current_block->advance_speed;
}
}
else {
eISR_Rate = ADV_NEVER;
if (e_steps) nextAdvanceISR = 0;
LA_isr_rate = LA_ADV_NEVER;
if (LA_steps) nextAdvanceISR = 0;
}
#endif // LIN_ADVANCE
}
// We must be in cruise phase otherwise
else {
#if ENABLED(LIN_ADVANCE)
// If there are any esteps, fire the next advance_isr "now"
if (e_steps && eISR_Rate != current_block->advance_speed) nextAdvanceISR = 0;
if (LA_steps && LA_isr_rate != current_block->advance_speed) nextAdvanceISR = 0;
#endif
// Calculate the ticks_nominal for this nominal speed, if not done yet
if (ticks_nominal < 0) {
// step_rate to timer interval and loops for the nominal speed
ticks_nominal = calc_timer_interval(current_block->nominal_rate, oversampling_factor, &steps_per_isr);
}
// The timer interval is just the nominal value for the nominal speed
interval = ticks_nominal;
// Ensure this runs at the correct step rate, even if it just came off an acceleration
step_loops = step_loops_nominal;
}
// If current block is finished, reset pointer
if (all_steps_done) {
axis_did_move = 0;
current_block = NULL;
planner.discard_current_block();
}
}
@ -1697,25 +1643,82 @@ uint32_t Stepper::stepper_block_phase_isr() {
//if (!!current_block->steps[C_AXIS]) SBI(axis_bits, Z_HEAD);
axis_did_move = axis_bits;
// Initialize the trapezoid generator from the current block.
// No acceleration / deceleration time elapsed so far
acceleration_time = deceleration_time = 0;
uint8_t oversampling = 0; // Assume we won't use it
#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
// At this point, we must decide if we can use Stepper movement axis smoothing.
uint32_t max_rate = current_block->nominal_rate; // Get the maximum rate (maximum event speed)
while (max_rate < MIN_STEP_ISR_FREQUENCY) {
max_rate <<= 1;
if (max_rate >= MAX_1X_STEP_ISR_FREQUENCY) break;
++oversampling;
}
oversampling_factor = oversampling;
#endif
// Based on the oversampling factor, do the calculations
step_event_count = current_block->step_event_count << oversampling;
// Initialize Bresenham delta errors to 1/2
delta_error[X_AXIS] = delta_error[Y_AXIS] = delta_error[Z_AXIS] = delta_error[E_AXIS] = -int32_t(step_event_count);
// Calculate Bresenham dividends
advance_dividend[X_AXIS] = current_block->steps[X_AXIS] << 1;
advance_dividend[Y_AXIS] = current_block->steps[Y_AXIS] << 1;
advance_dividend[Z_AXIS] = current_block->steps[Z_AXIS] << 1;
advance_dividend[E_AXIS] = current_block->steps[E_AXIS] << 1;
// Calculate Bresenham divisor
advance_divisor = step_event_count << 1;
// No step events completed so far
step_events_completed = 0;
// Compute the acceleration and deceleration points
accelerate_until = current_block->accelerate_until << oversampling;
decelerate_after = current_block->decelerate_after << oversampling;
#if ENABLED(MIXING_EXTRUDER)
const uint32_t e_steps = (
#if ENABLED(LIN_ADVANCE)
#if E_STEPPERS > 1
if (current_block->active_extruder != last_movement_extruder) {
current_adv_steps = 0; // If the now active extruder wasn't in use during the last move, its pressure is most likely gone.
LA_active_extruder = current_block->active_extruder;
current_block->steps[E_AXIS]
#else
step_event_count
#endif
);
MIXING_STEPPERS_LOOP(i) {
delta_error_m[i] = -int32_t(e_steps);
advance_dividend_m[i] = current_block->mix_steps[i] << 1;
}
advance_divisor_m = e_steps << 1;
#else
active_extruder = current_block->active_extruder;
#endif
if ((use_advance_lead = current_block->use_advance_lead)) {
LA_decelerate_after = current_block->decelerate_after;
final_adv_steps = current_block->final_adv_steps;
max_adv_steps = current_block->max_adv_steps;
// Initialize the trapezoid generator from the current block.
#if ENABLED(LIN_ADVANCE)
#if DISABLED(MIXING_EXTRUDER) && E_STEPPERS > 1
// If the now active extruder wasn't in use during the last move, its pressure is most likely gone.
if (active_extruder != last_moved_extruder) LA_current_adv_steps = 0;
#endif
if ((LA_use_advance_lead = current_block->use_advance_lead)) {
LA_final_adv_steps = current_block->final_adv_steps;
LA_max_adv_steps = current_block->max_adv_steps;
}
#endif
if (current_block->direction_bits != last_direction_bits || current_block->active_extruder != last_movement_extruder) {
if (current_block->direction_bits != last_direction_bits
#if DISABLED(MIXING_EXTRUDER)
|| active_extruder != last_moved_extruder
#endif
) {
last_direction_bits = current_block->direction_bits;
last_movement_extruder = current_block->active_extruder;
#if DISABLED(MIXING_EXTRUDER)
last_moved_extruder = active_extruder;
#endif
set_directions();
}
@ -1728,17 +1731,15 @@ uint32_t Stepper::stepper_block_phase_isr() {
// on the next call to this ISR, will be discarded.
endstops.check_possible_change();
// No acceleration / deceleration time elapsed so far
acceleration_time = deceleration_time = 0;
// No step events completed so far
step_events_completed = 0;
// step_rate to timer interval for the nominal speed
ticks_nominal = calc_timer_interval(current_block->nominal_rate);
#if ENABLED(Z_LATE_ENABLE)
// If delayed Z enable, enable it now. This option will severely interfere with
// timing between pulses when chaining motion between blocks, and it could lead
// to lost steps in both X and Y axis, so avoid using it unless strictly necessary!!
if (current_block->steps[Z_AXIS]) enable_Z();
#endif
// make a note of the number of step loops required at nominal speed
step_loops_nominal = step_loops;
// Mark the time_nominal as not calculated yet
ticks_nominal = -1;
#if DISABLED(S_CURVE_ACCELERATION)
// Set as deceleration point the initial rate of the block
@ -1748,24 +1749,12 @@ uint32_t Stepper::stepper_block_phase_isr() {
#if ENABLED(S_CURVE_ACCELERATION)
// Initialize the Bézier speed curve
_calc_bezier_curve_coeffs(current_block->initial_rate, current_block->cruise_rate, current_block->acceleration_time_inverse);
// We have not started the 2nd half of the trapezoid
// We haven't started the 2nd half of the trapezoid
bezier_2nd_half = false;
#endif
// Initialize Bresenham counters to 1/2 the ceiling, with proper roundup (as explained in the article linked above)
counter_X = counter_Y = counter_Z = counter_E = -int32_t((current_block->step_event_count + 1) >> 1);
#if ENABLED(MIXING_EXTRUDER)
MIXING_STEPPERS_LOOP(i)
counter_m[i] = -int32_t((current_block->mix_event_count[i] + 1) >> 1);
#endif
#if ENABLED(Z_LATE_ENABLE)
// If delayed Z enable, enable it now. This option will severely interfere with
// timing between pulses when chaining motion between blocks, and it could lead
// to lost steps in both X and Y axis, so avoid using it unless strictly necessary!!
if (current_block->steps[Z_AXIS]) enable_Z();
#endif
// Calculate the initial timer interval
interval = calc_timer_interval(current_block->initial_rate, oversampling_factor, &steps_per_isr);
}
}
@ -1775,65 +1764,85 @@ uint32_t Stepper::stepper_block_phase_isr() {
#if ENABLED(LIN_ADVANCE)
#define CYCLES_EATEN_E (E_STEPPERS * 5)
#define EXTRA_CYCLES_E (STEP_PULSE_CYCLES - (CYCLES_EATEN_E))
// Timer interrupt for E. e_steps is set in the main routine;
// Timer interrupt for E. LA_steps is set in the main routine
uint32_t Stepper::advance_isr() {
uint32_t interval;
if (use_advance_lead) {
if (step_events_completed > LA_decelerate_after && current_adv_steps > final_adv_steps) {
e_steps--;
current_adv_steps--;
interval = eISR_Rate;
if (LA_use_advance_lead) {
if (step_events_completed > decelerate_after && LA_current_adv_steps > LA_final_adv_steps) {
LA_steps--;
LA_current_adv_steps--;
interval = LA_isr_rate;
}
else if (step_events_completed < LA_decelerate_after && current_adv_steps < max_adv_steps) {
//step_events_completed <= (uint32_t)current_block->accelerate_until) {
e_steps++;
current_adv_steps++;
interval = eISR_Rate;
else if (step_events_completed < decelerate_after && LA_current_adv_steps < LA_max_adv_steps) {
//step_events_completed <= (uint32_t)accelerate_until) {
LA_steps++;
LA_current_adv_steps++;
interval = LA_isr_rate;
}
else
interval = eISR_Rate = ADV_NEVER;
interval = LA_isr_rate = LA_ADV_NEVER;
}
else
interval = ADV_NEVER;
interval = LA_ADV_NEVER;
if (e_steps >= 0)
NORM_E_DIR(LA_active_extruder);
#if ENABLED(MIXING_EXTRUDER)
if (LA_steps >= 0)
MIXING_STEPPERS_LOOP(j) NORM_E_DIR(j);
else
MIXING_STEPPERS_LOOP(j) REV_E_DIR(j);
#else
if (LA_steps >= 0)
NORM_E_DIR(active_extruder);
else
REV_E_DIR(LA_active_extruder);
REV_E_DIR(active_extruder);
#endif
// Step E stepper if we have steps
while (e_steps) {
while (LA_steps) {
#if EXTRA_CYCLES_E > 20
hal_timer_t pulse_start = HAL_timer_get_count(PULSE_TIMER_NUM);
#if MINIMUM_STEPPER_PULSE
hal_timer_t pulse_end = HAL_timer_get_count(PULSE_TIMER_NUM) + hal_timer_t((HAL_TICKS_PER_US) * (MINIMUM_STEPPER_PULSE));
#endif
E_STEP_WRITE(LA_active_extruder, !INVERT_E_STEP_PIN);
#if ENABLED(MIXING_EXTRUDER)
MIXING_STEPPERS_LOOP(j) {
// Step mixing steppers (proportionally)
delta_error_m[j] += advance_dividend_m[j];
// Step when the counter goes over zero
if (delta_error_m[j] >= 0) E_STEP_WRITE(j, !INVERT_E_STEP_PIN);
}
#else
E_STEP_WRITE(active_extruder, !INVERT_E_STEP_PIN);
#endif
// For minimum pulse time wait before stopping pulses
#if EXTRA_CYCLES_E > 20
while (EXTRA_CYCLES_E > (hal_timer_t)(HAL_timer_get_count(PULSE_TIMER_NUM) - pulse_start) * (PULSE_TIMER_PRESCALE)) { /* nada */ }
pulse_start = HAL_timer_get_count(PULSE_TIMER_NUM);
#elif EXTRA_CYCLES_E > 0
DELAY_NS(EXTRA_CYCLES_E * NANOSECONDS_PER_CYCLE);
#if MINIMUM_STEPPER_PULSE
// Just wait for the requested pulse duration
while (HAL_timer_get_count(PULSE_TIMER_NUM) < pulse_end) { /* nada */ }
// Get the timer count and estimate the end of the pulse for the OFF phase
pulse_end = HAL_timer_get_count(PULSE_TIMER_NUM) + hal_timer_t((HAL_TICKS_PER_US) * (MINIMUM_STEPPER_PULSE));
#endif
e_steps < 0 ? ++e_steps : --e_steps;
LA_steps < 0 ? ++LA_steps : --LA_steps;
E_STEP_WRITE(LA_active_extruder, INVERT_E_STEP_PIN);
#if ENABLED(MIXING_EXTRUDER)
MIXING_STEPPERS_LOOP(j) {
if (delta_error_m[j] >= 0) {
delta_error_m[j] -= advance_divisor_m;
E_STEP_WRITE(j, INVERT_E_STEP_PIN);
}
}
#else
E_STEP_WRITE(active_extruder, INVERT_E_STEP_PIN);
#endif
#if MINIMUM_STEPPER_PULSE
// For minimum pulse time wait before looping
#if EXTRA_CYCLES_E > 20
if (e_steps) while (EXTRA_CYCLES_E > (hal_timer_t)(HAL_timer_get_count(PULSE_TIMER_NUM) - pulse_start) * (PULSE_TIMER_PRESCALE)) { /* nada */ }
#elif EXTRA_CYCLES_E > 0
if (e_steps) DELAY_NS(EXTRA_CYCLES_E * NANOSECONDS_PER_CYCLE);
// Just wait for the requested pulse duration
if (LA_steps) while (HAL_timer_get_count(PULSE_TIMER_NUM) < pulse_end) { /* nada */ }
#endif
} // e_steps
} // LA_steps
return interval;
}
@ -2145,6 +2154,12 @@ void Stepper::report_positions() {
#if ENABLED(BABYSTEPPING)
#if MINIMUM_STEPPER_PULSE
#define STEP_PULSE_CYCLES ((MINIMUM_STEPPER_PULSE) * CYCLES_PER_MICROSECOND)
#else
#define STEP_PULSE_CYCLES 0
#endif
#if ENABLED(DELTA)
#define CYCLES_EATEN_BABYSTEP (2 * 15)
#else
@ -2158,8 +2173,8 @@ void Stepper::report_positions() {
#define _APPLY_DIR(AXIS, INVERT) AXIS ##_APPLY_DIR(INVERT, true)
#if EXTRA_CYCLES_BABYSTEP > 20
#define _SAVE_START const hal_timer_t pulse_start = HAL_timer_get_count(STEP_TIMER_NUM)
#define _PULSE_WAIT while (EXTRA_CYCLES_BABYSTEP > (uint32_t)(HAL_timer_get_count(STEP_TIMER_NUM) - pulse_start) * (PULSE_TIMER_PRESCALE)) { /* nada */ }
#define _SAVE_START const hal_timer_t pulse_start = HAL_timer_get_count(PULSE_TIMER_NUM)
#define _PULSE_WAIT while (EXTRA_CYCLES_BABYSTEP > (uint32_t)(HAL_timer_get_count(PULSE_TIMER_NUM) - pulse_start) * (PULSE_TIMER_PRESCALE)) { /* nada */ }
#else
#define _SAVE_START NOOP
#if EXTRA_CYCLES_BABYSTEP > 0

@ -76,10 +76,14 @@ class Stepper {
private:
static uint8_t last_direction_bits, // The next stepping-bits to be output
last_movement_extruder, // Last movement extruder, as computed when the last movement was fetched from planner
axis_did_move; // Last Movement in the given direction is not null, as computed when the last movement was fetched from planner
static bool abort_current_block; // Signals to the stepper that current block should be aborted
#if DISABLED(MIXING_EXTRUDER)
static uint8_t last_moved_extruder; // Last-moved extruder, as set when the last movement was fetched from planner
#endif
#if ENABLED(X_DUAL_ENDSTOPS)
static bool locked_X_motor, locked_X2_motor;
#endif
@ -90,9 +94,34 @@ class Stepper {
static bool locked_Z_motor, locked_Z2_motor;
#endif
// Counter variables for the Bresenham line tracer
static int32_t counter_X, counter_Y, counter_Z, counter_E;
static uint32_t step_events_completed; // The number of step events executed in the current block
static uint32_t acceleration_time, deceleration_time; // time measured in Stepper Timer ticks
static uint8_t steps_per_isr; // Count of steps to perform per Stepper ISR call
#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
static uint8_t oversampling_factor; // Oversampling factor (log2(multiplier)) to increase temporal resolution of axis
#else
static constexpr uint8_t oversampling_factor = 0;
#endif
// Delta error variables for the Bresenham line tracer
static int32_t delta_error[XYZE];
static uint32_t advance_dividend[XYZE],
advance_divisor,
step_events_completed, // The number of step events executed in the current block
accelerate_until, // The point from where we need to stop acceleration
decelerate_after, // The point from where we need to start decelerating
step_event_count; // The total event count for the current block
// Mixing extruder mix delta_errors for bresenham tracing
#if ENABLED(MIXING_EXTRUDER)
static int32_t delta_error_m[MIXING_STEPPERS];
static uint32_t advance_dividend_m[MIXING_STEPPERS],
advance_divisor_m;
#define MIXING_STEPPERS_LOOP(VAR) \
for (uint8_t VAR = 0; VAR < MIXING_STEPPERS; VAR++)
#else
static int8_t active_extruder; // Active extruder
#endif
#if ENABLED(S_CURVE_ACCELERATION)
static int32_t bezier_A, // A coefficient in Bézier speed curve
@ -107,33 +136,19 @@ class Stepper {
#endif
static uint32_t nextMainISR; // time remaining for the next Step ISR
static bool all_steps_done; // all steps done
#if ENABLED(LIN_ADVANCE)
static uint32_t LA_decelerate_after; // Copy from current executed block. Needed because current_block is set to NULL "too early".
static uint32_t nextAdvanceISR, eISR_Rate;
static uint16_t current_adv_steps, final_adv_steps, max_adv_steps; // Copy from current executed block. Needed because current_block is set to NULL "too early".
static int8_t e_steps;
static bool use_advance_lead;
#if E_STEPPERS > 1
static int8_t LA_active_extruder; // Copy from current executed block. Needed because current_block is set to NULL "too early".
#else
static constexpr int8_t LA_active_extruder = 0;
#endif
static uint32_t nextAdvanceISR, LA_isr_rate;
static uint16_t LA_current_adv_steps, LA_final_adv_steps, LA_max_adv_steps; // Copy from current executed block. Needed because current_block is set to NULL "too early".
static int8_t LA_steps;
static bool LA_use_advance_lead;
#endif // LIN_ADVANCE
static uint32_t acceleration_time, deceleration_time;
static uint8_t step_loops, step_loops_nominal;
static uint32_t ticks_nominal;
static int32_t ticks_nominal;
#if DISABLED(S_CURVE_ACCELERATION)
static uint32_t acc_step_rate; // needed for deceleration start point
#endif
static volatile int32_t endstops_trigsteps[XYZ];
static volatile int32_t endstops_stepsTotal, endstops_stepsDone;
//
// Positions of stepper motors, in step units
@ -145,16 +160,6 @@ class Stepper {
//
static int8_t count_direction[NUM_AXIS];
//
// Mixing extruder mix counters
//
#if ENABLED(MIXING_EXTRUDER)
static int32_t counter_m[MIXING_STEPPERS];
#define MIXING_STEPPERS_LOOP(VAR) \
for (uint8_t VAR = 0; VAR < MIXING_STEPPERS; VAR++) \
if (current_block->mix_event_count[VAR])
#endif
public:
//
@ -201,7 +206,15 @@ class Stepper {
FORCE_INLINE static bool axis_is_moving(const AxisEnum axis) { return TEST(axis_did_move, axis); }
// The extruder associated to the last movement
FORCE_INLINE static uint8_t movement_extruder() { return last_movement_extruder; }
FORCE_INLINE static uint8_t movement_extruder() {
return
#if ENABLED(MIXING_EXTRUDER)
0
#else
last_moved_extruder
#endif
;
}
// Handle a triggered endstop
static void endstop_triggered(const AxisEnum axis);
@ -279,34 +292,42 @@ class Stepper {
// Set direction bits for all steppers
static void set_directions();
// Limit the speed to 10KHz for AVR
#ifndef STEP_DOUBLER_FREQUENCY
#define STEP_DOUBLER_FREQUENCY 10000
#endif
FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate) {
FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate, uint8_t scale, uint8_t* loops) {
uint32_t timer;
NOMORE(step_rate, uint32_t(MAX_STEP_FREQUENCY));
// Scale the frequency, as requested by the caller
step_rate <<= scale;
uint8_t multistep = 1;
#if DISABLED(DISABLE_MULTI_STEPPING)
if (step_rate > STEP_DOUBLER_FREQUENCY * 2) { // If steprate > (STEP_DOUBLER_FREQUENCY * 2) kHz >> step 4 times
step_rate >>= 2;
step_loops = 4;
}
else if (step_rate > STEP_DOUBLER_FREQUENCY) { // If steprate > STEP_DOUBLER_FREQUENCY kHz >> step 2 times
// The stepping frequency limits for each multistepping rate
static const uint32_t limit[] PROGMEM = {
( MAX_1X_STEP_ISR_FREQUENCY ),
( MAX_2X_STEP_ISR_FREQUENCY >> 1),
( MAX_4X_STEP_ISR_FREQUENCY >> 2),
( MAX_8X_STEP_ISR_FREQUENCY >> 3),
( MAX_16X_STEP_ISR_FREQUENCY >> 4),
( MAX_32X_STEP_ISR_FREQUENCY >> 5),
( MAX_64X_STEP_ISR_FREQUENCY >> 6),
(MAX_128X_STEP_ISR_FREQUENCY >> 7)
};
// Select the proper multistepping
uint8_t idx = 0;
while (idx < 7 && step_rate > (uint32_t)pgm_read_dword(&limit[idx])) {
step_rate >>= 1;
step_loops = 2;
}
else
multistep <<= 1;
++idx;
};
#else
NOMORE(step_rate, uint32_t(MAX_1X_STEP_ISR_FREQUENCY));
#endif
step_loops = 1;
*loops = multistep;
#ifdef CPU_32_BIT
// In case of high-performance processor, it is able to calculate in real-time
const uint32_t min_time_per_step = (HAL_STEPPER_TIMER_RATE) / ((STEP_DOUBLER_FREQUENCY) * 2);
timer = uint32_t(HAL_STEPPER_TIMER_RATE) / step_rate;
NOLESS(timer, min_time_per_step); // (STEP_DOUBLER_FREQUENCY * 2 kHz - this should never happen)
#else
constexpr uint32_t min_step_rate = F_CPU / 500000U;
NOLESS(step_rate, min_step_rate);
@ -324,10 +345,8 @@ class Stepper {
timer = (uint16_t)pgm_read_word_near(table_address)
- (((uint16_t)pgm_read_word_near(table_address + 2) * (uint8_t)(step_rate & 0x0007)) >> 3);
}
if (timer < 100) { // (20kHz - this should never happen)
timer = 100;
SERIAL_ECHOLNPAIR(MSG_STEPPER_TOO_HIGH, step_rate);
}
// (there is no need to limit the timer value here. All limits have been
// applied above, and AVR is able to keep up at 30khz Stepping ISR rate)
#endif
return timer;

@ -0,0 +1,269 @@
On the Bresenham algorithm as implemented by Marlin:
(Taken from (https://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html)
The basic Bresenham algorithm:
Consider drawing a line on a raster grid where we restrict the allowable slopes of the line to the range 0 <= m <= 1
If we further restrict the line-drawing routine so that it always increments x as it plots, it becomes clear that, having plotted a point at (x,y), the routine has a severely limited range of options as to where it may put the next point on the line:
- It may plot the point (x+1,y), or:
- It may plot the point (x+1,y+1).
So, working in the first positive octant of the plane, line drawing becomes a matter of deciding between two possibilities at each step.
We can draw a diagram of the situation which the plotting program finds itself in having plotted (x,y).
```
y+1 +--------------*
| /
| /
| /
| /
| y+e+m*--------+-
| /| ^ |
| / | |m |
| / | | |
| / | v |
| y+e*----|----- |m+ε
| /| | ^ |
| / | | |ε |
| / | | | |
|/ | | v v
y *----+----+----------+--
x x+1
```
In plotting (x,y) the line drawing routine will, in general, be making a compromise between what it would like to draw and what the resolution of the stepper motors actually allows it to draw. Usually the plotted point (x,y) will be in error, the actual, mathematical point on the line will not be addressable on the pixel grid. So we associate an error, ε, with each y ordinate, the real value of y should be y+ε . This error will range from -0.5 to just under +0.5.
In moving from x to x+1 we increase the value of the true (mathematical) y-ordinate by an amount equal to the slope of the line, m. We will choose to plot (x+1,y) if the difference between this new value and y is less than 0.5
```
y + ε + m < y + 0.5
```
Otherwise we will plot (x+1,y+1). It should be clear that by so doing we minimize the total error between the mathematical line segment and what actually gets drawn on the display.
The error resulting from this new point can now be written back into ε, this will allow us to repeat the whole process for the next point along the line, at x+2.
The new value of error can adopt one of two possible values, depending on what new point is plotted. If (x+1,y) is chosen, the new value of error is given by:
```
ε[new] = (y + ε + m) - y
```
Otherwise, it is:
```
ε[new] = (y + ε + m) - (y + 1)
```
This gives an algorithm for a DDA which avoids rounding operations, instead using the error variable ε to control plotting:
```
ε = 0, y = y[1]
for x = x1 to x2 do
Plot point at (x,y)
if (ε + m < 0.5)
ε = ε + m
else
y = y + 1, ε = ε + m - 1
endif
endfor
```
This still employs floating point values. Consider, however, what happens if we multiply across both sides of the plotting test by Δx and then by 2:
```
ε + m < 0.5
ε + Δy/Δx < 0.5
2.ε.Δx + 2.Δy < Δx
```
All quantities in this inequality are now integral.
Substitute ε' for ε.Δx . The test becomes:
```
2.(ε' + Δy) < Δx
```
This gives an integer-only test for deciding which point to plot.
The update rules for the error on each step may also be cast into ε' form. Consider the floating-point versions of the update rules:
```
ε = ε + m
ε = ε + m - 1
```
Multiplying through by Δx yields:
```
ε.Δx = ε.Δx + Δy
ε.Δx = ε.Δx + Δy - Δx
```
Which is in ε' form:
```
ε' = ε' + Δy
ε' = ε' + Δy - Δx
```
Using this new ``error'' value, ε' with the new test and update equations gives Bresenham's integer-only line drawing algorithm:
```
ε' = 0, y = y[1]
for x = x1 to x2 do
Plot point at (x,y)
if (2.(ε' + Δy) < Δx)
ε' = ε' + Δy
else
y = y + 1, ε' = ε' + Δy - Δx
endif
endfor
```
It is a Integer only algorithm - hence efficient (fast). And the Multiplication by 2 can be implemented by left-shift. 0 <= m <= 1
### Oversampling Bresenham algorithm:
Even if Bresenham does NOT lose steps at all, and also does NOT accumulate error, there is a concept i would call "time resolution" - If the quotient between major axis and minor axis (major axis means, in this context, the axis that must create more step pulses compared with the other ones, including the extruder)
Well, if the quotient result is not an integer, then Bresenham, at some points in the movement of the major axis, must decide that it has to move the minor axis. It is done in such way that after the full major axis movement has executed, it also has executed the full movements of the minor axis. And the minor axis steps were properly distributed evenly along the major axis movement. So good so far.
But, as said, Bresenham has "discrete" decision points: It can only decide to move (or not to move) minor axis exactly at the moment the major axis moves. And that is not the ideal point (in time) usually.
With slow movements that are composed of a similar, but not equal number of steps in all axes, the problem worsens, as the decision points are distributed very sparsely, and there are large delays between those decision points.
It is nearly trivial to extend Bresenham to "oversample" in that situation: Let's do it:
Assume that we want to use Bresenham to calculate when to step (move in Y direction), but we want to do it, not for integer increments of the X axis, rather than, for fractional increments.
Let's call 'r' the count of subdivisions we want to split an integer increment of the X axis:
```
m = Δy/Δx = increment of y due to the increment of x1
```
Every time we move `1/r` in the X axis, then the Y axis should move `m.1/r`
But, as stated previously, due to the resolution of the screen, there are 2 choices:
- It may plot the point `(x+(1/r),y)`, or:
- It may plot the point `(x+(1/r),y+1)`.
That decision must be made keeping the error as small as possible:
```
-0.5 < ε < 0.5
```
So, the proper condition for that decision is (`m/r` is the increment of y due to the fractional `1/r` increment of `x`):
```
y + ε + m/r < y + 0.5
ε + m/r < 0.5 [1]
```
Once we did the decision, then the error update conditions are:
Decision A:
```
ε[new] = y + ε + m/r - y
ε[new] = ε + m/r [2]
```
Decision B:
```
ε[new] = y + ε + m/r - (y+1)
ε[new] = ε + m/r - 1 [3]
```
We replace m in the decision inequality [1] by its definition:
```
ε + m/r < 0.5
ε + ΔY/(ΔX*r) < 0.5
```
Then, we multiply it by `2.Δx.r`:
```
ε + ΔY/(ΔX*r) < 0.5
2.ΔX.ε.r + 2.ΔY < ΔX.r
```
If we define `ε' = 2.ε.ΔX.r` then it becomes:
```
ε' + 2.ΔY < ΔX.r [4]
```
Now, for the update rules, we multiply by 2.r.ΔX
```
ε[new] = ε + m/r
2.r.ΔX.ε[new] = 2.r.ΔX.ε + 2.r.ΔX.ΔY/ΔX/r
2.r.ΔX.ε[new] = 2.r.ΔX.ε + 2.ΔY
ε'[new] = ε' + 2.ΔY [6]
```
```
ε[new] = ε + m/r - 1
2.r.ΔX.ε[new] = 2.r.ΔX.ε + 2.r.ΔX.ΔY/ΔX/r - 1 . 2.r.ΔX
2.r.ΔX.ε[new] = 2.r.ΔX.ε + 2.ΔY - 2.ΔX.r
ε'[new] = ε' + 2.ΔY - 2.ΔX.r [7]
```
All expressions, the decision inequality [4], and the update equations [5] and [6] are integer valued. There is no need for floating point arithmetic at all.
Summarizing:
```
Condition equation:
ε' + 2.ΔY < ΔX.r [4]
Error update equations:
ε'[new] = ε' + 2.ΔY [6]
ε'[new] = ε' + 2.ΔY - 2.ΔX.r [7]
```
This can be implemented in C as:
```cpp
class OversampledBresenham {
private:
long divisor, // stepsX
dividend, // stepsY
advanceDivisor, // advanceX
advanceDividend; // advanceY
int errorAccumulator; // Error accumulator
public:
unsigned int ticker;
OversampledBresenhan(const long& inDividend, const long& inDivisor, int rate) {
ticker = 0;
divisor = inDivisor;
dividend = inDividend;
advanceDivisor = divisor * 2 * rate;
advanceDividend = dividend * 2;
errorAccumulator = -divisor * rate;
}
bool tick() {
errorAccumulator += advanceDividend;
const bool over = errorAccumulator >= 0;
if (over) {
ticker++;
errorAccumulator -= advanceDivisor;
}
return over;
}
};
```
Loading…
Cancel
Save